diff --git a/Cargo.lock b/Cargo.lock index 071803b3..2d6d2cec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "addr2line" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gimli 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -92,9 +92,9 @@ name = "async-trait" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -102,7 +102,7 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -117,7 +117,7 @@ name = "backtrace" version = "0.3.48" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "addr2line 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "addr2line 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "object 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -328,9 +328,9 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -441,9 +441,9 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -471,7 +471,7 @@ dependencies = [ "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -529,7 +529,7 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", @@ -603,7 +603,7 @@ dependencies = [ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -921,7 +921,7 @@ name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1008,9 +1008,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "pest_meta 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1025,20 +1025,20 @@ dependencies = [ [[package]] name = "pin-project" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "pin-project-internal 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project-internal 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pin-project-internal" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1068,7 +1068,7 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1083,7 +1083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1104,10 +1104,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1127,7 +1127,7 @@ name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1289,9 +1289,9 @@ name = "serde_derive" version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1361,7 +1361,7 @@ dependencies = [ "native-tls 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.29 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "qrcode 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1377,7 +1377,7 @@ dependencies = [ "strum_macros 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-native-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-rustls 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "tower 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "trust-dns-proto 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", "trust-dns-resolver 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1451,9 +1451,9 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1463,11 +1463,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1528,20 +1528,20 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "thiserror-impl 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thiserror-impl" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1589,9 +1589,9 @@ name = "tokio-macros" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1605,7 +1605,7 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1650,7 +1650,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "tower-layer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1663,7 +1663,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1678,7 +1678,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "tower-layer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tower-load 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1692,7 +1692,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "tower-discover 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1704,7 +1704,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "tower-layer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1715,7 +1715,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "tower-layer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1731,7 +1731,7 @@ name = "tower-timeout" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "tower-layer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1744,7 +1744,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1764,9 +1764,9 @@ name = "tracing-attributes" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1790,9 +1790,9 @@ dependencies = [ "http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-rustls 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "trust-dns-proto 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", "trust-dns-rustls 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", "typed-headers 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1814,7 +1814,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1834,9 +1834,9 @@ dependencies = [ "resolv-conf 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-rustls 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "trust-dns-https 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", "trust-dns-proto 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", "trust-dns-rustls 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1852,7 +1852,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-rustls 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "trust-dns-proto 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)", "webpki 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1976,9 +1976,9 @@ dependencies = [ "bumpalo 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-shared 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1987,7 +1987,7 @@ name = "wasm-bindgen-macro" version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-macro-support 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1996,9 +1996,9 @@ name = "wasm-bindgen-macro-support" version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-backend 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-shared 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2107,7 +2107,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum addr2line 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "456d75cbb82da1ad150c8a9d97285ffcd21c9931dcb11e995903e7d75141b38b" +"checksum addr2line 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a49806b9dadc843c61e7c97e72490ad7f7220ae249012fbda9ad0609457c0543" "checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" "checksum aead 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4cf01b9b56e767bb57b94ebf91a58b338002963785cdd7013e21c0d4679471e4" "checksum aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9" @@ -2172,7 +2172,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gimli 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" "checksum h2 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "79b7246d7e4b979c03fa093da39cfb3617a96bbeee6310af63991668d7e843ff" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hermit-abi 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4" +"checksum hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" "checksum hkdf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fa08a006102488bd9cd5b8013aabe84955cf5ae22e304c2caf655b633aefae3" "checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" "checksum hostname 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" @@ -2228,19 +2228,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" "checksum pest_generator 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" "checksum pest_meta 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" -"checksum pin-project 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)" = "81d480cb4e89522ccda96d0eed9af94180b7a5f93fb28f66e1fd7d68431663d1" -"checksum pin-project-internal 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)" = "a82996f11efccb19b685b14b5df818de31c1edcee3daa256ab5775dd98e72feb" +"checksum pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)" = "edc93aeee735e60ecb40cf740eb319ff23eab1c5748abfdb5c180e4ce49f7791" +"checksum pin-project-internal 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)" = "e58db2081ba5b4c93bd6be09c40fd36cb9193a8336c384f3b40012e531aa7e40" "checksum pin-project-lite 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f7505eeebd78492e0f6108f7171c4948dbb120ee8119d9d77d0afa5469bef67f" "checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum pmac 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd76d63e86aa67a4bd063079f0d93bb8730b036eea5697345f651e6874ea61e5" -"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" "checksum proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" "checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" -"checksum proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8872cf6f48eee44265156c111456a700ab3483686b3f96df4cf5481c89157319" +"checksum proc-macro2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "53f5ffe53a6b28e37c9c1ce74893477864d64f74778a93a4beb43c8fa167f639" "checksum qrcode 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16d2f1455f3630c6e5107b4f2b94e74d76dea80736de0981fd27644216cff57f" "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -"checksum quote 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "42934bc9c8ab0d3b273a16d8551c8f0fcff46be73276ca083ec2414c15c4ba5e" +"checksum quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" @@ -2276,21 +2276,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum strum 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" "checksum strum_macros 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" -"checksum syn 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "4696caa4048ac7ce2bcd2e484b3cef88c1004e41b8e945a277e2c25dc0b72060" +"checksum syn 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "1425de3c33b0941002740a420b1a906a350b88d08b82b2c8a01035a3f9447bac" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "b3196bfbffbba3e57481b6ea32249fbaf590396a52505a2615adbb79d9d826d3" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term_size 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9" "checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thiserror 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "467e5ff447618a916519a4e0d62772ab14f434897f3d63f05d8700ef1e9b22c1" -"checksum thiserror-impl 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "e63c1091225b9834089b429bc4a2e01223470e3183e891582909e9d1c4cb55d9" +"checksum thiserror 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5976891d6950b4f68477850b5b9e5aa64d955961466f9e174363f573e54e8ca7" +"checksum thiserror-impl 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "ab81dbd1cd69cd2ce22ecfbdd3bdb73334ba25350649408cc6c085f46d89573d" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" "checksum tokio 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d099fa27b9702bed751524694adbe393e18b36b204da91eb1cbbbbb4a5ee2d58" "checksum tokio-macros 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" "checksum tokio-native-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd608593a919a8e05a7d1fc6df885e40f6a88d3a70a3a7eff23ff27964eda069" -"checksum tokio-rustls 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4adb8b3e5f86b707f1b54e7c15b6de52617a823608ccda98a15d3a24222f265a" +"checksum tokio-rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "15cb62a0d2770787abc96e99c1cd98fcf17f94959f3af63ca85bdfb203f051b4" "checksum tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" "checksum tower 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd3169017c090b7a28fce80abaad0ab4f5566423677c9331bb320af7e49cfe62" "checksum tower-buffer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4887dc2a65d464c8b9b66e0e4d51c2fd6cf5b3373afc72805b0a60bce00446a" diff --git a/Cargo.toml b/Cargo.toml index 4d8d213c..4727817f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ incremental = false panic = "abort" [features] -default = ["sodium", "rc4", "aes-cfb", "aes-ctr", "trust-dns", "local-http", "local-tunnel", "local-http-native-tls"] +default = ["sodium", "rc4", "aes-cfb", "aes-ctr", "trust-dns", "local-http", "local-http-native-tls", "local-tunnel", "local-socks4"] # Enables ciphers that depending on libsodium # chacha20, xchacha20, chacha20-ietf # salsa20, xsalsa20 @@ -77,6 +77,8 @@ local-http-rustls = ["tokio-rustls", "webpki-roots", "rustls-native-certs"] local-redir = [] # Enable tunnel protocol for sslocal local-tunnel = [] +# Enable SOCKS4/4a protocol for sslocal +local-socks4 = [] [dependencies] log = "0.4" diff --git a/src/bin/local.rs b/src/bin/local.rs index 6baad13c..e29e5058 100644 --- a/src/bin/local.rs +++ b/src/bin/local.rs @@ -30,6 +30,8 @@ mod validator; const AVAILABLE_PROTOCOLS: &[&str] = &[ "socks5", + #[cfg(feature = "local-socks4")] + "socks4", #[cfg(feature = "local-http")] "http", #[cfg(feature = "local-tunnel")] @@ -128,6 +130,8 @@ fn main() { let config_type = match matches.value_of("PROTOCOL") { Some("socks5") => ConfigType::Socks5Local, + #[cfg(feature = "local-socks4")] + Some("socks4") => ConfigType::Socks4Local, #[cfg(feature = "local-http")] Some("http") => ConfigType::HttpLocal, #[cfg(feature = "local-tunnel")] diff --git a/src/config.rs b/src/config.rs index e4019c2f..2ae00fd1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -583,6 +583,12 @@ pub enum ConfigType { /// Requires `local` configuration Socks5Local, + /// Config for socks4 local + /// + /// Requires `local` configuration + #[cfg(feature = "local-socks4")] + Socks4Local, + /// Config for HTTP local /// /// Requires `local` configuration @@ -619,6 +625,8 @@ impl ConfigType { pub fn is_local(self) -> bool { match self { ConfigType::Socks5Local => true, + #[cfg(feature = "local-socks4")] + ConfigType::Socks4Local => true, #[cfg(feature = "local-dns-relay")] ConfigType::DnsLocal => true, #[cfg(feature = "local-tunnel")] @@ -635,6 +643,8 @@ impl ConfigType { pub fn is_server(self) -> bool { match self { ConfigType::Socks5Local => false, + #[cfg(feature = "local-socks4")] + ConfigType::Socks4Local => false, #[cfg(feature = "local-dns-relay")] ConfigType::DnsLocal => false, #[cfg(feature = "local-tunnel")] diff --git a/src/relay/local.rs b/src/relay/local.rs index dfdf7d90..793d65a2 100644 --- a/src/relay/local.rs +++ b/src/relay/local.rs @@ -47,18 +47,25 @@ pub async fn run(mut config: Config) -> io::Result<()> { let mut vf = Vec::new(); let enable_tcp = match config_type { - #[cfg(not(target_os = "android"))] // Socks5 always true, because UDP associate command also requires a TCP connection + #[cfg(not(target_os = "android"))] ConfigType::Socks5Local => true, // On Android, we allows UDP only mode to support fallback UDP upstream #[cfg(target_os = "android")] ConfigType::Socks5Local => mode.enable_tcp(), + + // Socks4 always true + #[cfg(feature = "local-socks4")] + ConfigType::Socks4Local => true, + // Tunnel mode controlled by this flag #[cfg(feature = "local-tunnel")] ConfigType::TunnelLocal => mode.enable_tcp(), + // HTTP must be TCP #[cfg(feature = "local-http")] ConfigType::HttpLocal => true, + // Redir mode controlled by this flag #[cfg(feature = "local-redir")] ConfigType::RedirLocal => mode.enable_tcp(), diff --git a/src/relay/mod.rs b/src/relay/mod.rs index e941381a..6f9165bc 100644 --- a/src/relay/mod.rs +++ b/src/relay/mod.rs @@ -10,6 +10,7 @@ pub mod manager; #[cfg(feature = "local-redir")] pub(crate) mod redir; pub mod server; +pub mod socks4; pub mod socks5; pub(crate) mod sys; pub mod tcprelay; diff --git a/src/relay/socks4.rs b/src/relay/socks4.rs new file mode 100644 index 00000000..45b247bf --- /dev/null +++ b/src/relay/socks4.rs @@ -0,0 +1,375 @@ +//! Socks4a Protocol Definition +//! +//! http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol + +use std::{ + fmt, + io::{self, Error, ErrorKind}, + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, +}; + +use byteorder::{BigEndian, ByteOrder}; +use bytes::{BufMut, BytesMut}; +use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; + +use crate::relay::socks5; + +#[rustfmt::skip] +mod consts { + pub const SOCKS4_VERSION: u8 = 4; + + pub const SOCKS4_COMMAND_CONNECT: u8 = 1; + pub const SOCKS4_COMMAND_BIND: u8 = 2; + + pub const SOCKS4_RESULT_REQUEST_GRANTED: u8 = 90; + pub const SOCKS4_RESULT_REQUEST_REJECTED_OR_FAILED: u8 = 91; + pub const SOCKS4_RESULT_REQUEST_REJECTED_CANNOT_CONNECT: u8 = 92; + pub const SOCKS4_RESULT_REQUEST_REJECTED_DFFERENT_USER_ID: u8 = 93; +} + +/// SOCKS4 Command +#[derive(Clone, Debug, Copy)] +pub enum Command { + /// CONNECT command + Connect, + /// BIND command + Bind, +} + +impl Command { + #[inline] + fn as_u8(self) -> u8 { + match self { + Command::Connect => consts::SOCKS4_COMMAND_CONNECT, + Command::Bind => consts::SOCKS4_COMMAND_BIND, + } + } + + #[inline] + fn from_u8(code: u8) -> Option { + match code { + consts::SOCKS4_COMMAND_CONNECT => Some(Command::Connect), + consts::SOCKS4_COMMAND_BIND => Some(Command::Bind), + _ => None, + } + } +} + +/// SOCKS4 Result Code +#[derive(Clone, Debug, Copy)] +pub enum ResultCode { + /// 90: request granted + RequestGranted, + /// 91: request rejected or failed + RequestRejectedOrFailed, + /// 92: request rejected becasue SOCKS server cannot connect to identd on the client + RequestRejectedCannotConnect, + /// 93: request rejected because the client program and identd report different user-ids + RequestRejectedDifferentUserId, + /// Other replies + Other(u8), +} + +impl ResultCode { + #[inline] + fn as_u8(self) -> u8 { + match self { + ResultCode::RequestGranted => consts::SOCKS4_RESULT_REQUEST_GRANTED, + ResultCode::RequestRejectedOrFailed => consts::SOCKS4_RESULT_REQUEST_REJECTED_OR_FAILED, + ResultCode::RequestRejectedCannotConnect => consts::SOCKS4_RESULT_REQUEST_REJECTED_CANNOT_CONNECT, + ResultCode::RequestRejectedDifferentUserId => consts::SOCKS4_RESULT_REQUEST_REJECTED_DFFERENT_USER_ID, + ResultCode::Other(c) => c, + } + } + + #[inline] + fn from_u8(code: u8) -> ResultCode { + match code { + consts::SOCKS4_RESULT_REQUEST_GRANTED => ResultCode::RequestGranted, + consts::SOCKS4_RESULT_REQUEST_REJECTED_OR_FAILED => ResultCode::RequestRejectedOrFailed, + consts::SOCKS4_RESULT_REQUEST_REJECTED_CANNOT_CONNECT => ResultCode::RequestRejectedCannotConnect, + consts::SOCKS4_RESULT_REQUEST_REJECTED_DFFERENT_USER_ID => ResultCode::RequestRejectedDifferentUserId, + code => ResultCode::Other(code), + } + } +} + +impl fmt::Display for ResultCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + ResultCode::RequestGranted => f.write_str("request granted"), + ResultCode::RequestRejectedOrFailed => f.write_str("request rejected or failed"), + ResultCode::RequestRejectedCannotConnect => { + f.write_str("request rejected becasue SOCKS server cannot connect to identd on the client") + } + ResultCode::RequestRejectedDifferentUserId => { + f.write_str("request rejected because the client program and identd report different user-ids") + } + ResultCode::Other(code) => write!(f, "other result code {}", code), + } + } +} + +/// SOCKS4 Address type +#[derive(Clone, PartialEq, Eq, Hash)] +pub enum Address { + /// Socket address (IP Address) + SocketAddress(SocketAddrV4), + /// Domain name address + DomainNameAddress(String, u16), +} + +impl fmt::Debug for Address { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Address::SocketAddress(ref addr) => write!(f, "{}", addr), + Address::DomainNameAddress(ref addr, ref port) => write!(f, "{}:{}", addr, port), + } + } +} + +impl fmt::Display for Address { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Address::SocketAddress(ref addr) => write!(f, "{}", addr), + Address::DomainNameAddress(ref addr, ref port) => write!(f, "{}:{}", addr, port), + } + } +} + +impl From for Address { + fn from(s: SocketAddrV4) -> Address { + Address::SocketAddress(s) + } +} + +impl From<(String, u16)> for Address { + fn from((dn, port): (String, u16)) -> Address { + Address::DomainNameAddress(dn, port) + } +} + +impl From<&Address> for Address { + fn from(addr: &Address) -> Address { + addr.clone() + } +} + +impl From
for socks5::Address { + fn from(addr: Address) -> socks5::Address { + match addr { + Address::SocketAddress(a) => socks5::Address::SocketAddress(SocketAddr::V4(a)), + Address::DomainNameAddress(d, p) => socks5::Address::DomainNameAddress(d, p), + } + } +} + +/// Handshake Request +/// +/// ```plain +/// The client connects to the SOCKS server and sends a CONNECT/BIND request when +/// it wants to establish a connection to an application server. The client +/// includes in the request packet the IP address and the port number of the +/// destination host, and userid, in the following format. +/// +/// +----+----+----+----+----+----+----+----+----+----+....+----+ +/// | VN | CD | DSTPORT | DSTIP | USERID |NULL| +/// +----+----+----+----+----+----+----+----+----+----+....+----+ +/// # of bytes: 1 1 2 4 variable 1 +/// +/// VN is the SOCKS protocol version number and should be 4. CD is the +/// SOCKS command code and should be 1 for CONNECT request, 2 for BIND request. NULL is a byte +/// of all zero bits. +/// ``` +#[derive(Debug, Clone)] +pub struct HandshakeRequest { + pub cd: Command, + pub dst: Address, + pub user_id: Vec, +} + +impl HandshakeRequest { + /// Read from a reader + pub async fn read_from(r: &mut R) -> io::Result + where + R: AsyncBufRead + Unpin, + { + let mut buf = [0u8; 8]; + let _ = r.read_exact(&mut buf).await?; + + let vn = buf[0]; + if vn != consts::SOCKS4_VERSION { + let err = Error::new(ErrorKind::InvalidData, format!("unsupported socks version {:#x}", vn)); + return Err(err); + } + + let cd = buf[1]; + let command = match Command::from_u8(cd) { + Some(c) => c, + None => { + let err = Error::new(ErrorKind::InvalidData, format!("unsupported command {:#x}", cd)); + return Err(err); + } + }; + + let port = BigEndian::read_u16(&buf[2..4]); + + let mut user_id = Vec::new(); + let _ = r.read_until(b'\0', &mut user_id).await?; + if user_id.is_empty() || user_id.last() != Some(&b'\0') { + return Err(ErrorKind::UnexpectedEof.into()); + } + user_id.pop(); // Pops the last b'\0' + + let dst = if buf[4] == 0x00 && buf[5] == 0x00 && buf[6] == 0x00 && buf[7] != 0x00 { + // SOCKS4a, indicates that it is a HOST address + let mut host = Vec::new(); + let _ = r.read_until(b'\0', &mut host).await?; + if host.is_empty() || host.last() != Some(&b'\0') { + return Err(ErrorKind::UnexpectedEof.into()); + } + host.pop(); // Pops the last b'\0' + + match String::from_utf8(host) { + Ok(host) => Address::DomainNameAddress(host, port), + Err(..) => { + let err = Error::new(ErrorKind::InvalidData, "invalid host encoding"); + return Err(err); + } + } + } else { + let ip = Ipv4Addr::new(buf[4], buf[5], buf[6], buf[7]); + Address::SocketAddress(SocketAddrV4::new(ip, port)) + }; + + Ok(HandshakeRequest { + cd: command, + dst, + user_id, + }) + } + + /// Writes to buffer + pub fn write_to_buf(&self, buf: &mut B) { + debug_assert!( + !self.user_id.contains(&b'\0'), + "USERID shouldn't contain any NULL characters" + ); + + buf.put_u8(consts::SOCKS4_VERSION); + buf.put_u8(self.cd.as_u8()); + match self.dst { + Address::SocketAddress(ref saddr) => { + let port = saddr.port(); + buf.put_u16(port); + buf.put_slice(&saddr.ip().octets()); + + buf.put_slice(&self.user_id); + buf.put_u8(b'\0'); + } + Address::DomainNameAddress(ref dname, port) => { + buf.put_u16(port); + + // 0.0.0.x (x != 0) + const PLACEHOLDER: [u8; 4] = [0x00, 0x00, 0x00, 0xff]; + buf.put_slice(&PLACEHOLDER); + + buf.put_slice(&self.user_id); + buf.put_u8(b'\0'); + + buf.put_slice(dname.as_bytes()); + buf.put_u8(b'\0'); + } + } + } + + /// Length in bytes + #[inline] + pub fn serialized_len(&self) -> usize { + let mut s = 1 + 1 + 2 + 4 + self.user_id.len() + 1; // USERID.LEN + NULL + if let Address::DomainNameAddress(ref dname, _) = self.dst { + s += dname.len() + 1; + } + s + } +} + +/// Handshake Response +/// +/// ```plain +/// +----+----+----+----+----+----+----+----+ +/// | VN | CD | DSTPORT | DSTIP | +/// +----+----+----+----+----+----+----+----+ +/// # of bytes: 1 1 2 4 +/// ``` +#[derive(Debug, Clone)] +pub struct HandshakeResponse { + pub cd: ResultCode, +} + +impl HandshakeResponse { + /// Create a response with code + pub fn new(code: ResultCode) -> HandshakeResponse { + HandshakeResponse { cd: code } + } + + /// Read from a reader + pub async fn read_from(r: &mut R) -> io::Result + where + R: AsyncRead + Unpin, + { + let mut buf = [0u8; 8]; + let _ = r.read_exact(&mut buf).await?; + + let vn = buf[0]; + if vn != consts::SOCKS4_VERSION { + let err = Error::new(ErrorKind::InvalidData, format!("unsupported socks version {:#x}", vn)); + return Err(err); + } + + let cd = buf[1]; + let result_code = ResultCode::from_u8(cd); + + // DSTPORT, DSTIP are ignored + + Ok(HandshakeResponse { cd: result_code }) + } + + /// Write data into a writer + pub async fn write_to(&self, w: &mut W) -> io::Result<()> + where + W: AsyncWrite + Unpin, + { + let mut buf = BytesMut::with_capacity(self.serialized_len()); + self.write_to_buf(&mut buf); + w.write_all(&buf).await + } + + /// Writes to buffer + pub fn write_to_buf(&self, buf: &mut B) { + let HandshakeResponse { ref cd } = *self; + + buf.put_slice(&[ + // VN: Result Code's version, must be 0 + 0x00, + // CD: Result Code + cd.as_u8(), + // DSTPORT: Ignored + 0x00, + 0x00, + // DSTIP: Ignored + 0x00, + 0x00, + 0x00, + 0x00, + ]); + } + + /// Length in bytes + #[inline] + pub fn serialized_len(&self) -> usize { + 1 + 1 + 2 + 4 + } +} diff --git a/src/relay/tcprelay/local.rs b/src/relay/tcprelay/local.rs index ebef5f02..6a1a7907 100644 --- a/src/relay/tcprelay/local.rs +++ b/src/relay/tcprelay/local.rs @@ -7,9 +7,11 @@ use crate::{config::ConfigType, context::SharedContext}; /// Starts a TCP local server pub async fn run(context: SharedContext) -> io::Result<()> { match context.config().config_type { + ConfigType::Socks5Local => super::socks5_local::run(context).await, + #[cfg(feature = "local-socks4")] + ConfigType::Socks4Local => super::socks4_local::run(context).await, #[cfg(feature = "local-tunnel")] ConfigType::TunnelLocal => super::tunnel_local::run(context).await, - ConfigType::Socks5Local => super::socks5_local::run(context).await, #[cfg(feature = "local-http")] ConfigType::HttpLocal => super::http_local::run(context).await, #[cfg(feature = "local-redir")] diff --git a/src/relay/tcprelay/mod.rs b/src/relay/tcprelay/mod.rs index 06f3f2b9..253ebcfd 100644 --- a/src/relay/tcprelay/mod.rs +++ b/src/relay/tcprelay/mod.rs @@ -27,6 +27,7 @@ mod redir; #[cfg(feature = "local-redir")] mod redir_local; pub mod server; +mod socks4_local; mod socks5_local; mod stream; #[cfg(feature = "local-tunnel")] diff --git a/src/relay/tcprelay/proxy_stream.rs b/src/relay/tcprelay/proxy_stream.rs index f6d80617..0b22cae1 100644 --- a/src/relay/tcprelay/proxy_stream.rs +++ b/src/relay/tcprelay/proxy_stream.rs @@ -463,6 +463,8 @@ async fn connect_proxy_server(context: &Context, svr_cfg: &ServerConfig) -> io:: ConfigType::Server => svr_cfg.addr(), ConfigType::Socks5Local => svr_cfg.external_addr(), + #[cfg(feature = "local-socks4")] + ConfigType::Socks4Local => svr_cfg.external_addr(), #[cfg(feature = "local-tunnel")] ConfigType::TunnelLocal => svr_cfg.external_addr(), #[cfg(feature = "local-dns-relay")] diff --git a/src/relay/tcprelay/socks4_local.rs b/src/relay/tcprelay/socks4_local.rs new file mode 100644 index 00000000..f7562f32 --- /dev/null +++ b/src/relay/tcprelay/socks4_local.rs @@ -0,0 +1,181 @@ +//! Local server that accepts SOCKS4 protocol + +use std::{ + io::{self, ErrorKind}, + net::SocketAddr, +}; + +use futures::future::{self, Either}; +use log::{debug, error, info, trace, warn}; +use tokio::{ + io::{AsyncWriteExt, BufReader}, + net::{TcpListener, TcpStream}, +}; + +use crate::{ + context::SharedContext, + relay::{ + loadbalancing::server::{PlainPingBalancer, ServerType, SharedPlainServerStatistic}, + socks4::{Address, Command, HandshakeRequest, HandshakeResponse, ResultCode}, + tcprelay::ProxyStream, + }, +}; + +async fn handle_socks4_connect( + server: &SharedPlainServerStatistic, + mut stream: BufReader, + client_addr: SocketAddr, + addr: &Address, +) -> io::Result<()> { + let context = server.context(); + let svr_cfg = server.server_config(); + + // NOTE: Shadowsocks server uses SOCKS5 Address + let ss_addr = From::from(addr.clone()); + + let mut svr_s = match ProxyStream::connect(server.clone_context(), svr_cfg, &ss_addr).await { + Ok(svr_s) => { + // Tell the client that we are ready + let handshake_rsp = HandshakeResponse::new(ResultCode::RequestGranted); + handshake_rsp.write_to(&mut stream).await?; + + trace!("sent header: {:?}", handshake_rsp); + + svr_s + } + Err(perr) => { + if perr.is_proxied() { + // Report to global statistic + server.report_failure().await; + } + + let err = perr.into_inner(); + let result_code = match err.kind() { + ErrorKind::ConnectionRefused => ResultCode::RequestRejectedCannotConnect, + ErrorKind::ConnectionAborted => ResultCode::RequestRejectedCannotConnect, + _ => ResultCode::RequestRejectedOrFailed, + }; + + let handshake_rsp = HandshakeResponse::new(result_code); + handshake_rsp.write_to(&mut stream).await?; + + return Err(err); + } + }; + + // NOTE: Transfer all buffered data before unwrap, or these data will be lost + let buffer = stream.buffer(); + if !buffer.is_empty() { + svr_s.write_all(buffer).await?; + } + + // UNWRAP. + let mut stream = stream.into_inner(); + + // Reset `TCP_NODELAY` after Socks5 handshake + if !context.config().no_delay { + if let Err(err) = stream.set_nodelay(false) { + error!("failed to reset TCP_NODELAY on socket, error: {:?}", err); + } + } + + let (mut svr_r, mut svr_w) = svr_s.split(); + let (mut r, mut w) = stream.split(); + + use tokio::io::copy; + + let rhalf = copy(&mut r, &mut svr_w); + let whalf = copy(&mut svr_r, &mut w); + + debug!("CONNECT relay established {} <-> {}", client_addr, addr); + + match future::select(rhalf, whalf).await { + Either::Left((Ok(..), _)) => trace!("CONNECT relay {} -> {} closed", client_addr, addr), + Either::Left((Err(err), _)) => { + if let ErrorKind::TimedOut = err.kind() { + trace!("CONNECT relay {} -> {} closed with error {}", client_addr, addr, err); + } else { + error!("CONNECT relay {} -> {} closed with error {}", client_addr, addr, err); + } + } + Either::Right((Ok(..), _)) => trace!("CONNECT relay {} <- {} closed", client_addr, addr), + Either::Right((Err(err), _)) => { + if let ErrorKind::TimedOut = err.kind() { + trace!("CONNECT relay {} <- {} closed with error {}", client_addr, addr, err); + } else { + error!("CONNECT relay {} <- {} closed with error {}", client_addr, addr, err); + } + } + } + + debug!("CONNECT relay {} <-> {} closed", client_addr, addr); + + Ok(()) +} + +async fn handle_socks4_client(server: &SharedPlainServerStatistic, s: TcpStream) -> io::Result<()> { + let svr_cfg = server.server_config(); + + if let Err(err) = s.set_keepalive(svr_cfg.timeout()) { + error!("failed to set keep alive: {:?}", err); + } + + // Enable TCP_NODELAY for quick handshaking + if let Err(err) = s.set_nodelay(true) { + error!("failed to set TCP_NODELAY on accepted socket, error: {:?}", err); + } + + let client_addr = s.peer_addr()?; + + // NOTE: Wraps it with BufReader for reading NULL terminated informations in HandshakeRequest + let mut s = BufReader::new(s); + let handshake_req = HandshakeRequest::read_from(&mut s).await?; + + trace!("socks4 {:?}", handshake_req); + + match handshake_req.cd { + Command::Connect => { + debug!("CONNECT {}", handshake_req.dst); + + handle_socks4_connect(server, s, client_addr, &handshake_req.dst).await + } + Command::Bind => { + warn!("BIND is not supported"); + + let handshake_rsp = HandshakeResponse::new(ResultCode::RequestRejectedOrFailed); + handshake_rsp.write_to(&mut s).await?; + + Ok(()) + } + } +} + +/// Starts a TCP local server with Socks4 proxy protocol +pub async fn run(context: SharedContext) -> io::Result<()> { + let local_addr = context.config().local_addr.as_ref().expect("local config"); + let bind_addr = local_addr.bind_addr(&context).await?; + + let mut listener = TcpListener::bind(&bind_addr) + .await + .unwrap_or_else(|err| panic!("failed to listen on {}, {}", local_addr, err)); + + let actual_local_addr = listener.local_addr().expect("determine port bound to"); + + let servers = PlainPingBalancer::new(context, ServerType::Tcp).await; + + info!("shadowsocks TCP listening on {}", actual_local_addr); + + loop { + let (socket, peer_addr) = listener.accept().await?; + let server = servers.pick_server(); + + trace!("got connection {}", peer_addr); + trace!("picked proxy server: {:?}", server.server_config()); + + tokio::spawn(async move { + if let Err(err) = handle_socks4_client(&server, socket).await { + error!("TCP socks4 client exited with error: {}", err); + } + }); + } +} diff --git a/src/relay/tcprelay/socks5_local.rs b/src/relay/tcprelay/socks5_local.rs index 17fab786..a68728a3 100644 --- a/src/relay/tcprelay/socks5_local.rs +++ b/src/relay/tcprelay/socks5_local.rs @@ -1,4 +1,4 @@ -//! Local server that accepts SOCKS 5 protocol +//! Local server that accepts SOCKS5 protocol use std::{ io::{self, ErrorKind}, @@ -28,7 +28,7 @@ struct UdpConfig { client_addr: SocketAddr, } -async fn handle_socks5_connect<'a>( +async fn handle_socks5_connect( server: &SharedPlainServerStatistic, stream: &mut TcpStream, client_addr: SocketAddr, @@ -86,7 +86,7 @@ async fn handle_socks5_connect<'a>( let rhalf = copy(&mut r, &mut svr_w); let whalf = copy(&mut svr_r, &mut w); - debug!("CONNECT relay established {} <-> {}", client_addr, addr,); + debug!("CONNECT relay established {} <-> {}", client_addr, addr); match future::select(rhalf, whalf).await { Either::Left((Ok(..), _)) => trace!("CONNECT relay {} -> {} closed", client_addr, addr), diff --git a/src/relay/udprelay/local.rs b/src/relay/udprelay/local.rs index a6ae07b8..147b906b 100644 --- a/src/relay/udprelay/local.rs +++ b/src/relay/udprelay/local.rs @@ -20,9 +20,11 @@ pub async fn run(context: SharedContext) -> io::Result<()> { } match context.config().config_type { + ConfigType::Socks5Local => super::socks5_local::run(context).await, + #[cfg(feature = "local-socks4")] + ConfigType::Socks4Local => unreachable!(), #[cfg(feature = "local-tunnel")] ConfigType::TunnelLocal => super::tunnel_local::run(context).await, - ConfigType::Socks5Local => super::socks5_local::run(context).await, #[cfg(feature = "local-redir")] ConfigType::RedirLocal => super::redir_local::run(context).await, #[cfg(feature = "local-http")]