Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
073fa6ac6b | ||
|
|
51315efb52 | ||
|
|
30cbf39e7f | ||
|
|
2973d88df3 | ||
|
|
8b2d7293fe | ||
|
|
215d9aa362 | ||
|
|
c3f27e8727 | ||
|
|
755339189d | ||
|
|
71cf0aa66d | ||
|
|
d695efd787 | ||
|
|
66129c2a24 | ||
|
|
0bc7115102 | ||
|
|
dca33a3ec1 | ||
|
|
9acbae2554 | ||
|
|
ccfff7b1f6 | ||
|
|
39ae4c5dd6 | ||
|
|
350357076d | ||
|
|
1e5e15f1f5 | ||
|
|
1a385a777e | ||
|
|
16278dae62 | ||
|
|
8294e46003 | ||
|
|
dedc66875b |
@@ -108,7 +108,7 @@ jobs:
|
||||
rustup set auto-self-update disable
|
||||
|
||||
if [[ $OS =~ ^ubuntu.*$ ]]; then
|
||||
sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools
|
||||
sudo apt-get update && sudo apt-get install clang llvm libc6-dev-i386 crossbuild-essential-arm64 crossbuild-essential-armhf musl-tools libboost-all-dev libc6-dev -y
|
||||
# curl -s musl.cc | grep mipsel
|
||||
case $TARGET in
|
||||
mipsel-unknown-linux-musl)
|
||||
@@ -193,7 +193,9 @@ jobs:
|
||||
EOF
|
||||
- name: Install rust target
|
||||
run: rustup target add $TARGET
|
||||
- name: Run build
|
||||
- name: Run build vn-link-cli
|
||||
run: cargo build --package vn-link-cli --release --verbose --target $TARGET --features $FEATURES
|
||||
- name: Run build vnt-cli
|
||||
run: cargo build --package vnt-cli --release --verbose --target $TARGET --features $FEATURES
|
||||
- name: List target
|
||||
run: find ./target
|
||||
@@ -202,17 +204,22 @@ jobs:
|
||||
mkdir -p ./artifacts
|
||||
# windows is the only OS using a different convention for executable file name
|
||||
if [[ $OS =~ ^windows.*$ ]]; then
|
||||
EXEC=$NAME.exe
|
||||
EXEC_VNT_CLI=vnt-cli.exe
|
||||
EXEC_VN_LINK_CLI=vn-link-cli.exe
|
||||
else
|
||||
EXEC=$NAME
|
||||
EXEC_VNT_CLI=vnt-cli
|
||||
EXEC_VN_LINK_CLI=vn-link-cli
|
||||
fi
|
||||
if [[ $GITHUB_REF_TYPE =~ ^tag$ ]]; then
|
||||
TAG=$GITHUB_REF_NAME
|
||||
else
|
||||
TAG=$GITHUB_SHA
|
||||
fi
|
||||
mv ./target/$TARGET/release/$EXEC ./artifacts/$EXEC
|
||||
tar -czf ./artifacts/$NAME-$TARGET-$TAG.tar.gz -C ./artifacts $EXEC
|
||||
mv ./target/$TARGET/release/$EXEC_VNT_CLI ./artifacts/$EXEC_VNT_CLI
|
||||
mv ./target/$TARGET/release/$EXEC_VN_LINK_CLI ./artifacts/$EXEC_VN_LINK_CLI
|
||||
mv ./README ./artifacts/README
|
||||
cd ./artifacts
|
||||
tar -czf vnt-$TARGET-$TAG.tar.gz *
|
||||
- name: Archive artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
target/*
|
||||
vnt/src/proto/*
|
||||
vnt-cli/src/generated_serial_number.rs
|
||||
common/src/generated_serial_number.rs
|
||||
Generated
+190
-192
@@ -67,24 +67,6 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_log-sys"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937"
|
||||
|
||||
[[package]]
|
||||
name = "android_logger"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f"
|
||||
dependencies = [
|
||||
"android_log-sys",
|
||||
"env_logger",
|
||||
"log",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
@@ -133,6 +115,29 @@ version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.69.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn 2.0.60",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -192,19 +197,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.94"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
|
||||
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cesu8"
|
||||
version = "1.1.0"
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -268,18 +277,33 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
name = "clang-sys"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "1.2.10"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"console",
|
||||
"gethostname",
|
||||
"getopts",
|
||||
"log",
|
||||
"log4rs",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"uuid",
|
||||
"vnt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
@@ -315,6 +339,38 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-queue",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
@@ -423,28 +479,12 @@ version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
|
||||
|
||||
[[package]]
|
||||
name = "embed-manifest"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41cd446c890d6bed1d8b53acef5f240069ebef91d6fae7c5f52efe61fe8b5eae"
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
@@ -483,6 +523,16 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.21"
|
||||
@@ -521,6 +571,12 @@ version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
@@ -613,34 +669,21 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bd11f3a29434026f5ff98c730b668ba74b1033637b8817940b54d040696133c"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"cfg-if",
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.31"
|
||||
@@ -668,6 +711,12 @@ dependencies = [
|
||||
"spin 0.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.153"
|
||||
@@ -764,6 +813,20 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lwip-rs"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/lbl8603/lwip-rs#3133f0c3bde55333a27641182ae3550e7acc2a39"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
"crossbeam",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lz4_flex"
|
||||
version = "0.11.3"
|
||||
@@ -776,6 +839,12 @@ version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.2"
|
||||
@@ -797,6 +866,16 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.4"
|
||||
@@ -915,17 +994,6 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_info"
|
||||
version = "3.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packet"
|
||||
version = "0.1.0"
|
||||
@@ -1027,6 +1095,16 @@ version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.81"
|
||||
@@ -1267,6 +1345,12 @@ version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.32"
|
||||
@@ -1286,15 +1370,6 @@ version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
@@ -1366,6 +1441,12 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.17"
|
||||
@@ -1655,6 +1736,29 @@ version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "vn-link"
|
||||
version = "1.2.10"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"crossbeam-utils",
|
||||
"log",
|
||||
"lwip-rs",
|
||||
"parking_lot",
|
||||
"tokio",
|
||||
"vnt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vn-link-cli"
|
||||
version = "1.2.10"
|
||||
dependencies = [
|
||||
"common",
|
||||
"log",
|
||||
"tokio",
|
||||
"vn-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vnt"
|
||||
version = "1.2.10"
|
||||
@@ -1705,45 +1809,14 @@ dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"common",
|
||||
"console",
|
||||
"embed-manifest",
|
||||
"getopts",
|
||||
"log",
|
||||
"log4rs",
|
||||
"os_info",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"signal-hook",
|
||||
"sudo",
|
||||
"uuid",
|
||||
"vnt",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vnt-jni"
|
||||
version = "1.2.10"
|
||||
dependencies = [
|
||||
"android_logger",
|
||||
"common",
|
||||
"jni",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"spki",
|
||||
"vnt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
@@ -1838,15 +1911,6 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
@@ -1862,15 +1926,6 @@ dependencies = [
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
@@ -1889,21 +1944,6 @@ dependencies = [
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
@@ -1935,12 +1975,6 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
@@ -1953,12 +1987,6 @@ version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
@@ -1971,12 +1999,6 @@ version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
@@ -1995,12 +2017,6 @@ version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
@@ -2013,12 +2029,6 @@ version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
@@ -2031,12 +2041,6 @@ version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
@@ -2049,12 +2053,6 @@ version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
[workspace]
|
||||
members = ["vnt","common","vnt-cli","vnt-jni"]
|
||||
members = ["vnt", "common", "vnt-cli", "vn-link", "vn-link-cli"]
|
||||
|
||||
[profile.release]
|
||||
opt-level = 'z'
|
||||
debug = 0
|
||||
debug-assertions = false
|
||||
strip= "debuginfo"
|
||||
strip = "debuginfo"
|
||||
lto = true
|
||||
panic = 'abort'
|
||||
incremental = false
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
一、程序说明
|
||||
1. vnt-cli vnt的命令行程序
|
||||
2. vn-link-cli 功能和vnt-cli基本一致,但是不依赖tun、不改变本地路由、不需要管理员/root权限
|
||||
|
||||
二、使用说明
|
||||
使用-k参数构建虚拟网络
|
||||
|
||||
|
||||
1. Program Description
|
||||
a. vnt-cli: Command-line program for VNT.
|
||||
b. vn-link-cli: Functions similarly to vnt-cli, but does not depend on TUN, does not change local routing, and does not require administrator/root permissions.
|
||||
|
||||
2. Instructions for Use
|
||||
Use the -k parameter to create a virtual network.
|
||||
@@ -6,3 +6,38 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
vnt = { path = "../vnt", package = "vnt", default-features = false }
|
||||
anyhow = "1.0.82"
|
||||
console = "0.15.2"
|
||||
log = "0.4.17"
|
||||
log4rs = { version = "1.3.0", optional = true }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_yaml = "0.9.32"
|
||||
getopts = "0.2.21"
|
||||
gethostname = "0.4.3"
|
||||
uuid = { version = "1.8.0", features = ["v4"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
openssl = ["vnt/openssl"]
|
||||
openssl-vendored = ["vnt/openssl-vendored"]
|
||||
ring-cipher = ["vnt/ring-cipher"]
|
||||
aes_cbc = ["vnt/aes_cbc"]
|
||||
aes_ecb = ["vnt/aes_ecb"]
|
||||
sm4_cbc = ["vnt/sm4_cbc"]
|
||||
aes_gcm = ["vnt/aes_gcm"]
|
||||
chacha20_poly1305 = ["vnt/chacha20_poly1305"]
|
||||
server_encrypt = ["vnt/server_encrypt"]
|
||||
ip_proxy = ["vnt/ip_proxy"]
|
||||
port_mapping = ["vnt/port_mapping"]
|
||||
lz4 = ["vnt/lz4_compress"]
|
||||
zstd = ["vnt/zstd_compress"]
|
||||
|
||||
command = []
|
||||
file_config = []
|
||||
log = ["log4rs"]
|
||||
integrated_tun = ["vnt/integrated_tun"]
|
||||
|
||||
[build-dependencies]
|
||||
rand = "0.8.5"
|
||||
chrono = "0.4.23"
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::process;
|
||||
|
||||
use console::style;
|
||||
|
||||
use vnt::handle::callback::{ConnectInfo, ErrorType};
|
||||
use vnt::{DeviceInfo, ErrorInfo, HandshakeInfo, RegisterInfo, VntCallback};
|
||||
use vnt::{ConnectInfo, ErrorInfo, ErrorType, HandshakeInfo, RegisterInfo, VntCallback};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VntHandler {}
|
||||
@@ -12,7 +10,8 @@ impl VntCallback for VntHandler {
|
||||
fn success(&self) {
|
||||
println!(" {} ", style("====== Connect Successfully ======").green())
|
||||
}
|
||||
fn create_tun(&self, info: DeviceInfo) {
|
||||
#[cfg(feature = "vnt-model")]
|
||||
fn create_tun(&self, info: vnt::DeviceInfo) {
|
||||
println!("create_tun {}", info)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,463 @@
|
||||
use crate::args_parse::{ips_parse, out_ips_parse};
|
||||
#[cfg(feature = "command")]
|
||||
use crate::command;
|
||||
use crate::{config, generated_serial_number};
|
||||
use anyhow::anyhow;
|
||||
use console::style;
|
||||
use getopts::Options;
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use vnt::channel::punch::PunchModel;
|
||||
use vnt::channel::UseChannelType;
|
||||
use vnt::cipher::CipherModel;
|
||||
use vnt::compression::Compressor;
|
||||
use vnt::core::Config;
|
||||
|
||||
pub fn app_home() -> io::Result<PathBuf> {
|
||||
let root_path = match std::env::current_exe() {
|
||||
Ok(path) => {
|
||||
if let Some(v) = path.as_path().parent() {
|
||||
v.to_path_buf()
|
||||
} else {
|
||||
log::warn!("current_exe parent none:{:?}", path);
|
||||
PathBuf::new()
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("current_exe err:{:?}", e);
|
||||
PathBuf::new()
|
||||
}
|
||||
};
|
||||
let path = root_path.join("env");
|
||||
if !path.exists() {
|
||||
std::fs::create_dir_all(&path)?;
|
||||
}
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>> {
|
||||
#[cfg(feature = "log")]
|
||||
let _ = log4rs::init_file("log4rs.yaml", Default::default());
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let program = args[0].clone();
|
||||
let mut opts = Options::new();
|
||||
opts.optopt("k", "", "组网标识", "<token>");
|
||||
opts.optopt("n", "", "设备名称", "<name>");
|
||||
opts.optopt("d", "", "设备标识", "<id>");
|
||||
opts.optflag("c", "", "关闭交互式命令");
|
||||
opts.optopt("s", "", "注册和中继服务器地址", "<server>");
|
||||
opts.optmulti("e", "", "stun服务器", "<stun-server>");
|
||||
opts.optflag("a", "", "使用tap模式");
|
||||
opts.optopt("", "nic", "虚拟网卡名称,windows下使用tap则必填", "<tun0>");
|
||||
opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", "<in-ip>");
|
||||
opts.optmulti("o", "", "配置点对网出站时使用", "<out-ip>");
|
||||
opts.optopt("w", "", "客户端加密", "<password>");
|
||||
opts.optflag("W", "", "服务端加密");
|
||||
opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>");
|
||||
opts.optflag("", "tcp", "tcp");
|
||||
opts.optopt("", "ip", "指定虚拟ip", "<ip>");
|
||||
opts.optflag("", "relay", "仅使用服务器转发");
|
||||
opts.optopt("", "par", "任务并行度(必须为正整数)", "<parallel>");
|
||||
opts.optopt("", "model", "加密模式", "<model>");
|
||||
opts.optflag("", "finger", "指纹校验");
|
||||
opts.optopt("", "punch", "取值ipv4/ipv6", "<punch>");
|
||||
opts.optopt("", "ports", "监听的端口", "<port,port>");
|
||||
opts.optflag("", "cmd", "开启窗口输入");
|
||||
opts.optflag("", "no-proxy", "关闭内置代理");
|
||||
opts.optflag("", "first-latency", "优先延迟");
|
||||
opts.optopt("", "use-channel", "使用通道 relay/p2p", "<use-channel>");
|
||||
opts.optopt("", "packet-loss", "丢包率", "<packet-loss>");
|
||||
opts.optopt("", "packet-delay", "延迟", "<packet-delay>");
|
||||
opts.optmulti("", "dns", "dns", "<dns>");
|
||||
opts.optmulti("", "mapping", "mapping", "<mapping>");
|
||||
opts.optmulti("", "vnt-mapping", "vnt-mapping", "<mapping>");
|
||||
opts.optopt("f", "", "配置文件", "<conf>");
|
||||
opts.optopt("", "compressor", "压缩算法", "<lz4>");
|
||||
//"后台运行时,查看其他设备列表"
|
||||
opts.optflag("", "add", "后台运行时,添加地址");
|
||||
opts.optflag("", "list", "后台运行时,查看其他设备列表");
|
||||
opts.optflag("", "all", "后台运行时,查看其他设备完整信息");
|
||||
opts.optflag("", "info", "后台运行时,查看当前设备信息");
|
||||
opts.optflag("", "route", "后台运行时,查看数据转发路径");
|
||||
opts.optflag("", "stop", "停止后台运行");
|
||||
opts.optflag("h", "help", "帮助");
|
||||
let matches = match opts.parse(&args[1..]) {
|
||||
Ok(m) => m,
|
||||
Err(f) => {
|
||||
print_usage(&program, opts);
|
||||
return Err(anyhow::anyhow!("{}", f.to_string()));
|
||||
}
|
||||
};
|
||||
if matches.opt_present("h") || args.len() == 1 {
|
||||
print_usage(&program, opts);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
#[cfg(feature = "command")]
|
||||
if matches.opt_present("list") {
|
||||
command::command(command::CommandEnum::List);
|
||||
return Ok(None);
|
||||
} else if matches.opt_present("info") {
|
||||
command::command(command::CommandEnum::Info);
|
||||
return Ok(None);
|
||||
} else if matches.opt_present("stop") {
|
||||
command::command(command::CommandEnum::Stop);
|
||||
return Ok(None);
|
||||
} else if matches.opt_present("route") {
|
||||
command::command(command::CommandEnum::Route);
|
||||
return Ok(None);
|
||||
} else if matches.opt_present("all") {
|
||||
command::command(command::CommandEnum::All);
|
||||
return Ok(None);
|
||||
}
|
||||
let conf = matches.opt_str("f");
|
||||
let (config, vnt_link_config, cmd) = if conf.is_some() {
|
||||
match config::read_config(&conf.unwrap()) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
return Err(anyhow::anyhow!("conf err {}", e));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !matches.opt_present("k") {
|
||||
print_usage(&program, opts);
|
||||
return Err(anyhow::anyhow!("parameter -k not found ."));
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
let tap = matches.opt_present("a");
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
let device_name = matches.opt_str("nic");
|
||||
let token: String = matches.opt_get("k").unwrap().unwrap();
|
||||
let device_id = matches.opt_get_default("d", String::new()).unwrap();
|
||||
let device_id = if device_id.is_empty() {
|
||||
config::get_device_id()
|
||||
} else {
|
||||
device_id
|
||||
};
|
||||
if device_id.is_empty() {
|
||||
print_usage(&program, opts);
|
||||
return Err(anyhow::anyhow!("parameter -d not found ."));
|
||||
}
|
||||
let name = matches
|
||||
.opt_get_default(
|
||||
"n",
|
||||
gethostname::gethostname()
|
||||
.to_str()
|
||||
.unwrap_or("UnknownName")
|
||||
.to_string(),
|
||||
)
|
||||
.unwrap();
|
||||
let server_address_str = matches
|
||||
.opt_get_default("s", "vnt.wherewego.top:29872".to_string())
|
||||
.unwrap();
|
||||
|
||||
let mut stun_server = matches.opt_strs("e");
|
||||
if stun_server.is_empty() {
|
||||
stun_server.push("stun1.l.google.com:19302".to_string());
|
||||
stun_server.push("stun2.l.google.com:19302".to_string());
|
||||
stun_server.push("stun.miwifi.com:3478".to_string());
|
||||
}
|
||||
let dns = matches.opt_strs("dns");
|
||||
let in_ip = matches.opt_strs("i");
|
||||
let in_ip = match ips_parse(&in_ip) {
|
||||
Ok(in_ip) => in_ip,
|
||||
Err(e) => {
|
||||
print_usage(&program, opts);
|
||||
println!();
|
||||
println!("-i: {:?} {}", in_ip, e);
|
||||
return Err(anyhow::anyhow!("example: -i 192.168.0.0/24,10.26.0.3"));
|
||||
}
|
||||
};
|
||||
let out_ip = matches.opt_strs("o");
|
||||
let out_ip = match out_ips_parse(&out_ip) {
|
||||
Ok(out_ip) => out_ip,
|
||||
Err(e) => {
|
||||
print_usage(&program, opts);
|
||||
println!();
|
||||
println!("-o: {:?} {}", out_ip, e);
|
||||
return Err(anyhow::anyhow!("example: -o 0.0.0.0/0"));
|
||||
}
|
||||
};
|
||||
let password: Option<String> = matches.opt_get("w").unwrap();
|
||||
let server_encrypt = matches.opt_present("W");
|
||||
#[cfg(not(feature = "server_encrypt"))]
|
||||
{
|
||||
if server_encrypt {
|
||||
println!("Server encryption not supported");
|
||||
return Err(anyhow::anyhow!("Server encryption not supported"));
|
||||
}
|
||||
}
|
||||
let mtu: Option<String> = matches.opt_get("u").unwrap();
|
||||
let mtu = if let Some(mtu) = mtu {
|
||||
match u32::from_str(&mtu) {
|
||||
Ok(mtu) => Some(mtu),
|
||||
Err(e) => {
|
||||
print_usage(&program, opts);
|
||||
println!();
|
||||
println!("'-u {}' {}", mtu, e);
|
||||
return Err(anyhow::anyhow!("'-u {}' {}", mtu, e));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let virtual_ip: Option<String> = matches.opt_get("ip").unwrap();
|
||||
let virtual_ip =
|
||||
virtual_ip.map(|v| Ipv4Addr::from_str(&v).expect(&format!("'--ip {}' error", v)));
|
||||
if let Some(virtual_ip) = virtual_ip {
|
||||
if virtual_ip.is_unspecified() || virtual_ip.is_broadcast() || virtual_ip.is_multicast()
|
||||
{
|
||||
return Err(anyhow::anyhow!("'--ip {}' invalid", virtual_ip));
|
||||
}
|
||||
}
|
||||
let tcp_channel = matches.opt_present("tcp");
|
||||
let relay = matches.opt_present("relay");
|
||||
|
||||
let cipher_model = match matches.opt_get::<CipherModel>("model") {
|
||||
Ok(model) => {
|
||||
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
|
||||
{
|
||||
if password.is_some() && model.is_none() {
|
||||
return Err(anyhow::anyhow!("'--model ' undefined"));
|
||||
}
|
||||
model.unwrap_or(CipherModel::None)
|
||||
}
|
||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||
model.unwrap_or(CipherModel::AesGcm)
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(anyhow::anyhow!("'--model ' invalid,{}", e));
|
||||
}
|
||||
};
|
||||
|
||||
let finger = matches.opt_present("finger");
|
||||
let punch_model = matches
|
||||
.opt_get::<PunchModel>("punch")
|
||||
.unwrap()
|
||||
.unwrap_or(PunchModel::All);
|
||||
let use_channel_type = matches
|
||||
.opt_get::<UseChannelType>("use-channel")
|
||||
.unwrap()
|
||||
.unwrap_or_else(|| {
|
||||
if relay {
|
||||
UseChannelType::Relay
|
||||
} else {
|
||||
UseChannelType::All
|
||||
}
|
||||
});
|
||||
|
||||
let ports = matches
|
||||
.opt_get::<String>("ports")
|
||||
.unwrap_or(None)
|
||||
.map(|v| v.split(",").map(|x| x.parse().unwrap_or(0)).collect());
|
||||
|
||||
let cmd = matches.opt_present("cmd");
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
let no_proxy = matches.opt_present("no-proxy");
|
||||
let first_latency = matches.opt_present("first-latency");
|
||||
let packet_loss = matches
|
||||
.opt_get::<f64>("packet-loss")
|
||||
.expect("--packet-loss");
|
||||
let packet_delay = matches
|
||||
.opt_get::<u32>("packet-delay")
|
||||
.expect("--packet-delay")
|
||||
.unwrap_or(0);
|
||||
#[cfg(feature = "port_mapping")]
|
||||
let port_mapping_list = matches.opt_strs("mapping");
|
||||
let vnt_mapping_list = matches.opt_strs("vnt-mapping");
|
||||
let compressor = if let Some(compressor) = matches.opt_str("compressor").as_ref() {
|
||||
Compressor::from_str(compressor)
|
||||
.map_err(|e| anyhow!("{}", e))
|
||||
.unwrap()
|
||||
} else {
|
||||
Compressor::None
|
||||
};
|
||||
let config = match Config::new(
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(target_os = "windows")]
|
||||
tap,
|
||||
token,
|
||||
device_id,
|
||||
name,
|
||||
server_address_str,
|
||||
dns,
|
||||
stun_server,
|
||||
in_ip,
|
||||
out_ip,
|
||||
password,
|
||||
mtu,
|
||||
tcp_channel,
|
||||
virtual_ip,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
no_proxy,
|
||||
server_encrypt,
|
||||
cipher_model,
|
||||
finger,
|
||||
punch_model,
|
||||
ports,
|
||||
first_latency,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
device_name,
|
||||
use_channel_type,
|
||||
packet_loss,
|
||||
packet_delay,
|
||||
#[cfg(feature = "port_mapping")]
|
||||
port_mapping_list,
|
||||
compressor,
|
||||
) {
|
||||
Ok(config) => config,
|
||||
Err(e) => {
|
||||
println!("config.toml error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
(config, vnt_mapping_list, cmd)
|
||||
};
|
||||
println!("version {}", vnt::VNT_VERSION);
|
||||
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
|
||||
log::info!(
|
||||
"version:{},Serial:{}",
|
||||
vnt::VNT_VERSION,
|
||||
generated_serial_number::SERIAL_NUMBER
|
||||
);
|
||||
Ok(Some((config, vnt_link_config, cmd)))
|
||||
}
|
||||
|
||||
fn print_usage(program: &str, _opts: Options) {
|
||||
println!("Usage: {} [options]", program);
|
||||
println!("version:{}", vnt::VNT_VERSION);
|
||||
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
|
||||
println!("Options:");
|
||||
println!(
|
||||
" -k <token> {}",
|
||||
green("使用相同的token,就能组建一个局域网络".to_string())
|
||||
);
|
||||
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
|
||||
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复");
|
||||
println!(" -s <server> 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录");
|
||||
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可使用多个地址,如-e stun1.l.google.com -e stun2.l.google.com");
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
println!(
|
||||
" -a 使用tap模式,默认使用tun模式,使用tap时需要配合'--nic'参数指定tap网卡"
|
||||
);
|
||||
println!(" -i <in-ip> 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据");
|
||||
println!(" 并转发到10.26.0.3,可指定多个网段");
|
||||
println!(" -o <out-ip> 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段");
|
||||
|
||||
println!(" -w <password> 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信");
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
|
||||
println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)");
|
||||
#[cfg(feature = "file_config")]
|
||||
println!(" -f <conf_file> 读取配置文件中的配置");
|
||||
|
||||
println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp");
|
||||
println!(" --ip <ip> 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配");
|
||||
let mut enums = String::new();
|
||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||
enums.push_str("/aes_gcm");
|
||||
#[cfg(feature = "chacha20_poly1305")]
|
||||
enums.push_str("/chacha20_poly1305/chacha20");
|
||||
#[cfg(feature = "aes_cbc")]
|
||||
enums.push_str("/aes_cbc");
|
||||
#[cfg(feature = "aes_ecb")]
|
||||
enums.push_str("/aes_ecb");
|
||||
#[cfg(feature = "sm4_cbc")]
|
||||
enums.push_str("/sm4_cbc");
|
||||
enums.push_str("/xor");
|
||||
println!(
|
||||
" --model <model> 加密模式(默认aes_gcm),可选值{}",
|
||||
&enums[1..]
|
||||
);
|
||||
#[cfg(any(
|
||||
feature = "aes_gcm",
|
||||
feature = "chacha20_poly1305",
|
||||
feature = "server_encrypt",
|
||||
feature = "aes_cbc",
|
||||
feature = "aes_ecb",
|
||||
feature = "sm4_cbc"
|
||||
))]
|
||||
println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启");
|
||||
println!(" --punch <punch> 取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞");
|
||||
println!(" --ports <port,port> 取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担");
|
||||
#[cfg(feature = "command")]
|
||||
println!(" --cmd 开启交互式命令,使用此参数开启控制台输入");
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
println!(" --no-proxy 关闭内置代理,如需点对网则需要配置网卡NAT转发");
|
||||
println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道");
|
||||
println!(" --use-channel <p2p> 使用通道 relay/p2p/all,默认两者都使用");
|
||||
#[cfg(not(feature = "vn-link-model"))]
|
||||
println!(" --nic <tun0> 指定虚拟网卡名称");
|
||||
println!(" --packet-loss <0> 模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网");
|
||||
println!(
|
||||
" --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网"
|
||||
);
|
||||
println!(" --dns <host:port> DNS服务器地址,可使用多个dns,不指定时使用系统解析");
|
||||
|
||||
#[cfg(feature = "port_mapping")]
|
||||
println!(" --mapping <mapping> 端口映射,例如 --mapping udp:0.0.0.0:80-domain:80 映射目标是本地路由能访问的设备");
|
||||
|
||||
#[cfg(all(feature = "lz4", feature = "zstd"))]
|
||||
println!(" --compressor <lz4> 启用压缩,可选值lz4/zstd<,level>,level为压缩级别,例如 --compressor lz4 或--compressor zstd,10");
|
||||
#[cfg(feature = "lz4")]
|
||||
#[cfg(not(feature = "zstd"))]
|
||||
println!(" --compressor <lz4> 启用压缩,可选值lz4,例如 --compressor lz4");
|
||||
#[cfg(feature = "zstd")]
|
||||
#[cfg(not(feature = "lz4"))]
|
||||
println!(" --compressor <zstd> 启用压缩,可选值zstd<,level>,level为压缩级别,例如 --compressor zstd,10");
|
||||
|
||||
#[cfg(not(feature = "integrated_tun"))]
|
||||
println!(
|
||||
" --vnt-mapping <x> {}",
|
||||
green(
|
||||
"vnt地址映射,例如 --vnt-mapping tcp:80-10.26.0.10:80 映射目标是vnt网络或其子网中的设备"
|
||||
.to_string()
|
||||
)
|
||||
);
|
||||
println!();
|
||||
#[cfg(feature = "command")]
|
||||
{
|
||||
// #[cfg(not(feature = "integrated_tun"))]
|
||||
// println!(
|
||||
// " --add {}",
|
||||
// yellow("后台运行时,添加VNT地址映射 用法同'--vnt-mapping'".to_string())
|
||||
// );
|
||||
println!(
|
||||
" --list {}",
|
||||
yellow("后台运行时,查看其他设备列表".to_string())
|
||||
);
|
||||
println!(
|
||||
" --all {}",
|
||||
yellow("后台运行时,查看其他设备完整信息".to_string())
|
||||
);
|
||||
println!(
|
||||
" --info {}",
|
||||
yellow("后台运行时,查看当前设备信息".to_string())
|
||||
);
|
||||
println!(
|
||||
" --route {}",
|
||||
yellow("后台运行时,查看数据转发路径".to_string())
|
||||
);
|
||||
println!(
|
||||
" --stop {}",
|
||||
yellow("停止后台运行".to_string())
|
||||
);
|
||||
}
|
||||
println!(" -h, --help 帮助");
|
||||
}
|
||||
|
||||
fn green(str: String) -> impl std::fmt::Display {
|
||||
style(str).green()
|
||||
}
|
||||
|
||||
#[cfg(feature = "command")]
|
||||
fn yellow(str: String) -> impl std::fmt::Display {
|
||||
style(str).yellow()
|
||||
}
|
||||
@@ -30,7 +30,7 @@ impl CommandClient {
|
||||
}
|
||||
}
|
||||
fn read_command_port() -> io::Result<u16> {
|
||||
let path_buf = crate::app_home()?.join("command-port");
|
||||
let path_buf = crate::cli::app_home()?.join("command-port");
|
||||
let port = std::fs::read_to_string(path_buf)?;
|
||||
match u16::from_str(&port) {
|
||||
Ok(port) => Ok(port),
|
||||
@@ -16,6 +16,37 @@ pub enum CommandEnum {
|
||||
Stop,
|
||||
}
|
||||
|
||||
pub fn command_str(cmd: &str, vnt: &Vnt) -> bool {
|
||||
if cmd.is_empty() {
|
||||
return false;
|
||||
}
|
||||
match cmd.to_lowercase().trim() {
|
||||
"list" => {
|
||||
let list = command_list(&vnt);
|
||||
console_out::console_device_list(list);
|
||||
}
|
||||
"info" => {
|
||||
let info = command_info(&vnt);
|
||||
console_out::console_info(info);
|
||||
}
|
||||
"route" => {
|
||||
let route = command_route(&vnt);
|
||||
console_out::console_route_table(route);
|
||||
}
|
||||
"all" => {
|
||||
let list = command_list(&vnt);
|
||||
console_out::console_device_list_all(list);
|
||||
}
|
||||
"stop" => {
|
||||
let _ = vnt.stop();
|
||||
return false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
println!();
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn command(cmd: CommandEnum) {
|
||||
if let Err(e) = command_(cmd) {
|
||||
println!("cmd: {:?}", e);
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::net::UdpSocket;
|
||||
|
||||
use vnt::core::Vnt;
|
||||
|
||||
pub struct CommandServer {}
|
||||
@@ -48,7 +47,7 @@ impl CommandServer {
|
||||
}
|
||||
}
|
||||
fn save_port(port: u16) -> io::Result<()> {
|
||||
let path_buf = crate::app_home()?.join("command-port");
|
||||
let path_buf = crate::cli::app_home()?.join("command-port");
|
||||
let mut file = std::fs::File::create(path_buf)?;
|
||||
file.write_all(port.to_string().as_bytes())?;
|
||||
file.sync_all()
|
||||
@@ -2,9 +2,9 @@ use anyhow::anyhow;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::args_parse;
|
||||
use crate::config::get_device_id;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vnt::channel::punch::PunchModel;
|
||||
use vnt::channel::UseChannelType;
|
||||
use vnt::cipher::CipherModel;
|
||||
@@ -32,7 +32,6 @@ pub struct FileConfig {
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
pub no_proxy: bool,
|
||||
pub server_encrypt: bool,
|
||||
pub parallel: usize,
|
||||
pub cipher_model: Option<String>,
|
||||
pub finger: bool,
|
||||
pub punch_model: String,
|
||||
@@ -45,6 +44,7 @@ pub struct FileConfig {
|
||||
#[cfg(feature = "port_mapping")]
|
||||
pub mapping: Vec<String>,
|
||||
pub compressor: Option<String>,
|
||||
pub vnt_mapping: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for FileConfig {
|
||||
@@ -54,7 +54,10 @@ impl Default for FileConfig {
|
||||
tap: false,
|
||||
token: "".to_string(),
|
||||
device_id: get_device_id(),
|
||||
name: os_info::get().to_string(),
|
||||
name: gethostname::gethostname()
|
||||
.to_str()
|
||||
.unwrap_or("UnknownName")
|
||||
.to_string(),
|
||||
server_address: "nat1.wherewego.top:29872".to_string(),
|
||||
stun_server: vec![
|
||||
"stun1.l.google.com:19302".to_string(),
|
||||
@@ -72,7 +75,6 @@ impl Default for FileConfig {
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
no_proxy: false,
|
||||
server_encrypt: false,
|
||||
parallel: 1,
|
||||
cipher_model: None,
|
||||
finger: false,
|
||||
punch_model: "all".to_string(),
|
||||
@@ -85,11 +87,12 @@ impl Default for FileConfig {
|
||||
#[cfg(feature = "port_mapping")]
|
||||
mapping: vec![],
|
||||
compressor: None,
|
||||
vnt_mapping: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_config(file_path: &str) -> anyhow::Result<(Config, bool)> {
|
||||
pub fn read_config(file_path: &str) -> anyhow::Result<(Config, Vec<String>, bool)> {
|
||||
let conf = std::fs::read_to_string(file_path)?;
|
||||
let file_conf = match serde_yaml::from_str::<FileConfig>(&conf) {
|
||||
Ok(val) => val,
|
||||
@@ -102,13 +105,13 @@ pub fn read_config(file_path: &str) -> anyhow::Result<(Config, bool)> {
|
||||
return Err(anyhow!("token is_empty"));
|
||||
}
|
||||
|
||||
let in_ips = match common::args_parse::ips_parse(&file_conf.in_ips) {
|
||||
let in_ips = match args_parse::ips_parse(&file_conf.in_ips) {
|
||||
Ok(in_ips) => in_ips,
|
||||
Err(e) => {
|
||||
return Err(anyhow!("in_ips {:?} error:{}", &file_conf.in_ips, e));
|
||||
}
|
||||
};
|
||||
let out_ips = match common::args_parse::out_ips_parse(&file_conf.out_ips) {
|
||||
let out_ips = match args_parse::out_ips_parse(&file_conf.out_ips) {
|
||||
Ok(out_ips) => out_ips,
|
||||
Err(e) => {
|
||||
return Err(anyhow!("out_ips {:?} error:{}", &file_conf.out_ips, e));
|
||||
@@ -122,6 +125,10 @@ pub fn read_config(file_path: &str) -> anyhow::Result<(Config, bool)> {
|
||||
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
|
||||
if file_conf.password.is_some() && file_conf.cipher_model.is_none() {
|
||||
Err(anyhow!("cipher_model undefined"))?
|
||||
} else if let Some(v) = file_conf.cipher_model {
|
||||
CipherModel::from_str(&v).map_err(|e| anyhow!("{}", e))?
|
||||
} else {
|
||||
CipherModel::None
|
||||
}
|
||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||
CipherModel::AesGcm
|
||||
@@ -137,6 +144,7 @@ pub fn read_config(file_path: &str) -> anyhow::Result<(Config, bool)> {
|
||||
};
|
||||
let config = Config::new(
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
file_conf.tap,
|
||||
file_conf.token,
|
||||
file_conf.device_id,
|
||||
@@ -150,15 +158,16 @@ pub fn read_config(file_path: &str) -> anyhow::Result<(Config, bool)> {
|
||||
file_conf.mtu,
|
||||
file_conf.tcp,
|
||||
virtual_ip,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
file_conf.no_proxy,
|
||||
file_conf.server_encrypt,
|
||||
file_conf.parallel,
|
||||
cipher_model,
|
||||
file_conf.finger,
|
||||
punch_model,
|
||||
file_conf.ports,
|
||||
file_conf.first_latency,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
file_conf.device_name,
|
||||
use_channel_type,
|
||||
file_conf.packet_loss,
|
||||
@@ -167,5 +176,6 @@ pub fn read_config(file_path: &str) -> anyhow::Result<(Config, bool)> {
|
||||
file_conf.mapping,
|
||||
compressor,
|
||||
)?;
|
||||
Ok((config, file_conf.cmd))
|
||||
|
||||
Ok((config, file_conf.vnt_mapping, file_conf.cmd))
|
||||
}
|
||||
@@ -1,19 +1,20 @@
|
||||
#[cfg(feature = "file_config")]
|
||||
mod file_config;
|
||||
|
||||
use crate::identifier;
|
||||
#[cfg(feature = "file_config")]
|
||||
pub use file_config::read_config;
|
||||
|
||||
#[cfg(not(feature = "file_config"))]
|
||||
pub fn read_config(_file_path: &str) -> anyhow::Result<(vnt::core::Config, bool)> {
|
||||
pub fn read_config(_file_path: &str) -> anyhow::Result<(vnt::core::Config, Vec<String>, bool)> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn get_device_id() -> String {
|
||||
if let Some(id) = common::identifier::get_unique_identifier() {
|
||||
if let Some(id) = identifier::get_unique_identifier() {
|
||||
id
|
||||
} else {
|
||||
let path_buf = match crate::app_home() {
|
||||
let path_buf = match crate::cli::app_home() {
|
||||
Ok(path_buf) => path_buf.join("device-id"),
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
@@ -1,2 +1,12 @@
|
||||
pub mod args_parse;
|
||||
#[cfg(feature = "command")]
|
||||
pub mod command;
|
||||
pub mod config;
|
||||
#[cfg(feature = "command")]
|
||||
mod console_out;
|
||||
pub mod identifier;
|
||||
|
||||
pub mod cli;
|
||||
mod generated_serial_number;
|
||||
|
||||
pub mod callback;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
[package]
|
||||
name = "vn-link-cli"
|
||||
version = "1.2.10"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
vn-link = { path = "../vn-link", default-features = false }
|
||||
common = { path = "../common", default-features = false }
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
log = "0.4.17"
|
||||
|
||||
[features]
|
||||
default = ["default-feature"]
|
||||
openssl = ["vn-link/openssl","common/openssl"]
|
||||
openssl-vendored = ["vn-link/openssl-vendored","common/openssl-vendored"]
|
||||
ring-cipher = ["vn-link/ring-cipher","common/ring-cipher"]
|
||||
aes_cbc = ["vn-link/aes_cbc","common/aes_cbc"]
|
||||
aes_ecb = ["vn-link/aes_ecb","common/aes_ecb"]
|
||||
sm4_cbc = ["vn-link/sm4_cbc","common/sm4_cbc"]
|
||||
aes_gcm = ["vn-link/aes_gcm","common/aes_gcm"]
|
||||
chacha20_poly1305 = ["vn-link/chacha20_poly1305","common/chacha20_poly1305"]
|
||||
server_encrypt = ["vn-link/server_encrypt","common/server_encrypt"]
|
||||
port_mapping = ["vn-link/port_mapping","common/port_mapping"]
|
||||
lz4 = ["vn-link/lz4_compress","common/lz4"]
|
||||
zstd = ["vn-link/zstd_compress","common/zstd"]
|
||||
log = ["common/log"]
|
||||
command = ["common/command"]
|
||||
file_config = ["common/file_config"]
|
||||
|
||||
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4"]
|
||||
@@ -0,0 +1,61 @@
|
||||
# 端口映射模式
|
||||
|
||||
## 一、特点
|
||||
|
||||
1. 不需要tap/tun虚拟网卡
|
||||
2. 不需要管理员/root权限
|
||||
3. 不改变本地路由
|
||||
4. 使用端口映射来访问目标服务
|
||||
|
||||
## 二、作用
|
||||
|
||||
和vnt互补,能简单快速构建网络,外部依赖更少
|
||||
|
||||
## 三、使用方式
|
||||
|
||||
和vnt的使用方式一样,只是多了"--vnt-mapping"这个参数
|
||||
|
||||
### vn-link作为被访问端,不需要额外配置vnt-mapping
|
||||
|
||||
### vn-link访问vnt或者vn-link,需要加vnt-mapping
|
||||
|
||||
例如:
|
||||
|
||||
设备A 运行vnt(虚拟IP 10.26.0.A),设备B 运行vn-link(虚拟IP 10.26.0.B)。
|
||||
|
||||
如果要用B访问A上的tcp 80端口,则在设备B上需要加--vnt-mapping "tcp:port1-10.26.0.A:80"
|
||||
|
||||
这个参数的作用是将B上的***本地端口port1***转发到设备A的地址10.26.0.A:
|
||||
80,此时在设备B上可以访问本地port1端口从而间接访问10.26.0.A:80
|
||||
|
||||
## 四、vn-link的子网代理
|
||||
|
||||
vn-link也支持点对网参数。 还是接着上面的例子
|
||||
|
||||
假设 设备C在设备A的子网下,C的子网IP为192.168.1.C,A的子网IP为192.168.1.A,要在设备B上访问C
|
||||
|
||||
则在B上加这些参数
|
||||
|
||||
- --vnt-mapping "tcp:port2-192.168.1.C:80" (将本地port2端口映射到C的80端口)
|
||||
- -i 192.168.1.0/24,10.26.0.A (将目标192.168.1.0/24的数据发送到10.26.0.A,也就是A节点)
|
||||
|
||||
在A上加参数
|
||||
|
||||
- -o 0.0.0.0/0 (允许所有流量转发)
|
||||
|
||||
***再次说明,vn-link作为被访问端时和vnt使用方式一致,vn-link作为访问端时需要加--vnt-mapping映射端口***
|
||||
|
||||
***vn-link是基于端口映射的使用模式,不会改变本地路由***
|
||||
|
||||
## 五、参数介绍
|
||||
|
||||
--vnt-mapping支持udp/tcp,例如 --vnt-mapping "tcp:port1-remoteIp:remotePort"
|
||||
|
||||
- 第一部分为协议,支持使用udp/tcp
|
||||
- 第二部分是本地端口,注意不要和本地服务的端口冲突
|
||||
- 第三部分是目标机器的地址,一般是目标虚拟IP地址,如果配置了点对网参数(-i和-o)则也可以是目标子网地址
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
use common::callback;
|
||||
use vn_link::config::VnLinkConfig;
|
||||
use vn_link::vnt::core::Config;
|
||||
|
||||
fn main() {
|
||||
let (config, vnt_link_config, cmd) = match common::cli::parse_args_config() {
|
||||
Ok(rs) => {
|
||||
if let Some(rs) = rs {
|
||||
rs
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let vnt_link_config = VnLinkConfig::new(vn_link::config::convert(vnt_link_config).unwrap());
|
||||
main0(config, vnt_link_config, cmd)
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main0(config: Config, vn_link_config: VnLinkConfig, _show_cmd: bool) {
|
||||
#[cfg(feature = "port_mapping")]
|
||||
for (is_tcp, addr, dest) in config.port_mapping_list.iter() {
|
||||
if *is_tcp {
|
||||
println!("TCP port mapping {}->{}", addr, dest)
|
||||
} else {
|
||||
println!("UDP port mapping {}->{}", addr, dest)
|
||||
}
|
||||
}
|
||||
for x in &vn_link_config.mapping {
|
||||
if x.protocol.is_tcp() {
|
||||
println!("TCP vnt addr mapping 127.0.0.1:{}->{}", x.src_port, x.dest)
|
||||
} else {
|
||||
println!("UDP vnt addr mapping 127.0.0.1:{}->{}", x.src_port, x.dest)
|
||||
}
|
||||
}
|
||||
|
||||
let vnt_util = match vn_link::VnLink::new(config, vn_link_config, callback::VntHandler {}).await
|
||||
{
|
||||
Ok(vnt) => vnt,
|
||||
Err(e) => {
|
||||
println!("error: {:?}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "command")]
|
||||
{
|
||||
let vnt_c = vnt_util.as_vnt().clone();
|
||||
std::thread::Builder::new()
|
||||
.name("CommandServer".into())
|
||||
.spawn(move || {
|
||||
if let Err(e) = common::command::server::CommandServer::new().start(vnt_c) {
|
||||
log::warn!("cmd:{:?}", e);
|
||||
}
|
||||
})
|
||||
.expect("CommandServer");
|
||||
let vnt_c = vnt_util.as_vnt();
|
||||
if _show_cmd {
|
||||
use tokio::io::AsyncBufReadExt;
|
||||
let mut cmd = String::new();
|
||||
let mut reader = tokio::io::BufReader::new(tokio::io::stdin());
|
||||
loop {
|
||||
cmd.clear();
|
||||
println!("======== input:list,info,route,all,stop ========");
|
||||
match reader.read_line(&mut cmd).await {
|
||||
Ok(len) => {
|
||||
if !common::command::command_str(&cmd[..len], vnt_c) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("input err:{}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
vnt_util.wait().await
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "vn-link"
|
||||
version = "1.2.10"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
lwip-rs = { git = "https://github.com/lbl8603/lwip-rs" }
|
||||
vnt = { path = "../vnt", package = "vnt", default-features = false }
|
||||
log = "0.4.17"
|
||||
anyhow = "1.0.82"
|
||||
parking_lot = "0.12.1"
|
||||
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
crossbeam-utils = "0.8"
|
||||
|
||||
[features]
|
||||
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "lz4_compress"]
|
||||
openssl = ["vnt/openssl"]
|
||||
openssl-vendored = ["vnt/openssl-vendored"]
|
||||
ring-cipher = ["vnt/ring-cipher"]
|
||||
aes_cbc = ["vnt/aes_cbc"]
|
||||
aes_ecb = ["vnt/aes_ecb"]
|
||||
sm4_cbc = ["vnt/sm4_cbc"]
|
||||
aes_gcm = ["vnt/aes_gcm"]
|
||||
chacha20_poly1305 = ["vnt/chacha20_poly1305"]
|
||||
server_encrypt = ["vnt/server_encrypt"]
|
||||
port_mapping = ["vnt/port_mapping"]
|
||||
lz4_compress = ["vnt/lz4_compress"]
|
||||
zstd_compress = ["vnt/zstd_compress"]
|
||||
@@ -0,0 +1,85 @@
|
||||
use anyhow::Context;
|
||||
use std::net::SocketAddr;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct VnLinkConfig {
|
||||
pub mapping: Vec<LinkItem>,
|
||||
}
|
||||
|
||||
impl VnLinkConfig {
|
||||
pub fn new(mapping: Vec<LinkItem>) -> Self {
|
||||
Self { mapping }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum LinkProtocol {
|
||||
Tcp,
|
||||
Udp,
|
||||
}
|
||||
|
||||
impl LinkProtocol {
|
||||
pub fn is_tcp(&self) -> bool {
|
||||
self == &LinkProtocol::Tcp
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct LinkItem {
|
||||
pub protocol: LinkProtocol,
|
||||
pub src_port: u16,
|
||||
pub dest: SocketAddr,
|
||||
}
|
||||
|
||||
impl LinkItem {
|
||||
pub fn new(protocol: LinkProtocol, src_port: u16, dest: SocketAddr) -> Self {
|
||||
Self {
|
||||
protocol,
|
||||
src_port,
|
||||
dest,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<LinkItem>> {
|
||||
let mut rs = Vec::with_capacity(vec.len());
|
||||
for x in vec {
|
||||
let string = x.trim().to_lowercase();
|
||||
if let Some(udp_mapping) = string.strip_prefix("udp:") {
|
||||
let mut split = udp_mapping.split("-");
|
||||
let bind_port = split
|
||||
.next()
|
||||
.with_context(|| format!("vnt-mapping error {:?},eg: udp:80-10.26.0.10:8080", x))?;
|
||||
let bind_port = u16::from_str(bind_port)
|
||||
.with_context(|| format!("udp_mapping error {}", bind_port))?;
|
||||
let dest = split
|
||||
.next()
|
||||
.with_context(|| format!("vnt-mapping error {:?},eg: udp:80-10.26.0.10:8080", x))?;
|
||||
let dest_addr = SocketAddr::from_str(dest)
|
||||
.with_context(|| format!("udp_mapping error {}", dest))?;
|
||||
rs.push(LinkItem::new(LinkProtocol::Udp, bind_port, dest_addr));
|
||||
continue;
|
||||
}
|
||||
if let Some(tcp_mapping) = string.strip_prefix("tcp:") {
|
||||
let mut split = tcp_mapping.split("-");
|
||||
let bind_port = split
|
||||
.next()
|
||||
.with_context(|| format!("vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", x))?;
|
||||
let bind_port = u16::from_str(bind_port)
|
||||
.with_context(|| format!("tcp_mapping error {}", bind_port))?;
|
||||
let dest = split
|
||||
.next()
|
||||
.with_context(|| format!("vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", x))?;
|
||||
let dest_addr = SocketAddr::from_str(dest)
|
||||
.with_context(|| format!("tcp_mapping error {}", dest))?;
|
||||
rs.push(LinkItem::new(LinkProtocol::Tcp, bind_port, dest_addr));
|
||||
continue;
|
||||
}
|
||||
Err(anyhow::anyhow!(
|
||||
"vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080",
|
||||
x
|
||||
))?;
|
||||
}
|
||||
Ok(rs)
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod tcp;
|
||||
pub mod udp;
|
||||
@@ -0,0 +1,46 @@
|
||||
use crate::out_mapping::tcp::tcp_copy;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use lwip_rs::tcp_stream::TcpStream as LwIpTcpStream;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::net::TcpListener;
|
||||
use vnt::handle::CurrentDeviceInfo;
|
||||
|
||||
pub async fn tcp_mapping_listen(
|
||||
tcp_listener: TcpListener,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
dest: SocketAddr,
|
||||
) {
|
||||
loop {
|
||||
let (stream, addr) = match tcp_listener.accept().await {
|
||||
Ok((stream, addr)) => (stream, addr),
|
||||
Err(e) => {
|
||||
log::warn!("tcp_mapping_listen {:?} dest {}", e, dest);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let current_info = current_device.load();
|
||||
if current_info.virtual_ip.is_unspecified() {
|
||||
continue;
|
||||
}
|
||||
if let IpAddr::V4(ip) = dest.ip() {
|
||||
if ip == current_info.virtual_ip {
|
||||
//防止用错参数的
|
||||
log::warn!("目的地址不能是本地虚拟ip tcp->{}", dest);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let src = SocketAddr::new(IpAddr::V4(current_info.virtual_ip), addr.port());
|
||||
tokio::spawn(async move {
|
||||
match LwIpTcpStream::connect(src, dest, Duration::from_secs(5)).await {
|
||||
Ok(lw_tcp) => {
|
||||
tcp_copy(lw_tcp, stream);
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("{} {}->{} {}", addr, src, dest, e);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
use std::collections::HashMap;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use tokio::net::UdpSocket;
|
||||
|
||||
use lwip_rs::udp::UdpSocketWrite;
|
||||
use vnt::handle::CurrentDeviceInfo;
|
||||
|
||||
pub async fn udp_mapping_start(
|
||||
udp: UdpSocket,
|
||||
lwip_udp_write: UdpSocketWrite,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
in_udp_map: &Arc<
|
||||
Mutex<
|
||||
HashMap<
|
||||
(SocketAddr, SocketAddr),
|
||||
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
|
||||
dest: SocketAddr,
|
||||
) {
|
||||
let udp = Arc::new(udp);
|
||||
let mut buf = [0u8; 65536];
|
||||
loop {
|
||||
let (len, addr) = match udp.recv_from(&mut buf).await {
|
||||
Ok(rs) => rs,
|
||||
Err(e) => {
|
||||
log::warn!("recv_from {} {}", dest, e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let current_info = current_device.load();
|
||||
if current_info.virtual_ip.is_unspecified() {
|
||||
continue;
|
||||
}
|
||||
if let IpAddr::V4(ip) = dest.ip() {
|
||||
if ip == current_info.virtual_ip {
|
||||
//防止用错参数的
|
||||
log::warn!("目的地址不能是本地虚拟ip udp->{}", dest);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let src = SocketAddr::new(IpAddr::V4(current_info.virtual_ip), addr.port());
|
||||
in_udp_map.lock().insert(
|
||||
(dest, src),
|
||||
(
|
||||
udp.clone(),
|
||||
Some(addr),
|
||||
Arc::new(AtomicCell::new(Instant::now())),
|
||||
),
|
||||
);
|
||||
|
||||
if let Err(e) = lwip_udp_write.send(&buf[..len], &src, &dest) {
|
||||
log::warn!("lwip_udp_write {}->{} {}", src, dest, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
pub mod config;
|
||||
mod in_mapping;
|
||||
mod out_mapping;
|
||||
mod vnt_link;
|
||||
|
||||
pub use vnt;
|
||||
|
||||
pub use vnt_link::*;
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod tcp;
|
||||
pub mod udp;
|
||||
@@ -0,0 +1,64 @@
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use tokio::net::TcpStream;
|
||||
|
||||
use lwip_rs::tcp_listener::TcpListener;
|
||||
use lwip_rs::tcp_stream::TcpStream as LwIpTcpStream;
|
||||
use vnt::handle::CurrentDeviceInfo;
|
||||
|
||||
pub async fn tcp_mapping_listen(
|
||||
mut tcp_listener: TcpListener,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
) {
|
||||
loop {
|
||||
let stream = match tcp_listener.accept().await {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
log::warn!("tcp_mapping_listen err {:?}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
let device_info = current_device.load();
|
||||
tokio::spawn(async move {
|
||||
let dest = stream.dest_addr();
|
||||
let src = stream.src_addr();
|
||||
if let Err(e) = tcp_mapping_handle(stream, device_info).await {
|
||||
log::warn!("tcp_mapping_handle {}->{} {:?}", src, dest, e)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async fn tcp_mapping_handle(
|
||||
tcp_stream: LwIpTcpStream,
|
||||
device_info: CurrentDeviceInfo,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut dest = tcp_stream.dest_addr();
|
||||
// let src = tcp_stream.src_addr();
|
||||
if let IpAddr::V4(ip) = dest.ip() {
|
||||
if ip.is_unspecified()
|
||||
|| ip.is_broadcast()
|
||||
|| ip.is_multicast()
|
||||
|| ip == device_info.virtual_ip
|
||||
|| ip == device_info.broadcast_ip
|
||||
{
|
||||
//是自己
|
||||
dest.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
|
||||
}
|
||||
}
|
||||
let peer_stream = TcpStream::connect(dest).await?;
|
||||
if dest.port() == peer_stream.local_addr()?.port() {
|
||||
return Err(anyhow::anyhow!("tcp port loop"));
|
||||
}
|
||||
tcp_copy(tcp_stream, peer_stream);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn tcp_copy(lw_tcp: LwIpTcpStream, tokio_tcp: TcpStream) {
|
||||
let (mut write, mut read) = lw_tcp.into_split();
|
||||
let (mut peer_read, mut peer_write) = tokio_tcp.into_split();
|
||||
tokio::spawn(async move { tokio::io::copy(&mut read, &mut peer_write).await });
|
||||
tokio::spawn(async move { tokio::io::copy(&mut peer_read, &mut write).await });
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use lwip_rs::udp::{UdpSocketRead, UdpSocketWrite};
|
||||
use parking_lot::Mutex;
|
||||
use std::collections::HashMap;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::net::UdpSocket;
|
||||
use vnt::handle::CurrentDeviceInfo;
|
||||
|
||||
pub async fn udp_mapping_start(
|
||||
lwip_udp_write: UdpSocketWrite,
|
||||
mut lwip_udp_read: UdpSocketRead,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
in_udp_map: Arc<
|
||||
Mutex<
|
||||
HashMap<
|
||||
(SocketAddr, SocketAddr),
|
||||
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
) {
|
||||
loop {
|
||||
let (buf, src, dest) = match lwip_udp_read.recv().await {
|
||||
Ok(rs) => rs,
|
||||
Err(e) => {
|
||||
log::warn!("udp_mapping err {:?}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
if let Err(e) = handle(
|
||||
¤t_device,
|
||||
&lwip_udp_write,
|
||||
&in_udp_map,
|
||||
buf,
|
||||
src,
|
||||
dest,
|
||||
)
|
||||
.await
|
||||
{
|
||||
log::warn!("udp_mapping err {}->{} {:?}", src, dest, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle(
|
||||
current_device: &AtomicCell<CurrentDeviceInfo>,
|
||||
lwip_udp_write: &UdpSocketWrite,
|
||||
map: &Arc<
|
||||
Mutex<
|
||||
HashMap<
|
||||
(SocketAddr, SocketAddr),
|
||||
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
buf: Vec<u8>,
|
||||
src: SocketAddr,
|
||||
dest: SocketAddr,
|
||||
) -> anyhow::Result<()> {
|
||||
let option = map.lock().get(&(src, dest)).cloned();
|
||||
|
||||
if let Some((dest_udp, addr, time)) = option {
|
||||
time.store(Instant::now());
|
||||
if let Some(addr) = addr {
|
||||
dest_udp.send_to(&buf, addr).await?;
|
||||
} else {
|
||||
dest_udp.send(&buf).await?;
|
||||
}
|
||||
} else {
|
||||
let mut real_dest = dest;
|
||||
let peer_udp_socket = match UdpSocket::bind(format!("0.0.0.0:{}", src.port())).await {
|
||||
Ok(udp) => udp,
|
||||
Err(_) => UdpSocket::bind("0.0.0.0:0").await?,
|
||||
};
|
||||
if let IpAddr::V4(ip) = dest.ip() {
|
||||
let device_info = current_device.load();
|
||||
if ip.is_unspecified()
|
||||
|| ip.is_broadcast()
|
||||
|| ip.is_multicast()
|
||||
|| ip == device_info.virtual_ip
|
||||
|| ip == device_info.broadcast_ip
|
||||
{
|
||||
//是自己
|
||||
real_dest.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
|
||||
}
|
||||
}
|
||||
peer_udp_socket.connect(real_dest).await?;
|
||||
peer_udp_socket.send(&buf).await?;
|
||||
let peer_udp_socket = Arc::new(peer_udp_socket);
|
||||
let time = Arc::new(AtomicCell::new(Instant::now()));
|
||||
let map = map.clone();
|
||||
map.lock()
|
||||
.insert((src, dest), (peer_udp_socket.clone(), None, time.clone()));
|
||||
let lwip_udp_write = lwip_udp_write.clone();
|
||||
tokio::spawn(async move {
|
||||
peer_udp_handle(peer_udp_socket, lwip_udp_write, src, dest, time).await;
|
||||
map.lock().remove(&(src, dest));
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn peer_udp_handle(
|
||||
peer_udp_socket: Arc<UdpSocket>,
|
||||
lwip_udp_write: UdpSocketWrite,
|
||||
src: SocketAddr,
|
||||
dest: SocketAddr,
|
||||
time: Arc<AtomicCell<Instant>>,
|
||||
) {
|
||||
let mut buf = [0u8; 65536];
|
||||
loop {
|
||||
match tokio::time::timeout(Duration::from_secs(600), peer_udp_socket.recv(&mut buf)).await {
|
||||
Ok(rs) => match rs {
|
||||
Ok(len) => match lwip_udp_write.send(&buf[..len], &dest, &src) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("udp proxy {}->{} {:?}", dest, src, e);
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::warn!("udp proxy {}->{} {:?}", dest, src, e);
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
if time.load().elapsed() > Duration::from_secs(580) {
|
||||
//超时关闭
|
||||
log::warn!("udp proxy timeout {}->{}", dest, src,);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
use std::collections::HashMap;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
use anyhow::Context;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use tokio::net::{TcpListener, UdpSocket};
|
||||
use tokio::sync::watch::{channel, Sender};
|
||||
|
||||
use lwip_rs::stack::{NetStack, NetStackWrite};
|
||||
use lwip_rs::tcp_listener::TcpListener as LwIPTcpListener;
|
||||
use lwip_rs::udp::{UdpSocket as LwIpUdpSocket, UdpSocketWrite};
|
||||
use vnt::channel::BUFFER_SIZE;
|
||||
use vnt::core::{Config, Vnt};
|
||||
use vnt::packet::ip::ipv4::packet::IpV4Packet;
|
||||
use vnt::protocol::HEAD_LEN;
|
||||
use vnt::vnt_device::DeviceWrite;
|
||||
use vnt::VntCallback;
|
||||
|
||||
use crate::config::{LinkItem, LinkProtocol, VnLinkConfig};
|
||||
use crate::{in_mapping, out_mapping};
|
||||
|
||||
pub struct VnLink {
|
||||
vnt: Vnt,
|
||||
in_udp_map: Arc<
|
||||
Mutex<
|
||||
HashMap<
|
||||
(SocketAddr, SocketAddr),
|
||||
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
lwip_udp_write: UdpSocketWrite,
|
||||
shutdown_tx: Sender<bool>,
|
||||
}
|
||||
|
||||
impl VnLink {
|
||||
pub async fn new<Call: VntCallback>(
|
||||
vnt_config: Config,
|
||||
vn_link_config: VnLinkConfig,
|
||||
callback: Call,
|
||||
) -> anyhow::Result<Self> {
|
||||
let stack = NetStack::new(HEAD_LEN, 1024, vnt_config.mtu.unwrap_or(1420) as u16).await;
|
||||
let udp = LwIpUdpSocket::new()?;
|
||||
let tcp_listener = LwIPTcpListener::new()?;
|
||||
let (shutdown_tx, shutdown_rx) = channel(false);
|
||||
let (net_stack_write, mut net_stack_read) = stack.into_split();
|
||||
let vnt = Vnt::new_device(vnt_config, callback, VntDevice { net_stack_write })?;
|
||||
let shutdown_tx_ = shutdown_tx.clone();
|
||||
let w = vnt.add_stop_listener("vnt-link".into(), move || {
|
||||
let _ = shutdown_tx_.send(true);
|
||||
})?;
|
||||
let ip_sender = vnt.ipv4_packet_sender().unwrap();
|
||||
let mut shutdown_rx_ = shutdown_rx.clone();
|
||||
tokio::spawn(async move {
|
||||
let mut extend = [0; BUFFER_SIZE];
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = shutdown_rx_.changed() => {
|
||||
break;
|
||||
}
|
||||
rs = net_stack_read.recv_ip() => {
|
||||
match rs{
|
||||
Ok((mut buf, start_index, len)) => {
|
||||
let ipv4_packet = if let Ok(packet) =
|
||||
IpV4Packet::new(&buf[start_index..len])
|
||||
{
|
||||
packet
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
let destination_ip = ipv4_packet.destination_ip();
|
||||
let source_ip = ipv4_packet.source_ip();
|
||||
|
||||
if let Err(e) = ip_sender.send_ip(&mut buf, len, &mut extend, destination_ip) {
|
||||
log::warn!("{}->{},{}", source_ip, destination_ip, e);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("net_stack_read {:?}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
w.stop_all();
|
||||
});
|
||||
|
||||
let (lwip_udp_write, lwip_udp_read) = udp.into_split();
|
||||
let in_udp_map: Arc<
|
||||
Mutex<
|
||||
HashMap<
|
||||
(SocketAddr, SocketAddr),
|
||||
(Arc<UdpSocket>, Option<SocketAddr>, Arc<AtomicCell<Instant>>),
|
||||
>,
|
||||
>,
|
||||
> = Arc::new(Mutex::new(HashMap::new()));
|
||||
|
||||
let current_device_info = vnt.current_device_info();
|
||||
let in_udp_map_ = in_udp_map.clone();
|
||||
let lwip_udp_write_ = lwip_udp_write.clone();
|
||||
let vnt_ = vnt.clone();
|
||||
let mut shutdown_rx_ = shutdown_rx.clone();
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_ = shutdown_rx_.changed() => {}
|
||||
_ = out_mapping::udp::udp_mapping_start(
|
||||
lwip_udp_write_,
|
||||
lwip_udp_read,
|
||||
current_device_info,
|
||||
in_udp_map_,
|
||||
) => {}
|
||||
}
|
||||
|
||||
vnt_.stop();
|
||||
});
|
||||
let current_device_info = vnt.current_device_info();
|
||||
let vnt_ = vnt.clone();
|
||||
let mut shutdown_rx_ = shutdown_rx.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_ = shutdown_rx_.changed() => {}
|
||||
_ = out_mapping::tcp::tcp_mapping_listen(tcp_listener, current_device_info) => {}
|
||||
}
|
||||
vnt_.stop();
|
||||
});
|
||||
let link = Self {
|
||||
vnt,
|
||||
in_udp_map,
|
||||
lwip_udp_write,
|
||||
shutdown_tx,
|
||||
};
|
||||
link.add_mapping(vn_link_config.mapping).await?;
|
||||
Ok(link)
|
||||
}
|
||||
pub async fn add_mapping(&self, mapping: Vec<LinkItem>) -> anyhow::Result<()> {
|
||||
for item in mapping {
|
||||
let current_device_info = self.vnt.current_device_info();
|
||||
if item.dest.ip().is_unspecified() {
|
||||
Err(anyhow::anyhow!("dest_address {:?} is_unspecified", item))?
|
||||
}
|
||||
let mut shutdown_rx_ = self.shutdown_tx.subscribe();
|
||||
if *shutdown_rx_.borrow() {
|
||||
Err(anyhow::anyhow!("mapping stop"))?
|
||||
}
|
||||
if item.protocol == LinkProtocol::Udp {
|
||||
let lwip_udp_write = self.lwip_udp_write.clone();
|
||||
let in_udp_map = self.in_udp_map.clone();
|
||||
//只能本机访问,不然不同IP的相同来源端口会有问题
|
||||
let udp = UdpSocket::bind(format!("127.0.0.1:{}", item.src_port))
|
||||
.await
|
||||
.with_context(|| format!("udp bind failed {}", item.src_port))?;
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_ = shutdown_rx_.changed() => {}
|
||||
_ = in_mapping::udp::udp_mapping_start(
|
||||
udp,
|
||||
lwip_udp_write,
|
||||
current_device_info,
|
||||
&in_udp_map,
|
||||
item.dest,
|
||||
) => {}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let listener = TcpListener::bind(format!("127.0.0.1:{}", item.src_port))
|
||||
.await
|
||||
.with_context(|| format!("tcp bind failed {}", item.src_port))?;
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_ = shutdown_rx_.changed() => {}
|
||||
_ = in_mapping::tcp::tcp_mapping_listen(
|
||||
listener,
|
||||
current_device_info,
|
||||
item.dest,
|
||||
) => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn stop(&self) {
|
||||
self.as_vnt().stop()
|
||||
}
|
||||
pub async fn wait(&self) {
|
||||
loop {
|
||||
let mut receiver = self.shutdown_tx.subscribe();
|
||||
if *receiver.borrow() {
|
||||
return;
|
||||
}
|
||||
if receiver.changed().await.is_err() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vnt(&self) -> &Vnt {
|
||||
&self.vnt
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VntDevice {
|
||||
net_stack_write: NetStackWrite,
|
||||
}
|
||||
|
||||
impl DeviceWrite for VntDevice {
|
||||
fn write(&self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
self.net_stack_write.send_ip(buf)?;
|
||||
Ok(buf.len())
|
||||
}
|
||||
}
|
||||
+24
-31
@@ -6,21 +6,11 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
vnt = { path = "../vnt", package = "vnt", default-features = false }
|
||||
common = { path = "../common" }
|
||||
getopts = "0.2.21"
|
||||
console = "0.15.2"
|
||||
os_info = "3.7.0"
|
||||
serde = "1.0"
|
||||
serde_yaml = "0.9.32"
|
||||
vnt = { path = "../vnt", package = "vnt", default-features = false, features = ["integrated_tun"] }
|
||||
common = { path = "../common", default-features = false, features = ["integrated_tun"] }
|
||||
log = "0.4.17"
|
||||
log4rs = { version = "1.2.0", optional = true }
|
||||
anyhow = "1.0.82"
|
||||
[dependencies.uuid]
|
||||
version = "1.4.1"
|
||||
features = [
|
||||
"v4", # Lets you generate random UUIDs
|
||||
]
|
||||
|
||||
|
||||
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
||||
sudo = "0.6.0"
|
||||
@@ -30,24 +20,27 @@ signal-hook = "0.3.17"
|
||||
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
||||
|
||||
[features]
|
||||
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4"]
|
||||
openssl = ["vnt/openssl"]
|
||||
openssl-vendored = ["vnt/openssl-vendored"]
|
||||
ring-cipher = ["vnt/ring-cipher"]
|
||||
aes_cbc = ["vnt/aes_cbc"]
|
||||
aes_ecb = ["vnt/aes_ecb"]
|
||||
sm4_cbc = ["vnt/sm4_cbc"]
|
||||
aes_gcm = ["vnt/aes_gcm"]
|
||||
chacha20_poly1305 = ["vnt/chacha20_poly1305"]
|
||||
server_encrypt = ["vnt/server_encrypt"]
|
||||
ip_proxy = ["vnt/ip_proxy"]
|
||||
port_mapping = ["vnt/port_mapping"]
|
||||
lz4 = ["vnt/lz4_compress"]
|
||||
zstd = ["vnt/zstd_compress"]
|
||||
log = ["log4rs"]
|
||||
command = []
|
||||
file_config = []
|
||||
default = ["default-feature"]
|
||||
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4"]
|
||||
|
||||
openssl = ["vnt/openssl", "common/openssl"]
|
||||
openssl-vendored = ["vnt/openssl-vendored", "common/openssl-vendored"]
|
||||
ring-cipher = ["vnt/ring-cipher", "common/ring-cipher"]
|
||||
aes_cbc = ["vnt/aes_cbc", "common/aes_cbc"]
|
||||
aes_ecb = ["vnt/aes_ecb", "common/aes_ecb"]
|
||||
sm4_cbc = ["vnt/sm4_cbc", "common/sm4_cbc"]
|
||||
aes_gcm = ["vnt/aes_gcm", "common/aes_gcm"]
|
||||
chacha20_poly1305 = ["vnt/chacha20_poly1305", "common/chacha20_poly1305"]
|
||||
server_encrypt = ["vnt/server_encrypt", "common/server_encrypt"]
|
||||
port_mapping = ["vnt/port_mapping", "common/port_mapping"]
|
||||
lz4 = ["vnt/lz4_compress", "common/lz4"]
|
||||
zstd = ["vnt/zstd_compress", "common/zstd"]
|
||||
ip_proxy = ["vnt/ip_proxy", "common/ip_proxy"]
|
||||
log = ["common/log"]
|
||||
command = ["common/command"]
|
||||
file_config = ["common/file_config"]
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
embed-manifest = "1.4.0"
|
||||
rand = "0.8.5"
|
||||
chrono = "0.4.23"
|
||||
+5
-5
@@ -143,9 +143,9 @@ aes_gcm/aes_cbc/aes_ecb/sm4_cbc/chacha20_poly1305/chacha20/xor,默认使用aes
|
||||
|
||||
当地址解析失败时,会依次尝试后面的dns,直到有A记录、AAAA记录(或TXT记录)的解析结果
|
||||
|
||||
### --mapping `<udp:0.0.0.0:80->10.26.0.10:80>`
|
||||
### --mapping `<udp:0.0.0.0:80-10.26.0.10:80>`
|
||||
|
||||
端口映射,可以设置多个映射地址,例如 '--mapping udp:0.0.0.0:80->10.26.0.10:80 --mapping tcp:0.0.0.0:80->10.26.0.11:81'
|
||||
端口映射,可以设置多个映射地址,例如 '--mapping udp:0.0.0.0:80-10.26.0.10:80 --mapping tcp:0.0.0.0:80-10.26.0.11:81'
|
||||
表示将本地udp 80端口的数据转发到10.26.0.10:80,将本地tcp 80端口的数据转发到10.26.0.11:81,转发的目的地址可以使用域名+端口
|
||||
|
||||
### --compressor `<lz4>`
|
||||
@@ -198,9 +198,9 @@ dns:
|
||||
- 223.5.5.5 # 首选dns
|
||||
- 8.8.8.8 # 备选dns
|
||||
mapping:
|
||||
- udp:0.0.0.0:80->10.26.0.10:80 # 映射udp数据
|
||||
- tcp:0.0.0.0:80->10.26.0.10:81 # 映射tcp数据
|
||||
- tcp:0.0.0.0:82->localhost:83 # 映射tcp数据
|
||||
- udp:0.0.0.0:80-10.26.0.10:80 # 映射udp数据
|
||||
- tcp:0.0.0.0:80-10.26.0.10:81 # 映射tcp数据
|
||||
- tcp:0.0.0.0:82-localhost:83 # 映射tcp数据
|
||||
```
|
||||
|
||||
或者需要哪个配置就加哪个,当然token是必须的
|
||||
|
||||
+14
-483
@@ -1,350 +1,29 @@
|
||||
use anyhow::anyhow;
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use console::style;
|
||||
use getopts::Options;
|
||||
|
||||
use common::args_parse::{ips_parse, out_ips_parse};
|
||||
use vnt::channel::punch::PunchModel;
|
||||
use vnt::channel::UseChannelType;
|
||||
use vnt::cipher::CipherModel;
|
||||
use vnt::compression::Compressor;
|
||||
use common::callback;
|
||||
use vnt::core::{Config, Vnt};
|
||||
|
||||
#[cfg(feature = "command")]
|
||||
mod command;
|
||||
mod config;
|
||||
#[cfg(feature = "command")]
|
||||
mod console_out;
|
||||
mod generated_serial_number;
|
||||
mod root_check;
|
||||
|
||||
pub fn app_home() -> io::Result<PathBuf> {
|
||||
let root_path = match std::env::current_exe() {
|
||||
Ok(path) => {
|
||||
if let Some(v) = path.as_path().parent() {
|
||||
v.to_path_buf()
|
||||
fn main() {
|
||||
let (config, _vnt_link_config, cmd) = match common::cli::parse_args_config() {
|
||||
Ok(rs) => {
|
||||
if let Some(rs) = rs {
|
||||
rs
|
||||
} else {
|
||||
log::warn!("current_exe parent none:{:?}", path);
|
||||
PathBuf::new()
|
||||
return;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("current_exe err:{:?}", e);
|
||||
PathBuf::new()
|
||||
}
|
||||
};
|
||||
let path = root_path.join("env");
|
||||
if !path.exists() {
|
||||
std::fs::create_dir_all(&path)?;
|
||||
}
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[cfg(feature = "log")]
|
||||
let _ = log4rs::init_file("log4rs.yaml", Default::default());
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let program = args[0].clone();
|
||||
let mut opts = Options::new();
|
||||
opts.optopt("k", "", "组网标识", "<token>");
|
||||
opts.optopt("n", "", "设备名称", "<name>");
|
||||
opts.optopt("d", "", "设备标识", "<id>");
|
||||
opts.optflag("c", "", "关闭交互式命令");
|
||||
opts.optopt("s", "", "注册和中继服务器地址", "<server>");
|
||||
opts.optmulti("e", "", "stun服务器", "<stun-server>");
|
||||
opts.optflag("a", "", "使用tap模式");
|
||||
opts.optopt("", "nic", "虚拟网卡名称,windows下使用tap则必填", "<tun0>");
|
||||
opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", "<in-ip>");
|
||||
opts.optmulti("o", "", "配置点对网出站时使用", "<out-ip>");
|
||||
opts.optopt("w", "", "客户端加密", "<password>");
|
||||
opts.optflag("W", "", "服务端加密");
|
||||
opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>");
|
||||
opts.optflag("", "tcp", "tcp");
|
||||
opts.optopt("", "ip", "指定虚拟ip", "<ip>");
|
||||
opts.optflag("", "relay", "仅使用服务器转发");
|
||||
opts.optopt("", "par", "任务并行度(必须为正整数)", "<parallel>");
|
||||
opts.optopt("", "model", "加密模式", "<model>");
|
||||
opts.optflag("", "finger", "指纹校验");
|
||||
opts.optopt("", "punch", "取值ipv4/ipv6", "<punch>");
|
||||
opts.optopt("", "ports", "监听的端口", "<port,port>");
|
||||
opts.optflag("", "cmd", "开启窗口输入");
|
||||
opts.optflag("", "no-proxy", "关闭内置代理");
|
||||
opts.optflag("", "first-latency", "优先延迟");
|
||||
opts.optopt("", "use-channel", "使用通道 relay/p2p", "<use-channel>");
|
||||
opts.optopt("", "packet-loss", "丢包率", "<packet-loss>");
|
||||
opts.optopt("", "packet-delay", "延迟", "<packet-delay>");
|
||||
opts.optmulti("", "dns", "dns", "<dns>");
|
||||
opts.optmulti("", "mapping", "mapping", "<mapping>");
|
||||
opts.optopt("f", "", "配置文件", "<conf>");
|
||||
opts.optopt("", "compressor", "压缩算法", "<lz4>");
|
||||
//"后台运行时,查看其他设备列表"
|
||||
opts.optflag("", "list", "后台运行时,查看其他设备列表");
|
||||
opts.optflag("", "all", "后台运行时,查看其他设备完整信息");
|
||||
opts.optflag("", "info", "后台运行时,查看当前设备信息");
|
||||
opts.optflag("", "route", "后台运行时,查看数据转发路径");
|
||||
opts.optflag("", "stop", "停止后台运行");
|
||||
opts.optflag("h", "help", "帮助");
|
||||
let matches = match opts.parse(&args[1..]) {
|
||||
Ok(m) => m,
|
||||
Err(f) => {
|
||||
print_usage(&program, opts);
|
||||
println!("{}", f.to_string());
|
||||
println!("{}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if matches.opt_present("h") || args.len() == 1 {
|
||||
print_usage(&program, opts);
|
||||
return;
|
||||
}
|
||||
main0(config, cmd)
|
||||
}
|
||||
fn main0(config: Config, _show_cmd: bool) {
|
||||
if !root_check::is_app_elevated() {
|
||||
println!("Please run it with administrator or root privileges");
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
sudo::escalate_if_needed().unwrap();
|
||||
return;
|
||||
}
|
||||
#[cfg(feature = "command")]
|
||||
if matches.opt_present("list") {
|
||||
command::command(command::CommandEnum::List);
|
||||
return;
|
||||
} else if matches.opt_present("info") {
|
||||
command::command(command::CommandEnum::Info);
|
||||
return;
|
||||
} else if matches.opt_present("stop") {
|
||||
command::command(command::CommandEnum::Stop);
|
||||
return;
|
||||
} else if matches.opt_present("route") {
|
||||
command::command(command::CommandEnum::Route);
|
||||
return;
|
||||
} else if matches.opt_present("all") {
|
||||
command::command(command::CommandEnum::All);
|
||||
return;
|
||||
}
|
||||
let conf = matches.opt_str("f");
|
||||
let (config, cmd) = if conf.is_some() {
|
||||
match config::read_config(&conf.unwrap()) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
println!("conf err {}", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !matches.opt_present("k") {
|
||||
print_usage(&program, opts);
|
||||
println!("parameter -k not found .");
|
||||
return;
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
let tap = matches.opt_present("a");
|
||||
let device_name = matches.opt_str("nic");
|
||||
let token: String = matches.opt_get("k").unwrap().unwrap();
|
||||
let device_id = matches.opt_get_default("d", String::new()).unwrap();
|
||||
let device_id = if device_id.is_empty() {
|
||||
config::get_device_id()
|
||||
} else {
|
||||
device_id
|
||||
};
|
||||
if device_id.is_empty() {
|
||||
print_usage(&program, opts);
|
||||
println!("parameter -d not found .");
|
||||
return;
|
||||
}
|
||||
let name = matches
|
||||
.opt_get_default("n", os_info::get().to_string())
|
||||
.unwrap();
|
||||
let server_address_str = matches
|
||||
.opt_get_default("s", "nat1.wherewego.top:29872".to_string())
|
||||
.unwrap();
|
||||
|
||||
let mut stun_server = matches.opt_strs("e");
|
||||
if stun_server.is_empty() {
|
||||
stun_server.push("stun1.l.google.com:19302".to_string());
|
||||
stun_server.push("stun2.l.google.com:19302".to_string());
|
||||
stun_server.push("stun.miwifi.com:3478".to_string());
|
||||
}
|
||||
let dns = matches.opt_strs("dns");
|
||||
let in_ip = matches.opt_strs("i");
|
||||
let in_ip = match ips_parse(&in_ip) {
|
||||
Ok(in_ip) => in_ip,
|
||||
Err(e) => {
|
||||
print_usage(&program, opts);
|
||||
println!();
|
||||
println!("-i: {:?} {}", in_ip, e);
|
||||
println!("example: -i 192.168.0.0/24,10.26.0.3");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let out_ip = matches.opt_strs("o");
|
||||
let out_ip = match out_ips_parse(&out_ip) {
|
||||
Ok(out_ip) => out_ip,
|
||||
Err(e) => {
|
||||
print_usage(&program, opts);
|
||||
println!();
|
||||
println!("-o: {:?} {}", out_ip, e);
|
||||
println!("example: -o 0.0.0.0/0");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let password: Option<String> = matches.opt_get("w").unwrap();
|
||||
let server_encrypt = matches.opt_present("W");
|
||||
#[cfg(not(feature = "server_encrypt"))]
|
||||
{
|
||||
if server_encrypt {
|
||||
println!("Server encryption not supported");
|
||||
return;
|
||||
}
|
||||
}
|
||||
let mtu: Option<String> = matches.opt_get("u").unwrap();
|
||||
let mtu = if let Some(mtu) = mtu {
|
||||
match u32::from_str(&mtu) {
|
||||
Ok(mtu) => Some(mtu),
|
||||
Err(e) => {
|
||||
print_usage(&program, opts);
|
||||
println!();
|
||||
println!("'-u {}' {}", mtu, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let virtual_ip: Option<String> = matches.opt_get("ip").unwrap();
|
||||
let virtual_ip =
|
||||
virtual_ip.map(|v| Ipv4Addr::from_str(&v).expect(&format!("'--ip {}' error", v)));
|
||||
if let Some(virtual_ip) = virtual_ip {
|
||||
if virtual_ip.is_unspecified() || virtual_ip.is_broadcast() || virtual_ip.is_multicast()
|
||||
{
|
||||
println!("'--ip {}' invalid", virtual_ip);
|
||||
return;
|
||||
}
|
||||
}
|
||||
let tcp_channel = matches.opt_present("tcp");
|
||||
let relay = matches.opt_present("relay");
|
||||
|
||||
let parallel = matches.opt_get::<usize>("par").unwrap().unwrap_or(1);
|
||||
if parallel == 0 {
|
||||
println!("'--par {}' invalid", parallel);
|
||||
return;
|
||||
}
|
||||
|
||||
let cipher_model = match matches.opt_get::<CipherModel>("model") {
|
||||
Ok(model) => {
|
||||
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
|
||||
{
|
||||
if password.is_some() && model.is_none() {
|
||||
println!("'--model ' undefined");
|
||||
return;
|
||||
}
|
||||
model.unwrap_or(CipherModel::None)
|
||||
}
|
||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||
model.unwrap_or(CipherModel::AesGcm)
|
||||
}
|
||||
Err(e) => {
|
||||
println!("'--model ' invalid,{}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let finger = matches.opt_present("finger");
|
||||
let punch_model = matches
|
||||
.opt_get::<PunchModel>("punch")
|
||||
.unwrap()
|
||||
.unwrap_or(PunchModel::All);
|
||||
let use_channel_type = matches
|
||||
.opt_get::<UseChannelType>("use-channel")
|
||||
.unwrap()
|
||||
.unwrap_or_else(|| {
|
||||
if relay {
|
||||
UseChannelType::Relay
|
||||
} else {
|
||||
UseChannelType::All
|
||||
}
|
||||
});
|
||||
|
||||
let ports = matches
|
||||
.opt_get::<String>("ports")
|
||||
.unwrap_or(None)
|
||||
.map(|v| v.split(",").map(|x| x.parse().unwrap_or(0)).collect());
|
||||
|
||||
let cmd = matches.opt_present("cmd");
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
let no_proxy = matches.opt_present("no-proxy");
|
||||
let first_latency = matches.opt_present("first-latency");
|
||||
let packet_loss = matches
|
||||
.opt_get::<f64>("packet-loss")
|
||||
.expect("--packet-loss");
|
||||
let packet_delay = matches
|
||||
.opt_get::<u32>("packet-delay")
|
||||
.expect("--packet-delay")
|
||||
.unwrap_or(0);
|
||||
#[cfg(feature = "port_mapping")]
|
||||
let port_mapping_list = matches.opt_strs("mapping");
|
||||
let compressor = if let Some(compressor) = matches.opt_str("compressor").as_ref() {
|
||||
Compressor::from_str(compressor)
|
||||
.map_err(|e| anyhow!("{}", e))
|
||||
.unwrap()
|
||||
} else {
|
||||
Compressor::None
|
||||
};
|
||||
let config = match Config::new(
|
||||
#[cfg(target_os = "windows")]
|
||||
tap,
|
||||
token,
|
||||
device_id,
|
||||
name,
|
||||
server_address_str,
|
||||
dns,
|
||||
stun_server,
|
||||
in_ip,
|
||||
out_ip,
|
||||
password,
|
||||
mtu,
|
||||
tcp_channel,
|
||||
virtual_ip,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
no_proxy,
|
||||
server_encrypt,
|
||||
parallel,
|
||||
cipher_model,
|
||||
finger,
|
||||
punch_model,
|
||||
ports,
|
||||
first_latency,
|
||||
device_name,
|
||||
use_channel_type,
|
||||
packet_loss,
|
||||
packet_delay,
|
||||
#[cfg(feature = "port_mapping")]
|
||||
port_mapping_list,
|
||||
compressor,
|
||||
) {
|
||||
Ok(config) => config,
|
||||
Err(e) => {
|
||||
println!("config.toml error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
(config, cmd)
|
||||
};
|
||||
println!("version {}", vnt::VNT_VERSION);
|
||||
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
|
||||
log::info!(
|
||||
"version:{},Serial:{}",
|
||||
vnt::VNT_VERSION,
|
||||
generated_serial_number::SERIAL_NUMBER
|
||||
);
|
||||
main0(config, cmd);
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
mod callback;
|
||||
|
||||
fn main0(config: Config, _show_cmd: bool) {
|
||||
#[cfg(feature = "port_mapping")]
|
||||
for (is_tcp, addr, dest) in config.port_mapping_list.iter() {
|
||||
if *is_tcp {
|
||||
@@ -389,7 +68,7 @@ fn main0(config: Config, _show_cmd: bool) {
|
||||
std::thread::Builder::new()
|
||||
.name("CommandServer".into())
|
||||
.spawn(move || {
|
||||
if let Err(e) = command::server::CommandServer::new().start(vnt_c) {
|
||||
if let Err(e) = common::command::server::CommandServer::new().start(vnt_c) {
|
||||
log::warn!("cmd:{:?}", e);
|
||||
}
|
||||
})
|
||||
@@ -399,9 +78,9 @@ fn main0(config: Config, _show_cmd: bool) {
|
||||
loop {
|
||||
cmd.clear();
|
||||
println!("======== input:list,info,route,all,stop ========");
|
||||
match io::stdin().read_line(&mut cmd) {
|
||||
match std::io::stdin().read_line(&mut cmd) {
|
||||
Ok(len) => {
|
||||
if !command(&cmd[..len], &vnt_util) {
|
||||
if !common::command::command_str(&cmd[..len], &vnt_util) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -416,151 +95,3 @@ fn main0(config: Config, _show_cmd: bool) {
|
||||
|
||||
vnt_util.wait()
|
||||
}
|
||||
|
||||
#[cfg(feature = "command")]
|
||||
fn command(cmd: &str, vnt: &Vnt) -> bool {
|
||||
if cmd.is_empty() {
|
||||
return false;
|
||||
}
|
||||
match cmd.to_lowercase().trim() {
|
||||
"list" => {
|
||||
let list = command::command_list(&vnt);
|
||||
console_out::console_device_list(list);
|
||||
}
|
||||
"info" => {
|
||||
let info = command::command_info(&vnt);
|
||||
console_out::console_info(info);
|
||||
}
|
||||
"route" => {
|
||||
let route = command::command_route(&vnt);
|
||||
console_out::console_route_table(route);
|
||||
}
|
||||
"all" => {
|
||||
let list = command::command_list(&vnt);
|
||||
console_out::console_device_list_all(list);
|
||||
}
|
||||
"stop" => {
|
||||
let _ = vnt.stop();
|
||||
return false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
println!();
|
||||
return true;
|
||||
}
|
||||
|
||||
fn print_usage(program: &str, _opts: Options) {
|
||||
println!("Usage: {} [options]", program);
|
||||
println!("version:{}", vnt::VNT_VERSION);
|
||||
println!("Serial:{}", generated_serial_number::SERIAL_NUMBER);
|
||||
println!("Options:");
|
||||
println!(
|
||||
" -k <token> {}",
|
||||
green("使用相同的token,就能组建一个局域网络".to_string())
|
||||
);
|
||||
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
|
||||
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复");
|
||||
println!(" -s <server> 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录");
|
||||
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可使用多个地址,如-e stun1.l.google.com -e stun2.l.google.com");
|
||||
#[cfg(target_os = "windows")]
|
||||
println!(
|
||||
" -a 使用tap模式,默认使用tun模式,使用tap时需要配合'--nic'参数指定tap网卡"
|
||||
);
|
||||
println!(" -i <in-ip> 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据");
|
||||
println!(" 并转发到10.26.0.3,可指定多个网段");
|
||||
println!(" -o <out-ip> 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段");
|
||||
|
||||
println!(" -w <password> 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信");
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
|
||||
println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)");
|
||||
#[cfg(feature = "file_config")]
|
||||
println!(" -f <conf_file> 读取配置文件中的配置");
|
||||
|
||||
println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp");
|
||||
println!(" --ip <ip> 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配");
|
||||
println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1");
|
||||
let mut enums = String::new();
|
||||
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
|
||||
enums.push_str("/aes_gcm");
|
||||
#[cfg(feature = "chacha20_poly1305")]
|
||||
enums.push_str("/chacha20_poly1305/chacha20");
|
||||
#[cfg(feature = "aes_cbc")]
|
||||
enums.push_str("/aes_cbc");
|
||||
#[cfg(feature = "aes_ecb")]
|
||||
enums.push_str("/aes_ecb");
|
||||
#[cfg(feature = "sm4_cbc")]
|
||||
enums.push_str("/sm4_cbc");
|
||||
enums.push_str("/xor");
|
||||
println!(
|
||||
" --model <model> 加密模式(默认aes_gcm),可选值{}",
|
||||
&enums[1..]
|
||||
);
|
||||
#[cfg(any(
|
||||
feature = "aes_gcm",
|
||||
feature = "chacha20_poly1305",
|
||||
feature = "server_encrypt",
|
||||
feature = "aes_cbc",
|
||||
feature = "aes_ecb",
|
||||
feature = "sm4_cbc"
|
||||
))]
|
||||
println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启");
|
||||
println!(" --punch <punch> 取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞");
|
||||
println!(" --ports <port,port> 取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担");
|
||||
#[cfg(feature = "command")]
|
||||
println!(" --cmd 开启交互式命令,使用此参数开启控制台输入");
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
println!(" --no-proxy 关闭内置代理,如需点对网则需要配置网卡NAT转发");
|
||||
println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道");
|
||||
println!(" --use-channel <p2p> 使用通道 relay/p2p/all,默认两者都使用");
|
||||
println!(" --nic <tun0> 指定虚拟网卡名称");
|
||||
println!(" --packet-loss <0> 模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网");
|
||||
println!(
|
||||
" --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网"
|
||||
);
|
||||
println!(" --dns <host:port> DNS服务器地址,可使用多个dns,不指定时使用系统解析");
|
||||
#[cfg(feature = "port_mapping")]
|
||||
println!(" --mapping <mapping> 端口映射,例如 --mapping udp:0.0.0.0:80->10.26.0.10:80 --mapping tcp:0.0.0.0:80->10.26.0.10:80");
|
||||
#[cfg(all(feature = "lz4", feature = "zstd"))]
|
||||
println!(" --compressor <lz4> 启用压缩,可选值lz4/zstd<,level>,level为压缩级别,例如 --compressor lz4 或--compressor zstd,10");
|
||||
#[cfg(feature = "lz4")]
|
||||
#[cfg(not(feature = "zstd"))]
|
||||
println!(" --compressor <lz4> 启用压缩,可选值lz4,例如 --compressor lz4");
|
||||
#[cfg(feature = "zstd")]
|
||||
#[cfg(not(feature = "lz4"))]
|
||||
println!(" --compressor <zstd> 启用压缩,可选值zstd<,level>,level为压缩级别,例如 --compressor zstd,10");
|
||||
println!();
|
||||
#[cfg(feature = "command")]
|
||||
{
|
||||
println!(
|
||||
" --list {}",
|
||||
yellow("后台运行时,查看其他设备列表".to_string())
|
||||
);
|
||||
println!(
|
||||
" --all {}",
|
||||
yellow("后台运行时,查看其他设备完整信息".to_string())
|
||||
);
|
||||
println!(
|
||||
" --info {}",
|
||||
yellow("后台运行时,查看当前设备信息".to_string())
|
||||
);
|
||||
println!(
|
||||
" --route {}",
|
||||
yellow("后台运行时,查看数据转发路径".to_string())
|
||||
);
|
||||
println!(
|
||||
" --stop {}",
|
||||
yellow("停止后台运行".to_string())
|
||||
);
|
||||
}
|
||||
println!(" -h, --help 帮助");
|
||||
}
|
||||
|
||||
fn green(str: String) -> impl std::fmt::Display {
|
||||
style(str).green()
|
||||
}
|
||||
|
||||
#[cfg(feature = "command")]
|
||||
fn yellow(str: String) -> impl std::fmt::Display {
|
||||
style(str).yellow()
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
[package]
|
||||
name = "vnt-jni"
|
||||
version = "1.2.10"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
common = { path = "../common" }
|
||||
vnt = {path="../vnt"}
|
||||
parking_lot = "0.12.1"
|
||||
|
||||
jni = { version = "0.21.1", default-features = false }
|
||||
log = "0.4.20"
|
||||
spki = { version = "0.7.2", features = ["fingerprint", "alloc","base64","pem"]}
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
android_logger = "0.13"
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib", "cdylib"]
|
||||
@@ -1 +0,0 @@
|
||||
## 提供给安卓端使用
|
||||
@@ -1,77 +0,0 @@
|
||||
package top.wherewego.vnt.jni;
|
||||
|
||||
import top.wherewego.vnt.jni.param.*;
|
||||
|
||||
/**
|
||||
* 回调
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public interface CallBack {
|
||||
/**
|
||||
* 连接成功的回调
|
||||
*/
|
||||
void success();
|
||||
|
||||
/**
|
||||
* 创建虚拟网卡成功的回调方法
|
||||
* 仅在 windows/linux/macos上使用
|
||||
*
|
||||
* @param info 网卡信息
|
||||
*/
|
||||
void createTun(DeviceInfo info);
|
||||
|
||||
/**
|
||||
* 连接服务端
|
||||
*
|
||||
* @param info 将要连接的服务端信息
|
||||
*/
|
||||
void connect(ConnectInfo info);
|
||||
|
||||
/**
|
||||
* 和服务端握手
|
||||
*
|
||||
* @param info 握手信息
|
||||
* @return 是否确认握手
|
||||
*/
|
||||
boolean handshake(HandshakeInfo info);
|
||||
|
||||
/**
|
||||
* 注册成功回调
|
||||
*
|
||||
* @param info 注册信息
|
||||
* @return 是否确认注册信息
|
||||
*/
|
||||
boolean register(RegisterInfo info);
|
||||
|
||||
/**
|
||||
* 创建网卡回调
|
||||
* 仅在android上使用
|
||||
*
|
||||
* @param info 创建配置
|
||||
* @return 网卡fd
|
||||
*/
|
||||
|
||||
int generateTun(DeviceConfig info);
|
||||
|
||||
/**
|
||||
* 对端用户列表
|
||||
*
|
||||
* @param infoArray
|
||||
*/
|
||||
void peerClientList(PeerClientInfo[] infoArray);
|
||||
|
||||
|
||||
/**
|
||||
* 异常回调
|
||||
*
|
||||
* @param info 错误信息
|
||||
*/
|
||||
void error(ErrorInfo info);
|
||||
|
||||
/**
|
||||
* 服务停止
|
||||
*/
|
||||
void stop();
|
||||
|
||||
}
|
||||
@@ -1,333 +0,0 @@
|
||||
package top.wherewego.vnt.jni;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 启动配置
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class Config implements Serializable {
|
||||
/**
|
||||
* 是否是tap模式,仅支持windows
|
||||
*/
|
||||
private boolean tap;
|
||||
/**
|
||||
* 组网标识
|
||||
*/
|
||||
private String token;
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 客户端间加密的密码
|
||||
*/
|
||||
private String password;
|
||||
/**
|
||||
* 客户端间加密模式 aes_gcm/aes_cbc/aes_ecb/sm4_cbc
|
||||
*/
|
||||
private String cipherModel;
|
||||
/**
|
||||
* 打洞模式 ipv4/ipv6/all
|
||||
*/
|
||||
private String punchModel;
|
||||
/**
|
||||
* mtu 默认自动计算
|
||||
*/
|
||||
private Integer mtu;
|
||||
/**
|
||||
* 是否开启服务端加密
|
||||
*/
|
||||
private boolean serverEncrypt;
|
||||
/**
|
||||
* 设备id,请使用唯一值
|
||||
*/
|
||||
private String deviceId;
|
||||
/**
|
||||
* 服务端地址
|
||||
*/
|
||||
private String server;
|
||||
/**
|
||||
* dns地址
|
||||
*/
|
||||
private String[] dns;
|
||||
/**
|
||||
* 端口映射
|
||||
*/
|
||||
private String[] portMapping;
|
||||
/**
|
||||
* stun服务地址
|
||||
*/
|
||||
private String[] stunServer;
|
||||
/**
|
||||
* 和服务端使用tcp通信,默认使用udp
|
||||
*/
|
||||
private boolean tcp;
|
||||
/**
|
||||
* 指定组网IP
|
||||
*/
|
||||
private String ip;
|
||||
/**
|
||||
* 开启加密指纹校验
|
||||
*/
|
||||
private boolean finger;
|
||||
/**
|
||||
* 延迟优先,默认p2p优先
|
||||
*/
|
||||
private boolean firstLatency;
|
||||
/**
|
||||
* 点对网入口 格式 192.168.0.0/26,10.26.0.2
|
||||
*/
|
||||
private String[] inIps;
|
||||
/**
|
||||
* 点对网出口 格式 192.168.0.0/26
|
||||
*/
|
||||
private String[] outIps;
|
||||
/**
|
||||
* 端口组,udp会监听一组端口,tcp监听ports[0]端口
|
||||
*/
|
||||
private int[] ports;
|
||||
/**
|
||||
* 虚拟网卡名称 仅在linux、windows、macos上支持
|
||||
*/
|
||||
private String deviceName;
|
||||
/**
|
||||
* enum: relay/p2p/all
|
||||
*/
|
||||
private String useChannel;
|
||||
/**
|
||||
* 模拟丢包率,取0~1之间的数,为null表示不丢包,1表示全部丢包
|
||||
*/
|
||||
private Double packetLossRate;
|
||||
/**
|
||||
* 模拟延迟 单位毫秒(ms)
|
||||
*/
|
||||
private Integer packetDelay;
|
||||
|
||||
public Config() {
|
||||
}
|
||||
|
||||
public boolean isTap() {
|
||||
return tap;
|
||||
}
|
||||
|
||||
public void setTap(boolean tap) {
|
||||
this.tap = tap;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getCipherModel() {
|
||||
return cipherModel;
|
||||
}
|
||||
|
||||
public void setCipherModel(String cipherModel) {
|
||||
this.cipherModel = cipherModel;
|
||||
}
|
||||
|
||||
public String getPunchModel() {
|
||||
return punchModel;
|
||||
}
|
||||
|
||||
public void setPunchModel(String punchModel) {
|
||||
this.punchModel = punchModel;
|
||||
}
|
||||
|
||||
public Integer getMtu() {
|
||||
return mtu;
|
||||
}
|
||||
|
||||
public void setMtu(Integer mtu) {
|
||||
this.mtu = mtu;
|
||||
}
|
||||
|
||||
public boolean isServerEncrypt() {
|
||||
return serverEncrypt;
|
||||
}
|
||||
|
||||
public void setServerEncrypt(boolean serverEncrypt) {
|
||||
this.serverEncrypt = serverEncrypt;
|
||||
}
|
||||
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public String getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public void setServer(String server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public String[] getDns() {
|
||||
return dns;
|
||||
}
|
||||
|
||||
public void setDns(String[] dns) {
|
||||
this.dns = dns;
|
||||
}
|
||||
public String[] getPortMapping() {
|
||||
return portMapping;
|
||||
}
|
||||
|
||||
public void setPortMapping(String[] portMapping) {
|
||||
this.portMapping = portMapping;
|
||||
}
|
||||
|
||||
public String[] getStunServer() {
|
||||
return stunServer;
|
||||
}
|
||||
|
||||
public void setStunServer(String[] stunServer) {
|
||||
this.stunServer = stunServer;
|
||||
}
|
||||
|
||||
public boolean isTcp() {
|
||||
return tcp;
|
||||
}
|
||||
|
||||
public void setTcp(boolean tcp) {
|
||||
this.tcp = tcp;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public boolean isFinger() {
|
||||
return finger;
|
||||
}
|
||||
|
||||
public void setFinger(boolean finger) {
|
||||
this.finger = finger;
|
||||
}
|
||||
|
||||
public boolean isFirstLatency() {
|
||||
return firstLatency;
|
||||
}
|
||||
|
||||
public void setFirstLatency(boolean firstLatency) {
|
||||
this.firstLatency = firstLatency;
|
||||
}
|
||||
|
||||
public String[] getInIps() {
|
||||
return inIps;
|
||||
}
|
||||
|
||||
public void setInIps(String[] inIps) {
|
||||
this.inIps = inIps;
|
||||
}
|
||||
|
||||
public String[] getOutIps() {
|
||||
return outIps;
|
||||
}
|
||||
|
||||
public void setOutIps(String[] outIps) {
|
||||
this.outIps = outIps;
|
||||
}
|
||||
|
||||
public int[] getPorts() {
|
||||
return ports;
|
||||
}
|
||||
|
||||
public void setPorts(int[] ports) {
|
||||
this.ports = ports;
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
public void setDeviceName(String deviceName) {
|
||||
this.deviceName = deviceName;
|
||||
}
|
||||
|
||||
public String getUseChannel() {
|
||||
return useChannel;
|
||||
}
|
||||
|
||||
public void setUseChannel(String useChannel) {
|
||||
this.useChannel = useChannel;
|
||||
}
|
||||
|
||||
public Double getPacketLossRate() {
|
||||
return packetLossRate;
|
||||
}
|
||||
|
||||
public void setPacketLossRate(Double packetLossRate) {
|
||||
this.packetLossRate = packetLossRate;
|
||||
}
|
||||
|
||||
public Integer getPacketDelay() {
|
||||
return packetDelay;
|
||||
}
|
||||
|
||||
public void setPacketDelay(Integer packetDelay) {
|
||||
this.packetDelay = packetDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Config{" +
|
||||
"tap=" + tap +
|
||||
", token='" + token + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
", cipherModel='" + cipherModel + '\'' +
|
||||
", punchModel='" + punchModel + '\'' +
|
||||
", mtu=" + mtu +
|
||||
", serverEncrypt=" + serverEncrypt +
|
||||
", deviceId='" + deviceId + '\'' +
|
||||
", server='" + server + '\'' +
|
||||
", dns=" + Arrays.toString(dns) +
|
||||
", portMapping=" + Arrays.toString(portMapping) +
|
||||
", stunServer=" + Arrays.toString(stunServer) +
|
||||
", tcp=" + tcp +
|
||||
", ip='" + ip + '\'' +
|
||||
", finger=" + finger +
|
||||
", firstLatency=" + firstLatency +
|
||||
", inIps=" + Arrays.toString(inIps) +
|
||||
", outIps=" + Arrays.toString(outIps) +
|
||||
", ports=" + Arrays.toString(ports) +
|
||||
", deviceName='" + deviceName + '\'' +
|
||||
", useChannel='" + useChannel + '\'' +
|
||||
", packetLossRate=" + packetLossRate +
|
||||
", packetDelay=" + packetDelay +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package top.wherewego.vnt.jni;
|
||||
|
||||
/**
|
||||
* ip转换
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class IpUtils {
|
||||
/**
|
||||
* 将整数的ip地址转成字符串,例如 0 转成 "0.0.0.0"
|
||||
*
|
||||
* @param ipAddress
|
||||
* @return
|
||||
*/
|
||||
public static String intToIpAddress(int ipAddress) {
|
||||
|
||||
return ((ipAddress & 0xFF000000) >>> 24) + "." +
|
||||
((ipAddress & 0x00FF0000) >>> 16) + "." +
|
||||
((ipAddress & 0x0000FF00) >>> 8) + "." +
|
||||
(ipAddress & 0x000000FF);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回掩码的长度
|
||||
*
|
||||
* @param subnetMask
|
||||
* @return
|
||||
*/
|
||||
public static int subnetMaskToPrefixLength(int subnetMask) {
|
||||
int prefixLength = 0;
|
||||
int bit = 1 << 31;
|
||||
|
||||
while (subnetMask != 0) {
|
||||
if ((subnetMask & bit) != bit) {
|
||||
break;
|
||||
}
|
||||
prefixLength++;
|
||||
subnetMask <<= 1;
|
||||
}
|
||||
|
||||
return prefixLength;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package top.wherewego.vnt.jni;
|
||||
|
||||
/**
|
||||
* 对端设备信息
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class PeerRouteInfo {
|
||||
private final int virtualIp;
|
||||
private final String name;
|
||||
private final String status;
|
||||
private final Route route;
|
||||
|
||||
public PeerRouteInfo(int virtualIp, String name, String status, Route route) {
|
||||
this.virtualIp = virtualIp;
|
||||
this.name = name;
|
||||
this.status = status;
|
||||
this.route = route;
|
||||
}
|
||||
|
||||
public int getVirtualIp() {
|
||||
return virtualIp;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public Route getRoute() {
|
||||
return route;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PeerDeviceInfo{" +
|
||||
"virtualIp=" + IpUtils.intToIpAddress(virtualIp) +
|
||||
", name='" + name + '\'' +
|
||||
", status='" + status + '\'' +
|
||||
", route=" + route +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package top.wherewego.vnt.jni;
|
||||
|
||||
/**
|
||||
* 路由信息
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class Route {
|
||||
/**
|
||||
* 是否使用tcp
|
||||
*/
|
||||
private final boolean tcp;
|
||||
private final String address;
|
||||
private final byte metric;
|
||||
private final int rt;
|
||||
|
||||
|
||||
public Route(boolean tcp, String address, byte metric, int rt) {
|
||||
this.tcp = tcp;
|
||||
this.address = address;
|
||||
this.metric = metric;
|
||||
this.rt = rt;
|
||||
}
|
||||
|
||||
public boolean isTcp() {
|
||||
return tcp;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public byte getMetric() {
|
||||
return metric;
|
||||
}
|
||||
|
||||
public int getRt() {
|
||||
return rt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Route{" +
|
||||
"tcp=" + tcp +
|
||||
", address='" + address + '\'' +
|
||||
", metric=" + metric +
|
||||
", rt=" + rt +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package top.wherewego.vnt.jni;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* vnt的Java映射
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class Vnt implements Closeable {
|
||||
private final long raw;
|
||||
|
||||
public Vnt(Config config, CallBack callBack) throws Exception {
|
||||
this.raw = new0(config, callBack);
|
||||
if (this.raw == 0) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
stop0(raw);
|
||||
}
|
||||
|
||||
public void await() {
|
||||
wait0(raw);
|
||||
}
|
||||
|
||||
public boolean awaitTimeout(long ms) {
|
||||
return waitTimeout0(raw, ms);
|
||||
}
|
||||
|
||||
public PeerRouteInfo[] list() {
|
||||
return list0(raw);
|
||||
}
|
||||
|
||||
private native long new0(Config config, CallBack callBack) throws Exception;
|
||||
|
||||
private native void stop0(long raw);
|
||||
|
||||
private native void wait0(long raw);
|
||||
|
||||
private native boolean waitTimeout0(long raw, long ms);
|
||||
|
||||
private native void drop0(long raw);
|
||||
|
||||
private native PeerRouteInfo[] list0(long raw);
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
drop0(raw);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package top.wherewego.vnt.jni.param;
|
||||
|
||||
/**
|
||||
* 连接信息
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class ConnectInfo {
|
||||
private final long count;
|
||||
private final String address;
|
||||
|
||||
public ConnectInfo(long count, String address) {
|
||||
this.count = count;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConnectInfo{" +
|
||||
"count=" + count +
|
||||
", address='" + address + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package top.wherewego.vnt.jni.param;
|
||||
|
||||
import top.wherewego.vnt.jni.IpUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 创建网卡所需信息,仅在android上使用
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class DeviceConfig {
|
||||
/**
|
||||
* 虚拟IP
|
||||
*/
|
||||
public final int virtualIp;
|
||||
/**
|
||||
* 掩码
|
||||
*/
|
||||
public final int virtualNetmask;
|
||||
/**
|
||||
* 网关
|
||||
*/
|
||||
public final int virtualGateway;
|
||||
/**
|
||||
* 虚拟网段
|
||||
*/
|
||||
public final int virtualNetwork;
|
||||
/**
|
||||
* 额外路由,来自点对网的路由配置
|
||||
*/
|
||||
public final String[] externalRoute;
|
||||
|
||||
public DeviceConfig(int virtualIp, int virtualNetmask, int virtualGateway, int virtualNetwork, String[] externalRoute) {
|
||||
this.virtualIp = virtualIp;
|
||||
this.virtualNetmask = virtualNetmask;
|
||||
this.virtualGateway = virtualGateway;
|
||||
this.virtualNetwork = virtualNetwork;
|
||||
this.externalRoute = externalRoute;
|
||||
}
|
||||
|
||||
public int getVirtualIp() {
|
||||
return virtualIp;
|
||||
}
|
||||
|
||||
public int getVirtualNetmask() {
|
||||
return virtualNetmask;
|
||||
}
|
||||
|
||||
public int getVirtualGateway() {
|
||||
return virtualGateway;
|
||||
}
|
||||
|
||||
public int getVirtualNetwork() {
|
||||
return virtualNetwork;
|
||||
}
|
||||
|
||||
public String[] getExternalRoute() {
|
||||
return externalRoute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DeviceConfig{" +
|
||||
"virtualIp=" + IpUtils.intToIpAddress(virtualIp) +
|
||||
", virtualNetmask=" + IpUtils.intToIpAddress(virtualNetmask) +
|
||||
", virtualGateway=" + IpUtils.intToIpAddress(virtualGateway) +
|
||||
", virtualNetwork=" + IpUtils.intToIpAddress(virtualNetwork) +
|
||||
", externalRoute=" + Arrays.toString(externalRoute) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package top.wherewego.vnt.jni.param;
|
||||
|
||||
/**
|
||||
* 网卡信息 仅在 windows/linux/macos上使用
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class DeviceInfo {
|
||||
/**
|
||||
* 虚拟网卡名称
|
||||
*/
|
||||
private final String name;
|
||||
/**
|
||||
* 虚拟网卡版本
|
||||
*/
|
||||
private final String version;
|
||||
|
||||
public DeviceInfo(String name, String version) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DeviceInfo{" +
|
||||
"name='" + name + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package top.wherewego.vnt.jni.param;
|
||||
|
||||
/**
|
||||
* 异常回调信息
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class ErrorInfo {
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
public final ErrorCodeEnum code;
|
||||
/**
|
||||
* 错误信息,可能为空
|
||||
*/
|
||||
public final String msg;
|
||||
|
||||
public ErrorInfo(int code, String msg) {
|
||||
switch (code) {
|
||||
case 1:
|
||||
this.code = ErrorCodeEnum.TokenError;
|
||||
break;
|
||||
case 2:
|
||||
this.code = ErrorCodeEnum.Disconnect;
|
||||
break;
|
||||
case 3:
|
||||
this.code = ErrorCodeEnum.AddressExhausted;
|
||||
break;
|
||||
case 4:
|
||||
this.code = ErrorCodeEnum.IpAlreadyExists;
|
||||
break;
|
||||
case 5:
|
||||
this.code = ErrorCodeEnum.InvalidIp;
|
||||
break;
|
||||
default:
|
||||
this.code = ErrorCodeEnum.Unknown;
|
||||
}
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public ErrorCodeEnum getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public enum ErrorCodeEnum {
|
||||
TokenError,
|
||||
Disconnect,
|
||||
AddressExhausted,
|
||||
IpAlreadyExists,
|
||||
InvalidIp,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ErrorInfo{" +
|
||||
"code=" + code +
|
||||
", msg='" + msg + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package top.wherewego.vnt.jni.param;
|
||||
|
||||
/**
|
||||
* 握手回调信息
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class HandshakeInfo {
|
||||
/**
|
||||
* 公钥 pem格式 CRLF分隔,不加密时为空
|
||||
*/
|
||||
private final String publicKey;
|
||||
/**
|
||||
* 公钥签名,不加密时为空
|
||||
*/
|
||||
private final String finger;
|
||||
/**
|
||||
* 服务端版本
|
||||
*/
|
||||
private final String version;
|
||||
|
||||
public HandshakeInfo() {
|
||||
this.publicKey = "publicKey";
|
||||
this.finger = "finger";
|
||||
this.version = "version";
|
||||
}
|
||||
|
||||
public HandshakeInfo(String publicKey, String finger, String version) {
|
||||
this.publicKey = publicKey;
|
||||
this.finger = finger;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public String getFinger() {
|
||||
return finger;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HandshakeInfo{" +
|
||||
"publicKey='" + publicKey + '\'' +
|
||||
", finger='" + finger + '\'' +
|
||||
", version='" + version + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package top.wherewego.vnt.jni.param;
|
||||
|
||||
import top.wherewego.vnt.jni.IpUtils;
|
||||
|
||||
/**
|
||||
* 创建网卡所需信息,仅在android上使用
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class PeerClientInfo {
|
||||
/**
|
||||
* 虚拟IP
|
||||
*/
|
||||
public final int virtualIp;
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
public final String name;
|
||||
/**
|
||||
* 是否在线
|
||||
*/
|
||||
public final boolean online;
|
||||
/**
|
||||
* 是否开启客户端加密,不同加密状态的不能通信
|
||||
*/
|
||||
public final boolean clientSecret;
|
||||
|
||||
public PeerClientInfo(int virtualIp, String name, boolean online, boolean clientSecret) {
|
||||
this.virtualIp = virtualIp;
|
||||
this.name = name;
|
||||
this.online = online;
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
public int getVirtualIp() {
|
||||
return virtualIp;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isOnline() {
|
||||
return online;
|
||||
}
|
||||
|
||||
public boolean isClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PeerDeviceInfo{" +
|
||||
"virtualIp=" + IpUtils.intToIpAddress(virtualIp) +
|
||||
", name='" + name + '\'' +
|
||||
", online=" + online +
|
||||
", clientSecret=" + clientSecret +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package top.wherewego.vnt.jni.param;
|
||||
|
||||
import top.wherewego.vnt.jni.IpUtils;
|
||||
|
||||
/**
|
||||
* 注册回调信息
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class RegisterInfo {
|
||||
/**
|
||||
* 虚拟IP
|
||||
*/
|
||||
public final int virtualIp;
|
||||
/**
|
||||
* 掩码
|
||||
*/
|
||||
public final int virtualNetmask;
|
||||
/**
|
||||
* 网关
|
||||
*/
|
||||
public final int virtualGateway;
|
||||
|
||||
public RegisterInfo(int virtualIp, int virtualNetmask, int virtualGateway) {
|
||||
this.virtualIp = virtualIp;
|
||||
this.virtualNetmask = virtualNetmask;
|
||||
this.virtualGateway = virtualGateway;
|
||||
}
|
||||
|
||||
public int getVirtualIp() {
|
||||
return virtualIp;
|
||||
}
|
||||
|
||||
public int getVirtualNetmask() {
|
||||
return virtualNetmask;
|
||||
}
|
||||
|
||||
public int getVirtualGateway() {
|
||||
return virtualGateway;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RegisterInfo{" +
|
||||
"virtualIp='" + IpUtils.intToIpAddress(virtualIp) + '\'' +
|
||||
", virtualNetmask='" + IpUtils.intToIpAddress(virtualNetmask) + '\'' +
|
||||
", virtualGateway='" + IpUtils.intToIpAddress(virtualGateway) + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,322 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use jni::objects::{GlobalRef, JClass, JObject, JString, JValue};
|
||||
use jni::{JNIEnv, JavaVM};
|
||||
use spki::der::pem::LineEnding;
|
||||
use spki::EncodePublicKey;
|
||||
|
||||
use vnt::handle::callback::ConnectInfo;
|
||||
#[cfg(target_os = "android")]
|
||||
use vnt::handle::callback::DeviceConfig;
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
use vnt::DeviceInfo;
|
||||
use vnt::{ErrorInfo, HandshakeInfo, PeerClientInfo, RegisterInfo, VntCallback};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CallBack {
|
||||
jvm: Arc<JavaVM>,
|
||||
this: GlobalRef,
|
||||
connect_info_class: GlobalRef,
|
||||
handshake_info_class: GlobalRef,
|
||||
error_info_class: GlobalRef,
|
||||
register_info_class: GlobalRef,
|
||||
#[cfg(target_os = "android")]
|
||||
device_config_class: GlobalRef,
|
||||
peer_client_info_class: GlobalRef,
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
device_info_class: GlobalRef,
|
||||
}
|
||||
|
||||
unsafe impl Send for CallBack {}
|
||||
|
||||
fn find_class_global_ref(env: &mut JNIEnv, class: &str) -> jni::errors::Result<GlobalRef> {
|
||||
let class = env.find_class(class)?;
|
||||
env.new_global_ref(class)
|
||||
}
|
||||
impl CallBack {
|
||||
pub fn new(jvm: JavaVM, this: GlobalRef) -> jni::errors::Result<Self> {
|
||||
let mut env = jvm.attach_current_thread_as_daemon()?;
|
||||
let connect_info_class =
|
||||
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/ConnectInfo")?;
|
||||
let handshake_info_class =
|
||||
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/HandshakeInfo")?;
|
||||
let error_info_class =
|
||||
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/ErrorInfo")?;
|
||||
let register_info_class =
|
||||
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/RegisterInfo")?;
|
||||
#[cfg(target_os = "android")]
|
||||
let device_config_class = crate::callback::find_class_global_ref(
|
||||
&mut env,
|
||||
"top/wherewego/vnt/jni/param/DeviceConfig",
|
||||
)?;
|
||||
let peer_client_info_class =
|
||||
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/PeerClientInfo")?;
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
let device_info_class =
|
||||
find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/DeviceInfo")?;
|
||||
Ok(Self {
|
||||
jvm: Arc::new(jvm),
|
||||
this,
|
||||
connect_info_class,
|
||||
handshake_info_class,
|
||||
error_info_class,
|
||||
register_info_class,
|
||||
#[cfg(target_os = "android")]
|
||||
device_config_class,
|
||||
peer_client_info_class,
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
device_info_class,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl CallBack {
|
||||
fn success0(&self) -> jni::errors::Result<()> {
|
||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
||||
env.call_method(&self.this, "success", "()V", &[])?;
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
fn create_tun0(&self, info: DeviceInfo) -> jni::errors::Result<()> {
|
||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
||||
let class = unsafe { JClass::from_raw(self.device_info_class.as_raw()) };
|
||||
let param = env.new_object(
|
||||
class,
|
||||
"(Ljava/lang/String;Ljava/lang/String;)V",
|
||||
&[
|
||||
JValue::Object(&env.new_string(info.name)?.into()),
|
||||
JValue::Object(&env.new_string(info.version)?.into()),
|
||||
],
|
||||
)?;
|
||||
env.call_method(
|
||||
&self.this,
|
||||
"createTun",
|
||||
"(Ltop/wherewego/vnt/jni/param/DeviceInfo;)V",
|
||||
&[JValue::Object(¶m)],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
fn connect0(&self, info: ConnectInfo) -> jni::errors::Result<()> {
|
||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
||||
let class = unsafe { JClass::from_raw(self.connect_info_class.as_raw()) };
|
||||
let param = env.new_object(
|
||||
class,
|
||||
"(JLjava/lang/String;)V",
|
||||
&[
|
||||
JValue::Long(info.count as _),
|
||||
JValue::Object(&env.new_string(info.address.to_string())?.into()),
|
||||
],
|
||||
)?;
|
||||
env.call_method(
|
||||
&self.this,
|
||||
"connect",
|
||||
"(Ltop/wherewego/vnt/jni/param/ConnectInfo;)V",
|
||||
&[JValue::Object(¶m)],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
fn handshake0(&self, info: HandshakeInfo) -> jni::errors::Result<bool> {
|
||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
||||
let public_key = if let Some(public_key) = info.public_key {
|
||||
match public_key.to_public_key_pem(LineEnding::CRLF) {
|
||||
Ok(public_key) => env.new_string(public_key)?,
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
JString::default()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
JString::default()
|
||||
};
|
||||
let finger = if let Some(finger) = info.finger {
|
||||
env.new_string(finger)?
|
||||
} else {
|
||||
JString::default()
|
||||
};
|
||||
let class = unsafe { JClass::from_raw(self.handshake_info_class.as_raw()) };
|
||||
|
||||
let param = env.new_object(
|
||||
class,
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
|
||||
&[
|
||||
JValue::Object(&public_key),
|
||||
JValue::Object(&finger),
|
||||
JValue::Object(&env.new_string(info.version)?.into()),
|
||||
],
|
||||
)?;
|
||||
let rs = env.call_method(
|
||||
&self.this,
|
||||
"handshake",
|
||||
"(Ltop/wherewego/vnt/jni/param/HandshakeInfo;)Z",
|
||||
&[JValue::Object(¶m)],
|
||||
)?;
|
||||
rs.z()
|
||||
}
|
||||
fn register0(&self, info: RegisterInfo) -> jni::errors::Result<bool> {
|
||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
||||
let class = unsafe { JClass::from_raw(self.register_info_class.as_raw()) };
|
||||
let param = env.new_object(
|
||||
class,
|
||||
"(III)V",
|
||||
&[
|
||||
JValue::Int(u32::from(info.virtual_ip) as _),
|
||||
JValue::Int(u32::from(info.virtual_netmask) as _),
|
||||
JValue::Int(u32::from(info.virtual_gateway) as _),
|
||||
],
|
||||
)?;
|
||||
let rs = env.call_method(
|
||||
&self.this,
|
||||
"register",
|
||||
"(Ltop/wherewego/vnt/jni/param/RegisterInfo;)Z",
|
||||
&[JValue::Object(¶m)],
|
||||
)?;
|
||||
rs.z()
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
fn generate_tun0(&self, info: DeviceConfig) -> jni::errors::Result<u32> {
|
||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
||||
let class = unsafe { JClass::from_raw(self.device_config_class.as_raw()) };
|
||||
|
||||
let object_array = env.new_object_array(
|
||||
info.external_route.len() as _,
|
||||
"java/lang/String",
|
||||
JObject::null(),
|
||||
)?;
|
||||
for (index, (network, mask)) in info.external_route.into_iter().enumerate() {
|
||||
let param =
|
||||
env.new_string(format!("{}/{}", network, u32::from(mask).leading_ones()))?;
|
||||
env.set_object_array_element(&object_array, index as _, ¶m)?;
|
||||
}
|
||||
let param = env.new_object(
|
||||
class,
|
||||
"(IIII[Ljava/lang/String;)V",
|
||||
&[
|
||||
JValue::Int(u32::from(info.virtual_ip) as _),
|
||||
JValue::Int(u32::from(info.virtual_netmask) as _),
|
||||
JValue::Int(u32::from(info.virtual_gateway) as _),
|
||||
JValue::Int(u32::from(info.virtual_network) as _),
|
||||
JValue::Object(&object_array),
|
||||
],
|
||||
)?;
|
||||
let rs = env.call_method(
|
||||
&self.this,
|
||||
"generateTun",
|
||||
"(Ltop/wherewego/vnt/jni/param/DeviceConfig;)I",
|
||||
&[JValue::Object(¶m)],
|
||||
)?;
|
||||
rs.i().map(|v| v as _)
|
||||
}
|
||||
fn peer_client_list0(&self, info_vec: Vec<PeerClientInfo>) -> jni::errors::Result<()> {
|
||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
||||
let class = unsafe { JClass::from_raw(self.peer_client_info_class.as_raw()) };
|
||||
let object_array = env.new_object_array(info_vec.len() as _, &class, JObject::null())?;
|
||||
for (index, info) in info_vec.into_iter().enumerate() {
|
||||
let param = env.new_object(
|
||||
&class,
|
||||
"(ILjava/lang/String;ZZ)V",
|
||||
&[
|
||||
JValue::Int(u32::from(info.virtual_ip) as _),
|
||||
JValue::Object(&env.new_string(info.name)?.into()),
|
||||
JValue::Bool(info.status.is_online() as _),
|
||||
JValue::Bool(info.client_secret as _),
|
||||
],
|
||||
)?;
|
||||
env.set_object_array_element(&object_array, index as _, ¶m)?;
|
||||
}
|
||||
|
||||
env.call_method(
|
||||
&self.this,
|
||||
"peerClientList",
|
||||
"([Ltop/wherewego/vnt/jni/param/PeerClientInfo;)V",
|
||||
&[JValue::Object(&object_array)],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn error0(&self, info: ErrorInfo) -> jni::errors::Result<()> {
|
||||
let code: u8 = info.code.into();
|
||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
||||
let class = unsafe { JClass::from_raw(self.error_info_class.as_raw()) };
|
||||
let msg = if let Some(msg) = info.msg {
|
||||
env.new_string(msg)?
|
||||
} else {
|
||||
JString::default()
|
||||
};
|
||||
let param = env.new_object(
|
||||
class,
|
||||
"(ILjava/lang/String;)V",
|
||||
&[JValue::Int(code as _), JValue::Object(&msg.into())],
|
||||
)?;
|
||||
env.call_method(
|
||||
&self.this,
|
||||
"error",
|
||||
"(Ltop/wherewego/vnt/jni/param/ErrorInfo;)V",
|
||||
&[JValue::Object(¶m)],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
fn stop0(&self) -> jni::errors::Result<()> {
|
||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
||||
env.call_method(&self.this, "stop", "()V", &[])?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl VntCallback for CallBack {
|
||||
fn success(&self) {
|
||||
if let Err(e) = self.success0() {
|
||||
log::warn!("success {:?}", e);
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
fn create_tun(&self, info: DeviceInfo) {
|
||||
if let Err(e) = self.create_tun0(info) {
|
||||
log::warn!("create_tun {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn connect(&self, info: ConnectInfo) {
|
||||
if let Err(e) = self.connect0(info) {
|
||||
log::warn!("connect {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn handshake(&self, info: HandshakeInfo) -> bool {
|
||||
self.handshake0(info).unwrap_or_else(|e| {
|
||||
log::warn!("handshake {:?}", e);
|
||||
false
|
||||
})
|
||||
}
|
||||
|
||||
fn register(&self, info: RegisterInfo) -> bool {
|
||||
self.register0(info).unwrap_or_else(|e| {
|
||||
log::warn!("register {:?}", e);
|
||||
false
|
||||
})
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
fn generate_tun(&self, info: DeviceConfig) -> u32 {
|
||||
self.generate_tun0(info).unwrap_or_else(|e| {
|
||||
log::warn!("generate_tun {:?}", e);
|
||||
0
|
||||
})
|
||||
}
|
||||
|
||||
fn peer_client_list(&self, info: Vec<PeerClientInfo>) {
|
||||
if let Err(e) = self.peer_client_list0(info) {
|
||||
log::warn!("peer_client_list {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn error(&self, info: ErrorInfo) {
|
||||
if let Err(e) = self.error0(info) {
|
||||
log::warn!("error {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn stop(&self) {
|
||||
if let Err(e) = self.stop0() {
|
||||
log::warn!("stop {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use jni::errors::Error;
|
||||
use jni::objects::JObject;
|
||||
use jni::JNIEnv;
|
||||
|
||||
use vnt::channel::punch::PunchModel;
|
||||
use vnt::channel::UseChannelType;
|
||||
use vnt::cipher::CipherModel;
|
||||
use vnt::compression::Compressor;
|
||||
use vnt::core::Config;
|
||||
|
||||
use crate::utils::*;
|
||||
|
||||
pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
|
||||
#[cfg(target_os = "windows")]
|
||||
let tap = env.get_field(&config, "tap", "Z")?.z()?;
|
||||
let token = to_string_not_null(env, &config, "token")?;
|
||||
let name = to_string_not_null(env, &config, "name")?;
|
||||
let device_id = to_string_not_null(env, &config, "deviceId")?;
|
||||
let password = to_string(env, &config, "password")?;
|
||||
let server_address_str = to_string_not_null(env, &config, "server")?;
|
||||
let stun_server = to_string_array_not_null(env, &config, "stunServer")?;
|
||||
let dns = to_string_array(env, &config, "dns")?.unwrap_or_else(|| vec![]);
|
||||
let port_mapping = to_string_array(env, &config, "portMapping")?.unwrap_or_else(|| vec![]);
|
||||
let cipher_model = to_string_not_null(env, &config, "cipherModel")?;
|
||||
let punch_model = to_string(env, &config, "punchModel")?;
|
||||
let mtu = to_integer(env, &config, "mtu")?.map(|v| v as u32);
|
||||
let tcp = env.get_field(&config, "tcp", "Z")?.z()?;
|
||||
let server_encrypt = env.get_field(&config, "serverEncrypt", "Z")?.z()?;
|
||||
let use_channel = to_string(env, &config, "useChannel")?;
|
||||
let finger = env.get_field(&config, "finger", "Z")?.z()?;
|
||||
let first_latency = env.get_field(&config, "firstLatency", "Z")?.z()?;
|
||||
let packet_delay = to_integer(env, &config, "packetDelay")?
|
||||
.map(|v| v as u32)
|
||||
.unwrap_or_default();
|
||||
let packet_loss_rate = to_double(env, &config, "packetLossRate")?;
|
||||
|
||||
let in_ips = to_string_array(env, &config, "inIps")?;
|
||||
let out_ips = to_string_array(env, &config, "outIps")?;
|
||||
let ports =
|
||||
to_i32_array(env, &config, "ports")?.map(|v| v.into_iter().map(|v| v as u16).collect());
|
||||
let ip = if let Some(ip) = to_string(env, &config, "ip")? {
|
||||
match ip.parse() {
|
||||
Ok(ip) => Some(ip),
|
||||
Err(e) => {
|
||||
env.throw_new(
|
||||
"java/lang/RuntimeException",
|
||||
format!("ip {} err: {}", ip, e),
|
||||
)
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let in_ips = if let Some(in_ips) = in_ips {
|
||||
match common::args_parse::ips_parse(&in_ips) {
|
||||
Ok(in_ips) => in_ips,
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("in_ips {}", e))
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
let out_ips = if let Some(out_ips) = out_ips {
|
||||
match common::args_parse::out_ips_parse(&out_ips) {
|
||||
Ok(out_ips) => out_ips,
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("out_ips {}", e))
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let cipher_model = match CipherModel::from_str(&cipher_model) {
|
||||
Ok(cipher_model) => cipher_model,
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("cipher_model {}", e))
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
};
|
||||
#[cfg(not(target_os = "android"))]
|
||||
let device_name = to_string(env, &config, "deviceName")?;
|
||||
let config = match Config::new(
|
||||
#[cfg(target_os = "windows")]
|
||||
tap,
|
||||
token,
|
||||
device_id,
|
||||
name,
|
||||
server_address_str,
|
||||
dns,
|
||||
stun_server,
|
||||
in_ips,
|
||||
out_ips,
|
||||
password,
|
||||
mtu,
|
||||
tcp,
|
||||
ip,
|
||||
false,
|
||||
server_encrypt,
|
||||
1,
|
||||
cipher_model,
|
||||
finger,
|
||||
PunchModel::from_str(&punch_model.unwrap_or_default()).unwrap_or_default(),
|
||||
ports,
|
||||
first_latency,
|
||||
#[cfg(not(target_os = "android"))]
|
||||
device_name,
|
||||
UseChannelType::from_str(&use_channel.unwrap_or_default()).unwrap_or_default(),
|
||||
packet_loss_rate,
|
||||
packet_delay,
|
||||
port_mapping,
|
||||
Compressor::None,
|
||||
) {
|
||||
Ok(config) => config,
|
||||
Err(e) => {
|
||||
env.throw_new(
|
||||
"java/lang/RuntimeException",
|
||||
format!("vnt start error {:?}", e),
|
||||
)
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
};
|
||||
Ok(config)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
pub mod callback;
|
||||
pub mod config;
|
||||
pub mod utils;
|
||||
pub mod vnt;
|
||||
pub(crate) mod vnt_logger;
|
||||
@@ -1,131 +0,0 @@
|
||||
use jni::errors::Error;
|
||||
use jni::objects::{JIntArray, JObject, JObjectArray, JString};
|
||||
use jni::JNIEnv;
|
||||
|
||||
pub fn to_string_not_null(
|
||||
env: &mut JNIEnv,
|
||||
config: &JObject,
|
||||
name: &'static str,
|
||||
) -> Result<String, Error> {
|
||||
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
|
||||
if value.is_null() {
|
||||
env.throw_new("java/lang/NullPointerException", name)
|
||||
.expect("throw");
|
||||
return Err(Error::NullPtr(name));
|
||||
}
|
||||
let binding = JString::from(value);
|
||||
let value = env.get_string(binding.as_ref())?;
|
||||
match value.to_str() {
|
||||
Ok(value) => Ok(value.to_string()),
|
||||
Err(_) => {
|
||||
env.throw_new("java/lang/RuntimeException", "not utf-8")
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<String>, Error> {
|
||||
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
|
||||
if value.is_null() {
|
||||
return Ok(None);
|
||||
}
|
||||
let tmp = JString::from(value);
|
||||
let value = env.get_string(tmp.as_ref())?;
|
||||
match value.to_str() {
|
||||
Ok(value) => Ok(Some(value.to_string())),
|
||||
Err(_) => {
|
||||
env.throw_new("java/lang/RuntimeException", "not utf-8")
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string_array_not_null(
|
||||
env: &mut JNIEnv,
|
||||
config: &JObject,
|
||||
name: &str,
|
||||
) -> Result<Vec<String>, Error> {
|
||||
match to_string_array(env, config, name)? {
|
||||
None => {
|
||||
env.throw_new("java/lang/NullPointerException", name)
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
Some(rs) => Ok(rs),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string_array(
|
||||
env: &mut JNIEnv,
|
||||
config: &JObject,
|
||||
name: &str,
|
||||
) -> Result<Option<Vec<String>>, Error> {
|
||||
let value = env.get_field(config, name, "[Ljava/lang/String;")?.l()?;
|
||||
if value.is_null() {
|
||||
return Ok(None);
|
||||
}
|
||||
let arr = JObjectArray::from(value);
|
||||
let len = env.get_array_length(&arr)?;
|
||||
let mut rs = Vec::with_capacity(len as usize);
|
||||
for index in 0..len {
|
||||
let object = env.get_object_array_element(&arr, index)?;
|
||||
if object.is_null() {
|
||||
env.throw_new(
|
||||
"java/lang/NullPointerException",
|
||||
format!("{},index={}", name, index),
|
||||
)
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
match env.get_string(JString::from(object).as_ref())?.to_str() {
|
||||
Ok(value) => {
|
||||
rs.push(value.to_string());
|
||||
}
|
||||
Err(_) => {
|
||||
env.throw_new("java/lang/RuntimeException", "not utf-8")
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Some(rs))
|
||||
}
|
||||
|
||||
pub fn to_i32_array(
|
||||
env: &mut JNIEnv,
|
||||
config: &JObject,
|
||||
name: &str,
|
||||
) -> Result<Option<Vec<i32>>, Error> {
|
||||
let obj = env.get_field(&config, name, "[I")?.l()?;
|
||||
if obj.is_null() {
|
||||
Ok(None)
|
||||
} else {
|
||||
let j_arr = JIntArray::from(obj);
|
||||
let len = env.get_array_length(&j_arr)?;
|
||||
let mut arr = vec![0i32; len as usize];
|
||||
env.get_int_array_region(j_arr, 0, &mut arr)?;
|
||||
Ok(Some(arr))
|
||||
}
|
||||
}
|
||||
pub fn to_integer(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<i32>, Error> {
|
||||
let value = env.get_field(config, name, "Ljava/lang/Integer;")?.l()?;
|
||||
if value.is_null() {
|
||||
return Ok(None);
|
||||
}
|
||||
// 调用 intValue
|
||||
return Ok(Some(
|
||||
env.call_method(value, "intValue", "()I", &[])?.i()? as _
|
||||
));
|
||||
}
|
||||
pub fn to_double(env: &mut JNIEnv, config: &JObject, name: &str) -> Result<Option<f64>, Error> {
|
||||
let value = env.get_field(config, name, "Ljava/lang/Double;")?.l()?;
|
||||
if value.is_null() {
|
||||
return Ok(None);
|
||||
}
|
||||
// 调用 intValue
|
||||
return Ok(Some(
|
||||
env.call_method(value, "doubleValue", "()D", &[])?.d()? as _,
|
||||
));
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
use std::ptr;
|
||||
use std::time::Duration;
|
||||
|
||||
use jni::errors::Error;
|
||||
use jni::objects::{JClass, JObject, JValue};
|
||||
use jni::sys::{jboolean, jint, jlong, jobject, jobjectArray, jsize};
|
||||
use jni::JNIEnv;
|
||||
|
||||
use vnt::channel::Route;
|
||||
use vnt::core::Vnt;
|
||||
use vnt::handle::PeerDeviceInfo;
|
||||
|
||||
use crate::callback::CallBack;
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_new0(
|
||||
mut env: JNIEnv<'static>,
|
||||
_class: JClass,
|
||||
config: JObject,
|
||||
call_back: JObject<'static>,
|
||||
) -> jlong {
|
||||
crate::vnt_logger::init_log();
|
||||
let jvm = if let Ok(jvm) = env.get_java_vm() {
|
||||
jvm
|
||||
} else {
|
||||
return 0;
|
||||
};
|
||||
match crate::config::new_config(&mut env, config) {
|
||||
Ok(config) => {
|
||||
let call_back = if let Ok(call_back) = env.new_global_ref(call_back) {
|
||||
call_back
|
||||
} else {
|
||||
return 0;
|
||||
};
|
||||
let call_back = match CallBack::new(jvm, call_back) {
|
||||
Ok(call_back) => call_back,
|
||||
Err(_) => {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
let vnt_util = match Vnt::new(config, call_back) {
|
||||
Ok(vnt_util) => vnt_util,
|
||||
Err(e) => {
|
||||
env.throw_new(
|
||||
"java/lang/RuntimeException",
|
||||
format!("vnt start error {}", e),
|
||||
)
|
||||
.expect("throw");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
let ptr = Box::into_raw(Box::new(vnt_util));
|
||||
return ptr as jlong;
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_stop0(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt: jlong,
|
||||
) {
|
||||
let vnt = raw_vnt as *mut Vnt;
|
||||
let _ = (&*vnt).stop();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_wait0(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt: jlong,
|
||||
) {
|
||||
let vnt = raw_vnt as *mut Vnt;
|
||||
let _ = (&*vnt).wait();
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_waitTimeout0(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt: jlong,
|
||||
time: jlong,
|
||||
) -> jboolean {
|
||||
let vnt = raw_vnt as *mut Vnt;
|
||||
(&*vnt).wait_timeout(Duration::from_millis(time as _)) as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_drop0(
|
||||
_env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt: jlong,
|
||||
) {
|
||||
let vnt = raw_vnt as *mut Vnt;
|
||||
let _ = Box::from_raw(vnt).stop();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_list0(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
raw_vnt: jlong,
|
||||
) -> jobjectArray {
|
||||
let vnt = raw_vnt as *mut Vnt;
|
||||
let vnt = &mut *vnt;
|
||||
let list = vnt.device_list();
|
||||
|
||||
let arr = match env.new_object_array(
|
||||
list.len() as jsize,
|
||||
"top/wherewego/vnt/jni/PeerRouteInfo",
|
||||
JObject::null(),
|
||||
) {
|
||||
Ok(arr) => arr,
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
||||
.expect("throw");
|
||||
return ptr::null_mut();
|
||||
}
|
||||
};
|
||||
for (index, peer) in list.into_iter().enumerate() {
|
||||
let route = if let Some(route) = vnt.route(&peer.virtual_ip) {
|
||||
match route_parse(&mut env, route) {
|
||||
Ok(route) => JObject::from_raw(route),
|
||||
Err(_) => JObject::null(),
|
||||
}
|
||||
} else {
|
||||
JObject::null()
|
||||
};
|
||||
match peer_device_info_parse(&mut env, peer, route) {
|
||||
Ok(peer) => {
|
||||
match env.set_object_array_element(&arr, index as jsize, JObject::from_raw(peer)) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
||||
.expect("throw");
|
||||
return ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw_new("java/lang/RuntimeException", format!("error:{:?}", e))
|
||||
.expect("throw");
|
||||
return ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
arr.as_raw()
|
||||
}
|
||||
|
||||
fn route_parse(env: &mut JNIEnv, route: Route) -> Result<jobject, Error> {
|
||||
let rs = env.new_object(
|
||||
"top/wherewego/vnt/jni/Route",
|
||||
"(ZLjava/lang/String;BI)V",
|
||||
&[
|
||||
JValue::Bool(route.is_tcp as _),
|
||||
JValue::Object(&env.new_string(route.addr.to_string())?.into()),
|
||||
JValue::Byte(route.metric as _),
|
||||
JValue::Int(route.rt as _),
|
||||
],
|
||||
)?;
|
||||
Ok(rs.as_raw())
|
||||
}
|
||||
|
||||
fn peer_device_info_parse(
|
||||
env: &mut JNIEnv,
|
||||
peer: PeerDeviceInfo,
|
||||
route: JObject,
|
||||
) -> Result<jobject, Error> {
|
||||
let virtual_ip = u32::from(peer.virtual_ip);
|
||||
let name = peer.name.to_string();
|
||||
let status = format!("{:?}", peer.status);
|
||||
let rs = env.new_object(
|
||||
"top/wherewego/vnt/jni/PeerRouteInfo",
|
||||
"(ILjava/lang/String;Ljava/lang/String;Ltop/wherewego/vnt/jni/Route;)V",
|
||||
&[
|
||||
JValue::Int(virtual_ip as jint),
|
||||
JValue::Object(&env.new_string(name)?.into()),
|
||||
JValue::Object(&env.new_string(status)?.into()),
|
||||
JValue::Object(&route),
|
||||
],
|
||||
)?;
|
||||
Ok(rs.as_raw())
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn init_log() {
|
||||
use android_logger::Config;
|
||||
use log::LevelFilter;
|
||||
android_logger::init_once(
|
||||
Config::default()
|
||||
.with_max_level(LevelFilter::Info) // limit log level
|
||||
.with_tag("vnt_jni"), // logs will show under mytag tag
|
||||
);
|
||||
}
|
||||
#[cfg(not(target_os = "android"))]
|
||||
pub fn init_log() {}
|
||||
+3
-2
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
tun = { path = "tun" }
|
||||
tun = { path = "tun" ,optional = true}
|
||||
packet = { path = "./packet" }
|
||||
bytes = "1.5.0"
|
||||
log = "0.4.17"
|
||||
@@ -53,7 +53,7 @@ protoc-bin-vendored = "3.0.0"
|
||||
cfg_aliases = "0.2.1"
|
||||
|
||||
[features]
|
||||
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "lz4_compress", "zstd_compress"]
|
||||
default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "lz4_compress", "zstd_compress","integrated_tun"]
|
||||
openssl = ["openssl-sys"]
|
||||
# 从源码编译
|
||||
openssl-vendored = ["openssl-sys/vendored"]
|
||||
@@ -68,3 +68,4 @@ ip_proxy = ["tokio"]
|
||||
port_mapping = ["tokio"]
|
||||
lz4_compress = ["lz4_flex"]
|
||||
zstd_compress = ["zstd"]
|
||||
integrated_tun = ["tun"]
|
||||
|
||||
@@ -11,7 +11,7 @@ use parking_lot::RwLock;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::channel::punch::NatType;
|
||||
use crate::channel::sender::{AcceptSocketSender, ChannelSender, PacketSender};
|
||||
use crate::channel::sender::{AcceptSocketSender, PacketSender};
|
||||
use crate::channel::{Route, RouteKey, UseChannelType, DEFAULT_RT};
|
||||
|
||||
/// 传输通道上下文,持有udp socket、tcp socket和路由信息
|
||||
@@ -57,9 +57,6 @@ impl ChannelContext {
|
||||
inner: Arc::new(inner),
|
||||
}
|
||||
}
|
||||
pub fn sender(&self) -> ChannelSender {
|
||||
ChannelSender::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ChannelContext {
|
||||
|
||||
@@ -138,7 +138,7 @@ impl RouteKey {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_context(
|
||||
pub(crate) fn init_context(
|
||||
ports: Vec<u16>,
|
||||
use_channel_type: UseChannelType,
|
||||
first_latency: bool,
|
||||
@@ -233,7 +233,7 @@ pub fn init_context(
|
||||
Ok((context, tcp_listener))
|
||||
}
|
||||
|
||||
pub fn init_channel<H>(
|
||||
pub(crate) fn init_channel<H>(
|
||||
tcp_listener: mio::net::TcpListener,
|
||||
context: ChannelContext,
|
||||
stop_manager: StopManager,
|
||||
|
||||
+93
-12
@@ -1,31 +1,111 @@
|
||||
use std::io;
|
||||
use std::ops::Deref;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::mpsc::{SyncSender, TrySendError};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use mio::Token;
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::notify::{AcceptNotify, WritableNotify};
|
||||
use crate::cipher::Cipher;
|
||||
use crate::compression::Compressor;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::protocol;
|
||||
use crate::protocol::{ip_turn_packet, NetPacket};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ChannelSender {
|
||||
pub struct IpPacketSender {
|
||||
context: ChannelContext,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
compressor: Compressor,
|
||||
client_cipher: Cipher,
|
||||
ip_route: ExternalRoute,
|
||||
}
|
||||
|
||||
impl ChannelSender {
|
||||
pub fn new(context: ChannelContext) -> Self {
|
||||
Self { context }
|
||||
impl IpPacketSender {
|
||||
pub fn new(
|
||||
context: ChannelContext,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
compressor: Compressor,
|
||||
client_cipher: Cipher,
|
||||
ip_route: ExternalRoute,
|
||||
) -> Self {
|
||||
Self {
|
||||
context,
|
||||
current_device,
|
||||
compressor,
|
||||
client_cipher,
|
||||
ip_route,
|
||||
}
|
||||
}
|
||||
pub fn self_virtual_ip(&self) -> Ipv4Addr {
|
||||
self.current_device.load().virtual_ip
|
||||
}
|
||||
pub fn send_ip(
|
||||
&self,
|
||||
buf: &mut [u8],
|
||||
data_len: usize,
|
||||
auxiliary_buf: &mut [u8],
|
||||
mut dest_ip: Ipv4Addr,
|
||||
) -> anyhow::Result<()> {
|
||||
let device_info = self.current_device.load();
|
||||
let src_ip = device_info.virtual_ip;
|
||||
if src_ip.is_unspecified() {
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(v) = self.ip_route.route(&dest_ip) {
|
||||
dest_ip = v;
|
||||
}
|
||||
if dest_ip.is_multicast() || dest_ip.is_broadcast() || dest_ip == device_info.broadcast_ip {
|
||||
//广播
|
||||
dest_ip = Ipv4Addr::BROADCAST;
|
||||
}
|
||||
|
||||
let mut net_packet = NetPacket::new0(data_len, buf)?;
|
||||
let mut auxiliary = NetPacket::new(auxiliary_buf)?;
|
||||
net_packet.set_default_version();
|
||||
net_packet.set_protocol(protocol::Protocol::IpTurn);
|
||||
net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
|
||||
net_packet.first_set_ttl(6);
|
||||
net_packet.set_source(src_ip);
|
||||
net_packet.set_destination(dest_ip);
|
||||
|
||||
let mut net_packet = if self.compressor.compress(&net_packet, &mut auxiliary)? {
|
||||
auxiliary.set_default_version();
|
||||
auxiliary.set_protocol(protocol::Protocol::IpTurn);
|
||||
auxiliary.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into());
|
||||
auxiliary.first_set_ttl(6);
|
||||
auxiliary.set_source(src_ip);
|
||||
auxiliary.set_destination(dest_ip);
|
||||
auxiliary
|
||||
} else {
|
||||
net_packet
|
||||
};
|
||||
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
if dest_ip.is_broadcast() {
|
||||
//走服务端广播
|
||||
self.context
|
||||
.send_default(net_packet.buffer(), device_info.connect_server)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// if u32::from_be_bytes(dest_ip.octets()) & u32::from_be_bytes(device_info.virtual_netmask.octets())
|
||||
// != u32::from_be_bytes(device_info.virtual_network.octets()) {
|
||||
// //不是一个网段的直接忽略
|
||||
// return Ok(());
|
||||
// }
|
||||
self.context.send_ipv4_by_id(
|
||||
net_packet.buffer(),
|
||||
&dest_ip,
|
||||
device_info.connect_server,
|
||||
device_info.status.online(),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ChannelSender {
|
||||
type Target = ChannelContext;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.context
|
||||
}
|
||||
}
|
||||
pub struct AcceptSocketSender<T> {
|
||||
sender: SyncSender<T>,
|
||||
notify: AcceptNotify,
|
||||
@@ -39,6 +119,7 @@ impl<T> Clone for AcceptSocketSender<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AcceptSocketSender<T> {
|
||||
pub fn new(notify: AcceptNotify, sender: SyncSender<T>) -> Self {
|
||||
Self { sender, notify }
|
||||
|
||||
+81
-42
@@ -1,4 +1,3 @@
|
||||
use anyhow::Context;
|
||||
use std::collections::HashMap;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
@@ -7,16 +6,16 @@ use std::time::Duration;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use rand::Rng;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use tun::device::IFace;
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::idle::Idle;
|
||||
use crate::channel::punch::{NatInfo, Punch};
|
||||
use crate::channel::sender::IpPacketSender;
|
||||
use crate::channel::{init_channel, init_context, Route, RouteKey};
|
||||
use crate::cipher::Cipher;
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
use crate::cipher::RsaCipher;
|
||||
use crate::compression::Compressor;
|
||||
use crate::core::Config;
|
||||
use crate::external_route::{AllowExternalRoute, ExternalRoute};
|
||||
use crate::handle::handshaker::Handshake;
|
||||
@@ -24,13 +23,13 @@ use crate::handle::maintain::PunchReceiver;
|
||||
use crate::handle::recv_data::RecvDataHandler;
|
||||
use crate::handle::{maintain, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo};
|
||||
use crate::nat::NatTest;
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
use crate::tun_tap_device::tun_create_helper::{DeviceAdapter, TunDeviceHelper};
|
||||
use crate::tun_tap_device::vnt_device::DeviceWrite;
|
||||
use crate::util::{
|
||||
Scheduler, SingleU64Adder, StopManager, U64Adder, WatchSingleU64Adder, WatchU64Adder,
|
||||
};
|
||||
use crate::{nat, VntCallback};
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use crate::{tun_tap_device, DeviceInfo};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vnt {
|
||||
@@ -44,10 +43,29 @@ pub struct Vnt {
|
||||
down_count_watcher: WatchU64Adder,
|
||||
up_count_watcher: WatchSingleU64Adder,
|
||||
client_secret_hash: Option<[u8; 16]>,
|
||||
compressor: Compressor,
|
||||
client_cipher: Cipher,
|
||||
external_route: ExternalRoute,
|
||||
}
|
||||
|
||||
impl Vnt {
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
|
||||
Vnt::new_device0(config, callback, DeviceAdapter::default())
|
||||
}
|
||||
#[cfg(not(feature = "integrated_tun"))]
|
||||
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
|
||||
config: Config,
|
||||
callback: Call,
|
||||
device: Device,
|
||||
) -> anyhow::Result<Self> {
|
||||
Vnt::new_device0(config, callback, device)
|
||||
}
|
||||
fn new_device0<Call: VntCallback, Device: DeviceWrite>(
|
||||
config: Config,
|
||||
callback: Call,
|
||||
device: Device,
|
||||
) -> anyhow::Result<Self> {
|
||||
log::info!("config.toml:{:?}", config);
|
||||
//服务端非对称加密
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
@@ -85,6 +103,13 @@ impl Vnt {
|
||||
config.device_id.clone(),
|
||||
config.server_address_str.clone(),
|
||||
config.name_servers.clone(),
|
||||
config.mtu.unwrap_or(1420),
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(target_os = "windows")]
|
||||
config.tap,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
config.device_name.clone(),
|
||||
);
|
||||
// 服务停止管理器
|
||||
let stop_manager = {
|
||||
@@ -129,27 +154,13 @@ impl Vnt {
|
||||
udp_ports,
|
||||
tcp_port,
|
||||
);
|
||||
|
||||
// pc上先创建虚拟网卡
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
let device = {
|
||||
log::info!("开始创建tun");
|
||||
let device = tun_tap_device::create_device(&config).context("create tun failed")?;
|
||||
log::info!("创建tun成功");
|
||||
let tun_info = DeviceInfo::new(
|
||||
device.name().unwrap_or("unknown".into()),
|
||||
device.version().unwrap_or("unknown".into()),
|
||||
);
|
||||
log::info!("tun信息{:?}", tun_info);
|
||||
callback.create_tun(tun_info);
|
||||
device
|
||||
};
|
||||
// 定时器
|
||||
let scheduler = Scheduler::new(stop_manager.clone())?;
|
||||
let external_route = ExternalRoute::new(config.in_ips.clone());
|
||||
let out_external_route = AllowExternalRoute::new(config.out_ips.clone());
|
||||
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
let proxy_map = if !config.out_ips.is_empty() && !config.no_proxy {
|
||||
Some(crate::ip_proxy::init_proxy(
|
||||
context.clone(),
|
||||
@@ -172,24 +183,23 @@ impl Vnt {
|
||||
);
|
||||
let up_counter = SingleU64Adder::new();
|
||||
let up_count_watcher = up_counter.watch();
|
||||
let tun_helper = TunDeviceHelper::new(
|
||||
stop_manager.clone(),
|
||||
context.clone(),
|
||||
current_device.clone(),
|
||||
external_route.clone(),
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
proxy_map.clone(),
|
||||
client_cipher.clone(),
|
||||
server_cipher.clone(),
|
||||
config.parallel,
|
||||
up_counter,
|
||||
device_list.clone(),
|
||||
config.compressor,
|
||||
);
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
let device_adapter = DeviceAdapter::new(device.clone());
|
||||
#[cfg(target_os = "android")]
|
||||
let device_adapter = DeviceAdapter::new(tun_helper);
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
let tun_device_helper = {
|
||||
TunDeviceHelper::new(
|
||||
stop_manager.clone(),
|
||||
context.clone(),
|
||||
current_device.clone(),
|
||||
external_route.clone(),
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
proxy_map.clone(),
|
||||
client_cipher.clone(),
|
||||
server_cipher.clone(),
|
||||
up_counter,
|
||||
device_list.clone(),
|
||||
config.compressor,
|
||||
device.clone().into_device_adapter(),
|
||||
)
|
||||
};
|
||||
|
||||
let handler = RecvDataHandler::new(
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
@@ -197,7 +207,7 @@ impl Vnt {
|
||||
server_cipher.clone(),
|
||||
client_cipher.clone(),
|
||||
current_device.clone(),
|
||||
device_adapter,
|
||||
device,
|
||||
device_list.clone(),
|
||||
config_info.clone(),
|
||||
nat_test.clone(),
|
||||
@@ -207,9 +217,12 @@ impl Vnt {
|
||||
external_route.clone(),
|
||||
out_external_route,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
proxy_map.clone(),
|
||||
down_counter,
|
||||
handshake.clone(),
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
tun_device_helper,
|
||||
);
|
||||
|
||||
//初始化网络数据通道
|
||||
@@ -225,8 +238,8 @@ impl Vnt {
|
||||
nat_test.clone(),
|
||||
);
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
tun_helper.start(device)?;
|
||||
// #[cfg(not(target_os = "android"))]
|
||||
// tun_helper.start(device)?;
|
||||
|
||||
maintain::idle_gateway(
|
||||
&scheduler,
|
||||
@@ -255,6 +268,7 @@ impl Vnt {
|
||||
udp_socket_sender,
|
||||
);
|
||||
}
|
||||
let client_cipher = client_cipher.clone();
|
||||
//延迟启动
|
||||
scheduler.timeout(Duration::from_secs(3), move |scheduler| {
|
||||
start(
|
||||
@@ -274,7 +288,7 @@ impl Vnt {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
let compressor = config.compressor;
|
||||
Ok(Self {
|
||||
stop_manager,
|
||||
config,
|
||||
@@ -286,6 +300,9 @@ impl Vnt {
|
||||
down_count_watcher,
|
||||
up_count_watcher,
|
||||
client_secret_hash: config_info.client_secret_hash,
|
||||
compressor,
|
||||
client_cipher,
|
||||
external_route,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -382,6 +399,9 @@ impl Vnt {
|
||||
pub fn current_device(&self) -> CurrentDeviceInfo {
|
||||
self.current_device.load()
|
||||
}
|
||||
pub fn current_device_info(&self) -> Arc<AtomicCell<CurrentDeviceInfo>> {
|
||||
self.current_device.clone()
|
||||
}
|
||||
pub fn peer_nat_info(&self, ip: &Ipv4Addr) -> Option<NatInfo> {
|
||||
self.peer_nat_info_map.read().get(ip).cloned()
|
||||
}
|
||||
@@ -428,6 +448,12 @@ impl Vnt {
|
||||
let _ = self.context.lock().take();
|
||||
self.stop_manager.stop()
|
||||
}
|
||||
pub fn add_stop_listener<F>(&self, name: String, f: F) -> anyhow::Result<crate::util::Worker>
|
||||
where
|
||||
F: FnOnce() + Send + 'static,
|
||||
{
|
||||
self.stop_manager.add_listener(name, f)
|
||||
}
|
||||
pub fn wait(&self) {
|
||||
self.stop_manager.wait()
|
||||
}
|
||||
@@ -437,4 +463,17 @@ impl Vnt {
|
||||
pub fn config(&self) -> &Config {
|
||||
&self.config
|
||||
}
|
||||
pub fn ipv4_packet_sender(&self) -> Option<IpPacketSender> {
|
||||
if let Some(c) = self.context.lock().as_ref() {
|
||||
Some(IpPacketSender::new(
|
||||
c.clone(),
|
||||
self.current_device.clone(),
|
||||
self.compressor.clone(),
|
||||
self.client_cipher.clone(),
|
||||
self.external_route.clone(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-7
@@ -14,6 +14,7 @@ mod conn;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Config {
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(target_os = "windows")]
|
||||
pub tap: bool,
|
||||
pub token: String,
|
||||
@@ -30,15 +31,16 @@ pub struct Config {
|
||||
pub tcp: bool,
|
||||
pub ip: Option<Ipv4Addr>,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
pub no_proxy: bool,
|
||||
pub server_encrypt: bool,
|
||||
pub parallel: usize,
|
||||
pub cipher_model: CipherModel,
|
||||
pub finger: bool,
|
||||
pub punch_model: PunchModel,
|
||||
pub ports: Option<Vec<u16>>,
|
||||
pub first_latency: bool,
|
||||
#[cfg(not(target_os = "android"))]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
pub device_name: Option<String>,
|
||||
pub use_channel_type: UseChannelType,
|
||||
//控制丢包率
|
||||
@@ -52,7 +54,9 @@ pub struct Config {
|
||||
|
||||
impl Config {
|
||||
pub fn new(
|
||||
#[cfg(target_os = "windows")] tap: bool,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(target_os = "windows")]
|
||||
tap: bool,
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
@@ -65,15 +69,18 @@ impl Config {
|
||||
mtu: Option<u32>,
|
||||
tcp: bool,
|
||||
ip: Option<Ipv4Addr>,
|
||||
#[cfg(feature = "ip_proxy")] no_proxy: bool,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
no_proxy: bool,
|
||||
server_encrypt: bool,
|
||||
parallel: usize,
|
||||
cipher_model: CipherModel,
|
||||
finger: bool,
|
||||
punch_model: PunchModel,
|
||||
ports: Option<Vec<u16>>,
|
||||
first_latency: bool,
|
||||
#[cfg(not(target_os = "android"))] device_name: Option<String>,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(not(target_os = "android"))]
|
||||
device_name: Option<String>,
|
||||
use_channel_type: UseChannelType,
|
||||
packet_loss_rate: Option<f64>,
|
||||
packet_delay: u32,
|
||||
@@ -112,6 +119,7 @@ impl Config {
|
||||
}
|
||||
in_ips.sort_by(|(dest1, _, _), (dest2, _, _)| dest2.cmp(dest1));
|
||||
Ok(Self {
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(target_os = "windows")]
|
||||
tap,
|
||||
token,
|
||||
@@ -128,14 +136,15 @@ impl Config {
|
||||
tcp,
|
||||
ip,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
no_proxy,
|
||||
server_encrypt,
|
||||
parallel,
|
||||
cipher_model,
|
||||
finger,
|
||||
punch_model,
|
||||
ports,
|
||||
first_latency,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(not(target_os = "android"))]
|
||||
device_name,
|
||||
use_channel_type,
|
||||
|
||||
@@ -189,9 +189,16 @@ impl Into<u8> for ErrorType {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DeviceConfig {
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(target_os = "windows")]
|
||||
pub tap: bool,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
pub device_name: Option<String>,
|
||||
//虚拟网卡mtu值
|
||||
pub mtu: u32,
|
||||
//本机虚拟IP
|
||||
pub virtual_ip: Ipv4Addr,
|
||||
//子网掩码
|
||||
@@ -204,9 +211,15 @@ pub struct DeviceConfig {
|
||||
pub external_route: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
impl DeviceConfig {
|
||||
pub fn new(
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(target_os = "windows")]
|
||||
tap: bool,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
device_name: Option<String>,
|
||||
mtu: u32,
|
||||
virtual_ip: Ipv4Addr,
|
||||
virtual_netmask: Ipv4Addr,
|
||||
virtual_gateway: Ipv4Addr,
|
||||
@@ -214,6 +227,13 @@ impl DeviceConfig {
|
||||
external_route: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||
) -> Self {
|
||||
Self {
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(target_os = "windows")]
|
||||
tap,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
device_name,
|
||||
mtu,
|
||||
virtual_ip,
|
||||
virtual_netmask,
|
||||
virtual_gateway,
|
||||
@@ -223,7 +243,6 @@ impl DeviceConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
impl Display for DeviceConfig {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&format!(
|
||||
@@ -272,6 +291,7 @@ pub trait VntCallback: Clone + Send + Sync + 'static {
|
||||
|
||||
/// 创建网卡的信息
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
fn create_tun(&self, _info: DeviceInfo) {}
|
||||
/// 连接
|
||||
fn connect(&self, _info: ConnectInfo) {}
|
||||
@@ -283,8 +303,11 @@ pub trait VntCallback: Clone + Send + Sync + 'static {
|
||||
fn register(&self, _info: RegisterInfo) -> bool {
|
||||
true
|
||||
}
|
||||
#[cfg(not(feature = "integrated_tun"))]
|
||||
fn create_device(&self, _info: DeviceConfig) {}
|
||||
#[cfg(target_os = "android")]
|
||||
fn generate_tun(&self, _info: DeviceConfig) -> u32 {
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
fn generate_tun(&self, _info: DeviceConfig) -> usize {
|
||||
0
|
||||
}
|
||||
fn peer_client_list(&self, _info: Vec<PeerClientInfo>) {}
|
||||
|
||||
@@ -19,13 +19,6 @@ use crate::proto::message::SecretHandshakeRequest;
|
||||
use crate::protocol::body::RSA_ENCRYPTION_RESERVED;
|
||||
use crate::protocol::{service_packet, NetPacket, Protocol, MAX_TTL};
|
||||
|
||||
pub enum HandshakeEnum {
|
||||
NotSecret,
|
||||
KeyError,
|
||||
Timeout,
|
||||
ServerError(String),
|
||||
Other(String),
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct Handshake {
|
||||
time: Arc<AtomicCell<Instant>>,
|
||||
|
||||
+22
-6
@@ -7,6 +7,7 @@ pub mod handshaker;
|
||||
pub mod maintain;
|
||||
pub mod recv_data;
|
||||
pub mod registrar;
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
pub mod tun_tap;
|
||||
|
||||
const SELF_IP: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 2);
|
||||
@@ -21,12 +22,6 @@ pub fn now_time() -> u64 {
|
||||
}
|
||||
}
|
||||
|
||||
/// 是否在一个网段
|
||||
fn check_dest(dest: Ipv4Addr, virtual_netmask: Ipv4Addr, virtual_network: Ipv4Addr) -> bool {
|
||||
u32::from_be_bytes(dest.octets()) & u32::from_be_bytes(virtual_netmask.octets())
|
||||
== u32::from_be_bytes(virtual_network.octets())
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct PeerDeviceInfo {
|
||||
pub virtual_ip: Ipv4Addr,
|
||||
@@ -64,6 +59,13 @@ pub struct BaseConfigInfo {
|
||||
pub device_id: String,
|
||||
pub server_addr: String,
|
||||
pub name_servers: Vec<String>,
|
||||
pub mtu: u32,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(target_os = "windows")]
|
||||
pub tap: bool,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
pub device_name: Option<String>,
|
||||
}
|
||||
|
||||
impl BaseConfigInfo {
|
||||
@@ -76,6 +78,13 @@ impl BaseConfigInfo {
|
||||
device_id: String,
|
||||
server_addr: String,
|
||||
name_servers: Vec<String>,
|
||||
mtu: u32,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(target_os = "windows")]
|
||||
tap: bool,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
device_name: Option<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
@@ -86,6 +95,13 @@ impl BaseConfigInfo {
|
||||
device_id,
|
||||
server_addr,
|
||||
name_servers,
|
||||
mtu,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(target_os = "windows")]
|
||||
tap,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
device_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ use protobuf::Message;
|
||||
use packet::icmp::{icmp, Kind};
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
use tun::device::IFace;
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::punch::NatInfo;
|
||||
@@ -30,30 +28,33 @@ use crate::protocol::control_packet::ControlPacket;
|
||||
use crate::protocol::{
|
||||
control_packet, ip_turn_packet, other_turn_packet, NetPacket, Protocol, MAX_TTL,
|
||||
};
|
||||
use crate::tun_tap_device::tun_create_helper::DeviceAdapter;
|
||||
use crate::tun_tap_device::vnt_device::DeviceWrite;
|
||||
|
||||
/// 处理来源于客户端的包
|
||||
#[derive(Clone)]
|
||||
pub struct ClientPacketHandler {
|
||||
device: DeviceAdapter,
|
||||
pub struct ClientPacketHandler<Device> {
|
||||
device: Device,
|
||||
client_cipher: Cipher,
|
||||
punch_sender: PunchSender,
|
||||
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
||||
nat_test: NatTest,
|
||||
route: AllowExternalRoute,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
}
|
||||
|
||||
impl ClientPacketHandler {
|
||||
impl<Device: DeviceWrite> ClientPacketHandler<Device> {
|
||||
pub fn new(
|
||||
device: DeviceAdapter,
|
||||
device: Device,
|
||||
client_cipher: Cipher,
|
||||
punch_sender: PunchSender,
|
||||
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
||||
nat_test: NatTest,
|
||||
route: AllowExternalRoute,
|
||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
) -> Self {
|
||||
Self {
|
||||
device,
|
||||
@@ -62,13 +63,14 @@ impl ClientPacketHandler {
|
||||
peer_nat_info_map,
|
||||
nat_test,
|
||||
route,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
ip_proxy_map,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketHandler for ClientPacketHandler {
|
||||
impl<Device: DeviceWrite> PacketHandler for ClientPacketHandler<Device> {
|
||||
fn handle(
|
||||
&self,
|
||||
mut net_packet: NetPacket<&mut [u8]>,
|
||||
@@ -110,7 +112,7 @@ impl PacketHandler for ClientPacketHandler {
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientPacketHandler {
|
||||
impl<Device: DeviceWrite> ClientPacketHandler<Device> {
|
||||
fn ip_turn(
|
||||
&self,
|
||||
mut net_packet: NetPacket<&mut [u8]>,
|
||||
@@ -183,6 +185,7 @@ impl ClientPacketHandler {
|
||||
_ => {}
|
||||
}
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
if let Some(ip_proxy_map) = &self.ip_proxy_map {
|
||||
if ip_proxy_map.recv_handle(&mut ipv4, source, destination)? {
|
||||
return Ok(());
|
||||
|
||||
@@ -25,7 +25,7 @@ use crate::handle::{BaseConfigInfo, CurrentDeviceInfo, PeerDeviceInfo, SELF_IP};
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::nat::NatTest;
|
||||
use crate::protocol::{NetPacket, HEAD_LEN};
|
||||
use crate::tun_tap_device::tun_create_helper::DeviceAdapter;
|
||||
use crate::tun_tap_device::vnt_device::DeviceWrite;
|
||||
use crate::util::U64Adder;
|
||||
|
||||
mod client;
|
||||
@@ -33,16 +33,16 @@ mod server;
|
||||
mod turn;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RecvDataHandler<Call> {
|
||||
pub struct RecvDataHandler<Call, Device> {
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
turn: TurnPacketHandler,
|
||||
client: ClientPacketHandler,
|
||||
server: ServerPacketHandler<Call>,
|
||||
client: ClientPacketHandler<Device>,
|
||||
server: ServerPacketHandler<Call, Device>,
|
||||
counter: U64Adder,
|
||||
nat_test: NatTest,
|
||||
}
|
||||
|
||||
impl<Call: VntCallback> RecvChannelHandler for RecvDataHandler<Call> {
|
||||
impl<Call: VntCallback, Device: DeviceWrite> RecvChannelHandler for RecvDataHandler<Call, Device> {
|
||||
fn handle(
|
||||
&mut self,
|
||||
buf: &mut [u8],
|
||||
@@ -75,13 +75,13 @@ impl<Call: VntCallback> RecvChannelHandler for RecvDataHandler<Call> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: VntCallback> RecvDataHandler<Call> {
|
||||
impl<Call: VntCallback, Device: DeviceWrite> RecvDataHandler<Call, Device> {
|
||||
pub fn new(
|
||||
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
||||
server_cipher: Cipher,
|
||||
client_cipher: Cipher,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
device: DeviceAdapter,
|
||||
device: Device,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
config_info: BaseConfigInfo,
|
||||
nat_test: NatTest,
|
||||
@@ -90,9 +90,13 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
|
||||
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
||||
external_route: ExternalRoute,
|
||||
route: AllowExternalRoute,
|
||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
counter: U64Adder,
|
||||
handshake: Handshake,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
tun_device_helper: crate::tun_tap_device::tun_create_helper::TunDeviceHelper,
|
||||
) -> Self {
|
||||
let server = ServerPacketHandler::new(
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
@@ -106,6 +110,8 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
|
||||
callback,
|
||||
external_route.clone(),
|
||||
handshake,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
tun_device_helper,
|
||||
);
|
||||
let client = ClientPacketHandler::new(
|
||||
device.clone(),
|
||||
@@ -114,6 +120,7 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
|
||||
peer_nat_info_map,
|
||||
nat_test.clone(),
|
||||
route,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
ip_proxy_map,
|
||||
);
|
||||
|
||||
@@ -12,8 +12,6 @@ use protobuf::Message;
|
||||
use packet::icmp::{icmp, Kind};
|
||||
use packet::ip::ipv4;
|
||||
use packet::ip::ipv4::packet::IpV4Packet;
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
use tun::device::IFace;
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::{Route, RouteKey};
|
||||
@@ -35,41 +33,43 @@ use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
use crate::protocol::control_packet::ControlPacket;
|
||||
use crate::protocol::error_packet::InErrorPacket;
|
||||
use crate::protocol::{ip_turn_packet, service_packet, NetPacket, Protocol, MAX_TTL};
|
||||
use crate::tun_tap_device::tun_create_helper::DeviceAdapter;
|
||||
use crate::tun_tap_device::vnt_device::DeviceWrite;
|
||||
use crate::{proto, PeerClientInfo};
|
||||
|
||||
/// 处理来源于服务端的包
|
||||
#[derive(Clone)]
|
||||
pub struct ServerPacketHandler<Call> {
|
||||
pub struct ServerPacketHandler<Call, Device> {
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
||||
server_cipher: Cipher,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
device: DeviceAdapter,
|
||||
device: Device,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
config_info: BaseConfigInfo,
|
||||
nat_test: NatTest,
|
||||
callback: Call,
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
up_key_time: Arc<AtomicCell<Instant>>,
|
||||
#[cfg(not(target_os = "android"))]
|
||||
route_record: Arc<Mutex<Vec<(Ipv4Addr, Ipv4Addr)>>>,
|
||||
external_route: ExternalRoute,
|
||||
handshake: Handshake,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
tun_device_helper: crate::tun_tap_device::tun_create_helper::TunDeviceHelper,
|
||||
}
|
||||
|
||||
impl<Call> ServerPacketHandler<Call> {
|
||||
impl<Call, Device> ServerPacketHandler<Call, Device> {
|
||||
pub fn new(
|
||||
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
||||
server_cipher: Cipher,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
device: DeviceAdapter,
|
||||
device: Device,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
config_info: BaseConfigInfo,
|
||||
nat_test: NatTest,
|
||||
callback: Call,
|
||||
external_route: ExternalRoute,
|
||||
handshake: Handshake,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
tun_device_helper: crate::tun_tap_device::tun_create_helper::TunDeviceHelper,
|
||||
) -> Self {
|
||||
Self {
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
@@ -83,15 +83,15 @@ impl<Call> ServerPacketHandler<Call> {
|
||||
callback,
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
up_key_time: Arc::new(AtomicCell::new(Instant::now() - Duration::from_secs(60))),
|
||||
#[cfg(not(target_os = "android"))]
|
||||
route_record: Arc::new(Mutex::default()),
|
||||
external_route,
|
||||
handshake,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
tun_device_helper,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
||||
impl<Call: VntCallback, Device: DeviceWrite> PacketHandler for ServerPacketHandler<Call, Device> {
|
||||
fn handle(
|
||||
&self,
|
||||
mut net_packet: NetPacket<&mut [u8]>,
|
||||
@@ -246,7 +246,7 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: VntCallback> ServerPacketHandler<Call> {
|
||||
impl<Call: VntCallback, Device: DeviceWrite> ServerPacketHandler<Call, Device> {
|
||||
fn service(
|
||||
&self,
|
||||
context: &ChannelContext,
|
||||
@@ -305,80 +305,85 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
||||
if old.virtual_ip != Ipv4Addr::UNSPECIFIED {
|
||||
log::info!("ip发生变化,old:{:?},response={:?}", old, response);
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
let device_config = crate::handle::callback::DeviceConfig::new(
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(target_os = "windows")]
|
||||
self.config_info.tap,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(any(
|
||||
target_os = "windows",
|
||||
target_os = "linux",
|
||||
target_os = "macos"
|
||||
))]
|
||||
self.config_info.device_name.clone(),
|
||||
self.config_info.mtu,
|
||||
virtual_ip,
|
||||
virtual_netmask,
|
||||
virtual_gateway,
|
||||
virtual_network,
|
||||
self.external_route.to_route(),
|
||||
);
|
||||
#[cfg(not(feature = "integrated_tun"))]
|
||||
self.callback.create_device(device_config);
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
{
|
||||
let device_config = crate::handle::callback::DeviceConfig::new(
|
||||
virtual_ip,
|
||||
virtual_netmask,
|
||||
virtual_gateway,
|
||||
virtual_network,
|
||||
self.external_route.to_route(),
|
||||
);
|
||||
let device_fd = self.callback.generate_tun(device_config);
|
||||
if device_fd == 0 {
|
||||
self.callback.error(ErrorInfo::new_msg(
|
||||
ErrorType::Unknown,
|
||||
"device_fd == 0".into(),
|
||||
));
|
||||
} else {
|
||||
if let Err(e) = self.device.start(device_fd as _) {
|
||||
self.tun_device_helper.stop();
|
||||
#[cfg(any(
|
||||
target_os = "windows",
|
||||
target_os = "linux",
|
||||
target_os = "macos"
|
||||
))]
|
||||
match crate::tun_tap_device::create_device(device_config) {
|
||||
Ok(device) => {
|
||||
use tun::device::IFace;
|
||||
let tun_info = crate::handle::callback::DeviceInfo::new(
|
||||
device.name().unwrap_or("unknown".into()),
|
||||
device.version().unwrap_or("unknown".into()),
|
||||
);
|
||||
log::info!("tun信息{:?}", tun_info);
|
||||
self.callback.create_tun(tun_info);
|
||||
self.tun_device_helper.start(device)?;
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}", e);
|
||||
self.callback.error(e);
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
let device_config = crate::handle::callback::DeviceConfig::new(
|
||||
self.config_info.mtu,
|
||||
virtual_ip,
|
||||
virtual_netmask,
|
||||
virtual_gateway,
|
||||
virtual_network,
|
||||
self.external_route.to_route(),
|
||||
);
|
||||
let device_fd = self.callback.generate_tun(device_config);
|
||||
if device_fd == 0 {
|
||||
self.callback.error(ErrorInfo::new_msg(
|
||||
ErrorType::Unknown,
|
||||
format!("{:?}", e),
|
||||
"device_fd == 0".into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_os = "android"))]
|
||||
{
|
||||
if let Err(e) = self.device.set_ip(virtual_ip, virtual_netmask) {
|
||||
log::error!("LocalIpExists {:?}", e);
|
||||
self.callback.error(ErrorInfo::new_msg(
|
||||
ErrorType::LocalIpExists,
|
||||
format!("set_ip {:?}", e),
|
||||
));
|
||||
return Ok(());
|
||||
}
|
||||
let mut guard = self.route_record.lock();
|
||||
for (dest, mask) in guard.drain(..) {
|
||||
if let Err(e) = self.device.delete_route(dest, mask) {
|
||||
log::warn!("删除路由失败 ={:?}", e);
|
||||
}
|
||||
}
|
||||
if let Err(e) =
|
||||
self.device.add_route(virtual_network, virtual_netmask, 1)
|
||||
{
|
||||
log::warn!("添加默认路由失败 ={:?}", e);
|
||||
} else {
|
||||
guard.push((virtual_network, virtual_netmask));
|
||||
}
|
||||
if let Err(e) =
|
||||
self.device
|
||||
.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, 1)
|
||||
{
|
||||
log::warn!("添加广播路由失败 ={:?}", e);
|
||||
} else {
|
||||
guard.push((Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST));
|
||||
}
|
||||
|
||||
if let Err(e) = self.device.add_route(
|
||||
Ipv4Addr::from([224, 0, 0, 0]),
|
||||
Ipv4Addr::from([240, 0, 0, 0]),
|
||||
1,
|
||||
) {
|
||||
log::warn!("添加组播路由失败 ={:?}", e);
|
||||
} else {
|
||||
guard.push((
|
||||
Ipv4Addr::from([224, 0, 0, 0]),
|
||||
Ipv4Addr::from([240, 0, 0, 0]),
|
||||
));
|
||||
}
|
||||
|
||||
for (dest, mask) in self.external_route.to_route() {
|
||||
if let Err(e) = self.device.add_route(dest, mask, 1) {
|
||||
log::warn!("添加路由失败 ={:?}", e);
|
||||
} else {
|
||||
guard.push((dest, mask));
|
||||
match tun::Device::new(device_fd as _) {
|
||||
Ok(device) => {
|
||||
if let Err(e) =
|
||||
self.tun_device_helper.start(Arc::new(device))
|
||||
{
|
||||
self.callback.error(ErrorInfo::new_msg(
|
||||
ErrorType::Unknown,
|
||||
format!("{:?}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
self.callback.error(ErrorInfo::new_msg(
|
||||
ErrorType::Unknown,
|
||||
format!("{:?}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
use std::sync::mpsc::{sync_channel, Receiver, SendError, SyncSender};
|
||||
|
||||
pub fn channel_group<T>(size: usize, bound: usize) -> (GroupSyncSender<T>, Vec<Receiver<T>>) {
|
||||
let mut senders = Vec::with_capacity(size);
|
||||
let mut receivers = Vec::with_capacity(size);
|
||||
for _ in 0..size {
|
||||
let (s, r) = sync_channel(bound);
|
||||
senders.push(s);
|
||||
receivers.push(r);
|
||||
}
|
||||
(
|
||||
GroupSyncSender {
|
||||
count: 0,
|
||||
base: senders,
|
||||
},
|
||||
receivers,
|
||||
)
|
||||
}
|
||||
|
||||
pub struct GroupSyncSender<T> {
|
||||
count: usize,
|
||||
base: Vec<SyncSender<T>>,
|
||||
}
|
||||
|
||||
impl<T> GroupSyncSender<T> {
|
||||
pub fn send(&mut self, t: T) -> Result<(), SendError<T>> {
|
||||
self.count += 1;
|
||||
self.base[self.count % self.base.len()].send(t)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,45 @@
|
||||
mod channel_group;
|
||||
pub mod tun_handler;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod unix;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
#[cfg(unix)]
|
||||
pub(crate) use unix::*;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub(crate) use windows::*;
|
||||
|
||||
/// 仅仅是停止tun,不停止vnt
|
||||
#[derive(Clone, Default)]
|
||||
pub struct DeviceStop {
|
||||
f: Arc<Mutex<Option<Box<dyn FnOnce() -> bool + Send>>>>,
|
||||
stopped: Arc<AtomicCell<bool>>,
|
||||
}
|
||||
|
||||
impl DeviceStop {
|
||||
pub fn set_stop_fn<F>(&self, f: F)
|
||||
where
|
||||
F: FnOnce() -> bool + Send + 'static,
|
||||
{
|
||||
self.f.lock().replace(Box::new(f));
|
||||
}
|
||||
pub fn stop(&self) -> bool {
|
||||
if let Some(f) = self.f.lock().take() {
|
||||
f()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
pub fn stopped(&self) {
|
||||
self.stopped.store(true);
|
||||
}
|
||||
pub fn is_stop(&self) -> bool {
|
||||
self.stopped.load()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,11 @@ use tun::device::IFace;
|
||||
use tun::Device;
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::BUFFER_SIZE;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::compression::Compressor;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::tun_tap::channel_group::channel_group;
|
||||
use crate::handle::{check_dest, CurrentDeviceInfo, PeerDeviceInfo};
|
||||
use crate::handle::tun_tap::DeviceStop;
|
||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
@@ -28,7 +27,12 @@ use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
use crate::protocol::ip_turn_packet::BroadcastPacket;
|
||||
use crate::protocol::{ip_turn_packet, NetPacket, MAX_TTL};
|
||||
use crate::util::{SingleU64Adder, StopManager};
|
||||
|
||||
/// 是否在一个网段
|
||||
#[inline]
|
||||
fn check_dest(dest: Ipv4Addr, virtual_netmask: Ipv4Addr, virtual_network: Ipv4Addr) -> bool {
|
||||
u32::from_be_bytes(dest.octets()) & u32::from_be_bytes(virtual_netmask.octets())
|
||||
== u32::from_be_bytes(virtual_network.octets())
|
||||
}
|
||||
fn icmp(device_writer: &Device, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> anyhow::Result<()> {
|
||||
if ipv4_packet.protocol() == Protocol::Icmp {
|
||||
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
|
||||
@@ -54,89 +58,33 @@ pub fn start(
|
||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
parallel: usize,
|
||||
mut up_counter: SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
compressor: Compressor,
|
||||
device_stop: DeviceStop,
|
||||
) -> io::Result<()> {
|
||||
if parallel > 1 {
|
||||
let (sender, receivers) = channel_group::<(Vec<u8>, usize)>(parallel, 16);
|
||||
for (index, receiver) in receivers.into_iter().enumerate() {
|
||||
let context = context.clone();
|
||||
let device = device.clone();
|
||||
let current_device = current_device.clone();
|
||||
let ip_route = ip_route.clone();
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
let ip_proxy_map = ip_proxy_map.clone();
|
||||
let client_cipher = client_cipher.clone();
|
||||
let server_cipher = server_cipher.clone();
|
||||
let device_list = device_list.clone();
|
||||
thread::Builder::new()
|
||||
.name(format!("tunHandler-{}", index))
|
||||
.spawn(move || {
|
||||
let mut extend = [0; BUFFER_SIZE];
|
||||
while let Ok((mut buf, len)) = receiver.recv() {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let start = 0;
|
||||
#[cfg(target_os = "macos")]
|
||||
let start = 4;
|
||||
match handle(
|
||||
&context,
|
||||
&mut buf[start..],
|
||||
len,
|
||||
&mut extend,
|
||||
&device,
|
||||
current_device.load(),
|
||||
&ip_route,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
&ip_proxy_map,
|
||||
&client_cipher,
|
||||
&server_cipher,
|
||||
&device_list,
|
||||
&compressor,
|
||||
) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
})?;
|
||||
}
|
||||
thread::Builder::new()
|
||||
.name("tunHandlerM".into())
|
||||
.spawn(move || {
|
||||
if let Err(e) = crate::handle::tun_tap::start_multi(
|
||||
stop_manager,
|
||||
device,
|
||||
sender,
|
||||
&mut up_counter,
|
||||
) {
|
||||
log::warn!("stop:{}", e);
|
||||
}
|
||||
})?;
|
||||
} else {
|
||||
thread::Builder::new()
|
||||
.name("tunHandlerS".into())
|
||||
.spawn(move || {
|
||||
if let Err(e) = crate::handle::tun_tap::start_simple(
|
||||
stop_manager,
|
||||
&context,
|
||||
device,
|
||||
current_device,
|
||||
ip_route,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
ip_proxy_map,
|
||||
client_cipher,
|
||||
server_cipher,
|
||||
&mut up_counter,
|
||||
device_list,
|
||||
compressor,
|
||||
) {
|
||||
log::warn!("stop:{}", e);
|
||||
}
|
||||
})?;
|
||||
}
|
||||
thread::Builder::new()
|
||||
.name("tunHandlerS".into())
|
||||
.spawn(move || {
|
||||
if let Err(e) = crate::handle::tun_tap::start_simple(
|
||||
stop_manager,
|
||||
&context,
|
||||
device,
|
||||
current_device,
|
||||
ip_route,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
ip_proxy_map,
|
||||
client_cipher,
|
||||
server_cipher,
|
||||
&mut up_counter,
|
||||
device_list,
|
||||
compressor,
|
||||
device_stop,
|
||||
) {
|
||||
log::warn!("stop:{}", e);
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::channel::BUFFER_SIZE;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::compression::Compressor;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::tun_tap::channel_group::GroupSyncSender;
|
||||
use crate::handle::tun_tap::DeviceStop;
|
||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
@@ -33,13 +33,38 @@ pub(crate) fn start_simple(
|
||||
up_counter: &mut SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
compressor: Compressor,
|
||||
device_stop: DeviceStop,
|
||||
) -> anyhow::Result<()> {
|
||||
let stop_all = Arc::new(AtomicCell::new(true));
|
||||
let poll = Poll::new()?;
|
||||
let waker = Arc::new(Waker::new(poll.registry(), STOP)?);
|
||||
let _waker = waker.clone();
|
||||
let worker = stop_manager.add_listener("tun_device".into(), move || {
|
||||
let _ = waker.wake();
|
||||
})?;
|
||||
let device_cell = Arc::new(AtomicCell::new(Some(waker)));
|
||||
let worker = {
|
||||
let device_cell = device_cell.clone();
|
||||
stop_manager.add_listener("tun_device".into(), move || {
|
||||
if let Some(waker) = device_cell.take() {
|
||||
if let Err(e) = waker.wake() {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
}
|
||||
})?
|
||||
};
|
||||
{
|
||||
let stop_all = stop_all.clone();
|
||||
device_stop.set_stop_fn(move || {
|
||||
if let Some(waker) = device_cell.take() {
|
||||
stop_all.store(false);
|
||||
if let Err(e) = waker.wake() {
|
||||
log::warn!("{:?}", e);
|
||||
return false;
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
}
|
||||
if let Err(e) = start_simple0(
|
||||
poll,
|
||||
context,
|
||||
@@ -56,7 +81,10 @@ pub(crate) fn start_simple(
|
||||
) {
|
||||
log::error!("{:?}", e);
|
||||
};
|
||||
worker.stop_all();
|
||||
device_stop.stopped();
|
||||
if stop_all.load() {
|
||||
worker.stop_all();
|
||||
}
|
||||
drop(_waker);
|
||||
Ok(())
|
||||
}
|
||||
@@ -131,65 +159,3 @@ fn start_simple0(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn start_multi(
|
||||
stop_manager: StopManager,
|
||||
device: Arc<Device>,
|
||||
group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
|
||||
up_counter: &mut SingleU64Adder,
|
||||
) -> anyhow::Result<()> {
|
||||
let poll = Poll::new()?;
|
||||
let waker = Arc::new(Waker::new(poll.registry(), STOP)?);
|
||||
let _waker = waker.clone();
|
||||
let worker = stop_manager.add_listener("tun_device".into(), move || {
|
||||
let _ = waker.wake();
|
||||
})?;
|
||||
if let Err(e) = start_multi0(poll, device, group_sync_sender, up_counter) {
|
||||
log::error!("{:?}", e);
|
||||
};
|
||||
worker.stop_all();
|
||||
drop(_waker);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_multi0(
|
||||
mut poll: Poll,
|
||||
device: Arc<Device>,
|
||||
mut group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
|
||||
up_counter: &mut SingleU64Adder,
|
||||
) -> anyhow::Result<()> {
|
||||
let fd = device.as_tun_fd();
|
||||
fd.set_nonblock()?;
|
||||
SourceFd(&fd.as_raw_fd()).register(poll.registry(), FD, Interest::READABLE)?;
|
||||
let mut evnets = Events::with_capacity(4);
|
||||
let mut buf = vec![0; 1024 * 16];
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let start = 12;
|
||||
#[cfg(target_os = "macos")]
|
||||
let start = 12 - 4;
|
||||
loop {
|
||||
poll.poll(&mut evnets, None)?;
|
||||
for event in evnets.iter() {
|
||||
if event.token() == STOP {
|
||||
return Ok(());
|
||||
}
|
||||
loop {
|
||||
let len = match fd.read(&mut buf[start..]) {
|
||||
Ok(len) => len + start,
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::WouldBlock {
|
||||
break;
|
||||
}
|
||||
Err(e)?
|
||||
}
|
||||
};
|
||||
//单线程的
|
||||
up_counter.add(len as u64);
|
||||
if group_sync_sender.send((buf, len)).is_err() {
|
||||
return Ok(());
|
||||
}
|
||||
buf = vec![0; 1024 * 16];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::channel::BUFFER_SIZE;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::compression::Compressor;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::tun_tap::channel_group::GroupSyncSender;
|
||||
use crate::handle::tun_tap::DeviceStop;
|
||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
@@ -26,15 +26,35 @@ pub(crate) fn start_simple(
|
||||
up_counter: &mut SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
compressor: Compressor,
|
||||
device_stop: DeviceStop,
|
||||
) -> anyhow::Result<()> {
|
||||
let device_cell = Arc::new(AtomicCell::new(Some(device.clone())));
|
||||
let stop_all = Arc::new(AtomicCell::new(true));
|
||||
let worker = {
|
||||
let device = device.clone();
|
||||
let device_cell = device_cell.clone();
|
||||
stop_manager.add_listener("tun_device".into(), move || {
|
||||
if let Err(e) = device.shutdown() {
|
||||
log::warn!("{:?}", e);
|
||||
if let Some(device) = device_cell.take() {
|
||||
if let Err(e) = device.shutdown() {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
}
|
||||
})?
|
||||
};
|
||||
{
|
||||
let stop_all = stop_all.clone();
|
||||
device_stop.set_stop_fn(move || {
|
||||
if let Some(device) = device_cell.take() {
|
||||
stop_all.store(false);
|
||||
if let Err(e) = device.shutdown() {
|
||||
log::warn!("{:?}", e);
|
||||
return false;
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
}
|
||||
if let Err(e) = start_simple0(
|
||||
context,
|
||||
device,
|
||||
@@ -50,9 +70,13 @@ pub(crate) fn start_simple(
|
||||
) {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
worker.stop_all();
|
||||
device_stop.stopped();
|
||||
if stop_all.load() {
|
||||
worker.stop_all();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_simple0(
|
||||
context: &ChannelContext,
|
||||
device: Arc<Device>,
|
||||
@@ -95,38 +119,3 @@ fn start_simple0(
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) fn start_multi(
|
||||
stop_manager: StopManager,
|
||||
device: Arc<Device>,
|
||||
group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
|
||||
up_counter: &mut SingleU64Adder,
|
||||
) -> anyhow::Result<()> {
|
||||
let worker = {
|
||||
let device = device.clone();
|
||||
stop_manager.add_listener("tun_device_multi".into(), move || {
|
||||
if let Err(e) = device.shutdown() {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
})?
|
||||
};
|
||||
if let Err(e) = start_multi0(device, group_sync_sender, up_counter) {
|
||||
log::error!("{:?}", e);
|
||||
};
|
||||
worker.stop_all();
|
||||
Ok(())
|
||||
}
|
||||
fn start_multi0(
|
||||
device: Arc<Device>,
|
||||
mut group_sync_sender: GroupSyncSender<(Vec<u8>, usize)>,
|
||||
up_counter: &mut SingleU64Adder,
|
||||
) -> anyhow::Result<()> {
|
||||
loop {
|
||||
let mut buf = vec![0; 1024 * 16];
|
||||
let len = device.read(&mut buf[12..])? + 12;
|
||||
//单线程的
|
||||
up_counter.add(len as u64);
|
||||
if group_sync_sender.send((buf, len)).is_err() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -3,21 +3,23 @@ pub const VNT_VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
pub mod channel;
|
||||
pub mod cipher;
|
||||
pub mod core;
|
||||
pub mod external_route;
|
||||
mod external_route;
|
||||
pub mod handle;
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
pub mod ip_proxy;
|
||||
mod ip_proxy;
|
||||
pub mod nat;
|
||||
#[cfg(feature = "port_mapping")]
|
||||
pub mod port_mapping;
|
||||
pub mod proto;
|
||||
mod port_mapping;
|
||||
mod proto;
|
||||
pub mod protocol;
|
||||
pub mod tun_tap_device;
|
||||
mod tun_tap_device;
|
||||
pub use tun_tap_device::*;
|
||||
pub mod util;
|
||||
|
||||
pub use handle::callback::*;
|
||||
|
||||
pub mod compression;
|
||||
pub use packet;
|
||||
|
||||
pub(crate) fn ignore_io_interrupted(e: std::io::Error) -> std::io::Result<()> {
|
||||
if e.kind() == std::io::ErrorKind::Interrupted {
|
||||
|
||||
@@ -15,10 +15,10 @@ pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String
|
||||
for x in vec {
|
||||
let string = x.trim().to_lowercase();
|
||||
if let Some(udp_mapping) = string.strip_prefix("udp:") {
|
||||
let mut split = udp_mapping.split("->");
|
||||
let mut split = udp_mapping.split("-");
|
||||
let bind_addr = split.next().with_context(|| {
|
||||
format!(
|
||||
"udp_mapping error {:?},eg: udp:127.0.0.1:80->10.26.0.10:8080",
|
||||
"udp_mapping error {:?},eg: udp:127.0.0.1:80-10.26.0.10:8080",
|
||||
x
|
||||
)
|
||||
})?;
|
||||
@@ -26,7 +26,7 @@ pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String
|
||||
.with_context(|| format!("udp_mapping error {}", bind_addr))?;
|
||||
let dest = split.next().with_context(|| {
|
||||
format!(
|
||||
"udp_mapping error {:?},eg: udp:127.0.0.1:80->10.26.0.10:8080",
|
||||
"udp_mapping error {:?},eg: udp:127.0.0.1:80-10.26.0.10:8080",
|
||||
x
|
||||
)
|
||||
})?;
|
||||
@@ -34,10 +34,10 @@ pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String
|
||||
continue;
|
||||
}
|
||||
if let Some(tcp_mapping) = string.strip_prefix("tcp:") {
|
||||
let mut split = tcp_mapping.split("->");
|
||||
let mut split = tcp_mapping.split("-");
|
||||
let bind_addr = split.next().with_context(|| {
|
||||
format!(
|
||||
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80->10.26.0.10:8080",
|
||||
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080",
|
||||
x
|
||||
)
|
||||
})?;
|
||||
@@ -45,7 +45,7 @@ pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String
|
||||
.with_context(|| format!("udp_mapping error {}", bind_addr))?;
|
||||
let dest = split.next().with_context(|| {
|
||||
format!(
|
||||
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80->10.26.0.10:8080",
|
||||
"tcp_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080",
|
||||
x
|
||||
)
|
||||
})?;
|
||||
@@ -53,7 +53,7 @@ pub fn convert(vec: Vec<String>) -> anyhow::Result<Vec<(bool, SocketAddr, String
|
||||
continue;
|
||||
}
|
||||
Err(anyhow::anyhow!(
|
||||
"port_mapping error {:?},eg: tcp:127.0.0.1:80->10.26.0.10:8080",
|
||||
"port_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080",
|
||||
x
|
||||
))?;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::{DeviceConfig, ErrorInfo, ErrorType};
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
use tun::device::IFace;
|
||||
use tun::Device;
|
||||
@@ -8,8 +10,47 @@ const DEFAULT_TUN_NAME: &str = "vnt-tun";
|
||||
#[cfg(target_os = "windows")]
|
||||
const DEFAULT_TAP_NAME: &str = "vnt-tap";
|
||||
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
pub fn create_device(config: &crate::core::Config) -> io::Result<Arc<Device>> {
|
||||
pub fn create_device(config: DeviceConfig) -> Result<Arc<Device>, ErrorInfo> {
|
||||
let device = match create_device0(&config) {
|
||||
Ok(device) => device,
|
||||
Err(e) => {
|
||||
return Err(ErrorInfo::new_msg(
|
||||
ErrorType::Unknown,
|
||||
format!("create device {:?}", e),
|
||||
));
|
||||
}
|
||||
};
|
||||
if let Err(e) = device.set_ip(config.virtual_ip, config.virtual_netmask) {
|
||||
log::error!("LocalIpExists {:?}", e);
|
||||
return Err(ErrorInfo::new_msg(
|
||||
ErrorType::LocalIpExists,
|
||||
format!("set_ip {:?}", e),
|
||||
));
|
||||
}
|
||||
if let Err(e) = device.add_route(config.virtual_network, config.virtual_netmask, 1) {
|
||||
log::warn!("添加默认路由失败 ={:?}", e);
|
||||
}
|
||||
if let Err(e) = device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, 1) {
|
||||
log::warn!("添加广播路由失败 ={:?}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = device.add_route(
|
||||
Ipv4Addr::from([224, 0, 0, 0]),
|
||||
Ipv4Addr::from([240, 0, 0, 0]),
|
||||
1,
|
||||
) {
|
||||
log::warn!("添加组播路由失败 ={:?}", e);
|
||||
}
|
||||
|
||||
for (dest, mask) in config.external_route {
|
||||
if let Err(e) = device.add_route(dest, mask, 1) {
|
||||
log::warn!("添加路由失败 ={:?}", e);
|
||||
}
|
||||
}
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
fn create_device0(config: &DeviceConfig) -> io::Result<Arc<Device>> {
|
||||
#[cfg(target_os = "windows")]
|
||||
let default_name: &str = if config.tap {
|
||||
DEFAULT_TAP_NAME
|
||||
@@ -37,14 +78,7 @@ pub fn create_device(config: &crate::core::Config) -> io::Result<Arc<Device>> {
|
||||
.unwrap_or(default_name.to_string()),
|
||||
config.tap,
|
||||
)?);
|
||||
let mtu = config.mtu.unwrap_or_else(|| {
|
||||
if config.password.is_none() {
|
||||
1450
|
||||
} else {
|
||||
1410
|
||||
}
|
||||
});
|
||||
device.set_mtu(mtu)?;
|
||||
device.set_mtu(config.mtu)?;
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
pub use create_device::create_device;
|
||||
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
mod create_device;
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
pub mod tun_create_helper;
|
||||
|
||||
pub mod vnt_device;
|
||||
|
||||
@@ -4,69 +4,60 @@ use std::sync::Arc;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use tun::device::IFace;
|
||||
use tun::Device;
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::compression::Compressor;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::tun_tap::DeviceStop;
|
||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::tun_tap_device::vnt_device::DeviceWrite;
|
||||
use crate::util::{SingleU64Adder, StopManager};
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct DeviceAdapter {
|
||||
tun: Arc<Device>,
|
||||
tun: Arc<Mutex<Option<Arc<Device>>>>,
|
||||
}
|
||||
|
||||
impl DeviceAdapter {
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
pub fn new(tun: Arc<Device>) -> Self {
|
||||
Self { tun }
|
||||
pub fn insert(&self, device: Arc<Device>) {
|
||||
let r = self.tun.lock().replace(device);
|
||||
assert!(r.is_none());
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn new(tun_device_helper: TunDeviceHelper) -> Self {
|
||||
Self {
|
||||
tun: Arc::new(AtomicCell::new(-1 as _)),
|
||||
tun_device_helper,
|
||||
/// 要保证先remove 再insert
|
||||
pub fn remove(&self) {
|
||||
drop(self.tun.lock().take());
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceWrite for DeviceAdapter {
|
||||
#[inline]
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
if let Some(tun) = self.tun.lock().as_ref() {
|
||||
tun.write(buf)
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "not tun device"))
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
impl std::ops::Deref for DeviceAdapter {
|
||||
type Target = Arc<Device>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.tun
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceAdapter {
|
||||
tun: Arc<AtomicCell<std::os::fd::RawFd>>,
|
||||
tun_device_helper: TunDeviceHelper,
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
impl DeviceAdapter {
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
let fd = self.tun.load();
|
||||
tun::Fd(fd).write(buf)
|
||||
}
|
||||
pub fn start(&self, fd: std::os::fd::RawFd) -> io::Result<()> {
|
||||
//安卓端fd是由外部释放的,所以这里这么搞免得加锁
|
||||
self.tun_device_helper.start(Arc::new(Device::new(fd)?))?;
|
||||
self.tun.store(fd);
|
||||
Ok(())
|
||||
fn into_device_adapter(self) -> DeviceAdapter {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TunDeviceHelper {
|
||||
inner: Arc<AtomicCell<Option<TunDeviceHelperInner>>>,
|
||||
inner: Arc<Mutex<TunDeviceHelperInner>>,
|
||||
device_adapter: DeviceAdapter,
|
||||
device_stop: Arc<Mutex<Option<DeviceStop>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct TunDeviceHelperInner {
|
||||
stop_manager: StopManager,
|
||||
context: ChannelContext,
|
||||
@@ -76,7 +67,6 @@ struct TunDeviceHelperInner {
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
parallel: usize,
|
||||
up_counter: SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
compressor: Compressor,
|
||||
@@ -91,48 +81,65 @@ impl TunDeviceHelper {
|
||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
parallel: usize,
|
||||
up_counter: SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
compressor: Compressor,
|
||||
device_adapter: DeviceAdapter,
|
||||
) -> Self {
|
||||
let inner = TunDeviceHelperInner {
|
||||
stop_manager,
|
||||
context,
|
||||
current_device,
|
||||
ip_route,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
ip_proxy_map,
|
||||
client_cipher,
|
||||
server_cipher,
|
||||
up_counter,
|
||||
device_list,
|
||||
compressor,
|
||||
};
|
||||
Self {
|
||||
inner: Arc::new(AtomicCell::new(Some(TunDeviceHelperInner {
|
||||
stop_manager,
|
||||
context,
|
||||
current_device,
|
||||
ip_route,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
ip_proxy_map,
|
||||
client_cipher,
|
||||
server_cipher,
|
||||
parallel,
|
||||
up_counter,
|
||||
device_list,
|
||||
compressor,
|
||||
}))),
|
||||
inner: Arc::new(Mutex::new(inner)),
|
||||
device_adapter,
|
||||
device_stop: Default::default(),
|
||||
}
|
||||
}
|
||||
pub fn start(&self, device: Arc<Device>) -> io::Result<()> {
|
||||
if let Some(inner) = self.inner.take() {
|
||||
crate::handle::tun_tap::tun_handler::start(
|
||||
inner.stop_manager,
|
||||
inner.context,
|
||||
device,
|
||||
inner.current_device,
|
||||
inner.ip_route,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
inner.ip_proxy_map,
|
||||
inner.client_cipher,
|
||||
inner.server_cipher,
|
||||
inner.parallel,
|
||||
inner.up_counter,
|
||||
inner.device_list,
|
||||
inner.compressor,
|
||||
)?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "Repeated start"))
|
||||
pub fn stop(&self) {
|
||||
//先停止旧的,再启动新的,改变旧网卡的IP太麻烦
|
||||
if let Some(device_stop) = self.device_stop.lock().take() {
|
||||
self.device_adapter.remove();
|
||||
loop {
|
||||
device_stop.stop();
|
||||
std::thread::sleep(std::time::Duration::from_millis(300));
|
||||
//确保停止了
|
||||
if device_stop.is_stop() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// 要保证先stop 再start
|
||||
pub fn start(&self, device: Arc<Device>) -> io::Result<()> {
|
||||
self.device_adapter.insert(device.clone());
|
||||
let device_stop = DeviceStop::default();
|
||||
let s = self.device_stop.lock().replace(device_stop.clone());
|
||||
assert!(s.is_none());
|
||||
let inner = self.inner.lock().clone();
|
||||
crate::handle::tun_tap::tun_handler::start(
|
||||
inner.stop_manager,
|
||||
inner.context,
|
||||
device,
|
||||
inner.current_device,
|
||||
inner.ip_route,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
inner.ip_proxy_map,
|
||||
inner.client_cipher,
|
||||
inner.server_cipher,
|
||||
inner.up_counter,
|
||||
inner.device_list,
|
||||
inner.compressor,
|
||||
device_stop,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
use std::io;
|
||||
|
||||
pub trait DeviceWrite: Clone + Send + Sync + 'static {
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize>;
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
fn into_device_adapter(self) -> crate::tun_tap_device::tun_create_helper::DeviceAdapter;
|
||||
}
|
||||
@@ -8,6 +8,7 @@ pub struct U64Adder {
|
||||
inner: Arc<U64AdderInner>,
|
||||
index: usize,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct SingleU64Adder {
|
||||
inner: Arc<SingleU64AdderInner>,
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
mod notify;
|
||||
mod scheduler;
|
||||
pub use notify::StopManager;
|
||||
pub use notify::{StopManager, Worker};
|
||||
pub use scheduler::Scheduler;
|
||||
|
||||
mod counter;
|
||||
|
||||
@@ -5,8 +5,8 @@ use std::os::fd::AsRawFd;
|
||||
use std::{io, mem, ptr};
|
||||
|
||||
use libc::{
|
||||
c_char, c_short, ifreq, AF_INET, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_RUNNING, IFF_TUN,
|
||||
IFF_UP, IFNAMSIZ, O_RDWR, SOCK_DGRAM,
|
||||
c_char, c_short, ifreq, AF_INET, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_RUNNING, IFF_TUN, IFF_UP,
|
||||
IFNAMSIZ, O_RDWR, SOCK_DGRAM,
|
||||
};
|
||||
|
||||
use crate::device::IFace;
|
||||
|
||||
@@ -62,9 +62,7 @@ impl IntoRawFd for Fd {
|
||||
impl Drop for Fd {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if self.0 >= 0 {
|
||||
libc::close(self.0);
|
||||
}
|
||||
libc::close(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ impl Device {
|
||||
));
|
||||
}
|
||||
// 开启session
|
||||
let session = win_tun.WintunStartSession(adapter, MAX_RING_CAPACITY);
|
||||
let session = win_tun.WintunStartSession(adapter, 128 * 1024);
|
||||
if session.is_null() {
|
||||
log::error!("session.is_null {:?}", io::Error::last_os_error());
|
||||
return Err(io::Error::new(
|
||||
|
||||
Reference in New Issue
Block a user