feat/kcp (#580)
Some checks are pending
EasyTier Core / pre_job (push) Waiting to run
EasyTier Core / build (freebsd-13.2-x86_64, 13.2, ubuntu-22.04, x86_64-unknown-freebsd) (push) Blocked by required conditions
EasyTier Core / build (linux-aarch64, ubuntu-22.04, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-arm, ubuntu-22.04, arm-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armhf, ubuntu-22.04, arm-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7, ubuntu-22.04, armv7-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7hf, ubuntu-22.04, armv7-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-mips, ubuntu-22.04, mips-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-mipsel, ubuntu-22.04, mipsel-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-x86_64, ubuntu-22.04, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (windows-arm64, windows-latest, aarch64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / build (windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / core-result (push) Blocked by required conditions
EasyTier GUI / pre_job (push) Waiting to run
EasyTier GUI / build-gui (linux-aarch64, aarch64-unknown-linux-gnu, ubuntu-22.04, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (linux-x86_64, x86_64-unknown-linux-gnu, ubuntu-22.04, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-aarch64, aarch64-apple-darwin, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-x86_64, x86_64-apple-darwin, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-arm64, aarch64-pc-windows-msvc, windows-latest, aarch64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-x86_64, x86_64-pc-windows-msvc, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / gui-result (push) Blocked by required conditions
EasyTier Mobile / pre_job (push) Waiting to run
EasyTier Mobile / build-mobile (android, ubuntu-22.04, android) (push) Blocked by required conditions
EasyTier Mobile / mobile-result (push) Blocked by required conditions
EasyTier Test / pre_job (push) Waiting to run
EasyTier Test / test (push) Blocked by required conditions

* support proxy tcp stream with kcp to improve experience of tcp over udp
* update rust version
* make subnet proxy route metrics lower in windows.
This commit is contained in:
Sijie.Sun
2025-01-26 00:41:15 +08:00
committed by GitHub
parent 1194ee1c2d
commit 55a39491cb
19 changed files with 723 additions and 164 deletions

View File

@@ -114,6 +114,9 @@ jobs:
if: ${{ ! endsWith(matrix.TARGET, 'freebsd') }} if: ${{ ! endsWith(matrix.TARGET, 'freebsd') }}
run: | run: |
bash ./.github/workflows/install_rust.sh bash ./.github/workflows/install_rust.sh
# 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 [[ $OS =~ ^ubuntu.*$ && $TARGET =~ ^mips.*$ ]]; then 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 cargo +nightly build -r --verbose --target $TARGET -Z build-std=std,panic_abort --no-default-features --features mips --package=easytier
else else
@@ -142,14 +145,14 @@ jobs:
whoami whoami
env | sort env | sort
sudo pkg install -y git protobuf sudo pkg install -y git protobuf llvm-devel
curl --proto 'https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y curl --proto 'https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source $HOME/.cargo/env source $HOME/.cargo/env
rustup set auto-self-update disable rustup set auto-self-update disable
rustup install 1.77 rustup install 1.84
rustup default 1.77 rustup default 1.84
export CC=clang export CC=clang
export CXX=clang++ export CXX=clang++

View File

@@ -124,6 +124,20 @@ jobs:
# GitHub repo token to use to avoid rate limiter # GitHub repo token to use to avoid rate limiter
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install GUI dependencies (x86 only)
if: ${{ matrix.TARGET == 'x86_64-unknown-linux-musl' }}
run: |
sudo apt install -qq libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libgtk-3-dev \
librsvg2-dev \
libxdo-dev \
libssl-dev \
patchelf
- name: Install GUI cross compile (aarch64 only) - name: Install GUI cross compile (aarch64 only)
if: ${{ matrix.TARGET == 'aarch64-unknown-linux-musl' }} if: ${{ matrix.TARGET == 'aarch64-unknown-linux-musl' }}
run: | run: |

View File

@@ -8,20 +8,7 @@
# dependencies are only needed on ubuntu as that's the only place where # dependencies are only needed on ubuntu as that's the only place where
# we make cross-compilation # we make cross-compilation
if [[ $OS =~ ^ubuntu.*$ ]]; then if [[ $OS =~ ^ubuntu.*$ ]]; then
sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools libappindicator3-dev sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools libappindicator3-dev llvm clang
# for easytier-gui
if [[ $GUI_TARGET != '' && $GUI_TARGET =~ ^x86_64.*$ ]]; then
sudo apt install -qq libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libgtk-3-dev \
librsvg2-dev \
libxdo-dev \
libssl-dev \
patchelf
fi
# curl -s musl.cc | grep mipsel # curl -s musl.cc | grep mipsel
case $TARGET in case $TARGET in
mipsel-unknown-linux-musl) mipsel-unknown-linux-musl)
@@ -52,13 +39,14 @@ if [[ $OS =~ ^ubuntu.*$ ]]; then
wget -c https://musl.cc/${MUSL_URI}-cross.tgz -P ./musl_gcc/ wget -c https://musl.cc/${MUSL_URI}-cross.tgz -P ./musl_gcc/
tar zxf ./musl_gcc/${MUSL_URI}-cross.tgz -C ./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/bin/*gcc /usr/bin/
sudo ln -s $(pwd)/musl_gcc/${MUSL_URI}-cross/${MUSL_URI}/include/ /usr/include/musl-cross
fi fi
fi fi
# see https://github.com/rust-lang/rustup/issues/3709 # see https://github.com/rust-lang/rustup/issues/3709
rustup set auto-self-update disable rustup set auto-self-update disable
rustup install 1.77 rustup install 1.84
rustup default 1.77 rustup default 1.84
# mips/mipsel cannot add target from rustup, need compile by ourselves # mips/mipsel cannot add target from rustup, need compile by ourselves
if [[ $OS =~ ^ubuntu.*$ && $TARGET =~ ^mips.*$ ]]; then if [[ $OS =~ ^ubuntu.*$ && $TARGET =~ ^mips.*$ ]]; then

192
Cargo.lock generated
View File

@@ -183,9 +183,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.86" version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]] [[package]]
name = "approx" name = "approx"
@@ -506,9 +506,9 @@ dependencies = [
[[package]] [[package]]
name = "auto_impl" name = "auto_impl"
version = "1.2.0" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -684,6 +684,24 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "bindgen"
version = "0.71.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
dependencies = [
"bitflags 2.8.0",
"cexpr",
"clang-sys",
"itertools 0.11.0",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 2.0.87",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@@ -692,9 +710,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.6.0" version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@@ -955,7 +973,7 @@ version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"cairo-sys-rs", "cairo-sys-rs",
"glib", "glib",
"libc", "libc",
@@ -1018,9 +1036,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.1.12" version = "1.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68064e60dbf1f17005c2fde4d07c16d8baa506fd7ffed8ccab702d93617975c7" checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc", "libc",
@@ -1033,6 +1051,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]] [[package]]
name = "cfb" name = "cfb"
version = "0.7.3" version = "0.7.3"
@@ -1125,6 +1152,17 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading 0.8.5",
]
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.15" version = "4.5.15"
@@ -1183,7 +1221,7 @@ version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"block", "block",
"cocoa-foundation", "cocoa-foundation",
"core-foundation 0.10.0", "core-foundation 0.10.0",
@@ -1199,7 +1237,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d" checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"block", "block",
"core-foundation 0.10.0", "core-foundation 0.10.0",
"core-graphics-types 0.2.0", "core-graphics-types 0.2.0",
@@ -1335,7 +1373,7 @@ version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"core-foundation 0.10.0", "core-foundation 0.10.0",
"core-graphics-types 0.2.0", "core-graphics-types 0.2.0",
"foreign-types 0.5.0", "foreign-types 0.5.0",
@@ -1359,7 +1397,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"core-foundation 0.10.0", "core-foundation 0.10.0",
"libc", "libc",
] ]
@@ -1843,7 +1881,7 @@ dependencies = [
"atomicbox", "atomicbox",
"auto_impl", "auto_impl",
"base64 0.22.1", "base64 0.22.1",
"bitflags 2.6.0", "bitflags 2.8.0",
"boringtun-easytier", "boringtun-easytier",
"bytecodec", "bytecodec",
"byteorder", "byteorder",
@@ -1866,6 +1904,7 @@ dependencies = [
"http 1.1.0", "http 1.1.0",
"humansize", "humansize",
"indexmap 1.9.3", "indexmap 1.9.3",
"kcp-sys",
"machine-uid", "machine-uid",
"mimalloc-rust", "mimalloc-rust",
"network-interface", "network-interface",
@@ -2709,7 +2748,7 @@ version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-executor", "futures-executor",
@@ -3392,15 +3431,6 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.8" version = "0.4.8"
@@ -3518,13 +3548,35 @@ dependencies = [
"serde_json", "serde_json",
] ]
[[package]]
name = "kcp-sys"
version = "0.1.0"
source = "git+https://github.com/EasyTier/kcp-sys#a932f3ed394cad1ace9c56f90611b421d856e628"
dependencies = [
"anyhow",
"auto_impl",
"bindgen",
"bitflags 2.8.0",
"bytes",
"cc",
"dashmap",
"parking_lot",
"rand 0.8.5",
"thiserror 2.0.11",
"tokio",
"tokio-util",
"tracing",
"tracing-subscriber",
"zerocopy",
]
[[package]] [[package]]
name = "keyboard-types" name = "keyboard-types"
version = "0.7.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"serde", "serde",
"unicode-segmentation", "unicode-segmentation",
] ]
@@ -3613,7 +3665,7 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"libc", "libc",
] ]
@@ -3895,7 +3947,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"jni-sys", "jni-sys",
"log", "log",
"ndk-sys", "ndk-sys",
@@ -4029,7 +4081,7 @@ version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"cfg-if", "cfg-if",
"libc", "libc",
"memoffset", "memoffset",
@@ -4041,7 +4093,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"cfg-if", "cfg-if",
"cfg_aliases", "cfg_aliases",
"libc", "libc",
@@ -4250,7 +4302,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"block2", "block2",
"libc", "libc",
"objc2", "objc2",
@@ -4266,7 +4318,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"block2", "block2",
"objc2", "objc2",
"objc2-core-location", "objc2-core-location",
@@ -4290,7 +4342,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"block2", "block2",
"objc2", "objc2",
"objc2-foundation", "objc2-foundation",
@@ -4332,7 +4384,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"block2", "block2",
"dispatch", "dispatch",
"libc", "libc",
@@ -4357,7 +4409,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"block2", "block2",
"objc2", "objc2",
"objc2-foundation", "objc2-foundation",
@@ -4369,7 +4421,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"block2", "block2",
"objc2", "objc2",
"objc2-foundation", "objc2-foundation",
@@ -4392,7 +4444,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"block2", "block2",
"objc2", "objc2",
"objc2-cloud-kit", "objc2-cloud-kit",
@@ -4424,7 +4476,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"block2", "block2",
"objc2", "objc2",
"objc2-core-location", "objc2-core-location",
@@ -4437,7 +4489,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65" checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"block2", "block2",
"objc2", "objc2",
"objc2-app-kit", "objc2-app-kit",
@@ -4482,7 +4534,7 @@ version = "0.10.66"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"cfg-if", "cfg-if",
"foreign-types 0.3.2", "foreign-types 0.3.2",
"libc", "libc",
@@ -5288,7 +5340,7 @@ checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302"
dependencies = [ dependencies = [
"bytes", "bytes",
"heck 0.5.0", "heck 0.5.0",
"itertools 0.13.0", "itertools 0.11.0",
"log", "log",
"multimap", "multimap",
"once_cell", "once_cell",
@@ -5308,7 +5360,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"itertools 0.13.0", "itertools 0.11.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.87", "syn 2.0.87",
@@ -5556,7 +5608,7 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
] ]
[[package]] [[package]]
@@ -5942,9 +5994,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "2.0.0" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
@@ -5961,7 +6013,7 @@ version = "0.38.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
@@ -6332,7 +6384,7 @@ version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"core-foundation 0.9.4", "core-foundation 0.9.4",
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@@ -6716,9 +6768,9 @@ dependencies = [
[[package]] [[package]]
name = "smoltcp" name = "smoltcp"
version = "0.11.0" version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a1a996951e50b5971a2c8c0fa05a381480d70a933064245c4a223ddc87ccc97" checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"byteorder", "byteorder",
@@ -6924,7 +6976,7 @@ dependencies = [
"atoi", "atoi",
"base64 0.22.1", "base64 0.22.1",
"bigdecimal", "bigdecimal",
"bitflags 2.6.0", "bitflags 2.8.0",
"byteorder", "byteorder",
"bytes", "bytes",
"chrono", "chrono",
@@ -6971,7 +7023,7 @@ dependencies = [
"atoi", "atoi",
"base64 0.22.1", "base64 0.22.1",
"bigdecimal", "bigdecimal",
"bitflags 2.6.0", "bitflags 2.8.0",
"byteorder", "byteorder",
"chrono", "chrono",
"crc", "crc",
@@ -7257,7 +7309,7 @@ version = "0.30.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "833b4d43383d76d5078d72f3acd977f47eb5b6751eb40baa665d13828e7b79df" checksum = "833b4d43383d76d5078d72f3acd977f47eb5b6751eb40baa665d13828e7b79df"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"cocoa", "cocoa",
"core-foundation 0.10.0", "core-foundation 0.10.0",
"core-graphics 0.24.0", "core-graphics 0.24.0",
@@ -7406,7 +7458,7 @@ dependencies = [
"sha2", "sha2",
"syn 2.0.87", "syn 2.0.87",
"tauri-utils", "tauri-utils",
"thiserror 2.0.2", "thiserror 2.0.11",
"time", "time",
"url", "url",
"uuid", "uuid",
@@ -7637,7 +7689,7 @@ dependencies = [
"serde_json", "serde_json",
"serde_with", "serde_with",
"swift-rs", "swift-rs",
"thiserror 2.0.2", "thiserror 2.0.11",
"toml 0.8.19", "toml 0.8.19",
"url", "url",
"urlpattern", "urlpattern",
@@ -7706,11 +7758,11 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "2.0.2" version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037e29b009aa709f293b974da5cd33b15783c049e07f8435778ce8c4871525d8" checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
dependencies = [ dependencies = [
"thiserror-impl 2.0.2", "thiserror-impl 2.0.11",
] ]
[[package]] [[package]]
@@ -7726,9 +7778,9 @@ dependencies = [
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "2.0.2" version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea4778c7e8ff768bdb32a58a2349903859fe719a320300d7d4ce8636f19a1e69" checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -7885,9 +7937,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.7.11" version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-core", "futures-core",
@@ -8067,7 +8119,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97"
dependencies = [ dependencies = [
"async-compression", "async-compression",
"bitflags 2.6.0", "bitflags 2.8.0",
"bytes", "bytes",
"futures-core", "futures-core",
"http 1.1.0", "http 1.1.0",
@@ -8158,9 +8210,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.40" version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [ dependencies = [
"log", "log",
"pin-project-lite", "pin-project-lite",
@@ -8182,9 +8234,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-attributes" name = "tracing-attributes"
version = "0.1.27" version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -8193,9 +8245,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.32" version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"valuable", "valuable",
@@ -8214,9 +8266,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-subscriber" name = "tracing-subscriber"
version = "0.3.18" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
dependencies = [ dependencies = [
"matchers", "matchers",
"nu-ansi-term", "nu-ansi-term",
@@ -8962,7 +9014,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d24d6bcc7f734a4091ecf8d7a64c5f7d7066f45585c1861eba06449909609c8a" checksum = "d24d6bcc7f734a4091ecf8d7a64c5f7d7066f45585c1861eba06449909609c8a"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.8.0",
"widestring", "widestring",
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]

View File

@@ -8,7 +8,7 @@ repository = "https://github.com/EasyTier/EasyTier"
authors = ["kkrainbow"] authors = ["kkrainbow"]
keywords = ["vpn", "p2p", "network", "easytier"] keywords = ["vpn", "p2p", "network", "easytier"]
categories = ["network-programming", "command-line-utilities"] categories = ["network-programming", "command-line-utilities"]
rust-version = "1.77.0" rust-version = "1.84.0"
license-file = "LICENSE" license-file = "LICENSE"
readme = "README.md" readme = "README.md"

View File

@@ -8,7 +8,7 @@ edition = "2021"
authors = ["kkrainbow"] authors = ["kkrainbow"]
keywords = ["vpn", "p2p", "network", "easytier"] keywords = ["vpn", "p2p", "network", "easytier"]
categories = ["network-programming", "command-line-utilities"] categories = ["network-programming", "command-line-utilities"]
rust-version = "1.77.0" rust-version = "1.84.0"
license-file = "LICENSE" license-file = "LICENSE"
readme = "README.md" readme = "README.md"
@@ -163,12 +163,13 @@ indexmap = { version = "~1.9.3", optional = false, features = ["std"] }
atomic-shim = "0.2.0" atomic-shim = "0.2.0"
smoltcp = { version = "0.11.0", optional = true, default-features = false, features = [ smoltcp = { version = "0.12.0", optional = true, default-features = false, features = [
"std", "std",
"medium-ip", "medium-ip",
"proto-ipv4", "proto-ipv4",
"proto-ipv6", "proto-ipv6",
"socket-tcp", "socket-tcp",
"socket-tcp-cubic",
"async", "async",
] } ] }
parking_lot = { version = "0.12.0", optional = true } parking_lot = { version = "0.12.0", optional = true }
@@ -185,6 +186,8 @@ service-manager = {git = "https://github.com/chipsenkbeil/service-manager-rs.git
async-compression = { version = "0.4.17", default-features = false, features = ["zstd", "tokio"] } async-compression = { version = "0.4.17", default-features = false, features = ["zstd", "tokio"] }
kcp-sys = { git = "https://github.com/EasyTier/kcp-sys" }
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "freebsd"))'.dependencies] [target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "freebsd"))'.dependencies]
machine-uid = "0.5.3" machine-uid = "0.5.3"

View File

@@ -30,6 +30,9 @@ pub fn gen_default_flags() -> Flags {
multi_thread: true, multi_thread: true,
data_compress_algo: CompressionAlgoPb::None.into(), data_compress_algo: CompressionAlgoPb::None.into(),
bind_device: true, bind_device: true,
enable_kcp_proxy: false,
disable_kcp_input: true,
disable_relay_kcp: true,
} }
} }

View File

@@ -295,7 +295,7 @@ impl IfConfiguerTrait for WindowsIfConfiger {
}; };
run_shell_cmd( run_shell_cmd(
format!( format!(
"route ADD {} MASK {} 10.1.1.1 IF {} METRIC 255", "route ADD {} MASK {} 10.1.1.1 IF {} METRIC 9000",
address, address,
cidr_to_subnet_mask(cidr_prefix), cidr_to_subnet_mask(cidr_prefix),
idx idx

View File

@@ -313,6 +313,20 @@ struct Cli {
help = t!("core_clap.bind_device").to_string() help = t!("core_clap.bind_device").to_string()
)] )]
bind_device: Option<bool>, bind_device: Option<bool>,
#[arg(
long,
help = t!("core_clap.enable_kcp_proxy").to_string(),
default_value = "false"
)]
enable_kcp_proxy: bool,
#[arg(
long,
help = t!("core_clap.enable_kcp_proxy").to_string(),
default_value = "false"
)]
disable_kcp_input: bool,
} }
rust_i18n::i18n!("locales", fallback = "en"); rust_i18n::i18n!("locales", fallback = "en");
@@ -567,6 +581,8 @@ impl TryFrom<&Cli> for TomlConfigLoader {
if let Some(bind_device) = cli.bind_device { if let Some(bind_device) = cli.bind_device {
f.bind_device = bind_device; f.bind_device = bind_device;
} }
f.enable_kcp_proxy = cli.enable_kcp_proxy;
f.disable_kcp_input = cli.disable_kcp_input;
cfg.set_flags(f); cfg.set_flags(f);
cfg.set_exit_nodes(cli.exit_nodes.clone()); cfg.set_exit_nodes(cli.exit_nodes.clone());

View File

@@ -0,0 +1,315 @@
use std::{
net::{IpAddr, SocketAddr},
sync::Arc,
time::Duration,
};
use anyhow::Context;
use bytes::Bytes;
use kcp_sys::{
endpoint::{KcpEndpoint, KcpPacketReceiver},
packet_def::KcpPacket,
stream::KcpStream,
};
use pnet::packet::{ip::IpNextHeaderProtocols, ipv4::Ipv4Packet};
use prost::Message;
use tokio::{io::copy_bidirectional, task::JoinSet};
use super::{
tcp_proxy::{NatDstConnector, NatDstTcpConnector, TcpProxy},
CidrSet,
};
use crate::{
common::{
error::Result,
global_ctx::{ArcGlobalCtx, GlobalCtx},
},
peers::{peer_manager::PeerManager, NicPacketFilter, PeerPacketFilter},
proto::peer_rpc::KcpConnData,
tunnel::packet_def::{PacketType, PeerManagerHeader, ZCPacket},
};
struct KcpEndpointFilter {
kcp_endpoint: Arc<KcpEndpoint>,
is_src: bool,
}
#[async_trait::async_trait]
impl PeerPacketFilter for KcpEndpointFilter {
async fn try_process_packet_from_peer(&self, packet: ZCPacket) -> Option<ZCPacket> {
let t = packet.peer_manager_header().unwrap().packet_type;
if t == PacketType::KcpSrc as u8 && !self.is_src {
} else if t == PacketType::KcpDst as u8 && self.is_src {
} else {
return Some(packet);
}
let _ = self
.kcp_endpoint
.input_sender_ref()
.send(KcpPacket::from(packet.payload_bytes()))
.await;
None
}
}
#[tracing::instrument]
async fn handle_kcp_output(
peer_mgr: Arc<PeerManager>,
mut output_receiver: KcpPacketReceiver,
is_src: bool,
) {
while let Some(packet) = output_receiver.recv().await {
let dst_peer_id = if is_src {
packet.header().dst_session_id()
} else {
packet.header().src_session_id()
};
let packet_type = if is_src {
PacketType::KcpSrc as u8
} else {
PacketType::KcpDst as u8
};
let mut packet = ZCPacket::new_with_payload(&packet.inner().freeze());
packet.fill_peer_manager_hdr(peer_mgr.my_peer_id(), dst_peer_id, packet_type as u8);
if let Err(e) = peer_mgr.send_msg(packet, dst_peer_id).await {
tracing::error!("failed to send kcp packet to peer: {:?}", e);
}
}
}
#[derive(Debug, Clone)]
pub struct NatDstKcpConnector {
kcp_endpoint: Arc<KcpEndpoint>,
peer_mgr: Arc<PeerManager>,
}
#[async_trait::async_trait]
impl NatDstConnector for NatDstKcpConnector {
type DstStream = KcpStream;
async fn connect(&self, nat_dst: SocketAddr) -> Result<Self::DstStream> {
let conn_data = KcpConnData {
dst: Some(nat_dst.into()),
};
let (dst_peers, _) = match nat_dst {
SocketAddr::V4(addr) => {
let ip = addr.ip();
self.peer_mgr.get_msg_dst_peer(&ip).await
}
SocketAddr::V6(_) => return Err(anyhow::anyhow!("ipv6 is not supported").into()),
};
tracing::trace!("kcp nat dst: {:?}, dst peers: {:?}", nat_dst, dst_peers);
if dst_peers.len() != 1 {
return Err(anyhow::anyhow!("no dst peer found for nat dst: {}", nat_dst).into());
}
let ret = self
.kcp_endpoint
.connect(
Duration::from_secs(10),
self.peer_mgr.my_peer_id(),
dst_peers[0],
Bytes::from(conn_data.encode_to_vec()),
)
.await
.with_context(|| format!("failed to connect to nat dst: {}", nat_dst.to_string()))?;
let stream = KcpStream::new(&self.kcp_endpoint, ret)
.ok_or(anyhow::anyhow!("failed to create kcp stream"))?;
Ok(stream)
}
fn check_packet_from_peer_fast(&self, _cidr_set: &CidrSet, _global_ctx: &GlobalCtx) -> bool {
// if kcp is turned off, the filter will not be added to the pipeline
true
}
fn check_packet_from_peer(
&self,
_cidr_set: &CidrSet,
_global_ctx: &GlobalCtx,
_hdr: &PeerManagerHeader,
_ipv4: &Ipv4Packet,
) -> bool {
true
}
}
#[derive(Clone)]
struct TcpProxyForKcpSrc(Arc<TcpProxy<NatDstKcpConnector>>);
pub struct KcpProxySrc {
kcp_endpoint: Arc<KcpEndpoint>,
peer_manager: Arc<PeerManager>,
tcp_proxy: TcpProxyForKcpSrc,
tasks: JoinSet<()>,
}
#[async_trait::async_trait]
impl NicPacketFilter for TcpProxyForKcpSrc {
async fn try_process_packet_from_nic(&self, zc_packet: &mut ZCPacket) -> bool {
let ret = self.0.try_process_packet_from_nic(zc_packet).await;
if ret {
return true;
}
let Some(my_ipv4) = self.0.get_local_ip() else {
return false;
};
let data = zc_packet.payload();
let ip_packet = Ipv4Packet::new(data).unwrap();
if ip_packet.get_version() != 4
// TODO: how to support net to net kcp proxy?
|| ip_packet.get_source() != my_ipv4
|| ip_packet.get_next_level_protocol() != IpNextHeaderProtocols::Tcp
{
return false;
}
zc_packet.mut_peer_manager_header().unwrap().to_peer_id = self.0.get_my_peer_id().into();
true
}
}
impl KcpProxySrc {
pub async fn new(peer_manager: Arc<PeerManager>) -> Self {
let mut kcp_endpoint = KcpEndpoint::new();
kcp_endpoint.run().await;
let output_receiver = kcp_endpoint.output_receiver().unwrap();
let mut tasks = JoinSet::new();
tasks.spawn(handle_kcp_output(
peer_manager.clone(),
output_receiver,
true,
));
let kcp_endpoint = Arc::new(kcp_endpoint);
let tcp_proxy = TcpProxy::new(
peer_manager.clone(),
NatDstKcpConnector {
kcp_endpoint: kcp_endpoint.clone(),
peer_mgr: peer_manager.clone(),
},
);
Self {
kcp_endpoint,
peer_manager,
tcp_proxy: TcpProxyForKcpSrc(tcp_proxy),
tasks,
}
}
pub async fn start(&self) {
self.peer_manager
.add_nic_packet_process_pipeline(Box::new(self.tcp_proxy.clone()))
.await;
self.peer_manager
.add_packet_process_pipeline(Box::new(self.tcp_proxy.0.clone()))
.await;
self.peer_manager
.add_packet_process_pipeline(Box::new(KcpEndpointFilter {
kcp_endpoint: self.kcp_endpoint.clone(),
is_src: true,
}))
.await;
self.tcp_proxy.0.start(false).await.unwrap();
}
}
pub struct KcpProxyDst {
kcp_endpoint: Arc<KcpEndpoint>,
peer_manager: Arc<PeerManager>,
tasks: JoinSet<()>,
}
impl KcpProxyDst {
pub async fn new(peer_manager: Arc<PeerManager>) -> Self {
let mut kcp_endpoint = KcpEndpoint::new();
kcp_endpoint.run().await;
let mut tasks = JoinSet::new();
let output_receiver = kcp_endpoint.output_receiver().unwrap();
tasks.spawn(handle_kcp_output(
peer_manager.clone(),
output_receiver,
false,
));
Self {
kcp_endpoint: Arc::new(kcp_endpoint),
peer_manager,
tasks,
}
}
#[tracing::instrument(ret)]
async fn handle_one_in_stream(
mut kcp_stream: KcpStream,
global_ctx: ArcGlobalCtx,
) -> Result<()> {
let mut conn_data = kcp_stream.conn_data().clone();
let parsed_conn_data = KcpConnData::decode(&mut conn_data)
.with_context(|| format!("failed to decode kcp conn data: {:?}", conn_data))?;
let mut dst_socket: SocketAddr = parsed_conn_data
.dst
.ok_or(anyhow::anyhow!(
"failed to get dst socket from kcp conn data: {:?}",
parsed_conn_data
))?
.into();
if Some(dst_socket.ip()) == global_ctx.get_ipv4().map(|ip| IpAddr::V4(ip.address())) {
dst_socket = format!("127.0.0.1:{}", dst_socket.port()).parse().unwrap();
}
tracing::debug!("kcp connect to dst socket: {:?}", dst_socket);
let _g = global_ctx.net_ns.guard();
let connector = NatDstTcpConnector {};
let mut ret = connector.connect(dst_socket).await?;
copy_bidirectional(&mut ret, &mut kcp_stream).await?;
Ok(())
}
async fn run_accept_task(&mut self) {
let kcp_endpoint = self.kcp_endpoint.clone();
let global_ctx = self.peer_manager.get_global_ctx().clone();
self.tasks.spawn(async move {
while let Ok(conn) = kcp_endpoint.accept().await {
let stream = KcpStream::new(&kcp_endpoint, conn)
.ok_or(anyhow::anyhow!("failed to create kcp stream"))
.unwrap();
let global_ctx = global_ctx.clone();
tokio::spawn(async move {
let _ = Self::handle_one_in_stream(stream, global_ctx).await;
});
}
});
}
pub async fn start(&mut self) {
self.run_accept_task().await;
self.peer_manager
.add_packet_process_pipeline(Box::new(KcpEndpointFilter {
kcp_endpoint: self.kcp_endpoint.clone(),
is_src: false,
}))
.await;
}
}

View File

@@ -15,8 +15,10 @@ pub mod fast_socks5;
#[cfg(feature = "socks5")] #[cfg(feature = "socks5")]
pub mod socks5; pub mod socks5;
pub mod kcp_proxy;
#[derive(Debug)] #[derive(Debug)]
struct CidrSet { pub(crate) struct CidrSet {
global_ctx: ArcGlobalCtx, global_ctx: ArcGlobalCtx,
cidr_set: Arc<Mutex<Vec<cidr::IpCidr>>>, cidr_set: Arc<Mutex<Vec<cidr::IpCidr>>>,
tasks: JoinSet<()>, tasks: JoinSet<()>,

View File

@@ -1,3 +1,4 @@
use anyhow::Context;
use cidr::Ipv4Inet; use cidr::Ipv4Inet;
use core::panic; use core::panic;
use crossbeam::atomic::AtomicCell; use crossbeam::atomic::AtomicCell;
@@ -11,7 +12,7 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
use std::sync::atomic::{AtomicBool, AtomicU16}; use std::sync::atomic::{AtomicBool, AtomicU16};
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use tokio::io::copy_bidirectional; use tokio::io::{copy_bidirectional, AsyncRead, AsyncWrite};
use tokio::net::{TcpListener, TcpSocket, TcpStream}; use tokio::net::{TcpListener, TcpSocket, TcpStream};
use tokio::sync::{mpsc, Mutex}; use tokio::sync::{mpsc, Mutex};
use tokio::task::JoinSet; use tokio::task::JoinSet;
@@ -23,13 +24,74 @@ use crate::common::join_joinset_background;
use crate::peers::peer_manager::PeerManager; use crate::peers::peer_manager::PeerManager;
use crate::peers::{NicPacketFilter, PeerPacketFilter}; use crate::peers::{NicPacketFilter, PeerPacketFilter};
use crate::tunnel::packet_def::{PacketType, ZCPacket}; use crate::tunnel::packet_def::{PacketType, PeerManagerHeader, ZCPacket};
use super::CidrSet; use super::CidrSet;
#[cfg(feature = "smoltcp")] #[cfg(feature = "smoltcp")]
use super::tokio_smoltcp::{self, channel_device, Net, NetConfig}; use super::tokio_smoltcp::{self, channel_device, Net, NetConfig};
#[async_trait::async_trait]
pub(crate) trait NatDstConnector: Send + Sync + Clone + 'static {
type DstStream: AsyncRead + AsyncWrite + Unpin + Send;
async fn connect(&self, dst: SocketAddr) -> Result<Self::DstStream>;
fn check_packet_from_peer_fast(&self, cidr_set: &CidrSet, global_ctx: &GlobalCtx) -> bool;
fn check_packet_from_peer(
&self,
cidr_set: &CidrSet,
global_ctx: &GlobalCtx,
hdr: &PeerManagerHeader,
ipv4: &Ipv4Packet,
) -> bool;
}
#[derive(Debug, Clone)]
pub struct NatDstTcpConnector;
#[async_trait::async_trait]
impl NatDstConnector for NatDstTcpConnector {
type DstStream = TcpStream;
async fn connect(&self, nat_dst: SocketAddr) -> Result<Self::DstStream> {
let socket = TcpSocket::new_v4().unwrap();
if let Err(e) = socket.set_nodelay(true) {
tracing::warn!("set_nodelay failed, ignore it: {:?}", e);
}
Ok(
tokio::time::timeout(Duration::from_secs(10), socket.connect(nat_dst))
.await?
.with_context(|| format!("connect to nat dst failed: {:?}", nat_dst))?,
)
}
fn check_packet_from_peer_fast(&self, cidr_set: &CidrSet, global_ctx: &GlobalCtx) -> bool {
!cidr_set.is_empty() || global_ctx.enable_exit_node() || global_ctx.no_tun()
}
fn check_packet_from_peer(
&self,
cidr_set: &CidrSet,
global_ctx: &GlobalCtx,
hdr: &PeerManagerHeader,
ipv4: &Ipv4Packet,
) -> bool {
let is_exit_node = hdr.is_exit_node();
if !cidr_set.contains_v4(ipv4.get_destination())
&& !is_exit_node
&& !(global_ctx.no_tun()
&& Some(ipv4.get_destination())
== global_ctx.get_ipv4().as_ref().map(Ipv4Inet::address))
{
return false;
}
true
}
}
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
enum NatDstEntryState { enum NatDstEntryState {
// receive syn packet but not start connecting to dst // receive syn packet but not start connecting to dst
@@ -83,7 +145,10 @@ impl ProxyTcpStream {
} }
} }
pub async fn copy_bidirectional(&mut self, dst: &mut TcpStream) -> Result<()> { pub async fn copy_bidirectional<D: AsyncRead + AsyncWrite + Unpin>(
&mut self,
dst: &mut D,
) -> Result<()> {
match self { match self {
Self::KernelTcpStream(stream) => { Self::KernelTcpStream(stream) => {
copy_bidirectional(stream, dst).await?; copy_bidirectional(stream, dst).await?;
@@ -176,7 +241,7 @@ type ConnSockMap = Arc<DashMap<uuid::Uuid, ArcNatDstEntry>>;
type AddrConnSockMap = Arc<DashMap<SocketAddr, ArcNatDstEntry>>; type AddrConnSockMap = Arc<DashMap<SocketAddr, ArcNatDstEntry>>;
#[derive(Debug)] #[derive(Debug)]
pub struct TcpProxy { pub struct TcpProxy<C: NatDstConnector> {
global_ctx: Arc<GlobalCtx>, global_ctx: Arc<GlobalCtx>,
peer_manager: Arc<PeerManager>, peer_manager: Arc<PeerManager>,
local_port: AtomicU16, local_port: AtomicU16,
@@ -194,10 +259,12 @@ pub struct TcpProxy {
#[cfg(feature = "smoltcp")] #[cfg(feature = "smoltcp")]
smoltcp_net: Arc<Mutex<Option<Net>>>, smoltcp_net: Arc<Mutex<Option<Net>>>,
enable_smoltcp: Arc<AtomicBool>, enable_smoltcp: Arc<AtomicBool>,
connector: C,
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl PeerPacketFilter for TcpProxy { impl<C: NatDstConnector> PeerPacketFilter for TcpProxy<C> {
async fn try_process_packet_from_peer(&self, mut packet: ZCPacket) -> Option<ZCPacket> { async fn try_process_packet_from_peer(&self, mut packet: ZCPacket) -> Option<ZCPacket> {
if let Some(_) = self.try_handle_peer_packet(&mut packet).await { if let Some(_) = self.try_handle_peer_packet(&mut packet).await {
if self if self
@@ -221,10 +288,10 @@ impl PeerPacketFilter for TcpProxy {
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl NicPacketFilter for TcpProxy { impl<C: NatDstConnector> NicPacketFilter for TcpProxy<C> {
async fn try_process_packet_from_nic(&self, zc_packet: &mut ZCPacket) { async fn try_process_packet_from_nic(&self, zc_packet: &mut ZCPacket) -> bool {
let Some(my_ipv4) = self.get_local_ip() else { let Some(my_ipv4) = self.get_local_ip() else {
return; return false;
}; };
let data = zc_packet.payload(); let data = zc_packet.payload();
@@ -233,25 +300,33 @@ impl NicPacketFilter for TcpProxy {
|| ip_packet.get_source() != my_ipv4 || ip_packet.get_source() != my_ipv4
|| ip_packet.get_next_level_protocol() != IpNextHeaderProtocols::Tcp || ip_packet.get_next_level_protocol() != IpNextHeaderProtocols::Tcp
{ {
return; return false;
} }
let tcp_packet = TcpPacket::new(ip_packet.payload()).unwrap(); let tcp_packet = TcpPacket::new(ip_packet.payload()).unwrap();
if tcp_packet.get_source() != self.get_local_port() { if tcp_packet.get_source() != self.get_local_port() {
return; return false;
} }
let dst_addr = SocketAddr::V4(SocketAddrV4::new( let mut dst_addr = SocketAddr::V4(SocketAddrV4::new(
ip_packet.get_destination(), ip_packet.get_destination(),
tcp_packet.get_destination(), tcp_packet.get_destination(),
)); ));
let mut need_transform_dst = false;
// for kcp proxy, the src ip of nat entry will be converted from my ip to fake ip
// here we need to convert it back
if !self.is_smoltcp_enabled() && dst_addr.ip() == Self::get_fake_local_ipv4(my_ipv4) {
dst_addr.set_ip(IpAddr::V4(my_ipv4));
need_transform_dst = true;
}
tracing::trace!(dst_addr = ?dst_addr, "tcp packet try find entry"); tracing::trace!(dst_addr = ?dst_addr, "tcp packet try find entry");
let entry = if let Some(entry) = self.addr_conn_map.get(&dst_addr) { let entry = if let Some(entry) = self.addr_conn_map.get(&dst_addr) {
entry entry
} else { } else {
let Some(syn_entry) = self.syn_map.get(&dst_addr) else { let Some(syn_entry) = self.syn_map.get(&dst_addr) else {
return; return false;
}; };
syn_entry syn_entry
}; };
@@ -267,9 +342,15 @@ impl NicPacketFilter for TcpProxy {
.mut_peer_manager_header() .mut_peer_manager_header()
.unwrap() .unwrap()
.set_no_proxy(true); .set_no_proxy(true);
if need_transform_dst {
zc_packet.mut_peer_manager_header().unwrap().to_peer_id = self.get_my_peer_id().into();
}
let mut ip_packet = MutableIpv4Packet::new(zc_packet.mut_payload()).unwrap(); let mut ip_packet = MutableIpv4Packet::new(zc_packet.mut_payload()).unwrap();
ip_packet.set_source(ip); ip_packet.set_source(ip);
if need_transform_dst {
ip_packet.set_destination(my_ipv4);
}
let dst = ip_packet.get_destination(); let dst = ip_packet.get_destination();
let mut tcp_packet = MutableTcpPacket::new(ip_packet.payload_mut()).unwrap(); let mut tcp_packet = MutableTcpPacket::new(ip_packet.payload_mut()).unwrap();
@@ -280,12 +361,15 @@ impl NicPacketFilter for TcpProxy {
Self::update_ip_packet_checksum(&mut ip_packet); Self::update_ip_packet_checksum(&mut ip_packet);
tracing::trace!(dst_addr = ?dst_addr, nat_entry = ?nat_entry, packet = ?ip_packet, "tcp packet after modified"); tracing::trace!(dst_addr = ?dst_addr, nat_entry = ?nat_entry, packet = ?ip_packet, "tcp packet after modified");
true
} }
} }
impl TcpProxy { impl<C: NatDstConnector> TcpProxy<C> {
pub fn new(global_ctx: Arc<GlobalCtx>, peer_manager: Arc<PeerManager>) -> Arc<Self> { pub fn new(peer_manager: Arc<PeerManager>, connector: C) -> Arc<Self> {
let (smoltcp_stack_sender, smoltcp_stack_receiver) = mpsc::channel::<ZCPacket>(1000); let (smoltcp_stack_sender, smoltcp_stack_receiver) = mpsc::channel::<ZCPacket>(1000);
let global_ctx = peer_manager.get_global_ctx();
Arc::new(Self { Arc::new(Self {
global_ctx: global_ctx.clone(), global_ctx: global_ctx.clone(),
@@ -307,6 +391,8 @@ impl TcpProxy {
smoltcp_net: Arc::new(Mutex::new(None)), smoltcp_net: Arc::new(Mutex::new(None)),
enable_smoltcp: Arc::new(AtomicBool::new(true)), enable_smoltcp: Arc::new(AtomicBool::new(true)),
connector,
}) })
} }
@@ -326,15 +412,17 @@ impl TcpProxy {
ip_packet.set_checksum(pnet::packet::ipv4::checksum(&ip_packet.to_immutable())); ip_packet.set_checksum(pnet::packet::ipv4::checksum(&ip_packet.to_immutable()));
} }
pub async fn start(self: &Arc<Self>) -> Result<()> { pub async fn start(self: &Arc<Self>, add_pipeline: bool) -> Result<()> {
self.run_syn_map_cleaner().await?; self.run_syn_map_cleaner().await?;
self.run_listener().await?; self.run_listener().await?;
self.peer_manager if add_pipeline {
.add_packet_process_pipeline(Box::new(self.clone())) self.peer_manager
.await; .add_packet_process_pipeline(Box::new(self.clone()))
self.peer_manager .await;
.add_nic_packet_process_pipeline(Box::new(self.clone())) self.peer_manager
.await; .add_nic_packet_process_pipeline(Box::new(self.clone()))
.await;
}
join_joinset_background(self.tasks.clone(), "TcpProxy".to_owned()); join_joinset_background(self.tasks.clone(), "TcpProxy".to_owned());
Ok(()) Ok(())
@@ -458,11 +546,26 @@ impl TcpProxy {
let syn_map = self.syn_map.clone(); let syn_map = self.syn_map.clone();
let conn_map = self.conn_map.clone(); let conn_map = self.conn_map.clone();
let addr_conn_map = self.addr_conn_map.clone(); let addr_conn_map = self.addr_conn_map.clone();
let connector = self.connector.clone();
let accept_task = async move { let accept_task = async move {
let conn_map = conn_map.clone(); let conn_map = conn_map.clone();
while let Ok((tcp_stream, socket_addr)) = tcp_listener.accept().await { while let Ok((tcp_stream, mut socket_addr)) = tcp_listener.accept().await {
let my_ip = global_ctx
.get_ipv4()
.as_ref()
.map(Ipv4Inet::address)
.unwrap_or(Ipv4Addr::UNSPECIFIED);
if socket_addr.ip() == Self::get_fake_local_ipv4(my_ip) {
socket_addr.set_ip(IpAddr::V4(my_ip));
}
let Some(entry) = syn_map.get(&socket_addr) else { let Some(entry) = syn_map.get(&socket_addr) else {
tracing::error!("tcp connection from unknown source: {:?}", socket_addr); tracing::error!(
?my_ip,
?socket_addr,
"tcp connection from unknown source, ignore it"
);
continue; continue;
}; };
tracing::info!( tracing::info!(
@@ -483,6 +586,7 @@ impl TcpProxy {
assert!(old_nat_val.is_none()); assert!(old_nat_val.is_none());
tasks.lock().unwrap().spawn(Self::connect_to_nat_dst( tasks.lock().unwrap().spawn(Self::connect_to_nat_dst(
connector.clone(),
global_ctx.clone(), global_ctx.clone(),
tcp_stream, tcp_stream,
conn_map.clone(), conn_map.clone(),
@@ -511,6 +615,7 @@ impl TcpProxy {
} }
async fn connect_to_nat_dst( async fn connect_to_nat_dst(
connector: C,
global_ctx: ArcGlobalCtx, global_ctx: ArcGlobalCtx,
src_tcp_stream: ProxyTcpStream, src_tcp_stream: ProxyTcpStream,
conn_map: ConnSockMap, conn_map: ConnSockMap,
@@ -521,12 +626,6 @@ impl TcpProxy {
tracing::warn!("set_nodelay failed, ignore it: {:?}", e); tracing::warn!("set_nodelay failed, ignore it: {:?}", e);
} }
let _guard = global_ctx.net_ns.guard();
let socket = TcpSocket::new_v4().unwrap();
if let Err(e) = socket.set_nodelay(true) {
tracing::warn!("set_nodelay failed, ignore it: {:?}", e);
}
let nat_dst = if Some(nat_entry.dst.ip()) let nat_dst = if Some(nat_entry.dst.ip())
== global_ctx.get_ipv4().map(|ip| IpAddr::V4(ip.address())) == global_ctx.get_ipv4().map(|ip| IpAddr::V4(ip.address()))
{ {
@@ -537,12 +636,8 @@ impl TcpProxy {
nat_entry.dst nat_entry.dst
}; };
let Ok(Ok(dst_tcp_stream)) = tokio::time::timeout( let _guard = global_ctx.net_ns.guard();
Duration::from_secs(10), let Ok(dst_tcp_stream) = connector.connect(nat_dst).await else {
TcpSocket::new_v4().unwrap().connect(nat_dst),
)
.await
else {
tracing::error!("connect to dst failed: {:?}", nat_entry); tracing::error!("connect to dst failed: {:?}", nat_entry);
nat_entry.state.store(NatDstEntryState::Closed); nat_entry.state.store(NatDstEntryState::Closed);
Self::remove_entry_from_all_conn_map(conn_map, addr_conn_map, nat_entry); Self::remove_entry_from_all_conn_map(conn_map, addr_conn_map, nat_entry);
@@ -567,7 +662,7 @@ impl TcpProxy {
async fn handle_nat_connection( async fn handle_nat_connection(
mut src_tcp_stream: ProxyTcpStream, mut src_tcp_stream: ProxyTcpStream,
mut dst_tcp_stream: TcpStream, mut dst_tcp_stream: C::DstStream,
conn_map: ConnSockMap, conn_map: ConnSockMap,
addr_conn_map: AddrConnSockMap, addr_conn_map: AddrConnSockMap,
nat_entry: ArcNatDstEntry, nat_entry: ArcNatDstEntry,
@@ -577,6 +672,10 @@ impl TcpProxy {
let ret = src_tcp_stream.copy_bidirectional(&mut dst_tcp_stream).await; let ret = src_tcp_stream.copy_bidirectional(&mut dst_tcp_stream).await;
tracing::info!(nat_entry = ?nat_entry_clone, ret = ?ret, "nat tcp connection closed"); tracing::info!(nat_entry = ?nat_entry_clone, ret = ?ret, "nat tcp connection closed");
nat_entry_clone.state.store(NatDstEntryState::Closed); nat_entry_clone.state.store(NatDstEntryState::Closed);
drop(src_tcp_stream);
// sleep later so the fin packet can be processed
tokio::time::sleep(Duration::from_secs(10)).await;
Self::remove_entry_from_all_conn_map(conn_map, addr_conn_map, nat_entry_clone); Self::remove_entry_from_all_conn_map(conn_map, addr_conn_map, nat_entry_clone);
}); });
@@ -586,11 +685,12 @@ impl TcpProxy {
self.local_port.load(std::sync::atomic::Ordering::Relaxed) self.local_port.load(std::sync::atomic::Ordering::Relaxed)
} }
pub fn get_my_peer_id(&self) -> u32 {
self.peer_manager.my_peer_id()
}
pub fn get_local_ip(&self) -> Option<Ipv4Addr> { pub fn get_local_ip(&self) -> Option<Ipv4Addr> {
if self if self.is_smoltcp_enabled() {
.enable_smoltcp
.load(std::sync::atomic::Ordering::Relaxed)
{
Some(Ipv4Addr::new(192, 88, 99, 254)) Some(Ipv4Addr::new(192, 88, 99, 254))
} else { } else {
self.global_ctx self.global_ctx
@@ -600,17 +700,26 @@ impl TcpProxy {
} }
} }
pub fn is_smoltcp_enabled(&self) -> bool {
self.enable_smoltcp
.load(std::sync::atomic::Ordering::Relaxed)
}
pub fn get_fake_local_ipv4(local_ip: Ipv4Addr) -> Ipv4Addr {
let octets = local_ip.octets();
Ipv4Addr::new(octets[0], octets[1], octets[2], 0)
}
async fn try_handle_peer_packet(&self, packet: &mut ZCPacket) -> Option<()> { async fn try_handle_peer_packet(&self, packet: &mut ZCPacket) -> Option<()> {
if self.cidr_set.is_empty() if !self
&& !self.global_ctx.enable_exit_node() .connector
&& !self.global_ctx.no_tun() .check_packet_from_peer_fast(&self.cidr_set, &self.global_ctx)
{ {
return None; return None;
} }
let ipv4_addr = self.get_local_ip()?; let ipv4_addr = self.get_local_ip()?;
let hdr = packet.peer_manager_header().unwrap(); let hdr = packet.peer_manager_header().unwrap().clone();
let is_exit_node = hdr.is_exit_node();
if hdr.packet_type != PacketType::Data as u8 || hdr.is_no_proxy() { if hdr.packet_type != PacketType::Data as u8 || hdr.is_no_proxy() {
return None; return None;
@@ -623,11 +732,9 @@ impl TcpProxy {
return None; return None;
} }
if !self.cidr_set.contains_v4(ipv4.get_destination()) if !self
&& !is_exit_node .connector
&& !(self.global_ctx.no_tun() .check_packet_from_peer(&self.cidr_set, &self.global_ctx, &hdr, &ipv4)
&& Some(ipv4.get_destination())
== self.global_ctx.get_ipv4().as_ref().map(Ipv4Inet::address))
{ {
return None; return None;
} }
@@ -658,6 +765,10 @@ impl TcpProxy {
} }
let mut ip_packet = MutableIpv4Packet::new(payload_bytes).unwrap(); let mut ip_packet = MutableIpv4Packet::new(payload_bytes).unwrap();
if !self.is_smoltcp_enabled() && source_ip == ipv4_addr {
// modify the source so the response packet can be handled by tun device
ip_packet.set_source(Self::get_fake_local_ipv4(ipv4_addr));
}
ip_packet.set_destination(ipv4_addr); ip_packet.set_destination(ipv4_addr);
let source = ip_packet.get_source(); let source = ip_packet.get_source();

View File

@@ -43,7 +43,7 @@ pub struct BufferRxToken(Packet);
impl RxToken for BufferRxToken { impl RxToken for BufferRxToken {
fn consume<R, F>(mut self, f: F) -> R fn consume<R, F>(mut self, f: F) -> R
where where
F: FnOnce(&mut [u8]) -> R, F: FnOnce(&[u8]) -> R,
{ {
let p = &mut self.0; let p = &mut self.0;
let result = f(p); let result = f(p);

View File

@@ -17,7 +17,8 @@ use crate::connector::direct::DirectConnectorManager;
use crate::connector::manual::{ConnectorManagerRpcService, ManualConnectorManager}; use crate::connector::manual::{ConnectorManagerRpcService, ManualConnectorManager};
use crate::connector::udp_hole_punch::UdpHolePunchConnector; use crate::connector::udp_hole_punch::UdpHolePunchConnector;
use crate::gateway::icmp_proxy::IcmpProxy; use crate::gateway::icmp_proxy::IcmpProxy;
use crate::gateway::tcp_proxy::TcpProxy; use crate::gateway::kcp_proxy::{KcpProxyDst, KcpProxySrc};
use crate::gateway::tcp_proxy::{NatDstTcpConnector, TcpProxy};
use crate::gateway::udp_proxy::UdpProxy; use crate::gateway::udp_proxy::UdpProxy;
use crate::peer_center::instance::PeerCenterInstance; use crate::peer_center::instance::PeerCenterInstance;
use crate::peers::peer_conn::PeerConnId; use crate::peers::peer_conn::PeerConnId;
@@ -40,7 +41,7 @@ use crate::gateway::socks5::Socks5Server;
#[derive(Clone)] #[derive(Clone)]
struct IpProxy { struct IpProxy {
tcp_proxy: Arc<TcpProxy>, tcp_proxy: Arc<TcpProxy<NatDstTcpConnector>>,
icmp_proxy: Arc<IcmpProxy>, icmp_proxy: Arc<IcmpProxy>,
udp_proxy: Arc<UdpProxy>, udp_proxy: Arc<UdpProxy>,
global_ctx: ArcGlobalCtx, global_ctx: ArcGlobalCtx,
@@ -49,7 +50,7 @@ struct IpProxy {
impl IpProxy { impl IpProxy {
fn new(global_ctx: ArcGlobalCtx, peer_manager: Arc<PeerManager>) -> Result<Self, Error> { fn new(global_ctx: ArcGlobalCtx, peer_manager: Arc<PeerManager>) -> Result<Self, Error> {
let tcp_proxy = TcpProxy::new(global_ctx.clone(), peer_manager.clone()); let tcp_proxy = TcpProxy::new(peer_manager.clone(), NatDstTcpConnector {});
let icmp_proxy = IcmpProxy::new(global_ctx.clone(), peer_manager.clone()) let icmp_proxy = IcmpProxy::new(global_ctx.clone(), peer_manager.clone())
.with_context(|| "create icmp proxy failed")?; .with_context(|| "create icmp proxy failed")?;
let udp_proxy = UdpProxy::new(global_ctx.clone(), peer_manager.clone()) let udp_proxy = UdpProxy::new(global_ctx.clone(), peer_manager.clone())
@@ -72,7 +73,7 @@ impl IpProxy {
} }
self.started.store(true, Ordering::Relaxed); self.started.store(true, Ordering::Relaxed);
self.tcp_proxy.start().await?; self.tcp_proxy.start(true).await?;
self.icmp_proxy.start().await?; self.icmp_proxy.start().await?;
self.udp_proxy.start().await?; self.udp_proxy.start().await?;
Ok(()) Ok(())
@@ -116,6 +117,9 @@ pub struct Instance {
ip_proxy: Option<IpProxy>, ip_proxy: Option<IpProxy>,
kcp_proxy_src: Option<KcpProxySrc>,
kcp_proxy_dst: Option<KcpProxyDst>,
peer_center: Arc<PeerCenterInstance>, peer_center: Arc<PeerCenterInstance>,
vpn_portal: Arc<Mutex<Box<dyn VpnPortal>>>, vpn_portal: Arc<Mutex<Box<dyn VpnPortal>>>,
@@ -193,6 +197,8 @@ impl Instance {
udp_hole_puncher: Arc::new(Mutex::new(udp_hole_puncher)), udp_hole_puncher: Arc::new(Mutex::new(udp_hole_puncher)),
ip_proxy: None, ip_proxy: None,
kcp_proxy_src: None,
kcp_proxy_dst: None,
peer_center, peer_center,
@@ -383,6 +389,18 @@ impl Instance {
)?); )?);
self.run_ip_proxy().await?; self.run_ip_proxy().await?;
if self.global_ctx.get_flags().enable_kcp_proxy {
let src_proxy = KcpProxySrc::new(self.get_peer_manager()).await;
src_proxy.start().await;
self.kcp_proxy_src = Some(src_proxy);
}
if !self.global_ctx.get_flags().disable_kcp_input {
let mut dst_proxy = KcpProxyDst::new(self.get_peer_manager()).await;
dst_proxy.start().await;
self.kcp_proxy_dst = Some(dst_proxy);
}
self.udp_hole_puncher.lock().await.run().await?; self.udp_hole_puncher.lock().await.run().await?;
self.peer_center.init().await; self.peer_center.init().await;

View File

@@ -33,7 +33,7 @@ pub trait PeerPacketFilter {
#[async_trait::async_trait] #[async_trait::async_trait]
#[auto_impl::auto_impl(Arc)] #[auto_impl::auto_impl(Arc)]
pub trait NicPacketFilter { pub trait NicPacketFilter {
async fn try_process_packet_from_nic(&self, data: &mut ZCPacket); async fn try_process_packet_from_nic(&self, data: &mut ZCPacket) -> bool;
} }
type BoxPeerPacketFilter = Box<dyn PeerPacketFilter + Send + Sync>; type BoxPeerPacketFilter = Box<dyn PeerPacketFilter + Send + Sync>;

View File

@@ -675,7 +675,7 @@ impl PeerManager {
async fn run_nic_packet_process_pipeline(&self, data: &mut ZCPacket) { async fn run_nic_packet_process_pipeline(&self, data: &mut ZCPacket) {
for pipeline in self.nic_packet_process_pipeline.read().await.iter().rev() { for pipeline in self.nic_packet_process_pipeline.read().await.iter().rev() {
pipeline.try_process_packet_from_nic(data).await; let _ = pipeline.try_process_packet_from_nic(data).await;
} }
} }
@@ -722,13 +722,7 @@ impl PeerManager {
} }
} }
pub async fn send_msg_ipv4(&self, mut msg: ZCPacket, ipv4_addr: Ipv4Addr) -> Result<(), Error> { pub async fn get_msg_dst_peer(&self, ipv4_addr: &Ipv4Addr) -> (Vec<PeerId>, bool) {
tracing::trace!(
"do send_msg in peer manager, msg: {:?}, ipv4_addr: {}",
msg,
ipv4_addr
);
let mut is_exit_node = false; let mut is_exit_node = false;
let mut dst_peers = vec![]; let mut dst_peers = vec![];
let network_length = self let network_length = self
@@ -736,10 +730,10 @@ impl PeerManager {
.get_ipv4() .get_ipv4()
.map(|x| x.network_length()) .map(|x| x.network_length())
.unwrap_or(24); .unwrap_or(24);
let ipv4_inet = cidr::Ipv4Inet::new(ipv4_addr, network_length).unwrap(); let ipv4_inet = cidr::Ipv4Inet::new(*ipv4_addr, network_length).unwrap();
if ipv4_addr.is_broadcast() if ipv4_addr.is_broadcast()
|| ipv4_addr.is_multicast() || ipv4_addr.is_multicast()
|| ipv4_addr == ipv4_inet.last_address() || *ipv4_addr == ipv4_inet.last_address()
{ {
dst_peers.extend( dst_peers.extend(
self.peers self.peers
@@ -760,10 +754,15 @@ impl PeerManager {
} }
} }
if dst_peers.is_empty() { (dst_peers, is_exit_node)
tracing::info!("no peer id for ipv4: {}", ipv4_addr); }
return Ok(());
} pub async fn send_msg_ipv4(&self, mut msg: ZCPacket, ipv4_addr: Ipv4Addr) -> Result<(), Error> {
tracing::trace!(
"do send_msg in peer manager, msg: {:?}, ipv4_addr: {}",
msg,
ipv4_addr
);
msg.fill_peer_manager_hdr( msg.fill_peer_manager_hdr(
self.my_peer_id, self.my_peer_id,
@@ -771,6 +770,24 @@ impl PeerManager {
tunnel::packet_def::PacketType::Data as u8, tunnel::packet_def::PacketType::Data as u8,
); );
self.run_nic_packet_process_pipeline(&mut msg).await; self.run_nic_packet_process_pipeline(&mut msg).await;
let cur_to_peer_id = msg.peer_manager_header().unwrap().to_peer_id.into();
if cur_to_peer_id != 0 {
return Self::send_msg_internal(
&self.peers,
&self.foreign_network_client,
msg,
cur_to_peer_id,
)
.await;
}
let (dst_peers, is_exit_node) = self.get_msg_dst_peer(&ipv4_addr).await;
if dst_peers.is_empty() {
tracing::info!("no peer id for ipv4: {}", ipv4_addr);
return Ok(());
}
let compressor = DefaultCompressor {}; let compressor = DefaultCompressor {};
compressor compressor
.compress(&mut msg, self.data_compress_algo) .compress(&mut msg, self.data_compress_algo)

View File

@@ -22,6 +22,13 @@ message FlagsInConfig {
bool multi_thread = 15; bool multi_thread = 15;
CompressionAlgoPb data_compress_algo = 16; CompressionAlgoPb data_compress_algo = 16;
bool bind_device = 17; bool bind_device = 17;
// should we convert all tcp streams into kcp streams
bool enable_kcp_proxy = 18;
// does this peer allow kcp input
bool disable_kcp_input = 19;
// allow relay kcp packets (for public server, this can reduce the throughput)
bool disable_relay_kcp = 20;
} }
message RpcDescriptor { message RpcDescriptor {

View File

@@ -205,3 +205,7 @@ message HandshakeRequest {
string network_name = 5; string network_name = 5;
bytes network_secret_digrest = 6; bytes network_secret_digrest = 6;
} }
message KcpConnData {
common.SocketAddr dst = 4;
}

View File

@@ -61,6 +61,8 @@ pub enum PacketType {
RpcReq = 8, RpcReq = 8,
RpcResp = 9, RpcResp = 9,
ForeignNetworkPacket = 10, ForeignNetworkPacket = 10,
KcpSrc = 11,
KcpDst = 12,
} }
bitflags::bitflags! { bitflags::bitflags! {
@@ -494,6 +496,10 @@ impl ZCPacket {
&self.inner[self.payload_offset()..] &self.inner[self.payload_offset()..]
} }
pub fn payload_bytes(mut self) -> BytesMut {
self.inner.split_off(self.payload_offset())
}
pub fn peer_manager_header(&self) -> Option<&PeerManagerHeader> { pub fn peer_manager_header(&self) -> Option<&PeerManagerHeader> {
PeerManagerHeader::ref_from_prefix( PeerManagerHeader::ref_from_prefix(
&self.inner[self &self.inner[self