Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc45602661 | ||
|
|
27c0f389ee | ||
|
|
59d6bfd957 | ||
|
|
31b8661b7d | ||
|
|
8ae20497c6 | ||
|
|
a70b4f30b5 | ||
|
|
df4795c9c4 | ||
|
|
c21a73f950 | ||
|
|
29cd111a49 | ||
|
|
367a56d346 | ||
|
|
d81ac6368e | ||
|
|
a228b62d23 | ||
|
|
995ff9b059 | ||
|
|
7dc78cc170 | ||
|
|
7e218355f2 | ||
|
|
98c394c993 | ||
|
|
31b06cd713 | ||
|
|
d7266926d8 | ||
|
|
1df5a1cfb1 | ||
|
|
8658bd3601 | ||
|
|
17d1ad3716 | ||
|
|
728598ba8e | ||
|
|
218483f431 | ||
|
|
1f80e06d9d | ||
|
|
5e56064ec6 | ||
|
|
31f0213fc5 | ||
|
|
54b1fef164 | ||
|
|
7c18df0a6f | ||
|
|
916fd8254b | ||
|
|
9e249862dc | ||
|
|
3773c09f57 | ||
|
|
6798c652f9 | ||
|
|
382d5b61ba | ||
|
|
ac162eba66 | ||
|
|
05a60b3cb7 | ||
|
|
7f210e9319 | ||
|
|
481c00629a | ||
|
|
bf55ec9512 | ||
|
|
e36e45054c | ||
|
|
39170b74ca | ||
|
|
0e3f06429b | ||
|
|
ee7c597bd8 | ||
|
|
7f500d72c7 | ||
|
|
4dca4c4f22 |
+13
-13
@@ -44,40 +44,40 @@ jobs:
|
||||
FEATURES: default
|
||||
- TARGET: x86_64-unknown-linux-musl # test in an alpine container on a mac
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher,openssl-vendored
|
||||
FEATURES: ring-cipher,wss
|
||||
- TARGET: aarch64-unknown-linux-musl # tested on aws t4g.nano in alpine container
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher,openssl-vendored
|
||||
FEATURES: ring-cipher,wss
|
||||
- TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: openssl-vendored
|
||||
FEATURES: ring-cipher,wss
|
||||
- TARGET: armv7-unknown-linux-musleabi # raspberry pi 2-3-4, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: openssl-vendored
|
||||
FEATURES: ring-cipher,wss
|
||||
- TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher,openssl-vendored
|
||||
FEATURES: ring-cipher,wss
|
||||
- TARGET: arm-unknown-linux-musleabi # raspberry pi 0-1, not tested
|
||||
OS: ubuntu-latest
|
||||
FEATURES: ring-cipher,openssl-vendored
|
||||
FEATURES: ring-cipher,wss
|
||||
- TARGET: x86_64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
|
||||
OS: macos-latest
|
||||
FEATURES: ring-cipher,openssl-vendored
|
||||
FEATURES: ring-cipher,wss
|
||||
- TARGET: aarch64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
|
||||
OS: macos-latest
|
||||
FEATURES: ring-cipher,openssl-vendored
|
||||
FEATURES: ring-cipher,wss
|
||||
- TARGET: i686-pc-windows-msvc # tested on a windows machine
|
||||
OS: windows-2019
|
||||
FEATURES: ring-cipher,openssl-vendored
|
||||
FEATURES: ring-cipher,wss
|
||||
- TARGET: x86_64-pc-windows-msvc # tested on a windows machine
|
||||
OS: windows-latest
|
||||
FEATURES: ring-cipher,openssl-vendored
|
||||
FEATURES: ring-cipher,wss
|
||||
- TARGET: mipsel-unknown-linux-musl # openwrt
|
||||
OS: ubuntu-latest
|
||||
FEATURES: openssl-vendored,ring-cipher
|
||||
FEATURES: ring-cipher,wss
|
||||
- TARGET: mips-unknown-linux-musl # openwrt
|
||||
OS: ubuntu-latest
|
||||
FEATURES: openssl-vendored
|
||||
FEATURES: ring-cipher,wss
|
||||
# needs: test
|
||||
runs-on: ${{ matrix.OS }}
|
||||
env:
|
||||
@@ -217,7 +217,7 @@ jobs:
|
||||
fi
|
||||
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
|
||||
mv ./README ./artifacts/README.txt
|
||||
cd ./artifacts
|
||||
tar -czf vnt-$TARGET-$TAG.tar.gz *
|
||||
- name: Archive artifact
|
||||
|
||||
+4
-1
@@ -1,3 +1,6 @@
|
||||
target/*
|
||||
vnt/src/proto/*
|
||||
common/src/generated_serial_number.rs
|
||||
common/src/generated_serial_number.rs
|
||||
|
||||
# RustRover
|
||||
.idea
|
||||
Generated
+407
-16
@@ -88,6 +88,18 @@ version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "attohttpc"
|
||||
version = "0.16.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb8867f378f33f78a811a8eb9bf108ad99430d7aad43315dd9319c827ef6247"
|
||||
dependencies = [
|
||||
"http 0.2.12",
|
||||
"log",
|
||||
"url",
|
||||
"wildmatch",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.2.0"
|
||||
@@ -109,6 +121,12 @@ dependencies = [
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
@@ -289,7 +307,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "1.2.10"
|
||||
version = "1.2.11"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@@ -324,6 +342,16 @@ version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.6"
|
||||
@@ -415,6 +443,12 @@ dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.9"
|
||||
@@ -513,6 +547,59 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
@@ -604,6 +691,34 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
@@ -633,6 +748,29 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "igd"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "556b5a75cd4adb7c4ea21c64af1c48cefb2ce7d43dc4352c720a1fe47c21f355"
|
||||
dependencies = [
|
||||
"attohttpc",
|
||||
"log",
|
||||
"rand",
|
||||
"url",
|
||||
"xmltree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
@@ -965,6 +1103,12 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-src"
|
||||
version = "300.1.3+3.1.2"
|
||||
@@ -1033,12 +1177,24 @@ dependencies = [
|
||||
"base64ct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkcs1"
|
||||
version = "0.7.5"
|
||||
@@ -1116,9 +1272,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "3.4.0"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58678a64de2fced2bdec6bca052a6716a0efe692d6e3f53d1bda6a1def64cfc0"
|
||||
checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"protobuf-support",
|
||||
@@ -1127,9 +1283,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "protobuf-codegen"
|
||||
version = "3.4.0"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32777b0b3f6538d9d2e012b3fad85c7e4b9244b5958d04a6415f4333782b7a77"
|
||||
checksum = "0dd418ac3c91caa4032d37cb80ff0d44e2ebe637b2fb243b6234bf89cdac4901"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"once_cell",
|
||||
@@ -1142,9 +1298,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "protobuf-parse"
|
||||
version = "3.4.0"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96cb37955261126624a25b5e6bda40ae34cf3989d52a783087ca6091b29b5642"
|
||||
checksum = "9d39b14605eaa1f6a340aec7f320b34064feb26c93aec35d6a9a2272a8ddfa49"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap 1.9.3",
|
||||
@@ -1158,9 +1314,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "protobuf-support"
|
||||
version = "3.4.0"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1ed294a835b0f30810e13616b1cd34943c6d1e84a8f3b0dcfe466d256c3e7e7"
|
||||
checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
@@ -1364,18 +1520,104 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-native-certs"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba"
|
||||
dependencies = [
|
||||
"openssl-probe",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.102.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.198"
|
||||
@@ -1430,6 +1672,17 @@ dependencies = [
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
@@ -1476,6 +1729,15 @@ dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
@@ -1614,6 +1876,21 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.37.0"
|
||||
@@ -1644,6 +1921,34 @@ dependencies = [
|
||||
"syn 2.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tungstenite",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tun"
|
||||
version = "0.1.0"
|
||||
@@ -1657,6 +1962,26 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http 1.1.0",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typemap-ors"
|
||||
version = "1.0.0"
|
||||
@@ -1672,6 +1997,12 @@ version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
@@ -1679,10 +2010,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.11"
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||
checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
@@ -1715,6 +2055,23 @@ version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.8.0"
|
||||
@@ -1738,7 +2095,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "vn-link"
|
||||
version = "1.2.10"
|
||||
version = "1.2.11"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"crossbeam-utils",
|
||||
@@ -1751,7 +2108,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vn-link-cli"
|
||||
version = "1.2.10"
|
||||
version = "1.2.11"
|
||||
dependencies = [
|
||||
"common",
|
||||
"log",
|
||||
@@ -1761,7 +2118,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vnt"
|
||||
version = "1.2.10"
|
||||
version = "1.2.11"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"aes-gcm",
|
||||
@@ -1777,6 +2134,8 @@ dependencies = [
|
||||
"dns-parser",
|
||||
"ecb",
|
||||
"fnv",
|
||||
"futures-util",
|
||||
"igd",
|
||||
"libc",
|
||||
"libloading",
|
||||
"libsm",
|
||||
@@ -1792,19 +2151,21 @@ dependencies = [
|
||||
"rand",
|
||||
"ring",
|
||||
"rsa",
|
||||
"rustls",
|
||||
"sha2",
|
||||
"socket2",
|
||||
"spki",
|
||||
"stun-format",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"tun",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vnt-cli"
|
||||
version = "1.2.10"
|
||||
version = "1.2.11"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@@ -1877,6 +2238,15 @@ version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.2"
|
||||
@@ -1895,6 +2265,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
|
||||
|
||||
[[package]]
|
||||
name = "wildmatch"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f44b95f62d34113cf558c93511ac93027e03e9c29a60dd0fd70e6e025c7270a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@@ -2065,6 +2441,21 @@ version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193"
|
||||
|
||||
[[package]]
|
||||
name = "xmltree"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb"
|
||||
dependencies = [
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yasna"
|
||||
version = "0.5.2"
|
||||
|
||||
+4
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "common"
|
||||
version = "1.2.10"
|
||||
version = "1.2.11"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@@ -32,7 +32,9 @@ ip_proxy = ["vnt/ip_proxy"]
|
||||
port_mapping = ["vnt/port_mapping"]
|
||||
lz4 = ["vnt/lz4_compress"]
|
||||
zstd = ["vnt/zstd_compress"]
|
||||
|
||||
upnp = ["vnt/upnp"]
|
||||
ws = ["vnt/ws"]
|
||||
wss = ["vnt/wss"]
|
||||
command = []
|
||||
file_config = []
|
||||
log = ["log4rs"]
|
||||
|
||||
+29
-10
@@ -56,7 +56,6 @@ pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>
|
||||
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>");
|
||||
@@ -75,12 +74,15 @@ pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>
|
||||
opts.optmulti("", "vnt-mapping", "vnt-mapping", "<mapping>");
|
||||
opts.optopt("f", "", "配置文件", "<conf>");
|
||||
opts.optopt("", "compressor", "压缩算法", "<lz4>");
|
||||
opts.optflag("", "disable-stats", "关闭流量统计");
|
||||
//"后台运行时,查看其他设备列表"
|
||||
opts.optflag("", "add", "后台运行时,添加地址");
|
||||
opts.optflag("", "list", "后台运行时,查看其他设备列表");
|
||||
opts.optflag("", "all", "后台运行时,查看其他设备完整信息");
|
||||
opts.optflag("", "info", "后台运行时,查看当前设备信息");
|
||||
opts.optflag("", "route", "后台运行时,查看数据转发路径");
|
||||
opts.optflag("", "chart_a", "后台运行时,查看流量统计");
|
||||
opts.optopt("", "chart_b", "后台运行时,查看流量统计", "<IP>");
|
||||
opts.optflag("", "stop", "停止后台运行");
|
||||
opts.optflag("h", "help", "帮助");
|
||||
let matches = match opts.parse(&args[1..]) {
|
||||
@@ -111,6 +113,13 @@ pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>
|
||||
} else if matches.opt_present("all") {
|
||||
command::command(command::CommandEnum::All);
|
||||
return Ok(None);
|
||||
} else if matches.opt_present("chart_a") {
|
||||
command::command(command::CommandEnum::ChartA);
|
||||
return Ok(None);
|
||||
}
|
||||
if let Some(v) = matches.opt_str("chart_b") {
|
||||
command::command(command::CommandEnum::ChartB(v));
|
||||
return Ok(None);
|
||||
}
|
||||
let conf = matches.opt_str("f");
|
||||
let (config, vnt_link_config, cmd) = if conf.is_some() {
|
||||
@@ -156,9 +165,9 @@ pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>
|
||||
|
||||
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());
|
||||
for x in config::PUB_STUN {
|
||||
stun_server.push(x.to_string());
|
||||
}
|
||||
}
|
||||
let dns = matches.opt_strs("dns");
|
||||
let in_ip = matches.opt_strs("i");
|
||||
@@ -213,7 +222,6 @@ pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>
|
||||
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") {
|
||||
@@ -269,6 +277,7 @@ pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>
|
||||
#[cfg(feature = "port_mapping")]
|
||||
let port_mapping_list = matches.opt_strs("mapping");
|
||||
let vnt_mapping_list = matches.opt_strs("vnt-mapping");
|
||||
let disable_stats = matches.opt_present("disable-stats");
|
||||
let compressor = if let Some(compressor) = matches.opt_str("compressor").as_ref() {
|
||||
Compressor::from_str(compressor)
|
||||
.map_err(|e| anyhow!("{}", e))
|
||||
@@ -290,7 +299,6 @@ pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>
|
||||
out_ip,
|
||||
password,
|
||||
mtu,
|
||||
tcp_channel,
|
||||
virtual_ip,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
@@ -309,10 +317,11 @@ pub fn parse_args_config() -> anyhow::Result<Option<(Config, Vec<String>, bool)>
|
||||
#[cfg(feature = "port_mapping")]
|
||||
port_mapping_list,
|
||||
compressor,
|
||||
!disable_stats,
|
||||
) {
|
||||
Ok(config) => config,
|
||||
Err(e) => {
|
||||
println!("config.toml error: {}", e);
|
||||
println!("config error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
@@ -339,8 +348,10 @@ fn print_usage(program: &str, _opts: Options) {
|
||||
);
|
||||
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");
|
||||
println!(
|
||||
" -s <server> 注册和中继服务器地址,协议支持使用tcp://和ws://和wss://,默认为udp://"
|
||||
);
|
||||
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可使用多个地址,如-e stun.miwifi.com -e turn.cloudflare.com");
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
println!(
|
||||
@@ -357,7 +368,6 @@ fn print_usage(program: &str, _opts: Options) {
|
||||
#[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"))]
|
||||
@@ -421,6 +431,7 @@ fn print_usage(program: &str, _opts: Options) {
|
||||
.to_string()
|
||||
)
|
||||
);
|
||||
println!(" --disable-stats 关闭流量统计");
|
||||
println!();
|
||||
#[cfg(feature = "command")]
|
||||
{
|
||||
@@ -445,6 +456,14 @@ fn print_usage(program: &str, _opts: Options) {
|
||||
" --route {}",
|
||||
yellow("后台运行时,查看数据转发路径".to_string())
|
||||
);
|
||||
println!(
|
||||
" --chart_a {}",
|
||||
yellow("后台运行时,查看所有IP的流量统计".to_string())
|
||||
);
|
||||
println!(
|
||||
" --chart_b <IP> {}",
|
||||
yellow("后台运行时,查看单个IP的历史流量".to_string())
|
||||
);
|
||||
println!(
|
||||
" --stop {}",
|
||||
yellow("停止后台运行".to_string())
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::command::entity::{DeviceItem, Info, RouteItem};
|
||||
use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem};
|
||||
|
||||
pub struct CommandClient {
|
||||
buf: Vec<u8>,
|
||||
@@ -53,6 +53,17 @@ impl CommandClient {
|
||||
pub fn info(&mut self) -> io::Result<Info> {
|
||||
self.send_cmd(b"info")
|
||||
}
|
||||
pub fn chart_a(&mut self) -> io::Result<ChartA> {
|
||||
self.send_cmd(b"chart_a")
|
||||
}
|
||||
pub fn chart_b(&mut self, input: &str) -> io::Result<ChartB> {
|
||||
let cmd = if input.is_empty() {
|
||||
"chart_b".to_string()
|
||||
} else {
|
||||
format!("chart_b:{}", input)
|
||||
};
|
||||
self.send_cmd(cmd.as_bytes())
|
||||
}
|
||||
fn send_cmd<'a, V: Deserialize<'a>>(&'a mut self, cmd: &[u8]) -> io::Result<V> {
|
||||
self.udp.send(cmd)?;
|
||||
let len = self.udp.recv(&mut self.buf)?;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Info {
|
||||
pub name: String,
|
||||
@@ -12,11 +14,11 @@ pub struct Info {
|
||||
pub public_ips: String,
|
||||
pub local_addr: String,
|
||||
pub ipv6_addr: String,
|
||||
pub up: u64,
|
||||
pub down: u64,
|
||||
pub port_mapping_list: Vec<(bool, SocketAddr, String)>,
|
||||
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||
pub out_ips: Vec<(u32, u32)>,
|
||||
pub udp_listen_addr: Vec<String>,
|
||||
pub tcp_listen_addr: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@@ -44,3 +46,22 @@ pub struct DeviceItem {
|
||||
pub current_client_secret: bool,
|
||||
pub current_client_secret_hash: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
pub struct ChartA {
|
||||
pub disable_stats: bool,
|
||||
pub up_total: u64,
|
||||
pub down_total: u64,
|
||||
pub up_map: HashMap<Ipv4Addr, u64>,
|
||||
pub down_map: HashMap<Ipv4Addr, u64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
pub struct ChartB {
|
||||
pub disable_stats: bool,
|
||||
pub ip: Option<Ipv4Addr>,
|
||||
pub up_total: u64,
|
||||
pub up_list: Vec<usize>,
|
||||
pub down_total: u64,
|
||||
pub down_list: Vec<usize>,
|
||||
}
|
||||
|
||||
+122
-12
@@ -1,7 +1,10 @@
|
||||
use std::collections::HashSet;
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use vnt::channel::ConnectProtocol;
|
||||
use vnt::core::Vnt;
|
||||
|
||||
use crate::command::entity::{DeviceItem, Info, RouteItem};
|
||||
use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem};
|
||||
use crate::console_out;
|
||||
|
||||
pub mod client;
|
||||
@@ -13,6 +16,8 @@ pub enum CommandEnum {
|
||||
List,
|
||||
All,
|
||||
Info,
|
||||
ChartA,
|
||||
ChartB(String),
|
||||
Stop,
|
||||
}
|
||||
|
||||
@@ -20,7 +25,9 @@ pub fn command_str(cmd: &str, vnt: &Vnt) -> bool {
|
||||
if cmd.is_empty() {
|
||||
return false;
|
||||
}
|
||||
match cmd.to_lowercase().trim() {
|
||||
let cmd = cmd.to_lowercase();
|
||||
let cmd = cmd.trim();
|
||||
match cmd {
|
||||
"list" => {
|
||||
let list = command_list(&vnt);
|
||||
console_out::console_device_list(list);
|
||||
@@ -37,12 +44,24 @@ pub fn command_str(cmd: &str, vnt: &Vnt) -> bool {
|
||||
let list = command_list(&vnt);
|
||||
console_out::console_device_list_all(list);
|
||||
}
|
||||
"chart_a" => {
|
||||
let chart = command_chart_a(&vnt);
|
||||
console_out::console_chart_a(chart);
|
||||
}
|
||||
"stop" => {
|
||||
let _ = vnt.stop();
|
||||
return false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if let Some(ip) = cmd.strip_prefix("chart_b") {
|
||||
let chart = if ip.is_empty() {
|
||||
command_chart_b(&vnt, &vnt.current_device().virtual_gateway.to_string())
|
||||
} else {
|
||||
command_chart_b(&vnt, &ip[1..])
|
||||
};
|
||||
console_out::console_chart_b(chart);
|
||||
}
|
||||
println!();
|
||||
return true;
|
||||
}
|
||||
@@ -72,6 +91,14 @@ fn command_(cmd: CommandEnum) -> io::Result<()> {
|
||||
let info = command_client.info()?;
|
||||
console_out::console_info(info);
|
||||
}
|
||||
CommandEnum::ChartA => {
|
||||
let chart = command_client.chart_a()?;
|
||||
console_out::console_chart_a(chart);
|
||||
}
|
||||
CommandEnum::ChartB(input) => {
|
||||
let chart = command_client.chart_b(&input)?;
|
||||
console_out::console_chart_b(chart);
|
||||
}
|
||||
CommandEnum::Stop => {
|
||||
command_client.stop()?;
|
||||
}
|
||||
@@ -81,6 +108,7 @@ fn command_(cmd: CommandEnum) -> io::Result<()> {
|
||||
|
||||
pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> {
|
||||
let route_table = vnt.route_table();
|
||||
let server_addr = vnt.config().server_address_str.clone();
|
||||
let mut route_list = Vec::with_capacity(route_table.len());
|
||||
for (destination, routes) in route_table {
|
||||
for route in routes {
|
||||
@@ -93,11 +121,14 @@ pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> {
|
||||
} else {
|
||||
route.rt.to_string()
|
||||
};
|
||||
let interface = if route.is_tcp {
|
||||
format!("tcp@{}", route.addr)
|
||||
} else {
|
||||
route.addr.to_string()
|
||||
let interface = match route.protocol {
|
||||
ConnectProtocol::UDP => route.addr.to_string(),
|
||||
ConnectProtocol::TCP => {
|
||||
format!("tcp@{}", route.addr)
|
||||
}
|
||||
ConnectProtocol::WS | ConnectProtocol::WSS => server_addr.clone(),
|
||||
};
|
||||
|
||||
let item = RouteItem {
|
||||
destination: destination.to_string(),
|
||||
next_hop,
|
||||
@@ -145,7 +176,7 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
|
||||
};
|
||||
let (nat_traversal_type, rt) = if let Some(route) = vnt.route(&peer.virtual_ip) {
|
||||
let nat_traversal_type = if route.metric == 1 {
|
||||
if route.is_tcp {
|
||||
if route.protocol.is_base_tcp() {
|
||||
"tcp-p2p"
|
||||
} else {
|
||||
"p2p"
|
||||
@@ -195,6 +226,7 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
|
||||
}
|
||||
|
||||
pub fn command_info(vnt: &Vnt) -> Info {
|
||||
let config = vnt.config();
|
||||
let current_device = vnt.current_device();
|
||||
let nat_info = vnt.nat_info();
|
||||
let name = vnt.name().to_string();
|
||||
@@ -202,7 +234,11 @@ pub fn command_info(vnt: &Vnt) -> Info {
|
||||
let virtual_gateway = current_device.virtual_gateway().to_string();
|
||||
let virtual_netmask = current_device.virtual_netmask.to_string();
|
||||
let connect_status = format!("{:?}", vnt.connection_status());
|
||||
let relay_server = current_device.connect_server.to_string();
|
||||
let relay_server = if current_device.connect_server.port() == 0 {
|
||||
config.server_address_str.clone()
|
||||
} else {
|
||||
current_device.connect_server.to_string()
|
||||
};
|
||||
let nat_type = format!("{:?}", nat_info.nat_type);
|
||||
let public_ips: Vec<String> = nat_info.public_ips.iter().map(|v| v.to_string()).collect();
|
||||
let public_ips = public_ips.join(",");
|
||||
@@ -214,14 +250,18 @@ pub fn command_info(vnt: &Vnt) -> Info {
|
||||
.ipv6()
|
||||
.map(|v| v.to_string())
|
||||
.unwrap_or("None".to_string());
|
||||
let up = vnt.up_stream();
|
||||
let down = vnt.down_stream();
|
||||
#[cfg(feature = "port_mapping")]
|
||||
let port_mapping_list = vnt.config().port_mapping_list.clone();
|
||||
#[cfg(not(feature = "port_mapping"))]
|
||||
let port_mapping_list = vec![];
|
||||
let in_ips = vnt.config().in_ips.clone();
|
||||
let out_ips = vnt.config().out_ips.clone();
|
||||
let udp_listen_addr = nat_info
|
||||
.udp_ports
|
||||
.iter()
|
||||
.map(|port| format!("0.0.0.0:{}", port))
|
||||
.collect();
|
||||
let tcp_listen_addr = format!("0.0.0.0:{}", nat_info.tcp_port);
|
||||
Info {
|
||||
name,
|
||||
virtual_ip,
|
||||
@@ -233,10 +273,80 @@ pub fn command_info(vnt: &Vnt) -> Info {
|
||||
public_ips,
|
||||
local_addr,
|
||||
ipv6_addr,
|
||||
up,
|
||||
down,
|
||||
port_mapping_list,
|
||||
in_ips,
|
||||
out_ips,
|
||||
udp_listen_addr,
|
||||
tcp_listen_addr,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn command_chart_a(vnt: &Vnt) -> ChartA {
|
||||
let disable_stats = !vnt.config().enable_traffic;
|
||||
if disable_stats {
|
||||
let mut chart = ChartA::default();
|
||||
chart.disable_stats = true;
|
||||
return chart;
|
||||
}
|
||||
let (up_total, up_map) = vnt.up_stream_all().unwrap_or_default();
|
||||
let (down_total, down_map) = vnt.down_stream_all().unwrap_or_default();
|
||||
ChartA {
|
||||
disable_stats,
|
||||
up_total,
|
||||
down_total,
|
||||
up_map,
|
||||
down_map,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn command_chart_b(vnt: &Vnt, input_str: &str) -> ChartB {
|
||||
let disable_stats = !vnt.config().enable_traffic;
|
||||
if disable_stats {
|
||||
let mut chart = ChartB::default();
|
||||
chart.disable_stats = true;
|
||||
return chart;
|
||||
}
|
||||
let (_, up_map) = vnt.up_stream_history().unwrap_or_default();
|
||||
let (_, down_map) = vnt.down_stream_history().unwrap_or_default();
|
||||
let up_keys: HashSet<_> = up_map.keys().cloned().collect();
|
||||
let down_keys: HashSet<_> = down_map.keys().cloned().collect();
|
||||
let mut keys: Vec<Ipv4Addr> = up_keys.union(&down_keys).cloned().collect();
|
||||
keys.sort();
|
||||
if let Some(ip) = find_matching_ipv4_address(input_str, &keys) {
|
||||
let (up_total, up_list) = up_map.get(&ip).cloned().unwrap_or_default();
|
||||
let (down_total, down_list) = down_map.get(&ip).cloned().unwrap_or_default();
|
||||
ChartB {
|
||||
disable_stats,
|
||||
ip: Some(ip),
|
||||
up_total,
|
||||
up_list,
|
||||
down_total,
|
||||
down_list,
|
||||
}
|
||||
} else {
|
||||
ChartB::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn match_from_end(input_str: &str, ip: &str) -> bool {
|
||||
let mut input_chars = input_str.chars().rev();
|
||||
let mut ip_chars = ip.chars().rev();
|
||||
|
||||
while let (Some(ic), Some(pc)) = (input_chars.next(), ip_chars.next()) {
|
||||
if ic != pc {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
input_chars.next().is_none() // Ensure all input characters matched
|
||||
}
|
||||
|
||||
fn find_matching_ipv4_address(input_str: &str, ip_addresses: &[Ipv4Addr]) -> Option<Ipv4Addr> {
|
||||
for &ip in ip_addresses {
|
||||
let ip_str = ip.to_string();
|
||||
if match_from_end(input_str, &ip_str) {
|
||||
return Some(ip);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::command::command_chart_b;
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::net::UdpSocket;
|
||||
@@ -62,15 +63,26 @@ fn command(cmd: &str, vnt: &Vnt) -> io::Result<String> {
|
||||
.unwrap_or_else(|e| format!("error {:?}", e)),
|
||||
"info" => serde_yaml::to_string(&crate::command::command_info(vnt))
|
||||
.unwrap_or_else(|e| format!("error {:?}", e)),
|
||||
"chart_a" => serde_yaml::to_string(&crate::command::command_chart_a(vnt))
|
||||
.unwrap_or_else(|e| format!("error {:?}", e)),
|
||||
"stop" => {
|
||||
vnt.stop();
|
||||
"stopped".to_string()
|
||||
}
|
||||
_ => {
|
||||
format!(
|
||||
"command '{}' not found. Try to enter: 'route'/'list'/'stop' \n",
|
||||
cmd
|
||||
)
|
||||
if let Some(ip) = cmd.strip_prefix("chart_b") {
|
||||
let chart = if ip.is_empty() {
|
||||
command_chart_b(&vnt, &vnt.current_device().virtual_gateway.to_string())
|
||||
} else {
|
||||
command_chart_b(&vnt, &ip[1..])
|
||||
};
|
||||
serde_yaml::to_string(&chart).unwrap_or_else(|e| format!("error {:?}", e))
|
||||
} else {
|
||||
format!(
|
||||
"command '{}' not found. Try to enter: 'route'/'list'/'stop' \n",
|
||||
cmd
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(out_str)
|
||||
|
||||
@@ -2,8 +2,8 @@ use anyhow::anyhow;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::args_parse;
|
||||
use crate::config::get_device_id;
|
||||
use crate::{args_parse, config};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vnt::channel::punch::PunchModel;
|
||||
use vnt::channel::UseChannelType;
|
||||
@@ -45,10 +45,15 @@ pub struct FileConfig {
|
||||
pub mapping: Vec<String>,
|
||||
pub compressor: Option<String>,
|
||||
pub vnt_mapping: Vec<String>,
|
||||
pub disable_stats: bool,
|
||||
}
|
||||
|
||||
impl Default for FileConfig {
|
||||
fn default() -> Self {
|
||||
let mut stun_server = Vec::new();
|
||||
for x in config::PUB_STUN {
|
||||
stun_server.push(x.to_string());
|
||||
}
|
||||
Self {
|
||||
#[cfg(target_os = "windows")]
|
||||
tap: false,
|
||||
@@ -59,11 +64,7 @@ impl Default for FileConfig {
|
||||
.unwrap_or("UnknownName")
|
||||
.to_string(),
|
||||
server_address: "nat1.wherewego.top:29872".to_string(),
|
||||
stun_server: vec![
|
||||
"stun1.l.google.com:19302".to_string(),
|
||||
"stun2.l.google.com:19302".to_string(),
|
||||
"stun.miwifi.com:3478".to_string(),
|
||||
],
|
||||
stun_server,
|
||||
dns: vec![],
|
||||
in_ips: vec![],
|
||||
out_ips: vec![],
|
||||
@@ -88,6 +89,7 @@ impl Default for FileConfig {
|
||||
mapping: vec![],
|
||||
compressor: None,
|
||||
vnt_mapping: vec![],
|
||||
disable_stats: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,7 +158,6 @@ pub fn read_config(file_path: &str) -> anyhow::Result<(Config, Vec<String>, bool
|
||||
out_ips,
|
||||
file_conf.password,
|
||||
file_conf.mtu,
|
||||
file_conf.tcp,
|
||||
virtual_ip,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
@@ -175,6 +176,7 @@ pub fn read_config(file_path: &str) -> anyhow::Result<(Config, Vec<String>, bool
|
||||
#[cfg(feature = "port_mapping")]
|
||||
file_conf.mapping,
|
||||
compressor,
|
||||
!file_conf.disable_stats,
|
||||
)?;
|
||||
|
||||
Ok((config, file_conf.vnt_mapping, file_conf.cmd))
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
pub const PUB_STUN: [&'static str; 4] = [
|
||||
"stun.miwifi.com",
|
||||
"stun.chat.bilibili.com",
|
||||
"stun.hitv.com",
|
||||
"stun.cdnbye.com",
|
||||
];
|
||||
#[cfg(feature = "file_config")]
|
||||
mod file_config;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use console::{style, Style};
|
||||
use std::collections::HashSet;
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use crate::command::entity::{DeviceItem, Info, RouteItem};
|
||||
use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem};
|
||||
|
||||
pub mod table;
|
||||
|
||||
@@ -21,11 +22,14 @@ pub fn console_info(status: Info) {
|
||||
|
||||
println!("NAT type: {}", style(status.nat_type).green());
|
||||
println!("Relay server: {}", style(status.relay_server).green());
|
||||
println!(
|
||||
"Udp listen: {}",
|
||||
style(status.udp_listen_addr.join(", ")).green()
|
||||
);
|
||||
println!("Tcp listen: {}", style(status.tcp_listen_addr).green());
|
||||
println!("Public ips: {}", style(status.public_ips).green());
|
||||
println!("Local addr: {}", style(status.local_addr).green());
|
||||
println!("IPv6: {}", style(status.ipv6_addr).green());
|
||||
println!("Up: {}", style(convert(status.up)).green());
|
||||
println!("Down: {}", style(convert(status.down)).green());
|
||||
|
||||
if !status.port_mapping_list.is_empty() {
|
||||
println!("------------------------------------------");
|
||||
@@ -237,3 +241,120 @@ pub fn console_device_list_all(mut list: Vec<DeviceItem>) {
|
||||
}
|
||||
table::println_table(out_list)
|
||||
}
|
||||
|
||||
pub fn console_chart_a(chart_a: ChartA) {
|
||||
if chart_a.disable_stats {
|
||||
println!("Traffic statistics not enabled");
|
||||
return;
|
||||
}
|
||||
println!();
|
||||
println!("-----------------------------------------------------------------");
|
||||
println!(
|
||||
"Upload total = {}",
|
||||
style(convert(chart_a.up_total)).green()
|
||||
);
|
||||
println!(
|
||||
"Download total = {}",
|
||||
style(convert(chart_a.down_total)).green()
|
||||
);
|
||||
println!("-----------------------------------------------------------------");
|
||||
let up_keys: HashSet<_> = chart_a.up_map.keys().cloned().collect();
|
||||
let down_keys: HashSet<_> = chart_a.down_map.keys().cloned().collect();
|
||||
let mut keys: Vec<Ipv4Addr> = up_keys.union(&down_keys).cloned().collect();
|
||||
// 排序
|
||||
keys.sort();
|
||||
|
||||
// 找到最大的值,用于缩放条形图长度
|
||||
let up_max_value = *chart_a.up_map.values().max().unwrap_or(&0);
|
||||
let down_max_value = *chart_a.down_map.values().max().unwrap_or(&0);
|
||||
let max_value = up_max_value.max(down_max_value);
|
||||
let max_value = max_value.max(1);
|
||||
let max_height = 50;
|
||||
// 打印条形图
|
||||
for key in &keys {
|
||||
if let Some(&value) = chart_a.up_map.get(key) {
|
||||
let bar = "█".repeat(((value as f64 / max_value as f64) * max_height as f64) as usize);
|
||||
println!(
|
||||
"{:<10} | {} upload {}",
|
||||
key,
|
||||
bar,
|
||||
style(convert(value)).green()
|
||||
);
|
||||
}
|
||||
if let Some(&value) = chart_a.down_map.get(key) {
|
||||
let bar = "█".repeat(((value as f64 / max_value as f64) * max_height as f64) as usize);
|
||||
println!(
|
||||
"{:<10} | {} download {}",
|
||||
key,
|
||||
bar,
|
||||
style(convert(value)).green()
|
||||
);
|
||||
}
|
||||
println!("-");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn console_chart_b(chart_b: ChartB) {
|
||||
if chart_b.disable_stats {
|
||||
println!("Traffic statistics not enabled");
|
||||
return;
|
||||
}
|
||||
let ip = if let Some(ip) = chart_b.ip {
|
||||
ip
|
||||
} else {
|
||||
println!("Ip: None");
|
||||
return;
|
||||
};
|
||||
println!("---------------------------- upload ----------------------------");
|
||||
println!("IP: {}", ip);
|
||||
println!("Upload total: {}", style(convert(chart_b.up_total)).green());
|
||||
println!(
|
||||
"Max: {}",
|
||||
style(convert(
|
||||
chart_b
|
||||
.up_list
|
||||
.iter()
|
||||
.max()
|
||||
.cloned()
|
||||
.map_or(0, |v| v as u64)
|
||||
))
|
||||
.green()
|
||||
);
|
||||
console_chart_b_list(chart_b.up_list);
|
||||
println!("---------------------------- download ----------------------------");
|
||||
println!("IP: {}", ip);
|
||||
println!(
|
||||
"Download total: {}",
|
||||
style(convert(chart_b.down_total)).green()
|
||||
);
|
||||
println!(
|
||||
"Max: {}",
|
||||
style(convert(
|
||||
chart_b
|
||||
.down_list
|
||||
.iter()
|
||||
.max()
|
||||
.cloned()
|
||||
.map_or(0, |v| v as u64)
|
||||
))
|
||||
.green()
|
||||
);
|
||||
console_chart_b_list(chart_b.down_list);
|
||||
}
|
||||
fn console_chart_b_list(list: Vec<usize>) {
|
||||
let max_value = *list.iter().max().unwrap_or(&0);
|
||||
let max_value = max_value.max(1);
|
||||
let max_height = max_value.min(20);
|
||||
// 遍历从最大高度到0
|
||||
for i in (0..=max_height).rev() {
|
||||
for &value in &list {
|
||||
let scaled_value = (value as f64 / max_value as f64 * max_height as f64) as usize;
|
||||
if scaled_value >= i {
|
||||
print!("█");
|
||||
} else {
|
||||
print!(" ");
|
||||
}
|
||||
}
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
+14
-18
@@ -52,6 +52,19 @@ pub fn get_unique_identifier() -> Option<String> {
|
||||
pub fn get_unique_identifier() -> Option<String> {
|
||||
use std::process::Command;
|
||||
|
||||
// Try to execute 'dmidecode' command to get the system identifier first.
|
||||
if let Ok(output) = Command::new("dmidecode")
|
||||
.arg("-s")
|
||||
.arg("system-uuid")
|
||||
.output()
|
||||
{
|
||||
let identifier = String::from_utf8_lossy(&output.stdout).trim().to_owned();
|
||||
if !identifier.is_empty() {
|
||||
return Some(identifier.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Try to read file /etc/machine-id if 'dmidecode' command cannot be executed or get nothing.
|
||||
// 对 linux 或 wsl 来说,读取 /etc/machine-id 即可获取当前操作系统的
|
||||
// 唯一标识,而且某些环境没有预装`dmidecode`命令
|
||||
if let Ok(identifier) = std::fs::read_to_string("/etc/machine-id") {
|
||||
@@ -61,22 +74,5 @@ pub fn get_unique_identifier() -> Option<String> {
|
||||
}
|
||||
}
|
||||
|
||||
let output = match Command::new("dmidecode")
|
||||
.arg("-s")
|
||||
.arg("system-uuid")
|
||||
.output()
|
||||
{
|
||||
Ok(output) => output,
|
||||
Err(_) => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let result = String::from_utf8_lossy(&output.stdout);
|
||||
let identifier = result.trim();
|
||||
if identifier.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(identifier.to_string())
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
+18
-14
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "vn-link-cli"
|
||||
version = "1.2.10"
|
||||
version = "1.2.11"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -11,20 +11,24 @@ 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"]
|
||||
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4"]
|
||||
|
||||
openssl = ["vn-link/openssl", "common/openssl"]
|
||||
openssl-vendored = ["vn-link/openssl-vendored", "common/openssl-vendored"]
|
||||
ring-cipher = ["vn-link/ring-cipher", "common/ring-cipher"]
|
||||
aes_cbc = ["vn-link/aes_cbc", "common/aes_cbc"]
|
||||
aes_ecb = ["vn-link/aes_ecb", "common/aes_ecb"]
|
||||
sm4_cbc = ["vn-link/sm4_cbc", "common/sm4_cbc"]
|
||||
aes_gcm = ["vn-link/aes_gcm", "common/aes_gcm"]
|
||||
chacha20_poly1305 = ["vn-link/chacha20_poly1305", "common/chacha20_poly1305"]
|
||||
server_encrypt = ["vn-link/server_encrypt", "common/server_encrypt"]
|
||||
port_mapping = ["vn-link/port_mapping", "common/port_mapping"]
|
||||
lz4 = ["vn-link/lz4_compress", "common/lz4"]
|
||||
zstd = ["vn-link/zstd_compress", "common/zstd"]
|
||||
upnp = ["vn-link/upnp", "common/upnp"]
|
||||
ws = ["vn-link/ws", "common/ws"]
|
||||
wss = ["vn-link/wss", "common/wss"]
|
||||
log = ["common/log"]
|
||||
command = ["common/command"]
|
||||
file_config = ["common/file_config"]
|
||||
|
||||
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4"]
|
||||
|
||||
@@ -65,7 +65,7 @@ async fn main0(config: Config, vn_link_config: VnLinkConfig, _show_cmd: bool) {
|
||||
let mut reader = tokio::io::BufReader::new(tokio::io::stdin());
|
||||
loop {
|
||||
cmd.clear();
|
||||
println!("======== input:list,info,route,all,stop ========");
|
||||
println!("======== input:list,info,route,all,stop,chart_a,chart_b[:ip] ========");
|
||||
match reader.read_line(&mut cmd).await {
|
||||
Ok(len) => {
|
||||
if !common::command::command_str(&cmd[..len], vnt_c) {
|
||||
|
||||
+4
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "vn-link"
|
||||
version = "1.2.10"
|
||||
version = "1.2.11"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -27,3 +27,6 @@ server_encrypt = ["vnt/server_encrypt"]
|
||||
port_mapping = ["vnt/port_mapping"]
|
||||
lz4_compress = ["vnt/lz4_compress"]
|
||||
zstd_compress = ["vnt/zstd_compress"]
|
||||
upnp = ["vnt/upnp"]
|
||||
ws = ["vnt/ws"]
|
||||
wss = ["vnt/wss"]
|
||||
+5
-4
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "vnt-cli"
|
||||
version = "1.2.10"
|
||||
version = "1.2.11"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@@ -21,7 +21,7 @@ winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "win
|
||||
|
||||
[features]
|
||||
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"]
|
||||
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4", "ws"]
|
||||
|
||||
openssl = ["vnt/openssl", "common/openssl"]
|
||||
openssl-vendored = ["vnt/openssl-vendored", "common/openssl-vendored"]
|
||||
@@ -36,11 +36,12 @@ 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"]
|
||||
upnp = ["vnt/upnp", "common/upnp"]
|
||||
ws = ["vnt/ws", "common/ws"]
|
||||
wss = ["vnt/wss", "common/wss"]
|
||||
log = ["common/log"]
|
||||
command = ["common/command"]
|
||||
file_config = ["common/file_config"]
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
rand = "0.8.5"
|
||||
chrono = "0.4.23"
|
||||
+1
-1
@@ -77,7 +77,7 @@ fn main0(config: Config, _show_cmd: bool) {
|
||||
let mut cmd = String::new();
|
||||
loop {
|
||||
cmd.clear();
|
||||
println!("======== input:list,info,route,all,stop ========");
|
||||
println!("======== input:list,info,route,all,stop,chart_a,chart_b[:ip] ========");
|
||||
match std::io::stdin().read_line(&mut cmd) {
|
||||
Ok(len) => {
|
||||
if !common::command::command_str(&cmd[..len], &vnt_util) {
|
||||
|
||||
+16
-9
@@ -1,12 +1,12 @@
|
||||
[package]
|
||||
name = "vnt"
|
||||
version = "1.2.10"
|
||||
version = "1.2.11"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
tun = { path = "tun" ,optional = true}
|
||||
tun = { path = "tun", optional = true }
|
||||
packet = { path = "./packet" }
|
||||
bytes = "1.5.0"
|
||||
log = "0.4.17"
|
||||
@@ -17,7 +17,7 @@ parking_lot = "0.12.1"
|
||||
rand = "0.8.5"
|
||||
sha2 = { version = "0.10.6", features = ["oid"] }
|
||||
thiserror = "1.0.37"
|
||||
protobuf = "3.2.0"
|
||||
protobuf = "=3.2.0"
|
||||
socket2 = { version = "0.5.2", features = ["all"] }
|
||||
aes-gcm = { version = "0.10.2", optional = true }
|
||||
ring = { version = "0.17.0", optional = true }
|
||||
@@ -32,28 +32,32 @@ spki = { version = "0.7.2", features = ["fingerprint", "alloc", "base64"], optio
|
||||
openssl-sys = { git = "https://github.com/lbl8603/rust-openssl", optional = true }
|
||||
libsm = { git = "https://github.com/lbl8603/libsm", optional = true }
|
||||
|
||||
mio = { version = "0.8.10", features = ["os-poll", "net", "os-ext"] }
|
||||
mio = { version = "=0.8.11", features = ["os-poll", "net", "os-ext"] }
|
||||
crossbeam-queue = "0.3.11"
|
||||
anyhow = "1.0.82"
|
||||
dns-parser = "0.8.0"
|
||||
|
||||
tokio = { version = "1.37.0", features = ["full"], optional = true }
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
|
||||
lz4_flex = { version = "0.11", default-features = false, optional = true }
|
||||
zstd = { version = "0.13.1", optional = true }
|
||||
|
||||
fnv = "1.0.7"
|
||||
igd = { version = "0.12.1", optional = true }
|
||||
tokio-tungstenite = { version = "0.23.1", optional = true }
|
||||
rustls = { version = "0.23.0", features = ["ring"], default-features = false, optional = true }
|
||||
futures-util = "0.3.30"
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
libloading = "0.8.0"
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
protobuf-codegen = "3.2.0"
|
||||
protobuf-codegen = "=3.2.0"
|
||||
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","integrated_tun"]
|
||||
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"]
|
||||
@@ -64,8 +68,11 @@ sm4_cbc = ["libsm"]
|
||||
aes_gcm = ["aes-gcm"]
|
||||
chacha20_poly1305 = ["chacha20poly1305", "chacha20"]
|
||||
server_encrypt = ["aes-gcm", "rsa", "spki"]
|
||||
ip_proxy = ["tokio"]
|
||||
port_mapping = ["tokio"]
|
||||
ip_proxy = []
|
||||
port_mapping = []
|
||||
lz4_compress = ["lz4_flex"]
|
||||
zstd_compress = ["zstd"]
|
||||
integrated_tun = ["tun"]
|
||||
upnp = ["igd"]
|
||||
ws = ["tokio-tungstenite"]
|
||||
wss = ["ws", "tokio-tungstenite/rustls-tls-native-roots", "tokio-tungstenite/rustls-tls-webpki-roots", "rustls"]
|
||||
+83
-45
@@ -12,7 +12,9 @@ use rand::Rng;
|
||||
|
||||
use crate::channel::punch::NatType;
|
||||
use crate::channel::sender::{AcceptSocketSender, PacketSender};
|
||||
use crate::channel::{Route, RouteKey, UseChannelType, DEFAULT_RT};
|
||||
use crate::channel::{ConnectProtocol, Route, RouteKey, UseChannelType, DEFAULT_RT};
|
||||
use crate::protocol::NetPacket;
|
||||
use crate::util::limit::TrafficMeterMultiAddress;
|
||||
|
||||
/// 传输通道上下文,持有udp socket、tcp socket和路由信息
|
||||
#[derive(Clone)]
|
||||
@@ -25,10 +27,12 @@ impl ChannelContext {
|
||||
main_udp_socket: Vec<UdpSocket>,
|
||||
use_channel_type: UseChannelType,
|
||||
first_latency: bool,
|
||||
is_tcp: bool,
|
||||
protocol: ConnectProtocol,
|
||||
packet_loss_rate: Option<f64>,
|
||||
packet_delay: u32,
|
||||
use_ipv6: bool,
|
||||
up_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||
down_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||
) -> Self {
|
||||
let channel_num = main_udp_socket.len();
|
||||
assert_ne!(channel_num, 0, "not channel");
|
||||
@@ -45,13 +49,15 @@ impl ChannelContext {
|
||||
let inner = ContextInner {
|
||||
main_udp_socket,
|
||||
sub_udp_socket: RwLock::new(Vec::new()),
|
||||
tcp_map: RwLock::new(FnvHashMap::default()),
|
||||
packet_map: RwLock::new(FnvHashMap::default()),
|
||||
route_table: RouteTable::new(use_channel_type, first_latency, channel_num),
|
||||
is_tcp,
|
||||
protocol,
|
||||
packet_loss_rate,
|
||||
packet_delay,
|
||||
main_index: AtomicUsize::new(0),
|
||||
use_ipv6,
|
||||
up_traffic_meter,
|
||||
down_traffic_meter,
|
||||
};
|
||||
Self {
|
||||
inner: Arc::new(inner),
|
||||
@@ -68,7 +74,7 @@ impl Deref for ChannelContext {
|
||||
}
|
||||
|
||||
/// 对称网络增加的udp socket数目,有助于增加打洞成功率
|
||||
pub const SYMMETRIC_CHANNEL_NUM: usize = 100;
|
||||
pub const SYMMETRIC_CHANNEL_NUM: usize = 84;
|
||||
const PACKET_LOSS_RATE_DENOMINATOR: u32 = 100_0000;
|
||||
|
||||
pub struct ContextInner {
|
||||
@@ -77,17 +83,19 @@ pub struct ContextInner {
|
||||
// 对称网络增加的udp socket
|
||||
sub_udp_socket: RwLock<Vec<UdpSocket>>,
|
||||
// tcp数据发送器
|
||||
pub(crate) tcp_map: RwLock<FnvHashMap<SocketAddr, PacketSender>>,
|
||||
pub(crate) packet_map: RwLock<FnvHashMap<SocketAddr, PacketSender>>,
|
||||
// 路由信息
|
||||
pub route_table: RouteTable,
|
||||
// 是否使用tcp连接服务器
|
||||
is_tcp: bool,
|
||||
// 使用什么协议连接服务器
|
||||
protocol: ConnectProtocol,
|
||||
//控制丢包率,取值v=[0,100_0000] 丢包率r=v/100_0000
|
||||
packet_loss_rate: u32,
|
||||
//控制延迟
|
||||
packet_delay: u32,
|
||||
main_index: AtomicUsize,
|
||||
use_ipv6: bool,
|
||||
pub(crate) up_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||
pub(crate) down_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||
}
|
||||
|
||||
impl ContextInner {
|
||||
@@ -98,11 +106,11 @@ impl ContextInner {
|
||||
pub fn is_cone(&self) -> bool {
|
||||
self.sub_udp_socket.read().is_empty()
|
||||
}
|
||||
pub fn is_main_tcp(&self) -> bool {
|
||||
self.is_tcp
|
||||
pub fn main_protocol(&self) -> ConnectProtocol {
|
||||
self.protocol
|
||||
}
|
||||
pub fn is_udp_main(&self, route_key: &RouteKey) -> bool {
|
||||
!route_key.is_tcp() && route_key.index < self.main_udp_socket.len()
|
||||
route_key.protocol().is_udp() && route_key.index < self.main_udp_socket.len()
|
||||
}
|
||||
pub fn first_latency(&self) -> bool {
|
||||
self.route_table.first_latency
|
||||
@@ -157,7 +165,7 @@ impl ContextInner {
|
||||
Ok(ports)
|
||||
}
|
||||
pub fn send_tcp(&self, buf: &[u8], addr: SocketAddr) -> io::Result<()> {
|
||||
if let Some(tcp) = self.tcp_map.read().get(&addr) {
|
||||
if let Some(tcp) = self.packet_map.read().get(&addr) {
|
||||
tcp.try_send(buf)
|
||||
} else {
|
||||
Err(io::Error::from(io::ErrorKind::NotFound))
|
||||
@@ -179,13 +187,20 @@ impl ContextInner {
|
||||
Ok(())
|
||||
}
|
||||
/// 将数据发送到默认通道,一般发往服务器才用此方法
|
||||
pub fn send_default(&self, buf: &[u8], addr: SocketAddr) -> io::Result<()> {
|
||||
if self.is_tcp {
|
||||
//服务端地址只在重连时检测变化
|
||||
self.send_tcp(buf, addr)
|
||||
pub fn send_default<B: AsRef<[u8]>>(
|
||||
&self,
|
||||
buf: &NetPacket<B>,
|
||||
addr: SocketAddr,
|
||||
) -> io::Result<()> {
|
||||
if self.protocol.is_udp() {
|
||||
self.send_main_udp(self.main_index.load(Ordering::Relaxed), buf.buffer(), addr)?
|
||||
} else {
|
||||
self.send_main_udp(self.main_index.load(Ordering::Relaxed), buf, addr)
|
||||
self.send_tcp(buf.buffer(), addr)?
|
||||
}
|
||||
if let Some(up_traffic_meter) = &self.up_traffic_meter {
|
||||
up_traffic_meter.add_traffic(buf.destination(), buf.data_len());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn change_main_index(&self) {
|
||||
@@ -199,7 +214,7 @@ impl ContextInner {
|
||||
if let Err(e) = udp.send_to(buf, addr) {
|
||||
log::warn!("{:?},add={:?}", e, addr);
|
||||
}
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
thread::sleep(Duration::from_millis(3));
|
||||
}
|
||||
}
|
||||
pub fn try_send_all_main(&self, buf: &[u8], addr: SocketAddr) {
|
||||
@@ -210,9 +225,9 @@ impl ContextInner {
|
||||
}
|
||||
}
|
||||
/// 发送网络数据
|
||||
pub fn send_ipv4_by_id(
|
||||
pub fn send_ipv4_by_id<B: AsRef<[u8]>>(
|
||||
&self,
|
||||
buf: &[u8],
|
||||
buf: &NetPacket<B>,
|
||||
id: &Ipv4Addr,
|
||||
server_addr: SocketAddr,
|
||||
send_default: bool,
|
||||
@@ -222,6 +237,7 @@ impl ContextInner {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
if self.packet_delay > 0 {
|
||||
thread::sleep(Duration::from_millis(self.packet_delay as _));
|
||||
}
|
||||
@@ -238,7 +254,7 @@ impl ContextInner {
|
||||
Ok(())
|
||||
}
|
||||
/// 将数据发到指定id
|
||||
pub fn send_by_id(&self, buf: &[u8], id: &Ipv4Addr) -> io::Result<()> {
|
||||
pub fn send_by_id<B: AsRef<[u8]>>(&self, buf: &NetPacket<B>, id: &Ipv4Addr) -> io::Result<()> {
|
||||
let mut c = 0;
|
||||
loop {
|
||||
let route = self.route_table.get_route_by_id(c, id)?;
|
||||
@@ -258,25 +274,35 @@ impl ContextInner {
|
||||
}
|
||||
}
|
||||
/// 将数据发到指定路由
|
||||
pub fn send_by_key(&self, buf: &[u8], route_key: RouteKey) -> io::Result<()> {
|
||||
if route_key.is_tcp {
|
||||
self.send_tcp(buf, route_key.addr)
|
||||
} else {
|
||||
if let Some(main_udp) = self.main_udp_socket.get(route_key.index) {
|
||||
main_udp.send_to(buf, route_key.addr)?;
|
||||
} else {
|
||||
if let Some(udp) = self
|
||||
.sub_udp_socket
|
||||
.read()
|
||||
.get(route_key.index - self.main_udp_socket.len())
|
||||
{
|
||||
udp.send_to(buf, route_key.addr)?;
|
||||
pub fn send_by_key<B: AsRef<[u8]>>(
|
||||
&self,
|
||||
buf: &NetPacket<B>,
|
||||
route_key: RouteKey,
|
||||
) -> io::Result<()> {
|
||||
match route_key.protocol() {
|
||||
ConnectProtocol::UDP => {
|
||||
if let Some(main_udp) = self.main_udp_socket.get(route_key.index) {
|
||||
main_udp.send_to(buf.buffer(), route_key.addr)?;
|
||||
} else {
|
||||
Err(io::Error::from(io::ErrorKind::NotFound))?
|
||||
if let Some(udp) = self
|
||||
.sub_udp_socket
|
||||
.read()
|
||||
.get(route_key.index - self.main_udp_socket.len())
|
||||
{
|
||||
udp.send_to(buf.buffer(), route_key.addr)?;
|
||||
} else {
|
||||
Err(io::Error::from(io::ErrorKind::NotFound))?
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
ConnectProtocol::TCP | ConnectProtocol::WS | ConnectProtocol::WSS => {
|
||||
self.send_tcp(buf.buffer(), route_key.addr)?
|
||||
}
|
||||
}
|
||||
if let Some(up_traffic_meter) = &self.up_traffic_meter {
|
||||
up_traffic_meter.add_traffic(buf.destination(), buf.data_len());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn remove_route(&self, ip: &Ipv4Addr, route_key: RouteKey) {
|
||||
self.route_table.remove_route(ip, route_key)
|
||||
@@ -327,18 +353,18 @@ impl RouteTable {
|
||||
}
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "route not found"))
|
||||
}
|
||||
pub fn add_route_if_absent(&self, id: Ipv4Addr, route: Route) {
|
||||
pub fn add_route_if_absent(&self, id: Ipv4Addr, route: Route) -> bool {
|
||||
self.add_route_(id, route, true)
|
||||
}
|
||||
pub fn add_route(&self, id: Ipv4Addr, route: Route) {
|
||||
pub fn add_route(&self, id: Ipv4Addr, route: Route) -> bool {
|
||||
self.add_route_(id, route, false)
|
||||
}
|
||||
fn add_route_(&self, id: Ipv4Addr, route: Route, only_if_absent: bool) {
|
||||
fn add_route_(&self, id: Ipv4Addr, route: Route, only_if_absent: bool) -> bool {
|
||||
// 限制通道类型
|
||||
match self.use_channel_type {
|
||||
UseChannelType::P2p => {
|
||||
if !route.is_p2p() {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -346,10 +372,18 @@ impl RouteTable {
|
||||
let key = route.route_key();
|
||||
if only_if_absent {
|
||||
if let Some((_, list)) = self.route_table.read().get(&id) {
|
||||
let mut p2p_num = 0;
|
||||
for (x, _) in list {
|
||||
if x.route_key() == key {
|
||||
return;
|
||||
if x.is_p2p() {
|
||||
p2p_num += 1;
|
||||
}
|
||||
if x.route_key() == key {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if !self.first_latency && p2p_num >= self.channel_num {
|
||||
// 非优先延迟的情况下,通道满了则不用再添加
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -361,11 +395,11 @@ impl RouteTable {
|
||||
for (x, time) in list.iter_mut() {
|
||||
if x.metric < route.metric && !self.first_latency {
|
||||
//非优先延迟的情况下 不能比当前的路径更长
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if x.route_key() == key {
|
||||
if only_if_absent {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
x.metric = route.metric;
|
||||
x.rt = route.rt;
|
||||
@@ -380,7 +414,7 @@ impl RouteTable {
|
||||
//如果延迟都稳定了,则去除多余通道
|
||||
for (route, _) in list.iter() {
|
||||
if route.rt == DEFAULT_RT {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//延迟优先模式需要更多的通道探测延迟最低的路线
|
||||
@@ -396,6 +430,9 @@ impl RouteTable {
|
||||
//非优先延迟的情况下 添加了直连的则排除非直连的
|
||||
list.retain(|(k, _)| k.is_p2p());
|
||||
}
|
||||
if self.channel_num <= list.len() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
//增加路由表容量,避免波动
|
||||
let limit_len = self.channel_num * 2;
|
||||
@@ -403,6 +440,7 @@ impl RouteTable {
|
||||
self.truncate_(list, limit_len);
|
||||
list.push((route, AtomicCell::new(Instant::now())));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
fn truncate_(&self, list: &mut Vec<(Route, AtomicCell<Instant>)>, len: usize) {
|
||||
if list.len() <= len {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::RouteKey;
|
||||
|
||||
pub trait RecvChannelHandler: Clone + Send + 'static {
|
||||
pub trait RecvChannelHandler: Clone + Send + Sync + 'static {
|
||||
fn handle(
|
||||
&mut self,
|
||||
&self,
|
||||
buf: &mut [u8],
|
||||
extend: &mut [u8],
|
||||
route_key: RouteKey,
|
||||
|
||||
@@ -39,7 +39,7 @@ impl Idle {
|
||||
}
|
||||
}
|
||||
}
|
||||
let sleep_time = self.read_idle - max;
|
||||
let sleep_time = self.read_idle.checked_sub(max).unwrap_or_default();
|
||||
return IdleType::Sleep(sleep_time);
|
||||
}
|
||||
}
|
||||
|
||||
+89
-27
@@ -1,12 +1,16 @@
|
||||
use anyhow::Context;
|
||||
use std::net::{SocketAddr, UdpSocket};
|
||||
use std::str::FromStr;
|
||||
use tokio::sync::mpsc::channel;
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::handler::RecvChannelHandler;
|
||||
use crate::channel::sender::AcceptSocketSender;
|
||||
use crate::channel::sender::{AcceptSocketSender, ConnectUtil};
|
||||
use crate::channel::tcp_channel::tcp_listen;
|
||||
use crate::channel::udp_channel::udp_listen;
|
||||
#[cfg(feature = "ws")]
|
||||
use crate::channel::ws_channel::ws_connect_accept;
|
||||
use crate::util::limit::TrafficMeterMultiAddress;
|
||||
use crate::util::StopManager;
|
||||
|
||||
pub mod context;
|
||||
@@ -17,14 +21,21 @@ pub mod punch;
|
||||
pub mod sender;
|
||||
pub mod tcp_channel;
|
||||
pub mod udp_channel;
|
||||
#[cfg(feature = "ws")]
|
||||
pub mod ws_channel;
|
||||
|
||||
pub const BUFFER_SIZE: usize = 1024 * 64;
|
||||
// 这里留个坑,tcp是支持_TCP_MAX_PACKET_SIZE长度的,
|
||||
// 但是缓存只用BUFFER_SIZE,会导致多余的数据接收不了
|
||||
const TCP_MAX_PACKET_SIZE: usize = (1 << 24) - 1;
|
||||
|
||||
pub const BUFFER_SIZE: usize = 1024 * 16;
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum UseChannelType {
|
||||
Relay,
|
||||
P2p,
|
||||
All,
|
||||
}
|
||||
|
||||
impl UseChannelType {
|
||||
pub fn is_only_relay(&self) -> bool {
|
||||
self == &UseChannelType::Relay
|
||||
@@ -36,6 +47,7 @@ impl UseChannelType {
|
||||
self == &UseChannelType::All
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for UseChannelType {
|
||||
type Err = String;
|
||||
|
||||
@@ -48,15 +60,49 @@ impl FromStr for UseChannelType {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for UseChannelType {
|
||||
fn default() -> Self {
|
||||
UseChannelType::All
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub enum ConnectProtocol {
|
||||
UDP,
|
||||
TCP,
|
||||
WS,
|
||||
WSS,
|
||||
}
|
||||
|
||||
impl ConnectProtocol {
|
||||
#[inline]
|
||||
pub fn is_tcp(&self) -> bool {
|
||||
self == &ConnectProtocol::TCP
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_udp(&self) -> bool {
|
||||
self == &ConnectProtocol::UDP
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_ws(&self) -> bool {
|
||||
self == &ConnectProtocol::WS
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_wss(&self) -> bool {
|
||||
self == &ConnectProtocol::WSS
|
||||
}
|
||||
pub fn is_transport(&self) -> bool {
|
||||
self.is_tcp() || self.is_udp()
|
||||
}
|
||||
pub fn is_base_tcp(&self) -> bool {
|
||||
self.is_tcp() || self.is_ws() || self.is_wss()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Route {
|
||||
pub is_tcp: bool,
|
||||
pub protocol: ConnectProtocol,
|
||||
index: usize,
|
||||
pub addr: SocketAddr,
|
||||
pub metric: u8,
|
||||
@@ -68,11 +114,19 @@ pub struct RouteSortKey {
|
||||
pub metric: u8,
|
||||
pub rt: i64,
|
||||
}
|
||||
|
||||
const DEFAULT_RT: i64 = 9999;
|
||||
|
||||
impl Route {
|
||||
pub fn new(is_tcp: bool, index: usize, addr: SocketAddr, metric: u8, rt: i64) -> Self {
|
||||
pub fn new(
|
||||
protocol: ConnectProtocol,
|
||||
index: usize,
|
||||
addr: SocketAddr,
|
||||
metric: u8,
|
||||
rt: i64,
|
||||
) -> Self {
|
||||
Self {
|
||||
is_tcp,
|
||||
protocol,
|
||||
index,
|
||||
addr,
|
||||
metric,
|
||||
@@ -81,7 +135,7 @@ impl Route {
|
||||
}
|
||||
pub fn from(route_key: RouteKey, metric: u8, rt: i64) -> Self {
|
||||
Self {
|
||||
is_tcp: route_key.is_tcp,
|
||||
protocol: route_key.protocol,
|
||||
index: route_key.index,
|
||||
addr: route_key.addr,
|
||||
metric,
|
||||
@@ -90,7 +144,7 @@ impl Route {
|
||||
}
|
||||
pub fn from_default_rt(route_key: RouteKey, metric: u8) -> Self {
|
||||
Self {
|
||||
is_tcp: route_key.is_tcp,
|
||||
protocol: route_key.protocol,
|
||||
index: route_key.index,
|
||||
addr: route_key.addr,
|
||||
metric,
|
||||
@@ -99,7 +153,7 @@ impl Route {
|
||||
}
|
||||
pub fn route_key(&self) -> RouteKey {
|
||||
RouteKey {
|
||||
is_tcp: self.is_tcp,
|
||||
protocol: self.protocol,
|
||||
index: self.index,
|
||||
addr: self.addr,
|
||||
}
|
||||
@@ -117,22 +171,24 @@ impl Route {
|
||||
|
||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct RouteKey {
|
||||
is_tcp: bool,
|
||||
protocol: ConnectProtocol,
|
||||
index: usize,
|
||||
pub addr: SocketAddr,
|
||||
}
|
||||
|
||||
impl RouteKey {
|
||||
pub(crate) fn new(is_tcp: bool, index: usize, addr: SocketAddr) -> Self {
|
||||
pub(crate) fn new(protocol: ConnectProtocol, index: usize, addr: SocketAddr) -> Self {
|
||||
Self {
|
||||
is_tcp,
|
||||
protocol,
|
||||
index,
|
||||
addr,
|
||||
}
|
||||
}
|
||||
pub fn is_tcp(&self) -> bool {
|
||||
self.is_tcp
|
||||
#[inline]
|
||||
pub fn protocol(&self) -> ConnectProtocol {
|
||||
self.protocol
|
||||
}
|
||||
#[inline]
|
||||
pub fn index(&self) -> usize {
|
||||
self.index
|
||||
}
|
||||
@@ -142,10 +198,12 @@ pub(crate) fn init_context(
|
||||
ports: Vec<u16>,
|
||||
use_channel_type: UseChannelType,
|
||||
first_latency: bool,
|
||||
is_tcp: bool,
|
||||
protocol: ConnectProtocol,
|
||||
packet_loss_rate: Option<f64>,
|
||||
packet_delay: u32,
|
||||
) -> anyhow::Result<(ChannelContext, mio::net::TcpListener)> {
|
||||
up_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||
down_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||
) -> anyhow::Result<(ChannelContext, std::net::TcpListener)> {
|
||||
assert!(!ports.is_empty(), "not channel");
|
||||
let mut udps = Vec::with_capacity(ports.len());
|
||||
//检查系统是否支持ipv6
|
||||
@@ -172,11 +230,8 @@ pub(crate) fn init_context(
|
||||
address,
|
||||
)
|
||||
};
|
||||
if let Err(e) = socket.set_send_buffer_size(2 * 1024 * 1024) {
|
||||
log::warn!("set_send_buffer_size {:?}", e);
|
||||
}
|
||||
if let Err(e) = socket.set_recv_buffer_size(2 * 1024 * 1024) {
|
||||
log::warn!("set_send_buffer_size {:?}", e);
|
||||
log::warn!("set_recv_buffer_size {:?}", e);
|
||||
}
|
||||
socket
|
||||
.bind(&address.into())
|
||||
@@ -188,10 +243,12 @@ pub(crate) fn init_context(
|
||||
udps,
|
||||
use_channel_type,
|
||||
first_latency,
|
||||
is_tcp,
|
||||
protocol,
|
||||
packet_loss_rate,
|
||||
packet_delay,
|
||||
use_ipv6,
|
||||
up_traffic_meter,
|
||||
down_traffic_meter,
|
||||
);
|
||||
|
||||
let port = context.main_local_udp_port()?[0];
|
||||
@@ -229,32 +286,37 @@ pub(crate) fn init_context(
|
||||
socket.listen(128)?;
|
||||
socket.set_nonblocking(true)?;
|
||||
socket.set_nodelay(false)?;
|
||||
let tcp_listener = mio::net::TcpListener::from_std(socket.into());
|
||||
Ok((context, tcp_listener))
|
||||
Ok((context, socket.into()))
|
||||
}
|
||||
|
||||
pub(crate) fn init_channel<H>(
|
||||
tcp_listener: mio::net::TcpListener,
|
||||
tcp_listener: std::net::TcpListener,
|
||||
context: ChannelContext,
|
||||
stop_manager: StopManager,
|
||||
recv_handler: H,
|
||||
) -> anyhow::Result<(
|
||||
AcceptSocketSender<Option<Vec<mio::net::UdpSocket>>>,
|
||||
AcceptSocketSender<(mio::net::TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
||||
ConnectUtil,
|
||||
)>
|
||||
where
|
||||
H: RecvChannelHandler,
|
||||
{
|
||||
let (tcp_connect_s, tcp_connect_r) = channel(16);
|
||||
let (ws_connect_s, _ws_connect_r) = channel(16);
|
||||
let connect_util = ConnectUtil::new(tcp_connect_s, ws_connect_s);
|
||||
// udp监听,udp_socket_sender 用于NAT类型切换
|
||||
let udp_socket_sender =
|
||||
udp_listen(stop_manager.clone(), recv_handler.clone(), context.clone())?;
|
||||
// 建立tcp监听,tcp_socket_sender 用于tcp 直连
|
||||
let tcp_socket_sender = tcp_listen(
|
||||
tcp_listen(
|
||||
tcp_listener,
|
||||
stop_manager.clone(),
|
||||
tcp_connect_r,
|
||||
recv_handler.clone(),
|
||||
context.clone(),
|
||||
stop_manager.clone(),
|
||||
)?;
|
||||
#[cfg(feature = "ws")]
|
||||
ws_connect_accept(_ws_connect_r, recv_handler, context.clone(), stop_manager)?;
|
||||
|
||||
Ok((udp_socket_sender, tcp_socket_sender))
|
||||
Ok((udp_socket_sender, connect_util))
|
||||
}
|
||||
|
||||
+40
-51
@@ -1,16 +1,19 @@
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use std::collections::HashMap;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::ops::{Div, Mul};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{io, thread};
|
||||
|
||||
use mio::net::TcpStream;
|
||||
use rand::prelude::SliceRandom;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::sender::AcceptSocketSender;
|
||||
use crate::channel::sender::ConnectUtil;
|
||||
use crate::external_route::ExternalRoute;
|
||||
use crate::handle::CurrentDeviceInfo;
|
||||
use crate::nat::NatTest;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
@@ -47,7 +50,7 @@ pub struct NatInfo {
|
||||
pub nat_type: NatType,
|
||||
pub(crate) local_ipv4: Option<Ipv4Addr>,
|
||||
pub(crate) ipv6: Option<Ipv6Addr>,
|
||||
pub(crate) udp_ports: Vec<u16>,
|
||||
pub udp_ports: Vec<u16>,
|
||||
pub tcp_port: u16,
|
||||
}
|
||||
|
||||
@@ -99,26 +102,25 @@ impl NatInfo {
|
||||
nat_type,
|
||||
}
|
||||
}
|
||||
pub fn update_addr(&mut self, index: usize, ip: Ipv4Addr, port: u16) {
|
||||
pub fn update_addr(&mut self, index: usize, ip: Ipv4Addr, port: u16) -> bool {
|
||||
let mut updated = false;
|
||||
if port != 0 {
|
||||
if let Some(public_port) = self.public_ports.get_mut(index) {
|
||||
if *public_port != port {
|
||||
updated = true;
|
||||
log::info!("端口变化={}:{} index={}", ip, port, index)
|
||||
}
|
||||
*public_port = port;
|
||||
}
|
||||
}
|
||||
if !ip.is_multicast()
|
||||
&& !ip.is_broadcast()
|
||||
&& !ip.is_unspecified()
|
||||
&& !ip.is_loopback()
|
||||
&& !ip.is_private()
|
||||
{
|
||||
if crate::nat::is_ipv4_global(&ip) {
|
||||
if !self.public_ips.contains(&ip) {
|
||||
self.public_ips.push(ip);
|
||||
updated = true;
|
||||
log::info!("ip变化={},{:?}", ip, self.public_ips)
|
||||
}
|
||||
}
|
||||
updated
|
||||
}
|
||||
pub fn local_ipv4(&self) -> Option<Ipv4Addr> {
|
||||
self.local_ipv4
|
||||
@@ -186,9 +188,10 @@ pub struct Punch {
|
||||
port_index: HashMap<Ipv4Addr, usize>,
|
||||
punch_model: PunchModel,
|
||||
is_tcp: bool,
|
||||
tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
||||
connect_util: ConnectUtil,
|
||||
external_route: ExternalRoute,
|
||||
nat_test: NatTest,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
}
|
||||
|
||||
impl Punch {
|
||||
@@ -196,9 +199,10 @@ impl Punch {
|
||||
context: ChannelContext,
|
||||
punch_model: PunchModel,
|
||||
is_tcp: bool,
|
||||
tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
||||
connect_util: ConnectUtil,
|
||||
external_route: ExternalRoute,
|
||||
nat_test: NatTest,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
) -> Self {
|
||||
let mut port_vec: Vec<u16> = (1..65535).collect();
|
||||
port_vec.push(65535);
|
||||
@@ -210,34 +214,20 @@ impl Punch {
|
||||
port_index: HashMap::new(),
|
||||
punch_model,
|
||||
is_tcp,
|
||||
tcp_socket_sender,
|
||||
connect_util,
|
||||
external_route,
|
||||
nat_test,
|
||||
current_device,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Punch {
|
||||
fn connect_tcp(&self, buf: &[u8], addr: SocketAddr) -> bool {
|
||||
fn connect_tcp(&self, buf: &[u8], addr: SocketAddr) {
|
||||
if self.nat_test.is_local_address(true, addr) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
// mio是非阻塞的,不能立马判断是否能连接成功,所以用标准库的tcp
|
||||
match std::net::TcpStream::connect_timeout(&addr, Duration::from_millis(100)) {
|
||||
Ok(tcp_stream) => {
|
||||
if tcp_stream.set_nonblocking(true).is_err() {
|
||||
return false;
|
||||
}
|
||||
return self
|
||||
.tcp_socket_sender
|
||||
.try_add_socket((TcpStream::from_std(tcp_stream), addr, Some(buf.to_vec())))
|
||||
.is_ok();
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("连接到tcp失败,addr={},err={}", addr, e);
|
||||
}
|
||||
}
|
||||
false
|
||||
self.connect_util.try_connect_tcp(buf.to_vec(), addr);
|
||||
}
|
||||
pub fn punch(
|
||||
&mut self,
|
||||
@@ -245,19 +235,21 @@ impl Punch {
|
||||
id: Ipv4Addr,
|
||||
mut nat_info: NatInfo,
|
||||
punch_tcp: bool,
|
||||
count: usize,
|
||||
) -> io::Result<()> {
|
||||
if self.context.route_table.no_need_punch(&id) {
|
||||
log::info!("已打洞成功,无需打洞:{:?}", id);
|
||||
return Ok(());
|
||||
}
|
||||
nat_info
|
||||
.public_ips
|
||||
.retain(|ip| self.external_route.route(&ip).is_none());
|
||||
nat_info
|
||||
.local_ipv4
|
||||
.filter(|ip| self.external_route.route(&ip).is_none());
|
||||
let device_info = self.current_device.load();
|
||||
nat_info.public_ips.retain(|ip| {
|
||||
self.external_route.route(ip).is_none() && device_info.not_in_network(*ip)
|
||||
});
|
||||
nat_info.local_ipv4.filter(|ip| {
|
||||
self.external_route.route(ip).is_none() && device_info.not_in_network(*ip)
|
||||
});
|
||||
nat_info.ipv6.filter(|ip| {
|
||||
if let Some(ip) = ip.to_ipv4_mapped() {
|
||||
if let Some(ip) = ip.to_ipv4() {
|
||||
self.external_route.route(&ip).is_none()
|
||||
} else {
|
||||
true
|
||||
@@ -266,22 +258,16 @@ impl Punch {
|
||||
if punch_tcp && self.is_tcp && nat_info.tcp_port != 0 {
|
||||
//向tcp发起连接
|
||||
if let Some(ipv6_addr) = nat_info.local_tcp_ipv6addr() {
|
||||
if self.connect_tcp(buf, ipv6_addr) {
|
||||
// return Ok(());
|
||||
}
|
||||
self.connect_tcp(buf, ipv6_addr)
|
||||
}
|
||||
//向tcp发起连接
|
||||
if let Some(ipv4_addr) = nat_info.local_tcp_ipv4addr() {
|
||||
if self.connect_tcp(buf, ipv4_addr) {
|
||||
// return Ok(());
|
||||
}
|
||||
self.connect_tcp(buf, ipv4_addr)
|
||||
}
|
||||
if nat_info.nat_type == NatType::Cone && nat_info.public_ips.len() == 1 {
|
||||
let addr =
|
||||
SocketAddr::V4(SocketAddrV4::new(nat_info.public_ips[0], nat_info.tcp_port));
|
||||
if self.connect_tcp(buf, addr) {
|
||||
// return Ok(());
|
||||
}
|
||||
self.connect_tcp(buf, addr)
|
||||
}
|
||||
}
|
||||
let channel_num = self.context.channel_num();
|
||||
@@ -316,7 +302,11 @@ impl Punch {
|
||||
//预测范围内最多发送max_k1个包
|
||||
let max_k1 = 60;
|
||||
//全局最多发送max_k2个包
|
||||
let max_k2 = rand::thread_rng().gen_range(600..800);
|
||||
let mut max_k2: usize = rand::thread_rng().gen_range(600..800);
|
||||
if count > 2 {
|
||||
//递减探测规模
|
||||
max_k2 = max_k2.mul(2).div(count).max(max_k1 as usize);
|
||||
}
|
||||
let port = nat_info.public_ports.get(0).map(|e| *e).unwrap_or(0);
|
||||
if nat_info.public_port_range < max_k1 * 3 {
|
||||
//端口变化不大时,在预测的范围内随机发送
|
||||
@@ -332,8 +322,7 @@ impl Punch {
|
||||
} else {
|
||||
(max_port - min_port + 1) as usize
|
||||
};
|
||||
let mut nums: Vec<u16> = (min_port..max_port).collect();
|
||||
nums.push(max_port);
|
||||
let mut nums: Vec<u16> = (min_port..=max_port).collect();
|
||||
nums.shuffle(&mut rand::thread_rng());
|
||||
self.punch_symmetric(&nums[..k], buf, &nat_info.public_ips, max_k1 as usize)?;
|
||||
}
|
||||
@@ -397,7 +386,7 @@ impl Punch {
|
||||
}
|
||||
let addr = SocketAddr::V4(SocketAddrV4::new(*pub_ip, *port));
|
||||
self.context.send_main_udp(0, buf, addr)?;
|
||||
thread::sleep(Duration::from_millis(2));
|
||||
thread::sleep(Duration::from_millis(3));
|
||||
}
|
||||
}
|
||||
Ok(ports.len())
|
||||
|
||||
+49
-49
@@ -1,13 +1,13 @@
|
||||
use std::io;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::sync::mpsc::{SyncSender, TrySendError};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use mio::Token;
|
||||
use tokio::sync::mpsc::Sender;
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::notify::{AcceptNotify, WritableNotify};
|
||||
use crate::channel::notify::AcceptNotify;
|
||||
use crate::cipher::Cipher;
|
||||
use crate::compression::Compressor;
|
||||
use crate::external_route::ExternalRoute;
|
||||
@@ -87,17 +87,16 @@ impl IpPacketSender {
|
||||
if dest_ip.is_broadcast() {
|
||||
//走服务端广播
|
||||
self.context
|
||||
.send_default(net_packet.buffer(), device_info.connect_server)?;
|
||||
.send_default(&net_packet, 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(());
|
||||
// }
|
||||
if device_info.not_in_network(dest_ip) {
|
||||
//不是一个网段的直接忽略
|
||||
return Ok(());
|
||||
}
|
||||
self.context.send_ipv4_by_id(
|
||||
net_packet.buffer(),
|
||||
&net_packet,
|
||||
&dest_ip,
|
||||
device_info.connect_server,
|
||||
device_info.status.online(),
|
||||
@@ -134,53 +133,54 @@ impl<T> AcceptSocketSender<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PacketSender {
|
||||
inner: Arc<PacketSenderInner>,
|
||||
sender: Sender<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl PacketSender {
|
||||
pub fn new(notify: WritableNotify, buffer: SyncSender<Vec<u8>>, token: Token) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(PacketSenderInner {
|
||||
token,
|
||||
notify,
|
||||
buffer,
|
||||
}),
|
||||
}
|
||||
pub fn new(sender: Sender<Vec<u8>>) -> Self {
|
||||
Self { sender }
|
||||
}
|
||||
#[inline]
|
||||
pub fn try_send(&self, buf: &[u8]) -> io::Result<()> {
|
||||
self.inner.try_send(buf)
|
||||
}
|
||||
pub fn shutdown(&self) -> io::Result<()> {
|
||||
self.inner.shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PacketSenderInner {
|
||||
token: Token,
|
||||
notify: WritableNotify,
|
||||
buffer: SyncSender<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl PacketSenderInner {
|
||||
#[inline]
|
||||
fn try_send(&self, buf: &[u8]) -> io::Result<()> {
|
||||
let len = buf.len();
|
||||
let mut buf_vec = Vec::with_capacity(buf.len() + 4);
|
||||
buf_vec.extend_from_slice(&[0, 0, (len >> 8) as u8, (len & 0xFF) as u8]);
|
||||
buf_vec.extend_from_slice(buf);
|
||||
match self.buffer.try_send(buf_vec) {
|
||||
Ok(_) => self.notify.notify(self.token, true),
|
||||
Err(e) => match e {
|
||||
TrySendError::Disconnected(_) => Err(io::Error::from(io::ErrorKind::WriteZero)),
|
||||
TrySendError::Full(_) => Err(io::Error::from(io::ErrorKind::WouldBlock)),
|
||||
},
|
||||
match self.sender.try_send(buf.to_vec()) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => Err(io::Error::new(
|
||||
io::ErrorKind::WouldBlock,
|
||||
"通道已满,发生丢包",
|
||||
)),
|
||||
Err(_) => Err(io::Error::new(
|
||||
io::ErrorKind::ConnectionRefused,
|
||||
"通道关闭,发生丢包",
|
||||
)),
|
||||
}
|
||||
}
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
self.notify.notify(self.token, false)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ConnectUtil {
|
||||
connect_tcp: Sender<(Vec<u8>, SocketAddr)>,
|
||||
connect_ws: Sender<(Vec<u8>, String)>,
|
||||
}
|
||||
|
||||
impl ConnectUtil {
|
||||
pub fn new(
|
||||
connect_tcp: Sender<(Vec<u8>, SocketAddr)>,
|
||||
connect_ws: Sender<(Vec<u8>, String)>,
|
||||
) -> Self {
|
||||
Self {
|
||||
connect_tcp,
|
||||
connect_ws,
|
||||
}
|
||||
}
|
||||
pub fn try_connect_tcp(&self, buf: Vec<u8>, addr: SocketAddr) {
|
||||
if self.connect_tcp.try_send((buf, addr)).is_err() {
|
||||
log::warn!("try_connect_tcp failed {}", addr);
|
||||
}
|
||||
}
|
||||
pub fn try_connect_ws(&self, buf: Vec<u8>, addr: String) {
|
||||
if self.connect_ws.try_send((buf, addr)).is_err() {
|
||||
log::warn!("try_connect_ws failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+148
-430
@@ -1,468 +1,186 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{Shutdown, SocketAddr};
|
||||
#[cfg(any(unix))]
|
||||
use std::os::fd::FromRawFd;
|
||||
#[cfg(any(unix))]
|
||||
use std::os::fd::IntoRawFd;
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::io::FromRawSocket;
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::io::IntoRawSocket;
|
||||
use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TryRecvError, TrySendError};
|
||||
use std::{io, thread};
|
||||
|
||||
use mio::net::{TcpListener, TcpStream};
|
||||
use mio::{Events, Interest, Poll, Registry, Token, Waker};
|
||||
use anyhow::{anyhow, Context};
|
||||
use std::net::SocketAddr;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||
use tokio::net::tcp::OwnedReadHalf;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::sync::mpsc::{channel, Receiver};
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::handler::RecvChannelHandler;
|
||||
use crate::channel::notify::{AcceptNotify, WritableNotify};
|
||||
use crate::channel::sender::{AcceptSocketSender, PacketSender};
|
||||
use crate::channel::{RouteKey, BUFFER_SIZE};
|
||||
use crate::channel::sender::PacketSender;
|
||||
use crate::channel::{ConnectProtocol, RouteKey, BUFFER_SIZE, TCP_MAX_PACKET_SIZE};
|
||||
use crate::util::StopManager;
|
||||
|
||||
const SERVER: Token = Token(0);
|
||||
const NOTIFY: Token = Token(1);
|
||||
|
||||
/// 监听tcp端口,等待客户端连接
|
||||
pub fn tcp_listen<H>(
|
||||
tcp_server: TcpListener,
|
||||
stop_manager: StopManager,
|
||||
tcp_server: std::net::TcpListener,
|
||||
receiver: Receiver<(Vec<u8>, SocketAddr)>,
|
||||
recv_handler: H,
|
||||
context: ChannelContext,
|
||||
) -> anyhow::Result<AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>>
|
||||
stop_manager: StopManager,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
H: RecvChannelHandler,
|
||||
{
|
||||
let (tcp_sender, tcp_receiver) = sync_channel(64);
|
||||
let poll = Poll::new()?;
|
||||
let waker = AcceptNotify::new(Waker::new(poll.registry(), NOTIFY)?);
|
||||
let accept = AcceptSocketSender::new(waker.clone(), tcp_sender);
|
||||
let worker = {
|
||||
let waker = waker.clone();
|
||||
stop_manager.add_listener("tcp_listen".into(), move || {
|
||||
if let Err(e) = waker.stop() {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
})?
|
||||
};
|
||||
|
||||
let (stop_sender, stop_receiver) = tokio::sync::oneshot::channel::<()>();
|
||||
let worker = stop_manager.add_listener("tcpChannel".into(), move || {
|
||||
let _ = stop_sender.send(());
|
||||
})?;
|
||||
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||
.worker_threads(2)
|
||||
.enable_all()
|
||||
.build()
|
||||
.context("tcp tokio runtime build failed")?;
|
||||
thread::Builder::new()
|
||||
.name("tcpRead".into())
|
||||
.name("tcpChannel".into())
|
||||
.spawn(move || {
|
||||
if let Err(e) = tcp_listen0(
|
||||
poll,
|
||||
tcp_server,
|
||||
&stop_manager,
|
||||
waker,
|
||||
tcp_receiver,
|
||||
recv_handler,
|
||||
context,
|
||||
) {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
runtime.spawn(async move {
|
||||
{
|
||||
let recv_handler = recv_handler.clone();
|
||||
let context = context.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = tcp_accept(tcp_server, recv_handler, context).await {
|
||||
log::warn!("tcp_listen {:?}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
tokio::spawn(
|
||||
async move { connect_tcp_handle(receiver, recv_handler, context).await },
|
||||
);
|
||||
});
|
||||
runtime.block_on(async {
|
||||
let _ = stop_receiver.await;
|
||||
});
|
||||
runtime.shutdown_background();
|
||||
worker.stop_all();
|
||||
})?;
|
||||
Ok(accept)
|
||||
})
|
||||
.context("tcp thread build failed")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tcp_listen0<H>(
|
||||
mut poll: Poll,
|
||||
mut tcp_server: TcpListener,
|
||||
stop_manager: &StopManager,
|
||||
accept_notify: AcceptNotify,
|
||||
accept_tcp_receiver: Receiver<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
||||
mut recv_handler: H,
|
||||
async fn connect_tcp_handle<H>(
|
||||
mut receiver: Receiver<(Vec<u8>, SocketAddr)>,
|
||||
recv_handler: H,
|
||||
context: ChannelContext,
|
||||
) where
|
||||
H: RecvChannelHandler,
|
||||
{
|
||||
while let Some((data, addr)) = receiver.recv().await {
|
||||
let recv_handler = recv_handler.clone();
|
||||
let context = context.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = connect_tcp0(data, addr, recv_handler, context).await {
|
||||
log::warn!("发送失败,链接终止:{:?},{:?}", addr, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async fn connect_tcp0<H>(
|
||||
data: Vec<u8>,
|
||||
addr: SocketAddr,
|
||||
recv_handler: H,
|
||||
context: ChannelContext,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
H: RecvChannelHandler,
|
||||
{
|
||||
let (tcp_sender, tcp_receiver) = sync_channel(64);
|
||||
let write_waker = init_writable_handler(tcp_receiver, stop_manager.clone(), context.clone())?;
|
||||
poll.registry()
|
||||
.register(&mut tcp_server, SERVER, Interest::READABLE)?;
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut stream =
|
||||
tokio::time::timeout(Duration::from_secs(3), TcpStream::connect(addr)).await??;
|
||||
tcp_write(&mut stream, &data).await?;
|
||||
|
||||
let mut read_map: HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)> =
|
||||
HashMap::with_capacity(32);
|
||||
let mut extend = [0; BUFFER_SIZE];
|
||||
loop {
|
||||
if let Err(e) = poll.poll(&mut events, None) {
|
||||
crate::ignore_io_interrupted(e)?;
|
||||
continue;
|
||||
}
|
||||
for event in events.iter() {
|
||||
match event.token() {
|
||||
SERVER => loop {
|
||||
match tcp_server.accept() {
|
||||
Ok((stream, addr)) => {
|
||||
accept_handle(
|
||||
stream,
|
||||
addr,
|
||||
None,
|
||||
&write_waker,
|
||||
&mut read_map,
|
||||
&tcp_sender,
|
||||
poll.registry(),
|
||||
)?;
|
||||
}
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::WouldBlock {
|
||||
break;
|
||||
}
|
||||
return Err(e)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
NOTIFY => {
|
||||
if accept_notify.is_stop() {
|
||||
return Ok(());
|
||||
}
|
||||
if accept_notify.is_add_socket() {
|
||||
while let Ok((stream, addr, init_buf)) = accept_tcp_receiver.try_recv() {
|
||||
accept_handle(
|
||||
stream,
|
||||
addr,
|
||||
init_buf,
|
||||
&write_waker,
|
||||
&mut read_map,
|
||||
&tcp_sender,
|
||||
poll.registry(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
token => {
|
||||
if event.is_readable() {
|
||||
if let Err(e) = readable_handle(
|
||||
&token,
|
||||
&mut read_map,
|
||||
&mut recv_handler,
|
||||
&context,
|
||||
&mut extend,
|
||||
) {
|
||||
closed_handle_r(&token, &mut read_map);
|
||||
log::warn!("{:?}", e);
|
||||
if let Err(e) = write_waker.notify(token, false) {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
closed_handle_r(&token, &mut read_map);
|
||||
if let Err(e) = write_waker.notify(token, false) {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理写事件
|
||||
|
||||
fn init_writable_handler(
|
||||
receiver: Receiver<(TcpStream, Token, SocketAddr, Option<Vec<u8>>)>,
|
||||
stop_manager: StopManager,
|
||||
context: ChannelContext,
|
||||
) -> anyhow::Result<WritableNotify> {
|
||||
let poll = Poll::new()?;
|
||||
let writable_notify = WritableNotify::new(Waker::new(poll.registry(), NOTIFY)?);
|
||||
let worker = {
|
||||
let writable_notify = writable_notify.clone();
|
||||
stop_manager.add_listener("tcp_writable_handler".into(), move || {
|
||||
if let Err(e) = writable_notify.stop() {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
})?
|
||||
};
|
||||
{
|
||||
let writable_notify = writable_notify.clone();
|
||||
thread::Builder::new()
|
||||
.name("tcpWriteableListen".into())
|
||||
.spawn(move || {
|
||||
if let Err(e) = tcp_writable_listen(receiver, poll, writable_notify, &context) {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
worker.stop_all();
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(writable_notify)
|
||||
}
|
||||
|
||||
/// 处理写事件
|
||||
fn tcp_writable_listen(
|
||||
receiver: Receiver<(TcpStream, Token, SocketAddr, Option<Vec<u8>>)>,
|
||||
mut poll: Poll,
|
||||
writable_notify: WritableNotify,
|
||||
context: &ChannelContext,
|
||||
) -> io::Result<()> {
|
||||
let mut events = Events::with_capacity(1024);
|
||||
let mut write_map: HashMap<
|
||||
Token,
|
||||
(
|
||||
TcpStream,
|
||||
SocketAddr,
|
||||
Receiver<Vec<u8>>,
|
||||
Option<(Vec<u8>, usize)>,
|
||||
),
|
||||
> = HashMap::with_capacity(32);
|
||||
loop {
|
||||
if let Err(e) = poll.poll(&mut events, None) {
|
||||
crate::ignore_io_interrupted(e)?;
|
||||
continue;
|
||||
}
|
||||
for event in events.iter() {
|
||||
match event.token() {
|
||||
NOTIFY => {
|
||||
if writable_notify.is_stop() {
|
||||
//服务停止
|
||||
return Ok(());
|
||||
}
|
||||
if writable_notify.is_need_write() {
|
||||
// 需要写入数据
|
||||
if let Some(tokens) = writable_notify.take_all() {
|
||||
for (token, state) in tokens {
|
||||
if !state {
|
||||
closed_handle_w(&token, &mut write_map, &context);
|
||||
continue;
|
||||
}
|
||||
if let Err(e) = writable_handle(&token, &mut write_map) {
|
||||
closed_handle_w(&token, &mut write_map, &context);
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if writable_notify.is_add_socket() {
|
||||
//添加tcp连接,并监听写事件
|
||||
while let Ok((mut stream, token, addr, init_buf)) = receiver.try_recv() {
|
||||
if let Err(e) = stream.set_nodelay(true) {
|
||||
log::warn!("set_nodelay err={:?}", e);
|
||||
}
|
||||
if let Err(e) =
|
||||
poll.registry()
|
||||
.register(&mut stream, token, Interest::WRITABLE)
|
||||
{
|
||||
log::warn!("registry err={:?}", e);
|
||||
continue;
|
||||
}
|
||||
let (sender, receiver) = sync_channel(128);
|
||||
let packet_sender =
|
||||
PacketSender::new(writable_notify.clone(), sender, token);
|
||||
if let Some(init_buf) = init_buf {
|
||||
packet_sender.try_send(&init_buf)?;
|
||||
}
|
||||
|
||||
context.tcp_map.write().insert(addr, packet_sender);
|
||||
write_map.insert(token, (stream, addr, receiver, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
token => {
|
||||
if event.is_writable() {
|
||||
if let Err(e) = writable_handle(&token, &mut write_map) {
|
||||
closed_handle_w(&token, &mut write_map, &context);
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
} else {
|
||||
closed_handle_w(&token, &mut write_map, &context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn accept_handle(
|
||||
stream: TcpStream,
|
||||
addr: SocketAddr,
|
||||
init_buf: Option<Vec<u8>>,
|
||||
write_waker: &WritableNotify,
|
||||
read_map: &mut HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)>,
|
||||
tcp_sender: &SyncSender<(TcpStream, Token, SocketAddr, Option<Vec<u8>>)>,
|
||||
registry: &Registry,
|
||||
) -> io::Result<()> {
|
||||
#[cfg(windows)]
|
||||
let (tcp_stream, index) = unsafe {
|
||||
let fd = stream.into_raw_socket();
|
||||
(std::net::TcpStream::from_raw_socket(fd), fd as usize)
|
||||
};
|
||||
#[cfg(any(unix))]
|
||||
let (tcp_stream, index) = unsafe {
|
||||
let fd = stream.into_raw_fd();
|
||||
(std::net::TcpStream::from_raw_fd(fd), fd as usize)
|
||||
};
|
||||
if index == 0 || index == 1 {
|
||||
log::error!("index err={:?}", addr);
|
||||
return Ok(());
|
||||
}
|
||||
let token = Token(index);
|
||||
match tcp_stream.try_clone() {
|
||||
Ok(tcp_writer) => {
|
||||
match tcp_sender.try_send((TcpStream::from_std(tcp_writer), token, addr, init_buf)) {
|
||||
Ok(_) => {
|
||||
if let Err(e) = write_waker.add_socket() {
|
||||
log::error!("write_waker,err={:?},addr={:?}", e, addr);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return match e {
|
||||
TrySendError::Full(_) => {
|
||||
log::error!("Full,addr={:?}", addr);
|
||||
Ok(())
|
||||
}
|
||||
TrySendError::Disconnected(_) => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "write thread exit"))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("try_clone err={:?},addr={:?}", e, addr);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
let mut stream = TcpStream::from_std(tcp_stream);
|
||||
if let Err(e) = registry.register(&mut stream, token, Interest::READABLE) {
|
||||
log::error!("registry err={:?},addr={:?}", e, addr);
|
||||
return Ok(());
|
||||
}
|
||||
read_map.insert(
|
||||
token,
|
||||
(
|
||||
RouteKey::new(true, index, addr),
|
||||
stream,
|
||||
Box::new([0; BUFFER_SIZE]),
|
||||
0,
|
||||
),
|
||||
);
|
||||
tcp_stream_handle(stream, addr, recv_handler, context).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn readable_handle<H>(
|
||||
token: &Token,
|
||||
map: &mut HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)>,
|
||||
recv_handler: &mut H,
|
||||
context: &ChannelContext,
|
||||
extend: &mut [u8],
|
||||
) -> io::Result<()>
|
||||
async fn tcp_accept<H>(
|
||||
tcp_server: std::net::TcpListener,
|
||||
recv_handler: H,
|
||||
context: ChannelContext,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
H: RecvChannelHandler,
|
||||
{
|
||||
if let Some((route_key, stream, buf, begin)) = map.get_mut(token) {
|
||||
loop {
|
||||
let end = if *begin >= 4 {
|
||||
4 + (((buf[2] as u16) << 8) | buf[3] as u16) as usize
|
||||
} else {
|
||||
4
|
||||
};
|
||||
if end > BUFFER_SIZE {
|
||||
return Err(io::Error::from(io::ErrorKind::InvalidData));
|
||||
}
|
||||
match stream.read(&mut buf[*begin..end]) {
|
||||
Ok(len) => {
|
||||
if len == 0 {
|
||||
return Err(io::Error::from(io::ErrorKind::UnexpectedEof));
|
||||
}
|
||||
*begin += len;
|
||||
if end > 4 && *begin == end {
|
||||
recv_handler.handle(&mut buf[4..end], extend, *route_key, context);
|
||||
*begin = 0;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::WouldBlock {
|
||||
break;
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
let tcp_server = TcpListener::from_std(tcp_server)?;
|
||||
|
||||
loop {
|
||||
let (stream, addr) = tcp_server.accept().await?;
|
||||
tcp_stream_handle(stream, addr, recv_handler.clone(), context.clone()).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn tcp_stream_handle<H>(
|
||||
stream: TcpStream,
|
||||
addr: SocketAddr,
|
||||
recv_handler: H,
|
||||
context: ChannelContext,
|
||||
) where
|
||||
H: RecvChannelHandler,
|
||||
{
|
||||
let _ = stream.set_nodelay(true);
|
||||
let (r, mut w) = stream.into_split();
|
||||
let (sender, mut receiver) = channel::<Vec<u8>>(100);
|
||||
context
|
||||
.packet_map
|
||||
.write()
|
||||
.insert(addr, PacketSender::new(sender));
|
||||
tokio::spawn(async move {
|
||||
while let Some(data) = receiver.recv().await {
|
||||
if let Err(e) = tcp_write(&mut w, &data).await {
|
||||
log::info!("发送失败,tcp链接终止:{:?},{:?}", addr, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let _ = w.shutdown().await;
|
||||
});
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = tcp_read(r, addr, &context, recv_handler).await {
|
||||
log::warn!("tcp_read {:?}", e)
|
||||
}
|
||||
context.packet_map.write().remove(&addr);
|
||||
});
|
||||
}
|
||||
|
||||
async fn tcp_write<W: AsyncWrite + Unpin>(w: &mut W, buf: &[u8]) -> anyhow::Result<()> {
|
||||
let len = buf.len();
|
||||
if len > TCP_MAX_PACKET_SIZE {
|
||||
return Err(anyhow!("超过了tcp的最大长度传输"));
|
||||
}
|
||||
w.write_all(&[0, (len >> 16) as u8, (len >> 8) as u8, len as u8])
|
||||
.await?;
|
||||
w.write_all(&buf).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn writable_handle(
|
||||
token: &Token,
|
||||
map: &mut HashMap<
|
||||
Token,
|
||||
(
|
||||
TcpStream,
|
||||
SocketAddr,
|
||||
Receiver<Vec<u8>>,
|
||||
Option<(Vec<u8>, usize)>,
|
||||
),
|
||||
>,
|
||||
) -> io::Result<()> {
|
||||
if let Some((stream, _, receiver, last)) = map.get_mut(token) {
|
||||
loop {
|
||||
if let Some((buf, begin)) = last {
|
||||
match stream.write(&buf[*begin..]) {
|
||||
Ok(len) => {
|
||||
if len == 0 {
|
||||
return Err(io::Error::from(io::ErrorKind::WriteZero));
|
||||
}
|
||||
if len + *begin == buf.len() {
|
||||
*last = None;
|
||||
} else {
|
||||
*begin += len;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::WouldBlock {
|
||||
break;
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
match receiver.try_recv() {
|
||||
Ok(buf) => *last = Some((buf, 0)),
|
||||
Err(e) => match e {
|
||||
TryRecvError::Empty => {
|
||||
break;
|
||||
}
|
||||
TryRecvError::Disconnected => {
|
||||
return Err(io::Error::from(io::ErrorKind::Other));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn closed_handle_r(
|
||||
token: &Token,
|
||||
map: &mut HashMap<Token, (RouteKey, TcpStream, Box<[u8; BUFFER_SIZE]>, usize)>,
|
||||
) {
|
||||
if let Some((_, tcp, _, _)) = map.remove(token) {
|
||||
let _ = tcp.shutdown(Shutdown::Both);
|
||||
}
|
||||
}
|
||||
|
||||
fn closed_handle_w(
|
||||
token: &Token,
|
||||
map: &mut HashMap<
|
||||
Token,
|
||||
(
|
||||
TcpStream,
|
||||
SocketAddr,
|
||||
Receiver<Vec<u8>>,
|
||||
Option<(Vec<u8>, usize)>,
|
||||
),
|
||||
>,
|
||||
async fn tcp_read<H>(
|
||||
mut read: OwnedReadHalf,
|
||||
addr: SocketAddr,
|
||||
context: &ChannelContext,
|
||||
) {
|
||||
if let Some((tcp, addr, _, _)) = map.remove(token) {
|
||||
context.tcp_map.write().remove(&addr);
|
||||
let _ = tcp.shutdown(Shutdown::Both);
|
||||
recv_handler: H,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
H: RecvChannelHandler,
|
||||
{
|
||||
let mut head = [0; 4];
|
||||
let mut buf = [0; BUFFER_SIZE];
|
||||
let mut extend = [0; BUFFER_SIZE];
|
||||
loop {
|
||||
read.read_exact(&mut head).await?;
|
||||
if head[0] != 0 {
|
||||
return Err(anyhow!("tcp数据流错误 {}", addr));
|
||||
}
|
||||
let len = ((head[1] as usize) << 16) | ((head[2] as usize) << 8) | head[3] as usize;
|
||||
if len < 12 || len > buf.len() {
|
||||
return Err(anyhow!("tcp数据长度无效 {}", addr));
|
||||
}
|
||||
read.read_exact(&mut buf[..len]).await?;
|
||||
recv_handler.handle(
|
||||
&mut buf[..len],
|
||||
&mut extend,
|
||||
RouteKey::new(ConnectProtocol::TCP, 0, addr),
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::channel::context::ChannelContext;
|
||||
use crate::channel::handler::RecvChannelHandler;
|
||||
use crate::channel::notify::AcceptNotify;
|
||||
use crate::channel::sender::AcceptSocketSender;
|
||||
use crate::channel::{RouteKey, BUFFER_SIZE};
|
||||
use crate::channel::{ConnectProtocol, RouteKey, BUFFER_SIZE};
|
||||
use crate::util::StopManager;
|
||||
|
||||
pub fn udp_listen<H>(
|
||||
@@ -60,7 +60,7 @@ where
|
||||
|
||||
fn sub_udp_listen0<H>(
|
||||
mut poll: Poll,
|
||||
mut recv_handler: H,
|
||||
recv_handler: H,
|
||||
context: ChannelContext,
|
||||
accept_notify: AcceptNotify,
|
||||
accept_receiver: Receiver<Option<Vec<UdpSocket>>>,
|
||||
@@ -120,7 +120,7 @@ where
|
||||
recv_handler.handle(
|
||||
&mut buf[..len],
|
||||
&mut extend,
|
||||
RouteKey::new(false, token.0, addr),
|
||||
RouteKey::new(ConnectProtocol::UDP, token.0, addr),
|
||||
&context,
|
||||
);
|
||||
}
|
||||
@@ -238,7 +238,7 @@ where
|
||||
|
||||
pub fn main_udp_listen0<H>(
|
||||
mut poll: Poll,
|
||||
mut recv_handler: H,
|
||||
recv_handler: H,
|
||||
context: ChannelContext,
|
||||
) -> io::Result<()>
|
||||
where
|
||||
@@ -280,7 +280,7 @@ where
|
||||
recv_handler.handle(
|
||||
&mut buf[..len],
|
||||
&mut extend,
|
||||
RouteKey::new(false, index, addr),
|
||||
RouteKey::new(ConnectProtocol::UDP, index, addr),
|
||||
&context,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
use crate::channel::{ConnectProtocol, RouteKey, BUFFER_SIZE};
|
||||
use anyhow::Context;
|
||||
use futures_util::stream::SplitStream;
|
||||
use futures_util::{SinkExt, StreamExt};
|
||||
use std::convert::Into;
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::sync::mpsc::{channel, Receiver};
|
||||
use tokio_tungstenite::tungstenite::http::StatusCode;
|
||||
use tokio_tungstenite::tungstenite::{Error, Message};
|
||||
use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::handler::RecvChannelHandler;
|
||||
use crate::channel::sender::PacketSender;
|
||||
use crate::util::StopManager;
|
||||
|
||||
/// ws协议,
|
||||
/// 暂时只允许用ws连服务端,不能用ws打洞/连客户端
|
||||
pub fn ws_connect_accept<H>(
|
||||
receiver: Receiver<(Vec<u8>, String)>,
|
||||
recv_handler: H,
|
||||
context: ChannelContext,
|
||||
stop_manager: StopManager,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
H: RecvChannelHandler,
|
||||
{
|
||||
let (stop_sender, stop_receiver) = tokio::sync::oneshot::channel::<()>();
|
||||
let worker = stop_manager.add_listener("wsChannel".into(), move || {
|
||||
let _ = stop_sender.send(());
|
||||
})?;
|
||||
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||
.worker_threads(2)
|
||||
.enable_all()
|
||||
.build()
|
||||
.context("ws tokio runtime build failed")?;
|
||||
thread::Builder::new()
|
||||
.name("wsChannel".into())
|
||||
.spawn(move || {
|
||||
runtime.spawn(async move { connect_ws_handle(receiver, recv_handler, context).await });
|
||||
runtime.block_on(async {
|
||||
let _ = stop_receiver.await;
|
||||
});
|
||||
runtime.shutdown_background();
|
||||
worker.stop_all();
|
||||
})
|
||||
.context("ws thread build failed")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn connect_ws_handle<H>(
|
||||
mut receiver: Receiver<(Vec<u8>, String)>,
|
||||
recv_handler: H,
|
||||
context: ChannelContext,
|
||||
) where
|
||||
H: RecvChannelHandler,
|
||||
{
|
||||
while let Some((data, url)) = receiver.recv().await {
|
||||
let recv_handler = recv_handler.clone();
|
||||
let context = context.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = connect_ws(data, url, recv_handler, context).await {
|
||||
log::warn!("发送失败,ws链接终止:{:?}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
const WS_ADDR: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0));
|
||||
|
||||
async fn connect_ws<H>(
|
||||
data: Vec<u8>,
|
||||
mut url: String,
|
||||
recv_handler: H,
|
||||
context: ChannelContext,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
H: RecvChannelHandler,
|
||||
{
|
||||
let mut count = 0;
|
||||
log::info!("尝试建立连接 {:?}", url);
|
||||
let (mut ws, response) = loop {
|
||||
count += 1;
|
||||
if count > 3 {
|
||||
Err(anyhow::anyhow!("发生多次重定向,链接终止"))?
|
||||
}
|
||||
match tokio::time::timeout(Duration::from_secs(3), connect_async(url)).await? {
|
||||
Ok(rs) => break rs,
|
||||
Err(e) => {
|
||||
if let Error::Http(res) = &e {
|
||||
if res.status() == StatusCode::MOVED_PERMANENTLY
|
||||
|| res.status() == StatusCode::FOUND
|
||||
|| res.status() == StatusCode::SEE_OTHER
|
||||
|| res.status() == StatusCode::TEMPORARY_REDIRECT
|
||||
|| res.status() == StatusCode::PERMANENT_REDIRECT
|
||||
{
|
||||
if let Some(v) = res.headers().get("Location") {
|
||||
if let Ok(redirect) = v.to_str() {
|
||||
log::info!("url重定向响应头 {:?}", res.headers());
|
||||
log::info!("url重定向地址 {}", redirect);
|
||||
url = redirect.to_string();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Err(e)?;
|
||||
}
|
||||
}
|
||||
};
|
||||
log::info!("ws协议握手 {:?}", response);
|
||||
ws.send(Message::Binary(data)).await?;
|
||||
let (mut ws_write, ws_read) = ws.split();
|
||||
let (sender, mut receiver) = channel::<Vec<u8>>(100);
|
||||
context
|
||||
.packet_map
|
||||
.write()
|
||||
.insert(WS_ADDR, PacketSender::new(sender));
|
||||
tokio::spawn(async move {
|
||||
while let Some(data) = receiver.recv().await {
|
||||
if let Err(e) = ws_write.send(Message::Binary(data)).await {
|
||||
log::warn!("websocket err {:?}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let _ = ws_write.close().await;
|
||||
});
|
||||
if let Err(e) = ws_read_handle(ws_read, recv_handler, &context).await {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
context.packet_map.write().remove(&WS_ADDR);
|
||||
Ok(())
|
||||
}
|
||||
async fn ws_read_handle<H>(
|
||||
mut ws_read: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
|
||||
recv_handler: H,
|
||||
context: &ChannelContext,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
H: RecvChannelHandler,
|
||||
{
|
||||
let mut extend = [0; BUFFER_SIZE];
|
||||
let route_key = RouteKey::new(ConnectProtocol::WS, 0, WS_ADDR);
|
||||
while let Some(msg) = ws_read.next().await {
|
||||
let msg = msg.context("Error during WebSocket ")?;
|
||||
match msg {
|
||||
Message::Text(txt) => log::info!("Received text message: {}", txt),
|
||||
Message::Binary(mut data) => {
|
||||
recv_handler.handle(&mut data, &mut extend, route_key, context);
|
||||
}
|
||||
Message::Ping(_) | Message::Pong(_) => (),
|
||||
Message::Close(_) => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
+93
-49
@@ -1,5 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -26,32 +27,20 @@ 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::util::limit::TrafficMeterMultiAddress;
|
||||
use crate::util::{Scheduler, StopManager};
|
||||
use crate::{nat, VntCallback};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Vnt {
|
||||
stop_manager: StopManager,
|
||||
config: Config,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
nat_test: NatTest,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
context: Arc<Mutex<Option<ChannelContext>>>,
|
||||
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
||||
down_count_watcher: WatchU64Adder,
|
||||
up_count_watcher: WatchSingleU64Adder,
|
||||
client_secret_hash: Option<[u8; 16]>,
|
||||
compressor: Compressor,
|
||||
client_cipher: Cipher,
|
||||
external_route: ExternalRoute,
|
||||
inner: Arc<VntInner>,
|
||||
}
|
||||
|
||||
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())
|
||||
let inner = Arc::new(VntInner::new(config, callback)?);
|
||||
Ok(Self { inner })
|
||||
}
|
||||
#[cfg(not(feature = "integrated_tun"))]
|
||||
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
|
||||
@@ -59,14 +48,62 @@ impl Vnt {
|
||||
callback: Call,
|
||||
device: Device,
|
||||
) -> anyhow::Result<Self> {
|
||||
Vnt::new_device0(config, callback, device)
|
||||
let inner = Arc::new(VntInner::new_device(config, callback, device)?);
|
||||
Ok(Self { inner })
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Vnt {
|
||||
type Target = VntInner;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VntInner {
|
||||
stop_manager: StopManager,
|
||||
config: Config,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
nat_test: NatTest,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
context: Arc<Mutex<Option<ChannelContext>>>,
|
||||
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
||||
client_secret_hash: Option<[u8; 16]>,
|
||||
compressor: Compressor,
|
||||
client_cipher: Cipher,
|
||||
external_route: ExternalRoute,
|
||||
up_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||
down_traffic_meter: Option<TrafficMeterMultiAddress>,
|
||||
}
|
||||
|
||||
impl VntInner {
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
|
||||
VntInner::new_device0(config, callback, DeviceAdapter::default())
|
||||
}
|
||||
#[cfg(not(feature = "integrated_tun"))]
|
||||
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
|
||||
config: Config,
|
||||
callback: Call,
|
||||
device: Device,
|
||||
) -> anyhow::Result<Self> {
|
||||
VntInner::new_device0(config, callback, device)
|
||||
}
|
||||
fn new_device0<Call: VntCallback, Device: DeviceWrite>(
|
||||
config: Config,
|
||||
callback: Call,
|
||||
device: Device,
|
||||
) -> anyhow::Result<Self> {
|
||||
log::info!("config.toml:{:?}", config);
|
||||
log::info!("config: {:?}", config);
|
||||
let (up_traffic_meter, down_traffic_meter) = if config.enable_traffic {
|
||||
(
|
||||
Some(TrafficMeterMultiAddress::default()),
|
||||
Some(TrafficMeterMultiAddress::default()),
|
||||
)
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
//服务端非对称加密
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
let rsa_cipher: Arc<Mutex<Option<RsaCipher>>> = Arc::new(Mutex::new(None));
|
||||
@@ -137,9 +174,11 @@ impl Vnt {
|
||||
ports,
|
||||
config.use_channel_type,
|
||||
config.first_latency,
|
||||
config.tcp,
|
||||
config.protocol,
|
||||
config.packet_loss_rate,
|
||||
config.packet_delay,
|
||||
up_traffic_meter.clone(),
|
||||
down_traffic_meter.clone(),
|
||||
)?;
|
||||
let local_ipv4 = nat::local_ipv4();
|
||||
let local_ipv6 = nat::local_ipv6();
|
||||
@@ -174,15 +213,10 @@ impl Vnt {
|
||||
let (punch_sender, punch_receiver) = maintain::punch_channel();
|
||||
let peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>> =
|
||||
Arc::new(RwLock::new(HashMap::with_capacity(16)));
|
||||
let down_counter =
|
||||
U64Adder::with_capacity(config.ports.as_ref().map(|v| v.len()).unwrap_or_default() + 8);
|
||||
let down_count_watcher = down_counter.watch();
|
||||
let handshake = Handshake::new(
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
rsa_cipher.clone(),
|
||||
);
|
||||
let up_counter = SingleU64Adder::new();
|
||||
let up_count_watcher = up_counter.watch();
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
let tun_device_helper = {
|
||||
TunDeviceHelper::new(
|
||||
@@ -194,7 +228,6 @@ impl Vnt {
|
||||
proxy_map.clone(),
|
||||
client_cipher.clone(),
|
||||
server_cipher.clone(),
|
||||
up_counter,
|
||||
device_list.clone(),
|
||||
config.compressor,
|
||||
device.clone().into_device_adapter(),
|
||||
@@ -219,23 +252,23 @@ impl Vnt {
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
proxy_map.clone(),
|
||||
down_counter,
|
||||
handshake.clone(),
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
tun_device_helper,
|
||||
);
|
||||
|
||||
//初始化网络数据通道
|
||||
let (udp_socket_sender, tcp_socket_sender) =
|
||||
let (udp_socket_sender, connect_util) =
|
||||
init_channel(tcp_listener, context.clone(), stop_manager.clone(), handler)?;
|
||||
// 打洞逻辑
|
||||
let punch = Punch::new(
|
||||
context.clone(),
|
||||
config.punch_model,
|
||||
config.tcp,
|
||||
tcp_socket_sender.clone(),
|
||||
config.protocol.is_base_tcp(),
|
||||
connect_util.clone(),
|
||||
external_route.clone(),
|
||||
nat_test.clone(),
|
||||
current_device.clone(),
|
||||
);
|
||||
|
||||
// #[cfg(not(target_os = "android"))]
|
||||
@@ -246,7 +279,7 @@ impl Vnt {
|
||||
context.clone(),
|
||||
current_device.clone(),
|
||||
config_info.clone(),
|
||||
tcp_socket_sender.clone(),
|
||||
connect_util.clone(),
|
||||
callback.clone(),
|
||||
0,
|
||||
handshake,
|
||||
@@ -255,8 +288,6 @@ impl Vnt {
|
||||
let context = context.clone();
|
||||
let nat_test = nat_test.clone();
|
||||
let device_list = device_list.clone();
|
||||
let down_count_watcher = down_count_watcher.clone();
|
||||
let up_count_watcher = up_count_watcher.clone();
|
||||
let config_info = config_info.clone();
|
||||
let current_device = current_device.clone();
|
||||
if !config.use_channel_type.is_only_relay() {
|
||||
@@ -283,8 +314,6 @@ impl Vnt {
|
||||
config_info,
|
||||
punch,
|
||||
callback,
|
||||
down_count_watcher,
|
||||
up_count_watcher,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -297,12 +326,12 @@ impl Vnt {
|
||||
device_list,
|
||||
context: Arc::new(Mutex::new(Some(context))),
|
||||
peer_nat_info_map,
|
||||
down_count_watcher,
|
||||
up_count_watcher,
|
||||
client_secret_hash: config_info.client_secret_hash,
|
||||
compressor,
|
||||
client_cipher,
|
||||
external_route,
|
||||
up_traffic_meter,
|
||||
down_traffic_meter,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -319,8 +348,6 @@ pub fn start<Call: VntCallback>(
|
||||
config_info: BaseConfigInfo,
|
||||
punch: Punch,
|
||||
callback: Call,
|
||||
down_count_watcher: WatchU64Adder,
|
||||
up_count_watcher: WatchSingleU64Adder,
|
||||
) {
|
||||
// 定时心跳
|
||||
maintain::heartbeat(
|
||||
@@ -374,16 +401,10 @@ pub fn start<Call: VntCallback>(
|
||||
punch,
|
||||
);
|
||||
}
|
||||
maintain::up_status(
|
||||
scheduler,
|
||||
context.clone(),
|
||||
current_device.clone(),
|
||||
down_count_watcher,
|
||||
up_count_watcher,
|
||||
)
|
||||
maintain::up_status(scheduler, context.clone(), current_device.clone())
|
||||
}
|
||||
|
||||
impl Vnt {
|
||||
impl VntInner {
|
||||
pub fn name(&self) -> &str {
|
||||
&self.config.name
|
||||
}
|
||||
@@ -438,16 +459,33 @@ impl Vnt {
|
||||
}
|
||||
}
|
||||
pub fn up_stream(&self) -> u64 {
|
||||
self.up_count_watcher.get()
|
||||
self.up_traffic_meter.as_ref().map_or(0, |v| v.total())
|
||||
}
|
||||
pub fn up_stream_all(&self) -> Option<(u64, HashMap<Ipv4Addr, u64>)> {
|
||||
self.up_traffic_meter.as_ref().map(|v| v.get_all())
|
||||
}
|
||||
pub fn up_stream_history(&self) -> Option<(u64, HashMap<Ipv4Addr, (u64, Vec<usize>)>)> {
|
||||
self.up_traffic_meter.as_ref().map(|v| v.get_all_history())
|
||||
}
|
||||
pub fn down_stream(&self) -> u64 {
|
||||
self.down_count_watcher.get()
|
||||
self.down_traffic_meter.as_ref().map_or(0, |v| v.total())
|
||||
}
|
||||
pub fn down_stream_all(&self) -> Option<(u64, HashMap<Ipv4Addr, u64>)> {
|
||||
self.down_traffic_meter.as_ref().map(|v| v.get_all())
|
||||
}
|
||||
pub fn down_stream_history(&self) -> Option<(u64, HashMap<Ipv4Addr, (u64, Vec<usize>)>)> {
|
||||
self.down_traffic_meter
|
||||
.as_ref()
|
||||
.map(|v| v.get_all_history())
|
||||
}
|
||||
pub fn stop(&self) {
|
||||
//退出协助回收资源
|
||||
let _ = self.context.lock().take();
|
||||
self.stop_manager.stop()
|
||||
}
|
||||
pub fn is_stopped(&self) -> bool {
|
||||
self.stop_manager.is_stopped()
|
||||
}
|
||||
pub fn add_stop_listener<F>(&self, name: String, f: F) -> anyhow::Result<crate::util::Worker>
|
||||
where
|
||||
F: FnOnce() + Send + 'static,
|
||||
@@ -477,3 +515,9 @@ impl Vnt {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VntInner {
|
||||
fn drop(&mut self) {
|
||||
self.stop();
|
||||
}
|
||||
}
|
||||
|
||||
+33
-6
@@ -5,7 +5,7 @@ use std::str::FromStr;
|
||||
pub use conn::Vnt;
|
||||
|
||||
use crate::channel::punch::PunchModel;
|
||||
use crate::channel::UseChannelType;
|
||||
use crate::channel::{ConnectProtocol, UseChannelType};
|
||||
use crate::cipher::CipherModel;
|
||||
use crate::compression::Compressor;
|
||||
use crate::util::{address_choose, dns_query_all};
|
||||
@@ -28,7 +28,7 @@ pub struct Config {
|
||||
pub out_ips: Vec<(u32, u32)>,
|
||||
pub password: Option<String>,
|
||||
pub mtu: Option<u32>,
|
||||
pub tcp: bool,
|
||||
pub protocol: ConnectProtocol,
|
||||
pub ip: Option<Ipv4Addr>,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
@@ -50,6 +50,7 @@ pub struct Config {
|
||||
#[cfg(feature = "port_mapping")]
|
||||
pub port_mapping_list: Vec<(bool, SocketAddr, String)>,
|
||||
pub compressor: Compressor,
|
||||
pub enable_traffic: bool,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -67,7 +68,6 @@ impl Config {
|
||||
out_ips: Vec<(u32, u32)>,
|
||||
password: Option<String>,
|
||||
mtu: Option<u32>,
|
||||
tcp: bool,
|
||||
ip: Option<Ipv4Addr>,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
@@ -87,6 +87,7 @@ impl Config {
|
||||
// 例如 [udp:127.0.0.1:80->10.26.0.10:8080,tcp:127.0.0.1:80->10.26.0.10:8080]
|
||||
#[cfg(feature = "port_mapping")] port_mapping_list: Vec<String>,
|
||||
compressor: Compressor,
|
||||
enable_traffic: bool,
|
||||
) -> anyhow::Result<Self> {
|
||||
for x in stun_server.iter_mut() {
|
||||
if !x.contains(":") {
|
||||
@@ -109,8 +110,33 @@ impl Config {
|
||||
if name.is_empty() || name.len() > 128 {
|
||||
return Err(anyhow!("name too long"));
|
||||
}
|
||||
let server_address =
|
||||
address_choose(dns_query_all(&server_address_str, name_servers.clone())?)?;
|
||||
let mut server_address_str = server_address_str.to_lowercase();
|
||||
let mut _query_dns = true;
|
||||
let mut protocol = ConnectProtocol::UDP;
|
||||
if server_address_str.starts_with("ws://") {
|
||||
#[cfg(not(feature = "ws"))]
|
||||
Err(anyhow!("Ws not supported"))?;
|
||||
protocol = ConnectProtocol::WS;
|
||||
_query_dns = false;
|
||||
}
|
||||
if server_address_str.starts_with("wss://") {
|
||||
#[cfg(not(feature = "wss"))]
|
||||
Err(anyhow!("Wss not supported"))?;
|
||||
protocol = ConnectProtocol::WSS;
|
||||
_query_dns = false;
|
||||
}
|
||||
|
||||
let mut server_address = "0.0.0.0:0".parse().unwrap();
|
||||
if _query_dns {
|
||||
if let Some(s) = server_address_str.strip_prefix("udp://") {
|
||||
server_address_str = s.to_string();
|
||||
} else if let Some(s) = server_address_str.strip_prefix("tcp://") {
|
||||
server_address_str = s.to_string();
|
||||
protocol = ConnectProtocol::TCP;
|
||||
}
|
||||
server_address =
|
||||
address_choose(dns_query_all(&server_address_str, name_servers.clone())?)?;
|
||||
}
|
||||
#[cfg(feature = "port_mapping")]
|
||||
let port_mapping_list = crate::port_mapping::convert(port_mapping_list)?;
|
||||
|
||||
@@ -133,7 +159,7 @@ impl Config {
|
||||
out_ips,
|
||||
password,
|
||||
mtu,
|
||||
tcp,
|
||||
protocol,
|
||||
ip,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
@@ -153,6 +179,7 @@ impl Config {
|
||||
#[cfg(feature = "port_mapping")]
|
||||
port_mapping_list,
|
||||
compressor,
|
||||
enable_traffic,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,11 @@ impl Handshake {
|
||||
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
||||
) -> Self {
|
||||
Handshake {
|
||||
time: Arc::new(AtomicCell::new(Instant::now() - Duration::from_secs(60))),
|
||||
time: Arc::new(AtomicCell::new(
|
||||
Instant::now()
|
||||
.checked_sub(Duration::from_secs(60))
|
||||
.unwrap_or(Instant::now()),
|
||||
)),
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
rsa_cipher,
|
||||
}
|
||||
@@ -43,7 +47,7 @@ impl Handshake {
|
||||
}
|
||||
let request_packet = self.handshake_request_packet(secret)?;
|
||||
log::info!("发送握手请求,secret={},{:?}", secret, addr);
|
||||
context.send_default(request_packet.buffer(), addr)?;
|
||||
context.send_default(&request_packet, addr)?;
|
||||
self.time.store(Instant::now());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ fn pub_address_request(
|
||||
) {
|
||||
let channel_num = context.channel_num();
|
||||
let index = count % channel_num;
|
||||
let mut time = if index == channel_num - 1 { 19 } else { 1 };
|
||||
if let Err(e) = addr_request0(
|
||||
&context,
|
||||
¤t_device_info,
|
||||
@@ -51,12 +50,20 @@ fn pub_address_request(
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
let nat_info = nat_test.nat_info();
|
||||
if nat_info.nat_type == NatType::Symmetric {
|
||||
let time = if !nat_info.public_ports.contains(&0) && !nat_info.public_ips.is_empty() {
|
||||
//对称网络探测端口没啥作用,把频率放低,(锥形网络也只在打洞前需要探测端口,后续可以改改)
|
||||
if !nat_info.public_ports.contains(&0) && !nat_info.public_ips.is_empty() {
|
||||
time = 600;
|
||||
if nat_info.nat_type == NatType::Symmetric {
|
||||
600
|
||||
} else {
|
||||
if index == channel_num - 1 {
|
||||
19
|
||||
} else {
|
||||
7
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
3
|
||||
};
|
||||
|
||||
let rs = scheduler.timeout(Duration::from_secs(time), move |s| {
|
||||
pub_address_request(
|
||||
@@ -85,7 +92,7 @@ fn addr_request0(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if current_dev.connect_server.is_ipv4() && !context.is_main_tcp() {
|
||||
if current_dev.connect_server.is_ipv4() && !context.main_protocol().is_base_tcp() {
|
||||
// 如果连接的是ipv4服务,则探测公网端口
|
||||
let gateway_ip = current_dev.virtual_gateway;
|
||||
let src_ip = current_dev.virtual_ip;
|
||||
|
||||
@@ -59,8 +59,7 @@ fn heartbeat0(
|
||||
let mut is_send_gateway = false;
|
||||
match heartbeat_packet_server(device_list, server_cipher, src_ip, gateway_ip) {
|
||||
Ok(net_packet) => {
|
||||
if let Err(e) = context.send_default(net_packet.buffer(), current_device.connect_server)
|
||||
{
|
||||
if let Err(e) = context.send_default(&net_packet, current_device.connect_server) {
|
||||
log::warn!("heartbeat err={:?}", e)
|
||||
} else {
|
||||
is_send_gateway = true
|
||||
@@ -88,7 +87,7 @@ fn heartbeat0(
|
||||
}
|
||||
};
|
||||
for route in routes {
|
||||
if let Err(e) = context.send_by_key(net_packet.buffer(), route.route_key()) {
|
||||
if let Err(e) = context.send_by_key(&net_packet, route.route_key()) {
|
||||
log::warn!("heartbeat err={:?}", e)
|
||||
}
|
||||
}
|
||||
@@ -113,8 +112,7 @@ fn heartbeat0(
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if let Err(e) = context.send_default(net_packet.buffer(), current_device.connect_server)
|
||||
{
|
||||
if let Err(e) = context.send_default(&net_packet, current_device.connect_server) {
|
||||
log::error!("heartbeat_packet send_default err={:?}", e);
|
||||
}
|
||||
}
|
||||
@@ -195,7 +193,7 @@ fn client_relay0(
|
||||
if current_device.is_gateway(ip) {
|
||||
continue;
|
||||
}
|
||||
if let Err(e) = context.send_by_key(client_packet.buffer(), route.route_key()) {
|
||||
if let Err(e) = context.send_by_key(&client_packet, route.route_key()) {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
if index >= 2 {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use mio::net::TcpStream;
|
||||
|
||||
use crate::channel::context::ChannelContext;
|
||||
use crate::channel::idle::{Idle, IdleType};
|
||||
use crate::channel::sender::AcceptSocketSender;
|
||||
use crate::channel::sender::ConnectUtil;
|
||||
use crate::channel::ConnectProtocol;
|
||||
use crate::handle::callback::{ConnectInfo, ErrorType};
|
||||
use crate::handle::handshaker::Handshake;
|
||||
use crate::handle::{BaseConfigInfo, ConnectStatus, CurrentDeviceInfo};
|
||||
@@ -36,7 +35,7 @@ pub fn idle_gateway<Call: VntCallback>(
|
||||
context: ChannelContext,
|
||||
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
config: BaseConfigInfo,
|
||||
tcp_socket_sender: AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
||||
connect_util: ConnectUtil,
|
||||
call: Call,
|
||||
mut connect_count: usize,
|
||||
handshake: Handshake,
|
||||
@@ -45,7 +44,7 @@ pub fn idle_gateway<Call: VntCallback>(
|
||||
&context,
|
||||
¤t_device_info,
|
||||
&config,
|
||||
&tcp_socket_sender,
|
||||
&connect_util,
|
||||
&call,
|
||||
&mut connect_count,
|
||||
&handshake,
|
||||
@@ -56,7 +55,7 @@ pub fn idle_gateway<Call: VntCallback>(
|
||||
context,
|
||||
current_device_info,
|
||||
config,
|
||||
tcp_socket_sender,
|
||||
connect_util,
|
||||
call,
|
||||
connect_count,
|
||||
handshake,
|
||||
@@ -71,7 +70,7 @@ fn idle_gateway0<Call: VntCallback>(
|
||||
context: &ChannelContext,
|
||||
current_device: &AtomicCell<CurrentDeviceInfo>,
|
||||
config: &BaseConfigInfo,
|
||||
tcp_socket_sender: &AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
||||
connect_util: &ConnectUtil,
|
||||
call: &Call,
|
||||
connect_count: &mut usize,
|
||||
handshake: &Handshake,
|
||||
@@ -80,7 +79,7 @@ fn idle_gateway0<Call: VntCallback>(
|
||||
context,
|
||||
current_device,
|
||||
config,
|
||||
tcp_socket_sender,
|
||||
connect_util,
|
||||
call,
|
||||
connect_count,
|
||||
handshake,
|
||||
@@ -120,7 +119,7 @@ fn check_gateway_channel<Call: VntCallback>(
|
||||
context: &ChannelContext,
|
||||
current_device_info: &AtomicCell<CurrentDeviceInfo>,
|
||||
config: &BaseConfigInfo,
|
||||
tcp_socket_sender: &AcceptSocketSender<(TcpStream, SocketAddr, Option<Vec<u8>>)>,
|
||||
connect_util: &ConnectUtil,
|
||||
call: &Call,
|
||||
count: &mut usize,
|
||||
handshake: &Handshake,
|
||||
@@ -128,28 +127,29 @@ fn check_gateway_channel<Call: VntCallback>(
|
||||
let mut current_device = current_device_info.load();
|
||||
if current_device.status.offline() {
|
||||
*count += 1;
|
||||
// 探测服务器地址
|
||||
current_device = domain_request0(current_device_info, config);
|
||||
let connect_protocol = context.main_protocol();
|
||||
if connect_protocol.is_transport() {
|
||||
// 传输层的协议需要探测服务器地址
|
||||
current_device = domain_request0(current_device_info, config);
|
||||
}
|
||||
//需要重连
|
||||
call.connect(ConnectInfo::new(*count, current_device.connect_server));
|
||||
log::info!("发送握手请求,{:?}", config);
|
||||
if let Err(e) = handshake.send(context, config.server_secret, current_device.connect_server)
|
||||
{
|
||||
log::warn!("{:?}", e);
|
||||
if context.is_main_tcp() {
|
||||
let request_packet = handshake.handshake_request_packet(config.server_secret)?;
|
||||
//tcp需要重连
|
||||
let tcp_stream = std::net::TcpStream::connect_timeout(
|
||||
¤t_device.connect_server,
|
||||
Duration::from_secs(5),
|
||||
)?;
|
||||
tcp_stream.set_nonblocking(true)?;
|
||||
if let Err(e) = tcp_socket_sender.try_add_socket((
|
||||
TcpStream::from_std(tcp_stream),
|
||||
current_device.connect_server,
|
||||
Some(request_packet.into_buffer()),
|
||||
)) {
|
||||
log::warn!("{:?}", e)
|
||||
let request_packet = handshake.handshake_request_packet(config.server_secret)?;
|
||||
match connect_protocol {
|
||||
ConnectProtocol::UDP => {}
|
||||
ConnectProtocol::TCP => {
|
||||
connect_util.try_connect_tcp(
|
||||
request_packet.into_buffer(),
|
||||
current_device.connect_server,
|
||||
);
|
||||
}
|
||||
ConnectProtocol::WS | ConnectProtocol::WSS => {
|
||||
connect_util
|
||||
.try_connect_ws(request_packet.into_buffer(), config.server_addr.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::ops::{Div, Mul};
|
||||
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
@@ -158,7 +159,7 @@ fn punch_start(
|
||||
log::error!("{:?}", e);
|
||||
continue;
|
||||
}
|
||||
if let Err(e) = punch.punch(packet.buffer(), peer_ip, nat_info, count < 2) {
|
||||
if let Err(e) = punch.punch(packet.buffer(), peer_ip, nat_info, count < 2, count) {
|
||||
log::warn!("{:?}", e)
|
||||
}
|
||||
}
|
||||
@@ -190,7 +191,7 @@ fn punch_request(
|
||||
) {
|
||||
log::warn!("{:?}", e)
|
||||
}
|
||||
let sleep_time = [5, 6, 7];
|
||||
let sleep_time = [6, 7];
|
||||
Duration::from_secs(sleep_time[count % sleep_time.len()])
|
||||
} else {
|
||||
Duration::from_secs(5)
|
||||
@@ -249,9 +250,11 @@ fn punch0(
|
||||
.lock()
|
||||
.get(&info.virtual_ip)
|
||||
.cloned()
|
||||
.unwrap_or(0);
|
||||
.unwrap_or(0)
|
||||
.mul(2)
|
||||
.div(3);
|
||||
let p2p_num = context.route_table.p2p_num(&info.virtual_ip);
|
||||
let mut max_punch_interval = 70;
|
||||
let mut max_punch_interval = 50;
|
||||
if p2p_num > 0 {
|
||||
if punch_count == 0 {
|
||||
continue;
|
||||
@@ -286,7 +289,7 @@ fn punch0(
|
||||
punch_count,
|
||||
total_count,
|
||||
);
|
||||
context.send_default(packet.buffer(), current_device.connect_server)?;
|
||||
context.send_default(&packet, current_device.connect_server)?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ fn retrieve_nat_type0(
|
||||
log::warn!("nat re_test {:?}", e);
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "upnp")]
|
||||
nat_test.reset_upnp();
|
||||
log::info!("刷新nat成功")
|
||||
}
|
||||
})
|
||||
.expect("natTest");
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::handle::CurrentDeviceInfo;
|
||||
use crate::proto::message::{ClientStatusInfo, PunchNatType, RouteItem};
|
||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
use crate::protocol::{service_packet, NetPacket, Protocol, HEAD_LEN, MAX_TTL};
|
||||
use crate::util::{Scheduler, WatchSingleU64Adder, WatchU64Adder};
|
||||
use crate::util::Scheduler;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use protobuf::Message;
|
||||
use std::io;
|
||||
@@ -15,17 +15,9 @@ pub fn up_status(
|
||||
scheduler: &Scheduler,
|
||||
context: ChannelContext,
|
||||
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
down_count_watcher: WatchU64Adder,
|
||||
up_count_watcher: WatchSingleU64Adder,
|
||||
) {
|
||||
let _ = scheduler.timeout(Duration::from_secs(60), move |x| {
|
||||
up_status0(
|
||||
x,
|
||||
context,
|
||||
current_device_info,
|
||||
down_count_watcher,
|
||||
up_count_watcher,
|
||||
)
|
||||
up_status0(x, context, current_device_info)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -33,25 +25,12 @@ fn up_status0(
|
||||
scheduler: &Scheduler,
|
||||
context: ChannelContext,
|
||||
current_device_info: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
down_count_watcher: WatchU64Adder,
|
||||
up_count_watcher: WatchSingleU64Adder,
|
||||
) {
|
||||
if let Err(e) = send_up_status_packet(
|
||||
&context,
|
||||
¤t_device_info,
|
||||
&down_count_watcher,
|
||||
&up_count_watcher,
|
||||
) {
|
||||
if let Err(e) = send_up_status_packet(&context, ¤t_device_info) {
|
||||
log::warn!("{:?}", e)
|
||||
}
|
||||
let rs = scheduler.timeout(Duration::from_secs(10 * 60), move |x| {
|
||||
up_status0(
|
||||
x,
|
||||
context,
|
||||
current_device_info,
|
||||
down_count_watcher,
|
||||
up_count_watcher,
|
||||
)
|
||||
up_status0(x, context, current_device_info)
|
||||
});
|
||||
if !rs {
|
||||
log::info!("定时任务停止");
|
||||
@@ -61,8 +40,6 @@ fn up_status0(
|
||||
fn send_up_status_packet(
|
||||
context: &ChannelContext,
|
||||
current_device_info: &AtomicCell<CurrentDeviceInfo>,
|
||||
down_count_watcher: &WatchU64Adder,
|
||||
up_count_watcher: &WatchSingleU64Adder,
|
||||
) -> io::Result<()> {
|
||||
let device_info = current_device_info.load();
|
||||
if device_info.status.offline() {
|
||||
@@ -79,8 +56,8 @@ fn send_up_status_packet(
|
||||
item.next_ip = ip.into();
|
||||
message.p2p_list.push(item);
|
||||
}
|
||||
message.up_stream = up_count_watcher.get();
|
||||
message.down_stream = down_count_watcher.get();
|
||||
message.up_stream = context.up_traffic_meter.as_ref().map_or(0, |v| v.total());
|
||||
message.down_stream = context.down_traffic_meter.as_ref().map_or(0, |v| v.total());
|
||||
message.nat_type = protobuf::EnumOrUnknown::new(if context.is_cone() {
|
||||
PunchNatType::Cone
|
||||
} else {
|
||||
@@ -99,6 +76,6 @@ fn send_up_status_packet(
|
||||
net_packet.set_source(device_info.virtual_ip);
|
||||
net_packet.set_destination(device_info.virtual_gateway);
|
||||
net_packet.set_payload(&buf)?;
|
||||
context.send_default(net_packet.buffer(), device_info.connect_server)?;
|
||||
context.send_default(&net_packet, device_info.connect_server)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+16
-1
@@ -1,5 +1,5 @@
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
|
||||
pub mod callback;
|
||||
mod extension;
|
||||
@@ -229,9 +229,24 @@ impl CurrentDeviceInfo {
|
||||
pub fn virtual_gateway(&self) -> Ipv4Addr {
|
||||
self.virtual_gateway
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_gateway(&self, ip: &Ipv4Addr) -> bool {
|
||||
&self.virtual_gateway == ip || ip == &GATEWAY_IP
|
||||
}
|
||||
#[inline]
|
||||
pub fn not_in_network(&self, ip: Ipv4Addr) -> bool {
|
||||
u32::from(ip) & u32::from(self.virtual_netmask) != u32::from(self.virtual_network)
|
||||
}
|
||||
pub fn is_server_addr(&self, addr: SocketAddr) -> bool {
|
||||
if self.connect_server == addr {
|
||||
return true;
|
||||
}
|
||||
let f = |ip: IpAddr| match ip {
|
||||
IpAddr::V4(v4) => Some(v4),
|
||||
IpAddr::V6(v6) => v6.to_ipv4(),
|
||||
};
|
||||
addr.port() == self.connect_server.port() && f(addr.ip()) == f(self.connect_server.ip())
|
||||
}
|
||||
}
|
||||
pub fn change_status(
|
||||
current_device: &AtomicCell<CurrentDeviceInfo>,
|
||||
|
||||
@@ -140,7 +140,7 @@ impl<Device: DeviceWrite> ClientPacketHandler<Device> {
|
||||
net_packet.set_destination(source);
|
||||
//不管加不加密,和接收到的数据长度都一致
|
||||
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
context.send_by_key(net_packet.buffer(), route_key)?;
|
||||
context.send_by_key(&net_packet, route_key)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@@ -212,14 +212,18 @@ impl<Device: DeviceWrite> ClientPacketHandler<Device> {
|
||||
let source = net_packet.source();
|
||||
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||
ControlPacket::PingPacket(_) => {
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
|
||||
net_packet.set_source(current_device.virtual_ip);
|
||||
net_packet.set_destination(source);
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
context.send_by_key(net_packet.buffer(), route_key)?;
|
||||
let route = Route::from_default_rt(route_key, metric);
|
||||
context.route_table.add_route_if_absent(source, route);
|
||||
if context.route_table.add_route_if_absent(source, route)
|
||||
|| net_packet.source() < current_device.virtual_ip
|
||||
{
|
||||
//在路由表中,或者来源比自己小,就需要回复,注意不能调换顺序
|
||||
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
|
||||
net_packet.set_source(current_device.virtual_ip);
|
||||
net_packet.set_destination(source);
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
context.send_by_key(&net_packet, route_key)?;
|
||||
}
|
||||
}
|
||||
ControlPacket::PongPacket(pong_packet) => {
|
||||
let current_time = crate::handle::now_time() as u16;
|
||||
@@ -238,7 +242,7 @@ impl<Device: DeviceWrite> ClientPacketHandler<Device> {
|
||||
//忽略掉来源于自己的包
|
||||
if self
|
||||
.nat_test
|
||||
.is_local_address(route_key.is_tcp(), route_key.addr)
|
||||
.is_local_address(route_key.protocol().is_base_tcp(), route_key.addr)
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
@@ -249,7 +253,7 @@ impl<Device: DeviceWrite> ClientPacketHandler<Device> {
|
||||
net_packet.set_destination(source);
|
||||
net_packet.first_set_ttl(1);
|
||||
self.client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
context.send_by_key(net_packet.buffer(), route_key)?;
|
||||
context.send_by_key(&net_packet, route_key)?;
|
||||
// 收到PunchRequest就添加路由,会导致单向通信的问题,删掉试试
|
||||
// let route = Route::from_default_rt(route_key, 1);
|
||||
// context.route_table.add_route_if_absent(source, route);
|
||||
@@ -261,7 +265,7 @@ impl<Device: DeviceWrite> ClientPacketHandler<Device> {
|
||||
}
|
||||
if self
|
||||
.nat_test
|
||||
.is_local_address(route_key.is_tcp(), route_key.addr)
|
||||
.is_local_address(route_key.protocol().is_base_tcp(), route_key.addr)
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
@@ -281,7 +285,7 @@ impl<Device: DeviceWrite> ClientPacketHandler<Device> {
|
||||
addr_packet.set_ipv4(ipv4);
|
||||
addr_packet.set_port(route_key.addr.port());
|
||||
self.client_cipher.encrypt_ipv4(&mut packet)?;
|
||||
context.send_by_key(packet.buffer(), route_key)?;
|
||||
context.send_by_key(&packet, route_key)?;
|
||||
}
|
||||
std::net::IpAddr::V6(_) => {}
|
||||
},
|
||||
@@ -377,7 +381,7 @@ impl<Device: DeviceWrite> ClientPacketHandler<Device> {
|
||||
punch_packet.set_payload(&bytes)?;
|
||||
self.client_cipher.encrypt_ipv4(&mut punch_packet)?;
|
||||
if self.punch_sender.send(true, source, peer_nat_info) {
|
||||
context.send_by_key(punch_packet.buffer(), route_key)?;
|
||||
context.send_by_key(&punch_packet, route_key)?;
|
||||
}
|
||||
} else {
|
||||
self.punch_sender.send(false, source, peer_nat_info);
|
||||
|
||||
@@ -26,7 +26,6 @@ use crate::ip_proxy::IpProxyMap;
|
||||
use crate::nat::NatTest;
|
||||
use crate::protocol::{NetPacket, HEAD_LEN};
|
||||
use crate::tun_tap_device::vnt_device::DeviceWrite;
|
||||
use crate::util::U64Adder;
|
||||
|
||||
mod client;
|
||||
mod server;
|
||||
@@ -38,13 +37,12 @@ pub struct RecvDataHandler<Call, Device> {
|
||||
turn: TurnPacketHandler,
|
||||
client: ClientPacketHandler<Device>,
|
||||
server: ServerPacketHandler<Call, Device>,
|
||||
counter: U64Adder,
|
||||
nat_test: NatTest,
|
||||
}
|
||||
|
||||
impl<Call: VntCallback, Device: DeviceWrite> RecvChannelHandler for RecvDataHandler<Call, Device> {
|
||||
fn handle(
|
||||
&mut self,
|
||||
&self,
|
||||
buf: &mut [u8],
|
||||
extend: &mut [u8],
|
||||
route_key: RouteKey,
|
||||
@@ -54,7 +52,7 @@ impl<Call: VntCallback, Device: DeviceWrite> RecvChannelHandler for RecvDataHand
|
||||
return;
|
||||
}
|
||||
//判断stun响应包
|
||||
if !route_key.is_tcp() {
|
||||
if route_key.protocol().is_udp() {
|
||||
if let Ok(rs) = self
|
||||
.nat_test
|
||||
.recv_data(route_key.index(), route_key.addr, buf)
|
||||
@@ -93,7 +91,6 @@ impl<Call: VntCallback, Device: DeviceWrite> RecvDataHandler<Call, Device> {
|
||||
#[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,
|
||||
@@ -130,20 +127,18 @@ impl<Call: VntCallback, Device: DeviceWrite> RecvDataHandler<Call, Device> {
|
||||
turn,
|
||||
client,
|
||||
server,
|
||||
counter,
|
||||
nat_test,
|
||||
}
|
||||
}
|
||||
fn handle0(
|
||||
&mut self,
|
||||
&self,
|
||||
buf: &mut [u8],
|
||||
extend: &mut [u8],
|
||||
route_key: RouteKey,
|
||||
context: &ChannelContext,
|
||||
) -> anyhow::Result<()> {
|
||||
// 统计流量
|
||||
self.counter.add(buf.len() as _);
|
||||
let net_packet = NetPacket::new(buf)?;
|
||||
|
||||
let extend = NetPacket::unchecked(extend);
|
||||
if net_packet.ttl() == 0 || net_packet.source_ttl() < net_packet.ttl() {
|
||||
log::warn!("丢弃过时包:{:?} {}", net_packet.head(), route_key.addr);
|
||||
@@ -158,6 +153,10 @@ impl<Call: VntCallback, Device: DeviceWrite> RecvDataHandler<Call, Device> {
|
||||
|| dest.is_unspecified()
|
||||
|| dest == current_device.broadcast_ip
|
||||
{
|
||||
// 统计流量
|
||||
if let Some(down_traffic_meter) = &context.down_traffic_meter {
|
||||
down_traffic_meter.add_traffic(net_packet.source(), net_packet.data_len())
|
||||
}
|
||||
//发给自己的包
|
||||
if net_packet.is_gateway() {
|
||||
//服务端-客户端包
|
||||
|
||||
@@ -24,9 +24,7 @@ use crate::handle::callback::{ErrorInfo, ErrorType, HandshakeInfo, RegisterInfo,
|
||||
use crate::handle::handshaker;
|
||||
use crate::handle::handshaker::Handshake;
|
||||
use crate::handle::recv_data::PacketHandler;
|
||||
use crate::handle::{
|
||||
registrar, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo, GATEWAY_IP,
|
||||
};
|
||||
use crate::handle::{registrar, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo};
|
||||
use crate::nat::NatTest;
|
||||
use crate::proto::message::{DeviceList, HandshakeResponse, RegistrationResponse};
|
||||
use crate::protocol::body::ENCRYPTION_RESERVED;
|
||||
@@ -82,7 +80,11 @@ impl<Call, Device> ServerPacketHandler<Call, Device> {
|
||||
nat_test,
|
||||
callback,
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
up_key_time: Arc::new(AtomicCell::new(Instant::now() - Duration::from_secs(60))),
|
||||
up_key_time: Arc::new(AtomicCell::new(
|
||||
Instant::now()
|
||||
.checked_sub(Duration::from_secs(60))
|
||||
.unwrap_or(Instant::now()),
|
||||
)),
|
||||
external_route,
|
||||
handshake,
|
||||
#[cfg(feature = "integrated_tun")]
|
||||
@@ -100,6 +102,15 @@ impl<Call: VntCallback, Device: DeviceWrite> PacketHandler for ServerPacketHandl
|
||||
context: &ChannelContext,
|
||||
current_device: &CurrentDeviceInfo,
|
||||
) -> anyhow::Result<()> {
|
||||
if !current_device.is_server_addr(route_key.addr) {
|
||||
//拦截不是服务端的流量
|
||||
log::info!(
|
||||
"route_key={:?},不是来源于服务端地址{}",
|
||||
route_key,
|
||||
current_device.connect_server
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
context
|
||||
.route_table
|
||||
.update_read_time(&net_packet.source(), &route_key);
|
||||
@@ -129,7 +140,7 @@ impl<Call: VntCallback, Device: DeviceWrite> PacketHandler for ServerPacketHandl
|
||||
self.config_info.token.clone(),
|
||||
key,
|
||||
)?;
|
||||
context.send_by_key(packet.buffer(), route_key)?;
|
||||
context.send_by_key(&packet, route_key)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,7 +164,7 @@ impl<Call: VntCallback, Device: DeviceWrite> PacketHandler for ServerPacketHandl
|
||||
key,
|
||||
)?;
|
||||
drop(guard);
|
||||
context.send_by_key(packet.buffer(), route_key)?;
|
||||
context.send_by_key(&packet, route_key)?;
|
||||
return Ok(());
|
||||
}
|
||||
log::warn!(
|
||||
@@ -188,7 +199,7 @@ impl<Call: VntCallback, Device: DeviceWrite> PacketHandler for ServerPacketHandl
|
||||
self.config_info.token.clone(),
|
||||
key,
|
||||
)?;
|
||||
context.send_by_key(packet.buffer(), route_key)?;
|
||||
context.send_by_key(&packet, route_key)?;
|
||||
self.rsa_cipher.lock().replace(rsa_cipher);
|
||||
}
|
||||
return Ok(());
|
||||
@@ -473,7 +484,7 @@ impl<Call: VntCallback, Device: DeviceWrite> ServerPacketHandler<Call, Device> {
|
||||
)?;
|
||||
log::info!("发送注册请求,{:?}", self.config_info);
|
||||
//注册请求只发送到默认通道
|
||||
context.send_default(response.buffer(), current_device.connect_server)?;
|
||||
context.send_default(&response, current_device.connect_server)?;
|
||||
Ok(())
|
||||
}
|
||||
fn error(
|
||||
@@ -548,7 +559,7 @@ impl<Call: VntCallback, Device: DeviceWrite> ServerPacketHandler<Call, Device> {
|
||||
//纪元不一致,可能有新客户端连接,向服务端拉取客户端列表
|
||||
let mut poll_device = NetPacket::new_encrypt([0; 12 + ENCRYPTION_RESERVED])?;
|
||||
poll_device.set_source(current_device.virtual_ip);
|
||||
poll_device.set_destination(GATEWAY_IP);
|
||||
poll_device.set_destination(current_device.virtual_gateway);
|
||||
poll_device.set_default_version();
|
||||
poll_device.set_gateway_flag(true);
|
||||
poll_device.first_set_ttl(MAX_TTL);
|
||||
@@ -557,7 +568,7 @@ impl<Call: VntCallback, Device: DeviceWrite> ServerPacketHandler<Call, Device> {
|
||||
.set_transport_protocol(service_packet::Protocol::PullDeviceList.into());
|
||||
self.server_cipher.encrypt_ipv4(&mut poll_device)?;
|
||||
//发送到默认服务端即可
|
||||
context.send_default(poll_device.buffer(), current_device.connect_server)?;
|
||||
context.send_default(&poll_device, current_device.connect_server)?;
|
||||
}
|
||||
}
|
||||
ControlPacket::AddrResponse(addr_packet) => {
|
||||
|
||||
@@ -27,6 +27,10 @@ impl PacketHandler for TurnPacketHandler {
|
||||
// ttl减一
|
||||
let ttl = net_packet.incr_ttl();
|
||||
if ttl > 0 {
|
||||
if net_packet.is_gateway() {
|
||||
// 暂时不转发服务端包
|
||||
return Ok(());
|
||||
}
|
||||
let destination = net_packet.destination();
|
||||
if let Some(route) = context.route_table.route_one(&destination) {
|
||||
if route.addr == route_key.addr {
|
||||
@@ -36,7 +40,7 @@ impl PacketHandler for TurnPacketHandler {
|
||||
}
|
||||
if route.metric <= ttl {
|
||||
return context
|
||||
.send_by_key(net_packet.buffer(), route.route_key())
|
||||
.send_by_key(&net_packet, route.route_key())
|
||||
.context("转发失败");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,28 +18,26 @@ pub(crate) use windows::*;
|
||||
/// 仅仅是停止tun,不停止vnt
|
||||
#[derive(Clone, Default)]
|
||||
pub struct DeviceStop {
|
||||
f: Arc<Mutex<Option<Box<dyn FnOnce() -> bool + Send>>>>,
|
||||
f: Arc<Mutex<Option<Box<dyn FnOnce() + Send>>>>,
|
||||
stopped: Arc<AtomicCell<bool>>,
|
||||
}
|
||||
|
||||
impl DeviceStop {
|
||||
pub fn set_stop_fn<F>(&self, f: F)
|
||||
where
|
||||
F: FnOnce() -> bool + Send + 'static,
|
||||
F: FnOnce() + Send + 'static,
|
||||
{
|
||||
self.f.lock().replace(Box::new(f));
|
||||
}
|
||||
pub fn stop(&self) -> bool {
|
||||
pub fn stop(&self) {
|
||||
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 {
|
||||
pub fn is_stopped(&self) -> bool {
|
||||
self.stopped.load()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,13 +26,8 @@ use crate::protocol;
|
||||
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())
|
||||
}
|
||||
use crate::util::StopManager;
|
||||
|
||||
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())?;
|
||||
@@ -58,7 +53,6 @@ pub fn start(
|
||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
mut up_counter: SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
compressor: Compressor,
|
||||
device_stop: DeviceStop,
|
||||
@@ -76,7 +70,6 @@ pub fn start(
|
||||
ip_proxy_map,
|
||||
client_cipher,
|
||||
server_cipher,
|
||||
&mut up_counter,
|
||||
device_list,
|
||||
compressor,
|
||||
device_stop,
|
||||
@@ -112,10 +105,7 @@ fn broadcast(
|
||||
break;
|
||||
}
|
||||
if let Some(route) = sender.route_table.route_one_p2p(&peer_ip) {
|
||||
if sender
|
||||
.send_by_key(net_packet.buffer(), route.route_key())
|
||||
.is_ok()
|
||||
{
|
||||
if sender.send_by_key(&net_packet, route.route_key()).is_ok() {
|
||||
p2p_ips.push(peer_ip);
|
||||
continue;
|
||||
}
|
||||
@@ -130,7 +120,7 @@ fn broadcast(
|
||||
if p2p_ips.is_empty() {
|
||||
//都没有p2p则直接由服务器转发
|
||||
if current_device.status.online() {
|
||||
sender.send_default(net_packet.buffer(), current_device.connect_server)?;
|
||||
sender.send_default(&net_packet, current_device.connect_server)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
@@ -140,7 +130,7 @@ fn broadcast(
|
||||
//非直连的广播要改变目的地址,不然服务端收到了会再次广播
|
||||
net_packet.set_destination(peer_ip);
|
||||
sender.send_ipv4_by_id(
|
||||
net_packet.buffer(),
|
||||
&net_packet,
|
||||
&peer_ip,
|
||||
current_device.connect_server,
|
||||
current_device.status.online(),
|
||||
@@ -168,7 +158,7 @@ fn broadcast(
|
||||
broadcast.set_address(&p2p_ips)?;
|
||||
broadcast.set_data(net_packet.buffer())?;
|
||||
server_cipher.encrypt_ipv4(&mut server_packet)?;
|
||||
sender.send_default(server_packet.buffer(), current_device.connect_server)?;
|
||||
sender.send_default(&server_packet, current_device.connect_server)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -216,17 +206,13 @@ pub(crate) fn handle(
|
||||
if protocol == Protocol::Icmp {
|
||||
net_packet.set_gateway_flag(true);
|
||||
server_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
context.send_default(net_packet.buffer(), current_device.connect_server)?;
|
||||
context.send_default(&net_packet, current_device.connect_server)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
if !dest_ip.is_multicast() && !dest_ip.is_broadcast() && current_device.broadcast_ip != dest_ip
|
||||
{
|
||||
if !check_dest(
|
||||
dest_ip,
|
||||
current_device.virtual_netmask,
|
||||
current_device.virtual_network,
|
||||
) {
|
||||
if current_device.not_in_network(dest_ip) {
|
||||
if let Some(r_dest_ip) = ip_route.route(&dest_ip) {
|
||||
//路由的目标不能是自己
|
||||
if r_dest_ip == src_ip {
|
||||
@@ -278,7 +264,7 @@ pub(crate) fn handle(
|
||||
|
||||
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||
context.send_ipv4_by_id(
|
||||
net_packet.buffer(),
|
||||
&net_packet,
|
||||
&dest_ip,
|
||||
current_device.connect_server,
|
||||
current_device.status.online(),
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::handle::tun_tap::DeviceStop;
|
||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::util::{SingleU64Adder, StopManager};
|
||||
use crate::util::StopManager;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use mio::event::Source;
|
||||
use mio::unix::SourceFd;
|
||||
@@ -30,41 +30,27 @@ pub(crate) fn start_simple(
|
||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
up_counter: &mut SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
compressor: Compressor,
|
||||
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 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);
|
||||
}
|
||||
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
|
||||
}
|
||||
});
|
||||
}
|
||||
let worker_cell = Arc::new(AtomicCell::new(Some(worker)));
|
||||
let _worker_cell = worker_cell.clone();
|
||||
device_stop.set_stop_fn(move || {
|
||||
if let Some(worker) = _worker_cell.take() {
|
||||
worker.stop_self()
|
||||
}
|
||||
});
|
||||
if let Err(e) = start_simple0(
|
||||
poll,
|
||||
context,
|
||||
@@ -75,14 +61,13 @@ pub(crate) fn start_simple(
|
||||
ip_proxy_map,
|
||||
client_cipher,
|
||||
server_cipher,
|
||||
up_counter,
|
||||
device_list,
|
||||
compressor,
|
||||
) {
|
||||
log::error!("{:?}", e);
|
||||
};
|
||||
device_stop.stopped();
|
||||
if stop_all.load() {
|
||||
if let Some(worker) = worker_cell.take() {
|
||||
worker.stop_all();
|
||||
}
|
||||
drop(_waker);
|
||||
@@ -98,7 +83,6 @@ fn start_simple0(
|
||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
up_counter: &mut SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
compressor: Compressor,
|
||||
) -> anyhow::Result<()> {
|
||||
@@ -121,18 +105,21 @@ fn start_simple0(
|
||||
if event.token() == STOP {
|
||||
return Ok(());
|
||||
}
|
||||
let mut retries = 0;
|
||||
loop {
|
||||
let len = match fd.read(&mut buf[start..]) {
|
||||
Ok(len) => len + start,
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::WouldBlock {
|
||||
retries += 1;
|
||||
if retries < 8 {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Err(e)?
|
||||
}
|
||||
};
|
||||
//单线程的
|
||||
up_counter.add(len as u64);
|
||||
// buf是重复利用的,需要重置头部
|
||||
buf[..12].fill(0);
|
||||
match crate::handle::tun_tap::tun_handler::handle(
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::handle::tun_tap::DeviceStop;
|
||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
use crate::ip_proxy::IpProxyMap;
|
||||
use crate::util::{SingleU64Adder, StopManager};
|
||||
use crate::util::StopManager;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
@@ -23,35 +23,25 @@ pub(crate) fn start_simple(
|
||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
up_counter: &mut SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
compressor: Compressor,
|
||||
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_cell = device_cell.clone();
|
||||
let device = device.clone();
|
||||
stop_manager.add_listener("tun_device".into(), move || {
|
||||
if let Some(device) = device_cell.take() {
|
||||
if let Err(e) = device.shutdown() {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
if let Err(e) = device.shutdown() {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
})?
|
||||
};
|
||||
let worker_cell = Arc::new(AtomicCell::new(Some(worker)));
|
||||
|
||||
{
|
||||
let stop_all = stop_all.clone();
|
||||
let worker_cell = worker_cell.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 Some(worker) = worker_cell.take() {
|
||||
worker.stop_self()
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -64,14 +54,13 @@ pub(crate) fn start_simple(
|
||||
ip_proxy_map,
|
||||
client_cipher,
|
||||
server_cipher,
|
||||
up_counter,
|
||||
device_list,
|
||||
compressor,
|
||||
) {
|
||||
log::error!("{:?}", e);
|
||||
}
|
||||
device_stop.stopped();
|
||||
if stop_all.load() {
|
||||
if let Some(worker) = worker_cell.take() {
|
||||
worker.stop_all();
|
||||
}
|
||||
Ok(())
|
||||
@@ -85,7 +74,6 @@ fn start_simple0(
|
||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
up_counter: &mut SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
compressor: Compressor,
|
||||
) -> anyhow::Result<()> {
|
||||
@@ -94,7 +82,6 @@ fn start_simple0(
|
||||
loop {
|
||||
let len = device.read(&mut buf[12..])? + 12;
|
||||
//单线程的
|
||||
up_counter.add(len as u64);
|
||||
// buf是重复利用的,需要重置头部
|
||||
buf[..12].fill(0);
|
||||
match crate::handle::tun_tap::tun_handler::handle(
|
||||
|
||||
@@ -155,7 +155,7 @@ fn recv_handle(
|
||||
return;
|
||||
}
|
||||
if let Err(e) = context.send_ipv4_by_id(
|
||||
net_packet.buffer(),
|
||||
&net_packet,
|
||||
&dest_ip,
|
||||
current_device.connect_server,
|
||||
current_device.status.online(),
|
||||
|
||||
+86
-14
@@ -2,16 +2,18 @@ use anyhow::Context;
|
||||
use std::io;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
|
||||
use std::net::{SocketAddr, UdpSocket};
|
||||
use std::ops::Sub;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use rand::prelude::SliceRandom;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::channel::punch::{NatInfo, NatType};
|
||||
use crate::proto::message::PunchNatType;
|
||||
#[cfg(feature = "upnp")]
|
||||
use crate::util::UPnP;
|
||||
|
||||
mod stun;
|
||||
|
||||
@@ -47,12 +49,62 @@ pub fn local_ipv6_() -> io::Result<Ipv6Addr> {
|
||||
|
||||
pub fn local_ipv6() -> Option<Ipv6Addr> {
|
||||
match local_ipv6_() {
|
||||
Ok(ipv6) => Some(ipv6),
|
||||
Ok(ipv6) => {
|
||||
if is_ipv6_global(&ipv6) {
|
||||
return Some(ipv6);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("获取ipv6失败:{:?}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub const fn is_ipv4_global(ipv4: &Ipv4Addr) -> bool {
|
||||
!(ipv4.octets()[0] == 0 // "This network"
|
||||
|| ipv4.is_private()
|
||||
|| ipv4.octets()[0] == 100 && (ipv4.octets()[1] & 0b1100_0000 == 0b0100_0000)//ipv4.is_shared()
|
||||
|| ipv4.is_loopback()
|
||||
|| ipv4.is_link_local()
|
||||
// addresses reserved for future protocols (`192.0.0.0/24`)
|
||||
// .9 and .10 are documented as globally reachable so they're excluded
|
||||
|| (
|
||||
ipv4.octets()[0] == 192 && ipv4.octets()[1] == 0 && ipv4.octets()[2] == 0
|
||||
&& ipv4.octets()[3] != 9 && ipv4.octets()[3] != 10
|
||||
)
|
||||
|| ipv4.is_documentation()
|
||||
|| ipv4.octets()[0] == 198 && (ipv4.octets()[1] & 0xfe) == 18//ipv4.is_benchmarking()
|
||||
|| ipv4.octets()[0] & 240 == 240 && !ipv4.is_broadcast()//ipv4.is_reserved()
|
||||
|| ipv4.is_broadcast())
|
||||
}
|
||||
|
||||
pub const fn is_ipv6_global(ipv6addr: &Ipv6Addr) -> bool {
|
||||
!(ipv6addr.is_unspecified()
|
||||
|| ipv6addr.is_loopback()
|
||||
// IPv4-mapped Address (`::ffff:0:0/96`)
|
||||
|| matches!(ipv6addr.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
|
||||
// IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
|
||||
|| matches!(ipv6addr.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
|
||||
// Discard-Only Address Block (`100::/64`)
|
||||
|| matches!(ipv6addr.segments(), [0x100, 0, 0, 0, _, _, _, _])
|
||||
// IETF Protocol Assignments (`2001::/23`)
|
||||
|| (matches!(ipv6addr.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
|
||||
&& !(
|
||||
// Port Control Protocol Anycast (`2001:1::1`)
|
||||
u128::from_be_bytes(ipv6addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
|
||||
// Traversal Using Relays around NAT Anycast (`2001:1::2`)
|
||||
|| u128::from_be_bytes(ipv6addr.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
|
||||
// AMT (`2001:3::/32`)
|
||||
|| matches!(ipv6addr.segments(), [0x2001, 3, _, _, _, _, _, _])
|
||||
// AS112-v6 (`2001:4:112::/48`)
|
||||
|| matches!(ipv6addr.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
|
||||
// ORCHIDv2 (`2001:20::/28`)
|
||||
|| matches!(ipv6addr.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
|
||||
))
|
||||
|| (ipv6addr.segments()[0] == 0x2001) && (ipv6addr.segments()[1] == 0xdb8)//ipv6addr.is_documentation()
|
||||
|| (ipv6addr.segments()[0] & 0xfe00) == 0xfc00//ipv6addr.is_unique_local()
|
||||
|| (ipv6addr.segments()[0] & 0xffc0) == 0xfe80) //ipv6addr.is_unicast_link_local())
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -62,6 +114,8 @@ pub struct NatTest {
|
||||
time: Arc<AtomicCell<Instant>>,
|
||||
udp_ports: Vec<u16>,
|
||||
tcp_port: u16,
|
||||
#[cfg(feature = "upnp")]
|
||||
upnp: UPnP,
|
||||
}
|
||||
|
||||
impl From<NatType> for PunchNatType {
|
||||
@@ -92,7 +146,9 @@ impl NatTest {
|
||||
tcp_port: u16,
|
||||
) -> NatTest {
|
||||
if stun_server.len() > 5 {
|
||||
stun_server.shuffle(&mut rand::thread_rng());
|
||||
stun_server.truncate(5);
|
||||
log::info!("stun_server truncate {:?}", stun_server);
|
||||
}
|
||||
let ports = vec![0; udp_ports.len()];
|
||||
let nat_info = NatInfo::new(
|
||||
@@ -106,14 +162,27 @@ impl NatTest {
|
||||
NatType::Cone,
|
||||
);
|
||||
let info = Arc::new(Mutex::new(nat_info));
|
||||
#[cfg(feature = "upnp")]
|
||||
let upnp = UPnP::default();
|
||||
#[cfg(feature = "upnp")]
|
||||
for port in &udp_ports {
|
||||
upnp.add_udp_port(*port);
|
||||
}
|
||||
#[cfg(feature = "upnp")]
|
||||
upnp.add_tcp_port(tcp_port);
|
||||
let instant = Instant::now();
|
||||
NatTest {
|
||||
stun_server,
|
||||
info,
|
||||
time: Arc::new(AtomicCell::new(
|
||||
Instant::now().sub(Duration::from_secs(100)),
|
||||
instant
|
||||
.checked_sub(Duration::from_secs(100))
|
||||
.unwrap_or(instant),
|
||||
)),
|
||||
udp_ports,
|
||||
tcp_port,
|
||||
#[cfg(feature = "upnp")]
|
||||
upnp,
|
||||
}
|
||||
}
|
||||
pub fn can_update(&self) -> bool {
|
||||
@@ -185,7 +254,7 @@ impl NatTest {
|
||||
}
|
||||
false
|
||||
}
|
||||
pub fn update_addr(&self, index: usize, ip: Ipv4Addr, port: u16) {
|
||||
pub fn update_addr(&self, index: usize, ip: Ipv4Addr, port: u16) -> bool {
|
||||
let mut guard = self.info.lock();
|
||||
guard.update_addr(index, ip, port)
|
||||
}
|
||||
@@ -204,6 +273,13 @@ impl NatTest {
|
||||
|
||||
Ok(guard.clone())
|
||||
}
|
||||
#[cfg(feature = "upnp")]
|
||||
pub fn reset_upnp(&self) {
|
||||
let local_ipv4 = self.info.lock().local_ipv4.clone();
|
||||
if let Some(local_ipv4) = local_ipv4 {
|
||||
self.upnp.reset(local_ipv4)
|
||||
}
|
||||
}
|
||||
pub fn send_data(&self) -> anyhow::Result<(Vec<u8>, SocketAddr)> {
|
||||
let len = self.stun_server.len();
|
||||
let stun_server = if len == 1 {
|
||||
@@ -246,7 +322,7 @@ impl NatTest {
|
||||
let source_ip = match source_addr.ip() {
|
||||
IpAddr::V4(ip) => ip,
|
||||
IpAddr::V6(ip) => {
|
||||
if let Some(ip) = ip.to_ipv4_mapped() {
|
||||
if let Some(ip) = ip.to_ipv4() {
|
||||
ip
|
||||
} else {
|
||||
return Ok(());
|
||||
@@ -266,14 +342,10 @@ impl NatTest {
|
||||
}
|
||||
}
|
||||
if !check_fail {
|
||||
let ip = addr.ip();
|
||||
if !ip.is_multicast()
|
||||
&& !ip.is_broadcast()
|
||||
&& !ip.is_unspecified()
|
||||
&& !ip.is_loopback()
|
||||
&& !ip.is_private()
|
||||
{
|
||||
self.update_addr(index, *addr.ip(), addr.port());
|
||||
if is_ipv4_global(addr.ip()) {
|
||||
if self.update_addr(index, *addr.ip(), addr.port()) {
|
||||
log::info!("回应地址{:?},来源stun {:?}", addr, source_addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-11
@@ -9,17 +9,12 @@ use std::net::UdpSocket;
|
||||
use stun_format::Attr;
|
||||
|
||||
pub fn stun_test_nat(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
||||
let mut th = Vec::new();
|
||||
for _ in 0..2 {
|
||||
let stun_servers = stun_servers.clone();
|
||||
let handle = std::thread::spawn(move || stun_test_nat0(stun_servers));
|
||||
th.push(handle);
|
||||
}
|
||||
let mut nat_type = NatType::Cone;
|
||||
let mut port_range = 0;
|
||||
let mut hash_set = HashSet::new();
|
||||
for x in th {
|
||||
match x.join().unwrap() {
|
||||
for _ in 0..2 {
|
||||
let stun_servers = stun_servers.clone();
|
||||
match stun_test_nat0(stun_servers) {
|
||||
Ok((nat_type_t, ip_list_t, port_range_t)) => {
|
||||
if nat_type_t == NatType::Symmetric {
|
||||
nat_type = NatType::Symmetric;
|
||||
@@ -86,13 +81,13 @@ fn test_nat(udp: &UdpSocket, stun_server: &String) -> io::Result<HashSet<SocketA
|
||||
udp.connect(stun_server)?;
|
||||
let tid = rand::thread_rng().next_u64() as u128;
|
||||
let mut addr = HashSet::new();
|
||||
let (mapped_addr1, changed_addr1) = test_nat_(&udp, true, true, tid)?;
|
||||
let (mapped_addr1, changed_addr1) = test_nat_(&udp, stun_server, true, true, tid)?;
|
||||
if mapped_addr1.is_ipv4() {
|
||||
addr.insert(mapped_addr1);
|
||||
}
|
||||
if let Some(changed_addr1) = changed_addr1 {
|
||||
if udp.connect(changed_addr1).is_ok() {
|
||||
match test_nat_(&udp, false, false, tid + 1) {
|
||||
match test_nat_(&udp, stun_server, false, false, tid + 1) {
|
||||
Ok((mapped_addr2, _)) => {
|
||||
if mapped_addr2.is_ipv4() {
|
||||
addr.insert(mapped_addr1);
|
||||
@@ -116,6 +111,7 @@ fn test_nat(udp: &UdpSocket, stun_server: &String) -> io::Result<HashSet<SocketA
|
||||
|
||||
fn test_nat_(
|
||||
udp: &UdpSocket,
|
||||
stun_server: &String,
|
||||
change_ip: bool,
|
||||
change_port: bool,
|
||||
tid: u128,
|
||||
@@ -134,7 +130,7 @@ fn test_nat_(
|
||||
let (len, _addr) = match udp.recv_from(&mut buf) {
|
||||
Ok(rs) => rs,
|
||||
Err(e) => {
|
||||
log::warn!("stun error {:?}", e);
|
||||
log::warn!("stun {} error {:?}", stun_server, e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -128,11 +128,10 @@ impl<B: AsRef<[u8]>> NetPacket<B> {
|
||||
"length overflow",
|
||||
));
|
||||
}
|
||||
// 不能大于udp最大载荷长度
|
||||
if data_len < 12 || data_len > 65535 - 20 - 8 {
|
||||
if data_len < 12 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"length overflow",
|
||||
"data_len too short",
|
||||
));
|
||||
}
|
||||
Ok(NetPacket { data_len, buffer })
|
||||
@@ -215,8 +214,7 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
|
||||
}
|
||||
pub fn set_gateway_flag(&mut self, is_gateway: bool) {
|
||||
if is_gateway {
|
||||
// 后面的版本再改为0x40,改了之后不兼容1.2.5之前的版本
|
||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x50
|
||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x40
|
||||
} else {
|
||||
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xBF
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ 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};
|
||||
use crate::util::StopManager;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Default)]
|
||||
@@ -67,7 +67,6 @@ struct TunDeviceHelperInner {
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
up_counter: SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
compressor: Compressor,
|
||||
}
|
||||
@@ -81,7 +80,6 @@ impl TunDeviceHelper {
|
||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
up_counter: SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
compressor: Compressor,
|
||||
device_adapter: DeviceAdapter,
|
||||
@@ -95,7 +93,6 @@ impl TunDeviceHelper {
|
||||
ip_proxy_map,
|
||||
client_cipher,
|
||||
server_cipher,
|
||||
up_counter,
|
||||
device_list,
|
||||
compressor,
|
||||
};
|
||||
@@ -113,7 +110,7 @@ impl TunDeviceHelper {
|
||||
device_stop.stop();
|
||||
std::thread::sleep(std::time::Duration::from_millis(300));
|
||||
//确保停止了
|
||||
if device_stop.is_stop() {
|
||||
if device_stop.is_stopped() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -136,7 +133,6 @@ impl TunDeviceHelper {
|
||||
inner.ip_proxy_map,
|
||||
inner.client_cipher,
|
||||
inner.server_cipher,
|
||||
inner.up_counter,
|
||||
inner.device_list,
|
||||
inner.compressor,
|
||||
device_stop,
|
||||
|
||||
@@ -1,139 +1,33 @@
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// 不安全的并发计数器,谨慎使用
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct U64Adder {
|
||||
global_index: Arc<AtomicUsize>,
|
||||
inner: Arc<U64AdderInner>,
|
||||
index: usize,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct SingleU64Adder {
|
||||
inner: Arc<SingleU64AdderInner>,
|
||||
}
|
||||
impl SingleU64Adder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: Arc::new(SingleU64AdderInner::new()),
|
||||
}
|
||||
}
|
||||
pub fn add(&mut self, num: u64) {
|
||||
self.inner.add(num);
|
||||
}
|
||||
pub fn get(&self) -> u64 {
|
||||
self.inner.get()
|
||||
}
|
||||
pub fn watch(&self) -> WatchSingleU64Adder {
|
||||
WatchSingleU64Adder {
|
||||
inner: self.inner.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SingleU64AdderInner {
|
||||
ptr: *mut u64,
|
||||
}
|
||||
|
||||
impl SingleU64AdderInner {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
ptr: Box::into_raw(Box::new(0)),
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn add(&self, num: u64) {
|
||||
unsafe { *self.ptr += num }
|
||||
}
|
||||
|
||||
fn get(&self) -> u64 {
|
||||
unsafe { *self.ptr }
|
||||
}
|
||||
}
|
||||
impl Drop for SingleU64AdderInner {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let _ = Box::from_raw(self.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for SingleU64AdderInner {}
|
||||
|
||||
unsafe impl Sync for SingleU64AdderInner {}
|
||||
|
||||
struct U64AdderInner {
|
||||
base: Vec<SingleU64AdderInner>,
|
||||
}
|
||||
|
||||
impl U64AdderInner {
|
||||
pub fn get(&self) -> u64 {
|
||||
let mut count = 0;
|
||||
for counter in self.base.iter() {
|
||||
count += counter.get()
|
||||
}
|
||||
count
|
||||
}
|
||||
count: Arc<AtomicCell<u64>>,
|
||||
}
|
||||
|
||||
impl U64Adder {
|
||||
/// 计数槽容量
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
let mut base = Vec::with_capacity(capacity);
|
||||
for _ in 0..capacity {
|
||||
base.push(SingleU64AdderInner::new())
|
||||
}
|
||||
let inner = Arc::new(U64AdderInner { base });
|
||||
U64Adder {
|
||||
global_index: Arc::new(AtomicUsize::new(1)),
|
||||
inner,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
pub fn add(&mut self, num: u64) {
|
||||
self.inner.base[self.index].add(num);
|
||||
pub fn add(&self, num: u64) {
|
||||
self.count.fetch_add(num);
|
||||
}
|
||||
pub fn get(&self) -> u64 {
|
||||
self.inner.get()
|
||||
self.count.load()
|
||||
}
|
||||
pub fn watch(&self) -> WatchU64Adder {
|
||||
WatchU64Adder {
|
||||
inner: self.inner.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for U64Adder {
|
||||
fn clone(&self) -> Self {
|
||||
let index = self.global_index.fetch_add(1, Ordering::AcqRel);
|
||||
if index > self.inner.base.len() {
|
||||
panic!()
|
||||
}
|
||||
|
||||
Self {
|
||||
global_index: self.global_index.clone(),
|
||||
inner: self.inner.clone(),
|
||||
index,
|
||||
count: self.count.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WatchU64Adder {
|
||||
inner: Arc<U64AdderInner>,
|
||||
count: Arc<AtomicCell<u64>>,
|
||||
}
|
||||
|
||||
impl WatchU64Adder {
|
||||
pub fn get(&self) -> u64 {
|
||||
self.inner.get()
|
||||
}
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct WatchSingleU64Adder {
|
||||
inner: Arc<SingleU64AdderInner>,
|
||||
}
|
||||
impl WatchSingleU64Adder {
|
||||
pub fn get(&self) -> u64 {
|
||||
self.inner.get()
|
||||
self.count.load()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
mod rate_limiter;
|
||||
pub use rate_limiter::*;
|
||||
|
||||
mod traffic_meter;
|
||||
pub use traffic_meter::*;
|
||||
@@ -0,0 +1,62 @@
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ConcurrentRateLimiter {
|
||||
inner: Arc<Mutex<RateLimiter>>,
|
||||
}
|
||||
|
||||
impl ConcurrentRateLimiter {
|
||||
pub fn new(capacity: usize, refill_rate: usize) -> Self {
|
||||
let inner = RateLimiter::new(capacity, refill_rate);
|
||||
Self {
|
||||
inner: Arc::new(Mutex::new(inner)),
|
||||
}
|
||||
}
|
||||
pub fn try_acquire(&self) -> bool {
|
||||
self.inner.lock().try_acquire()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RateLimiter {
|
||||
capacity: usize,
|
||||
tokens: usize,
|
||||
refill_rate: usize,
|
||||
last_refill: Instant,
|
||||
}
|
||||
|
||||
impl RateLimiter {
|
||||
// 初始化限流器
|
||||
pub fn new(capacity: usize, refill_rate: usize) -> Self {
|
||||
Self {
|
||||
capacity,
|
||||
tokens: capacity,
|
||||
refill_rate,
|
||||
last_refill: Instant::now(),
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试获取一个令牌
|
||||
pub fn try_acquire(&mut self) -> bool {
|
||||
self.refill();
|
||||
if self.tokens > 0 {
|
||||
self.tokens -= 1;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// 补充令牌
|
||||
fn refill(&mut self) {
|
||||
let now = Instant::now();
|
||||
let elapsed = now.duration_since(self.last_refill).as_secs() as usize;
|
||||
let new_tokens = elapsed * self.refill_rate;
|
||||
|
||||
if new_tokens > 0 {
|
||||
self.tokens = std::cmp::min(self.capacity, self.tokens + new_tokens);
|
||||
self.last_refill = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
use parking_lot::Mutex;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TrafficMeterMultiAddress {
|
||||
history_capacity: usize,
|
||||
inner: Arc<Mutex<(u64, HashMap<Ipv4Addr, TrafficMeter>)>>,
|
||||
}
|
||||
|
||||
impl Default for TrafficMeterMultiAddress {
|
||||
fn default() -> Self {
|
||||
TrafficMeterMultiAddress::new(100)
|
||||
}
|
||||
}
|
||||
|
||||
impl TrafficMeterMultiAddress {
|
||||
pub fn new(history_capacity: usize) -> Self {
|
||||
let inner = Arc::new(Mutex::new((0, HashMap::new())));
|
||||
Self {
|
||||
inner,
|
||||
history_capacity,
|
||||
}
|
||||
}
|
||||
pub fn add_traffic(&self, ip: Ipv4Addr, amount: usize) {
|
||||
let mut guard = self.inner.lock();
|
||||
guard.0 += amount as u64;
|
||||
guard
|
||||
.1
|
||||
.entry(ip)
|
||||
.or_insert(TrafficMeter::new(self.history_capacity))
|
||||
.add_traffic(amount)
|
||||
}
|
||||
pub fn total(&self) -> u64 {
|
||||
self.inner.lock().0
|
||||
}
|
||||
pub fn get_all(&self) -> (u64, HashMap<Ipv4Addr, u64>) {
|
||||
let guard = self.inner.lock();
|
||||
(
|
||||
guard.0,
|
||||
guard.1.iter().map(|(ip, t)| (*ip, t.total())).collect(),
|
||||
)
|
||||
}
|
||||
pub fn get_all_history(&self) -> (u64, HashMap<Ipv4Addr, (u64, Vec<usize>)>) {
|
||||
let guard = self.inner.lock();
|
||||
(
|
||||
guard.0,
|
||||
guard
|
||||
.1
|
||||
.iter()
|
||||
.map(|(ip, t)| (*ip, (t.total(), t.get_history())))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
pub fn get_history(&self, ip: &Ipv4Addr) -> Option<(u64, Vec<usize>)> {
|
||||
self.inner
|
||||
.lock()
|
||||
.1
|
||||
.get(ip)
|
||||
.map(|t| (t.total(), t.get_history()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ConcurrentTrafficMeter {
|
||||
inner: Arc<Mutex<TrafficMeter>>,
|
||||
}
|
||||
|
||||
impl ConcurrentTrafficMeter {
|
||||
pub fn new(history_capacity: usize) -> Self {
|
||||
let inner = Arc::new(Mutex::new(TrafficMeter::new(history_capacity)));
|
||||
Self { inner }
|
||||
}
|
||||
pub fn add_traffic(&self, amount: usize) {
|
||||
self.inner.lock().add_traffic(amount)
|
||||
}
|
||||
pub fn get_history(&self) -> Vec<usize> {
|
||||
self.inner.lock().get_history()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TrafficMeter {
|
||||
start_time: Instant,
|
||||
total: u64,
|
||||
count: usize,
|
||||
history_capacity: usize,
|
||||
history: VecDeque<usize>,
|
||||
}
|
||||
|
||||
impl TrafficMeter {
|
||||
// 初始化一个新的 TrafficMeter
|
||||
pub fn new(history_capacity: usize) -> Self {
|
||||
Self {
|
||||
start_time: Instant::now(),
|
||||
total: 0,
|
||||
count: 0,
|
||||
history: VecDeque::with_capacity(history_capacity),
|
||||
history_capacity,
|
||||
}
|
||||
}
|
||||
|
||||
// 增加流量计数
|
||||
pub fn add_traffic(&mut self, amount: usize) {
|
||||
self.total += amount as u64;
|
||||
self.count += amount;
|
||||
self.check_time();
|
||||
}
|
||||
|
||||
// 检查时间是否超过一秒,如果是,记录流量并重置计数器和时间
|
||||
fn check_time(&mut self) {
|
||||
if self.start_time.elapsed() >= Duration::new(1, 0) {
|
||||
// 将当前计数添加到历史记录
|
||||
if self.history.len() >= self.history_capacity {
|
||||
self.history.pop_front(); // 保持历史记录不超过capacity
|
||||
}
|
||||
self.history.push_back(self.count);
|
||||
|
||||
// 重置计数器和时间
|
||||
self.count = 0;
|
||||
self.start_time = Instant::now();
|
||||
}
|
||||
}
|
||||
pub fn total(&self) -> u64 {
|
||||
self.total
|
||||
}
|
||||
// 获取流量记录
|
||||
pub fn get_history(&self) -> Vec<usize> {
|
||||
self.history.iter().cloned().collect()
|
||||
}
|
||||
}
|
||||
+9
-2
@@ -3,8 +3,15 @@ mod scheduler;
|
||||
pub use notify::{StopManager, Worker};
|
||||
pub use scheduler::Scheduler;
|
||||
|
||||
mod counter;
|
||||
pub use counter::*;
|
||||
// mod counter;
|
||||
// pub use counter::*;
|
||||
|
||||
mod dns_query;
|
||||
pub use dns_query::*;
|
||||
|
||||
#[cfg(feature = "upnp")]
|
||||
mod upnp;
|
||||
#[cfg(feature = "upnp")]
|
||||
pub use upnp::*;
|
||||
|
||||
pub mod limit;
|
||||
|
||||
+26
-9
@@ -28,7 +28,7 @@ impl StopManager {
|
||||
self.inner.add_listener(name, f)
|
||||
}
|
||||
pub fn stop(&self) {
|
||||
self.inner.stop("");
|
||||
self.inner.stop();
|
||||
}
|
||||
pub fn wait(&self) {
|
||||
self.inner.wait();
|
||||
@@ -36,8 +36,8 @@ impl StopManager {
|
||||
pub fn wait_timeout(&self, dur: Duration) -> bool {
|
||||
self.inner.wait_timeout(dur)
|
||||
}
|
||||
pub fn is_stop(&self) -> bool {
|
||||
self.inner.state.load(Ordering::Acquire)
|
||||
pub fn is_stopped(&self) -> bool {
|
||||
self.inner.is_stopped()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,17 +81,17 @@ impl StopManagerInner {
|
||||
guard.1.push((name.clone(), Box::new(f)));
|
||||
Ok(Worker::new(name, self.clone()))
|
||||
}
|
||||
fn stop(&self, skip_name: &str) {
|
||||
fn stop(&self) {
|
||||
self.state.store(true, Ordering::Release);
|
||||
let mut guard = self.listeners.lock();
|
||||
guard.0 = true;
|
||||
for (name, listener) in guard.1.drain(..) {
|
||||
if &name == skip_name {
|
||||
continue;
|
||||
}
|
||||
for (_name, listener) in guard.1.drain(..) {
|
||||
listener();
|
||||
}
|
||||
}
|
||||
pub fn is_stopped(&self) -> bool {
|
||||
self.worker_num.load(Ordering::Acquire) == 0
|
||||
}
|
||||
fn wait(&self) {
|
||||
{
|
||||
let mut guard = self.park_threads.lock();
|
||||
@@ -118,6 +118,7 @@ impl StopManagerInner {
|
||||
self.worker_num.load(Ordering::Acquire) == 0
|
||||
}
|
||||
fn stop_call(&self) {
|
||||
self.stop();
|
||||
if let Some(call) = self.stop_call.lock().take() {
|
||||
call();
|
||||
}
|
||||
@@ -136,6 +137,19 @@ impl Worker {
|
||||
}
|
||||
fn release0(&self) {
|
||||
let inner = &self.inner;
|
||||
let worker_name = &self.name;
|
||||
{
|
||||
let mut mutex_guard = inner.listeners.lock();
|
||||
if let Some(pos) = mutex_guard
|
||||
.1
|
||||
.iter()
|
||||
.position(|(name, _)| name == worker_name)
|
||||
{
|
||||
let (_, listener) = mutex_guard.1.remove(pos);
|
||||
listener();
|
||||
}
|
||||
}
|
||||
|
||||
let count = inner.worker_num.fetch_sub(1, Ordering::AcqRel);
|
||||
if count == 1 {
|
||||
for x in inner.park_threads.lock().drain(..) {
|
||||
@@ -145,7 +159,10 @@ impl Worker {
|
||||
}
|
||||
}
|
||||
pub fn stop_all(self) {
|
||||
self.inner.stop(&self.name)
|
||||
self.inner.stop()
|
||||
}
|
||||
pub fn stop_self(self) {
|
||||
drop(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::util::StopManager;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use std::collections::BinaryHeap;
|
||||
use std::sync::mpsc::TrySendError;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
sync::mpsc::{sync_channel, Receiver, SyncSender},
|
||||
@@ -10,45 +13,62 @@ struct DelayedTask {
|
||||
f: Box<dyn FnOnce(&Scheduler) + Send>,
|
||||
next: Instant,
|
||||
}
|
||||
|
||||
impl Eq for DelayedTask {}
|
||||
|
||||
impl PartialEq for DelayedTask {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.next.eq(&other.next)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for DelayedTask {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.next.partial_cmp(&other.next).map(|ord| ord.reverse())
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for DelayedTask {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.next.cmp(&other.next).reverse()
|
||||
}
|
||||
}
|
||||
|
||||
enum Op {
|
||||
Task(DelayedTask),
|
||||
Stop,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Scheduler {
|
||||
sender: SyncSender<Op>,
|
||||
state: Arc<AtomicCell<SchedulerState>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
enum SchedulerState {
|
||||
Running,
|
||||
ShutdownNow, // 立即停止任务执行,队列中剩余的任务不再执行
|
||||
_Shutdown, //执行完队列中剩余的任务再停止
|
||||
}
|
||||
|
||||
impl Scheduler {
|
||||
pub fn new(stop_manager: StopManager) -> anyhow::Result<Self> {
|
||||
let (sender, receiver) = sync_channel::<Op>(32);
|
||||
let s = Self { sender };
|
||||
let state = Arc::new(AtomicCell::new(SchedulerState::Running));
|
||||
let s = Self { sender, state };
|
||||
let s_inner = s.clone();
|
||||
let worker = {
|
||||
let scheduler = s.clone();
|
||||
stop_manager.add_listener("Scheduler".into(), move || {
|
||||
scheduler.shutdown();
|
||||
scheduler.shutdown_now();
|
||||
})?
|
||||
};
|
||||
std::thread::Builder::new()
|
||||
.name("Scheduler".into())
|
||||
.spawn(move || {
|
||||
run(receiver, s_inner);
|
||||
run(receiver, &s_inner);
|
||||
s_inner.shutdown_now();
|
||||
worker.stop_all();
|
||||
})
|
||||
.expect("Scheduler");
|
||||
@@ -58,20 +78,44 @@ impl Scheduler {
|
||||
where
|
||||
F: FnOnce(&Scheduler) + Send + 'static,
|
||||
{
|
||||
if self.state.load() != SchedulerState::Running {
|
||||
log::error!("定时任务执行停止");
|
||||
return false;
|
||||
}
|
||||
let task = DelayedTask {
|
||||
f: Box::new(f),
|
||||
next: Instant::now().checked_add(time).unwrap(),
|
||||
};
|
||||
self.sender.send(Op::Task(task)).is_ok()
|
||||
// 如果是任务中调用此方法,那这里用send可能会导致整个定时任务阻塞
|
||||
// 任务总数不能大于或等于通道长度,所以改成try_send快速失败
|
||||
match self.sender.try_send(Op::Task(task)) {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
match e {
|
||||
TrySendError::Full(_) => {
|
||||
log::error!("定时任务队列达到上限");
|
||||
}
|
||||
TrySendError::Disconnected(_) => {
|
||||
log::error!("定时任务执行停止 通道关闭");
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn shutdown(self) {
|
||||
pub fn shutdown_now(&self) {
|
||||
self.state.store(SchedulerState::ShutdownNow);
|
||||
let _ = self.sender.send(Op::Stop);
|
||||
}
|
||||
}
|
||||
fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
|
||||
|
||||
fn run(receiver: Receiver<Op>, s_inner: &Scheduler) {
|
||||
let mut binary_heap = BinaryHeap::<DelayedTask>::with_capacity(32);
|
||||
loop {
|
||||
while let Some(task) = binary_heap.peek() {
|
||||
if s_inner.state.load() == SchedulerState::ShutdownNow {
|
||||
return;
|
||||
}
|
||||
let now = Instant::now();
|
||||
if now < task.next {
|
||||
//需要等待对应时间
|
||||
@@ -89,7 +133,7 @@ fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
|
||||
}
|
||||
} else {
|
||||
if let Some(task) = binary_heap.pop() {
|
||||
(task.f)(&s_inner);
|
||||
(task.f)(s_inner);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,6 +164,7 @@ fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_task(op: Op, binary_heap: &mut BinaryHeap<DelayedTask>) -> bool {
|
||||
return match op {
|
||||
Op::Task(task) => {
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
use igd::{search_gateway, PortMappingProtocol};
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct UPnP {
|
||||
inner: Arc<UpnpInner>,
|
||||
}
|
||||
|
||||
impl Deref for UPnP {
|
||||
type Target = UpnpInner;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct UpnpInner {
|
||||
list: Mutex<Vec<(PortMappingProtocol, u16)>>,
|
||||
}
|
||||
|
||||
impl UpnpInner {
|
||||
pub fn add_tcp_port(&self, port: u16) {
|
||||
self.list.lock().push((PortMappingProtocol::TCP, port));
|
||||
}
|
||||
pub fn add_udp_port(&self, port: u16) {
|
||||
self.list.lock().push((PortMappingProtocol::UDP, port));
|
||||
}
|
||||
pub fn reset(&self, local_ip: Ipv4Addr) {
|
||||
let gateway = match search_gateway(Default::default()) {
|
||||
Ok(gateway) => gateway,
|
||||
Err(e) => {
|
||||
log::warn!("search_gateway {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let guard = self.list.lock();
|
||||
|
||||
// 不支持upnp的情况会阻塞30秒,之后再改这个库
|
||||
for (protocol, port) in guard.iter() {
|
||||
let local_addr = SocketAddrV4::new(local_ip, *port);
|
||||
log::info!("add upnp protocol={} {}", protocol, local_addr);
|
||||
if let Err(e) = gateway.add_port(*protocol, *port, local_addr, 700, "upnp") {
|
||||
log::warn!(
|
||||
"add upnp failed protocol={},port={} err:{:?}",
|
||||
protocol,
|
||||
port,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for UpnpInner {
|
||||
fn drop(&mut self) {
|
||||
// let gateway = match search_gateway(Default::default()) {
|
||||
// Ok(gateway) => gateway,
|
||||
// Err(e) => {
|
||||
// log::warn!("search_gateway {:?}", e);
|
||||
// return;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// let guard = self.list.lock();
|
||||
// for (protocol, port) in guard.iter() {
|
||||
// if let Err(e) = gateway.remove_port(*protocol, *port) {
|
||||
// log::warn!(
|
||||
// "remove upnp failed protocol={},port={} err:{:?}",
|
||||
// protocol,
|
||||
// port,
|
||||
// e
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -78,7 +78,9 @@ impl Device {
|
||||
));
|
||||
}
|
||||
wintun_log::set_default_logger_if_unset(&win_tun);
|
||||
let _ = Self::delete_for_name(&win_tun, &name_utf16);
|
||||
if Self::delete_for_name(&win_tun, &name_utf16).is_ok() {
|
||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||
}
|
||||
let mut guid_bytes: [u8; 16] = [0u8; 16];
|
||||
rand::thread_rng().fill(&mut guid_bytes);
|
||||
let guid = u128::from_ne_bytes(guid_bytes);
|
||||
@@ -101,7 +103,7 @@ impl Device {
|
||||
));
|
||||
}
|
||||
// 开启session
|
||||
let session = win_tun.WintunStartSession(adapter, 128 * 1024);
|
||||
let session = win_tun.WintunStartSession(adapter, 4 * 1024 * 1024);
|
||||
if session.is_null() {
|
||||
log::error!("session.is_null {:?}", io::Error::last_os_error());
|
||||
return Err(io::Error::new(
|
||||
@@ -172,7 +174,7 @@ impl IFace for Device {
|
||||
|
||||
fn shutdown(&self) -> io::Result<()> {
|
||||
unsafe {
|
||||
if 0 == synchapi::SetEvent(self.shutdown_event) {
|
||||
if winapi::shared::minwindef::TRUE == synchapi::SetEvent(self.shutdown_event) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
@@ -237,7 +239,10 @@ impl Device {
|
||||
if last_error == winapi::shared::winerror::ERROR_NO_MORE_ITEMS {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "try_receive failed"))
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("try_receive failed {:?}", io::Error::last_os_error()),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Ok(Some(packet::TunPacket {
|
||||
@@ -254,13 +259,21 @@ impl Device {
|
||||
loop {
|
||||
//Try 16 times to receive without blocking so we don't have to issue a syscall to wait
|
||||
//for the event if packets are being received at a rapid rate
|
||||
for _i in 0..20 {
|
||||
match self.try_receive()? {
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
Some(packet) => {
|
||||
return Ok(packet);
|
||||
for i in 0..20 {
|
||||
match self.try_receive() {
|
||||
Ok(data) => match data {
|
||||
None => {
|
||||
continue;
|
||||
}
|
||||
Some(packet) => {
|
||||
return Ok(packet);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
if i > 10 {
|
||||
// 某些系统存在错误退出的情况(原因不明),这里尝试忽略部分错误
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,11 +297,11 @@ impl Device {
|
||||
if result == winbase::WAIT_OBJECT_0 {
|
||||
//We have data!
|
||||
continue;
|
||||
} else if result == winbase::WAIT_OBJECT_0 + 1 {
|
||||
} else {
|
||||
//Shutdown event triggered
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"Shutdown event triggered",
|
||||
format!("Shutdown event triggered {}", io::Error::last_os_error()),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -336,8 +349,8 @@ impl Drop for Device {
|
||||
}
|
||||
self.win_tun.WintunEndSession(self.session);
|
||||
self.win_tun.WintunCloseAdapter(self.adapter);
|
||||
if 0 != self.win_tun.WintunDeleteDriver() {
|
||||
log::warn!("WintunDeleteDriver failed")
|
||||
if winapi::shared::minwindef::FALSE == self.win_tun.WintunDeleteDriver() {
|
||||
log::warn!("WintunDeleteDriver failed {:?}", io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user