mirror of https://github.com/ospab/ostp.git
feat: UoT and xHTTP stealth
This commit is contained in:
parent
9329bcef45
commit
83f7ff2119
|
|
@ -123,6 +123,28 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-lc-rs"
|
||||||
|
version = "1.16.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f"
|
||||||
|
dependencies = [
|
||||||
|
"aws-lc-sys",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-lc-sys"
|
||||||
|
version = "0.40.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cmake",
|
||||||
|
"dunce",
|
||||||
|
"fs_extra",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum"
|
name = "axum"
|
||||||
version = "0.8.9"
|
version = "0.8.9"
|
||||||
|
|
@ -224,6 +246,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
|
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
|
"jobserver",
|
||||||
|
"libc",
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -327,6 +351,15 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cmake"
|
||||||
|
version = "0.1.58"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
|
|
@ -426,6 +459,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dunce"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.14"
|
version = "0.3.14"
|
||||||
|
|
@ -457,6 +496,12 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fs_extra"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
|
|
@ -472,6 +517,17 @@ version = "0.3.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
|
|
@ -485,6 +541,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-macro",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"slab",
|
"slab",
|
||||||
|
|
@ -511,6 +568,18 @@ dependencies = [
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"r-efi",
|
||||||
|
"wasip2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ghash"
|
name = "ghash"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
@ -808,6 +877,16 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jobserver"
|
||||||
|
version = "0.1.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.3.4",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.98"
|
version = "0.3.98"
|
||||||
|
|
@ -948,16 +1027,22 @@ name = "ostp-client"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"futures-util",
|
||||||
|
"hmac",
|
||||||
"json_comments",
|
"json_comments",
|
||||||
"ostp-core",
|
"ostp-core",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"rand",
|
"rand",
|
||||||
|
"rustls",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1101,6 +1186,12 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r-efi"
|
||||||
|
version = "5.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
|
|
@ -1128,7 +1219,7 @@ version = "0.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.17",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1148,6 +1239,20 @@ version = "0.8.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ring"
|
||||||
|
version = "0.17.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"getrandom 0.2.17",
|
||||||
|
"libc",
|
||||||
|
"untrusted",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
|
@ -1157,6 +1262,43 @@ dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls"
|
||||||
|
version = "0.23.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
|
||||||
|
dependencies = [
|
||||||
|
"aws-lc-rs",
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"rustls-webpki",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pki-types"
|
||||||
|
version = "1.14.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9"
|
||||||
|
dependencies = [
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-webpki"
|
||||||
|
version = "0.103.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
|
||||||
|
dependencies = [
|
||||||
|
"aws-lc-rs",
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.22"
|
version = "1.0.22"
|
||||||
|
|
@ -1436,6 +1578,16 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-rustls"
|
||||||
|
version = "0.26.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
|
||||||
|
dependencies = [
|
||||||
|
"rustls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.5.11"
|
version = "0.5.11"
|
||||||
|
|
@ -1571,6 +1723,12 @@ dependencies = [
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.8"
|
version = "2.5.8"
|
||||||
|
|
@ -1623,6 +1781,15 @@ version = "0.11.1+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasip2"
|
||||||
|
version = "1.0.3+wasi-0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.121"
|
version = "0.2.121"
|
||||||
|
|
@ -1742,7 +1909,16 @@ version = "0.45.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets 0.42.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1760,13 +1936,29 @@ version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm 0.42.2",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc 0.42.2",
|
||||||
"windows_i686_gnu",
|
"windows_i686_gnu 0.42.2",
|
||||||
"windows_i686_msvc",
|
"windows_i686_msvc 0.42.2",
|
||||||
"windows_x86_64_gnu",
|
"windows_x86_64_gnu 0.42.2",
|
||||||
"windows_x86_64_gnullvm",
|
"windows_x86_64_gnullvm 0.42.2",
|
||||||
"windows_x86_64_msvc",
|
"windows_x86_64_msvc 0.42.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.52.6",
|
||||||
|
"windows_aarch64_msvc 0.52.6",
|
||||||
|
"windows_i686_gnu 0.52.6",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc 0.52.6",
|
||||||
|
"windows_x86_64_gnu 0.52.6",
|
||||||
|
"windows_x86_64_gnullvm 0.52.6",
|
||||||
|
"windows_x86_64_msvc 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1775,42 +1967,90 @@ version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winres"
|
name = "winres"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
|
|
@ -1820,6 +2060,12 @@ dependencies = [
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen"
|
||||||
|
version = "0.57.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "writeable"
|
name = "writeable"
|
||||||
version = "0.6.3"
|
version = "0.6.3"
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ Download pre-built binaries for your platform from [GitHub Releases](https://git
|
||||||
| **Fallback Server** | TCP fallback proxy to a web server — makes OSTP indistinguishable from nginx during active probing. |
|
| **Fallback Server** | TCP fallback proxy to a web server — makes OSTP indistinguishable from nginx during active probing. |
|
||||||
| **Multi-Listener** | Bind to multiple addresses simultaneously (dual-stack IPv4/IPv6, multi-port). |
|
| **Multi-Listener** | Bind to multiple addresses simultaneously (dual-stack IPv4/IPv6, multi-port). |
|
||||||
| **TUN Mode** | Full-system VPN via `tun2socks` integration. All traffic transparently routed through the tunnel. |
|
| **TUN Mode** | Full-system VPN via `tun2socks` integration. All traffic transparently routed through the tunnel. |
|
||||||
|
| **xHTTP Stealth (UoT)** | UDP-over-TCP tunnel disguised as standard HTTP/1.1 or TLS traffic to bypass Level 1 Deep Packet Inspection (DPI) whitelists. |
|
||||||
| **TURN Relay** | RFC 5766 TURN support for environments where direct UDP is blocked. |
|
| **TURN Relay** | RFC 5766 TURN support for environments where direct UDP is blocked. |
|
||||||
| **Hot-Reload** | Runtime config reload without restart (access keys, exclusions, mux settings). |
|
| **Hot-Reload** | Runtime config reload without restart (access keys, exclusions, mux settings). |
|
||||||
| **Structured Logging** | `tracing`-based logging with `RUST_LOG` filtering. JSON/file/syslog output support. |
|
| **Structured Logging** | `tracing`-based logging with `RUST_LOG` filtering. JSON/file/syslog output support. |
|
||||||
|
|
@ -121,6 +122,7 @@ Download pre-built binaries for your platform from [GitHub Releases](https://git
|
||||||
"server": "YOUR_SERVER_IP:50000",
|
"server": "YOUR_SERVER_IP:50000",
|
||||||
"access_key": "YOUR_SECRET_KEY",
|
"access_key": "YOUR_SECRET_KEY",
|
||||||
"socks5_bind": "127.0.0.1:1088",
|
"socks5_bind": "127.0.0.1:1088",
|
||||||
|
"transport": { "mode": "udp", "stealth_sni": "vk.com", "stealth_port": 443 },
|
||||||
"tun": { "enable": false, "dns": "1.1.1.1" }
|
"tun": { "enable": false, "dns": "1.1.1.1" }
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ OSTP — высокопроизводительный транспортный
|
||||||
| **Мультиплексирование** | Несколько логических TCP-потоков поверх одной зашифрованной UDP-сессии с per-stream flow control. |
|
| **Мультиплексирование** | Несколько логических TCP-потоков поверх одной зашифрованной UDP-сессии с per-stream flow control. |
|
||||||
| **Бесшовный роуминг** | Клиент может менять сети (WiFi ↔ 4G) без разрыва сессии — сервер отслеживает session-ID, а не IP-адрес. |
|
| **Бесшовный роуминг** | Клиент может менять сети (WiFi ↔ 4G) без разрыва сессии — сервер отслеживает session-ID, а не IP-адрес. |
|
||||||
| **TUN-режим** | Полносистемный VPN через интеграцию с `tun2socks` на Windows и Linux. |
|
| **TUN-режим** | Полносистемный VPN через интеграцию с `tun2socks` на Windows и Linux. |
|
||||||
|
| **xHTTP Стелс (UoT)** | Туннель UDP-over-TCP, замаскированный под обычный HTTP/1.1 или TLS трафик для обхода белых списков ТСПУ (DPI). |
|
||||||
| **TURN Relay** | RFC 5766 TURN для окружений, где прямой UDP заблокирован. |
|
| **TURN Relay** | RFC 5766 TURN для окружений, где прямой UDP заблокирован. |
|
||||||
| **Hot-Reload** | Перезагрузка конфига в рантайме без перезапуска (ключи, исключения, mux, TURN). |
|
| **Hot-Reload** | Перезагрузка конфига в рантайме без перезапуска (ключи, исключения, mux, TURN). |
|
||||||
| **Кросс-платформа** | Windows, Linux, macOS, Android. Один бинарник, без зависимостей. |
|
| **Кросс-платформа** | Windows, Linux, macOS, Android. Один бинарник, без зависимостей. |
|
||||||
|
|
@ -107,6 +108,12 @@ irm https://raw.githubusercontent.com/ospab/ostp/master/scripts/install.ps1 | ie
|
||||||
"access_key": "ВАШ_КЛЮЧ",
|
"access_key": "ВАШ_КЛЮЧ",
|
||||||
"socks5_bind": "127.0.0.1:1088",
|
"socks5_bind": "127.0.0.1:1088",
|
||||||
"debug": false,
|
"debug": false,
|
||||||
|
// Настройки транспорта (udp или uot)
|
||||||
|
"transport": {
|
||||||
|
"mode": "udp",
|
||||||
|
"stealth_sni": "vk.com",
|
||||||
|
"stealth_port": 443
|
||||||
|
},
|
||||||
// TUN-режим (полносистемный VPN)
|
// TUN-режим (полносистемный VPN)
|
||||||
"tun": {
|
"tun": {
|
||||||
"enable": false,
|
"enable": false,
|
||||||
|
|
|
||||||
|
|
@ -17,3 +17,9 @@ json_comments = "0.2"
|
||||||
portable-atomic.workspace = true
|
portable-atomic.workspace = true
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
socket2 = "0.6.3"
|
socket2 = "0.6.3"
|
||||||
|
rustls = { version = "0.23.40", features = ["ring", "std"] }
|
||||||
|
tokio-rustls = "0.26.0"
|
||||||
|
futures-util = "0.3.32"
|
||||||
|
hmac = "0.12.1"
|
||||||
|
sha2 = "0.10.8"
|
||||||
|
base64 = "0.22.1"
|
||||||
|
|
|
||||||
|
|
@ -38,20 +38,20 @@ pub struct BridgeMetrics {
|
||||||
pub connection_state: AtomicU8,
|
pub connection_state: AtomicU8,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_datagram(socket: &UdpSocket, frame: &Bytes, turn_enabled: bool) -> std::io::Result<usize> {
|
async fn send_datagram(socket: &crate::transport::Transport, frame: &Bytes, turn_enabled: bool) -> std::io::Result<usize> {
|
||||||
if turn_enabled {
|
if turn_enabled {
|
||||||
let mut out = bytes::BytesMut::with_capacity(4 + frame.len());
|
let mut out = bytes::BytesMut::with_capacity(4 + frame.len());
|
||||||
bytes::BufMut::put_u16(&mut out, 0x4000);
|
bytes::BufMut::put_u16(&mut out, 0x4000);
|
||||||
bytes::BufMut::put_u16(&mut out, frame.len() as u16);
|
bytes::BufMut::put_u16(&mut out, frame.len() as u16);
|
||||||
out.extend_from_slice(frame);
|
out.extend_from_slice(frame);
|
||||||
socket.send(&out).await
|
socket.send(&out.freeze()).await
|
||||||
} else {
|
} else {
|
||||||
socket.send(frame).await
|
socket.send(frame).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SessionState {
|
struct SessionState {
|
||||||
socket: Arc<UdpSocket>,
|
socket: crate::transport::Transport,
|
||||||
machine: ProtocolMachine,
|
machine: ProtocolMachine,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,6 +74,10 @@ pub struct Bridge {
|
||||||
pub mux_enabled: bool,
|
pub mux_enabled: bool,
|
||||||
pub mux_sessions: usize,
|
pub mux_sessions: usize,
|
||||||
|
|
||||||
|
pub transport_mode: String,
|
||||||
|
pub stealth_sni: String,
|
||||||
|
pub stealth_port: u16,
|
||||||
|
|
||||||
metrics: Arc<BridgeMetrics>,
|
metrics: Arc<BridgeMetrics>,
|
||||||
sample_sent: u64,
|
sample_sent: u64,
|
||||||
sample_recv: u64,
|
sample_recv: u64,
|
||||||
|
|
@ -103,6 +107,10 @@ impl Bridge {
|
||||||
mux_enabled: config.multiplex.enabled,
|
mux_enabled: config.multiplex.enabled,
|
||||||
mux_sessions: config.multiplex.sessions.max(1),
|
mux_sessions: config.multiplex.sessions.max(1),
|
||||||
|
|
||||||
|
transport_mode: config.transport.mode.clone(),
|
||||||
|
stealth_sni: config.transport.stealth_sni.clone(),
|
||||||
|
stealth_port: config.transport.stealth_port,
|
||||||
|
|
||||||
metrics,
|
metrics,
|
||||||
sample_sent: 0,
|
sample_sent: 0,
|
||||||
sample_recv: 0,
|
sample_recv: 0,
|
||||||
|
|
@ -261,8 +269,7 @@ impl Bridge {
|
||||||
match self.perform_handshake_with_id(&tx, session_id).await {
|
match self.perform_handshake_with_id(&tx, session_id).await {
|
||||||
Ok((sock, mach, rtt)) => {
|
Ok((sock, mach, rtt)) => {
|
||||||
let session_index = sessions.len();
|
let session_index = sessions.len();
|
||||||
let socket = Arc::new(sock);
|
let socket_clone = sock.clone();
|
||||||
let socket_clone = socket.clone();
|
|
||||||
let udp_tx_clone = udp_tx.clone();
|
let udp_tx_clone = udp_tx.clone();
|
||||||
let is_turn = self.turn_enabled;
|
let is_turn = self.turn_enabled;
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
|
@ -295,7 +302,7 @@ impl Bridge {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
sessions.push(SessionState { socket, machine: mach });
|
sessions.push(SessionState { socket: sock, machine: mach });
|
||||||
rtt_sum += rtt;
|
rtt_sum += rtt;
|
||||||
successful_sessions += 1;
|
successful_sessions += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -357,8 +364,7 @@ impl Bridge {
|
||||||
match self.perform_handshake_with_id(&tx, session_id).await {
|
match self.perform_handshake_with_id(&tx, session_id).await {
|
||||||
Ok((sock, mach, rtt)) => {
|
Ok((sock, mach, rtt)) => {
|
||||||
let session_index = new_sessions.len();
|
let session_index = new_sessions.len();
|
||||||
let socket = Arc::new(sock);
|
let socket_clone = sock.clone();
|
||||||
let socket_clone = socket.clone();
|
|
||||||
let udp_tx_clone = udp_tx.clone();
|
let udp_tx_clone = udp_tx.clone();
|
||||||
let is_turn = self.turn_enabled;
|
let is_turn = self.turn_enabled;
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
|
@ -381,7 +387,7 @@ impl Bridge {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
new_sessions.push(SessionState { socket, machine: mach });
|
new_sessions.push(SessionState { socket: sock, machine: mach });
|
||||||
rtt_sum += rtt;
|
rtt_sum += rtt;
|
||||||
successful_sessions += 1;
|
successful_sessions += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -470,8 +476,7 @@ impl Bridge {
|
||||||
match self.perform_handshake_with_id(&tx, session_id).await {
|
match self.perform_handshake_with_id(&tx, session_id).await {
|
||||||
Ok((sock, mach, rtt)) => {
|
Ok((sock, mach, rtt)) => {
|
||||||
let session_index = new_sessions.len();
|
let session_index = new_sessions.len();
|
||||||
let socket = Arc::new(sock);
|
let socket_clone = sock.clone();
|
||||||
let socket_clone = socket.clone();
|
|
||||||
let udp_tx_clone = udp_tx.clone();
|
let udp_tx_clone = udp_tx.clone();
|
||||||
let is_turn = self.turn_enabled;
|
let is_turn = self.turn_enabled;
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
|
@ -501,7 +506,7 @@ impl Bridge {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
new_sessions.push(SessionState { socket, machine: mach });
|
new_sessions.push(SessionState { socket: sock, machine: mach });
|
||||||
rtt_sum += rtt;
|
rtt_sum += rtt;
|
||||||
successful_sessions += 1;
|
successful_sessions += 1;
|
||||||
}
|
}
|
||||||
|
|
@ -750,7 +755,7 @@ impl Bridge {
|
||||||
&mut self,
|
&mut self,
|
||||||
tx: &mpsc::Sender<UiEvent>,
|
tx: &mpsc::Sender<UiEvent>,
|
||||||
session_id: u32,
|
session_id: u32,
|
||||||
) -> Result<(UdpSocket, ProtocolMachine, f64)> {
|
) -> Result<(crate::transport::Transport, ProtocolMachine, f64)> {
|
||||||
let timestamp = std::time::SystemTime::now()
|
let timestamp = std::time::SystemTime::now()
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
|
|
@ -791,13 +796,13 @@ impl Bridge {
|
||||||
|
|
||||||
tx.send(UiEvent::Log(format!("Connecting to remote server: {}...", target_addr))).await.ok();
|
tx.send(UiEvent::Log(format!("Connecting to remote server: {}...", target_addr))).await.ok();
|
||||||
|
|
||||||
let socket = match self.try_connect_socket(target_ip, port).await {
|
let socket = match self.try_connect_transport(target_ip, port).await {
|
||||||
Ok(sock) => sock,
|
Ok(sock) => sock,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if let std::net::IpAddr::V4(ipv4) = target_ip {
|
if let std::net::IpAddr::V4(ipv4) = target_ip {
|
||||||
tx.send(UiEvent::Log(format!("Direct IPv4 connection failed: {}. Trying NAT64 fallback...", e))).await.ok();
|
tx.send(UiEvent::Log(format!("Direct IPv4 connection failed: {}. Trying NAT64 fallback...", e))).await.ok();
|
||||||
let nat64_ipv6 = synthesize_nat64(ipv4);
|
let nat64_ipv6 = synthesize_nat64(ipv4);
|
||||||
match self.try_connect_socket(std::net::IpAddr::V6(nat64_ipv6), port).await {
|
match self.try_connect_transport(std::net::IpAddr::V6(nat64_ipv6), port).await {
|
||||||
Ok(sock) => sock,
|
Ok(sock) => sock,
|
||||||
Err(fallback_err) => {
|
Err(fallback_err) => {
|
||||||
return Err(anyhow::anyhow!("Direct IPv4 failed: {}. NAT64 fallback failed: {}", e, fallback_err));
|
return Err(anyhow::anyhow!("Direct IPv4 failed: {}. NAT64 fallback failed: {}", e, fallback_err));
|
||||||
|
|
@ -809,7 +814,11 @@ impl Bridge {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.turn_enabled {
|
if self.turn_enabled && self.transport_mode != "wss" {
|
||||||
|
let udp_socket = match &socket {
|
||||||
|
crate::transport::Transport::Udp(sock) => sock,
|
||||||
|
_ => return Err(anyhow::anyhow!("TURN requires UDP transport")),
|
||||||
|
};
|
||||||
let turn_addr = if self.turn_server.contains(':') {
|
let turn_addr = if self.turn_server.contains(':') {
|
||||||
self.turn_server.clone()
|
self.turn_server.clone()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -817,7 +826,7 @@ impl Bridge {
|
||||||
};
|
};
|
||||||
tx.send(UiEvent::Log(format!("Allocating TURN relay via {}", turn_addr))).await.ok();
|
tx.send(UiEvent::Log(format!("Allocating TURN relay via {}", turn_addr))).await.ok();
|
||||||
|
|
||||||
match crate::turn::perform_turn_allocation(&socket, &turn_addr, &self.turn_username, &self.turn_password, &self.server_addr).await {
|
match crate::turn::perform_turn_allocation(udp_socket, &turn_addr, &self.turn_username, &self.turn_password, &self.server_addr).await {
|
||||||
Ok(relay_addr) => {
|
Ok(relay_addr) => {
|
||||||
tx.send(UiEvent::Log(format!("TURN relay allocated ({})", relay_addr))).await.ok();
|
tx.send(UiEvent::Log(format!("TURN relay allocated ({})", relay_addr))).await.ok();
|
||||||
|
|
||||||
|
|
@ -826,7 +835,7 @@ impl Bridge {
|
||||||
.collect();
|
.collect();
|
||||||
let turn_target = resolved_turn.first().ok_or_else(|| anyhow::anyhow!("no IP resolved for TURN {}", turn_addr))?;
|
let turn_target = resolved_turn.first().ok_or_else(|| anyhow::anyhow!("no IP resolved for TURN {}", turn_addr))?;
|
||||||
|
|
||||||
let connect_ip = if socket.local_addr().map(|a| a.is_ipv6()).unwrap_or(false) && turn_target.is_ipv4() {
|
let connect_ip = if udp_socket.local_addr().map(|a| a.is_ipv6()).unwrap_or(false) && turn_target.is_ipv4() {
|
||||||
if let std::net::IpAddr::V4(ipv4) = turn_target.ip() {
|
if let std::net::IpAddr::V4(ipv4) = turn_target.ip() {
|
||||||
std::net::IpAddr::V6(synthesize_nat64(ipv4))
|
std::net::IpAddr::V6(synthesize_nat64(ipv4))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -837,14 +846,14 @@ impl Bridge {
|
||||||
};
|
};
|
||||||
|
|
||||||
let connect_addr = std::net::SocketAddr::new(connect_ip, turn_target.port());
|
let connect_addr = std::net::SocketAddr::new(connect_ip, turn_target.port());
|
||||||
socket
|
udp_socket
|
||||||
.connect(connect_addr)
|
.connect(connect_addr)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("failed to re-connect to TURN {}", connect_addr))?;
|
.with_context(|| format!("failed to re-connect to TURN {}", connect_addr))?;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tx.send(UiEvent::Log(format!("TURN allocation failed: {}. Using direct UDP.", e))).await.ok();
|
tx.send(UiEvent::Log(format!("TURN allocation failed: {}. Using direct UDP.", e))).await.ok();
|
||||||
let connect_ip = if socket.local_addr().map(|a| a.is_ipv6()).unwrap_or(false) && target_ip.is_ipv4() {
|
let connect_ip = if udp_socket.local_addr().map(|a| a.is_ipv6()).unwrap_or(false) && target_ip.is_ipv4() {
|
||||||
if let std::net::IpAddr::V4(ipv4) = target_ip {
|
if let std::net::IpAddr::V4(ipv4) = target_ip {
|
||||||
std::net::IpAddr::V6(synthesize_nat64(ipv4))
|
std::net::IpAddr::V6(synthesize_nat64(ipv4))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -854,7 +863,7 @@ impl Bridge {
|
||||||
target_ip
|
target_ip
|
||||||
};
|
};
|
||||||
let connect_addr = std::net::SocketAddr::new(connect_ip, port);
|
let connect_addr = std::net::SocketAddr::new(connect_ip, port);
|
||||||
socket
|
udp_socket
|
||||||
.connect(connect_addr)
|
.connect(connect_addr)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("failed to connect udp to {}", connect_addr))?;
|
.with_context(|| format!("failed to connect udp to {}", connect_addr))?;
|
||||||
|
|
@ -898,7 +907,7 @@ impl Bridge {
|
||||||
if let std::net::IpAddr::V4(ipv4) = target_ip {
|
if let std::net::IpAddr::V4(ipv4) = target_ip {
|
||||||
tx.send(UiEvent::Log("Direct IPv4 handshake timed out. Trying NAT64 fallback...".to_string())).await.ok();
|
tx.send(UiEvent::Log("Direct IPv4 handshake timed out. Trying NAT64 fallback...".to_string())).await.ok();
|
||||||
let nat64_ipv6 = synthesize_nat64(ipv4);
|
let nat64_ipv6 = synthesize_nat64(ipv4);
|
||||||
match self.try_connect_socket(std::net::IpAddr::V6(nat64_ipv6), port).await {
|
match self.try_connect_transport(std::net::IpAddr::V6(nat64_ipv6), port).await {
|
||||||
Ok(fallback_socket) => {
|
Ok(fallback_socket) => {
|
||||||
let mut fallback_success = false;
|
let mut fallback_success = false;
|
||||||
for attempt in 0..4 {
|
for attempt in 0..4 {
|
||||||
|
|
@ -963,13 +972,22 @@ impl Bridge {
|
||||||
self.turn_password = cfg.turn.access_key.clone();
|
self.turn_password = cfg.turn.access_key.clone();
|
||||||
self.mux_enabled = cfg.multiplex.enabled;
|
self.mux_enabled = cfg.multiplex.enabled;
|
||||||
self.mux_sessions = cfg.multiplex.sessions.max(1);
|
self.mux_sessions = cfg.multiplex.sessions.max(1);
|
||||||
|
self.transport_mode = cfg.transport.mode.clone();
|
||||||
|
self.stealth_sni = cfg.transport.stealth_sni.clone();
|
||||||
|
self.stealth_port = cfg.transport.stealth_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn try_connect_socket(
|
async fn try_connect_transport(
|
||||||
&self,
|
&self,
|
||||||
target_ip: std::net::IpAddr,
|
target_ip: std::net::IpAddr,
|
||||||
port: u16,
|
port: u16,
|
||||||
) -> Result<UdpSocket> {
|
) -> Result<crate::transport::Transport> {
|
||||||
|
if self.transport_mode == "uot" {
|
||||||
|
let (tx, rx) = crate::transport::xhttp::connect_xhttp(
|
||||||
|
target_ip, self.stealth_port, &self.stealth_sni, &self.access_key
|
||||||
|
).await?;
|
||||||
|
Ok(crate::transport::Transport::Uot { tx, rx })
|
||||||
|
} else {
|
||||||
let is_ipv6 = target_ip.is_ipv6();
|
let is_ipv6 = target_ip.is_ipv6();
|
||||||
let domain = if is_ipv6 { socket2::Domain::IPV6 } else { socket2::Domain::IPV4 };
|
let domain = if is_ipv6 { socket2::Domain::IPV6 } else { socket2::Domain::IPV4 };
|
||||||
let bind_addr = if is_ipv6 {
|
let bind_addr = if is_ipv6 {
|
||||||
|
|
@ -995,7 +1013,8 @@ impl Bridge {
|
||||||
|
|
||||||
let connect_addr = std::net::SocketAddr::new(target_ip, port);
|
let connect_addr = std::net::SocketAddr::new(target_ip, port);
|
||||||
socket.connect(connect_addr).await.with_context(|| format!("failed to connect udp to {}", connect_addr))?;
|
socket.connect(connect_addr).await.with_context(|| format!("failed to connect udp to {}", connect_addr))?;
|
||||||
Ok(socket)
|
Ok(crate::transport::Transport::Udp(Arc::new(socket)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,33 +55,29 @@ pub struct LocalProxyConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transport layer configuration.
|
/// Transport layer configuration.
|
||||||
/// `mode` = "udp" (default) or "wss" (WebSocket Secure — bypasses DPI whitelists).
|
/// `mode` = "udp" (default) or "uot" (UDP over TCP with xHTTP stealth).
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct TransportConfig {
|
pub struct TransportConfig {
|
||||||
/// "udp" or "wss"
|
/// "udp" or "uot"
|
||||||
#[serde(default = "default_transport_mode")]
|
#[serde(default = "default_transport_mode")]
|
||||||
pub mode: String,
|
pub mode: String,
|
||||||
/// WebSocket host (domain for TLS connect and HTTP Host header)
|
/// TLS SNI and HTTP Host for stealth routing
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub wss_host: String,
|
pub stealth_sni: String,
|
||||||
/// WebSocket HTTP path, e.g. "/ostp"
|
/// TCP Port for the stealth connection
|
||||||
#[serde(default = "default_wss_path")]
|
#[serde(default = "default_stealth_port")]
|
||||||
pub wss_path: String,
|
pub stealth_port: u16,
|
||||||
/// TLS SNI override; defaults to wss_host if empty
|
|
||||||
#[serde(default)]
|
|
||||||
pub wss_sni: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_transport_mode() -> String { "udp".to_string() }
|
fn default_transport_mode() -> String { "udp".to_string() }
|
||||||
fn default_wss_path() -> String { "/ostp".to_string() }
|
fn default_stealth_port() -> u16 { 443 }
|
||||||
|
|
||||||
impl Default for TransportConfig {
|
impl Default for TransportConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
mode: default_transport_mode(),
|
mode: default_transport_mode(),
|
||||||
wss_host: String::new(),
|
stealth_sni: String::new(),
|
||||||
wss_path: default_wss_path(),
|
stealth_port: default_stealth_port(),
|
||||||
wss_sni: String::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ pub mod bridge;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod signal;
|
pub mod signal;
|
||||||
pub mod sysproxy;
|
pub mod sysproxy;
|
||||||
|
pub mod transport;
|
||||||
pub mod tunnel;
|
pub mod tunnel;
|
||||||
|
|
||||||
pub mod turn;
|
pub mod turn;
|
||||||
pub mod runner;
|
pub mod runner;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
pub mod xhttp;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::net::UdpSocket;
|
||||||
|
use bytes::Bytes;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Transport {
|
||||||
|
Udp(Arc<UdpSocket>),
|
||||||
|
Uot {
|
||||||
|
tx: tokio::sync::mpsc::Sender<Bytes>,
|
||||||
|
rx: Arc<tokio::sync::Mutex<tokio::sync::mpsc::Receiver<Bytes>>>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Transport {
|
||||||
|
pub async fn send(&self, frame: &Bytes) -> std::io::Result<usize> {
|
||||||
|
match self {
|
||||||
|
Self::Udp(sock) => sock.send(frame).await,
|
||||||
|
Self::Uot { tx, .. } => {
|
||||||
|
tx.send(frame.clone()).await.map_err(|_| std::io::Error::new(std::io::ErrorKind::BrokenPipe, "uot closed"))?;
|
||||||
|
Ok(frame.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_to(&self, frame: &Bytes, target: std::net::SocketAddr) -> std::io::Result<usize> {
|
||||||
|
match self {
|
||||||
|
Self::Udp(sock) => sock.send_to(frame, target).await,
|
||||||
|
Self::Uot { .. } => self.send(frame).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
|
match self {
|
||||||
|
Self::Udp(sock) => sock.recv(buf).await,
|
||||||
|
Self::Uot { rx, .. } => {
|
||||||
|
let mut rx = rx.lock().await;
|
||||||
|
match rx.recv().await {
|
||||||
|
Some(bytes) => {
|
||||||
|
let len = bytes.len().min(buf.len());
|
||||||
|
buf[..len].copy_from_slice(&bytes[..len]);
|
||||||
|
Ok(len)
|
||||||
|
}
|
||||||
|
None => Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, "uot closed")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn local_addr(&self) -> std::io::Result<std::net::SocketAddr> {
|
||||||
|
match self {
|
||||||
|
Self::Udp(sock) => sock.local_addr(),
|
||||||
|
Self::Uot { .. } => Ok("0.0.0.0:0".parse().unwrap()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,175 @@
|
||||||
|
use std::net::IpAddr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
use bytes::{Bytes, BytesMut};
|
||||||
|
use anyhow::{Result, Context};
|
||||||
|
use tokio::sync::mpsc;
|
||||||
|
use rustls::pki_types::{ServerName, CertificateDer, UnixTime};
|
||||||
|
use rustls::client::danger::{ServerCertVerifier, ServerCertVerified, HandshakeSignatureValid};
|
||||||
|
use rustls::DigitallySignedStruct;
|
||||||
|
use sha2::{Sha256, Digest};
|
||||||
|
use hmac::{Hmac, Mac};
|
||||||
|
use base64::Engine;
|
||||||
|
|
||||||
|
type HmacSha256 = Hmac<Sha256>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct NoAuthVerifier;
|
||||||
|
|
||||||
|
impl ServerCertVerifier for NoAuthVerifier {
|
||||||
|
fn verify_server_cert(
|
||||||
|
&self,
|
||||||
|
_end_entity: &CertificateDer<'_>,
|
||||||
|
_intermediates: &[CertificateDer<'_>],
|
||||||
|
_server_name: &ServerName<'_>,
|
||||||
|
_ocsp_response: &[u8],
|
||||||
|
_now: UnixTime,
|
||||||
|
) -> Result<ServerCertVerified, rustls::Error> {
|
||||||
|
Ok(ServerCertVerified::assertion())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_tls12_signature(
|
||||||
|
&self,
|
||||||
|
_message: &[u8],
|
||||||
|
_cert: &CertificateDer<'_>,
|
||||||
|
_dss: &DigitallySignedStruct,
|
||||||
|
) -> Result<HandshakeSignatureValid, rustls::Error> {
|
||||||
|
Ok(HandshakeSignatureValid::assertion())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_tls13_signature(
|
||||||
|
&self,
|
||||||
|
_message: &[u8],
|
||||||
|
_cert: &CertificateDer<'_>,
|
||||||
|
_dss: &DigitallySignedStruct,
|
||||||
|
) -> Result<HandshakeSignatureValid, rustls::Error> {
|
||||||
|
Ok(HandshakeSignatureValid::assertion())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
|
||||||
|
vec![
|
||||||
|
rustls::SignatureScheme::RSA_PKCS1_SHA256,
|
||||||
|
rustls::SignatureScheme::ECDSA_NISTP256_SHA256,
|
||||||
|
rustls::SignatureScheme::ECDSA_NISTP384_SHA384,
|
||||||
|
rustls::SignatureScheme::ED25519,
|
||||||
|
rustls::SignatureScheme::RSA_PSS_SHA256,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn connect_xhttp(
|
||||||
|
target_ip: IpAddr,
|
||||||
|
port: u16,
|
||||||
|
sni: &str,
|
||||||
|
access_key: &[u8],
|
||||||
|
) -> Result<(mpsc::Sender<Bytes>, Arc<tokio::sync::Mutex<mpsc::Receiver<Bytes>>>)> {
|
||||||
|
let addr = std::net::SocketAddr::new(target_ip, port);
|
||||||
|
let tcp_stream = TcpStream::connect(addr).await
|
||||||
|
.with_context(|| format!("failed to connect to {}", addr))?;
|
||||||
|
tcp_stream.set_nodelay(true)?;
|
||||||
|
|
||||||
|
// 1. Generate auth token
|
||||||
|
let timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH)?.as_secs();
|
||||||
|
let mut mac = HmacSha256::new_from_slice(access_key).unwrap_or_else(|_| HmacSha256::new_from_slice(b"").unwrap());
|
||||||
|
mac.update(×tamp.to_be_bytes());
|
||||||
|
let sig = base64::prelude::BASE64_STANDARD.encode(mac.finalize().into_bytes());
|
||||||
|
let auth_token = format!("{}:{}", timestamp, sig);
|
||||||
|
|
||||||
|
let http_host = if sni.is_empty() { target_ip.to_string() } else { sni.to_string() };
|
||||||
|
|
||||||
|
let req = format!(
|
||||||
|
"GET /stream HTTP/1.1\r\n\
|
||||||
|
Host: {}\r\n\
|
||||||
|
Authorization: Bearer {}\r\n\
|
||||||
|
Connection: keep-alive\r\n\
|
||||||
|
\r\n",
|
||||||
|
http_host, auth_token
|
||||||
|
);
|
||||||
|
|
||||||
|
// 2. TLS wrapping (if port 443)
|
||||||
|
if port == 443 {
|
||||||
|
let mut config = rustls::ClientConfig::builder()
|
||||||
|
.dangerous()
|
||||||
|
.with_custom_certificate_verifier(Arc::new(NoAuthVerifier))
|
||||||
|
.with_no_client_auth();
|
||||||
|
config.alpn_protocols.push(b"http/1.1".to_vec());
|
||||||
|
let tls_connector = tokio_rustls::TlsConnector::from(Arc::new(config));
|
||||||
|
|
||||||
|
let server_name = ServerName::try_from(http_host.as_str())
|
||||||
|
.unwrap_or_else(|_| ServerName::try_from("localhost").unwrap())
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
|
let mut tls_stream = tls_connector.connect(server_name, tcp_stream).await?;
|
||||||
|
|
||||||
|
// HTTP Handshake
|
||||||
|
tls_stream.write_all(req.as_bytes()).await?;
|
||||||
|
tls_stream.flush().await?;
|
||||||
|
|
||||||
|
let mut buf = [0u8; 1024];
|
||||||
|
let n = tls_stream.read(&mut buf).await?;
|
||||||
|
let resp = String::from_utf8_lossy(&buf[..n]);
|
||||||
|
if !resp.contains("200 OK") {
|
||||||
|
anyhow::bail!("xHTTP handshake failed: expected 200 OK, got: {}", resp.lines().next().unwrap_or(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split stream
|
||||||
|
let (rx, tx) = tokio::io::split(tls_stream);
|
||||||
|
start_uot_loops(rx, tx)
|
||||||
|
} else {
|
||||||
|
let mut tcp_stream = tcp_stream;
|
||||||
|
tcp_stream.write_all(req.as_bytes()).await?;
|
||||||
|
tcp_stream.flush().await?;
|
||||||
|
|
||||||
|
let mut buf = [0u8; 1024];
|
||||||
|
let n = tcp_stream.read(&mut buf).await?;
|
||||||
|
let resp = String::from_utf8_lossy(&buf[..n]);
|
||||||
|
if !resp.contains("200 OK") {
|
||||||
|
anyhow::bail!("xHTTP handshake failed: expected 200 OK, got: {}", resp.lines().next().unwrap_or(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
let (rx, tx) = tcp_stream.into_split();
|
||||||
|
start_uot_loops(rx, tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_uot_loops<R, W>(
|
||||||
|
mut net_rx: R,
|
||||||
|
mut net_tx: W
|
||||||
|
) -> Result<(mpsc::Sender<Bytes>, Arc<tokio::sync::Mutex<mpsc::Receiver<Bytes>>>)>
|
||||||
|
where
|
||||||
|
R: tokio::io::AsyncRead + Unpin + Send + 'static,
|
||||||
|
W: tokio::io::AsyncWrite + Unpin + Send + 'static,
|
||||||
|
{
|
||||||
|
let (app_tx, bridge_rx) = mpsc::channel::<Bytes>(1024);
|
||||||
|
let (bridge_tx, app_rx) = mpsc::channel::<Bytes>(1024);
|
||||||
|
|
||||||
|
// TX Loop (App -> UoT -> Network)
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let mut rx = bridge_rx;
|
||||||
|
while let Some(frame) = rx.recv().await {
|
||||||
|
let len = frame.len() as u16;
|
||||||
|
if net_tx.write_u16(len).await.is_err() { break; }
|
||||||
|
if net_tx.write_all(&frame).await.is_err() { break; }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// RX Loop (Network -> UoT -> App)
|
||||||
|
tokio::spawn(async move {
|
||||||
|
loop {
|
||||||
|
let len = match net_rx.read_u16().await {
|
||||||
|
Ok(l) => l,
|
||||||
|
Err(_) => break,
|
||||||
|
};
|
||||||
|
let mut buf = vec![0u8; len as usize];
|
||||||
|
if net_rx.read_exact(&mut buf).await.is_err() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if app_tx.send(Bytes::from(buf)).await.is_err() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok((bridge_tx, Arc::new(tokio::sync::Mutex::new(app_rx))))
|
||||||
|
}
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 64efa677aca2551b61f71f2168611d884619e5ca
|
Subproject commit fe1cb7f196d79d0d5175f776dbeb297dd3ffe49a
|
||||||
|
|
@ -498,6 +498,13 @@ async fn run_app() -> Result<()> {
|
||||||
"access_key": "ostppassword"
|
"access_key": "ostppassword"
|
||||||
}},
|
}},
|
||||||
|
|
||||||
|
// Transport Mode: "udp" (default) or "uot" (xHTTP Stealth / UDP over TCP)
|
||||||
|
"transport": {{
|
||||||
|
"mode": "udp",
|
||||||
|
"stealth_sni": "vk.com",
|
||||||
|
"stealth_port": 443
|
||||||
|
}},
|
||||||
|
|
||||||
"mux": {{
|
"mux": {{
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"sessions": 1
|
"sessions": 1
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue