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:
Y. T. Chung
2018-10-01 10:32:04 +08:00
parent e78c5ff6e6
commit c60869aa50
48 changed files with 2611 additions and 2026 deletions
Generated
+160 -99
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+9 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -1,7 +1,6 @@
//! DNS relay
use std::io;
use std::sync::Arc;
use std::{io, sync::Arc};
use futures::Future;
+47 -43
View File
@@ -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)
}
+4 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+59 -48
View File
@@ -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
View File
@@ -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 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}
})
}
+69 -63
View File
@@ -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())
})
}
+34 -20
View File
@@ -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
View File
@@ -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 {
+1 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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!(),
};
+93 -91
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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]