mirror of
https://mirror.suhoan.cn/https://github.com/EasyTier/EasyTier.git
synced 2025-12-14 13:47:24 +08:00
http redirector
This commit is contained in:
163
Cargo.lock
generated
163
Cargo.lock
generated
@@ -664,12 +664,6 @@ version = "1.6.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "beef"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bigdecimal"
|
name = "bigdecimal"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
@@ -802,9 +796,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "borsh"
|
name = "borsh"
|
||||||
version = "1.5.1"
|
version = "1.5.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed"
|
checksum = "5430e3be710b68d984d1391c854eb431a9d548640711faa54eecb1df93db91cc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh-derive",
|
"borsh-derive",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
@@ -812,16 +806,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "borsh-derive"
|
name = "borsh-derive"
|
||||||
version = "1.5.1"
|
version = "1.5.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b"
|
checksum = "f8b668d39970baad5356d7c83a86fee3a539e6f93bf6764c97368243e17a0487"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro-crate 3.1.0",
|
"proc-macro-crate 3.1.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.87",
|
"syn 2.0.87",
|
||||||
"syn_derive",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1165,9 +1158,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.15"
|
version = "4.5.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc"
|
checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -1175,9 +1168,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.15"
|
version = "4.5.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
|
checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -1185,14 +1178,14 @@ dependencies = [
|
|||||||
"strsim",
|
"strsim",
|
||||||
"terminal_size",
|
"terminal_size",
|
||||||
"unicase",
|
"unicase",
|
||||||
"unicode-width",
|
"unicode-width 0.2.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.13"
|
version = "4.5.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
|
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -1202,9 +1195,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.7.2"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clipboard-win"
|
name = "clipboard-win"
|
||||||
@@ -1888,6 +1881,7 @@ dependencies = [
|
|||||||
"git-version",
|
"git-version",
|
||||||
"globwalk",
|
"globwalk",
|
||||||
"http",
|
"http",
|
||||||
|
"http_req",
|
||||||
"humansize",
|
"humansize",
|
||||||
"kcp-sys",
|
"kcp-sys",
|
||||||
"machine-uid",
|
"machine-uid",
|
||||||
@@ -3056,6 +3050,21 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http_req"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "git+https://github.com/EasyTier/http_req.git#e6d9e93c43c940f56f45e91b0923bcea53a718ea"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.22.1",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pemfile",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"unicase",
|
||||||
|
"webpki",
|
||||||
|
"webpki-roots",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.9.4"
|
version = "1.9.4"
|
||||||
@@ -3686,39 +3695,6 @@ version = "0.4.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "logos"
|
|
||||||
version = "0.14.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7251356ef8cb7aec833ddf598c6cb24d17b689d20b993f9d11a3d764e34e6458"
|
|
||||||
dependencies = [
|
|
||||||
"logos-derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "logos-codegen"
|
|
||||||
version = "0.14.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "59f80069600c0d66734f5ff52cc42f2dabd6b29d205f333d61fd7832e9e9963f"
|
|
||||||
dependencies = [
|
|
||||||
"beef",
|
|
||||||
"fnv",
|
|
||||||
"lazy_static",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"regex-syntax 0.8.4",
|
|
||||||
"syn 2.0.87",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "logos-derive"
|
|
||||||
version = "0.14.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "24fb722b06a9dc12adb0963ed585f19fc61dc5413e6a9be9422ef92c091e731d"
|
|
||||||
dependencies = [
|
|
||||||
"logos-codegen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "loom"
|
name = "loom"
|
||||||
version = "0.5.6"
|
version = "0.5.6"
|
||||||
@@ -4603,15 +4579,6 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ordered-float"
|
|
||||||
version = "2.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ordered-float"
|
name = "ordered-float"
|
||||||
version = "3.9.2"
|
version = "3.9.2"
|
||||||
@@ -4725,7 +4692,7 @@ checksum = "c7419ad52a7de9b60d33e11085a0fe3df1fbd5926aa3f93d3dd53afbc9e86725"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytecount",
|
"bytecount",
|
||||||
"fnv",
|
"fnv",
|
||||||
"unicode-width",
|
"unicode-width 0.1.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5396,14 +5363,10 @@ version = "0.14.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e92b959d24e05a3e2da1d0beb55b48bc8a97059b8336ea617780bd6addbbfb5a"
|
checksum = "e92b959d24e05a3e2da1d0beb55b48bc8a97059b8336ea617780bd6addbbfb5a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
|
||||||
"logos",
|
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"prost",
|
"prost",
|
||||||
"prost-reflect-derive",
|
"prost-reflect-derive",
|
||||||
"prost-types",
|
"prost-types",
|
||||||
"serde",
|
|
||||||
"serde-value",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6080,19 +6043,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pemfile"
|
name = "rustls-pemfile"
|
||||||
version = "2.1.3"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425"
|
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "1.8.0"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0"
|
checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-platform-verifier"
|
name = "rustls-platform-verifier"
|
||||||
@@ -6278,9 +6240,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sea-orm-cli"
|
name = "sea-orm-cli"
|
||||||
version = "1.1.0"
|
version = "1.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0aefbd960c9ed7b2dfbab97b11890f5d8c314ad6e2f68c7b36c73ea0967fcc25"
|
checksum = "0646647444d3a0366e30f26ff39f1656cc062b3dbf1f2e3d70cd9dc244b62cf7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -6333,7 +6295,7 @@ dependencies = [
|
|||||||
"bigdecimal",
|
"bigdecimal",
|
||||||
"chrono",
|
"chrono",
|
||||||
"inherent",
|
"inherent",
|
||||||
"ordered-float 3.9.2",
|
"ordered-float",
|
||||||
"rust_decimal",
|
"rust_decimal",
|
||||||
"sea-query-derive",
|
"sea-query-derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -6473,16 +6435,6 @@ dependencies = [
|
|||||||
"typeid",
|
"typeid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde-value"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
|
|
||||||
dependencies = [
|
|
||||||
"ordered-float 2.10.1",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.207"
|
version = "1.0.207"
|
||||||
@@ -7231,18 +7183,6 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn_derive"
|
|
||||||
version = "0.1.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.87",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sync_wrapper"
|
name = "sync_wrapper"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -7762,12 +7702,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "terminal_size"
|
name = "terminal_size"
|
||||||
version = "0.3.0"
|
version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
|
checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -8467,12 +8407,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
version = "2.7.0"
|
version = "2.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
|
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
|
||||||
dependencies = [
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
@@ -8513,6 +8450,12 @@ version = "0.1.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode_categories"
|
name = "unicode_categories"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -8821,6 +8764,16 @@ dependencies = [
|
|||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki"
|
||||||
|
version = "0.22.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpki-roots"
|
name = "webpki-roots"
|
||||||
version = "0.26.3"
|
version = "0.26.3"
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||||||
pnet = { version = "0.35.0", features = ["serde"] }
|
pnet = { version = "0.35.0", features = ["serde"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
|
||||||
clap = { version = "4.4.8", features = [
|
clap = { version = "4.5.30", features = [
|
||||||
"string",
|
"string",
|
||||||
"unicode",
|
"unicode",
|
||||||
"derive",
|
"derive",
|
||||||
@@ -182,14 +182,12 @@ async-compression = { version = "0.4.17", default-features = false, features = [
|
|||||||
|
|
||||||
kcp-sys = { git = "https://github.com/EasyTier/kcp-sys" }
|
kcp-sys = { git = "https://github.com/EasyTier/kcp-sys" }
|
||||||
|
|
||||||
prost-reflect = { version = "0.14.5", features = [
|
prost-reflect = { version = "0.14.5", default-features = false, features = [
|
||||||
"serde",
|
|
||||||
"derive",
|
"derive",
|
||||||
"text-format"
|
|
||||||
] }
|
] }
|
||||||
|
|
||||||
# for http connector
|
# for http connector
|
||||||
# reqwest = { version = "0.12.12", default-features = false, features = ["rustls-tls"] }
|
http_req = { git = "https://github.com/EasyTier/http_req.git", default-features = false, features = ["rust-tls"] }
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "freebsd"))'.dependencies]
|
[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "freebsd"))'.dependencies]
|
||||||
machine-uid = "0.5.3"
|
machine-uid = "0.5.3"
|
||||||
|
|||||||
298
easytier/src/connector/http_connector.rs
Normal file
298
easytier/src/connector/http_connector.rs
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
use std::{
|
||||||
|
net::SocketAddr,
|
||||||
|
pin::Pin,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use http_req::request::{RedirectPolicy, Request};
|
||||||
|
use rand::seq::SliceRandom as _;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
common::{error::Error, global_ctx::ArcGlobalCtx},
|
||||||
|
tunnel::{IpVersion, Tunnel, TunnelConnector, TunnelError, ZCPacketSink, ZCPacketStream},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::proto::common::TunnelInfo;
|
||||||
|
|
||||||
|
use super::create_connector_by_url;
|
||||||
|
|
||||||
|
pub struct TunnelWithInfo {
|
||||||
|
inner: Box<dyn Tunnel>,
|
||||||
|
info: TunnelInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TunnelWithInfo {
|
||||||
|
pub fn new(inner: Box<dyn Tunnel>, info: TunnelInfo) -> Self {
|
||||||
|
Self { inner, info }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tunnel for TunnelWithInfo {
|
||||||
|
fn split(&self) -> (Pin<Box<dyn ZCPacketStream>>, Pin<Box<dyn ZCPacketSink>>) {
|
||||||
|
self.inner.split()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn info(&self) -> Option<TunnelInfo> {
|
||||||
|
Some(self.info.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
|
enum HttpRedirectType {
|
||||||
|
Unknown,
|
||||||
|
// redirected url is in the path of new url
|
||||||
|
RedirectToQuery,
|
||||||
|
// redirected url is the entire new url
|
||||||
|
RedirectToUrl,
|
||||||
|
// redirected url is in the body of response
|
||||||
|
BodyUrls,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HttpTunnelConnector {
|
||||||
|
addr: url::Url,
|
||||||
|
bind_addrs: Vec<SocketAddr>,
|
||||||
|
ip_version: IpVersion,
|
||||||
|
global_ctx: ArcGlobalCtx,
|
||||||
|
redirect_type: HttpRedirectType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HttpTunnelConnector {
|
||||||
|
pub fn new(addr: url::Url, global_ctx: ArcGlobalCtx) -> Self {
|
||||||
|
Self {
|
||||||
|
addr,
|
||||||
|
bind_addrs: Vec::new(),
|
||||||
|
ip_version: IpVersion::Both,
|
||||||
|
global_ctx,
|
||||||
|
redirect_type: HttpRedirectType::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(ret)]
|
||||||
|
async fn handle_302_redirect(
|
||||||
|
&mut self,
|
||||||
|
new_url: url::Url,
|
||||||
|
) -> Result<Box<dyn TunnelConnector>, Error> {
|
||||||
|
// the url should be in following format:
|
||||||
|
// 1: http(s)://easytier.cn/?url=tcp://10.147.22.22:11010 (scheme is http, domain is ignored, path is splitted into proto type and addr)
|
||||||
|
// 2: tcp://10.137.22.22:11010 (scheme is protocol type, the url is used to construct a connector directly)
|
||||||
|
tracing::info!("redirect to {}", new_url);
|
||||||
|
let url = url::Url::parse(new_url.as_str())
|
||||||
|
.with_context(|| format!("parsing redirect url failed. url: {}", new_url))?;
|
||||||
|
if url.scheme() == "http" || url.scheme() == "https" {
|
||||||
|
let mut query = new_url
|
||||||
|
.query_pairs()
|
||||||
|
.filter_map(|x| url::Url::parse(&x.1).ok())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
query.shuffle(&mut rand::thread_rng());
|
||||||
|
if query.is_empty() {
|
||||||
|
return Err(Error::InvalidUrl(format!(
|
||||||
|
"no valid connector url found in url: url: {}",
|
||||||
|
url
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
tracing::info!("try to create connector by url: {}", query[0]);
|
||||||
|
self.redirect_type = HttpRedirectType::RedirectToQuery;
|
||||||
|
return create_connector_by_url(&query[0].to_string(), &self.global_ctx).await;
|
||||||
|
} else {
|
||||||
|
self.redirect_type = HttpRedirectType::RedirectToUrl;
|
||||||
|
return create_connector_by_url(new_url.as_str(), &self.global_ctx).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument]
|
||||||
|
async fn handle_200_success(
|
||||||
|
&mut self,
|
||||||
|
body: &String,
|
||||||
|
) -> Result<Box<dyn TunnelConnector>, Error> {
|
||||||
|
// resp body should be line of connector urls, like:
|
||||||
|
// tcp://10.1.1.1:11010
|
||||||
|
// udp://10.1.1.1:11010
|
||||||
|
let mut lines = body
|
||||||
|
.lines()
|
||||||
|
.map(|line| line.trim())
|
||||||
|
.filter(|line| !line.is_empty())
|
||||||
|
.collect::<Vec<&str>>();
|
||||||
|
|
||||||
|
tracing::info!("get {} lines of connector urls", lines.len());
|
||||||
|
|
||||||
|
// shuffle the lines and pick the usable one
|
||||||
|
lines.shuffle(&mut rand::thread_rng());
|
||||||
|
|
||||||
|
for line in lines {
|
||||||
|
let url = url::Url::parse(line);
|
||||||
|
if url.is_err() {
|
||||||
|
tracing::warn!("invalid url: {}, skip it", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
self.redirect_type = HttpRedirectType::BodyUrls;
|
||||||
|
return create_connector_by_url(line, &self.global_ctx).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(Error::InvalidUrl(
|
||||||
|
"no valid connector url found".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(ret)]
|
||||||
|
pub async fn get_redirected_connector(
|
||||||
|
&mut self,
|
||||||
|
original_url: &str,
|
||||||
|
) -> Result<Box<dyn TunnelConnector>, Error> {
|
||||||
|
self.redirect_type = HttpRedirectType::Unknown;
|
||||||
|
tracing::info!("get_redirected_url: {}", original_url);
|
||||||
|
// Container for body of a response.
|
||||||
|
let body = Arc::new(RwLock::new(Vec::new()));
|
||||||
|
|
||||||
|
let original_url_clone = original_url.to_string();
|
||||||
|
let body_clone = body.clone();
|
||||||
|
let res = tokio::task::spawn_blocking(move || {
|
||||||
|
let uri = http_req::uri::Uri::try_from(original_url_clone.as_ref())
|
||||||
|
.with_context(|| format!("parsing url failed. url: {}", original_url_clone))?;
|
||||||
|
|
||||||
|
tracing::info!("sending http request to {}", uri);
|
||||||
|
|
||||||
|
Request::new(&uri)
|
||||||
|
.redirect_policy(RedirectPolicy::Limit(0))
|
||||||
|
.timeout(std::time::Duration::from_secs(5))
|
||||||
|
.send(&mut *body_clone.write().unwrap())
|
||||||
|
.with_context(|| format!("sending http request failed. url: {}", uri))
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map_err(|e| Error::InvalidUrl(format!("task join error: {}", e)))??;
|
||||||
|
|
||||||
|
let body = String::from_utf8_lossy(&body.read().unwrap()).to_string();
|
||||||
|
|
||||||
|
if res.status_code().is_redirect() {
|
||||||
|
let redirect_url = res
|
||||||
|
.headers()
|
||||||
|
.get("Location")
|
||||||
|
.ok_or_else(|| Error::InvalidUrl("no redirect address found".to_string()))?;
|
||||||
|
let new_url = url::Url::parse(redirect_url.as_str())
|
||||||
|
.with_context(|| format!("parsing redirect url failed. url: {}", redirect_url))?;
|
||||||
|
return self.handle_302_redirect(new_url).await;
|
||||||
|
} else if res.status_code().is_success() {
|
||||||
|
return self.handle_200_success(&body).await;
|
||||||
|
} else {
|
||||||
|
return Err(Error::InvalidUrl(format!(
|
||||||
|
"unexpected response, resp: {:?}, body: {}",
|
||||||
|
res, body,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl super::TunnelConnector for HttpTunnelConnector {
|
||||||
|
async fn connect(&mut self) -> Result<Box<dyn Tunnel>, TunnelError> {
|
||||||
|
let mut conn = self
|
||||||
|
.get_redirected_connector(self.addr.to_string().as_str())
|
||||||
|
.await
|
||||||
|
.with_context(|| "get redirected url failed")?;
|
||||||
|
conn.set_ip_version(self.ip_version);
|
||||||
|
let t = conn.connect().await?;
|
||||||
|
let info = t.info().unwrap_or_default();
|
||||||
|
Ok(Box::new(TunnelWithInfo::new(
|
||||||
|
t,
|
||||||
|
TunnelInfo {
|
||||||
|
local_addr: info.local_addr.clone(),
|
||||||
|
remote_addr: Some(self.addr.clone().into()),
|
||||||
|
tunnel_type: format!(
|
||||||
|
"{:?}-{}",
|
||||||
|
self.redirect_type,
|
||||||
|
info.remote_addr.unwrap_or_default()
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remote_url(&self) -> url::Url {
|
||||||
|
self.addr.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_bind_addrs(&mut self, addrs: Vec<SocketAddr>) {
|
||||||
|
self.bind_addrs = addrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_ip_version(&mut self, ip_version: IpVersion) {
|
||||||
|
self.ip_version = ip_version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use tokio::{io::AsyncWriteExt as _, net::TcpListener};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
common::global_ctx::tests::get_mock_global_ctx,
|
||||||
|
tunnel::{tcp::TcpTunnelListener, TunnelConnector, TunnelListener},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
async fn run_http_redirect_server(port: u16, test_type: HttpRedirectType) -> Result<(), Error> {
|
||||||
|
let listener = TcpListener::bind(format!("0.0.0.0:{}", port)).await?;
|
||||||
|
let (mut stream, _) = listener.accept().await?;
|
||||||
|
|
||||||
|
match test_type {
|
||||||
|
HttpRedirectType::RedirectToQuery => {
|
||||||
|
let resp = "HTTP/1.1 301 Moved Permanently\r\nLocation: http://test.com/?url=tcp://127.0.0.1:25888\r\n\r\n";
|
||||||
|
stream.write_all(resp.as_bytes()).await?;
|
||||||
|
}
|
||||||
|
HttpRedirectType::RedirectToUrl => {
|
||||||
|
let resp =
|
||||||
|
"HTTP/1.1 301 Moved Permanently\r\nLocation: tcp://127.0.0.1:25888\r\n\r\n";
|
||||||
|
stream.write_all(resp.as_bytes()).await?;
|
||||||
|
}
|
||||||
|
HttpRedirectType::BodyUrls => {
|
||||||
|
let resp = "HTTP/1.1 200 OK\r\n\r\ntcp://127.0.0.1:25888";
|
||||||
|
stream.write_all(resp.as_bytes()).await?;
|
||||||
|
}
|
||||||
|
HttpRedirectType::Unknown => {
|
||||||
|
panic!("unexpected test type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest::rstest]
|
||||||
|
#[serial_test::serial(http_redirect_test)]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn http_redirect_test(
|
||||||
|
// 1. 301 redirect
|
||||||
|
// 2. 200 success with valid connector urls
|
||||||
|
#[values(
|
||||||
|
HttpRedirectType::RedirectToQuery,
|
||||||
|
HttpRedirectType::RedirectToUrl,
|
||||||
|
HttpRedirectType::BodyUrls
|
||||||
|
)]
|
||||||
|
test_type: HttpRedirectType,
|
||||||
|
) {
|
||||||
|
let http_task = tokio::spawn(run_http_redirect_server(35888, test_type));
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
|
||||||
|
let test_url: url::Url = "http://127.0.0.1:35888".parse().unwrap();
|
||||||
|
let global_ctx = get_mock_global_ctx();
|
||||||
|
let mut flags = global_ctx.config.get_flags();
|
||||||
|
flags.bind_device = false;
|
||||||
|
global_ctx.config.set_flags(flags);
|
||||||
|
let mut connector = HttpTunnelConnector::new(test_url.clone(), global_ctx.clone());
|
||||||
|
|
||||||
|
let mut listener = TcpTunnelListener::new("tcp://0.0.0.0:25888".parse().unwrap());
|
||||||
|
listener.listen().await.unwrap();
|
||||||
|
|
||||||
|
let task = tokio::spawn(async move {
|
||||||
|
let _conn = listener.accept().await.unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
let t = connector.connect().await.unwrap();
|
||||||
|
assert_eq!(connector.redirect_type, test_type);
|
||||||
|
let info = t.info().unwrap();
|
||||||
|
let remote_addr = info.remote_addr.unwrap();
|
||||||
|
assert_eq!(remote_addr, test_url.into());
|
||||||
|
|
||||||
|
tokio::join!(task).0.unwrap();
|
||||||
|
tokio::join!(http_task).0.unwrap().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use http_connector::HttpTunnelConnector;
|
||||||
|
|
||||||
#[cfg(feature = "quic")]
|
#[cfg(feature = "quic")]
|
||||||
use crate::tunnel::quic::QUICTunnelConnector;
|
use crate::tunnel::quic::QUICTunnelConnector;
|
||||||
#[cfg(feature = "wireguard")]
|
#[cfg(feature = "wireguard")]
|
||||||
@@ -19,7 +21,7 @@ pub mod direct;
|
|||||||
pub mod manual;
|
pub mod manual;
|
||||||
pub mod udp_hole_punch;
|
pub mod udp_hole_punch;
|
||||||
|
|
||||||
mod http_connector;
|
pub mod http_connector;
|
||||||
|
|
||||||
async fn set_bind_addr_for_peer_connector(
|
async fn set_bind_addr_for_peer_connector(
|
||||||
connector: &mut (impl TunnelConnector + ?Sized),
|
connector: &mut (impl TunnelConnector + ?Sized),
|
||||||
@@ -81,6 +83,10 @@ pub async fn create_connector_by_url(
|
|||||||
}
|
}
|
||||||
return Ok(Box::new(connector));
|
return Ok(Box::new(connector));
|
||||||
}
|
}
|
||||||
|
"http" | "https" => {
|
||||||
|
let connector = HttpTunnelConnector::new(url, global_ctx.clone());
|
||||||
|
return Ok(Box::new(connector));
|
||||||
|
}
|
||||||
"ring" => {
|
"ring" => {
|
||||||
check_scheme_and_get_socket_addr::<uuid::Uuid>(&url, "ring")?;
|
check_scheme_and_get_socket_addr::<uuid::Uuid>(&url, "ring")?;
|
||||||
let connector = RingTunnelConnector::new(url);
|
let connector = RingTunnelConnector::new(url);
|
||||||
|
|||||||
@@ -201,9 +201,21 @@ where
|
|||||||
Ok(T::from_url(url.clone(), IpVersion::Both)?)
|
Ok(T::from_url(url.clone(), IpVersion::Both)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_port(scheme: &str) -> Option<u16> {
|
||||||
|
match scheme {
|
||||||
|
"tcp" => Some(11010),
|
||||||
|
"udp" => Some(11010),
|
||||||
|
"ws" => Some(11011),
|
||||||
|
"wss" => Some(11012),
|
||||||
|
"quic" => Some(11012),
|
||||||
|
"wg" => Some(11011),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FromUrl for SocketAddr {
|
impl FromUrl for SocketAddr {
|
||||||
fn from_url(url: url::Url, ip_version: IpVersion) -> Result<Self, TunnelError> {
|
fn from_url(url: url::Url, ip_version: IpVersion) -> Result<Self, TunnelError> {
|
||||||
let addrs = url.socket_addrs(|| None)?;
|
let addrs = url.socket_addrs(|| default_port(url.scheme()))?;
|
||||||
tracing::debug!(?addrs, ?ip_version, ?url, "convert url to socket addrs");
|
tracing::debug!(?addrs, ?ip_version, ?url, "convert url to socket addrs");
|
||||||
let addrs = addrs
|
let addrs = addrs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
Reference in New Issue
Block a user