mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-11-06 08:14:07 +00:00
Refactor some boxed futures with impl Trait
- Replaced EncryptedWriterFut and DecryptedReaderFut with impl Trait - Replaced boxed future in try_timeout and io_timeout with a static type - Modified rustfmt configuration, fully reformatted
This commit is contained in:
Generated
+160
-99
@@ -199,6 +199,16 @@ name = "checked_int_cast"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.32.0"
|
||||
@@ -450,7 +460,7 @@ dependencies = [
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -535,7 +545,7 @@ name = "lazy_static"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -570,7 +580,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -615,7 +625,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -623,6 +633,14 @@ name = "memoffset"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz-sys"
|
||||
version = "0.1.10"
|
||||
@@ -731,6 +749,19 @@ name = "nodrop"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.8.0"
|
||||
@@ -781,7 +812,7 @@ name = "parking_lot"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -991,7 +1022,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.28"
|
||||
version = "1.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1034,15 +1065,15 @@ dependencies = [
|
||||
"qrcode 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_urlencoded 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"subprocess 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"subprocess 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-signal 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"trust-dns-resolver 0.10.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"trust-dns-resolver 0.10.0-alpha.2 (git+https://github.com/bluejekyll/trust-dns)",
|
||||
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1093,7 +1124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "subprocess"
|
||||
version = "0.1.15"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1184,46 +1215,47 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-current-thread 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-fs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tcp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-threadpool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-timer 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-uds 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-codec"
|
||||
version = "0.1.0"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-current-thread 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-fs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-uds 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-codec"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-current-thread"
|
||||
version = "0.1.1"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-executor"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1235,13 +1267,13 @@ version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-threadpool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-io"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1251,7 +1283,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-reactor"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1262,8 +1294,8 @@ dependencies = [
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1272,7 +1304,7 @@ version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -1285,28 +1317,28 @@ dependencies = [
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tcp"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-threadpool"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1315,18 +1347,18 @@ dependencies = [
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-timer"
|
||||
version = "0.2.6"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1338,14 +1370,14 @@ dependencies = [
|
||||
"futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-uds"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1355,28 +1387,30 @@ dependencies = [
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trust-dns-https"
|
||||
version = "0.1.0-alpha.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/bluejekyll/trust-dns#3ebe2d6edce8ff696d87035498dd3800d9f4b33b"
|
||||
dependencies = [
|
||||
"bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-rustls 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tcp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"trust-dns-proto 0.5.0-alpha.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"trust-dns-rustls 0.4.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"trust-dns-proto 0.5.0-alpha.1 (git+https://github.com/bluejekyll/trust-dns)",
|
||||
"trust-dns-rustls 0.4.0-alpha.2 (git+https://github.com/bluejekyll/trust-dns)",
|
||||
"typed-headers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1384,7 +1418,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "trust-dns-proto"
|
||||
version = "0.5.0-alpha.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/bluejekyll/trust-dns#3ebe2d6edce8ff696d87035498dd3800d9f4b33b"
|
||||
dependencies = [
|
||||
"byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1395,11 +1429,11 @@ dependencies = [
|
||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tcp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-timer 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -1407,7 +1441,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "trust-dns-resolver"
|
||||
version = "0.10.0-alpha.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/bluejekyll/trust-dns#3ebe2d6edce8ff696d87035498dd3800d9f4b33b"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1419,26 +1453,39 @@ dependencies = [
|
||||
"resolv-conf 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"trust-dns-https 0.1.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"trust-dns-proto 0.5.0-alpha.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"trust-dns-rustls 0.4.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"trust-dns-https 0.1.0-alpha.2 (git+https://github.com/bluejekyll/trust-dns)",
|
||||
"trust-dns-proto 0.5.0-alpha.1 (git+https://github.com/bluejekyll/trust-dns)",
|
||||
"trust-dns-rustls 0.4.0-alpha.2 (git+https://github.com/bluejekyll/trust-dns)",
|
||||
"webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trust-dns-rustls"
|
||||
version = "0.4.0-alpha.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
source = "git+https://github.com/bluejekyll/trust-dns#3ebe2d6edce8ff696d87035498dd3800d9f4b33b"
|
||||
dependencies = [
|
||||
"futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-rustls 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tcp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"trust-dns-proto 0.5.0-alpha.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"trust-dns-proto 0.5.0-alpha.1 (git+https://github.com/bluejekyll/trust-dns)",
|
||||
"webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typed-headers"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.10.0"
|
||||
@@ -1449,6 +1496,14 @@ name = "ucd-util"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.4"
|
||||
@@ -1517,7 +1572,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -1667,6 +1722,7 @@ dependencies = [
|
||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
|
||||
"checksum checked_int_cast 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17cc5e6b5ab06331c33589842070416baa137e8b0eb912b008cfd4a78ada7919"
|
||||
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
|
||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||
"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
@@ -1711,13 +1767,14 @@ dependencies = [
|
||||
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
|
||||
"checksum libsodium-ffi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "68b36690c5fa7d3cf212f498f24e712b87a276979d622d9e121e22171ecafc4e"
|
||||
"checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939"
|
||||
"checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54"
|
||||
"checksum lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775751a3e69bde4df9b38dd00a1b5d6ac13791e4223d4a0506577f0dd27cfb7a"
|
||||
"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f"
|
||||
"checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21"
|
||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
"checksum md-5 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9402eaae33a9e144ce18ef488a0e4ca19869673c7bcdbbfe2030fdc3f84211cd"
|
||||
"checksum memchr 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4b3629fe9fdbff6daa6c33b90f7c08355c1aca05a3d01fa8063b822fcf185f3b"
|
||||
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
||||
"checksum mime 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "4b082692d3f6cf41b453af73839ce3dfc212c4411cbb2441dff80a716e38bd79"
|
||||
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
|
||||
"checksum miniz_oxide 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9ba430291c9d6cedae28bcd2d49d1c32fc57d60cd49086646c5dd5673a870eb5"
|
||||
"checksum miniz_oxide_c_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5a5b8234d6103ebfba71e29786da4608540f862de5ce980a1c94f86a40ca0d51"
|
||||
@@ -1728,6 +1785,8 @@ dependencies = [
|
||||
"checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
|
||||
"checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7"
|
||||
"checksum openssl 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5e2e79eede055813a3ac52fb3915caf8e1c9da2dec1587871aec9f6f7b48508d"
|
||||
@@ -1761,7 +1820,7 @@ dependencies = [
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)" = "84257ccd054dc351472528c8587b4de2dbf0dc0fe2e634030c1a90bfdacebaa9"
|
||||
"checksum serde_json 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "d30ec34ac923489285d24688c7a9c0898d16edff27fc1f1bd854edeff6ca3b7f"
|
||||
"checksum serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "bb47a3d5c84320222f66d7db21157c4a7407755de41798f9b4c1c40593397b1a"
|
||||
"checksum serde_urlencoded 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aaed41d9fb1e2f587201b863356590c90c1157495d811430a0c0325fe8169650"
|
||||
"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d"
|
||||
"checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d"
|
||||
@@ -1770,7 +1829,7 @@ dependencies = [
|
||||
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||
"checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970"
|
||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||
"checksum subprocess 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "782b7c981ee2a9a30a96e9b125d64156a68712dac069428684b31d100a6d21d7"
|
||||
"checksum subprocess 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "a085ed5b2586bb28a5793845331dac6c58afe7a343f52522cc016dbc943a6343"
|
||||
"checksum subtle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7a6bab57c3efd01ebd3d750f4244ae0af4cdd1fc505a7904a41603192b803c5"
|
||||
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
|
||||
"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
|
||||
@@ -1780,26 +1839,28 @@ dependencies = [
|
||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
|
||||
"checksum tokio 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fbb6a6e9db2702097bfdfddcb09841211ad423b86c75b5ddaca1d62842ac492c"
|
||||
"checksum tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "881e9645b81c2ce95fcb799ded2c29ffb9f25ef5bef909089a420e5961dd8ccb"
|
||||
"checksum tokio-current-thread 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fdfb899688ac16f618076bd09215edbfda0fd5dfecb375b6942636cb31fa8a7"
|
||||
"checksum tokio-executor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "84823b932d566bc3c6aa644df4ca36cb38593c50b7db06011fd4e12e31e4047e"
|
||||
"checksum tokio 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "b67db11af0b714dc0c6cd134e4189491623cd60fdcdf534e8d4d26fa3c46407d"
|
||||
"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f"
|
||||
"checksum tokio-current-thread 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f90fcd90952f0a496d438a976afba8e5c205fb12123f813d8ab3aa1c8436638c"
|
||||
"checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde"
|
||||
"checksum tokio-fs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5cbe4ca6e71cb0b62a66e4e6f53a8c06a6eefe46cc5f665ad6f274c9906f135"
|
||||
"checksum tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6cc2de7725863c86ac71b0b9068476fec50834f055a243558ef1655bbd34cb"
|
||||
"checksum tokio-reactor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4bfbaf9f260635649ec26b6fb4aded03887295ffcd999f6e43fd2c4758f758ea"
|
||||
"checksum tokio-io 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "8b8a85fffbec3c5ab1ab62324570230dcd37ee5996a7859da5caf7b9d45e3e8c"
|
||||
"checksum tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4b26fd37f1125738b2170c80b551f69ff6fecb277e6e5ca885e53eec2b005018"
|
||||
"checksum tokio-rustls 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "208d62fa3e015426e3c64039d9d20adf054a3c9b4d9445560f1c41c75bef3eab"
|
||||
"checksum tokio-signal 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b6893092932264944edee8486d54b578c7098bea794aedaf9bd7947b49e6b7bf"
|
||||
"checksum tokio-tcp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5b4c329b47f071eb8a746040465fa751bd95e4716e98daef6a9b4e434c17d565"
|
||||
"checksum tokio-threadpool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a5758cecb6e0633cea5d563ac07c975e04961690b946b04fd84e7d6445a8f6af"
|
||||
"checksum tokio-timer 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d03fa701f9578a01b7014f106b47f0a363b4727a7f3f75d666e312ab7acbbf1c"
|
||||
"checksum tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad235e9dadd126b2d47f6736f65aa1fdcd6420e66ca63f44177bc78df89f912"
|
||||
"checksum tokio-threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bbd8a8b911301c60cbfaa2a6588fb210e5c1038375b8bdecc47aa09a94c3c05f"
|
||||
"checksum tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3a52f00c97fedb6d535d27f65cccb7181c8dd4c6edc3eda9ea93f6d45d05168e"
|
||||
"checksum tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "da941144b816d0dcda4db3a1ba87596e4df5e860a72b70783fe435891f80601c"
|
||||
"checksum tokio-uds 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "424c1ed15a0132251813ccea50640b224c809d6ceafb88154c1a8775873a0e89"
|
||||
"checksum trust-dns-https 0.1.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a9e0478d560377fbf7ad0392ffaf8352cd9b7e5e763afee01be2edfd61eaf590"
|
||||
"checksum trust-dns-proto 0.5.0-alpha.1 (registry+https://github.com/rust-lang/crates.io-index)" = "117d25ce0cfc13c1b55f97d1a665c2aae1c218ccd91f64117e1903b841412c13"
|
||||
"checksum trust-dns-resolver 0.10.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a3cb4eec55b1494f438430ed74005d15cc9c134fa2b395a2d82630425fa58cc"
|
||||
"checksum trust-dns-rustls 0.4.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7694ad20bb17527508580111b89bb511548f9d550cf94a86b34b4b5f803524b4"
|
||||
"checksum tokio-uds 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22e3aa6d1fcc19e635418dc0a30ab5bd65d347973d6f43f1a37bf8d9d1335fc9"
|
||||
"checksum trust-dns-https 0.1.0-alpha.2 (git+https://github.com/bluejekyll/trust-dns)" = "<none>"
|
||||
"checksum trust-dns-proto 0.5.0-alpha.1 (git+https://github.com/bluejekyll/trust-dns)" = "<none>"
|
||||
"checksum trust-dns-resolver 0.10.0-alpha.2 (git+https://github.com/bluejekyll/trust-dns)" = "<none>"
|
||||
"checksum trust-dns-rustls 0.4.0-alpha.2 (git+https://github.com/bluejekyll/trust-dns)" = "<none>"
|
||||
"checksum typed-headers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fb9c89066fda8824c7c9570d0f5c0dddd2a0b272b189855f89450e830f196eb"
|
||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
|
||||
"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
@@ -1811,7 +1872,7 @@ dependencies = [
|
||||
"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4"
|
||||
"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d"
|
||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051"
|
||||
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f"
|
||||
"checksum webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85d1f408918fd590908a70d36b7ac388db2edc221470333e4d6e5b598e44cabf"
|
||||
|
||||
+2
-1
@@ -63,7 +63,8 @@ libsodium-ffi = { version = "0.1", optional = true }
|
||||
miscreant = { version = "0.4.0-beta", optional = true }
|
||||
lru-cache = "0.1"
|
||||
dns-parser = "0.7"
|
||||
trust-dns-resolver = { version = "0.10.0-alpha", features = ["dns-over-rustls", "dns-over-https"] }
|
||||
#trust-dns-resolver = { version = "0.10.0-alpha", features = ["dns-over-rustls", "dns-over-https"] }
|
||||
trust-dns-resolver = { git = "https://github.com/bluejekyll/trust-dns", features = ["dns-over-rustls", "dns-over-https-rustls"] }
|
||||
spin = "0.4"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
|
||||
+8
-3
@@ -1,12 +1,17 @@
|
||||
max_width = 120
|
||||
indent_style = "Visual"
|
||||
#indent_style = "Visual"
|
||||
#fn_call_width = 120
|
||||
reorder_imports = true
|
||||
reorder_imports_in_group = true
|
||||
reorder_imported_names = true
|
||||
reorder_modules = true
|
||||
#reorder_imports_in_group = true
|
||||
#reorder_imported_names = true
|
||||
condense_wildcard_suffixes = true
|
||||
#fn_args_layout = "Visual"
|
||||
#fn_call_style = "Visual"
|
||||
#chain_indent = "Visual"
|
||||
normalize_comments = true
|
||||
use_try_shorthand = true
|
||||
reorder_impl_items = true
|
||||
#use_small_heuristics = "Max"
|
||||
imports_layout = "HorizontalVertical"
|
||||
merge_imports = true
|
||||
|
||||
+149
-116
@@ -3,7 +3,6 @@
|
||||
//! You have to provide all needed configuration attributes via command line parameters,
|
||||
//! or you could specify a configuration file. The format of configuration file is defined
|
||||
//! in mod `config`.
|
||||
//!
|
||||
|
||||
extern crate clap;
|
||||
extern crate env_logger;
|
||||
@@ -14,47 +13,52 @@ extern crate shadowsocks;
|
||||
extern crate time;
|
||||
extern crate tokio;
|
||||
|
||||
use std::{
|
||||
env,
|
||||
io::{self, Write},
|
||||
net::SocketAddr,
|
||||
};
|
||||
|
||||
use clap::{App, Arg};
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use env_logger::fmt::Formatter;
|
||||
use env_logger::Builder;
|
||||
use env_logger::{fmt::Formatter, Builder};
|
||||
use futures::Future;
|
||||
use log::{LevelFilter, Record};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
use shadowsocks::plugin::PluginConfig;
|
||||
use shadowsocks::{run_local, Config, ConfigType, ServerAddr, ServerConfig};
|
||||
use shadowsocks::{plugin::PluginConfig, run_local, Config, ConfigType, ServerAddr, ServerConfig};
|
||||
|
||||
fn log_time(fmt: &mut Formatter, without_time: bool, record: &Record) -> io::Result<()> {
|
||||
if without_time {
|
||||
writeln!(fmt, "[{}] {}", record.level(), record.args())
|
||||
} else {
|
||||
writeln!(fmt,
|
||||
"[{}][{}] {}",
|
||||
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
|
||||
record.level(),
|
||||
record.args())
|
||||
writeln!(
|
||||
fmt,
|
||||
"[{}][{}] {}",
|
||||
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
|
||||
record.level(),
|
||||
record.args()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn log_time_module(fmt: &mut Formatter, without_time: bool, record: &Record) -> io::Result<()> {
|
||||
if without_time {
|
||||
writeln!(fmt,
|
||||
"[{}] [{}] {}",
|
||||
record.level(),
|
||||
record.module_path().unwrap_or("*"),
|
||||
record.args())
|
||||
writeln!(
|
||||
fmt,
|
||||
"[{}] [{}] {}",
|
||||
record.level(),
|
||||
record.module_path().unwrap_or("*"),
|
||||
record.args()
|
||||
)
|
||||
} else {
|
||||
writeln!(fmt,
|
||||
"[{}][{}] [{}] {}",
|
||||
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
|
||||
record.level(),
|
||||
record.module_path().unwrap_or("*"),
|
||||
record.args())
|
||||
writeln!(
|
||||
fmt,
|
||||
"[{}][{}] [{}] {}",
|
||||
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
|
||||
record.level(),
|
||||
record.module_path().unwrap_or("*"),
|
||||
record.args()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,54 +66,76 @@ fn main() {
|
||||
let matches = App::new("shadowsocks")
|
||||
.version(shadowsocks::VERSION)
|
||||
.about("A fast tunnel proxy that helps you bypass firewalls.")
|
||||
.arg(Arg::with_name("VERBOSE")
|
||||
.short("v")
|
||||
.multiple(true)
|
||||
.help("Set the level of debug"))
|
||||
.arg(Arg::with_name("ENABLE_UDP")
|
||||
.short("u")
|
||||
.long("enable-udp")
|
||||
.help("Enable UDP relay"))
|
||||
.arg(Arg::with_name("CONFIG")
|
||||
.short("c")
|
||||
.long("config")
|
||||
.takes_value(true)
|
||||
.help("Specify config file"))
|
||||
.arg(Arg::with_name("SERVER_ADDR")
|
||||
.short("s")
|
||||
.long("server-addr")
|
||||
.takes_value(true)
|
||||
.help("Server address"))
|
||||
.arg(Arg::with_name("LOCAL_ADDR")
|
||||
.short("b")
|
||||
.long("local-addr")
|
||||
.takes_value(true)
|
||||
.help("Local address, listen only to this address if specified"))
|
||||
.arg(Arg::with_name("PASSWORD")
|
||||
.short("k")
|
||||
.long("password")
|
||||
.takes_value(true)
|
||||
.help("Password"))
|
||||
.arg(Arg::with_name("ENCRYPT_METHOD")
|
||||
.short("m")
|
||||
.long("encrypt-method")
|
||||
.takes_value(true)
|
||||
.help("Encryption method"))
|
||||
.arg(Arg::with_name("PLUGIN")
|
||||
.long("plugin")
|
||||
.takes_value(true)
|
||||
.help("Enable SIP003 plugin"))
|
||||
.arg(Arg::with_name("PLUGIN_OPT")
|
||||
.long("plugin-opts")
|
||||
.takes_value(true)
|
||||
.help("Set SIP003 plugin options"))
|
||||
.arg(Arg::with_name("LOG_WITHOUT_TIME")
|
||||
.long("log-without-time")
|
||||
.help("Disable time in log"))
|
||||
.arg(Arg::with_name("URL")
|
||||
.long("server-url")
|
||||
.takes_value(true)
|
||||
.help("Server address in SIP002 URL"))
|
||||
.arg(
|
||||
Arg::with_name("VERBOSE")
|
||||
.short("v")
|
||||
.multiple(true)
|
||||
.help("Set the level of debug"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ENABLE_UDP")
|
||||
.short("u")
|
||||
.long("enable-udp")
|
||||
.help("Enable UDP relay"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("CONFIG")
|
||||
.short("c")
|
||||
.long("config")
|
||||
.takes_value(true)
|
||||
.help("Specify config file"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("SERVER_ADDR")
|
||||
.short("s")
|
||||
.long("server-addr")
|
||||
.takes_value(true)
|
||||
.help("Server address"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("LOCAL_ADDR")
|
||||
.short("b")
|
||||
.long("local-addr")
|
||||
.takes_value(true)
|
||||
.help("Local address, listen only to this address if specified"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("PASSWORD")
|
||||
.short("k")
|
||||
.long("password")
|
||||
.takes_value(true)
|
||||
.help("Password"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ENCRYPT_METHOD")
|
||||
.short("m")
|
||||
.long("encrypt-method")
|
||||
.takes_value(true)
|
||||
.help("Encryption method"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("PLUGIN")
|
||||
.long("plugin")
|
||||
.takes_value(true)
|
||||
.help("Enable SIP003 plugin"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("PLUGIN_OPT")
|
||||
.long("plugin-opts")
|
||||
.takes_value(true)
|
||||
.help("Set SIP003 plugin options"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("LOG_WITHOUT_TIME")
|
||||
.long("log-without-time")
|
||||
.help("Disable time in log"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("URL")
|
||||
.long("server-url")
|
||||
.takes_value(true)
|
||||
.help("Server address in SIP002 URL"),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let mut log_builder = Builder::new();
|
||||
@@ -129,13 +155,15 @@ fn main() {
|
||||
}
|
||||
2 => {
|
||||
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
|
||||
log_builder.filter(Some("sslocal"), LevelFilter::Debug)
|
||||
.filter(Some("shadowsocks"), LevelFilter::Debug);
|
||||
log_builder
|
||||
.filter(Some("sslocal"), LevelFilter::Debug)
|
||||
.filter(Some("shadowsocks"), LevelFilter::Debug);
|
||||
}
|
||||
3 => {
|
||||
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
|
||||
log_builder.filter(Some("sslocal"), LevelFilter::Trace)
|
||||
.filter(Some("shadowsocks"), LevelFilter::Trace);
|
||||
log_builder
|
||||
.filter(Some("sslocal"), LevelFilter::Trace)
|
||||
.filter(Some("shadowsocks"), LevelFilter::Trace);
|
||||
}
|
||||
_ => {
|
||||
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
|
||||
@@ -152,48 +180,51 @@ fn main() {
|
||||
let mut has_provided_config = false;
|
||||
|
||||
let mut config = match matches.value_of("CONFIG") {
|
||||
Some(cpath) => {
|
||||
match Config::load_from_file(cpath, ConfigType::Local) {
|
||||
Ok(cfg) => {
|
||||
has_provided_config = true;
|
||||
cfg
|
||||
}
|
||||
Err(err) => {
|
||||
error!("{:?}", err);
|
||||
return;
|
||||
}
|
||||
Some(cpath) => match Config::load_from_file(cpath, ConfigType::Local) {
|
||||
Ok(cfg) => {
|
||||
has_provided_config = true;
|
||||
cfg
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
error!("{:?}", err);
|
||||
return;
|
||||
}
|
||||
},
|
||||
None => Config::new(),
|
||||
};
|
||||
|
||||
let mut has_provided_server_config =
|
||||
match (matches.value_of("SERVER_ADDR"), matches.value_of("PASSWORD"), matches.value_of("ENCRYPT_METHOD")) {
|
||||
(Some(svr_addr), Some(password), Some(method)) => {
|
||||
let method = match method.parse() {
|
||||
Ok(m) => m,
|
||||
Err(err) => {
|
||||
panic!("Does not support {:?} method: {:?}", method, err);
|
||||
}
|
||||
};
|
||||
let mut has_provided_server_config = match (
|
||||
matches.value_of("SERVER_ADDR"),
|
||||
matches.value_of("PASSWORD"),
|
||||
matches.value_of("ENCRYPT_METHOD"),
|
||||
) {
|
||||
(Some(svr_addr), Some(password), Some(method)) => {
|
||||
let method = match method.parse() {
|
||||
Ok(m) => m,
|
||||
Err(err) => {
|
||||
panic!("Does not support {:?} method: {:?}", method, err);
|
||||
}
|
||||
};
|
||||
|
||||
let sc = ServerConfig::new(svr_addr.parse::<ServerAddr>().expect("Invalid server addr"),
|
||||
password.to_owned(),
|
||||
method,
|
||||
None,
|
||||
None);
|
||||
let sc = ServerConfig::new(
|
||||
svr_addr.parse::<ServerAddr>().expect("Invalid server addr"),
|
||||
password.to_owned(),
|
||||
method,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
config.server.push(sc);
|
||||
true
|
||||
}
|
||||
(None, None, None) => {
|
||||
// Does not provide server config
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
panic!("`server-addr`, `method` and `password` should be provided together");
|
||||
}
|
||||
};
|
||||
config.server.push(sc);
|
||||
true
|
||||
}
|
||||
(None, None, None) => {
|
||||
// Does not provide server config
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
panic!("`server-addr`, `method` and `password` should be provided together");
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(url) = matches.value_of("URL") {
|
||||
let svr_addr = url.parse::<ServerConfig>().expect("Failed to parse `url`");
|
||||
@@ -222,8 +253,10 @@ fn main() {
|
||||
config.enable_udp |= matches.is_present("ENABLE_UDP");
|
||||
|
||||
if let Some(p) = matches.value_of("PLUGIN") {
|
||||
let plugin = PluginConfig { plugin: p.to_owned(),
|
||||
plugin_opt: matches.value_of("PLUGIN_OPT").map(ToOwned::to_owned), };
|
||||
let plugin = PluginConfig {
|
||||
plugin: p.to_owned(),
|
||||
plugin_opt: matches.value_of("PLUGIN_OPT").map(ToOwned::to_owned),
|
||||
};
|
||||
|
||||
// Overrides config in file
|
||||
for svr in config.server.iter_mut() {
|
||||
|
||||
+129
-87
@@ -16,83 +16,116 @@ extern crate shadowsocks;
|
||||
extern crate time;
|
||||
extern crate tokio;
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
use std::{
|
||||
env,
|
||||
io::{self, Write},
|
||||
};
|
||||
|
||||
use clap::{App, Arg};
|
||||
|
||||
use env_logger::fmt::Formatter;
|
||||
use env_logger::Builder;
|
||||
use env_logger::{fmt::Formatter, Builder};
|
||||
use futures::Future;
|
||||
use log::{LevelFilter, Record};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
use shadowsocks::plugin::PluginConfig;
|
||||
use shadowsocks::{run_server, Config, ConfigType, ServerAddr, ServerConfig};
|
||||
use shadowsocks::{plugin::PluginConfig, run_server, Config, ConfigType, ServerAddr, ServerConfig};
|
||||
|
||||
fn log_time(fmt: &mut Formatter, without_time: bool, record: &Record) -> io::Result<()> {
|
||||
if without_time {
|
||||
writeln!(fmt, "[{}] {}", record.level(), record.args())
|
||||
} else {
|
||||
writeln!(fmt,
|
||||
"[{}][{}] {}",
|
||||
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
|
||||
record.level(),
|
||||
record.args())
|
||||
writeln!(
|
||||
fmt,
|
||||
"[{}][{}] {}",
|
||||
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
|
||||
record.level(),
|
||||
record.args()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn log_time_module(fmt: &mut Formatter, without_time: bool, record: &Record) -> io::Result<()> {
|
||||
if without_time {
|
||||
writeln!(fmt,
|
||||
"[{}] [{}] {}",
|
||||
record.level(),
|
||||
record.module_path().unwrap_or("*"),
|
||||
record.args())
|
||||
writeln!(
|
||||
fmt,
|
||||
"[{}] [{}] {}",
|
||||
record.level(),
|
||||
record.module_path().unwrap_or("*"),
|
||||
record.args()
|
||||
)
|
||||
} else {
|
||||
writeln!(fmt,
|
||||
"[{}][{}] [{}] {}",
|
||||
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
|
||||
record.level(),
|
||||
record.module_path().unwrap_or("*"),
|
||||
record.args())
|
||||
writeln!(
|
||||
fmt,
|
||||
"[{}][{}] [{}] {}",
|
||||
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
|
||||
record.level(),
|
||||
record.module_path().unwrap_or("*"),
|
||||
record.args()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let matches = App::new("shadowsocks").version(shadowsocks::VERSION)
|
||||
.about("A fast tunnel proxy that helps you bypass firewalls.")
|
||||
.arg(Arg::with_name("VERBOSE").short("v")
|
||||
.multiple(true)
|
||||
.help("Set the level of debug"))
|
||||
.arg(Arg::with_name("ENABLE_UDP").short("u")
|
||||
.long("enable-udp")
|
||||
.help("Enable UDP relay"))
|
||||
.arg(Arg::with_name("CONFIG").short("c")
|
||||
.long("config")
|
||||
.takes_value(true)
|
||||
.help("Specify config file"))
|
||||
.arg(Arg::with_name("SERVER_ADDR").short("s")
|
||||
.long("server-addr")
|
||||
.takes_value(true)
|
||||
.help("Server address"))
|
||||
.arg(Arg::with_name("PASSWORD").short("k")
|
||||
.long("password")
|
||||
.takes_value(true)
|
||||
.help("Password"))
|
||||
.arg(Arg::with_name("ENCRYPT_METHOD").short("m")
|
||||
.long("encrypt-method")
|
||||
.takes_value(true)
|
||||
.help("Encryption method"))
|
||||
.arg(Arg::with_name("PLUGIN").long("plugin")
|
||||
.takes_value(true)
|
||||
.help("Enable SIP003 plugin"))
|
||||
.arg(Arg::with_name("PLUGIN_OPT").long("plugin-opts")
|
||||
.takes_value(true)
|
||||
.help("Set SIP003 plugin options"))
|
||||
.arg(Arg::with_name("LOG_WITHOUT_TIME").long("log-without-time")
|
||||
.help("Disable time in log"))
|
||||
.get_matches();
|
||||
let matches = App::new("shadowsocks")
|
||||
.version(shadowsocks::VERSION)
|
||||
.about("A fast tunnel proxy that helps you bypass firewalls.")
|
||||
.arg(
|
||||
Arg::with_name("VERBOSE")
|
||||
.short("v")
|
||||
.multiple(true)
|
||||
.help("Set the level of debug"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ENABLE_UDP")
|
||||
.short("u")
|
||||
.long("enable-udp")
|
||||
.help("Enable UDP relay"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("CONFIG")
|
||||
.short("c")
|
||||
.long("config")
|
||||
.takes_value(true)
|
||||
.help("Specify config file"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("SERVER_ADDR")
|
||||
.short("s")
|
||||
.long("server-addr")
|
||||
.takes_value(true)
|
||||
.help("Server address"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("PASSWORD")
|
||||
.short("k")
|
||||
.long("password")
|
||||
.takes_value(true)
|
||||
.help("Password"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ENCRYPT_METHOD")
|
||||
.short("m")
|
||||
.long("encrypt-method")
|
||||
.takes_value(true)
|
||||
.help("Encryption method"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("PLUGIN")
|
||||
.long("plugin")
|
||||
.takes_value(true)
|
||||
.help("Enable SIP003 plugin"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("PLUGIN_OPT")
|
||||
.long("plugin-opts")
|
||||
.takes_value(true)
|
||||
.help("Set SIP003 plugin options"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("LOG_WITHOUT_TIME")
|
||||
.long("log-without-time")
|
||||
.help("Disable time in log"),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let mut log_builder = Builder::new();
|
||||
log_builder.filter(None, LevelFilter::Info);
|
||||
@@ -111,13 +144,15 @@ fn main() {
|
||||
}
|
||||
2 => {
|
||||
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
|
||||
log_builder.filter(Some("ssserver"), LevelFilter::Debug)
|
||||
.filter(Some("shadowsocks"), LevelFilter::Debug);
|
||||
log_builder
|
||||
.filter(Some("ssserver"), LevelFilter::Debug)
|
||||
.filter(Some("shadowsocks"), LevelFilter::Debug);
|
||||
}
|
||||
3 => {
|
||||
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
|
||||
log_builder.filter(Some("ssserver"), LevelFilter::Trace)
|
||||
.filter(Some("shadowsocks"), LevelFilter::Trace);
|
||||
log_builder
|
||||
.filter(Some("ssserver"), LevelFilter::Trace)
|
||||
.filter(Some("shadowsocks"), LevelFilter::Trace);
|
||||
}
|
||||
_ => {
|
||||
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
|
||||
@@ -146,33 +181,38 @@ fn main() {
|
||||
None => Config::new(),
|
||||
};
|
||||
|
||||
let has_provided_server_config =
|
||||
match (matches.value_of("SERVER_ADDR"), matches.value_of("PASSWORD"), matches.value_of("ENCRYPT_METHOD")) {
|
||||
(Some(svr_addr), Some(password), Some(method)) => {
|
||||
let method = match method.parse() {
|
||||
Ok(m) => m,
|
||||
Err(err) => {
|
||||
panic!("Does not support {:?} method: {:?}", method, err);
|
||||
}
|
||||
};
|
||||
let has_provided_server_config = match (
|
||||
matches.value_of("SERVER_ADDR"),
|
||||
matches.value_of("PASSWORD"),
|
||||
matches.value_of("ENCRYPT_METHOD"),
|
||||
) {
|
||||
(Some(svr_addr), Some(password), Some(method)) => {
|
||||
let method = match method.parse() {
|
||||
Ok(m) => m,
|
||||
Err(err) => {
|
||||
panic!("Does not support {:?} method: {:?}", method, err);
|
||||
}
|
||||
};
|
||||
|
||||
let sc = ServerConfig::new(svr_addr.parse::<ServerAddr>().expect("Invalid server addr"),
|
||||
password.to_owned(),
|
||||
method,
|
||||
None,
|
||||
None);
|
||||
let sc = ServerConfig::new(
|
||||
svr_addr.parse::<ServerAddr>().expect("Invalid server addr"),
|
||||
password.to_owned(),
|
||||
method,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
config.server.push(sc);
|
||||
true
|
||||
}
|
||||
(None, None, None) => {
|
||||
// Does not provide server config
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
panic!("`server-addr`, `method` and `password` should be provided together");
|
||||
}
|
||||
};
|
||||
config.server.push(sc);
|
||||
true
|
||||
}
|
||||
(None, None, None) => {
|
||||
// Does not provide server config
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
panic!("`server-addr`, `method` and `password` should be provided together");
|
||||
}
|
||||
};
|
||||
|
||||
if !has_provided_config && !has_provided_server_config {
|
||||
println!("You have to specify a configuration file or pass arguments from argument list");
|
||||
@@ -183,8 +223,10 @@ fn main() {
|
||||
config.enable_udp |= matches.is_present("ENABLE_UDP");
|
||||
|
||||
if let Some(p) = matches.value_of("PLUGIN") {
|
||||
let plugin = PluginConfig { plugin: p.to_owned(),
|
||||
plugin_opt: matches.value_of("PLUGIN_OPT").map(ToOwned::to_owned), };
|
||||
let plugin = PluginConfig {
|
||||
plugin: p.to_owned(),
|
||||
plugin_opt: matches.value_of("PLUGIN_OPT").map(ToOwned::to_owned),
|
||||
};
|
||||
|
||||
// Overrides config in file
|
||||
for svr in config.server.iter_mut() {
|
||||
|
||||
+124
-92
@@ -9,14 +9,14 @@ extern crate env_logger;
|
||||
extern crate futures;
|
||||
extern crate time;
|
||||
|
||||
use std::{
|
||||
env,
|
||||
io::{self, Write},
|
||||
net::SocketAddr,
|
||||
};
|
||||
|
||||
use clap::{App, Arg};
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use env_logger::fmt::Formatter;
|
||||
use env_logger::Builder;
|
||||
use env_logger::{fmt::Formatter, Builder};
|
||||
use futures::Future;
|
||||
use log::{LevelFilter, Record};
|
||||
use tokio::runtime::Runtime;
|
||||
@@ -27,28 +27,34 @@ fn log_time(fmt: &mut Formatter, without_time: bool, record: &Record) -> io::Res
|
||||
if without_time {
|
||||
writeln!(fmt, "[{}] {}", record.level(), record.args())
|
||||
} else {
|
||||
writeln!(fmt,
|
||||
"[{}][{}] {}",
|
||||
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
|
||||
record.level(),
|
||||
record.args())
|
||||
writeln!(
|
||||
fmt,
|
||||
"[{}][{}] {}",
|
||||
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
|
||||
record.level(),
|
||||
record.args()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn log_time_module(fmt: &mut Formatter, without_time: bool, record: &Record) -> io::Result<()> {
|
||||
if without_time {
|
||||
writeln!(fmt,
|
||||
"[{}] [{}] {}",
|
||||
record.level(),
|
||||
record.module_path().unwrap_or("*"),
|
||||
record.args())
|
||||
writeln!(
|
||||
fmt,
|
||||
"[{}] [{}] {}",
|
||||
record.level(),
|
||||
record.module_path().unwrap_or("*"),
|
||||
record.args()
|
||||
)
|
||||
} else {
|
||||
writeln!(fmt,
|
||||
"[{}][{}] [{}] {}",
|
||||
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
|
||||
record.level(),
|
||||
record.module_path().unwrap_or("*"),
|
||||
record.args())
|
||||
writeln!(
|
||||
fmt,
|
||||
"[{}][{}] [{}] {}",
|
||||
time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
|
||||
record.level(),
|
||||
record.module_path().unwrap_or("*"),
|
||||
record.args()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,46 +62,64 @@ fn main() {
|
||||
let matches = App::new("ssdns")
|
||||
.version(shadowsocks::VERSION)
|
||||
.about("A DNS proxy that helps you bypass firewalls.")
|
||||
.arg(Arg::with_name("VERBOSE")
|
||||
.short("v")
|
||||
.multiple(true)
|
||||
.help("Set the level of debug"))
|
||||
.arg(Arg::with_name("CONFIG")
|
||||
.short("c")
|
||||
.long("config")
|
||||
.takes_value(true)
|
||||
.help("Specify config file"))
|
||||
.arg(Arg::with_name("SERVER_ADDR")
|
||||
.short("s")
|
||||
.long("server-addr")
|
||||
.takes_value(true)
|
||||
.help("Server address"))
|
||||
.arg(Arg::with_name("LOCAL_ADDR")
|
||||
.short("b")
|
||||
.long("local-addr")
|
||||
.takes_value(true)
|
||||
.help("Local address, listen only to this address if specified"))
|
||||
.arg(Arg::with_name("PASSWORD")
|
||||
.short("k")
|
||||
.long("password")
|
||||
.takes_value(true)
|
||||
.help("Password"))
|
||||
.arg(Arg::with_name("ENCRYPT_METHOD")
|
||||
.short("m")
|
||||
.long("encrypt-method")
|
||||
.takes_value(true)
|
||||
.help("Encryption method"))
|
||||
.arg(Arg::with_name("LOG_WITHOUT_TIME")
|
||||
.long("log-without-time")
|
||||
.help("Disable time in log"))
|
||||
.arg(Arg::with_name("URL")
|
||||
.long("server-url")
|
||||
.takes_value(true)
|
||||
.help("Server address in SIP002 URL"))
|
||||
.arg(Arg::with_name("REMOTE_DNS")
|
||||
.arg(
|
||||
Arg::with_name("VERBOSE")
|
||||
.short("v")
|
||||
.multiple(true)
|
||||
.help("Set the level of debug"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("CONFIG")
|
||||
.short("c")
|
||||
.long("config")
|
||||
.takes_value(true)
|
||||
.help("Specify config file"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("SERVER_ADDR")
|
||||
.short("s")
|
||||
.long("server-addr")
|
||||
.takes_value(true)
|
||||
.help("Server address"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("LOCAL_ADDR")
|
||||
.short("b")
|
||||
.long("local-addr")
|
||||
.takes_value(true)
|
||||
.help("Local address, listen only to this address if specified"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("PASSWORD")
|
||||
.short("k")
|
||||
.long("password")
|
||||
.takes_value(true)
|
||||
.help("Password"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ENCRYPT_METHOD")
|
||||
.short("m")
|
||||
.long("encrypt-method")
|
||||
.takes_value(true)
|
||||
.help("Encryption method"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("LOG_WITHOUT_TIME")
|
||||
.long("log-without-time")
|
||||
.help("Disable time in log"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("URL")
|
||||
.long("server-url")
|
||||
.takes_value(true)
|
||||
.help("Server address in SIP002 URL"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("REMOTE_DNS")
|
||||
.long("remote-dns")
|
||||
.takes_value(true)
|
||||
.help("Remote DNS server, default is 8.8.8.8:53"))
|
||||
.help("Remote DNS server, default is 8.8.8.8:53"),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let mut log_builder = Builder::new();
|
||||
@@ -115,13 +139,15 @@ fn main() {
|
||||
}
|
||||
2 => {
|
||||
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
|
||||
log_builder.filter(Some("ssdns"), LevelFilter::Debug)
|
||||
.filter(Some("shadowsocks"), LevelFilter::Debug);
|
||||
log_builder
|
||||
.filter(Some("ssdns"), LevelFilter::Debug)
|
||||
.filter(Some("shadowsocks"), LevelFilter::Debug);
|
||||
}
|
||||
3 => {
|
||||
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
|
||||
log_builder.filter(Some("ssdns"), LevelFilter::Trace)
|
||||
.filter(Some("shadowsocks"), LevelFilter::Trace);
|
||||
log_builder
|
||||
.filter(Some("ssdns"), LevelFilter::Trace)
|
||||
.filter(Some("shadowsocks"), LevelFilter::Trace);
|
||||
}
|
||||
_ => {
|
||||
let log_builder = log_builder.format(move |fmt, r| log_time_module(fmt, without_time, r));
|
||||
@@ -151,33 +177,38 @@ fn main() {
|
||||
None => Config::new(),
|
||||
};
|
||||
|
||||
let mut has_provided_server_config =
|
||||
match (matches.value_of("SERVER_ADDR"), matches.value_of("PASSWORD"), matches.value_of("ENCRYPT_METHOD")) {
|
||||
(Some(svr_addr), Some(password), Some(method)) => {
|
||||
let method = match method.parse() {
|
||||
Ok(m) => m,
|
||||
Err(err) => {
|
||||
panic!("Does not support {:?} method: {:?}", method, err);
|
||||
}
|
||||
};
|
||||
let mut has_provided_server_config = match (
|
||||
matches.value_of("SERVER_ADDR"),
|
||||
matches.value_of("PASSWORD"),
|
||||
matches.value_of("ENCRYPT_METHOD"),
|
||||
) {
|
||||
(Some(svr_addr), Some(password), Some(method)) => {
|
||||
let method = match method.parse() {
|
||||
Ok(m) => m,
|
||||
Err(err) => {
|
||||
panic!("Does not support {:?} method: {:?}", method, err);
|
||||
}
|
||||
};
|
||||
|
||||
let sc = ServerConfig::new(svr_addr.parse::<ServerAddr>().expect("Invalid server addr"),
|
||||
password.to_owned(),
|
||||
method,
|
||||
None,
|
||||
None);
|
||||
let sc = ServerConfig::new(
|
||||
svr_addr.parse::<ServerAddr>().expect("Invalid server addr"),
|
||||
password.to_owned(),
|
||||
method,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
config.server.push(sc);
|
||||
true
|
||||
}
|
||||
(None, None, None) => {
|
||||
// Does not provide server config
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
panic!("`server-addr`, `method` and `password` should be provided together");
|
||||
}
|
||||
};
|
||||
config.server.push(sc);
|
||||
true
|
||||
}
|
||||
(None, None, None) => {
|
||||
// Does not provide server config
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
panic!("`server-addr`, `method` and `password` should be provided together");
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(url) = matches.value_of("URL") {
|
||||
let svr_addr = url.parse::<ServerConfig>().expect("Failed to parse `url`");
|
||||
@@ -204,8 +235,9 @@ fn main() {
|
||||
}
|
||||
|
||||
if let Some(dns) = matches.value_of("REMOTE_DNS") {
|
||||
let dns_addr = dns.parse::<SocketAddr>()
|
||||
.expect("`remote-dns` is not a valid SocketAddr, must be IP:Port");
|
||||
let dns_addr = dns
|
||||
.parse::<SocketAddr>()
|
||||
.expect("`remote-dns` is not a valid SocketAddr, must be IP:Port");
|
||||
config.remote_dns = Some(dns_addr);
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -9,12 +9,12 @@ extern crate serde_json;
|
||||
extern crate shadowsocks;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use qrcode::{types::Color, QrCode};
|
||||
|
||||
use qrcode::types::Color;
|
||||
use qrcode::QrCode;
|
||||
|
||||
use shadowsocks::config::{Config, ConfigType, ServerConfig};
|
||||
use shadowsocks::VERSION;
|
||||
use shadowsocks::{
|
||||
config::{Config, ConfigType, ServerConfig},
|
||||
VERSION,
|
||||
};
|
||||
|
||||
const BLACK: &'static str = "\x1b[40m \x1b[0m";
|
||||
const WHITE: &'static str = "\x1b[47m \x1b[0m";
|
||||
|
||||
+208
-175
@@ -41,19 +41,20 @@
|
||||
//!
|
||||
//! These defined server will be used with a load balancing algorithm.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::convert::From;
|
||||
use std::default::Default;
|
||||
use std::error;
|
||||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
use std::fs::OpenOptions;
|
||||
use std::net::IpAddr;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::option::Option;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
convert::From,
|
||||
default::Default,
|
||||
error,
|
||||
fmt::{self, Debug, Display, Formatter},
|
||||
fs::OpenOptions,
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
|
||||
option::Option,
|
||||
path::Path,
|
||||
str::FromStr,
|
||||
string::ToString,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use base64::{decode_config, encode_config, URL_SAFE_NO_PAD};
|
||||
use bytes::Bytes;
|
||||
@@ -132,6 +133,7 @@ pub struct ServerAddrError;
|
||||
|
||||
impl FromStr for ServerAddr {
|
||||
type Err = ServerAddrError;
|
||||
|
||||
fn from_str(s: &str) -> Result<ServerAddr, ServerAddrError> {
|
||||
match s.parse::<SocketAddr>() {
|
||||
Ok(addr) => Ok(ServerAddr::SocketAddr(addr)),
|
||||
@@ -179,21 +181,24 @@ pub struct ServerConfig {
|
||||
|
||||
impl ServerConfig {
|
||||
/// Creates a new ServerConfig
|
||||
pub fn new(addr: ServerAddr,
|
||||
pwd: String,
|
||||
method: CipherType,
|
||||
timeout: Option<Duration>,
|
||||
plugin: Option<PluginConfig>)
|
||||
-> ServerConfig {
|
||||
pub fn new(
|
||||
addr: ServerAddr,
|
||||
pwd: String,
|
||||
method: CipherType,
|
||||
timeout: Option<Duration>,
|
||||
plugin: Option<PluginConfig>,
|
||||
) -> ServerConfig {
|
||||
let enc_key = method.bytes_to_key(pwd.as_bytes());
|
||||
trace!("Initialize config with pwd: {:?}, key: {:?}", pwd, enc_key);
|
||||
ServerConfig { addr: addr,
|
||||
password: pwd,
|
||||
method: method,
|
||||
timeout: timeout,
|
||||
enc_key: enc_key,
|
||||
plugin: plugin,
|
||||
udp_timeout: None, }
|
||||
ServerConfig {
|
||||
addr: addr,
|
||||
password: pwd,
|
||||
method: method,
|
||||
timeout: timeout,
|
||||
enc_key: enc_key,
|
||||
plugin: plugin,
|
||||
udp_timeout: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a basic config
|
||||
@@ -346,8 +351,10 @@ impl ServerConfig {
|
||||
match vsp.next() {
|
||||
None => {}
|
||||
Some(p) => {
|
||||
plugin = Some(PluginConfig { plugin: p.to_owned(),
|
||||
plugin_opt: vsp.next().map(ToOwned::to_owned), })
|
||||
plugin = Some(PluginConfig {
|
||||
plugin: p.to_owned(),
|
||||
plugin_opt: vsp.next().map(ToOwned::to_owned),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -361,6 +368,7 @@ impl ServerConfig {
|
||||
|
||||
impl FromStr for ServerConfig {
|
||||
type Err = UrlParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<ServerConfig, Self::Err> {
|
||||
ServerConfig::from_url(s)
|
||||
}
|
||||
@@ -501,9 +509,11 @@ pub struct Error {
|
||||
|
||||
impl Error {
|
||||
pub fn new(kind: ErrorKind, desc: &'static str, detail: Option<String>) -> Error {
|
||||
Error { kind: kind,
|
||||
desc: desc,
|
||||
detail: detail, }
|
||||
Error {
|
||||
kind: kind,
|
||||
desc: desc,
|
||||
detail: detail,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,80 +555,82 @@ impl Debug for Error {
|
||||
impl Config {
|
||||
/// Creates an empty configuration
|
||||
pub fn new() -> Config {
|
||||
Config { server: Vec::new(),
|
||||
local: None,
|
||||
enable_udp: false,
|
||||
forbidden_ip: HashSet::new(),
|
||||
dns: None,
|
||||
remote_dns: None, }
|
||||
Config {
|
||||
server: Vec::new(),
|
||||
local: None,
|
||||
enable_udp: false,
|
||||
forbidden_ip: HashSet::new(),
|
||||
dns: None,
|
||||
remote_dns: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_server(server: &Map<String, Value>, default_timeout: Option<Duration>) -> Result<ServerConfig, Error> {
|
||||
let method = server.get("method")
|
||||
.ok_or_else(|| Error::new(ErrorKind::MissingField, "need to specify a method", None))
|
||||
.and_then(|method_o| {
|
||||
method_o.as_str().ok_or_else(|| {
|
||||
Error::new(ErrorKind::Malformed,
|
||||
"`method` should be a string",
|
||||
None)
|
||||
})
|
||||
})
|
||||
.and_then(|method_str| {
|
||||
method_str.parse::<CipherType>().map_err(|_| {
|
||||
Error::new(ErrorKind::Invalid,
|
||||
"not supported method",
|
||||
Some(format!("`{}` is not a supported method", method_str)))
|
||||
})
|
||||
})?;
|
||||
let method = server
|
||||
.get("method")
|
||||
.ok_or_else(|| Error::new(ErrorKind::MissingField, "need to specify a method", None))
|
||||
.and_then(|method_o| {
|
||||
method_o
|
||||
.as_str()
|
||||
.ok_or_else(|| Error::new(ErrorKind::Malformed, "`method` should be a string", None))
|
||||
})
|
||||
.and_then(|method_str| {
|
||||
method_str.parse::<CipherType>().map_err(|_| {
|
||||
Error::new(
|
||||
ErrorKind::Invalid,
|
||||
"not supported method",
|
||||
Some(format!("`{}` is not a supported method", method_str)),
|
||||
)
|
||||
})
|
||||
})?;
|
||||
|
||||
let port = server.get("port")
|
||||
.or_else(|| server.get("server_port"))
|
||||
.ok_or_else(|| Error::new(ErrorKind::MissingField, "need to specify a server port", None))
|
||||
.and_then(|port_o| {
|
||||
port_o.as_u64().map(|u| u as u16).ok_or_else(|| {
|
||||
Error::new(ErrorKind::Malformed,
|
||||
"`port` should be an integer",
|
||||
None)
|
||||
})
|
||||
})?;
|
||||
let port = server
|
||||
.get("port")
|
||||
.or_else(|| server.get("server_port"))
|
||||
.ok_or_else(|| Error::new(ErrorKind::MissingField, "need to specify a server port", None))
|
||||
.and_then(|port_o| {
|
||||
port_o
|
||||
.as_u64()
|
||||
.map(|u| u as u16)
|
||||
.ok_or_else(|| Error::new(ErrorKind::Malformed, "`port` should be an integer", None))
|
||||
})?;
|
||||
|
||||
let addr = server.get("address")
|
||||
.or_else(|| server.get("server"))
|
||||
.ok_or_else(|| Error::new(ErrorKind::MissingField, "need to specify a server address", None))
|
||||
.and_then(|addr_o| {
|
||||
addr_o.as_str().ok_or_else(|| {
|
||||
Error::new(ErrorKind::Malformed,
|
||||
"`address` should be a string",
|
||||
None)
|
||||
})
|
||||
})
|
||||
.and_then(|addr_str| {
|
||||
addr_str.parse::<Ipv4Addr>()
|
||||
.map(|v4| ServerAddr::SocketAddr(SocketAddr::V4(SocketAddrV4::new(v4, port))))
|
||||
.or_else(|_| {
|
||||
addr_str
|
||||
let addr = server
|
||||
.get("address")
|
||||
.or_else(|| server.get("server"))
|
||||
.ok_or_else(|| Error::new(ErrorKind::MissingField, "need to specify a server address", None))
|
||||
.and_then(|addr_o| {
|
||||
addr_o
|
||||
.as_str()
|
||||
.ok_or_else(|| Error::new(ErrorKind::Malformed, "`address` should be a string", None))
|
||||
})
|
||||
.and_then(|addr_str| {
|
||||
addr_str
|
||||
.parse::<Ipv4Addr>()
|
||||
.map(|v4| ServerAddr::SocketAddr(SocketAddr::V4(SocketAddrV4::new(v4, port))))
|
||||
.or_else(|_| {
|
||||
addr_str
|
||||
.parse::<Ipv6Addr>()
|
||||
.map(|v6| ServerAddr::SocketAddr(SocketAddr::V6(SocketAddrV6::new(v6, port, 0, 0))))
|
||||
})
|
||||
.or_else(|_| Ok(ServerAddr::DomainName(addr_str.to_string(), port)))
|
||||
})?;
|
||||
})
|
||||
.or_else(|_| Ok(ServerAddr::DomainName(addr_str.to_string(), port)))
|
||||
})?;
|
||||
|
||||
let password = server.get("password")
|
||||
.ok_or_else(|| Error::new(ErrorKind::MissingField, "need to specify a password", None))
|
||||
.and_then(|pwd_o| {
|
||||
pwd_o.as_str()
|
||||
.ok_or_else(|| {
|
||||
Error::new(ErrorKind::Malformed,
|
||||
"`password` should be a string",
|
||||
None)
|
||||
})
|
||||
.map(|s| s.to_string())
|
||||
})?;
|
||||
let password = server
|
||||
.get("password")
|
||||
.ok_or_else(|| Error::new(ErrorKind::MissingField, "need to specify a password", None))
|
||||
.and_then(|pwd_o| {
|
||||
pwd_o
|
||||
.as_str()
|
||||
.ok_or_else(|| Error::new(ErrorKind::Malformed, "`password` should be a string", None))
|
||||
.map(|s| s.to_string())
|
||||
})?;
|
||||
|
||||
let timeout = match server.get("timeout") {
|
||||
Some(t) => {
|
||||
let val = t.as_u64()
|
||||
.ok_or(Error::new(ErrorKind::Malformed, "`timeout` should be an integer", None))?;
|
||||
let val = t
|
||||
.as_u64()
|
||||
.ok_or(Error::new(ErrorKind::Malformed, "`timeout` should be an integer", None))?;
|
||||
Some(Duration::from_secs(val))
|
||||
}
|
||||
None => default_timeout,
|
||||
@@ -626,8 +638,11 @@ impl Config {
|
||||
|
||||
let udp_timeout = match server.get("udp_timeout") {
|
||||
Some(t) => {
|
||||
let val = t.as_u64()
|
||||
.ok_or(Error::new(ErrorKind::Malformed, "`udp_timeout` should be an integer", None))?;
|
||||
let val = t.as_u64().ok_or(Error::new(
|
||||
ErrorKind::Malformed,
|
||||
"`udp_timeout` should be an integer",
|
||||
None,
|
||||
))?;
|
||||
Some(Duration::from_secs(val))
|
||||
}
|
||||
None => None,
|
||||
@@ -635,24 +650,24 @@ impl Config {
|
||||
|
||||
let plugin = match server.get("plugin") {
|
||||
Some(p) => {
|
||||
let plugin =
|
||||
p.as_str()
|
||||
.ok_or_else(|| Error::new(ErrorKind::Malformed, "`plugin` should be a string", None))?;
|
||||
let plugin = p
|
||||
.as_str()
|
||||
.ok_or_else(|| Error::new(ErrorKind::Malformed, "`plugin` should be a string", None))?;
|
||||
|
||||
let opt = match server.get("plugin_opts") {
|
||||
None => None,
|
||||
Some(o) => {
|
||||
let o = o.as_str().ok_or_else(|| {
|
||||
Error::new(ErrorKind::Malformed,
|
||||
"`plugin_opts` should be a string",
|
||||
None)
|
||||
})?;
|
||||
Error::new(ErrorKind::Malformed, "`plugin_opts` should be a string", None)
|
||||
})?;
|
||||
Some(o.to_owned())
|
||||
}
|
||||
};
|
||||
|
||||
Some(PluginConfig { plugin: plugin.to_owned(),
|
||||
plugin_opt: opt, })
|
||||
Some(PluginConfig {
|
||||
plugin: plugin.to_owned(),
|
||||
plugin_opt: opt,
|
||||
})
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
@@ -666,16 +681,18 @@ impl Config {
|
||||
let mut config = Config::new();
|
||||
|
||||
if o.contains_key("servers") {
|
||||
let server_list = o.get("servers")
|
||||
.unwrap()
|
||||
.as_array()
|
||||
.ok_or(Error::new(ErrorKind::Malformed, "`servers` should be a list", None))?;
|
||||
let server_list = o.get("servers").unwrap().as_array().ok_or(Error::new(
|
||||
ErrorKind::Malformed,
|
||||
"`servers` should be a list",
|
||||
None,
|
||||
))?;
|
||||
|
||||
let opt_timeout = match o.get("timeout") {
|
||||
None => None,
|
||||
Some(t) => {
|
||||
let val = t.as_u64()
|
||||
.ok_or(Error::new(ErrorKind::Malformed, "`timeout` should be an integer", None))?;
|
||||
let val =
|
||||
t.as_u64()
|
||||
.ok_or(Error::new(ErrorKind::Malformed, "`timeout` should be an integer", None))?;
|
||||
Some(Duration::from_secs(val))
|
||||
}
|
||||
};
|
||||
@@ -687,9 +704,9 @@ impl Config {
|
||||
}
|
||||
}
|
||||
} else if o.contains_key("server")
|
||||
&& o.contains_key("server_port")
|
||||
&& o.contains_key("password")
|
||||
&& o.contains_key("method")
|
||||
&& o.contains_key("server_port")
|
||||
&& o.contains_key("password")
|
||||
&& o.contains_key("method")
|
||||
{
|
||||
// Traditional configuration file
|
||||
let single_server = Config::parse_server(o, None)?;
|
||||
@@ -703,25 +720,29 @@ impl Config {
|
||||
if has_local_address && has_local_port {
|
||||
config.local = match o.get("local_address") {
|
||||
Some(local_addr) => {
|
||||
let addr_str = local_addr.as_str().ok_or(Error::new(ErrorKind::Malformed,
|
||||
"`local_address` should be a string",
|
||||
None))?;
|
||||
let addr_str = local_addr.as_str().ok_or(Error::new(
|
||||
ErrorKind::Malformed,
|
||||
"`local_address` should be a string",
|
||||
None,
|
||||
))?;
|
||||
|
||||
let port = o.get("local_port")
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.ok_or(Error::new(ErrorKind::Malformed, "`local_port` should be an integer", None))?
|
||||
as u16;
|
||||
let port = o.get("local_port").unwrap().as_u64().ok_or(Error::new(
|
||||
ErrorKind::Malformed,
|
||||
"`local_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_address` is not a valid IP \
|
||||
address",
|
||||
None))
|
||||
return Err(Error::new(
|
||||
ErrorKind::Malformed,
|
||||
"`local_address` is not a valid IP \
|
||||
address",
|
||||
None,
|
||||
))
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -734,27 +755,28 @@ impl Config {
|
||||
}
|
||||
|
||||
if let Some(forbidden_ip_conf) = o.get("forbidden_ip") {
|
||||
let forbidden_ip_arr =
|
||||
forbidden_ip_conf.as_array()
|
||||
.ok_or(Error::new(ErrorKind::Malformed, "`forbidden_ip` should be a list", None))?;
|
||||
let forbidden_ip_arr = forbidden_ip_conf.as_array().ok_or(Error::new(
|
||||
ErrorKind::Malformed,
|
||||
"`forbidden_ip` should be a list",
|
||||
None,
|
||||
))?;
|
||||
config.forbidden_ip.extend(forbidden_ip_arr.into_iter().filter_map(|x| {
|
||||
let x = match x.as_str() {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
error!("Forbidden IP should be a string, but found {:?}, skipping",
|
||||
x);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let x = match x.as_str() {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
error!("Forbidden IP should be a string, but found {:?}, skipping", x);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
match x.parse::<IpAddr>() {
|
||||
Ok(sock) => Some(sock),
|
||||
Err(err) => {
|
||||
error!("Invalid forbidden IP {}, {:?}, skipping", x, err);
|
||||
None
|
||||
}
|
||||
}
|
||||
}));
|
||||
match x.parse::<IpAddr>() {
|
||||
Ok(sock) => Some(sock),
|
||||
Err(err) => {
|
||||
error!("Invalid forbidden IP {}, {:?}, skipping", x, err);
|
||||
None
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if let Some(udp_enable) = o.get("enable_udp") {
|
||||
@@ -773,17 +795,15 @@ impl Config {
|
||||
let err = Error::new(ErrorKind::Malformed, "`remote_dns` should be string", None);
|
||||
return Err(err);
|
||||
}
|
||||
Some(dns) => {
|
||||
match dns.parse::<IpAddr>() {
|
||||
Err(..) => {
|
||||
let err = Error::new(ErrorKind::Malformed, "`remote_dns` should be IpAddr", None);
|
||||
return Err(err);
|
||||
}
|
||||
Ok(addr) => {
|
||||
config.remote_dns = Some(SocketAddr::new(addr, 53));
|
||||
}
|
||||
Some(dns) => match dns.parse::<IpAddr>() {
|
||||
Err(..) => {
|
||||
let err = Error::new(ErrorKind::Malformed, "`remote_dns` should be IpAddr", None);
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
Ok(addr) => {
|
||||
config.remote_dns = Some(SocketAddr::new(addr, 53));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -804,25 +824,35 @@ impl Config {
|
||||
|
||||
pub fn load_from_str(s: &str, config_type: ConfigType) -> Result<Config, Error> {
|
||||
let object = serde_json::from_str::<Value>(s)?;
|
||||
let json_object = except!(object.as_object(),
|
||||
ErrorKind::JsonParsingError,
|
||||
"root is not a JsonObject");
|
||||
Config::parse_json_object(json_object, match config_type {
|
||||
ConfigType::Local => true,
|
||||
ConfigType::Server => false,
|
||||
})
|
||||
let json_object = except!(
|
||||
object.as_object(),
|
||||
ErrorKind::JsonParsingError,
|
||||
"root is not a JsonObject"
|
||||
);
|
||||
Config::parse_json_object(
|
||||
json_object,
|
||||
match config_type {
|
||||
ConfigType::Local => true,
|
||||
ConfigType::Server => false,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn load_from_file(filename: &str, config_type: ConfigType) -> Result<Config, Error> {
|
||||
let reader = &mut OpenOptions::new().read(true).open(&Path::new(filename))?;
|
||||
let object = serde_json::from_reader::<_, Value>(reader)?;
|
||||
let json_object = except!(object.as_object(),
|
||||
ErrorKind::JsonParsingError,
|
||||
"root is not a JsonObject");
|
||||
Config::parse_json_object(json_object, match config_type {
|
||||
ConfigType::Local => true,
|
||||
ConfigType::Server => false,
|
||||
})
|
||||
let json_object = except!(
|
||||
object.as_object(),
|
||||
ErrorKind::JsonParsingError,
|
||||
"root is not a JsonObject"
|
||||
);
|
||||
Config::parse_json_object(
|
||||
json_object,
|
||||
match config_type {
|
||||
ConfigType::Local => true,
|
||||
ConfigType::Server => false,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_dns_config(&self) -> Option<ResolverConfig> {
|
||||
@@ -842,13 +872,16 @@ impl Config {
|
||||
_ => {
|
||||
// Set ips directly
|
||||
match ds.parse::<IpAddr>() {
|
||||
Ok(ip) => Some(ResolverConfig::from_parts(None,
|
||||
vec![],
|
||||
NameServerConfigGroup::from_ips_clear(&[ip],
|
||||
53))),
|
||||
Ok(ip) => Some(ResolverConfig::from_parts(
|
||||
None,
|
||||
vec![],
|
||||
NameServerConfigGroup::from_ips_clear(&[ip], 53),
|
||||
)),
|
||||
Err(..) => {
|
||||
error!("Failed to parse DNS \"{}\" in config to IpAddr, fallback to system config",
|
||||
ds);
|
||||
error!(
|
||||
"Failed to parse DNS \"{}\" in config to IpAddr, fallback to system config",
|
||||
ds
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
+1
-4
@@ -8,11 +8,8 @@ use crypto::siv::MiscreantCipher;
|
||||
#[cfg(feature = "sodium")]
|
||||
use crypto::sodium::SodiumAeadCipher;
|
||||
|
||||
use ring::digest::SHA1;
|
||||
use ring::hkdf;
|
||||
use ring::hmac::SigningKey;
|
||||
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use ring::{digest::SHA1, hkdf, hmac::SigningKey};
|
||||
|
||||
/// Encryptor API for AEAD ciphers
|
||||
pub trait AeadEncryptor {
|
||||
|
||||
+27
-31
@@ -1,10 +1,12 @@
|
||||
//! Ciphers
|
||||
|
||||
use std::convert::From;
|
||||
use std::fmt::{self, Debug, Display};
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::str::{self, FromStr};
|
||||
use std::{
|
||||
convert::From,
|
||||
fmt::{self, Debug, Display},
|
||||
io,
|
||||
mem,
|
||||
str::{self, FromStr},
|
||||
};
|
||||
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
use crypto::digest::{self, Digest, DigestType};
|
||||
@@ -226,30 +228,24 @@ impl CipherType {
|
||||
match *self {
|
||||
CipherType::Table | CipherType::Plain => 0,
|
||||
|
||||
CipherType::Aes128Cfb1 => {
|
||||
symm::Cipher::aes_128_cfb1().iv_len()
|
||||
.expect("iv_len should not be None")
|
||||
}
|
||||
CipherType::Aes128Cfb8 => {
|
||||
symm::Cipher::aes_128_cfb8().iv_len()
|
||||
.expect("iv_len should not be None")
|
||||
}
|
||||
CipherType::Aes128Cfb | CipherType::Aes128Cfb128 => {
|
||||
symm::Cipher::aes_128_cfb128().iv_len()
|
||||
.expect("iv_len should not be None")
|
||||
}
|
||||
CipherType::Aes256Cfb1 => {
|
||||
symm::Cipher::aes_256_cfb1().iv_len()
|
||||
.expect("iv_len should not be None")
|
||||
}
|
||||
CipherType::Aes256Cfb8 => {
|
||||
symm::Cipher::aes_256_cfb8().iv_len()
|
||||
.expect("iv_len should not be None")
|
||||
}
|
||||
CipherType::Aes256Cfb | CipherType::Aes256Cfb128 => {
|
||||
symm::Cipher::aes_256_cfb128().iv_len()
|
||||
.expect("iv_len should not be None")
|
||||
}
|
||||
CipherType::Aes128Cfb1 => symm::Cipher::aes_128_cfb1()
|
||||
.iv_len()
|
||||
.expect("iv_len should not be None"),
|
||||
CipherType::Aes128Cfb8 => symm::Cipher::aes_128_cfb8()
|
||||
.iv_len()
|
||||
.expect("iv_len should not be None"),
|
||||
CipherType::Aes128Cfb | CipherType::Aes128Cfb128 => symm::Cipher::aes_128_cfb128()
|
||||
.iv_len()
|
||||
.expect("iv_len should not be None"),
|
||||
CipherType::Aes256Cfb1 => symm::Cipher::aes_256_cfb1()
|
||||
.iv_len()
|
||||
.expect("iv_len should not be None"),
|
||||
CipherType::Aes256Cfb8 => symm::Cipher::aes_256_cfb8()
|
||||
.iv_len()
|
||||
.expect("iv_len should not be None"),
|
||||
CipherType::Aes256Cfb | CipherType::Aes256Cfb128 => symm::Cipher::aes_256_cfb128()
|
||||
.iv_len()
|
||||
.expect("iv_len should not be None"),
|
||||
|
||||
CipherType::Rc4 => symm::Cipher::rc4().iv_len().expect("iv_len should not be None"),
|
||||
CipherType::Rc4Md5 => 16,
|
||||
@@ -338,6 +334,7 @@ impl CipherType {
|
||||
|
||||
impl FromStr for CipherType {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<CipherType, Error> {
|
||||
match s {
|
||||
CIPHER_TABLE | "" => Ok(CipherType::Table),
|
||||
@@ -424,8 +421,7 @@ impl Display for CipherType {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_cipher {
|
||||
use crypto::CryptoMode;
|
||||
use crypto::{new_stream, CipherType, StreamCipher};
|
||||
use crypto::{new_stream, CipherType, CryptoMode, StreamCipher};
|
||||
|
||||
#[test]
|
||||
fn test_get_cipher() {
|
||||
|
||||
+4
-4
@@ -4,11 +4,11 @@ use std::convert::From;
|
||||
|
||||
use openssl::symm;
|
||||
|
||||
pub use self::aead::{
|
||||
new_aead_decryptor, new_aead_encryptor, AeadDecryptor, AeadEncryptor, BoxAeadDecryptor, BoxAeadEncryptor,
|
||||
pub use self::{
|
||||
aead::{new_aead_decryptor, new_aead_encryptor, AeadDecryptor, AeadEncryptor, BoxAeadDecryptor, BoxAeadEncryptor},
|
||||
cipher::{CipherCategory, CipherResult, CipherType},
|
||||
stream::{new_stream, StreamCipher, StreamCipherVariant},
|
||||
};
|
||||
pub use self::cipher::{CipherCategory, CipherResult, CipherType};
|
||||
pub use self::stream::{new_stream, StreamCipher, StreamCipherVariant};
|
||||
|
||||
pub mod aead;
|
||||
pub mod cipher;
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
use std::convert::From;
|
||||
|
||||
use crypto::cipher;
|
||||
use crypto::{CipherResult, CipherType, StreamCipher};
|
||||
use crypto::{cipher, CipherResult, CipherType, StreamCipher};
|
||||
|
||||
use crypto::CryptoMode;
|
||||
|
||||
@@ -34,8 +33,10 @@ impl OpenSSLCrypto {
|
||||
// Panic if error occurs
|
||||
let cipher = symm::Crypter::new(t, From::from(mode), key, Some(iv)).unwrap();
|
||||
|
||||
OpenSSLCrypto { cipher: t,
|
||||
inner: cipher, }
|
||||
OpenSSLCrypto {
|
||||
cipher: t,
|
||||
inner: cipher,
|
||||
}
|
||||
}
|
||||
|
||||
/// Update data
|
||||
@@ -80,8 +81,7 @@ impl OpenSSLCrypto {
|
||||
/// *Note: This behavior works just the same as the official version of shadowsocks.*
|
||||
///
|
||||
/// ```rust
|
||||
/// use shadowsocks::crypto::openssl::OpenSSLCipher;
|
||||
/// use shadowsocks::crypto::{CipherType, CryptoMode, StreamCipher};
|
||||
/// use shadowsocks::crypto::{openssl::OpenSSLCipher, CipherType, CryptoMode, StreamCipher};
|
||||
///
|
||||
/// let method = CipherType::Aes128Cfb;
|
||||
///
|
||||
@@ -107,7 +107,9 @@ pub struct OpenSSLCipher {
|
||||
impl OpenSSLCipher {
|
||||
/// Creates by type
|
||||
pub fn new(cipher_type: cipher::CipherType, key: &[u8], iv: &[u8], mode: CryptoMode) -> OpenSSLCipher {
|
||||
OpenSSLCipher { worker: OpenSSLCrypto::new(cipher_type, &key[..], &iv[..], mode), }
|
||||
OpenSSLCipher {
|
||||
worker: OpenSSLCrypto::new(cipher_type, &key[..], &iv[..], mode),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-11
@@ -1,9 +1,13 @@
|
||||
//! Rc4Md5 cipher definition
|
||||
|
||||
use crypto::digest::{self, Digest, DigestType};
|
||||
use crypto::openssl::OpenSSLCrypto;
|
||||
use crypto::CryptoMode;
|
||||
use crypto::{CipherResult, CipherType, StreamCipher};
|
||||
use crypto::{
|
||||
digest::{self, Digest, DigestType},
|
||||
openssl::OpenSSLCrypto,
|
||||
CipherResult,
|
||||
CipherType,
|
||||
CryptoMode,
|
||||
StreamCipher,
|
||||
};
|
||||
|
||||
use bytes::{BufMut, BytesMut};
|
||||
|
||||
@@ -20,7 +24,9 @@ impl Rc4Md5Cipher {
|
||||
let mut key = BytesMut::with_capacity(md5_digest.digest_len());
|
||||
md5_digest.digest(&mut key);
|
||||
|
||||
Rc4Md5Cipher { crypto: OpenSSLCrypto::new(CipherType::Rc4, &key, b"", mode), }
|
||||
Rc4Md5Cipher {
|
||||
crypto: OpenSSLCrypto::new(CipherType::Rc4, &key, b"", mode),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +49,7 @@ unsafe impl Send for Rc4Md5Cipher {}
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crypto::CryptoMode;
|
||||
use crypto::{CipherType, StreamCipher};
|
||||
use crypto::{CipherType, CryptoMode, StreamCipher};
|
||||
|
||||
#[test]
|
||||
fn test_rc4_md5_cipher() {
|
||||
@@ -56,13 +61,15 @@ mod test {
|
||||
|
||||
let mut enc = Rc4Md5Cipher::new(key, &iv[..], CryptoMode::Encrypt);
|
||||
let mut encrypted_msg = Vec::new();
|
||||
enc.update(msg, &mut encrypted_msg).and_then(|_| enc.finalize(&mut encrypted_msg))
|
||||
.unwrap();
|
||||
enc.update(msg, &mut encrypted_msg)
|
||||
.and_then(|_| enc.finalize(&mut encrypted_msg))
|
||||
.unwrap();
|
||||
|
||||
let mut dec = Rc4Md5Cipher::new(key, &iv[..], CryptoMode::Decrypt);
|
||||
let mut decrypted_msg = Vec::new();
|
||||
dec.update(&encrypted_msg[..], &mut decrypted_msg).and_then(|_| dec.finalize(&mut decrypted_msg))
|
||||
.unwrap();
|
||||
dec.update(&encrypted_msg[..], &mut decrypted_msg)
|
||||
.and_then(|_| dec.finalize(&mut decrypted_msg))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(msg, &decrypted_msg[..]);
|
||||
}
|
||||
|
||||
+23
-16
@@ -1,14 +1,17 @@
|
||||
//! Cipher defined with Ring
|
||||
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::{mem, ptr};
|
||||
|
||||
use ring::aead::{open_in_place, seal_in_place, AES_128_GCM, AES_256_GCM, CHACHA20_POLY1305, OpeningKey, SealingKey};
|
||||
use ring::aead::{open_in_place, seal_in_place, OpeningKey, SealingKey, AES_128_GCM, AES_256_GCM, CHACHA20_POLY1305};
|
||||
|
||||
use crypto::aead::{increase_nonce, make_skey};
|
||||
use crypto::cipher::Error;
|
||||
use crypto::{AeadDecryptor, AeadEncryptor};
|
||||
use crypto::{CipherResult, CipherType};
|
||||
use crypto::{
|
||||
aead::{increase_nonce, make_skey},
|
||||
cipher::Error,
|
||||
AeadDecryptor,
|
||||
AeadEncryptor,
|
||||
CipherResult,
|
||||
CipherType,
|
||||
};
|
||||
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
|
||||
@@ -44,10 +47,12 @@ impl RingAeadCipher {
|
||||
|
||||
let skey = make_skey(t, key, salt);
|
||||
let cipher = RingAeadCipher::new_variant(t, &skey, &nonce, is_seal);
|
||||
RingAeadCipher { cipher: cipher,
|
||||
cipher_type: t,
|
||||
key: skey,
|
||||
nonce: nonce, }
|
||||
RingAeadCipher {
|
||||
cipher: cipher,
|
||||
cipher_type: t,
|
||||
key: skey,
|
||||
nonce: nonce,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_variant(t: CipherType, key: &[u8], nonce: &[u8], is_seal: bool) -> RingAeadCryptoVariant {
|
||||
@@ -126,11 +131,13 @@ impl AeadDecryptor for RingAeadCipher {
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => {
|
||||
error!("AEAD decrypt failed, nonce={:?}, input={:?}, tag={:?}, err: {:?}",
|
||||
ByteStr::new(nonce),
|
||||
ByteStr::new(&input[..tag_len]),
|
||||
ByteStr::new(&input[tag_len..]),
|
||||
err);
|
||||
error!(
|
||||
"AEAD decrypt failed, nonce={:?}, input={:?}, tag={:?}, err: {:?}",
|
||||
ByteStr::new(nonce),
|
||||
ByteStr::new(&input[..tag_len]),
|
||||
ByteStr::new(&input[tag_len..]),
|
||||
err
|
||||
);
|
||||
Err(Error::AeadDecryptFailed)
|
||||
}
|
||||
}
|
||||
|
||||
+27
-18
@@ -4,10 +4,14 @@ use std::ptr;
|
||||
|
||||
use miscreant::aead::{Aes128PmacSiv, Aes256PmacSiv, Algorithm};
|
||||
|
||||
use crypto::aead::{increase_nonce, make_skey};
|
||||
use crypto::cipher::Error;
|
||||
use crypto::{AeadDecryptor, AeadEncryptor};
|
||||
use crypto::{CipherResult, CipherType};
|
||||
use crypto::{
|
||||
aead::{increase_nonce, make_skey},
|
||||
cipher::Error,
|
||||
AeadDecryptor,
|
||||
AeadEncryptor,
|
||||
CipherResult,
|
||||
CipherType,
|
||||
};
|
||||
|
||||
use bytes::{BufMut, BytesMut};
|
||||
|
||||
@@ -42,9 +46,11 @@ impl MiscreantCipher {
|
||||
|
||||
let skey = make_skey(t, key, salt);
|
||||
let cipher = Self::new_variant(t, &skey);
|
||||
MiscreantCipher { cipher_type: t,
|
||||
cipher: cipher,
|
||||
nonce: nonce, }
|
||||
MiscreantCipher {
|
||||
cipher_type: t,
|
||||
cipher: cipher,
|
||||
nonce: nonce,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_variant(t: CipherType, key: &[u8]) -> MiscreantCryptoVariant {
|
||||
@@ -109,17 +115,20 @@ impl AeadDecryptor for MiscreantCipher {
|
||||
MiscreantCryptoVariant::Aes256(ref mut cipher) => cipher.open_in_place(&self.nonce, b"", &mut buf),
|
||||
};
|
||||
|
||||
result.map(|buf| {
|
||||
output.copy_from_slice(buf);
|
||||
increase_nonce(&mut self.nonce);
|
||||
})
|
||||
.map_err(|_| {
|
||||
error!("AEAD decrypt failed, nonce={:?}, input={:?}, tag={:?}, err: decrypt failure",
|
||||
ByteStr::new(&self.nonce),
|
||||
ByteStr::new(&input[..input.len() - tag_size]),
|
||||
ByteStr::new(&input[input.len() - tag_size..]));
|
||||
Error::AeadDecryptFailed
|
||||
})
|
||||
result
|
||||
.map(|buf| {
|
||||
output.copy_from_slice(buf);
|
||||
increase_nonce(&mut self.nonce);
|
||||
})
|
||||
.map_err(|_| {
|
||||
error!(
|
||||
"AEAD decrypt failed, nonce={:?}, input={:?}, tag={:?}, err: decrypt failure",
|
||||
ByteStr::new(&self.nonce),
|
||||
ByteStr::new(&input[..input.len() - tag_size]),
|
||||
ByteStr::new(&input[input.len() - tag_size..])
|
||||
);
|
||||
Error::AeadDecryptFailed
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+103
-81
@@ -1,21 +1,32 @@
|
||||
//! Cipher defined with libsodium
|
||||
|
||||
use std::ptr;
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
use std::{
|
||||
ptr,
|
||||
sync::{Once, ONCE_INIT},
|
||||
};
|
||||
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
|
||||
use libc::{c_ulonglong, uint32_t};
|
||||
use libsodium_ffi::{
|
||||
crypto_aead_xchacha20poly1305_ietf_decrypt, crypto_aead_xchacha20poly1305_ietf_encrypt,
|
||||
crypto_stream_chacha20_ietf_xor_ic, crypto_stream_chacha20_xor_ic, crypto_stream_salsa20_xor_ic,
|
||||
crypto_stream_xsalsa20_xor_ic, sodium_init,
|
||||
crypto_aead_xchacha20poly1305_ietf_decrypt,
|
||||
crypto_aead_xchacha20poly1305_ietf_encrypt,
|
||||
crypto_stream_chacha20_ietf_xor_ic,
|
||||
crypto_stream_chacha20_xor_ic,
|
||||
crypto_stream_salsa20_xor_ic,
|
||||
crypto_stream_xsalsa20_xor_ic,
|
||||
sodium_init,
|
||||
};
|
||||
|
||||
use crypto::aead::{increase_nonce, make_skey};
|
||||
use crypto::cipher::Error;
|
||||
use crypto::{AeadDecryptor, AeadEncryptor};
|
||||
use crypto::{CipherResult, CipherType, StreamCipher};
|
||||
use crypto::{
|
||||
aead::{increase_nonce, make_skey},
|
||||
cipher::Error,
|
||||
AeadDecryptor,
|
||||
AeadEncryptor,
|
||||
CipherResult,
|
||||
CipherType,
|
||||
StreamCipher,
|
||||
};
|
||||
|
||||
static SODIUM_INIT_FLAG: Once = ONCE_INIT;
|
||||
|
||||
@@ -38,13 +49,15 @@ impl SodiumStreamCipher {
|
||||
}
|
||||
|
||||
SODIUM_INIT_FLAG.call_once(|| unsafe {
|
||||
assert_eq!(sodium_init(), 0);
|
||||
});
|
||||
assert_eq!(sodium_init(), 0);
|
||||
});
|
||||
|
||||
SodiumStreamCipher { cipher_type: t,
|
||||
key: key.to_owned(),
|
||||
iv: iv.to_owned(),
|
||||
counter: 0, }
|
||||
SodiumStreamCipher {
|
||||
cipher_type: t,
|
||||
key: key.to_owned(),
|
||||
iv: iv.to_owned(),
|
||||
counter: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn padding_len(&self) -> usize {
|
||||
@@ -59,12 +72,14 @@ impl SodiumStreamCipher {
|
||||
|
||||
let mut out_buf = BytesMut::with_capacity((data.len() + padding) * 2);
|
||||
|
||||
crypto_stream_xor_ic(self.cipher_type,
|
||||
self.counter / SODIUM_BLOCK_SIZE,
|
||||
&self.iv,
|
||||
&self.key,
|
||||
&plain_text,
|
||||
&mut out_buf)?;
|
||||
crypto_stream_xor_ic(
|
||||
self.cipher_type,
|
||||
self.counter / SODIUM_BLOCK_SIZE,
|
||||
&self.iv,
|
||||
&self.key,
|
||||
&plain_text,
|
||||
&mut out_buf,
|
||||
)?;
|
||||
|
||||
out.put_slice(&out_buf[padding..padding + data.len()]);
|
||||
|
||||
@@ -73,49 +88,50 @@ impl SodiumStreamCipher {
|
||||
}
|
||||
}
|
||||
|
||||
fn crypto_stream_xor_ic<B: BufMut>(t: CipherType,
|
||||
ic: usize,
|
||||
iv: &[u8],
|
||||
key: &[u8],
|
||||
data: &[u8],
|
||||
out: &mut B)
|
||||
-> CipherResult<()> {
|
||||
fn crypto_stream_xor_ic<B: BufMut>(
|
||||
t: CipherType,
|
||||
ic: usize,
|
||||
iv: &[u8],
|
||||
key: &[u8],
|
||||
data: &[u8],
|
||||
out: &mut B,
|
||||
) -> CipherResult<()> {
|
||||
assert!(data.len() <= unsafe { out.bytes_mut().len() });
|
||||
|
||||
let ret = unsafe {
|
||||
match t {
|
||||
CipherType::ChaCha20 => {
|
||||
crypto_stream_chacha20_xor_ic(out.bytes_mut().as_mut_ptr(),
|
||||
data.as_ptr(),
|
||||
data.len() as c_ulonglong,
|
||||
iv.as_ptr(),
|
||||
ic as c_ulonglong,
|
||||
key.as_ptr())
|
||||
}
|
||||
CipherType::ChaCha20Ietf => {
|
||||
crypto_stream_chacha20_ietf_xor_ic(out.bytes_mut().as_mut_ptr(),
|
||||
data.as_ptr(),
|
||||
data.len() as c_ulonglong,
|
||||
iv.as_ptr(),
|
||||
ic as uint32_t,
|
||||
key.as_ptr())
|
||||
}
|
||||
CipherType::Salsa20 => {
|
||||
crypto_stream_salsa20_xor_ic(out.bytes_mut().as_mut_ptr(),
|
||||
data.as_ptr(),
|
||||
data.len() as c_ulonglong,
|
||||
iv.as_ptr(),
|
||||
ic as c_ulonglong,
|
||||
key.as_ptr())
|
||||
}
|
||||
CipherType::XSalsa20 => {
|
||||
crypto_stream_xsalsa20_xor_ic(out.bytes_mut().as_mut_ptr(),
|
||||
data.as_ptr(),
|
||||
data.len() as c_ulonglong,
|
||||
iv.as_ptr(),
|
||||
ic as c_ulonglong,
|
||||
key.as_ptr())
|
||||
}
|
||||
CipherType::ChaCha20 => crypto_stream_chacha20_xor_ic(
|
||||
out.bytes_mut().as_mut_ptr(),
|
||||
data.as_ptr(),
|
||||
data.len() as c_ulonglong,
|
||||
iv.as_ptr(),
|
||||
ic as c_ulonglong,
|
||||
key.as_ptr(),
|
||||
),
|
||||
CipherType::ChaCha20Ietf => crypto_stream_chacha20_ietf_xor_ic(
|
||||
out.bytes_mut().as_mut_ptr(),
|
||||
data.as_ptr(),
|
||||
data.len() as c_ulonglong,
|
||||
iv.as_ptr(),
|
||||
ic as uint32_t,
|
||||
key.as_ptr(),
|
||||
),
|
||||
CipherType::Salsa20 => crypto_stream_salsa20_xor_ic(
|
||||
out.bytes_mut().as_mut_ptr(),
|
||||
data.as_ptr(),
|
||||
data.len() as c_ulonglong,
|
||||
iv.as_ptr(),
|
||||
ic as c_ulonglong,
|
||||
key.as_ptr(),
|
||||
),
|
||||
CipherType::XSalsa20 => crypto_stream_xsalsa20_xor_ic(
|
||||
out.bytes_mut().as_mut_ptr(),
|
||||
data.as_ptr(),
|
||||
data.len() as c_ulonglong,
|
||||
iv.as_ptr(),
|
||||
ic as c_ulonglong,
|
||||
key.as_ptr(),
|
||||
),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
@@ -165,9 +181,11 @@ impl SodiumAeadCipher {
|
||||
|
||||
let skey = make_skey(t, key, salt);
|
||||
|
||||
SodiumAeadCipher { cipher_type: t,
|
||||
key: skey,
|
||||
nonce: nonce, }
|
||||
SodiumAeadCipher {
|
||||
cipher_type: t,
|
||||
key: skey,
|
||||
nonce: nonce,
|
||||
}
|
||||
}
|
||||
|
||||
fn increase_nonce(&mut self) {
|
||||
@@ -189,15 +207,17 @@ impl AeadEncryptor for SodiumAeadCipher {
|
||||
|
||||
let ret = match self.cipher_type {
|
||||
CipherType::XChaCha20IetfPoly1305 => unsafe {
|
||||
crypto_aead_xchacha20poly1305_ietf_encrypt(output.as_mut_ptr(),
|
||||
&mut len,
|
||||
input.as_ptr(),
|
||||
input.len() as c_ulonglong,
|
||||
ptr::null(),
|
||||
0,
|
||||
ptr::null(),
|
||||
self.nonce.as_ref().as_ptr(),
|
||||
self.key.as_ref().as_ptr())
|
||||
crypto_aead_xchacha20poly1305_ietf_encrypt(
|
||||
output.as_mut_ptr(),
|
||||
&mut len,
|
||||
input.as_ptr(),
|
||||
input.len() as c_ulonglong,
|
||||
ptr::null(),
|
||||
0,
|
||||
ptr::null(),
|
||||
self.nonce.as_ref().as_ptr(),
|
||||
self.key.as_ref().as_ptr(),
|
||||
)
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
@@ -218,15 +238,17 @@ impl AeadDecryptor for SodiumAeadCipher {
|
||||
|
||||
let ret = match self.cipher_type {
|
||||
CipherType::XChaCha20IetfPoly1305 => unsafe {
|
||||
crypto_aead_xchacha20poly1305_ietf_decrypt(output.as_mut_ptr(),
|
||||
&mut len,
|
||||
ptr::null_mut(),
|
||||
input.as_ptr(),
|
||||
input.len() as c_ulonglong,
|
||||
ptr::null(),
|
||||
0,
|
||||
self.nonce.as_ref().as_ptr(),
|
||||
self.key.as_ref().as_ptr())
|
||||
crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
output.as_mut_ptr(),
|
||||
&mut len,
|
||||
ptr::null_mut(),
|
||||
input.as_ptr(),
|
||||
input.len() as c_ulonglong,
|
||||
ptr::null(),
|
||||
0,
|
||||
self.nonce.as_ref().as_ptr(),
|
||||
self.key.as_ref().as_ptr(),
|
||||
)
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
+12
-8
@@ -1,13 +1,15 @@
|
||||
//! Stream ciphers
|
||||
|
||||
use crypto::cipher::{CipherCategory, CipherResult, CipherType};
|
||||
use crypto::dummy;
|
||||
use crypto::openssl;
|
||||
use crypto::rc4_md5;
|
||||
#[cfg(feature = "sodium")]
|
||||
use crypto::sodium;
|
||||
use crypto::table;
|
||||
use crypto::CryptoMode;
|
||||
use crypto::{
|
||||
cipher::{CipherCategory, CipherResult, CipherType},
|
||||
dummy,
|
||||
openssl,
|
||||
rc4_md5,
|
||||
table,
|
||||
CryptoMode,
|
||||
};
|
||||
|
||||
use bytes::BufMut;
|
||||
|
||||
@@ -91,8 +93,10 @@ define_stream_ciphers! {
|
||||
|
||||
/// Generate a specific Cipher with key and initialize vector
|
||||
pub fn new_stream(t: CipherType, key: &[u8], iv: &[u8], mode: CryptoMode) -> StreamCipherVariant {
|
||||
assert!(t.category() == CipherCategory::Stream,
|
||||
"only allow initializing with stream cipher");
|
||||
assert!(
|
||||
t.category() == CipherCategory::Stream,
|
||||
"only allow initializing with stream cipher"
|
||||
);
|
||||
|
||||
match t {
|
||||
CipherType::Table => StreamCipherVariant::new(table::TableCipher::new(key, mode)),
|
||||
|
||||
+24
-19
@@ -2,9 +2,12 @@
|
||||
|
||||
use std::io::Cursor;
|
||||
|
||||
use crypto::digest::{self, Digest, DigestType};
|
||||
use crypto::CryptoMode;
|
||||
use crypto::{CipherResult, StreamCipher};
|
||||
use crypto::{
|
||||
digest::{self, Digest, DigestType},
|
||||
CipherResult,
|
||||
CryptoMode,
|
||||
StreamCipher,
|
||||
};
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
@@ -35,22 +38,24 @@ impl TableCipher {
|
||||
table.sort_by(|x, y| (a % (*x + i)).cmp(&(a % (*y + i))))
|
||||
}
|
||||
|
||||
TableCipher { table: match mode {
|
||||
CryptoMode::Encrypt => {
|
||||
let mut t = [0u8; TABLE_SIZE];
|
||||
for i in 0..TABLE_SIZE {
|
||||
t[i] = table[i] as u8;
|
||||
}
|
||||
t
|
||||
}
|
||||
CryptoMode::Decrypt => {
|
||||
let mut t = [0u8; TABLE_SIZE];
|
||||
for (idx, &item) in table.iter().enumerate() {
|
||||
t[item as usize] = idx as u8;
|
||||
}
|
||||
t
|
||||
}
|
||||
}, }
|
||||
TableCipher {
|
||||
table: match mode {
|
||||
CryptoMode::Encrypt => {
|
||||
let mut t = [0u8; TABLE_SIZE];
|
||||
for i in 0..TABLE_SIZE {
|
||||
t[i] = table[i] as u8;
|
||||
}
|
||||
t
|
||||
}
|
||||
CryptoMode::Decrypt => {
|
||||
let mut t = [0u8; TABLE_SIZE];
|
||||
for (idx, &item) in table.iter().enumerate() {
|
||||
t[item as usize] = idx as u8;
|
||||
}
|
||||
t
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn process<B: BufMut>(&mut self, data: &[u8], out: &mut B) -> CipherResult<()> {
|
||||
|
||||
+4
-5
@@ -108,11 +108,10 @@ extern crate url;
|
||||
/// ShadowSocks version
|
||||
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
pub use self::config::{ClientConfig, Config, ConfigType, ServerAddr, ServerConfig};
|
||||
pub use self::relay::dns::run as run_dns;
|
||||
pub use self::relay::local::run as run_local;
|
||||
pub use self::relay::server::run as run_server;
|
||||
pub use self::relay::tcprelay::client::Socks5Client;
|
||||
pub use self::{
|
||||
config::{ClientConfig, Config, ConfigType, ServerAddr, ServerConfig},
|
||||
relay::{dns::run as run_dns, local::run as run_local, server::run as run_server, tcprelay::client::Socks5Client},
|
||||
};
|
||||
|
||||
pub mod config;
|
||||
pub mod crypto;
|
||||
|
||||
+79
-73
@@ -1,14 +1,12 @@
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use std::io;
|
||||
use std::process;
|
||||
use std::{io, process};
|
||||
|
||||
use libc;
|
||||
use tokio;
|
||||
use tokio_io::IoFuture;
|
||||
|
||||
use futures::stream::futures_unordered;
|
||||
use futures::{self, Future, Stream};
|
||||
use futures::{self, stream::futures_unordered, Future, Stream};
|
||||
|
||||
use plugin::Plugin;
|
||||
use relay::boxed_future;
|
||||
@@ -18,62 +16,68 @@ pub fn monitor_signal(plugins: Vec<Plugin>) -> impl Future<Item = (), Error = io
|
||||
use tokio_signal::unix::Signal;
|
||||
|
||||
// Monitor SIGCHLD, triggered if subprocess (plugin) is exited.
|
||||
let fut1 = Signal::new(libc::SIGCHLD).and_then(|signal| {
|
||||
signal.take(1)
|
||||
.for_each(|_| -> Result<(), io::Error> {
|
||||
error!("Plugin exited unexpectly (SIGCHLD)");
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| libc::SIGCHLD)
|
||||
})
|
||||
.map_err(|err| {
|
||||
error!("Failed to monitor SIGCHLD, err: {:?}", err);
|
||||
err
|
||||
});
|
||||
let fut1 = Signal::new(libc::SIGCHLD)
|
||||
.and_then(|signal| {
|
||||
signal
|
||||
.take(1)
|
||||
.for_each(|_| -> Result<(), io::Error> {
|
||||
error!("Plugin exited unexpectly (SIGCHLD)");
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| libc::SIGCHLD)
|
||||
})
|
||||
.map_err(|err| {
|
||||
error!("Failed to monitor SIGCHLD, err: {:?}", err);
|
||||
err
|
||||
});
|
||||
|
||||
// Monitor SIGTERM, triggered if shadowsocks is exited gracefully. (Kill by user).
|
||||
let fut2 = Signal::new(libc::SIGTERM).and_then(|sigterm| {
|
||||
sigterm.take(1)
|
||||
.for_each(|_| -> Result<(), io::Error> {
|
||||
info!("Received SIGTERM, exiting.");
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| libc::SIGTERM)
|
||||
})
|
||||
.map_err(|err| {
|
||||
error!("Failed to monitor SIGTERM, err: {:?}", err);
|
||||
err
|
||||
});
|
||||
let fut2 = Signal::new(libc::SIGTERM)
|
||||
.and_then(|sigterm| {
|
||||
sigterm
|
||||
.take(1)
|
||||
.for_each(|_| -> Result<(), io::Error> {
|
||||
info!("Received SIGTERM, exiting.");
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| libc::SIGTERM)
|
||||
})
|
||||
.map_err(|err| {
|
||||
error!("Failed to monitor SIGTERM, err: {:?}", err);
|
||||
err
|
||||
});
|
||||
|
||||
// Monitor SIGINT, triggered by CTRL-C
|
||||
let fut3 = Signal::new(libc::SIGINT).and_then(|sigint| {
|
||||
sigint.take(1)
|
||||
.for_each(|_| -> Result<(), io::Error> {
|
||||
info!("Received SIGINT, exiting.");
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| libc::SIGINT)
|
||||
})
|
||||
.map_err(|err| {
|
||||
error!("Failed to monitor SIGINT, err: {:?}", err);
|
||||
err
|
||||
});
|
||||
let fut3 = Signal::new(libc::SIGINT)
|
||||
.and_then(|sigint| {
|
||||
sigint
|
||||
.take(1)
|
||||
.for_each(|_| -> Result<(), io::Error> {
|
||||
info!("Received SIGINT, exiting.");
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| libc::SIGINT)
|
||||
})
|
||||
.map_err(|err| {
|
||||
error!("Failed to monitor SIGINT, err: {:?}", err);
|
||||
err
|
||||
});
|
||||
|
||||
// Join them all, if any of them is triggered, kill all subprocesses and exit.
|
||||
futures_unordered(vec![boxed_future(fut1), boxed_future(fut2), boxed_future(fut3)])
|
||||
.into_future()
|
||||
.then(move |r| {
|
||||
// Something happened ... killing all subprocesses
|
||||
info!("Killing {} plugin(s) and then ... Bye Bye :)", plugins.len());
|
||||
drop(plugins);
|
||||
// Something happened ... killing all subprocesses
|
||||
info!("Killing {} plugin(s) and then ... Bye Bye :)", plugins.len());
|
||||
drop(plugins);
|
||||
|
||||
match r {
|
||||
Ok(..) => {
|
||||
process::exit(0);
|
||||
}
|
||||
Err((err, ..)) => Err(err),
|
||||
}
|
||||
})
|
||||
match r {
|
||||
Ok(..) => {
|
||||
process::exit(0);
|
||||
}
|
||||
Err((err, ..)) => Err(err),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -86,27 +90,29 @@ pub fn monitor_signal(plugins: Vec<Plugin>) -> impl Future<Item = (), Error = io
|
||||
// a task into the current executor. So if there is no current running executor, thread
|
||||
// will panic.
|
||||
futures::lazy(|| {
|
||||
let fut1 = Event::ctrl_c().and_then(|ev| {
|
||||
ev.take(1).for_each(|_| -> Result<(), io::Error> {
|
||||
error!("Received Ctrl-C event");
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
.map_err(|err| {
|
||||
error!("Failed to monitor Ctrl-C event: {:?}", err);
|
||||
err
|
||||
});
|
||||
let fut1 = Event::ctrl_c()
|
||||
.and_then(|ev| {
|
||||
ev.take(1).for_each(|_| -> Result<(), io::Error> {
|
||||
error!("Received Ctrl-C event");
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
.map_err(|err| {
|
||||
error!("Failed to monitor Ctrl-C event: {:?}", err);
|
||||
err
|
||||
});
|
||||
|
||||
let fut2 = Event::ctrl_break().and_then(|ev| {
|
||||
ev.take(1).for_each(|_| -> Result<(), io::Error> {
|
||||
error!("Received Ctrl-Break event");
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
.map_err(|err| {
|
||||
error!("Failed to monitor Ctrl-Break event: {:?}", err);
|
||||
err
|
||||
});
|
||||
let fut2 = Event::ctrl_break()
|
||||
.and_then(|ev| {
|
||||
ev.take(1).for_each(|_| -> Result<(), io::Error> {
|
||||
error!("Received Ctrl-Break event");
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
.map_err(|err| {
|
||||
error!("Failed to monitor Ctrl-Break event: {:?}", err);
|
||||
err
|
||||
});
|
||||
|
||||
// Join them all, if any of them is triggered, kill all subprocesses and exit.
|
||||
futures_unordered(vec![boxed_future(fut1), boxed_future(fut2)])
|
||||
@@ -119,7 +125,7 @@ pub fn monitor_signal(plugins: Vec<Plugin>) -> impl Future<Item = (), Error = io
|
||||
Ok(..) => {
|
||||
process::exit(libc::EXIT_FAILURE);
|
||||
}
|
||||
Err((err, ..)) => Err(err)
|
||||
Err((err, ..)) => Err(err),
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -130,6 +136,6 @@ pub fn monitor_signal(plugins: Vec<Plugin>) -> impl Future<Item = (), Error = io
|
||||
// FIXME: What can I do ...
|
||||
// Blocks forever
|
||||
futures::empty::<(), ()>().and_then(|_| {
|
||||
drop(plugins);
|
||||
})
|
||||
drop(plugins);
|
||||
})
|
||||
}
|
||||
|
||||
+15
-11
@@ -12,11 +12,12 @@
|
||||
//! +------------+ +---------------------------+
|
||||
//! ```
|
||||
|
||||
use std::io;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener};
|
||||
use std::{
|
||||
io,
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener},
|
||||
};
|
||||
|
||||
use subprocess::Popen;
|
||||
use subprocess::Result as PopenResult;
|
||||
use subprocess::{Popen, Result as PopenResult};
|
||||
|
||||
use config::{Config, ServerAddr};
|
||||
|
||||
@@ -75,8 +76,10 @@ pub fn launch_plugin(config: &mut Config, mode: PluginMode) -> io::Result<Vec<Pl
|
||||
}
|
||||
Ok(p) => {
|
||||
let svr_addr = ServerAddr::SocketAddr(local_addr);
|
||||
plugins.push(Plugin { addr: svr_addr.clone(),
|
||||
process: p, });
|
||||
plugins.push(Plugin {
|
||||
addr: svr_addr.clone(),
|
||||
process: p,
|
||||
});
|
||||
|
||||
// Replace addr with plugin
|
||||
svr_addr
|
||||
@@ -99,11 +102,12 @@ pub fn launch_plugin(config: &mut Config, mode: PluginMode) -> io::Result<Vec<Pl
|
||||
Ok(plugins)
|
||||
}
|
||||
|
||||
fn start_plugin(plugin: &PluginConfig,
|
||||
remote: &ServerAddr,
|
||||
local: &SocketAddr,
|
||||
mode: PluginMode)
|
||||
-> PopenResult<Popen> {
|
||||
fn start_plugin(
|
||||
plugin: &PluginConfig,
|
||||
remote: &ServerAddr,
|
||||
local: &SocketAddr,
|
||||
mode: PluginMode,
|
||||
) -> PopenResult<Popen> {
|
||||
if plugin.plugin == "obfsproxy" {
|
||||
obfs_proxy::start_plugin(plugin, remote, local, mode)
|
||||
} else {
|
||||
|
||||
+20
-15
@@ -1,7 +1,6 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use subprocess::Result as PopenResult;
|
||||
use subprocess::{Exec, Popen};
|
||||
use subprocess::{Exec, Popen, Result as PopenResult};
|
||||
|
||||
use config::ServerAddr;
|
||||
|
||||
@@ -31,13 +30,15 @@ use super::{PluginConfig, PluginMode};
|
||||
/// And the rest parameters are all assembled here.
|
||||
/// Some old obfsproxy will not be supported as it doesn't even support
|
||||
/// "--data-dir" option
|
||||
pub fn start_plugin(plugin: &PluginConfig,
|
||||
remote: &ServerAddr,
|
||||
local: &SocketAddr,
|
||||
mode: PluginMode)
|
||||
-> PopenResult<Popen> {
|
||||
let mut cmd = Exec::cmd(&plugin.plugin).arg("--data-dir")
|
||||
.arg(format!("/tmp/{}_{}_{}", plugin.plugin, remote, local)); // FIXME: Not compatible in Windows
|
||||
pub fn start_plugin(
|
||||
plugin: &PluginConfig,
|
||||
remote: &ServerAddr,
|
||||
local: &SocketAddr,
|
||||
mode: PluginMode,
|
||||
) -> PopenResult<Popen> {
|
||||
let mut cmd = Exec::cmd(&plugin.plugin)
|
||||
.arg("--data-dir")
|
||||
.arg(format!("/tmp/{}_{}_{}", plugin.plugin, remote, local)); // FIXME: Not compatible in Windows
|
||||
|
||||
if let Some(ref opt) = plugin.plugin_opt {
|
||||
for arg in opt.split(' ') {
|
||||
@@ -46,12 +47,16 @@ pub fn start_plugin(plugin: &PluginConfig,
|
||||
}
|
||||
|
||||
let cmd = match mode {
|
||||
PluginMode::Client => cmd.arg("--dest").arg(remote.to_string())
|
||||
.arg("client")
|
||||
.arg(local.to_string()),
|
||||
PluginMode::Server => cmd.arg("--dest").arg(local.to_string())
|
||||
.arg("server")
|
||||
.arg(remote.to_string()),
|
||||
PluginMode::Client => cmd
|
||||
.arg("--dest")
|
||||
.arg(remote.to_string())
|
||||
.arg("client")
|
||||
.arg(local.to_string()),
|
||||
PluginMode::Server => cmd
|
||||
.arg("--dest")
|
||||
.arg(local.to_string())
|
||||
.arg("server")
|
||||
.arg(remote.to_string()),
|
||||
};
|
||||
|
||||
cmd.popen()
|
||||
|
||||
+13
-12
@@ -1,24 +1,25 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use subprocess::Result as PopenResult;
|
||||
use subprocess::{Exec, NullFile, Popen};
|
||||
use subprocess::{Exec, NullFile, Popen, Result as PopenResult};
|
||||
|
||||
use config::ServerAddr;
|
||||
|
||||
use super::{PluginConfig, PluginMode};
|
||||
|
||||
pub fn start_plugin(plugin: &PluginConfig,
|
||||
remote: &ServerAddr,
|
||||
local: &SocketAddr,
|
||||
_mode: PluginMode)
|
||||
-> PopenResult<Popen> {
|
||||
pub fn start_plugin(
|
||||
plugin: &PluginConfig,
|
||||
remote: &ServerAddr,
|
||||
local: &SocketAddr,
|
||||
_mode: PluginMode,
|
||||
) -> PopenResult<Popen> {
|
||||
trace!("Start plugin \"{:?}\" remote: {}, local: {}", plugin, remote, local);
|
||||
|
||||
let mut exec = Exec::cmd(&plugin.plugin).env("SS_REMOTE_HOST", remote.host())
|
||||
.env("SS_REMOTE_PORT", remote.port().to_string())
|
||||
.env("SS_LOCAL_HOST", local.ip().to_string())
|
||||
.env("SS_LOCAL_PORT", local.port().to_string())
|
||||
.stdin(NullFile);
|
||||
let mut exec = Exec::cmd(&plugin.plugin)
|
||||
.env("SS_REMOTE_HOST", remote.host())
|
||||
.env("SS_REMOTE_PORT", remote.port().to_string())
|
||||
.env("SS_LOCAL_HOST", local.ip().to_string())
|
||||
.env("SS_LOCAL_PORT", local.port().to_string())
|
||||
.stdin(NullFile);
|
||||
|
||||
if let Some(ref opt) = plugin.plugin_opt {
|
||||
exec = exec.env("SS_PLUGIN_OPTIONS", opt);
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
//! DNS relay
|
||||
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::{io, sync::Arc};
|
||||
|
||||
use futures::Future;
|
||||
|
||||
|
||||
+47
-43
@@ -1,14 +1,15 @@
|
||||
//! Asynchronous DNS resolver
|
||||
|
||||
use std::io::{self, ErrorKind};
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
io::{self, ErrorKind},
|
||||
net::SocketAddr,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use futures::Future;
|
||||
use spin::Mutex;
|
||||
use tokio;
|
||||
use trust_dns_resolver::config::ResolverConfig;
|
||||
use trust_dns_resolver::AsyncResolver;
|
||||
use trust_dns_resolver::{config::ResolverConfig, AsyncResolver};
|
||||
|
||||
use config::Config;
|
||||
|
||||
@@ -68,50 +69,53 @@ fn init_resolver() -> AsyncResolver {
|
||||
resolver
|
||||
}
|
||||
|
||||
fn inner_resolve(config: Arc<Config>,
|
||||
addr: &str,
|
||||
port: u16,
|
||||
check_forbidden: bool)
|
||||
-> impl Future<Item = Vec<SocketAddr>, Error = io::Error> + Send {
|
||||
fn inner_resolve(
|
||||
config: Arc<Config>,
|
||||
addr: &str,
|
||||
port: u16,
|
||||
check_forbidden: bool,
|
||||
) -> impl Future<Item = Vec<SocketAddr>, Error = io::Error> + Send {
|
||||
let owned_addr = addr.to_owned();
|
||||
let owned_addr2 = owned_addr.clone();
|
||||
|
||||
GLOBAL_DNS_RESOLVER.lookup_ip(addr)
|
||||
.map_err(move |err| {
|
||||
error!("Failed to resolve {}, err: {}", owned_addr2, err);
|
||||
io::Error::new(io::ErrorKind::Other, "dns resolve error")
|
||||
})
|
||||
.and_then(move |lookup_result| {
|
||||
let mut vaddr = Vec::new();
|
||||
for ip in lookup_result.iter() {
|
||||
if check_forbidden {
|
||||
let forbidden_ip = &config.forbidden_ip;
|
||||
if forbidden_ip.contains(&ip) {
|
||||
debug!("Resolved {} => {}, which is skipped by forbidden_ip",
|
||||
owned_addr, ip);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
vaddr.push(SocketAddr::new(ip, port));
|
||||
}
|
||||
GLOBAL_DNS_RESOLVER
|
||||
.lookup_ip(addr)
|
||||
.map_err(move |err| {
|
||||
error!("Failed to resolve {}, err: {}", owned_addr2, err);
|
||||
io::Error::new(io::ErrorKind::Other, "dns resolve error")
|
||||
})
|
||||
.and_then(move |lookup_result| {
|
||||
let mut vaddr = Vec::new();
|
||||
for ip in lookup_result.iter() {
|
||||
if check_forbidden {
|
||||
let forbidden_ip = &config.forbidden_ip;
|
||||
if forbidden_ip.contains(&ip) {
|
||||
debug!("Resolved {} => {}, which is skipped by forbidden_ip", owned_addr, ip);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
vaddr.push(SocketAddr::new(ip, port));
|
||||
}
|
||||
|
||||
if vaddr.is_empty() {
|
||||
let err = io::Error::new(ErrorKind::Other,
|
||||
format!("resolved {} to empty address, all IPs are filtered",
|
||||
owned_addr));
|
||||
Err(err)
|
||||
} else {
|
||||
debug!("Resolved {} => {:?}", owned_addr, vaddr);
|
||||
Ok(vaddr)
|
||||
}
|
||||
})
|
||||
if vaddr.is_empty() {
|
||||
let err = io::Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("resolved {} to empty address, all IPs are filtered", owned_addr),
|
||||
);
|
||||
Err(err)
|
||||
} else {
|
||||
debug!("Resolved {} => {:?}", owned_addr, vaddr);
|
||||
Ok(vaddr)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Resolve address to IP
|
||||
pub fn resolve(config: Arc<Config>,
|
||||
addr: &str,
|
||||
port: u16,
|
||||
check_forbidden: bool)
|
||||
-> impl Future<Item = Vec<SocketAddr>, Error = io::Error> + Send {
|
||||
pub fn resolve(
|
||||
config: Arc<Config>,
|
||||
addr: &str,
|
||||
port: u16,
|
||||
check_forbidden: bool,
|
||||
) -> impl Future<Item = Vec<SocketAddr>, Error = io::Error> + Send {
|
||||
inner_resolve(config, addr, port, check_forbidden)
|
||||
}
|
||||
|
||||
@@ -13,8 +13,10 @@ pub struct RoundRobin {
|
||||
|
||||
impl RoundRobin {
|
||||
pub fn new(config: &Config) -> RoundRobin {
|
||||
RoundRobin { servers: config.server.iter().map(|s| Arc::new(s.clone())).collect(),
|
||||
index: 0usize, }
|
||||
RoundRobin {
|
||||
servers: config.server.iter().map(|s| Arc::new(s.clone())).collect(),
|
||||
index: 0usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-18
@@ -1,17 +1,13 @@
|
||||
//! Local side
|
||||
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::{io, sync::Arc};
|
||||
|
||||
use futures::stream::futures_unordered;
|
||||
use futures::{Future, Stream};
|
||||
use futures::{stream::futures_unordered, Future, Stream};
|
||||
|
||||
use super::dns_resolver::set_dns_config;
|
||||
use config::Config;
|
||||
use plugin::{launch_plugin, PluginMode};
|
||||
use relay::boxed_future;
|
||||
use relay::tcprelay::local::run as run_tcp;
|
||||
use relay::udprelay::local::run as run_udp;
|
||||
use relay::{boxed_future, tcprelay::local::run as run_tcp, udprelay::local::run as run_udp};
|
||||
|
||||
/// Relay server running under local environment.
|
||||
///
|
||||
@@ -19,17 +15,21 @@ use relay::udprelay::local::run as run_udp;
|
||||
/// extern crate tokio;
|
||||
/// extern crate shadowsocks;
|
||||
///
|
||||
/// use shadowsocks::config::{Config, ServerConfig};
|
||||
/// use shadowsocks::crypto::CipherType;
|
||||
/// use shadowsocks::relay::local::run;
|
||||
/// use shadowsocks::{
|
||||
/// config::{Config, ServerConfig},
|
||||
/// crypto::CipherType,
|
||||
/// relay::local::run,
|
||||
/// };
|
||||
///
|
||||
/// use tokio::prelude::*;
|
||||
///
|
||||
/// let mut config = Config::new();
|
||||
/// config.local = Some("127.0.0.1:1080".parse().unwrap());
|
||||
/// config.server = vec![ServerConfig::basic("127.0.0.1:8388".parse().unwrap(),
|
||||
/// "server-password".to_string(),
|
||||
/// CipherType::Aes256Cfb)];
|
||||
/// config.server = vec![ServerConfig::basic(
|
||||
/// "127.0.0.1:8388".parse().unwrap(),
|
||||
/// "server-password".to_string(),
|
||||
/// CipherType::Aes256Cfb,
|
||||
/// )];
|
||||
/// let fut = run(config);
|
||||
/// tokio::run(fut.map_err(|err| panic!("Server run failed with error {}", err)));
|
||||
/// ```
|
||||
@@ -63,9 +63,9 @@ pub fn run(mut config: Config) -> impl Future<Item = (), Error = io::Error> + Se
|
||||
vf.push(boxed_future(mon));
|
||||
vf.push(boxed_future(tcp_fut));
|
||||
futures_unordered(vf).into_future().then(|res| -> io::Result<()> {
|
||||
match res {
|
||||
Ok(..) => Ok(()),
|
||||
Err((err, ..)) => Err(err),
|
||||
}
|
||||
})
|
||||
match res {
|
||||
Ok(..) => Ok(()),
|
||||
Err((err, ..)) => Err(err),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+2
-1
@@ -13,7 +13,8 @@ pub mod udprelay;
|
||||
mod utils;
|
||||
|
||||
pub fn boxed_future<T, E, F>(f: F) -> Box<Future<Item = T, Error = E> + Send + 'static>
|
||||
where F: Future<Item = T, Error = E> + Send + 'static
|
||||
where
|
||||
F: Future<Item = T, Error = E> + Send + 'static,
|
||||
{
|
||||
Box::new(f)
|
||||
}
|
||||
|
||||
+18
-18
@@ -1,17 +1,13 @@
|
||||
//! Server side
|
||||
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::{io, sync::Arc};
|
||||
|
||||
use futures::stream::futures_unordered;
|
||||
use futures::{Future, Stream};
|
||||
use futures::{stream::futures_unordered, Future, Stream};
|
||||
|
||||
use super::dns_resolver::set_dns_config;
|
||||
use config::Config;
|
||||
use plugin::{launch_plugin, PluginMode};
|
||||
use relay::boxed_future;
|
||||
use relay::tcprelay::server::run as run_tcp;
|
||||
use relay::udprelay::server::run as run_udp;
|
||||
use relay::{boxed_future, tcprelay::server::run as run_tcp, udprelay::server::run as run_udp};
|
||||
|
||||
/// Relay server running on server side.
|
||||
///
|
||||
@@ -19,16 +15,20 @@ use relay::udprelay::server::run as run_udp;
|
||||
/// extern crate tokio;
|
||||
/// extern crate shadowsocks;
|
||||
///
|
||||
/// use shadowsocks::config::{Config, ServerConfig};
|
||||
/// use shadowsocks::crypto::CipherType;
|
||||
/// use shadowsocks::relay::server::run;
|
||||
/// use shadowsocks::{
|
||||
/// config::{Config, ServerConfig},
|
||||
/// crypto::CipherType,
|
||||
/// relay::server::run,
|
||||
/// };
|
||||
///
|
||||
/// use tokio::prelude::*;
|
||||
///
|
||||
/// let mut config = Config::new();
|
||||
/// config.server = vec![ServerConfig::basic("127.0.0.1:8388".parse().unwrap(),
|
||||
/// "server-password".to_string(),
|
||||
/// CipherType::Aes256Cfb)];
|
||||
/// config.server = vec![ServerConfig::basic(
|
||||
/// "127.0.0.1:8388".parse().unwrap(),
|
||||
/// "server-password".to_string(),
|
||||
/// CipherType::Aes256Cfb,
|
||||
/// )];
|
||||
///
|
||||
/// let fut = run(config);
|
||||
/// tokio::run(fut.map_err(|err| panic!("Server run failed with error {}", err)));
|
||||
@@ -64,9 +64,9 @@ pub fn run(mut config: Config) -> impl Future<Item = (), Error = io::Error> + Se
|
||||
vf.push(boxed_future(tcp_fut));
|
||||
|
||||
futures_unordered(vf).into_future().then(|res| -> io::Result<()> {
|
||||
match res {
|
||||
Ok(..) => Ok(()),
|
||||
Err((err, ..)) => Err(err),
|
||||
}
|
||||
})
|
||||
match res {
|
||||
Ok(..) => Ok(()),
|
||||
Err((err, ..)) => Err(err),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+138
-110
@@ -2,24 +2,28 @@
|
||||
//!
|
||||
//! Implements [SOCKS Protocol Version 5](https://www.ietf.org/rfc/rfc1928.txt) proxy protocol
|
||||
|
||||
use std::convert::From;
|
||||
use std::error;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::io::{self, Cursor, Read, Write};
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
|
||||
use std::u8;
|
||||
use std::vec;
|
||||
use std::{
|
||||
convert::From,
|
||||
error,
|
||||
fmt::{self, Debug, Formatter},
|
||||
io::{self, Cursor, Read, Write},
|
||||
net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs},
|
||||
u8,
|
||||
vec,
|
||||
};
|
||||
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use bytes::{BufMut, Bytes, BytesMut, IntoBuf};
|
||||
|
||||
use futures::{Async, Future, Poll};
|
||||
|
||||
use tokio_io::io::read_exact;
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
use tokio_io::{io::read_exact, AsyncRead, AsyncWrite};
|
||||
|
||||
pub use self::consts::{
|
||||
SOCKS5_AUTH_METHOD_GSSAPI, SOCKS5_AUTH_METHOD_NONE, SOCKS5_AUTH_METHOD_NOT_ACCEPTABLE, SOCKS5_AUTH_METHOD_PASSWORD,
|
||||
SOCKS5_AUTH_METHOD_GSSAPI,
|
||||
SOCKS5_AUTH_METHOD_NONE,
|
||||
SOCKS5_AUTH_METHOD_NOT_ACCEPTABLE,
|
||||
SOCKS5_AUTH_METHOD_PASSWORD,
|
||||
};
|
||||
|
||||
use super::utils::{write_bytes, WriteBytes};
|
||||
@@ -167,8 +171,10 @@ pub struct Error {
|
||||
|
||||
impl Error {
|
||||
pub fn new(reply: Reply, message: &str) -> Error {
|
||||
Error { reply: reply,
|
||||
message: message.to_string(), }
|
||||
Error {
|
||||
reply: reply,
|
||||
message: message.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,6 +271,7 @@ impl fmt::Display for Address {
|
||||
|
||||
impl ToSocketAddrs for Address {
|
||||
type Iter = vec::IntoIter<SocketAddr>;
|
||||
|
||||
fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
|
||||
match self.clone() {
|
||||
Address::SocketAddress(addr) => Ok(vec![addr].into_iter()),
|
||||
@@ -286,7 +293,8 @@ impl From<(String, u16)> for Address {
|
||||
}
|
||||
|
||||
pub struct ReadAddress<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
reader: Option<R>,
|
||||
state: ReadAddressState,
|
||||
@@ -303,10 +311,11 @@ enum ReadAddressState {
|
||||
}
|
||||
|
||||
impl<R> Future for ReadAddress<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
type Item = (R, Address);
|
||||
type Error = Error;
|
||||
type Item = (R, Address);
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
debug_assert!(self.reader.is_some());
|
||||
@@ -340,13 +349,16 @@ impl<R> Future for ReadAddress<R>
|
||||
}
|
||||
|
||||
impl<R> ReadAddress<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
fn new(r: R) -> ReadAddress<R> {
|
||||
ReadAddress { reader: Some(r),
|
||||
state: ReadAddressState::ReadingType,
|
||||
buf: None,
|
||||
already_read: 0, }
|
||||
ReadAddress {
|
||||
reader: Some(r),
|
||||
state: ReadAddressState::ReadingType,
|
||||
buf: None,
|
||||
already_read: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn read_addr_type(&mut self) -> Poll<(), Error> {
|
||||
@@ -375,10 +387,12 @@ impl<R> ReadAddress<R>
|
||||
fn read_ipv4(&mut self) -> Poll<Address, Error> {
|
||||
try_ready!(self.read_data());
|
||||
let mut stream: Cursor<Bytes> = self.freeze_buf().into_buf();
|
||||
let v4addr = Ipv4Addr::new(stream.read_u8()?,
|
||||
stream.read_u8()?,
|
||||
stream.read_u8()?,
|
||||
stream.read_u8()?);
|
||||
let v4addr = Ipv4Addr::new(
|
||||
stream.read_u8()?,
|
||||
stream.read_u8()?,
|
||||
stream.read_u8()?,
|
||||
stream.read_u8()?,
|
||||
);
|
||||
let port = stream.read_u16::<BigEndian>()?;
|
||||
let addr = Address::SocketAddress(SocketAddr::V4(SocketAddrV4::new(v4addr, port)));
|
||||
Ok(Async::Ready(addr))
|
||||
@@ -387,14 +401,16 @@ impl<R> ReadAddress<R>
|
||||
fn read_ipv6(&mut self) -> Poll<Address, Error> {
|
||||
try_ready!(self.read_data());
|
||||
let mut stream: Cursor<Bytes> = self.freeze_buf().into_buf();
|
||||
let v6addr = Ipv6Addr::new(stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?);
|
||||
let v6addr = Ipv6Addr::new(
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
stream.read_u16::<BigEndian>()?,
|
||||
);
|
||||
let port = stream.read_u16::<BigEndian>()?;
|
||||
|
||||
let addr = Address::SocketAddress(SocketAddr::V6(SocketAddrV6::new(v6addr, port, 0, 0)));
|
||||
@@ -539,42 +555,43 @@ pub struct TcpRequestHeader {
|
||||
impl TcpRequestHeader {
|
||||
/// Creates a request header
|
||||
pub fn new(cmd: Command, addr: Address) -> TcpRequestHeader {
|
||||
TcpRequestHeader { command: cmd,
|
||||
address: addr, }
|
||||
TcpRequestHeader {
|
||||
command: cmd,
|
||||
address: addr,
|
||||
}
|
||||
}
|
||||
|
||||
/// Read from a reader
|
||||
pub fn read_from<R>(r: R) -> impl Future<Item = (R, TcpRequestHeader), Error = Error> + Send
|
||||
where R: AsyncRead + Send + 'static
|
||||
where
|
||||
R: AsyncRead + Send + 'static,
|
||||
{
|
||||
read_exact(r, [0u8; 3]).map_err(From::from)
|
||||
.and_then(|(r, buf)| {
|
||||
let ver = buf[0];
|
||||
if ver != consts::SOCKS5_VERSION {
|
||||
return Err(Error::new(Reply::ConnectionRefused,
|
||||
"Unsupported Socks version"));
|
||||
}
|
||||
read_exact(r, [0u8; 3])
|
||||
.map_err(From::from)
|
||||
.and_then(|(r, buf)| {
|
||||
let ver = buf[0];
|
||||
if ver != consts::SOCKS5_VERSION {
|
||||
return Err(Error::new(Reply::ConnectionRefused, "Unsupported Socks version"));
|
||||
}
|
||||
|
||||
let cmd = buf[1];
|
||||
let command = match Command::from_u8(cmd) {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
return Err(Error::new(Reply::CommandNotSupported,
|
||||
"Unsupported command"))
|
||||
}
|
||||
};
|
||||
let cmd = buf[1];
|
||||
let command = match Command::from_u8(cmd) {
|
||||
Some(c) => c,
|
||||
None => return Err(Error::new(Reply::CommandNotSupported, "Unsupported command")),
|
||||
};
|
||||
|
||||
Ok((r, command))
|
||||
})
|
||||
.and_then(|(r, command)| {
|
||||
Address::read_from(r).map(move |(conn, address)| {
|
||||
let header =
|
||||
TcpRequestHeader { command: command,
|
||||
address: address, };
|
||||
Ok((r, command))
|
||||
})
|
||||
.and_then(|(r, command)| {
|
||||
Address::read_from(r).map(move |(conn, address)| {
|
||||
let header = TcpRequestHeader {
|
||||
command: command,
|
||||
address: address,
|
||||
};
|
||||
|
||||
(conn, header)
|
||||
})
|
||||
})
|
||||
(conn, header)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Write data into a writer
|
||||
@@ -586,8 +603,10 @@ impl TcpRequestHeader {
|
||||
|
||||
/// Writes to buffer
|
||||
pub fn write_to_buf<B: BufMut>(&self, buf: &mut B) {
|
||||
let TcpRequestHeader { ref address,
|
||||
ref command, } = *self;
|
||||
let TcpRequestHeader {
|
||||
ref address,
|
||||
ref command,
|
||||
} = *self;
|
||||
|
||||
buf.put_slice(&[consts::SOCKS5_VERSION, command.as_u8(), 0x00]);
|
||||
address.write_to_buf(buf);
|
||||
@@ -620,35 +639,39 @@ pub struct TcpResponseHeader {
|
||||
impl TcpResponseHeader {
|
||||
/// Creates a response header
|
||||
pub fn new(reply: Reply, address: Address) -> TcpResponseHeader {
|
||||
TcpResponseHeader { reply: reply,
|
||||
address: address, }
|
||||
TcpResponseHeader {
|
||||
reply: reply,
|
||||
address: address,
|
||||
}
|
||||
}
|
||||
|
||||
/// Read from a reader
|
||||
pub fn read_from<R>(r: R) -> impl Future<Item = (R, TcpResponseHeader), Error = Error> + Send
|
||||
where R: AsyncRead + Send + 'static
|
||||
where
|
||||
R: AsyncRead + Send + 'static,
|
||||
{
|
||||
read_exact(r, [0u8; 3]).map_err(From::from)
|
||||
.and_then(|(r, buf)| {
|
||||
let ver = buf[0];
|
||||
let reply_code = buf[1];
|
||||
read_exact(r, [0u8; 3])
|
||||
.map_err(From::from)
|
||||
.and_then(|(r, buf)| {
|
||||
let ver = buf[0];
|
||||
let reply_code = buf[1];
|
||||
|
||||
if ver != consts::SOCKS5_VERSION {
|
||||
return Err(Error::new(Reply::ConnectionRefused,
|
||||
"Unsupported Socks version"));
|
||||
}
|
||||
if ver != consts::SOCKS5_VERSION {
|
||||
return Err(Error::new(Reply::ConnectionRefused, "Unsupported Socks version"));
|
||||
}
|
||||
|
||||
Ok((r, reply_code))
|
||||
})
|
||||
.and_then(|(r, reply_code)| {
|
||||
Address::read_from(r).map(move |(r, address)| {
|
||||
let rep = TcpResponseHeader { reply:
|
||||
Reply::from_u8(reply_code),
|
||||
address: address, };
|
||||
Ok((r, reply_code))
|
||||
})
|
||||
.and_then(|(r, reply_code)| {
|
||||
Address::read_from(r).map(move |(r, address)| {
|
||||
let rep = TcpResponseHeader {
|
||||
reply: Reply::from_u8(reply_code),
|
||||
address: address,
|
||||
};
|
||||
|
||||
(r, rep)
|
||||
})
|
||||
})
|
||||
(r, rep)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Write to a writer
|
||||
@@ -694,21 +717,22 @@ impl HandshakeRequest {
|
||||
|
||||
/// Read from a reader
|
||||
pub fn read_from<R>(r: R) -> impl Future<Item = (R, HandshakeRequest), Error = io::Error>
|
||||
where R: AsyncRead + Send + 'static
|
||||
where
|
||||
R: AsyncRead + Send + 'static,
|
||||
{
|
||||
read_exact(r, [0u8, 0u8]).and_then(|(r, buf)| {
|
||||
let ver = buf[0];
|
||||
let nmet = buf[1];
|
||||
read_exact(r, [0u8, 0u8])
|
||||
.and_then(|(r, buf)| {
|
||||
let ver = buf[0];
|
||||
let nmet = buf[1];
|
||||
|
||||
if ver != consts::SOCKS5_VERSION {
|
||||
return Err(io::Error::new(io::ErrorKind::Other,
|
||||
"Invalid Socks5 version"));
|
||||
}
|
||||
if ver != consts::SOCKS5_VERSION {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Invalid Socks5 version"));
|
||||
}
|
||||
|
||||
Ok((r, nmet))
|
||||
})
|
||||
.and_then(|(r, nmet)| read_exact(r, vec![0u8; nmet as usize]))
|
||||
.and_then(|(r, methods)| Ok((r, HandshakeRequest { methods: methods })))
|
||||
Ok((r, nmet))
|
||||
})
|
||||
.and_then(|(r, nmet)| read_exact(r, vec![0u8; nmet as usize]))
|
||||
.and_then(|(r, methods)| Ok((r, HandshakeRequest { methods: methods })))
|
||||
}
|
||||
|
||||
/// Write to a writer
|
||||
@@ -753,18 +777,19 @@ impl HandshakeResponse {
|
||||
|
||||
/// Read from a reader
|
||||
pub fn read_from<R>(r: R) -> impl Future<Item = (R, HandshakeResponse), Error = io::Error>
|
||||
where R: AsyncRead + Send + 'static
|
||||
where
|
||||
R: AsyncRead + Send + 'static,
|
||||
{
|
||||
read_exact(r, [0u8, 0u8]).and_then(|(r, buf)| {
|
||||
let ver = buf[0];
|
||||
let met = buf[1];
|
||||
let ver = buf[0];
|
||||
let met = buf[1];
|
||||
|
||||
if ver != consts::SOCKS5_VERSION {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "Invalid Socks5 version"))
|
||||
} else {
|
||||
Ok((r, HandshakeResponse { chosen_method: met }))
|
||||
}
|
||||
})
|
||||
if ver != consts::SOCKS5_VERSION {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "Invalid Socks5 version"))
|
||||
} else {
|
||||
Ok((r, HandshakeResponse { chosen_method: met }))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Write to a writer
|
||||
@@ -807,20 +832,23 @@ pub struct UdpAssociateHeader {
|
||||
impl UdpAssociateHeader {
|
||||
/// Creates a header
|
||||
pub fn new(frag: u8, address: Address) -> UdpAssociateHeader {
|
||||
UdpAssociateHeader { frag: frag,
|
||||
address: address, }
|
||||
UdpAssociateHeader {
|
||||
frag: frag,
|
||||
address: address,
|
||||
}
|
||||
}
|
||||
|
||||
/// Read from a reader
|
||||
pub fn read_from<R>(r: R) -> impl Future<Item = (R, UdpAssociateHeader), Error = Error> + Send
|
||||
where R: AsyncRead + Send + 'static
|
||||
where
|
||||
R: AsyncRead + Send + 'static,
|
||||
{
|
||||
read_exact(r, [0u8; 3]).map_err(From::from).and_then(|(r, buf)| {
|
||||
let frag = buf[2];
|
||||
Address::read_from(r).map(move |(r, address)| {
|
||||
let h = UdpAssociateHeader::new(frag, address);
|
||||
(r, h)
|
||||
})
|
||||
let h = UdpAssociateHeader::new(frag, address);
|
||||
(r, h)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+55
-31
@@ -32,9 +32,11 @@
|
||||
//! +--------------+---------------+--------------+------------+
|
||||
//! ```
|
||||
|
||||
use std::cmp;
|
||||
use std::io::{self, BufRead, Read};
|
||||
use std::u16;
|
||||
use std::{
|
||||
cmp,
|
||||
io::{self, BufRead, Read},
|
||||
u16,
|
||||
};
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
@@ -55,7 +57,8 @@ enum ReadingStep {
|
||||
|
||||
/// Reader wrapper that will decrypt data automatically
|
||||
pub struct DecryptedReader<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
reader: R,
|
||||
buffer: BytesMut,
|
||||
@@ -68,17 +71,20 @@ pub struct DecryptedReader<R>
|
||||
}
|
||||
|
||||
impl<R> DecryptedReader<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
pub fn new(r: R, t: CipherType, key: &[u8], nounce: &[u8]) -> DecryptedReader<R> {
|
||||
DecryptedReader { reader: r,
|
||||
buffer: BytesMut::with_capacity(BUFFER_SIZE),
|
||||
data: BytesMut::with_capacity(BUFFER_SIZE),
|
||||
cipher: crypto::new_aead_decryptor(t, key, nounce),
|
||||
pos: 0,
|
||||
sent_final: false,
|
||||
tag_size: t.tag_size(),
|
||||
read_step: ReadingStep::Length, }
|
||||
DecryptedReader {
|
||||
reader: r,
|
||||
buffer: BytesMut::with_capacity(BUFFER_SIZE),
|
||||
data: BytesMut::with_capacity(BUFFER_SIZE),
|
||||
cipher: crypto::new_aead_decryptor(t, key, nounce),
|
||||
pos: 0,
|
||||
sent_final: false,
|
||||
tag_size: t.tag_size(),
|
||||
read_step: ReadingStep::Length,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_ref(&self) -> &R {
|
||||
@@ -142,12 +148,18 @@ impl<R> DecryptedReader<R>
|
||||
if len > MAX_PACKET_SIZE {
|
||||
use std::io::{Error, ErrorKind};
|
||||
|
||||
error!("AEAD packet size must be <= {}, but received length {}",
|
||||
MAX_PACKET_SIZE, len);
|
||||
error!(
|
||||
"AEAD packet size must be <= {}, but received length {}",
|
||||
MAX_PACKET_SIZE, len
|
||||
);
|
||||
|
||||
let err = Error::new(ErrorKind::InvalidData,
|
||||
format!("AEAD packet size must be <= {}, but received length {}",
|
||||
MAX_PACKET_SIZE, len));
|
||||
let err = Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
format!(
|
||||
"AEAD packet size must be <= {}, but received length {}",
|
||||
MAX_PACKET_SIZE, len
|
||||
),
|
||||
);
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
@@ -200,7 +212,8 @@ impl<R> DecryptedReader<R>
|
||||
}
|
||||
|
||||
impl<R> BufRead for DecryptedReader<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
||||
while self.pos >= self.data.len() {
|
||||
@@ -223,7 +236,8 @@ impl<R> BufRead for DecryptedReader<R>
|
||||
}
|
||||
|
||||
impl<R> Read for DecryptedReader<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let nread = {
|
||||
@@ -236,7 +250,8 @@ impl<R> Read for DecryptedReader<R>
|
||||
}
|
||||
|
||||
impl<R> DecryptedRead for DecryptedReader<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
fn buffer_size(&self, data: &[u8]) -> usize {
|
||||
2 + self.tag_size // len and len_tag
|
||||
@@ -248,7 +263,8 @@ impl<R> AsyncRead for DecryptedReader<R> where R: AsyncRead {}
|
||||
|
||||
/// Writer wrapper that will encrypt data automatically
|
||||
pub struct EncryptedWriter<W>
|
||||
where W: AsyncWrite
|
||||
where
|
||||
W: AsyncWrite,
|
||||
{
|
||||
writer: W,
|
||||
cipher: BoxAeadEncryptor,
|
||||
@@ -256,18 +272,22 @@ pub struct EncryptedWriter<W>
|
||||
}
|
||||
|
||||
impl<W> EncryptedWriter<W>
|
||||
where W: AsyncWrite
|
||||
where
|
||||
W: AsyncWrite,
|
||||
{
|
||||
/// Creates a new EncryptedWriter
|
||||
pub fn new(w: W, t: CipherType, key: &[u8], nonce: &[u8]) -> EncryptedWriter<W> {
|
||||
EncryptedWriter { writer: w,
|
||||
cipher: crypto::new_aead_encryptor(t, key, nonce),
|
||||
tag_size: t.tag_size(), }
|
||||
EncryptedWriter {
|
||||
writer: w,
|
||||
cipher: crypto::new_aead_encryptor(t, key, nonce),
|
||||
tag_size: t.tag_size(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<W> EncryptedWrite for EncryptedWriter<W>
|
||||
where W: AsyncWrite
|
||||
where
|
||||
W: AsyncWrite,
|
||||
{
|
||||
fn write_raw(&mut self, data: &[u8]) -> io::Result<usize> {
|
||||
self.writer.write(data)
|
||||
@@ -279,8 +299,10 @@ impl<W> EncryptedWrite for EncryptedWriter<W>
|
||||
|
||||
fn encrypt<B: BufMut>(&mut self, data: &[u8], buf: &mut B) -> io::Result<()> {
|
||||
// Data.Len is a 16-bit big-endian integer indicating the length of Data. It should be smaller than 0x3FFF.
|
||||
assert!(data.len() <= MAX_PACKET_SIZE,
|
||||
"Buffer size too large, AEAD encryption protocol requires buffer to be smaller than 0x3FFF");
|
||||
assert!(
|
||||
data.len() <= MAX_PACKET_SIZE,
|
||||
"Buffer size too large, AEAD encryption protocol requires buffer to be smaller than 0x3FFF"
|
||||
);
|
||||
|
||||
let output_length = self.buffer_size(data);
|
||||
let data_length = data.len() as u16;
|
||||
@@ -289,8 +311,10 @@ impl<W> EncryptedWrite for EncryptedWriter<W>
|
||||
BigEndian::write_u16(&mut data_len_buf, data_length);
|
||||
|
||||
let output_length_size = 2 + self.tag_size;
|
||||
self.cipher.encrypt(&data_len_buf, unsafe { &mut buf.bytes_mut()[..output_length_size] });
|
||||
self.cipher.encrypt(data, unsafe { &mut buf.bytes_mut()[output_length_size..output_length] });
|
||||
self.cipher
|
||||
.encrypt(&data_len_buf, unsafe { &mut buf.bytes_mut()[..output_length_size] });
|
||||
self.cipher
|
||||
.encrypt(data, unsafe { &mut buf.bytes_mut()[output_length_size..output_length] });
|
||||
|
||||
unsafe {
|
||||
buf.advance_mut(output_length);
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
//! TCP relay client implementation
|
||||
|
||||
use std::io::{self, Read, Write};
|
||||
use std::net::SocketAddr;
|
||||
use std::{
|
||||
io::{self, Read, Write},
|
||||
net::SocketAddr,
|
||||
};
|
||||
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_io::io::flush;
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
use tokio_io::{io::flush, AsyncRead, AsyncWrite};
|
||||
|
||||
use futures::{self, Async, Future, Poll};
|
||||
|
||||
use relay::socks5::{
|
||||
self, Address, Command, HandshakeRequest, HandshakeResponse, Reply, TcpRequestHeader, TcpResponseHeader,
|
||||
self,
|
||||
Address,
|
||||
Command,
|
||||
HandshakeRequest,
|
||||
HandshakeResponse,
|
||||
Reply,
|
||||
TcpRequestHeader,
|
||||
TcpResponseHeader,
|
||||
};
|
||||
|
||||
/// Socks5 proxy client
|
||||
@@ -21,8 +29,9 @@ pub struct Socks5Client {
|
||||
impl Socks5Client {
|
||||
/// Connects to `addr` via `proxy`
|
||||
pub fn connect<A>(addr: A, proxy: SocketAddr) -> impl Future<Item = Socks5Client, Error = io::Error> + Send
|
||||
where Address: From<A>,
|
||||
A: Send + 'static
|
||||
where
|
||||
Address: From<A>,
|
||||
A: Send + 'static,
|
||||
{
|
||||
futures::lazy(move || TcpStream::connect(&proxy))
|
||||
.and_then(move |s| {
|
||||
@@ -31,41 +40,43 @@ impl Socks5Client {
|
||||
trace!("Client connected, going to send handshake: {:?}", hs);
|
||||
|
||||
hs.write_to(s)
|
||||
.and_then(flush)
|
||||
.and_then(HandshakeResponse::read_from)
|
||||
.and_then(|(s, rsp)| {
|
||||
trace!("Got handshake response: {:?}", rsp);
|
||||
assert_eq!(rsp.chosen_method, socks5::SOCKS5_AUTH_METHOD_NONE);
|
||||
Ok(s)
|
||||
})
|
||||
.and_then(flush)
|
||||
.and_then(HandshakeResponse::read_from)
|
||||
.and_then(|(s, rsp)| {
|
||||
trace!("Got handshake response: {:?}", rsp);
|
||||
assert_eq!(rsp.chosen_method, socks5::SOCKS5_AUTH_METHOD_NONE);
|
||||
Ok(s)
|
||||
})
|
||||
})
|
||||
.and_then(move |s| {
|
||||
// 2. Send request header
|
||||
let h = TcpRequestHeader::new(Command::TcpConnect, From::from(addr));
|
||||
trace!("Going to connect, req: {:?}", h);
|
||||
h.write_to(s)
|
||||
.and_then(flush)
|
||||
.and_then(|s| TcpResponseHeader::read_from(s).map_err(From::from))
|
||||
.and_then(|(s, rsp)| {
|
||||
trace!("Got response: {:?}", rsp);
|
||||
match rsp.reply {
|
||||
Reply::Succeeded => Ok(s),
|
||||
r => {
|
||||
let err = io::Error::new(io::ErrorKind::Other, format!("{}", r));
|
||||
Err(err)
|
||||
.and_then(flush)
|
||||
.and_then(|s| TcpResponseHeader::read_from(s).map_err(From::from))
|
||||
.and_then(|(s, rsp)| {
|
||||
trace!("Got response: {:?}", rsp);
|
||||
match rsp.reply {
|
||||
Reply::Succeeded => Ok(s),
|
||||
r => {
|
||||
let err = io::Error::new(io::ErrorKind::Other, format!("{}", r));
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
.map(|s| Socks5Client { stream: s })
|
||||
}
|
||||
|
||||
/// UDP Associate `addr` via `proxy`
|
||||
pub fn udp_associate<A>(addr: A,
|
||||
proxy: SocketAddr)
|
||||
-> impl Future<Item = (Socks5Client, Address), Error = io::Error> + Send
|
||||
where Address: From<A>,
|
||||
A: Send + 'static
|
||||
pub fn udp_associate<A>(
|
||||
addr: A,
|
||||
proxy: SocketAddr,
|
||||
) -> impl Future<Item = (Socks5Client, Address), Error = io::Error> + Send
|
||||
where
|
||||
Address: From<A>,
|
||||
A: Send + 'static,
|
||||
{
|
||||
futures::lazy(move || TcpStream::connect(&proxy))
|
||||
.and_then(move |s| {
|
||||
@@ -74,31 +85,31 @@ impl Socks5Client {
|
||||
trace!("Client connected, going to send handshake: {:?}", hs);
|
||||
|
||||
hs.write_to(s)
|
||||
.and_then(flush)
|
||||
.and_then(HandshakeResponse::read_from)
|
||||
.and_then(|(s, rsp)| {
|
||||
trace!("Got handshake response: {:?}", rsp);
|
||||
assert_eq!(rsp.chosen_method, socks5::SOCKS5_AUTH_METHOD_NONE);
|
||||
Ok(s)
|
||||
})
|
||||
.and_then(flush)
|
||||
.and_then(HandshakeResponse::read_from)
|
||||
.and_then(|(s, rsp)| {
|
||||
trace!("Got handshake response: {:?}", rsp);
|
||||
assert_eq!(rsp.chosen_method, socks5::SOCKS5_AUTH_METHOD_NONE);
|
||||
Ok(s)
|
||||
})
|
||||
})
|
||||
.and_then(move |s| {
|
||||
// 2. Send request header
|
||||
let h = TcpRequestHeader::new(Command::UdpAssociate, From::from(addr));
|
||||
trace!("Going to connect, req: {:?}", h);
|
||||
h.write_to(s)
|
||||
.and_then(flush)
|
||||
.and_then(|s| TcpResponseHeader::read_from(s).map_err(From::from))
|
||||
.and_then(|(s, rsp)| {
|
||||
trace!("Got response: {:?}", rsp);
|
||||
match rsp.reply {
|
||||
Reply::Succeeded => Ok((s, rsp.address)),
|
||||
r => {
|
||||
let err = io::Error::new(io::ErrorKind::Other, format!("{}", r));
|
||||
Err(err)
|
||||
.and_then(flush)
|
||||
.and_then(|s| TcpResponseHeader::read_from(s).map_err(From::from))
|
||||
.and_then(|(s, rsp)| {
|
||||
trace!("Got response: {:?}", rsp);
|
||||
match rsp.reply {
|
||||
Reply::Succeeded => Ok((s, rsp.address)),
|
||||
r => {
|
||||
let err = io::Error::new(io::ErrorKind::Other, format!("{}", r));
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
.map(|(s, a)| (Socks5Client { stream: s }, a))
|
||||
}
|
||||
|
||||
+108
-73
@@ -1,19 +1,26 @@
|
||||
//! IO facilities for TCP relay
|
||||
|
||||
use std::io::{self, BufRead, Read};
|
||||
use std::mem;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{
|
||||
io::{self, BufRead, Read},
|
||||
mem,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use futures::{Async, Future, Poll};
|
||||
|
||||
use tokio::timer::Delay;
|
||||
use tokio_io::io::{copy, Copy};
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
use tokio_io::{
|
||||
io::{copy, Copy},
|
||||
AsyncRead,
|
||||
AsyncWrite,
|
||||
};
|
||||
|
||||
use bytes::{BufMut, BytesMut};
|
||||
|
||||
use super::utils::{copy_timeout, copy_timeout_opt, CopyTimeout, CopyTimeoutOpt};
|
||||
use super::BUFFER_SIZE;
|
||||
use super::{
|
||||
utils::{copy_timeout, copy_timeout_opt, CopyTimeout, CopyTimeoutOpt},
|
||||
BUFFER_SIZE,
|
||||
};
|
||||
|
||||
static DUMMY_BUFFER: [u8; BUFFER_SIZE] = [0u8; BUFFER_SIZE];
|
||||
|
||||
@@ -27,24 +34,27 @@ pub trait DecryptedRead: BufRead + AsyncRead {
|
||||
|
||||
/// Copies all data to `w`
|
||||
fn copy<W>(self, w: W) -> Copy<Self, W>
|
||||
where Self: Sized,
|
||||
W: AsyncWrite
|
||||
where
|
||||
Self: Sized,
|
||||
W: AsyncWrite,
|
||||
{
|
||||
copy(self, w)
|
||||
}
|
||||
|
||||
/// Copies all data to `w`, return `TimedOut` if timeout reaches
|
||||
fn copy_timeout<W>(self, w: W, timeout: Duration) -> CopyTimeout<Self, W>
|
||||
where Self: Sized,
|
||||
W: AsyncWrite
|
||||
where
|
||||
Self: Sized,
|
||||
W: AsyncWrite,
|
||||
{
|
||||
copy_timeout(self, w, timeout)
|
||||
}
|
||||
|
||||
/// The same as `copy_timeout`, but has optional `timeout`
|
||||
fn copy_timeout_opt<W>(self, w: W, timeout: Option<Duration>) -> CopyTimeoutOpt<Self, W>
|
||||
where Self: Sized,
|
||||
W: AsyncWrite
|
||||
where
|
||||
Self: Sized,
|
||||
W: AsyncWrite,
|
||||
{
|
||||
copy_timeout_opt(self, w, timeout)
|
||||
}
|
||||
@@ -66,28 +76,32 @@ pub trait EncryptedWrite {
|
||||
|
||||
/// Encrypt data in `buf` and write all to the writer
|
||||
fn write_all<B: AsRef<[u8]>>(self, buf: B) -> EncryptedWriteAll<Self, B>
|
||||
where Self: Sized
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
EncryptedWriteAll::new(self, buf)
|
||||
}
|
||||
|
||||
/// Copies all data from `r`
|
||||
fn copy<R: Read>(self, r: R) -> EncryptedCopy<R, Self>
|
||||
where Self: Sized
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
EncryptedCopy::new(r, self)
|
||||
}
|
||||
|
||||
/// Copies all data from `r` with timeout
|
||||
fn copy_timeout<R: Read>(self, r: R, timeout: Duration) -> EncryptedCopyTimeout<R, Self>
|
||||
where Self: Sized
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
EncryptedCopyTimeout::new(r, self, timeout)
|
||||
}
|
||||
|
||||
/// Copies all data from `r` with optional timeout
|
||||
fn copy_timeout_opt<R: Read>(self, r: R, timeout: Option<Duration>) -> EncryptedCopyOpt<R, Self>
|
||||
where Self: Sized
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match timeout {
|
||||
Some(t) => EncryptedCopyOpt::CopyTimeout(self.copy_timeout(r, t)),
|
||||
@@ -98,8 +112,9 @@ pub trait EncryptedWrite {
|
||||
|
||||
/// Write all data encrypted
|
||||
pub enum EncryptedWriteAll<W, B>
|
||||
where W: EncryptedWrite,
|
||||
B: AsRef<[u8]>
|
||||
where
|
||||
W: EncryptedWrite,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
Writing {
|
||||
writer: W,
|
||||
@@ -112,34 +127,40 @@ pub enum EncryptedWriteAll<W, B>
|
||||
}
|
||||
|
||||
impl<W, B> EncryptedWriteAll<W, B>
|
||||
where W: EncryptedWrite,
|
||||
B: AsRef<[u8]>
|
||||
where
|
||||
W: EncryptedWrite,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
fn new(w: W, buf: B) -> EncryptedWriteAll<W, B> {
|
||||
let buffer_size = w.buffer_size(&DUMMY_BUFFER);
|
||||
EncryptedWriteAll::Writing { writer: w,
|
||||
buf: buf,
|
||||
pos: 0,
|
||||
enc_buf: BytesMut::with_capacity(buffer_size),
|
||||
encrypted: false, }
|
||||
EncryptedWriteAll::Writing {
|
||||
writer: w,
|
||||
buf: buf,
|
||||
pos: 0,
|
||||
enc_buf: BytesMut::with_capacity(buffer_size),
|
||||
encrypted: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<W, B> Future for EncryptedWriteAll<W, B>
|
||||
where W: EncryptedWrite,
|
||||
B: AsRef<[u8]>
|
||||
where
|
||||
W: EncryptedWrite,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
type Item = (W, B);
|
||||
type Error = io::Error;
|
||||
type Item = (W, B);
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match *self {
|
||||
EncryptedWriteAll::Empty => panic!("poll after EncryptedWriteAll finished"),
|
||||
EncryptedWriteAll::Writing { ref mut writer,
|
||||
ref buf,
|
||||
ref mut pos,
|
||||
ref mut enc_buf,
|
||||
ref mut encrypted, } => {
|
||||
EncryptedWriteAll::Writing {
|
||||
ref mut writer,
|
||||
ref buf,
|
||||
ref mut pos,
|
||||
ref mut enc_buf,
|
||||
ref mut encrypted,
|
||||
} => {
|
||||
if !*encrypted {
|
||||
*encrypted = true;
|
||||
|
||||
@@ -170,8 +191,9 @@ impl<W, B> Future for EncryptedWriteAll<W, B>
|
||||
|
||||
/// Encrypted copy
|
||||
pub struct EncryptedCopy<R, W>
|
||||
where R: Read,
|
||||
W: EncryptedWrite
|
||||
where
|
||||
R: Read,
|
||||
W: EncryptedWrite,
|
||||
{
|
||||
reader: Option<R>,
|
||||
writer: Option<W>,
|
||||
@@ -183,27 +205,31 @@ pub struct EncryptedCopy<R, W>
|
||||
}
|
||||
|
||||
impl<R, W> EncryptedCopy<R, W>
|
||||
where R: Read,
|
||||
W: EncryptedWrite
|
||||
where
|
||||
R: Read,
|
||||
W: EncryptedWrite,
|
||||
{
|
||||
fn new(r: R, w: W) -> EncryptedCopy<R, W> {
|
||||
let buffer_size = w.buffer_size(&DUMMY_BUFFER);
|
||||
EncryptedCopy { reader: Some(r),
|
||||
writer: Some(w),
|
||||
read_done: false,
|
||||
amt: 0,
|
||||
pos: 0,
|
||||
cap: 0,
|
||||
buf: BytesMut::with_capacity(buffer_size), }
|
||||
EncryptedCopy {
|
||||
reader: Some(r),
|
||||
writer: Some(w),
|
||||
read_done: false,
|
||||
amt: 0,
|
||||
pos: 0,
|
||||
cap: 0,
|
||||
buf: BytesMut::with_capacity(buffer_size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, W> Future for EncryptedCopy<R, W>
|
||||
where R: Read,
|
||||
W: EncryptedWrite
|
||||
where
|
||||
R: Read,
|
||||
W: EncryptedWrite,
|
||||
{
|
||||
type Item = (u64, R, W);
|
||||
type Error = io::Error;
|
||||
type Item = (u64, R, W);
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
let mut local_buf = [0u8; BUFFER_SIZE];
|
||||
@@ -247,8 +273,9 @@ impl<R, W> Future for EncryptedCopy<R, W>
|
||||
|
||||
/// Encrypted copy
|
||||
pub struct EncryptedCopyTimeout<R, W>
|
||||
where R: Read,
|
||||
W: EncryptedWrite
|
||||
where
|
||||
R: Read,
|
||||
W: EncryptedWrite,
|
||||
{
|
||||
reader: Option<R>,
|
||||
writer: Option<W>,
|
||||
@@ -263,21 +290,24 @@ pub struct EncryptedCopyTimeout<R, W>
|
||||
}
|
||||
|
||||
impl<R, W> EncryptedCopyTimeout<R, W>
|
||||
where R: Read,
|
||||
W: EncryptedWrite
|
||||
where
|
||||
R: Read,
|
||||
W: EncryptedWrite,
|
||||
{
|
||||
fn new(r: R, w: W, dur: Duration) -> EncryptedCopyTimeout<R, W> {
|
||||
let buffer_size = w.buffer_size(&DUMMY_BUFFER);
|
||||
EncryptedCopyTimeout { reader: Some(r),
|
||||
writer: Some(w),
|
||||
read_done: false,
|
||||
amt: 0,
|
||||
pos: 0,
|
||||
cap: 0,
|
||||
timeout: dur,
|
||||
timer: None,
|
||||
read_buf: [0u8; BUFFER_SIZE],
|
||||
write_buf: BytesMut::with_capacity(buffer_size), }
|
||||
EncryptedCopyTimeout {
|
||||
reader: Some(r),
|
||||
writer: Some(w),
|
||||
read_done: false,
|
||||
amt: 0,
|
||||
pos: 0,
|
||||
cap: 0,
|
||||
timeout: dur,
|
||||
timer: None,
|
||||
read_buf: [0u8; BUFFER_SIZE],
|
||||
write_buf: BytesMut::with_capacity(buffer_size),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_poll_timeout(&mut self) -> io::Result<()> {
|
||||
@@ -336,9 +366,11 @@ impl<R, W> EncryptedCopyTimeout<R, W>
|
||||
// Then, unset the previous timeout
|
||||
self.clear_timer();
|
||||
|
||||
match self.writer.as_mut()
|
||||
.unwrap()
|
||||
.write_raw(&self.write_buf[self.pos..self.cap])
|
||||
match self
|
||||
.writer
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write_raw(&self.write_buf[self.pos..self.cap])
|
||||
{
|
||||
Ok(n) => {
|
||||
self.pos += n;
|
||||
@@ -355,11 +387,12 @@ impl<R, W> EncryptedCopyTimeout<R, W>
|
||||
}
|
||||
|
||||
impl<R, W> Future for EncryptedCopyTimeout<R, W>
|
||||
where R: Read,
|
||||
W: EncryptedWrite
|
||||
where
|
||||
R: Read,
|
||||
W: EncryptedWrite,
|
||||
{
|
||||
type Item = (u64, R, W);
|
||||
type Error = io::Error;
|
||||
type Item = (u64, R, W);
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
loop {
|
||||
@@ -395,19 +428,21 @@ impl<R, W> Future for EncryptedCopyTimeout<R, W>
|
||||
|
||||
/// Work for both timeout or no timeout
|
||||
pub enum EncryptedCopyOpt<R, W>
|
||||
where R: Read,
|
||||
W: EncryptedWrite
|
||||
where
|
||||
R: Read,
|
||||
W: EncryptedWrite,
|
||||
{
|
||||
Copy(EncryptedCopy<R, W>),
|
||||
CopyTimeout(EncryptedCopyTimeout<R, W>),
|
||||
}
|
||||
|
||||
impl<R, W> Future for EncryptedCopyOpt<R, W>
|
||||
where R: Read,
|
||||
W: EncryptedWrite
|
||||
where
|
||||
R: Read,
|
||||
W: EncryptedWrite,
|
||||
{
|
||||
type Item = (u64, R, W);
|
||||
type Error = io::Error;
|
||||
type Item = (u64, R, W);
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match *self {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
//! Relay for TCP server that running on local environment
|
||||
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::{io, sync::Arc};
|
||||
|
||||
use futures::Future;
|
||||
|
||||
|
||||
+163
-112
@@ -1,22 +1,26 @@
|
||||
//! Relay for TCP implementation
|
||||
|
||||
use std::io::{self, BufRead, Read};
|
||||
use std::iter::{IntoIterator, Iterator};
|
||||
use std::mem;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
io::{self, BufRead, Read},
|
||||
iter::{IntoIterator, Iterator},
|
||||
mem,
|
||||
net::SocketAddr,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use config::{Config, ServerAddr, ServerConfig};
|
||||
use crypto::CipherCategory;
|
||||
use relay::boxed_future;
|
||||
use relay::dns_resolver::resolve;
|
||||
use relay::socks5::Address;
|
||||
use relay::{boxed_future, dns_resolver::resolve, socks5::Address};
|
||||
|
||||
use tokio::net::{ConnectFuture, TcpStream};
|
||||
use tokio_io::io::{read_exact, write_all};
|
||||
use tokio_io::io::{ReadHalf, WriteHalf};
|
||||
use tokio_io::{AsyncRead, IoFuture};
|
||||
use tokio::{
|
||||
net::{tcp::ConnectFuture, TcpStream},
|
||||
timer::Timeout,
|
||||
};
|
||||
use tokio_io::{
|
||||
io::{read_exact, write_all, ReadHalf, WriteHalf},
|
||||
AsyncRead,
|
||||
};
|
||||
|
||||
use futures::{self, Async, Future, Poll};
|
||||
|
||||
@@ -26,8 +30,10 @@ use byte_string::ByteStr;
|
||||
|
||||
pub use self::crypto_io::{DecryptedRead, EncryptedWrite};
|
||||
|
||||
use self::aead::{DecryptedReader as AeadDecryptedReader, EncryptedWriter as AeadEncryptedWriter};
|
||||
use self::stream::{DecryptedReader as StreamDecryptedReader, EncryptedWriter as StreamEncryptedWriter};
|
||||
use self::{
|
||||
aead::{DecryptedReader as AeadDecryptedReader, EncryptedWriter as AeadEncryptedWriter},
|
||||
stream::{DecryptedReader as StreamDecryptedReader, EncryptedWriter as StreamEncryptedWriter},
|
||||
};
|
||||
|
||||
mod aead;
|
||||
pub mod client;
|
||||
@@ -148,11 +154,6 @@ impl From<AeadEncryptedWriter<TcpWriteHalf>> for EncryptedHalf {
|
||||
}
|
||||
}
|
||||
|
||||
/// Boxed future of `DecryptedHalf`
|
||||
pub type DecryptedHalfFut = IoFuture<DecryptedHalf>;
|
||||
/// Boxed future of `EncryptedHalf`
|
||||
pub type EncryptedHalfFut = IoFuture<EncryptedHalf>;
|
||||
|
||||
/// Try to connect every IPs one by one
|
||||
enum TcpStreamConnect<I: Iterator<Item = SocketAddr>> {
|
||||
Empty,
|
||||
@@ -165,23 +166,28 @@ enum TcpStreamConnect<I: Iterator<Item = SocketAddr>> {
|
||||
|
||||
impl<I: Iterator<Item = SocketAddr>> TcpStreamConnect<I> {
|
||||
fn new(iter: I) -> TcpStreamConnect<I> {
|
||||
TcpStreamConnect::Connect { last_err: None,
|
||||
addr_iter: iter,
|
||||
opt_stream_new: None, }
|
||||
TcpStreamConnect::Connect {
|
||||
last_err: None,
|
||||
addr_iter: iter,
|
||||
opt_stream_new: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Iterator<Item = SocketAddr>> Future for TcpStreamConnect<I> {
|
||||
type Item = TcpStream;
|
||||
type Error = io::Error;
|
||||
type Item = TcpStream;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
use std::io::ErrorKind;
|
||||
|
||||
match *self {
|
||||
TcpStreamConnect::Empty => unreachable!(),
|
||||
TcpStreamConnect::Connect { ref mut last_err,
|
||||
ref mut addr_iter,
|
||||
ref mut opt_stream_new, } => {
|
||||
TcpStreamConnect::Connect {
|
||||
ref mut last_err,
|
||||
ref mut addr_iter,
|
||||
ref mut opt_stream_new,
|
||||
} => {
|
||||
loop {
|
||||
// 1. Poll before doing anything else
|
||||
if let Some((ref mut stream_new, ref addr)) = *opt_stream_new {
|
||||
@@ -209,22 +215,21 @@ impl<I: Iterator<Item = SocketAddr>> Future for TcpStreamConnect<I> {
|
||||
|
||||
match mem::replace(self, TcpStreamConnect::Empty) {
|
||||
TcpStreamConnect::Empty => unreachable!(),
|
||||
TcpStreamConnect::Connect { last_err, .. } => {
|
||||
match last_err {
|
||||
None => {
|
||||
let err = io::Error::new(ErrorKind::Other, "connect TCP without any addresses");
|
||||
Err(err)
|
||||
}
|
||||
Some(err) => Err(err),
|
||||
TcpStreamConnect::Connect { last_err, .. } => match last_err {
|
||||
None => {
|
||||
let err = io::Error::new(ErrorKind::Other, "connect TCP without any addresses");
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
Some(err) => Err(err),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn connect_proxy_server(config: Arc<Config>,
|
||||
svr_cfg: Arc<ServerConfig>)
|
||||
-> impl Future<Item = TcpStream, Error = io::Error> + Send {
|
||||
fn connect_proxy_server(
|
||||
config: Arc<Config>,
|
||||
svr_cfg: Arc<ServerConfig>,
|
||||
) -> impl Future<Item = TcpStream, Error = io::Error> + Send {
|
||||
let timeout = *svr_cfg.timeout();
|
||||
trace!("Connecting to proxy {:?}, timeout: {:?}", svr_cfg.addr(), timeout);
|
||||
match *svr_cfg.addr() {
|
||||
@@ -235,9 +240,9 @@ fn connect_proxy_server(config: Arc<Config>,
|
||||
ServerAddr::DomainName(ref domain, port) => {
|
||||
let fut = {
|
||||
try_timeout(resolve(config.clone(), &domain[..], port, false), timeout).and_then(move |vec_ipaddr| {
|
||||
let fut = TcpStreamConnect::new(vec_ipaddr.into_iter());
|
||||
try_timeout(fut, timeout)
|
||||
})
|
||||
let fut = TcpStreamConnect::new(vec_ipaddr.into_iter());
|
||||
try_timeout(fut, timeout)
|
||||
})
|
||||
};
|
||||
boxed_future(fut)
|
||||
}
|
||||
@@ -245,33 +250,49 @@ fn connect_proxy_server(config: Arc<Config>,
|
||||
}
|
||||
|
||||
/// Handshake logic for ShadowSocks Client
|
||||
pub fn proxy_server_handshake(remote_stream: TcpStream,
|
||||
svr_cfg: Arc<ServerConfig>,
|
||||
relay_addr: Address)
|
||||
-> impl Future<Item = (DecryptedHalfFut, EncryptedHalfFut), Error = io::Error> + Send {
|
||||
pub fn proxy_server_handshake(
|
||||
remote_stream: TcpStream,
|
||||
svr_cfg: Arc<ServerConfig>,
|
||||
relay_addr: Address,
|
||||
) -> impl Future<
|
||||
Item = (
|
||||
impl Future<Item = DecryptedHalf, Error = io::Error> + Send,
|
||||
impl Future<Item = EncryptedHalf, Error = io::Error> + Send,
|
||||
),
|
||||
Error = io::Error,
|
||||
> + Send {
|
||||
let timeout = *svr_cfg.timeout();
|
||||
proxy_handshake(remote_stream, svr_cfg).and_then(move |(r_fut, w_fut)| {
|
||||
let w_fut = w_fut.and_then(move |enc_w| {
|
||||
// Send relay address to remote
|
||||
let mut buf = BytesMut::with_capacity(relay_addr.len());
|
||||
relay_addr.write_to_buf(&mut buf);
|
||||
let w_fut = w_fut.and_then(move |enc_w| {
|
||||
// Send relay address to remote
|
||||
let mut buf = BytesMut::with_capacity(relay_addr.len());
|
||||
relay_addr.write_to_buf(&mut buf);
|
||||
|
||||
trace!("Got encrypt stream and going to send addr: {:?}, buf: {:?}",
|
||||
relay_addr,
|
||||
buf);
|
||||
trace!(
|
||||
"Got encrypt stream and going to send addr: {:?}, buf: {:?}",
|
||||
relay_addr,
|
||||
buf
|
||||
);
|
||||
|
||||
try_timeout(enc_w.write_all(buf), timeout).map(|(w, _)| w)
|
||||
});
|
||||
try_timeout(enc_w.write_all(buf), timeout).map(|(w, _)| w)
|
||||
});
|
||||
|
||||
Ok((r_fut, boxed_future(w_fut)))
|
||||
})
|
||||
Ok((r_fut, w_fut))
|
||||
})
|
||||
}
|
||||
|
||||
/// ShadowSocks Client-Server handshake protocol
|
||||
/// Exchange cipher IV and creates stream wrapper
|
||||
pub fn proxy_handshake(remote_stream: TcpStream,
|
||||
svr_cfg: Arc<ServerConfig>)
|
||||
-> impl Future<Item = (DecryptedHalfFut, EncryptedHalfFut), Error = io::Error> + Send {
|
||||
pub fn proxy_handshake(
|
||||
remote_stream: TcpStream,
|
||||
svr_cfg: Arc<ServerConfig>,
|
||||
) -> impl Future<
|
||||
Item = (
|
||||
impl Future<Item = DecryptedHalf, Error = io::Error> + Send,
|
||||
impl Future<Item = EncryptedHalf, Error = io::Error> + Send,
|
||||
),
|
||||
Error = io::Error,
|
||||
> + Send {
|
||||
futures::lazy(|| Ok(remote_stream.split())).and_then(move |(r, w)| {
|
||||
let timeout = svr_cfg.timeout().clone();
|
||||
|
||||
@@ -296,19 +317,20 @@ pub fn proxy_handshake(remote_stream: TcpStream,
|
||||
}
|
||||
};
|
||||
|
||||
try_timeout(write_all(w, prev_buf), timeout).and_then(
|
||||
move |(w, prev_buf)| match svr_cfg.method().category() {
|
||||
try_timeout(write_all(w, prev_buf), timeout).and_then(move |(w, prev_buf)| {
|
||||
match svr_cfg.method().category() {
|
||||
CipherCategory::Stream => {
|
||||
let local_iv = prev_buf;
|
||||
Ok(From::from(StreamEncryptedWriter::new(w, svr_cfg.method(), svr_cfg.key(), &local_iv)))
|
||||
let wtr = StreamEncryptedWriter::new(w, svr_cfg.method(), svr_cfg.key(), &local_iv);
|
||||
Ok(From::from(wtr))
|
||||
}
|
||||
CipherCategory::Aead => {
|
||||
let local_salt = prev_buf;
|
||||
let wtr = AeadEncryptedWriter::new(w, svr_cfg.method(), svr_cfg.key(), &local_salt[..]);
|
||||
Ok(From::from(wtr))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let dec = {
|
||||
@@ -338,60 +360,56 @@ pub fn proxy_handshake(remote_stream: TcpStream,
|
||||
})
|
||||
};
|
||||
|
||||
Ok((boxed_future(dec), boxed_future(enc)))
|
||||
Ok((dec, enc))
|
||||
})
|
||||
}
|
||||
|
||||
/// Establish tunnel between server and client
|
||||
pub fn tunnel<CF, CFI, SF, SFI>(addr: Address, c2s: CF, s2c: SF) -> impl Future<Item = (), Error = io::Error> + Send
|
||||
where CF: Future<Item = CFI, Error = io::Error> + Send + 'static,
|
||||
SF: Future<Item = SFI, Error = io::Error> + Send + 'static
|
||||
where
|
||||
CF: Future<Item = CFI, Error = io::Error> + Send + 'static,
|
||||
SF: Future<Item = SFI, Error = io::Error> + Send + 'static,
|
||||
{
|
||||
let addr = Arc::new(addr);
|
||||
|
||||
let cloned_addr = addr.clone();
|
||||
let c2s = c2s.then(move |res| {
|
||||
match res {
|
||||
Ok(..) => {
|
||||
// Continue reading response from remote server
|
||||
trace!("Relay {} client -> server is finished", cloned_addr);
|
||||
match res {
|
||||
Ok(..) => {
|
||||
// Continue reading response from remote server
|
||||
trace!("Relay {} client -> server is finished", cloned_addr);
|
||||
|
||||
Ok(TunnelDirection::Client2Server)
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Relay {} client -> server aborted: {}", cloned_addr, err);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
});
|
||||
Ok(TunnelDirection::Client2Server)
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Relay {} client -> server aborted: {}", cloned_addr, err);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let cloned_addr = addr.clone();
|
||||
let s2c = s2c.then(move |res| match res {
|
||||
Ok(..) => {
|
||||
trace!("Relay {} client <- server is finished", cloned_addr);
|
||||
Ok(..) => {
|
||||
trace!("Relay {} client <- server is finished", cloned_addr);
|
||||
|
||||
Ok(TunnelDirection::Server2Client)
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Relay {} client <- server aborted: {}", cloned_addr, err);
|
||||
Err(err)
|
||||
}
|
||||
});
|
||||
Ok(TunnelDirection::Server2Client)
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Relay {} client <- server aborted: {}", cloned_addr, err);
|
||||
Err(err)
|
||||
}
|
||||
});
|
||||
|
||||
c2s.select(s2c)
|
||||
.and_then(move |(dir, _)| {
|
||||
match dir {
|
||||
TunnelDirection::Server2Client => {
|
||||
trace!("Relay {} client <- server is closed, abort connection", addr)
|
||||
}
|
||||
TunnelDirection::Client2Server => {
|
||||
trace!("Relay {} server -> client is closed, abort connection", addr)
|
||||
}
|
||||
}
|
||||
.and_then(move |(dir, _)| {
|
||||
match dir {
|
||||
TunnelDirection::Server2Client => trace!("Relay {} client <- server is closed, abort connection", addr),
|
||||
TunnelDirection::Client2Server => trace!("Relay {} server -> client is closed, abort connection", addr),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.map_err(|(err, _)| err)
|
||||
Ok(())
|
||||
}).map_err(|(err, _)| err)
|
||||
}
|
||||
|
||||
/// Read until EOF, and ignore
|
||||
@@ -401,8 +419,8 @@ pub enum IgnoreUntilEnd<R: Read> {
|
||||
}
|
||||
|
||||
impl<R: Read> Future for IgnoreUntilEnd<R> {
|
||||
type Item = u64;
|
||||
type Error = io::Error;
|
||||
type Item = u64;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match *self {
|
||||
@@ -432,24 +450,57 @@ pub fn ignore_until_end<R: Read>(r: R) -> IgnoreUntilEnd<R> {
|
||||
IgnoreUntilEnd::Pending { r: r, amt: 0 }
|
||||
}
|
||||
|
||||
fn try_timeout<T, F>(fut: F, dur: Option<Duration>) -> impl Future<Item = T, Error = io::Error> + Send
|
||||
where F: Future<Item = T, Error = io::Error> + Send + 'static,
|
||||
T: 'static
|
||||
pub enum TimeoutFuture<T, F>
|
||||
where
|
||||
T: 'static,
|
||||
F: Future<Item = T, Error = io::Error> + Send + 'static,
|
||||
{
|
||||
Direct(F),
|
||||
Wait(Timeout<F>),
|
||||
}
|
||||
|
||||
impl<T, F> Future for TimeoutFuture<T, F>
|
||||
where
|
||||
T: 'static,
|
||||
F: Future<Item = T, Error = io::Error> + Send + 'static,
|
||||
{
|
||||
type Error = io::Error;
|
||||
type Item = T;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match *self {
|
||||
TimeoutFuture::Direct(ref mut f) => f.poll(),
|
||||
TimeoutFuture::Wait(ref mut f) => match f.poll() {
|
||||
Ok(Async::NotReady) => Ok(Async::NotReady),
|
||||
Ok(Async::Ready(x)) => Ok(Async::Ready(x)),
|
||||
Err(err) => match err.into_inner() {
|
||||
Some(e) => Err(e),
|
||||
None => Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_timeout<T, F>(fut: F, dur: Option<Duration>) -> impl Future<Item = T, Error = io::Error> + Send
|
||||
where
|
||||
F: Future<Item = T, Error = io::Error> + Send + 'static,
|
||||
T: 'static,
|
||||
{
|
||||
use tokio::prelude::*;
|
||||
|
||||
match dur {
|
||||
Some(dur) => boxed_future(io_timeout(fut, dur)),
|
||||
None => boxed_future(fut),
|
||||
Some(dur) => TimeoutFuture::Wait(fut.timeout(dur)),
|
||||
None => TimeoutFuture::Direct(fut),
|
||||
}
|
||||
}
|
||||
|
||||
fn io_timeout<T, F>(fut: F, dur: Duration) -> impl Future<Item = T, Error = io::Error> + Send
|
||||
where F: Future<Item = T, Error = io::Error> + Send + 'static,
|
||||
T: 'static
|
||||
where
|
||||
F: Future<Item = T, Error = io::Error> + Send + 'static,
|
||||
T: 'static,
|
||||
{
|
||||
use tokio::prelude::*;
|
||||
|
||||
fut.timeout(dur).map_err(|err| match err.into_inner() {
|
||||
Some(e) => e,
|
||||
None => io::Error::new(io::ErrorKind::TimedOut, "connection timed out"),
|
||||
})
|
||||
TimeoutFuture::Wait(fut.timeout(dur))
|
||||
}
|
||||
|
||||
+169
-116
@@ -1,26 +1,37 @@
|
||||
//! Relay for TCP server that running on the server side
|
||||
|
||||
use std::io::{self, ErrorKind};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
io::{self, ErrorKind},
|
||||
net::SocketAddr,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use config::{Config, ServerConfig};
|
||||
|
||||
use relay::boxed_future;
|
||||
use relay::dns_resolver::resolve;
|
||||
use relay::socks5::Address;
|
||||
use relay::tcprelay::crypto_io::{DecryptedRead, EncryptedWrite};
|
||||
use relay::{
|
||||
boxed_future,
|
||||
dns_resolver::resolve,
|
||||
socks5::Address,
|
||||
tcprelay::crypto_io::{DecryptedRead, EncryptedWrite},
|
||||
};
|
||||
|
||||
use futures::stream::futures_unordered;
|
||||
use futures::stream::Stream;
|
||||
use futures::{self, Future};
|
||||
use futures::{
|
||||
self,
|
||||
stream::{futures_unordered, Stream},
|
||||
Future,
|
||||
};
|
||||
|
||||
use tokio;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio_io::io::{ReadHalf, WriteHalf};
|
||||
use tokio_io::AsyncRead;
|
||||
use tokio::{
|
||||
self,
|
||||
net::{TcpListener, TcpStream},
|
||||
};
|
||||
use tokio_io::{
|
||||
io::{ReadHalf, WriteHalf},
|
||||
AsyncRead,
|
||||
};
|
||||
|
||||
use super::{proxy_handshake, try_timeout, tunnel, DecryptedHalf, EncryptedHalfFut, TcpStreamConnect};
|
||||
use super::{proxy_handshake, try_timeout, tunnel, DecryptedHalf, EncryptedHalf, TcpStreamConnect};
|
||||
|
||||
/// Context for doing handshake with client
|
||||
pub struct TcpRelayClientHandshake {
|
||||
@@ -30,8 +41,24 @@ pub struct TcpRelayClientHandshake {
|
||||
}
|
||||
|
||||
impl TcpRelayClientHandshake {
|
||||
#[inline]
|
||||
fn error_handshake(peer_addr: SocketAddr) -> io::Error {
|
||||
io::Error::new(
|
||||
ErrorKind::Other,
|
||||
format!(
|
||||
"failed to decode Address, may be wrong method or key, peer: {}",
|
||||
peer_addr
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/// Doing handshake with client
|
||||
pub fn handshake(self) -> impl Future<Item = TcpRelayClientPending, Error = io::Error> {
|
||||
pub fn handshake(
|
||||
self,
|
||||
) -> impl Future<
|
||||
Item = TcpRelayClientPending<impl Future<Item = EncryptedHalf, Error = io::Error> + Send + 'static>,
|
||||
Error = io::Error,
|
||||
> + Send {
|
||||
let TcpRelayClientHandshake { s, svr_cfg, config } = self;
|
||||
|
||||
futures::lazy(move || s.peer_addr().map(|p| (s, p))).and_then(|(s, peer_addr)| {
|
||||
@@ -39,89 +66,109 @@ impl TcpRelayClientHandshake {
|
||||
|
||||
let timeout = *svr_cfg.timeout();
|
||||
proxy_handshake(s, svr_cfg).and_then(move |(r_fut, w_fut)| {
|
||||
r_fut.and_then(move |r| {
|
||||
let fut = Address::read_from(r).map_err(move |_| {
|
||||
io::Error::new(ErrorKind::Other,
|
||||
format!("failed to decode Address, may be wrong method or key, peer: {}",
|
||||
peer_addr))
|
||||
});
|
||||
try_timeout(fut, timeout)
|
||||
})
|
||||
.map(move |(r, addr)| TcpRelayClientPending { r: r,
|
||||
addr: addr,
|
||||
w: w_fut,
|
||||
timeout: timeout,
|
||||
config: config, })
|
||||
r_fut
|
||||
.and_then(move |r| {
|
||||
let fut =
|
||||
Address::read_from(r).map_err(move |_| TcpRelayClientHandshake::error_handshake(peer_addr));
|
||||
try_timeout(fut, timeout)
|
||||
})
|
||||
.map(move |(r, addr)| TcpRelayClientPending {
|
||||
r: r,
|
||||
addr: addr,
|
||||
w: w_fut,
|
||||
timeout: timeout,
|
||||
config: config,
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Context for connecting remote
|
||||
pub struct TcpRelayClientPending {
|
||||
pub struct TcpRelayClientPending<E>
|
||||
where
|
||||
E: Future<Item = EncryptedHalf, Error = io::Error> + Send + 'static,
|
||||
{
|
||||
r: DecryptedHalf,
|
||||
addr: Address,
|
||||
w: EncryptedHalfFut,
|
||||
w: E,
|
||||
timeout: Option<Duration>,
|
||||
config: Arc<Config>,
|
||||
}
|
||||
|
||||
impl TcpRelayClientPending {
|
||||
/// Connect to the remote server
|
||||
#[inline]
|
||||
fn connect_remote(config: Arc<Config>,
|
||||
addr: Address,
|
||||
timeout: Option<Duration>)
|
||||
-> impl Future<Item = TcpStream, Error = io::Error> {
|
||||
debug!("Connecting to remote {}", addr);
|
||||
/// Connect to the remote server
|
||||
#[inline]
|
||||
fn connect_remote(
|
||||
config: Arc<Config>,
|
||||
addr: Address,
|
||||
timeout: Option<Duration>,
|
||||
) -> impl Future<Item = TcpStream, Error = io::Error> + Send {
|
||||
debug!("Connecting to remote {}", addr);
|
||||
|
||||
match addr {
|
||||
Address::SocketAddress(saddr) => {
|
||||
if config.forbidden_ip.contains(&saddr.ip()) {
|
||||
let err = io::Error::new(ErrorKind::Other,
|
||||
format!("{} is forbidden, failed to connect {}", saddr.ip(), saddr));
|
||||
return boxed_future(futures::done(Err(err)));
|
||||
}
|
||||
match addr {
|
||||
Address::SocketAddress(saddr) => {
|
||||
if config.forbidden_ip.contains(&saddr.ip()) {
|
||||
let err = io::Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("{} is forbidden, failed to connect {}", saddr.ip(), saddr),
|
||||
);
|
||||
return boxed_future(futures::done(Err(err)));
|
||||
}
|
||||
|
||||
let conn = TcpStream::connect(&saddr);
|
||||
let fut = try_timeout(conn, timeout);
|
||||
boxed_future(fut)
|
||||
}
|
||||
Address::DomainNameAddress(dname, port) => {
|
||||
let fut = {
|
||||
try_timeout(resolve(config, dname.as_str(), port, true), timeout).and_then(move |addrs| {
|
||||
let conn = TcpStreamConnect::new(addrs.into_iter());
|
||||
try_timeout(conn, timeout)
|
||||
})
|
||||
};
|
||||
boxed_future(fut)
|
||||
}
|
||||
let conn = TcpStream::connect(&saddr);
|
||||
let fut = try_timeout(conn, timeout);
|
||||
boxed_future(fut)
|
||||
}
|
||||
Address::DomainNameAddress(dname, port) => {
|
||||
let fut = {
|
||||
try_timeout(resolve(config, dname.as_str(), port, true), timeout).and_then(move |addrs| {
|
||||
let conn = TcpStreamConnect::new(addrs.into_iter());
|
||||
try_timeout(conn, timeout)
|
||||
})
|
||||
};
|
||||
boxed_future(fut)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> TcpRelayClientPending<E>
|
||||
where
|
||||
E: Future<Item = EncryptedHalf, Error = io::Error> + Send + 'static,
|
||||
{
|
||||
/// Connect to the remote server
|
||||
pub fn connect(self) -> impl Future<Item = TcpRelayClientConnected, Error = io::Error> + Send {
|
||||
pub fn connect(
|
||||
self,
|
||||
) -> impl Future<
|
||||
Item = TcpRelayClientConnected<impl Future<Item = EncryptedHalf, Error = io::Error> + Send + 'static>,
|
||||
Error = io::Error,
|
||||
> + Send {
|
||||
let addr = self.addr.clone();
|
||||
let client_pair = (self.r, self.w);
|
||||
let timeout = self.timeout;
|
||||
TcpRelayClientPending::connect_remote(self.config, self.addr, self.timeout).map(move |stream| {
|
||||
TcpRelayClientConnected { server: stream.split(),
|
||||
client: client_pair,
|
||||
addr: addr,
|
||||
timeout: timeout, }
|
||||
connect_remote(self.config, self.addr, self.timeout).map(move |stream| TcpRelayClientConnected {
|
||||
server: stream.split(),
|
||||
client: client_pair,
|
||||
addr: addr,
|
||||
timeout: timeout,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Context for extablishing tunnel
|
||||
pub struct TcpRelayClientConnected {
|
||||
pub struct TcpRelayClientConnected<E>
|
||||
where
|
||||
E: Future<Item = EncryptedHalf, Error = io::Error> + Send + 'static,
|
||||
{
|
||||
server: (ReadHalf<TcpStream>, WriteHalf<TcpStream>),
|
||||
client: (DecryptedHalf, EncryptedHalfFut),
|
||||
client: (DecryptedHalf, E),
|
||||
addr: Address,
|
||||
timeout: Option<Duration>,
|
||||
}
|
||||
|
||||
impl TcpRelayClientConnected {
|
||||
impl<E> TcpRelayClientConnected<E>
|
||||
where
|
||||
E: Future<Item = EncryptedHalf, Error = io::Error> + Send + 'static,
|
||||
{
|
||||
/// Establish tunnel
|
||||
#[inline]
|
||||
pub fn tunnel(self) -> impl Future<Item = (), Error = io::Error> + Send {
|
||||
@@ -129,16 +176,19 @@ impl TcpRelayClientConnected {
|
||||
let (r, w_fut) = self.client;
|
||||
let timeout = self.timeout;
|
||||
|
||||
tunnel(self.addr,
|
||||
r.copy_timeout_opt(svr_w, self.timeout),
|
||||
w_fut.and_then(move |w| w.copy_timeout_opt(svr_r, timeout)))
|
||||
tunnel(
|
||||
self.addr,
|
||||
r.copy_timeout_opt(svr_w, self.timeout),
|
||||
w_fut.and_then(move |w| w.copy_timeout_opt(svr_r, timeout)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_client(server_cfg: Arc<ServerConfig>,
|
||||
config: Arc<Config>,
|
||||
socket: TcpStream)
|
||||
-> impl Future<Item = (), Error = ()> + Send {
|
||||
fn handle_client(
|
||||
server_cfg: Arc<ServerConfig>,
|
||||
config: Arc<Config>,
|
||||
socket: TcpStream,
|
||||
) -> impl Future<Item = (), Error = ()> + Send {
|
||||
if let Err(err) = socket.set_keepalive(*server_cfg.timeout()) {
|
||||
error!("Failed to set keep alive: {:?}", err);
|
||||
}
|
||||
@@ -148,26 +198,30 @@ fn handle_client(server_cfg: Arc<ServerConfig>,
|
||||
}
|
||||
|
||||
futures::lazy(move || match socket.peer_addr() {
|
||||
Ok(addr) => Ok((socket, addr)),
|
||||
Err(err) => {
|
||||
error!("Failed to get peer_addr after accept: {}", err);
|
||||
Err(())
|
||||
}
|
||||
}).and_then(move |(socket, addr)| {
|
||||
trace!("Got connection, addr: {}", addr);
|
||||
trace!("Picked proxy server: {:?}", server_cfg);
|
||||
Ok(addr) => Ok((socket, addr)),
|
||||
Err(err) => {
|
||||
error!("Failed to get peer_addr after accept: {}", err);
|
||||
Err(())
|
||||
}
|
||||
})
|
||||
.and_then(move |(socket, addr)| {
|
||||
trace!("Got connection, addr: {}", addr);
|
||||
trace!("Picked proxy server: {:?}", server_cfg);
|
||||
|
||||
let client = TcpRelayClientHandshake { s: socket,
|
||||
svr_cfg: server_cfg,
|
||||
config: config, };
|
||||
let client = TcpRelayClientHandshake {
|
||||
s: socket,
|
||||
svr_cfg: server_cfg,
|
||||
config: config,
|
||||
};
|
||||
|
||||
client.handshake()
|
||||
.and_then(|c| c.connect())
|
||||
.and_then(|c| c.tunnel())
|
||||
.map_err(move |err| {
|
||||
error!("Failed to handle client ({}): {}", addr, err);
|
||||
})
|
||||
})
|
||||
client
|
||||
.handshake()
|
||||
.and_then(|c| c.connect())
|
||||
.and_then(|c| c.tunnel())
|
||||
.map_err(move |err| {
|
||||
error!("Failed to handle client ({}): {}", addr, err);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Runs the server
|
||||
@@ -187,32 +241,31 @@ pub fn run(config: Arc<Config>) -> impl Future<Item = (), Error = io::Error> + S
|
||||
|
||||
let svr_cfg = Arc::new(svr_cfg.clone());
|
||||
let config = config.clone();
|
||||
let listening = listener.incoming()
|
||||
.for_each(move |socket| {
|
||||
let server_cfg = svr_cfg.clone();
|
||||
let config = config.clone();
|
||||
tokio::spawn(handle_client(server_cfg, config, socket));
|
||||
Ok(())
|
||||
})
|
||||
.map_err(|err| {
|
||||
error!("Server run failed: {}", err);
|
||||
err
|
||||
});
|
||||
let listening = listener
|
||||
.incoming()
|
||||
.for_each(move |socket| {
|
||||
let server_cfg = svr_cfg.clone();
|
||||
let config = config.clone();
|
||||
tokio::spawn(handle_client(server_cfg, config, socket));
|
||||
Ok(())
|
||||
})
|
||||
.map_err(|err| {
|
||||
error!("Server run failed: {}", err);
|
||||
err
|
||||
});
|
||||
|
||||
vec_fut.push(boxed_future(listening));
|
||||
}
|
||||
|
||||
futures_unordered(vec_fut).into_future().then(|res| match res {
|
||||
Ok(..) => {
|
||||
error!("One of TCP servers exited unexpectly without error");
|
||||
let err = io::Error::new(io::ErrorKind::Other,
|
||||
"server exited unexpectly");
|
||||
Err(err)
|
||||
}
|
||||
Err((err, ..)) => {
|
||||
error!("One of TCP servers exited unexpectly with error {}",
|
||||
err);
|
||||
Err(err)
|
||||
}
|
||||
})
|
||||
Ok(..) => {
|
||||
error!("One of TCP servers exited unexpectly without error");
|
||||
let err = io::Error::new(io::ErrorKind::Other, "server exited unexpectly");
|
||||
Err(err)
|
||||
}
|
||||
Err((err, ..)) => {
|
||||
error!("One of TCP servers exited unexpectly with error {}", err);
|
||||
Err(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,28 +1,26 @@
|
||||
//! Local server that accepts SOCKS 5 protocol
|
||||
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::{io, net::SocketAddr, sync::Arc};
|
||||
|
||||
use futures::stream::Stream;
|
||||
use futures::{self, Future};
|
||||
use futures::{self, stream::Stream, Future};
|
||||
|
||||
// use tokio_core::net::{TcpListener, TcpStream};
|
||||
use tokio_io::io::flush;
|
||||
use tokio_io::io::{ReadHalf, WriteHalf};
|
||||
use tokio_io::AsyncRead;
|
||||
|
||||
use tokio;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::{
|
||||
self,
|
||||
net::{TcpListener, TcpStream},
|
||||
};
|
||||
use tokio_io::{
|
||||
io::{flush, ReadHalf, WriteHalf},
|
||||
AsyncRead,
|
||||
};
|
||||
|
||||
use config::{Config, ServerConfig};
|
||||
|
||||
use relay::boxed_future;
|
||||
use relay::loadbalancing::server::LoadBalancer;
|
||||
use relay::loadbalancing::server::RoundRobin;
|
||||
use relay::socks5::{self, Address, HandshakeRequest, HandshakeResponse};
|
||||
use relay::socks5::{TcpRequestHeader, TcpResponseHeader};
|
||||
use relay::tcprelay::crypto_io::{DecryptedRead, EncryptedWrite};
|
||||
use relay::{
|
||||
boxed_future,
|
||||
loadbalancing::server::{LoadBalancer, RoundRobin},
|
||||
socks5::{self, Address, HandshakeRequest, HandshakeResponse, TcpRequestHeader, TcpResponseHeader},
|
||||
tcprelay::crypto_io::{DecryptedRead, EncryptedWrite},
|
||||
};
|
||||
|
||||
use super::{ignore_until_end, try_timeout, tunnel};
|
||||
|
||||
@@ -32,12 +30,13 @@ struct UdpConfig {
|
||||
client_addr: SocketAddr,
|
||||
}
|
||||
|
||||
fn handle_socks5_connect(config: Arc<Config>,
|
||||
(r, w): (ReadHalf<TcpStream>, WriteHalf<TcpStream>),
|
||||
client_addr: SocketAddr,
|
||||
addr: Address,
|
||||
svr_cfg: Arc<ServerConfig>)
|
||||
-> impl Future<Item = (), Error = io::Error> + Send {
|
||||
fn handle_socks5_connect(
|
||||
config: Arc<Config>,
|
||||
(r, w): (ReadHalf<TcpStream>, WriteHalf<TcpStream>),
|
||||
client_addr: SocketAddr,
|
||||
addr: Address,
|
||||
svr_cfg: Arc<ServerConfig>,
|
||||
) -> impl Future<Item = (), Error = io::Error> + Send {
|
||||
let cloned_addr = addr.clone();
|
||||
let cloned_svr_cfg = svr_cfg.clone();
|
||||
let timeout = *svr_cfg.timeout();
|
||||
@@ -53,11 +52,12 @@ fn handle_socks5_connect(config: Arc<Config>,
|
||||
|
||||
boxed_future(
|
||||
try_timeout(try_timeout(header.write_to(w), timeout).and_then(flush), timeout)
|
||||
.map(move |w| (svr_s, w)))
|
||||
.map(move |w| (svr_s, w)),
|
||||
)
|
||||
}
|
||||
Err(err) => {
|
||||
use std::io::ErrorKind;
|
||||
use relay::socks5::Reply;
|
||||
use std::io::ErrorKind;
|
||||
|
||||
error!("Failed to connect remote server, err: {}", err);
|
||||
|
||||
@@ -70,7 +70,10 @@ fn handle_socks5_connect(config: Arc<Config>,
|
||||
let header = TcpResponseHeader::new(reply, Address::SocketAddress(client_addr));
|
||||
trace!("Send header: {:?}", header);
|
||||
|
||||
boxed_future(try_timeout(try_timeout(header.write_to(w), timeout).and_then(flush), timeout).and_then(|_| Err(err)))
|
||||
boxed_future(
|
||||
try_timeout(try_timeout(header.write_to(w), timeout).and_then(flush), timeout)
|
||||
.and_then(|_| Err(err)),
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -87,11 +90,12 @@ fn handle_socks5_connect(config: Arc<Config>,
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_socks5_client(config: Arc<Config>,
|
||||
s: TcpStream,
|
||||
conf: Arc<ServerConfig>,
|
||||
udp_conf: UdpConfig)
|
||||
-> io::Result<()> {
|
||||
fn handle_socks5_client(
|
||||
config: Arc<Config>,
|
||||
s: TcpStream,
|
||||
conf: Arc<ServerConfig>,
|
||||
udp_conf: UdpConfig,
|
||||
) -> io::Result<()> {
|
||||
if let Err(err) = s.set_keepalive(*conf.timeout()) {
|
||||
error!("Failed to set keep alive: {:?}", err);
|
||||
}
|
||||
@@ -112,8 +116,10 @@ fn handle_socks5_client(config: Arc<Config>,
|
||||
let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NOT_ACCEPTABLE);
|
||||
let fut = resp.write_to(w).then(|_| {
|
||||
warn!("Currently shadowsocks-rust does not support authentication");
|
||||
Err(io::Error::new(io::ErrorKind::Other,
|
||||
"Currently shadowsocks-rust does not support authentication"))
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"Currently shadowsocks-rust does not support authentication",
|
||||
))
|
||||
});
|
||||
boxed_future(fut)
|
||||
} else {
|
||||
@@ -128,17 +134,15 @@ fn handle_socks5_client(config: Arc<Config>,
|
||||
.and_then(move |(r, w)| {
|
||||
// Fetch headers
|
||||
TcpRequestHeader::read_from(r).then(move |res| match res {
|
||||
Ok((r, h)) => boxed_future(futures::finished((r, w, h))),
|
||||
Err(err) => {
|
||||
error!("Failed to get TcpRequestHeader: {}", err);
|
||||
let fut =
|
||||
TcpResponseHeader::new(err.reply,
|
||||
Address::SocketAddress(client_addr))
|
||||
.write_to(w)
|
||||
.then(|_| Err(From::from(err)));
|
||||
boxed_future(fut)
|
||||
}
|
||||
})
|
||||
Ok((r, h)) => boxed_future(futures::finished((r, w, h))),
|
||||
Err(err) => {
|
||||
error!("Failed to get TcpRequestHeader: {}", err);
|
||||
let fut = TcpResponseHeader::new(err.reply, Address::SocketAddress(client_addr))
|
||||
.write_to(w)
|
||||
.then(|_| Err(From::from(err)));
|
||||
boxed_future(fut)
|
||||
}
|
||||
})
|
||||
})
|
||||
.and_then(move |(r, w, header)| {
|
||||
trace!("Socks5 {:?}", header);
|
||||
@@ -164,9 +168,9 @@ fn handle_socks5_client(config: Arc<Config>,
|
||||
.write_to(w)
|
||||
.and_then(flush)
|
||||
.and_then(|_| {
|
||||
// Hold the connection until it ends by its own
|
||||
ignore_until_end(r).map(|_| ())
|
||||
});
|
||||
// Hold the connection until it ends by its own
|
||||
ignore_until_end(r).map(|_| ())
|
||||
});
|
||||
|
||||
boxed_future(fut)
|
||||
} else {
|
||||
@@ -181,14 +185,14 @@ fn handle_socks5_client(config: Arc<Config>,
|
||||
});
|
||||
|
||||
tokio::spawn(fut.then(|res| match res {
|
||||
Ok(..) => Ok(()),
|
||||
Err(err) => {
|
||||
if err.kind() != io::ErrorKind::BrokenPipe {
|
||||
error!("Failed to handle client: {}", err);
|
||||
}
|
||||
Err(())
|
||||
}
|
||||
}));
|
||||
Ok(..) => Ok(()),
|
||||
Err(err) => {
|
||||
if err.kind() != io::ErrorKind::BrokenPipe {
|
||||
error!("Failed to handle client: {}", err);
|
||||
}
|
||||
Err(())
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -201,16 +205,18 @@ pub fn run(config: Arc<Config>) -> impl Future<Item = (), Error = io::Error> + S
|
||||
|
||||
info!("ShadowSocks TCP Listening on {}", local_addr);
|
||||
|
||||
let udp_conf = UdpConfig { enable_udp: config.enable_udp,
|
||||
client_addr: local_addr, };
|
||||
let udp_conf = UdpConfig {
|
||||
enable_udp: config.enable_udp,
|
||||
client_addr: local_addr,
|
||||
};
|
||||
|
||||
let mut servers = RoundRobin::new(&*config);
|
||||
listener.incoming().for_each(move |socket| {
|
||||
let server_cfg = servers.pick_server();
|
||||
let server_cfg = servers.pick_server();
|
||||
|
||||
trace!("Got connection, addr: {}", socket.peer_addr()?);
|
||||
trace!("Picked proxy server: {:?}", server_cfg);
|
||||
trace!("Got connection, addr: {}", socket.peer_addr()?);
|
||||
trace!("Picked proxy server: {:?}", server_cfg);
|
||||
|
||||
handle_socks5_client(config.clone(), socket, server_cfg, udp_conf.clone())
|
||||
})
|
||||
handle_socks5_client(config.clone(), socket, server_cfg, udp_conf.clone())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
//! Stream protocol implementation
|
||||
|
||||
use std::cmp;
|
||||
use std::io::{self, BufRead, Read};
|
||||
use std::{
|
||||
cmp,
|
||||
io::{self, BufRead, Read},
|
||||
};
|
||||
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use crypto::{new_stream, CipherType, CryptoMode, StreamCipher, StreamCipherVariant};
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use super::BUFFER_SIZE;
|
||||
use super::{DecryptedRead, EncryptedWrite};
|
||||
use super::{DecryptedRead, EncryptedWrite, BUFFER_SIZE};
|
||||
|
||||
const DUMMY_BUFFER: [u8; BUFFER_SIZE] = [0u8; BUFFER_SIZE];
|
||||
|
||||
/// Reader wrapper that will decrypt data automatically
|
||||
pub struct DecryptedReader<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
reader: R,
|
||||
buffer: BytesMut,
|
||||
@@ -24,16 +26,19 @@ pub struct DecryptedReader<R>
|
||||
}
|
||||
|
||||
impl<R> DecryptedReader<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
pub fn new(r: R, t: CipherType, key: &[u8], iv: &[u8]) -> DecryptedReader<R> {
|
||||
let cipher = new_stream(t, key, iv, CryptoMode::Decrypt);
|
||||
let buffer_size = cipher.buffer_size(&DUMMY_BUFFER);
|
||||
DecryptedReader { reader: r,
|
||||
buffer: BytesMut::with_capacity(buffer_size),
|
||||
cipher: cipher,
|
||||
pos: 0,
|
||||
sent_final: false, }
|
||||
DecryptedReader {
|
||||
reader: r,
|
||||
buffer: BytesMut::with_capacity(buffer_size),
|
||||
cipher: cipher,
|
||||
pos: 0,
|
||||
sent_final: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_ref(&self) -> &R {
|
||||
@@ -60,7 +65,8 @@ impl<R> DecryptedReader<R>
|
||||
}
|
||||
|
||||
impl<R> BufRead for DecryptedReader<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
||||
while self.pos >= self.buffer.len() {
|
||||
@@ -106,7 +112,8 @@ impl<R> BufRead for DecryptedReader<R>
|
||||
}
|
||||
|
||||
impl<R> Read for DecryptedReader<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let nread = {
|
||||
@@ -119,7 +126,8 @@ impl<R> Read for DecryptedReader<R>
|
||||
}
|
||||
|
||||
impl<R> DecryptedRead for DecryptedReader<R>
|
||||
where R: AsyncRead
|
||||
where
|
||||
R: AsyncRead,
|
||||
{
|
||||
fn buffer_size(&self, data: &[u8]) -> usize {
|
||||
self.cipher.buffer_size(data)
|
||||
@@ -130,19 +138,23 @@ impl<R> AsyncRead for DecryptedReader<R> where R: AsyncRead {}
|
||||
|
||||
/// Writer wrapper that will encrypt data automatically
|
||||
pub struct EncryptedWriter<W>
|
||||
where W: AsyncWrite
|
||||
where
|
||||
W: AsyncWrite,
|
||||
{
|
||||
writer: W,
|
||||
cipher: StreamCipherVariant,
|
||||
}
|
||||
|
||||
impl<W> EncryptedWriter<W>
|
||||
where W: AsyncWrite
|
||||
where
|
||||
W: AsyncWrite,
|
||||
{
|
||||
/// Creates a new EncryptedWriter
|
||||
pub fn new(w: W, t: CipherType, key: &[u8], iv: &[u8]) -> EncryptedWriter<W> {
|
||||
EncryptedWriter { writer: w,
|
||||
cipher: new_stream(t, key, iv, CryptoMode::Encrypt), }
|
||||
EncryptedWriter {
|
||||
writer: w,
|
||||
cipher: new_stream(t, key, iv, CryptoMode::Encrypt),
|
||||
}
|
||||
}
|
||||
|
||||
fn cipher_update<B: BufMut>(&mut self, data: &[u8], buf: &mut B) -> io::Result<()> {
|
||||
@@ -155,7 +167,8 @@ impl<W> EncryptedWriter<W>
|
||||
}
|
||||
|
||||
impl<W> Drop for EncryptedWriter<W>
|
||||
where W: AsyncWrite
|
||||
where
|
||||
W: AsyncWrite,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
let mut buf = Vec::new();
|
||||
@@ -168,7 +181,8 @@ impl<W> Drop for EncryptedWriter<W>
|
||||
}
|
||||
|
||||
impl<W> EncryptedWrite for EncryptedWriter<W>
|
||||
where W: AsyncWrite
|
||||
where
|
||||
W: AsyncWrite,
|
||||
{
|
||||
fn write_raw(&mut self, data: &[u8]) -> io::Result<usize> {
|
||||
self.writer.write(data)
|
||||
|
||||
+41
-31
@@ -1,11 +1,16 @@
|
||||
//! Utility functions
|
||||
|
||||
use std::io;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{
|
||||
io,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use tokio::timer::Delay;
|
||||
use tokio_io::io::{copy, Copy};
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
use tokio_io::{
|
||||
io::{copy, Copy},
|
||||
AsyncRead,
|
||||
AsyncWrite,
|
||||
};
|
||||
|
||||
use futures::{Async, Future, Poll};
|
||||
|
||||
@@ -13,16 +18,18 @@ use super::BUFFER_SIZE;
|
||||
|
||||
/// Copies all data from `r` to `w`, abort if timeout reaches
|
||||
pub fn copy_timeout<R, W>(r: R, w: W, dur: Duration) -> CopyTimeout<R, W>
|
||||
where R: AsyncRead,
|
||||
W: AsyncWrite
|
||||
where
|
||||
R: AsyncRead,
|
||||
W: AsyncWrite,
|
||||
{
|
||||
CopyTimeout::new(r, w, dur)
|
||||
}
|
||||
|
||||
/// Copies all data from `r` to `w`, abort if timeout reaches
|
||||
pub struct CopyTimeout<R, W>
|
||||
where R: AsyncRead,
|
||||
W: AsyncWrite
|
||||
where
|
||||
R: AsyncRead,
|
||||
W: AsyncWrite,
|
||||
{
|
||||
r: Option<R>,
|
||||
w: Option<W>,
|
||||
@@ -35,30 +42,31 @@ pub struct CopyTimeout<R, W>
|
||||
}
|
||||
|
||||
impl<R, W> CopyTimeout<R, W>
|
||||
where R: AsyncRead,
|
||||
W: AsyncWrite
|
||||
where
|
||||
R: AsyncRead,
|
||||
W: AsyncWrite,
|
||||
{
|
||||
fn new(r: R, w: W, timeout: Duration) -> CopyTimeout<R, W> {
|
||||
CopyTimeout { r: Some(r),
|
||||
w: Some(w),
|
||||
timeout: timeout,
|
||||
amt: 0,
|
||||
timer: None,
|
||||
buf: [0u8; BUFFER_SIZE],
|
||||
pos: 0,
|
||||
cap: 0, }
|
||||
CopyTimeout {
|
||||
r: Some(r),
|
||||
w: Some(w),
|
||||
timeout: timeout,
|
||||
amt: 0,
|
||||
timer: None,
|
||||
buf: [0u8; BUFFER_SIZE],
|
||||
pos: 0,
|
||||
cap: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_poll_timeout(&mut self) -> io::Result<()> {
|
||||
match self.timer.as_mut() {
|
||||
None => Ok(()),
|
||||
Some(t) => {
|
||||
match t.poll() {
|
||||
Err(err) => panic!("Failed to poll on timer, err: {}", err),
|
||||
Ok(Async::Ready(..)) => Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")),
|
||||
Ok(Async::NotReady) => Ok(()),
|
||||
}
|
||||
}
|
||||
Some(t) => match t.poll() {
|
||||
Err(err) => panic!("Failed to poll on timer, err: {}", err),
|
||||
Ok(Async::Ready(..)) => Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")),
|
||||
Ok(Async::NotReady) => Ok(()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,11 +112,12 @@ impl<R, W> CopyTimeout<R, W>
|
||||
}
|
||||
|
||||
impl<R, W> Future for CopyTimeout<R, W>
|
||||
where R: AsyncRead,
|
||||
W: AsyncWrite
|
||||
where
|
||||
R: AsyncRead,
|
||||
W: AsyncWrite,
|
||||
{
|
||||
type Item = (u64, R, W);
|
||||
type Error = io::Error;
|
||||
type Item = (u64, R, W);
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
loop {
|
||||
@@ -146,8 +155,9 @@ impl<R, W> Future for CopyTimeout<R, W>
|
||||
|
||||
/// Copies all data from `r` to `w` with optional timeout param
|
||||
pub fn copy_timeout_opt<R, W>(r: R, w: W, dur: Option<Duration>) -> CopyTimeoutOpt<R, W>
|
||||
where R: AsyncRead,
|
||||
W: AsyncWrite
|
||||
where
|
||||
R: AsyncRead,
|
||||
W: AsyncWrite,
|
||||
{
|
||||
match dur {
|
||||
Some(d) => CopyTimeoutOpt::CopyTimeout(copy_timeout(r, w, d)),
|
||||
@@ -162,8 +172,8 @@ pub enum CopyTimeoutOpt<R: AsyncRead, W: AsyncWrite> {
|
||||
}
|
||||
|
||||
impl<R: AsyncRead, W: AsyncWrite> Future for CopyTimeoutOpt<R, W> {
|
||||
type Item = (u64, R, W);
|
||||
type Error = io::Error;
|
||||
type Item = (u64, R, W);
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match *self {
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
|
||||
use std::io;
|
||||
|
||||
use crypto::StreamCipher;
|
||||
use crypto::{self, CipherCategory, CipherType, CryptoMode};
|
||||
use crypto::{self, CipherCategory, CipherType, CryptoMode, StreamCipher};
|
||||
|
||||
/// Encrypt payload into ShadowSocks UDP encrypted packet
|
||||
pub fn encrypt_payload(t: CipherType, key: &[u8], payload: &[u8]) -> io::Result<Vec<u8>> {
|
||||
|
||||
+178
-166
@@ -1,25 +1,26 @@
|
||||
//! UDP DNS relay
|
||||
|
||||
use std::fmt;
|
||||
use std::io::{self, Cursor};
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
use std::{
|
||||
fmt,
|
||||
io::{self, Cursor},
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
sync::{Arc, Mutex},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use dns_parser::{Packet, RRData};
|
||||
use futures::future::join_all;
|
||||
use futures::stream::futures_unordered;
|
||||
use futures::{self, Future, Stream};
|
||||
use futures::{self, future::join_all, stream::futures_unordered, Future, Stream};
|
||||
use lru_cache::LruCache;
|
||||
use tokio;
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio::{self, net::UdpSocket};
|
||||
|
||||
use super::crypto_io::{decrypt_payload, encrypt_payload};
|
||||
use super::{PacketStream, SendDgramRc, SharedUdpSocket};
|
||||
use super::{
|
||||
crypto_io::{decrypt_payload, encrypt_payload},
|
||||
PacketStream,
|
||||
SendDgramRc,
|
||||
SharedUdpSocket,
|
||||
};
|
||||
use config::{Config, ServerAddr, ServerConfig};
|
||||
use relay::boxed_future;
|
||||
use relay::dns_resolver::resolve;
|
||||
use relay::socks5::Address;
|
||||
use relay::{boxed_future, dns_resolver::resolve, socks5::Address};
|
||||
|
||||
struct PrettyRRData<'a> {
|
||||
data: &'a RRData<'a>,
|
||||
@@ -38,26 +39,37 @@ impl<'a> fmt::Display for PrettyRRData<'a> {
|
||||
RRData::NS(ref c) => write!(f, "NS({})", c.to_string()),
|
||||
RRData::A(ref i) => write!(f, "A({})", i),
|
||||
RRData::AAAA(ref i) => write!(f, "AAAA({})", i),
|
||||
RRData::SRV { priority, weight, port, target }
|
||||
=> write!(f,
|
||||
"SRV({{priority: {}, weight: {}, port: {}, target: {}}})",
|
||||
priority,
|
||||
weight,
|
||||
port,
|
||||
target.to_string()),
|
||||
RRData::SOA(ref s)
|
||||
=> write!(f,
|
||||
"SOA({{primary_ns: {}, mailbox: {}, serial: {}, refresh: {}, retry: {}, expire: {}, minimum_ttl: {}}})",
|
||||
s.primary_ns.to_string(),
|
||||
s.mailbox.to_string(),
|
||||
s.serial,
|
||||
s.refresh,
|
||||
s.retry,
|
||||
s.expire,
|
||||
s.minimum_ttl),
|
||||
RRData::SRV {
|
||||
priority,
|
||||
weight,
|
||||
port,
|
||||
target,
|
||||
} => write!(
|
||||
f,
|
||||
"SRV({{priority: {}, weight: {}, port: {}, target: {}}})",
|
||||
priority,
|
||||
weight,
|
||||
port,
|
||||
target.to_string()
|
||||
),
|
||||
RRData::SOA(ref s) => write!(
|
||||
f,
|
||||
"SOA({{primary_ns: {}, mailbox: {}, serial: {}, refresh: {}, retry: {}, expire: {}, minimum_ttl: {}}})",
|
||||
s.primary_ns.to_string(),
|
||||
s.mailbox.to_string(),
|
||||
s.serial,
|
||||
s.refresh,
|
||||
s.retry,
|
||||
s.expire,
|
||||
s.minimum_ttl
|
||||
),
|
||||
RRData::PTR(ref p) => write!(f, "PTR({})", p.to_string()),
|
||||
RRData::MX { preference, exchange }
|
||||
=> write!(f, "MX({{preference: {}, exchange: {}}})", preference, exchange.to_string()),
|
||||
RRData::MX { preference, exchange } => write!(
|
||||
f,
|
||||
"MX({{preference: {}, exchange: {}}})",
|
||||
preference,
|
||||
exchange.to_string()
|
||||
),
|
||||
RRData::TXT(t) => write!(f, "TXT({})", t),
|
||||
RRData::Unknown(u) => write!(f, "Unknown({:?})", u),
|
||||
}
|
||||
@@ -76,9 +88,11 @@ impl<'a> PrettyPacket<'a> {
|
||||
|
||||
impl<'a> fmt::Display for PrettyPacket<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f,
|
||||
"Packet (id={} opcode={:?})",
|
||||
self.pkt.header.id, self.pkt.header.opcode)?;
|
||||
write!(
|
||||
f,
|
||||
"Packet (id={} opcode={:?})",
|
||||
self.pkt.header.id, self.pkt.header.opcode
|
||||
)?;
|
||||
|
||||
if !self.pkt.questions.is_empty() {
|
||||
write!(f, " QUESTION[")?;
|
||||
@@ -125,10 +139,11 @@ pub fn run(config: Arc<Config>) -> impl Future<Item = (), Error = io::Error> + S
|
||||
let local_addr = *config.local.as_ref().unwrap();
|
||||
|
||||
futures::lazy(move || {
|
||||
info!("ShadowSocks UDP DNS Listening on {}", local_addr);
|
||||
info!("ShadowSocks UDP DNS Listening on {}", local_addr);
|
||||
|
||||
UdpSocket::bind(&local_addr)
|
||||
}).and_then(move |l| listen(config, l))
|
||||
UdpSocket::bind(&local_addr)
|
||||
})
|
||||
.and_then(move |l| listen(config, l))
|
||||
}
|
||||
|
||||
fn listen(config: Arc<Config>, l: UdpSocket) -> impl Future<Item = (), Error = io::Error> + Send {
|
||||
@@ -147,154 +162,151 @@ fn listen(config: Arc<Config>, l: UdpSocket) -> impl Future<Item = (), Error = i
|
||||
}
|
||||
|
||||
let cloned_config = config.clone();
|
||||
join_all(svr_fut).and_then(move |svr_addrs| {
|
||||
let mut u = Vec::with_capacity(svr_addrs.len());
|
||||
for (idx, svr_addr) in svr_addrs.into_iter().enumerate() {
|
||||
let local_addr = SocketAddr::new(IpAddr::from(Ipv4Addr::new(0, 0, 0, 0)), 0);
|
||||
let s = UdpSocket::bind(&local_addr)?;
|
||||
let svr_cfg = Arc::new(cloned_config.server[idx].clone());
|
||||
u.push((Arc::new(Mutex::new(s)), svr_cfg, svr_addr[0]));
|
||||
}
|
||||
Ok(u)
|
||||
})
|
||||
.and_then(move |vec_servers| {
|
||||
let mut f = Vec::with_capacity(1 + vec_servers.len());
|
||||
let l = Arc::new(Mutex::new(l));
|
||||
f.push(boxed_future(handle_l2r(config, l.clone(), vec_servers.clone())));
|
||||
for (svr, cfg, _) in vec_servers {
|
||||
f.push(boxed_future(handle_r2l(l.clone(), svr, cfg)))
|
||||
}
|
||||
futures_unordered(f).into_future().then(|res| match res {
|
||||
Ok(..) => {
|
||||
error!("One of DNS servers exited unexpectly without error");
|
||||
let err = io::Error::new(io::ErrorKind::Other, "server exited unexpectly");
|
||||
Err(err)
|
||||
}
|
||||
Err((err, ..)) => {
|
||||
error!("One of DNS servers exited unexpectly with error {}", err);
|
||||
Err(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
join_all(svr_fut)
|
||||
.and_then(move |svr_addrs| {
|
||||
let mut u = Vec::with_capacity(svr_addrs.len());
|
||||
for (idx, svr_addr) in svr_addrs.into_iter().enumerate() {
|
||||
let local_addr = SocketAddr::new(IpAddr::from(Ipv4Addr::new(0, 0, 0, 0)), 0);
|
||||
let s = UdpSocket::bind(&local_addr)?;
|
||||
let svr_cfg = Arc::new(cloned_config.server[idx].clone());
|
||||
u.push((Arc::new(Mutex::new(s)), svr_cfg, svr_addr[0]));
|
||||
}
|
||||
Ok(u)
|
||||
})
|
||||
.and_then(move |vec_servers| {
|
||||
let mut f = Vec::with_capacity(1 + vec_servers.len());
|
||||
let l = Arc::new(Mutex::new(l));
|
||||
f.push(boxed_future(handle_l2r(config, l.clone(), vec_servers.clone())));
|
||||
for (svr, cfg, _) in vec_servers {
|
||||
f.push(boxed_future(handle_r2l(l.clone(), svr, cfg)))
|
||||
}
|
||||
futures_unordered(f).into_future().then(|res| match res {
|
||||
Ok(..) => {
|
||||
error!("One of DNS servers exited unexpectly without error");
|
||||
let err = io::Error::new(io::ErrorKind::Other, "server exited unexpectly");
|
||||
Err(err)
|
||||
}
|
||||
Err((err, ..)) => {
|
||||
error!("One of DNS servers exited unexpectly with error {}", err);
|
||||
Err(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref GLOBAL_QUERY_ADDR: Mutex<LruCache<u16, (SocketAddr, Instant)>> = Mutex::new(LruCache::new(1024));
|
||||
}
|
||||
|
||||
fn handle_l2r(config: Arc<Config>,
|
||||
l: SharedUdpSocket,
|
||||
server: Vec<(SharedUdpSocket, Arc<ServerConfig>, SocketAddr)>)
|
||||
-> impl Future<Item = (), Error = io::Error> + Send {
|
||||
fn handle_l2r(
|
||||
config: Arc<Config>,
|
||||
l: SharedUdpSocket,
|
||||
server: Vec<(SharedUdpSocket, Arc<ServerConfig>, SocketAddr)>,
|
||||
) -> impl Future<Item = (), Error = io::Error> + Send {
|
||||
assert!(!server.is_empty());
|
||||
|
||||
let mut server_idx: usize = 0;
|
||||
let server = Arc::new(server);
|
||||
|
||||
PacketStream::new(l).for_each(move |(payload, src)| {
|
||||
let server = server.clone();
|
||||
let config = config.clone();
|
||||
let pkt_fut =
|
||||
futures::lazy(move || {
|
||||
let pkt = Packet::parse(&payload[..]).map_err(|err| {
|
||||
error!("Failed to parse DNS payload, err: {}", err);
|
||||
io::Error::new(io::ErrorKind::Other,
|
||||
"parse DNS packet failed")
|
||||
})?;
|
||||
|
||||
let (ref socket, ref svr_cfg, svr_addr) = server[server_idx % server.len()];
|
||||
let (ni, _) = server_idx.overflowing_add(1);
|
||||
server_idx = ni;
|
||||
|
||||
debug!("DNS {} -> {} {}", src, svr_cfg.addr(), PrettyPacket::new(&pkt));
|
||||
trace!("DETAIL {} -> {} {:?}", src, svr_cfg.addr(), pkt);
|
||||
|
||||
let mut buf = Vec::new();
|
||||
Address::SocketAddress(config.get_remote_dns()).write_to_buf(&mut buf);
|
||||
|
||||
buf.extend_from_slice(&payload);
|
||||
|
||||
let socket = socket.clone();
|
||||
let id = pkt.header.id;
|
||||
encrypt_payload(svr_cfg.method(), svr_cfg.key(), &buf).map(move |send_payload| {
|
||||
(socket,
|
||||
svr_addr,
|
||||
send_payload,
|
||||
id)
|
||||
})
|
||||
}).and_then(move |(socket, svr_addr, send_payload, id)| {
|
||||
SendDgramRc::new(socket, send_payload, svr_addr).map(move |_| {
|
||||
GLOBAL_QUERY_ADDR.lock()
|
||||
.unwrap()
|
||||
.insert(id, (src, Instant::now()));
|
||||
})
|
||||
});
|
||||
tokio::spawn(pkt_fut.then(|res| match res {
|
||||
Ok(..) => Ok(()),
|
||||
Err(err) => {
|
||||
error!("Failed to handle local -> remote packet, err: {}", err);
|
||||
Err(())
|
||||
}
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_r2l(l: SharedUdpSocket,
|
||||
r: SharedUdpSocket,
|
||||
svr_cfg: Arc<ServerConfig>)
|
||||
-> impl Future<Item = (), Error = io::Error> + Send {
|
||||
PacketStream::new(r).for_each(move |(payload, src)| {
|
||||
let l = l.clone();
|
||||
let svr_cfg = svr_cfg.clone();
|
||||
let server = server.clone();
|
||||
let config = config.clone();
|
||||
let pkt_fut = futures::lazy(move || {
|
||||
decrypt_payload(svr_cfg.method(), svr_cfg.key(), &payload)
|
||||
}).and_then(move |payload| {
|
||||
Address::read_from(Cursor::new(payload))
|
||||
.map_err(From::from)
|
||||
}).and_then(move |(cur, ..)| {
|
||||
let pos = cur.position() as usize;
|
||||
let payload = cur.into_inner();
|
||||
|
||||
let pkt = Packet::parse(&payload[pos..]).map_err(|err| {
|
||||
let pkt = Packet::parse(&payload[..]).map_err(|err| {
|
||||
error!("Failed to parse DNS payload, err: {}", err);
|
||||
io::Error::new(io::ErrorKind::Other, "parse DNS packet failed")
|
||||
})?;
|
||||
|
||||
let payload = payload[pos..].to_vec();
|
||||
let (ref socket, ref svr_cfg, svr_addr) = server[server_idx % server.len()];
|
||||
let (ni, _) = server_idx.overflowing_add(1);
|
||||
server_idx = ni;
|
||||
|
||||
match GLOBAL_QUERY_ADDR.lock().unwrap().remove(&pkt.header.id) {
|
||||
Some((cli_addr, start_time)) => {
|
||||
debug!("DNS {} <- {} {} elapsed: {:?}", cli_addr, src, PrettyPacket::new(&pkt), Instant::now() - start_time);
|
||||
trace!("DETAIL {} <- {} {:?}", cli_addr, src, pkt);
|
||||
debug!("DNS {} -> {} {}", src, svr_cfg.addr(), PrettyPacket::new(&pkt));
|
||||
trace!("DETAIL {} -> {} {:?}", src, svr_cfg.addr(), pkt);
|
||||
|
||||
Ok(Some((cli_addr, payload)))
|
||||
}
|
||||
None => {
|
||||
error!("DNS received packet id={} opcode={:?} but found no local endpoint",
|
||||
pkt.header.id, pkt.header.opcode);
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}).and_then(move |opt| {
|
||||
match opt {
|
||||
Some((cli_addr, payload)) => {
|
||||
let f = SendDgramRc::new(l, payload, cli_addr)
|
||||
.map(|_| ());
|
||||
boxed_future(f)
|
||||
}
|
||||
None => boxed_future(futures::finished(()))
|
||||
}
|
||||
let mut buf = Vec::new();
|
||||
Address::SocketAddress(config.get_remote_dns()).write_to_buf(&mut buf);
|
||||
|
||||
buf.extend_from_slice(&payload);
|
||||
|
||||
let socket = socket.clone();
|
||||
let id = pkt.header.id;
|
||||
encrypt_payload(svr_cfg.method(), svr_cfg.key(), &buf)
|
||||
.map(move |send_payload| (socket, svr_addr, send_payload, id))
|
||||
})
|
||||
.and_then(move |(socket, svr_addr, send_payload, id)| {
|
||||
SendDgramRc::new(socket, send_payload, svr_addr).map(move |_| {
|
||||
GLOBAL_QUERY_ADDR.lock().unwrap().insert(id, (src, Instant::now()));
|
||||
})
|
||||
});
|
||||
tokio::spawn(pkt_fut.then(|res| match res {
|
||||
Ok(..) => Ok(()),
|
||||
Err(err) => {
|
||||
error!("Failed to handle local -> remote packet, err: {}", err);
|
||||
Err(())
|
||||
}
|
||||
}));
|
||||
|
||||
tokio::spawn(pkt_fut.then(|res| {
|
||||
match res {
|
||||
Ok(..) => Ok(()),
|
||||
Err(err) => {
|
||||
error!("Failed to handle local <- remote packet, err: {}", err);
|
||||
Err(())
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_r2l(
|
||||
l: SharedUdpSocket,
|
||||
r: SharedUdpSocket,
|
||||
svr_cfg: Arc<ServerConfig>,
|
||||
) -> impl Future<Item = (), Error = io::Error> + Send {
|
||||
PacketStream::new(r).for_each(move |(payload, src)| {
|
||||
let l = l.clone();
|
||||
let svr_cfg = svr_cfg.clone();
|
||||
let pkt_fut = futures::lazy(move || decrypt_payload(svr_cfg.method(), svr_cfg.key(), &payload))
|
||||
.and_then(move |payload| Address::read_from(Cursor::new(payload)).map_err(From::from))
|
||||
.and_then(move |(cur, ..)| {
|
||||
let pos = cur.position() as usize;
|
||||
let payload = cur.into_inner();
|
||||
|
||||
let pkt = Packet::parse(&payload[pos..]).map_err(|err| {
|
||||
error!("Failed to parse DNS payload, err: {}", err);
|
||||
io::Error::new(io::ErrorKind::Other, "parse DNS packet failed")
|
||||
})?;
|
||||
|
||||
let payload = payload[pos..].to_vec();
|
||||
|
||||
match GLOBAL_QUERY_ADDR.lock().unwrap().remove(&pkt.header.id) {
|
||||
Some((cli_addr, start_time)) => {
|
||||
debug!(
|
||||
"DNS {} <- {} {} elapsed: {:?}",
|
||||
cli_addr,
|
||||
src,
|
||||
PrettyPacket::new(&pkt),
|
||||
Instant::now() - start_time
|
||||
);
|
||||
trace!("DETAIL {} <- {} {:?}", cli_addr, src, pkt);
|
||||
|
||||
Ok(Some((cli_addr, payload)))
|
||||
}
|
||||
None => {
|
||||
error!(
|
||||
"DNS received packet id={} opcode={:?} but found no local endpoint",
|
||||
pkt.header.id, pkt.header.opcode
|
||||
);
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
})
|
||||
.and_then(move |opt| match opt {
|
||||
Some((cli_addr, payload)) => {
|
||||
let f = SendDgramRc::new(l, payload, cli_addr).map(|_| ());
|
||||
boxed_future(f)
|
||||
}
|
||||
None => boxed_future(futures::finished(())),
|
||||
});
|
||||
|
||||
tokio::spawn(pkt_fut.then(|res| match res {
|
||||
Ok(..) => Ok(()),
|
||||
Err(err) => {
|
||||
error!("Failed to handle local <- remote packet, err: {}", err);
|
||||
Err(())
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
+76
-59
@@ -1,40 +1,45 @@
|
||||
//! UDP relay local server
|
||||
|
||||
use std::io::{self, Cursor, ErrorKind, Read};
|
||||
use std::net::SocketAddr;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
io::{self, Cursor, ErrorKind, Read},
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
sync::{Arc, Mutex},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use futures::{self, Future, Stream};
|
||||
|
||||
use tokio;
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio::util::FutureExt;
|
||||
use tokio::{self, net::UdpSocket, util::FutureExt};
|
||||
|
||||
use config::{Config, ServerAddr, ServerConfig};
|
||||
use relay::boxed_future;
|
||||
use relay::dns_resolver::resolve;
|
||||
use relay::loadbalancing::server::{LoadBalancer, RoundRobin};
|
||||
use relay::socks5::{Address, UdpAssociateHeader};
|
||||
use relay::{
|
||||
boxed_future,
|
||||
dns_resolver::resolve,
|
||||
loadbalancing::server::{LoadBalancer, RoundRobin},
|
||||
socks5::{Address, UdpAssociateHeader},
|
||||
};
|
||||
|
||||
use super::crypto_io::{decrypt_payload, encrypt_payload};
|
||||
use super::MAXIMUM_UDP_PAYLOAD_SIZE;
|
||||
use super::{PacketStream, SendDgramRc};
|
||||
use super::{
|
||||
crypto_io::{decrypt_payload, encrypt_payload},
|
||||
PacketStream,
|
||||
SendDgramRc,
|
||||
MAXIMUM_UDP_PAYLOAD_SIZE,
|
||||
};
|
||||
|
||||
/// Resolves server address to SocketAddr
|
||||
fn resolve_server_addr(config: Arc<Config>,
|
||||
svr_cfg: Arc<ServerConfig>)
|
||||
-> impl Future<Item = SocketAddr, Error = io::Error> + Send {
|
||||
fn resolve_server_addr(
|
||||
config: Arc<Config>,
|
||||
svr_cfg: Arc<ServerConfig>,
|
||||
) -> impl Future<Item = SocketAddr, Error = io::Error> + Send {
|
||||
match *svr_cfg.addr() {
|
||||
// Return directly if it is a SocketAddr
|
||||
ServerAddr::SocketAddr(ref addr) => boxed_future(futures::finished(*addr)),
|
||||
// Resolve domain name to SocketAddr
|
||||
ServerAddr::DomainName(ref dname, port) => {
|
||||
let fut = resolve(config, dname, port, false).map(move |vec_ipaddr| {
|
||||
assert!(!vec_ipaddr.is_empty());
|
||||
vec_ipaddr[0]
|
||||
});
|
||||
assert!(!vec_ipaddr.is_empty());
|
||||
vec_ipaddr[0]
|
||||
});
|
||||
boxed_future(fut)
|
||||
}
|
||||
}
|
||||
@@ -74,8 +79,7 @@ fn listen(config: Arc<Config>, l: UdpSocket) -> impl Future<Item = (), Error = i
|
||||
resolve_server_addr(config, svr_cfg)
|
||||
.and_then(|remote_addr| {
|
||||
let local_addr = SocketAddr::new(IpAddr::from(Ipv4Addr::new(0, 0, 0, 0)), 0);
|
||||
UdpSocket::bind(&local_addr)
|
||||
.map(|remote_udp| (remote_udp, remote_addr))
|
||||
UdpSocket::bind(&local_addr).map(|remote_udp| (remote_udp, remote_addr))
|
||||
})
|
||||
.map(|(remote_udp, remote_addr)| (remote_udp, remote_addr, payload, addr))
|
||||
})
|
||||
@@ -84,45 +88,54 @@ fn listen(config: Arc<Config>, l: UdpSocket) -> impl Future<Item = (), Error = i
|
||||
addr.write_to_buf(&mut buf);
|
||||
buf.extend_from_slice(&payload);
|
||||
encrypt_payload(svr_cfg.method(), svr_cfg.key(), &buf)
|
||||
.map(|payload| (remote_udp, remote_addr, payload, addr))
|
||||
.map(|payload| (remote_udp, remote_addr, payload, addr))
|
||||
})
|
||||
.and_then(move |(remote_udp, remote_addr, payload, addr)| {
|
||||
debug!("UDP ASSOCIATE {} -> {}, payload length {} bytes", src, addr, payload.len());
|
||||
debug!(
|
||||
"UDP ASSOCIATE {} -> {}, payload length {} bytes",
|
||||
src,
|
||||
addr,
|
||||
payload.len()
|
||||
);
|
||||
let to = timeout.unwrap_or(DEFAULT_TIMEOUT);
|
||||
let caddr = addr.clone();
|
||||
remote_udp.send_dgram(payload, &remote_addr)
|
||||
.timeout(to)
|
||||
.map_err(move |err| {
|
||||
match err.into_inner() {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
error!("Udp associate sending datagram {} -> {} timed out in {:?}", src, caddr, to);
|
||||
io::Error::new(io::ErrorKind::TimedOut, "udp send timed out")
|
||||
}
|
||||
}
|
||||
})
|
||||
.map(|(remote_udp, _)| (remote_udp, addr))
|
||||
remote_udp
|
||||
.send_dgram(payload, &remote_addr)
|
||||
.timeout(to)
|
||||
.map_err(move |err| match err.into_inner() {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
error!(
|
||||
"Udp associate sending datagram {} -> {} timed out in {:?}",
|
||||
src, caddr, to
|
||||
);
|
||||
io::Error::new(io::ErrorKind::TimedOut, "udp send timed out")
|
||||
}
|
||||
})
|
||||
.map(|(remote_udp, _)| (remote_udp, addr))
|
||||
})
|
||||
.and_then(move |(remote_udp, addr)| {
|
||||
let buf = vec![0u8; MAXIMUM_UDP_PAYLOAD_SIZE];
|
||||
let to = timeout.unwrap_or(DEFAULT_TIMEOUT);
|
||||
let caddr = addr.clone();
|
||||
remote_udp.recv_dgram(buf)
|
||||
.timeout(to)
|
||||
.map_err(move |err| {
|
||||
match err.into_inner() {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
error!("Udp associate waiting datagram {} <- {} timed out in {:?}", src, caddr, to);
|
||||
io::Error::new(io::ErrorKind::TimedOut, "udp recv timed out")
|
||||
}
|
||||
}
|
||||
})
|
||||
.and_then(move |(_remote_udp, buf, n, _from)| {
|
||||
let svr_cfg = svr_cfg_cloned;
|
||||
decrypt_payload(svr_cfg.method(), svr_cfg.key(), &buf[..n])
|
||||
})
|
||||
.map(|payload| (payload, addr))
|
||||
remote_udp
|
||||
.recv_dgram(buf)
|
||||
.timeout(to)
|
||||
.map_err(move |err| match err.into_inner() {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
error!(
|
||||
"Udp associate waiting datagram {} <- {} timed out in {:?}",
|
||||
src, caddr, to
|
||||
);
|
||||
io::Error::new(io::ErrorKind::TimedOut, "udp recv timed out")
|
||||
}
|
||||
})
|
||||
.and_then(move |(_remote_udp, buf, n, _from)| {
|
||||
let svr_cfg = svr_cfg_cloned;
|
||||
decrypt_payload(svr_cfg.method(), svr_cfg.key(), &buf[..n])
|
||||
})
|
||||
.map(|payload| (payload, addr))
|
||||
})
|
||||
.and_then(move |(payload, addr)| {
|
||||
Address::read_from(Cursor::new(payload))
|
||||
@@ -131,7 +144,10 @@ fn listen(config: Arc<Config>, l: UdpSocket) -> impl Future<Item = (), Error = i
|
||||
})
|
||||
.and_then(move |(mut cur, addr)| {
|
||||
let payload_len = cur.get_ref().len() - cur.position() as usize;
|
||||
debug!("UDP ASSOCIATE {} <- {}, payload length {} bytes", src, addr, payload_len);
|
||||
debug!(
|
||||
"UDP ASSOCIATE {} <- {}, payload length {} bytes",
|
||||
src, addr, payload_len
|
||||
);
|
||||
|
||||
let mut data = Vec::new();
|
||||
UdpAssociateHeader::new(0, Address::SocketAddress(src)).write_to_buf(&mut data);
|
||||
@@ -143,8 +159,8 @@ fn listen(config: Arc<Config>, l: UdpSocket) -> impl Future<Item = (), Error = i
|
||||
.map(|_| ());
|
||||
|
||||
tokio::spawn(rel.map_err(|err| {
|
||||
error!("Error occurs in UDP relay: {}", err);
|
||||
}));
|
||||
error!("Error occurs in UDP relay: {}", err);
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
})
|
||||
@@ -155,8 +171,9 @@ pub fn run(config: Arc<Config>) -> impl Future<Item = (), Error = io::Error> + S
|
||||
let local_addr = *config.local.as_ref().unwrap();
|
||||
|
||||
futures::lazy(move || {
|
||||
info!("ShadowSocks UDP Listening on {}", local_addr);
|
||||
info!("ShadowSocks UDP Listening on {}", local_addr);
|
||||
|
||||
UdpSocket::bind(&local_addr)
|
||||
}).and_then(move |l| listen(config, l))
|
||||
UdpSocket::bind(&local_addr)
|
||||
})
|
||||
.and_then(move |l| listen(config, l))
|
||||
}
|
||||
|
||||
+26
-14
@@ -37,10 +37,12 @@
|
||||
//! | Fixed | Variable |
|
||||
//! +-------+--------------+
|
||||
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{
|
||||
io,
|
||||
mem,
|
||||
net::SocketAddr,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use tokio::net::UdpSocket;
|
||||
|
||||
@@ -70,14 +72,17 @@ pub struct PacketStream {
|
||||
impl PacketStream {
|
||||
/// Creates a new `PacketStream`
|
||||
pub fn new(udp: SharedUdpSocket) -> PacketStream {
|
||||
PacketStream { udp: udp,
|
||||
buf: [0u8; MAXIMUM_UDP_PAYLOAD_SIZE], }
|
||||
PacketStream {
|
||||
udp: udp,
|
||||
buf: [0u8; MAXIMUM_UDP_PAYLOAD_SIZE],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for PacketStream {
|
||||
type Item = (Vec<u8>, SocketAddr);
|
||||
type Error = io::Error;
|
||||
type Item = (Vec<u8>, SocketAddr);
|
||||
|
||||
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||
let (n, addr) = try_ready!(self.udp.lock().unwrap().poll_recv_from(&mut self.buf));
|
||||
Ok(Async::Ready(Some((self.buf[..n].to_vec(), addr))))
|
||||
@@ -100,20 +105,27 @@ pub struct SendDgramRc<B: AsRef<[u8]>> {
|
||||
|
||||
impl<B: AsRef<[u8]>> SendDgramRc<B> {
|
||||
pub fn new(udp: SharedUdpSocket, buf: B, addr: SocketAddr) -> SendDgramRc<B> {
|
||||
SendDgramRc { stat: SendDgramStat::Pending { udp: udp,
|
||||
buf: buf,
|
||||
addr: addr, }, }
|
||||
SendDgramRc {
|
||||
stat: SendDgramStat::Pending {
|
||||
udp: udp,
|
||||
buf: buf,
|
||||
addr: addr,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]>> Future for SendDgramRc<B> {
|
||||
type Item = (SharedUdpSocket, usize, B);
|
||||
type Error = io::Error;
|
||||
type Item = (SharedUdpSocket, usize, B);
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
let n = match self.stat {
|
||||
SendDgramStat::Pending { ref udp,
|
||||
ref buf,
|
||||
ref addr, } => try_ready!(udp.lock().unwrap().poll_send_to(buf.as_ref(), addr)),
|
||||
SendDgramStat::Pending {
|
||||
ref udp,
|
||||
ref buf,
|
||||
ref addr,
|
||||
} => try_ready!(udp.lock().unwrap().poll_send_to(buf.as_ref(), addr)),
|
||||
SendDgramStat::Empty => unreachable!(),
|
||||
};
|
||||
|
||||
|
||||
@@ -1,32 +1,34 @@
|
||||
//! UDP relay proxy server
|
||||
|
||||
use std::io::{self, Cursor, ErrorKind};
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
io::{self, Cursor, ErrorKind},
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
sync::{Arc, Mutex},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use futures::stream::futures_unordered;
|
||||
use futures::{self, Future, Stream};
|
||||
use futures::{self, stream::futures_unordered, Future, Stream};
|
||||
|
||||
use tokio;
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio::util::FutureExt;
|
||||
use tokio::{self, net::UdpSocket, util::FutureExt};
|
||||
|
||||
use config::{Config, ServerConfig};
|
||||
use relay::boxed_future;
|
||||
use relay::dns_resolver::resolve;
|
||||
use relay::socks5::Address;
|
||||
use relay::{boxed_future, dns_resolver::resolve, socks5::Address};
|
||||
|
||||
use super::crypto_io::{decrypt_payload, encrypt_payload};
|
||||
use super::MAXIMUM_UDP_PAYLOAD_SIZE;
|
||||
use super::{PacketStream, SendDgramRc};
|
||||
use super::{
|
||||
crypto_io::{decrypt_payload, encrypt_payload},
|
||||
PacketStream,
|
||||
SendDgramRc,
|
||||
MAXIMUM_UDP_PAYLOAD_SIZE,
|
||||
};
|
||||
|
||||
fn resolve_remote_addr(config: Arc<Config>, addr: Address) -> impl Future<Item = SocketAddr, Error = io::Error> + Send {
|
||||
match addr {
|
||||
Address::SocketAddress(s) => {
|
||||
if config.forbidden_ip.contains(&s.ip()) {
|
||||
let err = io::Error::new(ErrorKind::Other,
|
||||
format!("{} is forbidden, failed to connect {}", s.ip(), s));
|
||||
let err = io::Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("{} is forbidden, failed to connect {}", s.ip(), s),
|
||||
);
|
||||
return boxed_future(futures::done(Err(err)));
|
||||
}
|
||||
|
||||
@@ -34,9 +36,9 @@ fn resolve_remote_addr(config: Arc<Config>, addr: Address) -> impl Future<Item =
|
||||
}
|
||||
Address::DomainNameAddress(dname, port) => {
|
||||
let fut = resolve(config, &dname, port, true).map(move |vec_ipaddr| {
|
||||
assert!(!vec_ipaddr.is_empty());
|
||||
vec_ipaddr[0]
|
||||
});
|
||||
assert!(!vec_ipaddr.is_empty());
|
||||
vec_ipaddr[0]
|
||||
});
|
||||
boxed_future(fut)
|
||||
}
|
||||
}
|
||||
@@ -54,46 +56,47 @@ fn listen(config: Arc<Config>, svr_cfg: Arc<ServerConfig>) -> impl Future<Item =
|
||||
let config = config.clone();
|
||||
let timeout = *svr_cfg.timeout();
|
||||
let rel = futures::lazy(move || decrypt_payload(svr_cfg.method(), svr_cfg.key(), &pkt))
|
||||
.and_then(move |payload| {
|
||||
// Read Address in the front (ShadowSocks protocol)
|
||||
Address::read_from(Cursor::new(payload))
|
||||
.map_err(From::from)
|
||||
.and_then(move |(r, addr)| {
|
||||
let header_len = r.position() as usize;
|
||||
let mut payload = r.into_inner();
|
||||
payload.drain(..header_len);
|
||||
let body = payload;
|
||||
.and_then(move |payload| {
|
||||
// Read Address in the front (ShadowSocks protocol)
|
||||
Address::read_from(Cursor::new(payload))
|
||||
.map_err(From::from)
|
||||
.and_then(move |(r, addr)| {
|
||||
let header_len = r.position() as usize;
|
||||
let mut payload = r.into_inner();
|
||||
payload.drain(..header_len);
|
||||
let body = payload;
|
||||
|
||||
debug!("UDP ASSOCIATE {} -> {}, payload length {} bytes", src, addr, body.len());
|
||||
Ok((addr, body))
|
||||
})
|
||||
.and_then(|(addr, body)| {
|
||||
let local_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
|
||||
UdpSocket::bind(&local_addr)
|
||||
.map(|remote_udp| (remote_udp, addr, body))
|
||||
})
|
||||
.and_then(|(remote_udp, addr, body)| {
|
||||
resolve_remote_addr(config, addr.clone())
|
||||
.and_then(|addr| remote_udp.send_dgram(body, &addr))
|
||||
.map(|(remote_udp, _)| (remote_udp, addr))
|
||||
})
|
||||
})
|
||||
.and_then(move |(remote_udp, addr)| {
|
||||
let buf = vec![0u8; MAXIMUM_UDP_PAYLOAD_SIZE];
|
||||
let to = timeout.unwrap_or(Duration::from_secs(5));
|
||||
let caddr = addr.clone();
|
||||
remote_udp.recv_dgram(buf)
|
||||
.timeout(to)
|
||||
.map_err(move |err| {
|
||||
match err.into_inner() {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
error!("Udp associate waiting datagram {} -> {} timed out in {:?}", src, caddr, to);
|
||||
io::Error::new(io::ErrorKind::TimedOut, "udp recv timed out")
|
||||
}
|
||||
}
|
||||
})
|
||||
.and_then(|(_remote_udp, buf, n, _from)| {
|
||||
debug!("UDP ASSOCIATE {} -> {}, payload length {} bytes", src, addr, body.len());
|
||||
Ok((addr, body))
|
||||
})
|
||||
.and_then(|(addr, body)| {
|
||||
let local_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
|
||||
UdpSocket::bind(&local_addr).map(|remote_udp| (remote_udp, addr, body))
|
||||
})
|
||||
.and_then(|(remote_udp, addr, body)| {
|
||||
resolve_remote_addr(config, addr.clone())
|
||||
.and_then(|addr| remote_udp.send_dgram(body, &addr))
|
||||
.map(|(remote_udp, _)| (remote_udp, addr))
|
||||
})
|
||||
})
|
||||
.and_then(move |(remote_udp, addr)| {
|
||||
let buf = vec![0u8; MAXIMUM_UDP_PAYLOAD_SIZE];
|
||||
let to = timeout.unwrap_or(Duration::from_secs(5));
|
||||
let caddr = addr.clone();
|
||||
remote_udp
|
||||
.recv_dgram(buf)
|
||||
.timeout(to)
|
||||
.map_err(move |err| match err.into_inner() {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
error!(
|
||||
"Udp associate waiting datagram {} -> {} timed out in {:?}",
|
||||
src, caddr, to
|
||||
);
|
||||
io::Error::new(io::ErrorKind::TimedOut, "udp recv timed out")
|
||||
}
|
||||
})
|
||||
.and_then(|(_remote_udp, buf, n, _from)| {
|
||||
let svr_cfg = svr_cfg_cloned;
|
||||
|
||||
let mut send_buf = Vec::new();
|
||||
@@ -101,29 +104,30 @@ fn listen(config: Arc<Config>, svr_cfg: Arc<ServerConfig>) -> impl Future<Item =
|
||||
send_buf.extend_from_slice(&buf[..n]);
|
||||
encrypt_payload(svr_cfg.method(), svr_cfg.key(), &send_buf).map(|buf| (buf, addr))
|
||||
})
|
||||
})
|
||||
.and_then(move |(buf, addr)| {
|
||||
debug!("UDP ASSOCIATE {} <- {}, payload length {} bytes", src, addr, buf.len());
|
||||
})
|
||||
.and_then(move |(buf, addr)| {
|
||||
debug!("UDP ASSOCIATE {} <- {}, payload length {} bytes", src, addr, buf.len());
|
||||
|
||||
let to = timeout.unwrap_or(Duration::from_secs(5));
|
||||
let caddr = addr.clone();
|
||||
SendDgramRc::new(socket, buf, src)
|
||||
.timeout(to)
|
||||
.map_err(move |err| {
|
||||
match err.into_inner() {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
error!("Udp associate sending datagram {} <- {} timed out in {:?}", src, caddr, to);
|
||||
io::Error::new(io::ErrorKind::TimedOut, "udp send timed out")
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
.map(|_| ());
|
||||
let to = timeout.unwrap_or(Duration::from_secs(5));
|
||||
let caddr = addr.clone();
|
||||
SendDgramRc::new(socket, buf, src)
|
||||
.timeout(to)
|
||||
.map_err(move |err| match err.into_inner() {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
error!(
|
||||
"Udp associate sending datagram {} <- {} timed out in {:?}",
|
||||
src, caddr, to
|
||||
);
|
||||
io::Error::new(io::ErrorKind::TimedOut, "udp send timed out")
|
||||
}
|
||||
})
|
||||
})
|
||||
.map(|_| ());
|
||||
|
||||
tokio::spawn(rel.map_err(|err| {
|
||||
error!("Udp relay error: {}", err);
|
||||
}));
|
||||
error!("Udp relay error: {}", err);
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
})
|
||||
@@ -142,16 +146,14 @@ pub fn run(config: Arc<Config>) -> impl Future<Item = (), Error = io::Error> + S
|
||||
}
|
||||
|
||||
futures_unordered(vec_fut).into_future().then(|res| match res {
|
||||
Ok(..) => {
|
||||
error!("One of UDP servers exited unexpectly without error");
|
||||
let err = io::Error::new(io::ErrorKind::Other,
|
||||
"server exited unexpectly");
|
||||
Err(err)
|
||||
}
|
||||
Err((err, ..)) => {
|
||||
error!("One of UDP servers exited unexpectly with error {}",
|
||||
err);
|
||||
Err(err)
|
||||
}
|
||||
})
|
||||
Ok(..) => {
|
||||
error!("One of UDP servers exited unexpectly without error");
|
||||
let err = io::Error::new(io::ErrorKind::Other, "server exited unexpectly");
|
||||
Err(err)
|
||||
}
|
||||
Err((err, ..)) => {
|
||||
error!("One of UDP servers exited unexpectly with error {}", err);
|
||||
Err(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+17
-10
@@ -1,32 +1,39 @@
|
||||
use std::io;
|
||||
|
||||
use futures::{Async, Future, Poll};
|
||||
use tokio_io::io::{write_all, WriteAll};
|
||||
use tokio_io::AsyncWrite;
|
||||
use tokio_io::{
|
||||
io::{write_all, WriteAll},
|
||||
AsyncWrite,
|
||||
};
|
||||
|
||||
/// Write all bytes without returning the internal bytes buffer
|
||||
pub struct WriteBytes<W, B>
|
||||
where W: AsyncWrite,
|
||||
B: AsRef<[u8]>
|
||||
where
|
||||
W: AsyncWrite,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
inner: WriteAll<W, B>,
|
||||
}
|
||||
|
||||
impl<W, B> WriteBytes<W, B>
|
||||
where W: AsyncWrite,
|
||||
B: AsRef<[u8]>
|
||||
where
|
||||
W: AsyncWrite,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
fn new(writer: W, bytes: B) -> WriteBytes<W, B> {
|
||||
WriteBytes { inner: write_all(writer, bytes), }
|
||||
WriteBytes {
|
||||
inner: write_all(writer, bytes),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<W, B> Future for WriteBytes<W, B>
|
||||
where W: AsyncWrite,
|
||||
B: AsRef<[u8]>
|
||||
where
|
||||
W: AsyncWrite,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
type Item = W;
|
||||
type Error = io::Error;
|
||||
type Item = W;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
let (w, _) = try_ready!(self.inner.poll());
|
||||
|
||||
+17
-12
@@ -6,14 +6,19 @@ extern crate tokio;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::net::{SocketAddr, UdpSocket};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
net::{SocketAddr, UdpSocket},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use dns_parser::{Builder, Packet, QueryClass, QueryType};
|
||||
use shadowsocks::config::{Config, ConfigType};
|
||||
use shadowsocks::{run_dns, run_server};
|
||||
use shadowsocks::{
|
||||
config::{Config, ConfigType},
|
||||
run_dns,
|
||||
run_server,
|
||||
};
|
||||
use tokio::runtime::current_thread::Runtime;
|
||||
|
||||
const CONFIG: &'static str = r#"{
|
||||
@@ -35,14 +40,14 @@ fn dns_relay() {
|
||||
let dns_cfg = Config::load_from_str(CONFIG, ConfigType::Local).unwrap();
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
runtime.block_on(run_server(server_cfg)).unwrap();
|
||||
});
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
runtime.block_on(run_server(server_cfg)).unwrap();
|
||||
});
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
runtime.block_on(run_dns(dns_cfg)).unwrap();
|
||||
});
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
runtime.block_on(run_dns(dns_cfg)).unwrap();
|
||||
});
|
||||
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
|
||||
|
||||
+64
-52
@@ -5,19 +5,23 @@ extern crate shadowsocks;
|
||||
extern crate tokio;
|
||||
extern crate tokio_io;
|
||||
|
||||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
net::{SocketAddr, ToSocketAddrs},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use futures::Future;
|
||||
use tokio::runtime::current_thread::Runtime;
|
||||
use tokio_io::io::{flush, read_to_end, write_all};
|
||||
|
||||
use shadowsocks::config::{Config, ServerConfig};
|
||||
use shadowsocks::crypto::CipherType;
|
||||
use shadowsocks::relay::socks5::Address;
|
||||
use shadowsocks::relay::tcprelay::client::Socks5Client;
|
||||
use shadowsocks::{run_local, run_server};
|
||||
use shadowsocks::{
|
||||
config::{Config, ServerConfig},
|
||||
crypto::CipherType,
|
||||
relay::{socks5::Address, tcprelay::client::Socks5Client},
|
||||
run_local,
|
||||
run_server,
|
||||
};
|
||||
|
||||
pub struct Socks5TestServer {
|
||||
local_addr: SocketAddr,
|
||||
@@ -25,26 +29,30 @@ pub struct Socks5TestServer {
|
||||
}
|
||||
|
||||
impl Socks5TestServer {
|
||||
pub fn new<S, L>(svr_addr: S,
|
||||
local_addr: L,
|
||||
pwd: &'static str,
|
||||
method: CipherType,
|
||||
enable_udp: bool)
|
||||
-> Socks5TestServer
|
||||
where S: ToSocketAddrs,
|
||||
L: ToSocketAddrs
|
||||
pub fn new<S, L>(
|
||||
svr_addr: S,
|
||||
local_addr: L,
|
||||
pwd: &'static str,
|
||||
method: CipherType,
|
||||
enable_udp: bool,
|
||||
) -> Socks5TestServer
|
||||
where
|
||||
S: ToSocketAddrs,
|
||||
L: ToSocketAddrs,
|
||||
{
|
||||
let svr_addr = svr_addr.to_socket_addrs().unwrap().next().unwrap();
|
||||
let local_addr = local_addr.to_socket_addrs().unwrap().next().unwrap();
|
||||
|
||||
Socks5TestServer { local_addr: local_addr,
|
||||
config: {
|
||||
let mut cfg = Config::new();
|
||||
cfg.local = Some(local_addr);
|
||||
cfg.server = vec![ServerConfig::basic(svr_addr, pwd.to_owned(), method)];
|
||||
cfg.enable_udp = enable_udp;
|
||||
cfg
|
||||
}, }
|
||||
Socks5TestServer {
|
||||
local_addr: local_addr,
|
||||
config: {
|
||||
let mut cfg = Config::new();
|
||||
cfg.local = Some(local_addr);
|
||||
cfg.server = vec![ServerConfig::basic(svr_addr, pwd.to_owned(), method)];
|
||||
cfg.enable_udp = enable_udp;
|
||||
cfg
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn client_addr(&self) -> &SocketAddr {
|
||||
@@ -54,17 +62,17 @@ impl Socks5TestServer {
|
||||
pub fn run(&self) {
|
||||
let svr_cfg = self.config.clone();
|
||||
thread::spawn(move || {
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
let fut = run_server(svr_cfg);
|
||||
runtime.block_on(fut).expect("Failed to run Server");
|
||||
});
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
let fut = run_server(svr_cfg);
|
||||
runtime.block_on(fut).expect("Failed to run Server");
|
||||
});
|
||||
|
||||
let client_cfg = self.config.clone();
|
||||
thread::spawn(move || {
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
let fut = run_local(client_cfg);
|
||||
runtime.block_on(fut).expect("Failed to run Local");
|
||||
});
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
let fut = run_local(client_cfg);
|
||||
runtime.block_on(fut).expect("Failed to run Local");
|
||||
});
|
||||
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
}
|
||||
@@ -83,18 +91,20 @@ fn socks5_relay_stream() {
|
||||
let svr = Socks5TestServer::new(SERVER_ADDR, LOCAL_ADDR, PASSWORD, METHOD, false);
|
||||
svr.run();
|
||||
|
||||
let c = Socks5Client::connect(Address::DomainNameAddress("www.example.com".to_owned(), 80),
|
||||
*svr.client_addr());
|
||||
let c = Socks5Client::connect(
|
||||
Address::DomainNameAddress("www.example.com".to_owned(), 80),
|
||||
*svr.client_addr(),
|
||||
);
|
||||
|
||||
let fut = c.and_then(|c| {
|
||||
let req = b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n";
|
||||
write_all(c, req.to_vec()).and_then(|(c, _)| flush(c))
|
||||
.and_then(|c| read_to_end(c, Vec::new()))
|
||||
.map(|(_, buf)| {
|
||||
println!("Got reply from server: {}",
|
||||
String::from_utf8(buf).unwrap());
|
||||
})
|
||||
});
|
||||
let req = b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n";
|
||||
write_all(c, req.to_vec())
|
||||
.and_then(|(c, _)| flush(c))
|
||||
.and_then(|c| read_to_end(c, Vec::new()))
|
||||
.map(|(_, buf)| {
|
||||
println!("Got reply from server: {}", String::from_utf8(buf).unwrap());
|
||||
})
|
||||
});
|
||||
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
runtime.block_on(fut).unwrap();
|
||||
@@ -113,17 +123,19 @@ fn socks5_relay_aead() {
|
||||
let svr = Socks5TestServer::new(SERVER_ADDR, LOCAL_ADDR, PASSWORD, METHOD, false);
|
||||
svr.run();
|
||||
|
||||
let c = Socks5Client::connect(Address::DomainNameAddress("www.example.com".to_owned(), 80),
|
||||
*svr.client_addr());
|
||||
let c = Socks5Client::connect(
|
||||
Address::DomainNameAddress("www.example.com".to_owned(), 80),
|
||||
*svr.client_addr(),
|
||||
);
|
||||
let fut = c.and_then(|c| {
|
||||
let req = b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n";
|
||||
write_all(c, req.to_vec()).and_then(|(c, _)| flush(c))
|
||||
.and_then(|c| read_to_end(c, Vec::new()))
|
||||
.map(|(_, buf)| {
|
||||
println!("Got reply from server: {}",
|
||||
String::from_utf8(buf).unwrap());
|
||||
})
|
||||
});
|
||||
let req = b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n";
|
||||
write_all(c, req.to_vec())
|
||||
.and_then(|(c, _)| flush(c))
|
||||
.and_then(|c| read_to_end(c, Vec::new()))
|
||||
.map(|(_, buf)| {
|
||||
println!("Got reply from server: {}", String::from_utf8(buf).unwrap());
|
||||
})
|
||||
});
|
||||
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
runtime.block_on(fut).unwrap();
|
||||
|
||||
+48
-37
@@ -7,22 +7,29 @@ extern crate shadowsocks;
|
||||
extern crate tokio;
|
||||
extern crate tokio_io;
|
||||
|
||||
use std::io::Cursor;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, Barrier};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
io::Cursor,
|
||||
net::SocketAddr,
|
||||
sync::{Arc, Barrier},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use futures::Future;
|
||||
use tokio::runtime::current_thread::Runtime;
|
||||
use tokio_io::io::read_to_end;
|
||||
|
||||
use shadowsocks::config::{Config, ServerConfig};
|
||||
use shadowsocks::crypto::CipherType;
|
||||
use shadowsocks::relay::socks5::{Address, UdpAssociateHeader};
|
||||
use shadowsocks::relay::tcprelay::client::Socks5Client;
|
||||
use shadowsocks::{run_local, run_server};
|
||||
use shadowsocks::{
|
||||
config::{Config, ServerConfig},
|
||||
crypto::CipherType,
|
||||
relay::{
|
||||
socks5::{Address, UdpAssociateHeader},
|
||||
tcprelay::client::Socks5Client,
|
||||
},
|
||||
run_local,
|
||||
run_server,
|
||||
};
|
||||
|
||||
const SERVER_ADDR: &'static str = "127.0.0.1:8093";
|
||||
const LOCAL_ADDR: &'static str = "127.0.0.1:8291";
|
||||
@@ -36,7 +43,11 @@ const METHOD: CipherType = CipherType::Aes128Cfb;
|
||||
fn get_config() -> Config {
|
||||
let mut cfg = Config::new();
|
||||
cfg.local = Some(LOCAL_ADDR.parse().unwrap());
|
||||
cfg.server = vec![ServerConfig::basic(SERVER_ADDR.parse().unwrap(), PASSWORD.to_owned(), METHOD)];
|
||||
cfg.server = vec![ServerConfig::basic(
|
||||
SERVER_ADDR.parse().unwrap(),
|
||||
PASSWORD.to_owned(),
|
||||
METHOD,
|
||||
)];
|
||||
cfg.enable_udp = true;
|
||||
cfg
|
||||
}
|
||||
@@ -47,55 +58,55 @@ fn get_client_addr() -> SocketAddr {
|
||||
|
||||
fn start_server(bar: Arc<Barrier>) {
|
||||
thread::spawn(move || {
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
|
||||
let fut = run_server(get_config());
|
||||
bar.wait();
|
||||
runtime.block_on(fut).expect("Failed to run Server");
|
||||
});
|
||||
let fut = run_server(get_config());
|
||||
bar.wait();
|
||||
runtime.block_on(fut).expect("Failed to run Server");
|
||||
});
|
||||
}
|
||||
|
||||
fn start_local(bar: Arc<Barrier>) {
|
||||
thread::spawn(move || {
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
|
||||
let fut = run_local(get_config());
|
||||
bar.wait();
|
||||
runtime.block_on(fut).expect("Failed to run Local");
|
||||
});
|
||||
let fut = run_local(get_config());
|
||||
bar.wait();
|
||||
runtime.block_on(fut).expect("Failed to run Local");
|
||||
});
|
||||
}
|
||||
|
||||
fn start_udp_echo_server(bar: Arc<Barrier>) {
|
||||
use std::net::UdpSocket;
|
||||
|
||||
thread::spawn(move || {
|
||||
let l = UdpSocket::bind(UDP_ECHO_SERVER_ADDR).unwrap();
|
||||
let l = UdpSocket::bind(UDP_ECHO_SERVER_ADDR).unwrap();
|
||||
|
||||
bar.wait();
|
||||
bar.wait();
|
||||
|
||||
let mut buf = [0u8; 65536];
|
||||
let (amt, src) = l.recv_from(&mut buf).unwrap();
|
||||
let mut buf = [0u8; 65536];
|
||||
let (amt, src) = l.recv_from(&mut buf).unwrap();
|
||||
|
||||
l.send_to(&buf[..amt], &src).unwrap();
|
||||
});
|
||||
l.send_to(&buf[..amt], &src).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
fn start_udp_request_holder(bar: Arc<Barrier>, addr: Address) {
|
||||
thread::spawn(move || {
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
let mut runtime = Runtime::new().expect("Failed to create Runtime");
|
||||
|
||||
let c = Socks5Client::udp_associate(addr, get_client_addr());
|
||||
let fut = c.and_then(|(c, addr)| {
|
||||
assert_eq!(addr, Address::SocketAddress(LOCAL_ADDR.parse().unwrap()));
|
||||
let c = Socks5Client::udp_associate(addr, get_client_addr());
|
||||
let fut = c.and_then(|(c, addr)| {
|
||||
assert_eq!(addr, Address::SocketAddress(LOCAL_ADDR.parse().unwrap()));
|
||||
|
||||
// Holds it forever
|
||||
read_to_end(c, Vec::new()).map(|_| ())
|
||||
});
|
||||
// Holds it forever
|
||||
read_to_end(c, Vec::new()).map(|_| ())
|
||||
});
|
||||
|
||||
bar.wait();
|
||||
bar.wait();
|
||||
|
||||
runtime.block_on(fut).expect("Failed to run UDP socks5 client");
|
||||
});
|
||||
runtime.block_on(fut).expect("Failed to run UDP socks5 client");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user