mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-02-09 01:59:16 +08:00
removed http proxy protocol, bump version to v1.1
This commit is contained in:
124
Cargo.lock
generated
124
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
||||
[root]
|
||||
name = "shadowsocks-rust"
|
||||
version = "1.0.3"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"base64 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -8,8 +8,6 @@ dependencies = [
|
||||
"env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ip 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -24,7 +22,6 @@ dependencies = [
|
||||
"serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -183,40 +180,6 @@ name = "glob"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"httparse 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-bidi 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.12.2"
|
||||
@@ -267,11 +230,6 @@ dependencies = [
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "language-tags"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.2"
|
||||
@@ -310,11 +268,6 @@ name = "lzw"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "1.0.1"
|
||||
@@ -333,14 +286,6 @@ dependencies = [
|
||||
"toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.4"
|
||||
@@ -523,14 +468,6 @@ name = "rustc-serialize"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "0.1.0"
|
||||
@@ -541,11 +478,6 @@ name = "scoped_threadpool"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "0.9.6"
|
||||
@@ -628,37 +560,6 @@ name = "toml"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "traitobject"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "typeable"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.0.3"
|
||||
@@ -677,15 +578,6 @@ dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "user32-sys"
|
||||
version = "0.2.0"
|
||||
@@ -752,16 +644,12 @@ dependencies = [
|
||||
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
|
||||
"checksum gif 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "01c7c19a035de94bd7afbaa62c241aadfbdf1a70f560b348d2312eafa566ca16"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum httparse 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a6e7a63e511f9edffbab707141fbb8707d1a3098615fb2adbd5769cdfcc9b17d"
|
||||
"checksum hyper 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "220407e5a263f110ec30a071787c9535918fdfc97def5680c90013c3f30c38c1"
|
||||
"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
|
||||
"checksum image 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fb38e372d9288be8fa60bea6f05342e4a35244c221cd9fe4c01ded02c86e60c"
|
||||
"checksum inflate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e7e0062d2dc2f17d2f13750d95316ae8a2ff909af0fda957084f5defd87c43bb"
|
||||
"checksum ip 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7349baf09910ffb475d8ea8a16f1bbe5ec2be295373feef33fb4fea658b8a0ef"
|
||||
"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c"
|
||||
"checksum jpeg-decoder 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "5c4ff3d14e7ef3522471ab712832c3dd50001f7fb7aa4cdc48af811d63b531e9"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||
"checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b"
|
||||
"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
|
||||
"checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5"
|
||||
@@ -769,10 +657,8 @@ dependencies = [
|
||||
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
|
||||
"checksum lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656fa4dfcb02bcf1063c592ba3ff6a5303ee1f2afe98c8a889e8b1a77c6dfdb7"
|
||||
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
|
||||
"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1"
|
||||
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
|
||||
"checksum metadeps 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829fffe7ea1d747e23f64be972991bc516b2f1ac2ae4a3b33d8bea150c410151"
|
||||
"checksum mime 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5c93a4bd787ddc6e7833c519b73a50883deb5863d76d9b71eb8216fb7f94e66"
|
||||
"checksum mio 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "eecdbdd49a849336e77b453f021c89972a2cfb5b51931a0026ae0ac4602de681"
|
||||
"checksum miow 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a78d2605eb97302c10cf944b8d96b0a2a890c52957caf92fcd1f24f69049579"
|
||||
"checksum net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "5edf9cb6be97212423aed9413dd4729d62b370b5e1c571750e882cebbbc1e3e2"
|
||||
@@ -793,10 +679,8 @@ dependencies = [
|
||||
"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
|
||||
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
|
||||
"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b"
|
||||
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
|
||||
"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
|
||||
"checksum scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef399c8893e8cb7aa9696e895427fab3a6bf265977bb96e126f24ddd2cda85a"
|
||||
"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
|
||||
"checksum serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0ae9a3c8b07c09dbe43022486d55a18c629a0618d2241e49829aaef9b6d862f9"
|
||||
"checksum serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cf37ce931677e98b4fa5e6469aaa3ab4b6228309ea33b1b22d3ec055adfc4515"
|
||||
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
|
||||
@@ -807,15 +691,9 @@ dependencies = [
|
||||
"checksum time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "211b63c112206356ef1ff9b19355f43740fc3f85960c598a93d3a3d3ba7beade"
|
||||
"checksum tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3d1be481b55126f02ef88ff86748086473cb537a949fc4a8f4be403a530ae54b"
|
||||
"checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4"
|
||||
"checksum traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "07eaeb7689bb7fca7ce15628319635758eda769fed481ecfe6686ddef2600616"
|
||||
"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
|
||||
"checksum unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a5906ca2b98c799f4b1ab4557b76367ebd6ae5ef14930ec841c74aed5f3764"
|
||||
"checksum unicode-bidi 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b61814f3e7fd0e0f15370f767c7c943e08bc2e3214233ae8f88522b334ceb778"
|
||||
"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff"
|
||||
"checksum unicode-segmentation 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3c5336c5173d8a77ae0b36151c706e32ae10f4985e29d704ad5b5f9565d6d4b6"
|
||||
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
||||
"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91"
|
||||
"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e"
|
||||
"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "shadowsocks-rust"
|
||||
version = "1.0.3"
|
||||
version = "1.1.0"
|
||||
authors = ["Y. T. CHUNG <zonyitoo@gmail.com>"]
|
||||
description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls."
|
||||
repository = "https://github.com/zonyitoo/shadowsocks-rust"
|
||||
@@ -52,9 +52,6 @@ ip = "1"
|
||||
openssl = "0.9"
|
||||
lru-cache = "0.1"
|
||||
libc = "0.2"
|
||||
hyper = "0.10"
|
||||
url = "1.4"
|
||||
httparse = "1.2"
|
||||
futures = "0.1"
|
||||
futures-cpupool = "0.1"
|
||||
tokio-core = "0.1"
|
||||
|
||||
@@ -256,7 +256,6 @@ pub enum ConfigType {
|
||||
pub struct Config {
|
||||
pub server: Vec<ServerConfig>,
|
||||
pub local: Option<ClientConfig>,
|
||||
pub http_proxy: Option<ClientConfig>,
|
||||
pub enable_udp: bool,
|
||||
pub timeout: Option<Duration>,
|
||||
pub forbidden_ip: HashSet<IpAddr>,
|
||||
@@ -340,7 +339,6 @@ impl Config {
|
||||
Config {
|
||||
server: Vec::new(),
|
||||
local: None,
|
||||
http_proxy: None,
|
||||
enable_udp: false,
|
||||
timeout: None,
|
||||
forbidden_ip: HashSet::new(),
|
||||
@@ -496,45 +494,6 @@ impl Config {
|
||||
} else if has_local_address ^ has_local_port {
|
||||
panic!("You have to provide `local_address` and `local_port` together");
|
||||
}
|
||||
|
||||
let has_proxy_addr = o.contains_key("local_http_address");
|
||||
let has_proxy_port = o.contains_key("local_http_port");
|
||||
|
||||
if has_proxy_addr && has_proxy_port {
|
||||
config.http_proxy = match o.get("local_http_address") {
|
||||
Some(local_addr) => {
|
||||
let addr_str = try!(local_addr.as_str()
|
||||
.ok_or(Error::new(ErrorKind::Malformed,
|
||||
"`local_http_address` should be a string",
|
||||
None)));
|
||||
|
||||
let port = try!(o.get("local_http_port")
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.ok_or(Error::new(ErrorKind::Malformed,
|
||||
"`local_http_port` should be an integer",
|
||||
None))) as u16;
|
||||
|
||||
match addr_str.parse::<Ipv4Addr>() {
|
||||
Ok(ip) => Some(SocketAddr::V4(SocketAddrV4::new(ip, port))),
|
||||
Err(..) => {
|
||||
match addr_str.parse::<Ipv6Addr>() {
|
||||
Ok(ip) => Some(SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0))),
|
||||
Err(..) => {
|
||||
return Err(Error::new(ErrorKind::Malformed,
|
||||
"`local_http_address` is not a valid IP \
|
||||
address",
|
||||
None))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
} else if has_proxy_addr ^ has_proxy_port {
|
||||
panic!("You have to provide `local_http_address` and `local_http_port` together");
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(forbidden_ip_conf) = o.get("forbidden_ip") {
|
||||
|
||||
@@ -102,9 +102,6 @@ extern crate rand;
|
||||
extern crate crypto as rust_crypto;
|
||||
extern crate ip;
|
||||
extern crate openssl;
|
||||
extern crate hyper;
|
||||
extern crate url;
|
||||
extern crate httparse;
|
||||
|
||||
extern crate futures;
|
||||
extern crate futures_cpupool;
|
||||
|
||||
@@ -1,668 +0,0 @@
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2014 Y. T. CHUNG <zonyitoo@gmail.com>
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
/// Http Proxy
|
||||
|
||||
use std::io::{self, BufRead, BufReader, Write};
|
||||
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::mem;
|
||||
use std::str;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
use hyper::uri::RequestUri;
|
||||
use hyper::header::{Header, HeaderFormat, Headers, ContentLength};
|
||||
use hyper::header::{Connection, ConnectionOption};
|
||||
use hyper::status::StatusCode;
|
||||
use hyper::version::HttpVersion;
|
||||
use hyper::method::Method;
|
||||
use hyper;
|
||||
|
||||
use httparse::{self, Request};
|
||||
|
||||
use url::Host;
|
||||
|
||||
use ip::IpAddr;
|
||||
|
||||
use futures::{self, Future, Poll};
|
||||
use futures::stream::Stream;
|
||||
|
||||
use tokio_core::net::{TcpStream, TcpListener};
|
||||
use tokio_core::reactor::Handle;
|
||||
use tokio_core::io::Io;
|
||||
use tokio_core::io::{ReadHalf, WriteHalf};
|
||||
use tokio_core::io::{flush, write_all, copy};
|
||||
|
||||
use net2::TcpBuilder;
|
||||
|
||||
use config::{Config, ServerConfig};
|
||||
|
||||
use relay::socks5::Address;
|
||||
use relay::loadbalancing::server::RoundRobin;
|
||||
use relay::loadbalancing::server::LoadBalancer;
|
||||
use relay::{BoxIoFuture, boxed_future};
|
||||
|
||||
use super::tunnel;
|
||||
use super::stream::EncryptedWriter;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HttpRequest {
|
||||
pub version: HttpVersion,
|
||||
pub method: Method,
|
||||
pub request_uri: RequestUri,
|
||||
pub headers: Headers,
|
||||
}
|
||||
|
||||
impl HttpRequest {
|
||||
pub fn from_raw<'headers, 'buf: 'headers>(req: &Request<'headers, 'buf>,
|
||||
headers: &'headers [httparse::Header])
|
||||
-> hyper::Result<HttpRequest> {
|
||||
|
||||
let mut he = Headers::new();
|
||||
for h in headers.iter() {
|
||||
if h.name.len() == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
he.append_raw(h.name.to_owned(), h.value.to_vec());
|
||||
}
|
||||
|
||||
Ok(HttpRequest {
|
||||
version: if req.version.unwrap() == 1 {
|
||||
HttpVersion::Http11
|
||||
} else {
|
||||
HttpVersion::Http10
|
||||
},
|
||||
method: try!(req.method.unwrap().parse::<Method>()),
|
||||
request_uri: try!(req.path.unwrap().parse::<RequestUri>()),
|
||||
headers: he,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn clear_request_uri_host(&mut self) {
|
||||
let ptr = &mut self.request_uri as *mut RequestUri;
|
||||
match &mut self.request_uri {
|
||||
&mut RequestUri::AbsoluteUri(ref url) => {
|
||||
let mut abs = String::new();
|
||||
abs += url.path();
|
||||
if let Some(query) = url.query() {
|
||||
abs += "?";
|
||||
abs += query;
|
||||
}
|
||||
|
||||
if let Some(frag) = url.fragment() {
|
||||
abs += "#";
|
||||
abs += frag;
|
||||
}
|
||||
|
||||
// Force replace
|
||||
let unsafe_ref = unsafe { &mut *ptr };
|
||||
::std::mem::replace(unsafe_ref, RequestUri::AbsolutePath(abs));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes request into an EncryptedWriter
|
||||
pub fn write_to_encrypted<W>(self, w: EncryptedWriter<W>) -> BoxIoFuture<EncryptedWriter<W>>
|
||||
where W: Write + 'static
|
||||
{
|
||||
let fut = futures::lazy(move || {
|
||||
let mut w = Vec::new();
|
||||
try!(write!(w,
|
||||
"{} {} {}\r\n",
|
||||
self.method,
|
||||
self.request_uri,
|
||||
self.version));
|
||||
|
||||
for header in self.headers.iter() {
|
||||
if !header.name().is_empty() {
|
||||
try!(write!(w, "{}: {}\r\n", header.name(), header.value_string()));
|
||||
}
|
||||
}
|
||||
|
||||
try!(write!(w, "\r\n"));
|
||||
|
||||
Ok(w)
|
||||
})
|
||||
.and_then(|buf| w.write_all_encrypted(buf))
|
||||
.map(|(w, _)| w);
|
||||
|
||||
Box::new(fut)
|
||||
}
|
||||
|
||||
/// Get Socks5 address from URI
|
||||
#[inline]
|
||||
pub fn get_address(&self) -> Result<Address, StatusCode> {
|
||||
get_address(&self.request_uri)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_address(uri: &RequestUri) -> Result<Address, StatusCode> {
|
||||
match uri {
|
||||
&RequestUri::Authority(ref s) => {
|
||||
match s.parse::<SocketAddr>() {
|
||||
Ok(addr) => Ok(Address::SocketAddress(addr)),
|
||||
Err(_) => {
|
||||
let mut sp = s.splitn(2, ':');
|
||||
match (sp.next(), sp.next()) {
|
||||
(Some(host), Some(port)) => {
|
||||
let port = match port.parse::<u16>() {
|
||||
Ok(port) => port,
|
||||
Err(err) => {
|
||||
error!("Failed to parse Url, {}", err);
|
||||
return Err(StatusCode::BadRequest);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Address::DomainNameAddress(host.to_owned(), port))
|
||||
}
|
||||
(host, port) => {
|
||||
error!("Failed to parse Url, {:?}:{:?}", host, port);
|
||||
return Err(StatusCode::BadRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&RequestUri::AbsoluteUri(ref uri) => {
|
||||
if !uri.has_host() {
|
||||
error!("URI does not have Host: {:?}", uri);
|
||||
return Err(StatusCode::BadRequest);
|
||||
}
|
||||
|
||||
let port = uri.port_or_known_default().unwrap_or(80);
|
||||
|
||||
let addr = match uri.host().unwrap() {
|
||||
Host::Domain(dom) => Address::DomainNameAddress(dom.to_owned(), port),
|
||||
Host::Ipv4(v4) => Address::SocketAddress(SocketAddr::V4(SocketAddrV4::new(v4, port))),
|
||||
Host::Ipv6(v6) => Address::SocketAddress(SocketAddr::V6(SocketAddrV6::new(v6, port, 0, 0))),
|
||||
};
|
||||
|
||||
Ok(addr)
|
||||
}
|
||||
u => {
|
||||
error!("Invalid Uri {:?}", u);
|
||||
Err(StatusCode::BadRequest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_response<W>(w: W, version: HttpVersion, status: StatusCode) -> BoxIoFuture<W>
|
||||
where W: Write + 'static
|
||||
{
|
||||
let buf = format!("{} {}\r\n\r\n", version, status);
|
||||
Box::new(write_all(w, buf.into_bytes()).map(|(w, _)| w))
|
||||
}
|
||||
|
||||
/// X-Forward-For header
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct XForwardFor(pub Vec<IpAddr>);
|
||||
|
||||
impl Header for XForwardFor {
|
||||
fn header_name() -> &'static str {
|
||||
"X-Forward-For"
|
||||
}
|
||||
|
||||
fn parse_header(raw: &[Vec<u8>]) -> hyper::Result<XForwardFor> {
|
||||
let mut ips = Vec::new();
|
||||
for raw_h in raw.iter() {
|
||||
let xfor = try!(str::from_utf8(&raw_h[..]));
|
||||
for xfor_str in xfor.split(',') {
|
||||
let trimmed = xfor_str.trim();
|
||||
if trimmed.is_empty() {
|
||||
// Ignore empty string
|
||||
continue;
|
||||
}
|
||||
match trimmed.parse::<IpAddr>() {
|
||||
Ok(i) => ips.push(i),
|
||||
Err(..) => return Err(hyper::Error::Header),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(XForwardFor(ips))
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for XForwardFor {
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut first = true;
|
||||
for ip in &self.0 {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
try!(write!(f, ", "));
|
||||
}
|
||||
|
||||
try!(write!(f, "{}", ip));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// X-Real-IP header
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct XRealIp(pub IpAddr);
|
||||
|
||||
impl Header for XRealIp {
|
||||
fn header_name() -> &'static str {
|
||||
"X-Real-IP"
|
||||
}
|
||||
|
||||
fn parse_header(raw: &[Vec<u8>]) -> hyper::Result<XRealIp> {
|
||||
let mut ip = None;
|
||||
for raw_ip in raw.iter() {
|
||||
let x_ip = try!(str::from_utf8(&raw_ip[..]));
|
||||
match x_ip.trim().parse::<IpAddr>() {
|
||||
Ok(i) => {
|
||||
if let Some(prev_ip) = ip.take() {
|
||||
if prev_ip != i {
|
||||
return Err(hyper::Error::Header);
|
||||
}
|
||||
}
|
||||
|
||||
ip = Some(i);
|
||||
}
|
||||
Err(..) => return Err(hyper::Error::Header),
|
||||
}
|
||||
}
|
||||
|
||||
match ip {
|
||||
Some(ip) => Ok(XRealIp(ip)),
|
||||
None => Err(hyper::Error::Header),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderFormat for XRealIp {
|
||||
#[inline]
|
||||
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Future for reading HttpRequest
|
||||
pub enum HttpRequestFut<R>
|
||||
where R: BufRead
|
||||
{
|
||||
Pending { r: R, buf: Vec<u8> },
|
||||
Empty,
|
||||
}
|
||||
|
||||
impl<R> HttpRequestFut<R>
|
||||
where R: BufRead
|
||||
{
|
||||
pub fn new(r: R) -> HttpRequestFut<R> {
|
||||
HttpRequestFut::with_buf(r, Vec::new())
|
||||
}
|
||||
|
||||
pub fn with_buf(r: R, buf: Vec<u8>) -> HttpRequestFut<R> {
|
||||
HttpRequestFut::Pending { r: r, buf: buf }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Future for HttpRequestFut<R>
|
||||
where R: BufRead
|
||||
{
|
||||
type Item = (R, HttpRequest);
|
||||
type Error = io::Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
let req = match self {
|
||||
&mut HttpRequestFut::Pending { ref mut r, ref mut buf } => {
|
||||
// FIXME: Compiler force me to do this!
|
||||
let http_req: Option<HttpRequest>;
|
||||
loop {
|
||||
let mut is_eof = false;
|
||||
loop {
|
||||
let n = try_nb!(r.read_until(b'\n', buf));
|
||||
if n == 0 {
|
||||
is_eof = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if buf.ends_with(b"\r\n\r\n") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Maximum 128 headers
|
||||
let mut headers = [httparse::EMPTY_HEADER; 128];
|
||||
let headers_ptr = &headers as *const _;
|
||||
let mut req = Request::new(&mut headers);
|
||||
match req.parse(&mut buf[..]) {
|
||||
Ok(httparse::Status::Partial) => {
|
||||
if is_eof {
|
||||
// Already EOF!
|
||||
let err = io::Error::new(io::ErrorKind::UnexpectedEof, "Unexpected Eof");
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
Ok(httparse::Status::Complete(..)) => {
|
||||
|
||||
// Make borrow checker happy
|
||||
let headers_ref = unsafe { &*headers_ptr };
|
||||
let hreq = match HttpRequest::from_raw(&req, headers_ref) {
|
||||
Ok(r) => r,
|
||||
Err(err) => {
|
||||
error!("HttpRequest::from_raw: {}", err);
|
||||
let err = io::Error::new(io::ErrorKind::Other, "Hyper error");
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
http_req = Some(hreq);
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Request parse: {:?}", err);
|
||||
let err = io::Error::new(io::ErrorKind::Other, "Hyper error");
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
http_req.unwrap()
|
||||
}
|
||||
&mut HttpRequestFut::Empty => panic!("poll a HttpRequestFut after it's done"),
|
||||
};
|
||||
|
||||
match mem::replace(self, HttpRequestFut::Empty) {
|
||||
HttpRequestFut::Pending { r, .. } => Ok((r, req).into()),
|
||||
HttpRequestFut::Empty => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn socket_to_ip(addr: &SocketAddr) -> IpAddr {
|
||||
match *addr {
|
||||
SocketAddr::V4(ref v4) => IpAddr::V4(v4.ip().clone()),
|
||||
SocketAddr::V6(ref v6) => IpAddr::V6(v6.ip().clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn preprocess_request(client_addr: Option<&SocketAddr>, req: &mut HttpRequest) -> usize {
|
||||
// Gets content length for body
|
||||
let content_length = req.headers.get::<ContentLength>().unwrap_or(&ContentLength(0)).0 as usize;
|
||||
|
||||
if let Some(client_addr) = client_addr {
|
||||
let client_ip = socket_to_ip(client_addr);
|
||||
|
||||
// Set proxy IP info
|
||||
let xf = if let Some(fw) = req.headers.get_mut::<XForwardFor>() {
|
||||
let mut flst = fw.0.clone();
|
||||
flst.push(client_ip.clone());
|
||||
flst
|
||||
} else {
|
||||
vec![client_ip.clone()]
|
||||
};
|
||||
req.headers.set(XForwardFor(xf));
|
||||
|
||||
// Set real ip
|
||||
req.headers.set(XRealIp(client_ip));
|
||||
}
|
||||
|
||||
// Clears host, which only for proxy
|
||||
req.clear_request_uri_host();
|
||||
|
||||
content_length
|
||||
}
|
||||
|
||||
/// Proxy this HTTP Request to writer
|
||||
pub fn proxy_request_encrypted<R, W>((r, w): (R, EncryptedWriter<W>),
|
||||
client_addr: Option<&SocketAddr>,
|
||||
mut req: HttpRequest)
|
||||
-> BoxIoFuture<(R, EncryptedWriter<W>)>
|
||||
where R: BufRead + 'static,
|
||||
W: Write + 'static
|
||||
{
|
||||
let content_length = preprocess_request(client_addr, &mut req);
|
||||
|
||||
let fut = req.write_to_encrypted(w)
|
||||
.and_then(|w| flush(w))
|
||||
.and_then(move |w| super::copy_exact_encrypted(r, w, content_length));
|
||||
Box::new(fut)
|
||||
}
|
||||
|
||||
/// Check `Connection` header to determine whether we should keep alive
|
||||
pub fn should_keep_alive(req: &HttpRequest) -> bool {
|
||||
let default_keep_alive = req.version >= HttpVersion::Http11;
|
||||
match req.headers.get::<Connection>() {
|
||||
Some(conn) => {
|
||||
for opt in conn.iter() {
|
||||
if let &ConnectionOption::KeepAlive = opt {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
default_keep_alive
|
||||
}
|
||||
None => default_keep_alive,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_connect(handle: Handle,
|
||||
(r, w): (BufReader<ReadHalf<TcpStream>>, WriteHalf<TcpStream>),
|
||||
req: HttpRequest,
|
||||
addr: Address,
|
||||
svr_cfg: Rc<ServerConfig>)
|
||||
-> Box<Future<Item = (), Error = io::Error>> {
|
||||
let cloned_addr = addr.clone();
|
||||
let http_version = req.version;
|
||||
let cloned_svr_cfg = svr_cfg.clone();
|
||||
|
||||
let fut = super::connect_proxy_server(&handle, svr_cfg)
|
||||
.and_then(move |svr_s| {
|
||||
trace!("Proxy server connected");
|
||||
|
||||
// Tell the client that we are ready
|
||||
let handshake_resp = format!("{} 200 Connection Established\r\n\r\n", http_version);
|
||||
trace!("Sending HTTP tunnel handshake response");
|
||||
write_all(w, handshake_resp.into_bytes())
|
||||
.and_then(|(w, _)| flush(w))
|
||||
.map(|w| (svr_s, w))
|
||||
})
|
||||
.and_then(move |(svr_s, w)| {
|
||||
super::proxy_server_handshake(svr_s, cloned_svr_cfg, addr).and_then(move |(svr_r, svr_w)| {
|
||||
let rhalf = svr_r.and_then(move |svr_r| copy(svr_r, w));
|
||||
let whalf = svr_w.and_then(move |svr_w| svr_w.copy_from_encrypted(r));
|
||||
tunnel(cloned_addr, whalf, rhalf)
|
||||
})
|
||||
});
|
||||
|
||||
Box::new(fut)
|
||||
}
|
||||
|
||||
fn handle_http_keepalive(r: BufReader<ReadHalf<TcpStream>>, svr_w: super::EncryptedHalf) -> BoxIoFuture<()> {
|
||||
let fut = HttpRequestFut::new(r).then(|res| {
|
||||
match res {
|
||||
Ok((r, req)) => {
|
||||
let should_keep_alive = should_keep_alive(&req);
|
||||
trace!("Going to proxy request: {:?}", req);
|
||||
trace!("Should keep alive? {}", should_keep_alive);
|
||||
|
||||
let fut = proxy_request_encrypted((r, svr_w), None, req).and_then(move |(r, svr_w)| {
|
||||
if should_keep_alive {
|
||||
handle_http_keepalive(r, svr_w)
|
||||
} else {
|
||||
futures::finished(()).boxed()
|
||||
}
|
||||
});
|
||||
Box::new(fut) as BoxIoFuture<()>
|
||||
}
|
||||
Err(err) => {
|
||||
let fut = futures::lazy(|| {
|
||||
use std::io::ErrorKind;
|
||||
match err.kind() {
|
||||
// It is Ok for client to close connection
|
||||
ErrorKind::UnexpectedEof | ErrorKind::BrokenPipe => Ok(()),
|
||||
_ => Err(err),
|
||||
}
|
||||
});
|
||||
Box::new(fut) as BoxIoFuture<()>
|
||||
}
|
||||
}
|
||||
});
|
||||
Box::new(fut)
|
||||
}
|
||||
|
||||
fn handle_http_proxy(handle: Handle,
|
||||
(r, w): (BufReader<ReadHalf<TcpStream>>, WriteHalf<TcpStream>),
|
||||
client_addr: &SocketAddr,
|
||||
req: HttpRequest,
|
||||
addr: Address,
|
||||
svr_cfg: Rc<ServerConfig>)
|
||||
-> Box<Future<Item = (), Error = io::Error>> {
|
||||
trace!("Using HTTP Proxy for {} -> {}", client_addr, addr);
|
||||
|
||||
let should_keep_alive = should_keep_alive(&req);
|
||||
let fut = super::connect_proxy_server(&handle, svr_cfg.clone()).and_then(move |svr_s| {
|
||||
trace!("Proxy server connected");
|
||||
|
||||
let cloned_addr = addr.clone();
|
||||
super::proxy_server_handshake(svr_s, svr_cfg, addr).and_then(move |(svr_r, svr_w)| {
|
||||
|
||||
// Just proxy anything to client
|
||||
let rhalf = svr_r.and_then(move |svr_r| copy(svr_r, w));
|
||||
let whalf = svr_w.and_then(move |svr_w| {
|
||||
// Send the first request to server
|
||||
trace!("Going to proxy request: {:?}", req);
|
||||
trace!("Should keep alive? {}", should_keep_alive);
|
||||
|
||||
proxy_request_encrypted((r, svr_w), None, req).and_then(move |(r, svr_w)| {
|
||||
if should_keep_alive {
|
||||
handle_http_keepalive(r, svr_w)
|
||||
} else {
|
||||
futures::finished(()).boxed()
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
let fut = rhalf.join(whalf)
|
||||
.then(move |_| {
|
||||
trace!("Relay to {} is finished", cloned_addr);
|
||||
Ok(())
|
||||
});
|
||||
boxed_future(fut)
|
||||
})
|
||||
});
|
||||
|
||||
Box::new(fut)
|
||||
}
|
||||
|
||||
fn handle_client(handle: &Handle, socket: TcpStream, _: SocketAddr, svr_cfg: Rc<ServerConfig>) -> io::Result<()> {
|
||||
let cloned_handle = handle.clone();
|
||||
let client_addr = try!(socket.peer_addr());
|
||||
let fut = futures::lazy(|| Ok(socket.split()))
|
||||
.and_then(|(r, w)| {
|
||||
// Process the first request to see whether client wants CONNECT tunnel or normal HTTP proxy
|
||||
|
||||
let r = BufReader::new(r);
|
||||
|
||||
HttpRequestFut::new(r).and_then(move |(r, mut req)| {
|
||||
trace!("Got HTTP Request, version: {}, method: {}, uri: {}",
|
||||
req.version,
|
||||
req.method,
|
||||
req.request_uri);
|
||||
|
||||
match req.get_address() {
|
||||
Ok(addr) => {
|
||||
req.clear_request_uri_host();
|
||||
boxed_future(futures::finished((r, w, req, addr)))
|
||||
}
|
||||
Err(status_code) => {
|
||||
error!("Invalid Uri: {}", req.request_uri);
|
||||
let fut = write_response(w, req.version, status_code).then(|_| {
|
||||
let err = io::Error::new(io::ErrorKind::Other, "Invalid Uri");
|
||||
Err(err)
|
||||
});
|
||||
boxed_future(fut)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
.and_then(move |(r, w, req, addr)| {
|
||||
match req.method.clone() {
|
||||
Method::Connect => {
|
||||
info!("CONNECT (Http) {}", addr);
|
||||
handle_connect(cloned_handle, (r, w), req, addr, svr_cfg)
|
||||
}
|
||||
met => {
|
||||
info!("{} (Http) {}", met, addr);
|
||||
handle_http_proxy(cloned_handle, (r, w), &client_addr, req, addr, svr_cfg)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
handle.spawn(fut.then(|res| {
|
||||
match res {
|
||||
Ok(..) => Ok(()),
|
||||
Err(err) => {
|
||||
if err.kind() != io::ErrorKind::BrokenPipe {
|
||||
error!("Failed to handle client: {}", err);
|
||||
}
|
||||
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// TCP local server using HTTP proxy protocol
|
||||
pub fn run(config: Rc<Config>, handle: Handle) -> Box<Future<Item = (), Error = io::Error>> {
|
||||
let listener = {
|
||||
let local_addr = config.http_proxy.as_ref().unwrap();
|
||||
|
||||
let tcp_builder = match local_addr {
|
||||
&SocketAddr::V4(..) => TcpBuilder::new_v4(),
|
||||
&SocketAddr::V6(..) => TcpBuilder::new_v6(),
|
||||
}
|
||||
.unwrap_or_else(|err| panic!("Failed to create listener, {}", err));
|
||||
|
||||
super::reuse_port(&tcp_builder)
|
||||
.and_then(|builder| builder.reuse_address(true))
|
||||
.and_then(|builder| builder.bind(local_addr))
|
||||
.unwrap_or_else(|err| panic!("Failed to bind {}, {}", local_addr, err));
|
||||
|
||||
let listener = tcp_builder.listen(1024)
|
||||
.and_then(|l| TcpListener::from_listener(l, local_addr, &handle))
|
||||
.unwrap_or_else(|err| panic!("Failed to listen, {}", err));
|
||||
info!("ShadowSocks HTTP Listening on {}", local_addr);
|
||||
listener
|
||||
};
|
||||
|
||||
let mut servers = RoundRobin::new(&*config);
|
||||
let listening = listener.incoming()
|
||||
.for_each(move |(socket, addr)| {
|
||||
let server_cfg = servers.pick_server();
|
||||
trace!("Got connection, addr: {}", addr);
|
||||
trace!("Picked proxy server: {:?}", server_cfg);
|
||||
handle_client(&handle, socket, addr, server_cfg)
|
||||
});
|
||||
|
||||
Box::new(listening.map_err(|err| {
|
||||
error!("HTTP server run failed: {}", err);
|
||||
err
|
||||
}))
|
||||
}
|
||||
@@ -23,8 +23,6 @@
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use futures::Future;
|
||||
|
||||
use tokio_core::reactor::Handle;
|
||||
|
||||
use config::Config;
|
||||
@@ -32,17 +30,9 @@ use config::Config;
|
||||
use relay::{BoxIoFuture, boxed_future};
|
||||
|
||||
use super::socks5_local;
|
||||
use super::http_local;
|
||||
|
||||
/// Starts a TCP local server
|
||||
pub fn run(config: Rc<Config>, handle: Handle) -> BoxIoFuture<()> {
|
||||
let tcp_fut = socks5_local::run(config.clone(), handle.clone());
|
||||
match &config.http_proxy {
|
||||
&Some(..) => {
|
||||
let http_fut = http_local::run(config, handle);
|
||||
boxed_future(tcp_fut.join(http_fut)
|
||||
.map(|_| ()))
|
||||
}
|
||||
&None => tcp_fut,
|
||||
}
|
||||
boxed_future(tcp_fut)
|
||||
}
|
||||
|
||||
@@ -21,11 +21,10 @@
|
||||
|
||||
//! TcpRelay implementation
|
||||
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io::{self, Read};
|
||||
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::rc::Rc;
|
||||
use std::mem;
|
||||
use std::cmp;
|
||||
|
||||
use crypto::cipher;
|
||||
use crypto::CryptoMode;
|
||||
@@ -50,7 +49,6 @@ use self::stream::{EncryptedWriter, DecryptedReader};
|
||||
|
||||
pub mod local;
|
||||
mod socks5_local;
|
||||
mod http_local;
|
||||
pub mod server;
|
||||
mod stream;
|
||||
pub mod client;
|
||||
@@ -165,109 +163,6 @@ pub fn proxy_handshake(remote_stream: TcpStream,
|
||||
boxed_future(fut)
|
||||
}
|
||||
|
||||
/// Copy exactly N bytes by encryption
|
||||
pub enum CopyExactEncrypted<R, W>
|
||||
where R: Read,
|
||||
W: Write
|
||||
{
|
||||
Pending {
|
||||
reader: R,
|
||||
writer: EncryptedWriter<W>,
|
||||
buf: [u8; 4096],
|
||||
remain: usize,
|
||||
pos: usize,
|
||||
cap: usize,
|
||||
enc_buf: Vec<u8>,
|
||||
},
|
||||
Empty,
|
||||
}
|
||||
|
||||
impl<R, W> CopyExactEncrypted<R, W>
|
||||
where R: Read,
|
||||
W: Write
|
||||
{
|
||||
pub fn new(r: R, w: EncryptedWriter<W>, amt: usize) -> CopyExactEncrypted<R, W> {
|
||||
CopyExactEncrypted::Pending {
|
||||
reader: r,
|
||||
writer: w,
|
||||
buf: [0u8; 4096],
|
||||
remain: amt,
|
||||
pos: 0,
|
||||
cap: 0,
|
||||
enc_buf: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, W> Future for CopyExactEncrypted<R, W>
|
||||
where R: Read,
|
||||
W: Write
|
||||
{
|
||||
type Item = (R, EncryptedWriter<W>);
|
||||
type Error = io::Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match self {
|
||||
&mut CopyExactEncrypted::Empty => panic!("poll after CopyExactEncrypted is finished"),
|
||||
&mut CopyExactEncrypted::Pending { ref mut reader,
|
||||
ref mut writer,
|
||||
ref mut buf,
|
||||
ref mut remain,
|
||||
ref mut pos,
|
||||
ref mut cap,
|
||||
ref mut enc_buf } => {
|
||||
loop {
|
||||
// If our buffer is empty, then we need to read some data to
|
||||
// continue.
|
||||
if *pos == *cap && *remain != 0 {
|
||||
let buf_len = cmp::min(*remain, buf.len());
|
||||
let n = try_nb!(reader.read(&mut buf[..buf_len]));
|
||||
if n == 0 {
|
||||
// Unexpected EOF!
|
||||
let err = io::Error::new(io::ErrorKind::UnexpectedEof, "Unexpected Eof");
|
||||
return Err(err);
|
||||
} else {
|
||||
*pos = 0;
|
||||
*remain -= n;
|
||||
|
||||
enc_buf.clear();
|
||||
try!(writer.cipher_update(&buf[..n], enc_buf));
|
||||
*cap = enc_buf.len();
|
||||
}
|
||||
}
|
||||
|
||||
// If our buffer has some data, let's write it out!
|
||||
while *pos < *cap {
|
||||
let i = try_nb!(writer.write(&enc_buf[*pos..*cap]));
|
||||
*pos += i;
|
||||
}
|
||||
|
||||
// If we've written al the data and we've seen EOF, flush out the
|
||||
// data and finish the transfer.
|
||||
// done with the entire transfer.
|
||||
if *pos == *cap && *remain == 0 {
|
||||
try_nb!(writer.flush());
|
||||
break; // The only path to execute the following logic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match mem::replace(self, CopyExactEncrypted::Empty) {
|
||||
CopyExactEncrypted::Pending { reader, writer, .. } => Ok((reader, writer).into()),
|
||||
CopyExactEncrypted::Empty => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy all bytes from reader and write all encrypted data into writer
|
||||
pub fn copy_exact_encrypted<R, W>(r: R, w: EncryptedWriter<W>, amt: usize) -> CopyExactEncrypted<R, W>
|
||||
where R: Read,
|
||||
W: Write
|
||||
{
|
||||
CopyExactEncrypted::new(r, w, amt)
|
||||
}
|
||||
|
||||
/// Establish tunnel between server and client
|
||||
pub fn tunnel<CF, SF>(addr: Address, c2s: CF, s2c: SF) -> BoxIoFuture<()>
|
||||
where CF: Future<Item = u64, Error = io::Error> + 'static,
|
||||
|
||||
Reference in New Issue
Block a user