mirror of
https://github.com/quintusl/rust-socksd.git
synced 2026-11-13 16:17:46 +00:00
Put user accounts to separated config file.
This commit is contained in:
Generated
+444
-1
@@ -26,6 +26,21 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
@@ -82,6 +97,18 @@ version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
|
||||
[[package]]
|
||||
name = "argon2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"blake2",
|
||||
"cpufeatures",
|
||||
"password-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.6"
|
||||
@@ -142,24 +169,123 @@ version = "0.21.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3"
|
||||
|
||||
[[package]]
|
||||
name = "bcrypt"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e65938ed058ef47d92cf8b346cc76ef48984572ade631927e9937b5ffc7662c7"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"blowfish",
|
||||
"getrandom",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
|
||||
[[package]]
|
||||
name = "blake2"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blowfish"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.38"
|
||||
@@ -206,6 +332,21 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.15"
|
||||
@@ -221,6 +362,16 @@ version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.9.0"
|
||||
@@ -236,6 +387,17 @@ dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
@@ -363,6 +525,16 @@ dependencies = [
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.16"
|
||||
@@ -392,6 +564,39 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "2.0.0"
|
||||
@@ -519,6 +724,15 @@ dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipconfig"
|
||||
version = "0.3.2"
|
||||
@@ -549,6 +763,16 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
@@ -649,6 +873,15 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
@@ -699,6 +932,27 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "password-hash"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pbkdf2"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"hmac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
@@ -854,17 +1108,27 @@ version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
||||
|
||||
[[package]]
|
||||
name = "rusty-socks"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
"async-trait",
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
"bcrypt",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"clap",
|
||||
"futures",
|
||||
"rand",
|
||||
"scrypt",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"socket2",
|
||||
@@ -884,12 +1148,33 @@ version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "salsa20"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "scrypt"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f"
|
||||
dependencies = [
|
||||
"password-hash",
|
||||
"pbkdf2",
|
||||
"salsa20",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
@@ -923,6 +1208,17 @@ dependencies = [
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
@@ -932,6 +1228,12 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.5"
|
||||
@@ -978,6 +1280,12 @@ version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.101"
|
||||
@@ -1271,6 +1579,12 @@ dependencies = [
|
||||
"trust-dns-proto",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.18"
|
||||
@@ -1327,12 +1641,76 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "1.2.0"
|
||||
@@ -1361,6 +1739,65 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
@@ -1590,6 +2027,12 @@ dependencies = [
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||
|
||||
[[package]]
|
||||
name = "zerotrie"
|
||||
version = "0.2.2"
|
||||
|
||||
@@ -27,6 +27,10 @@ trust-dns-resolver = "0.23"
|
||||
base64 = "0.21"
|
||||
futures = "0.3"
|
||||
rand = "0.8"
|
||||
argon2 = "0.5"
|
||||
bcrypt = "0.15"
|
||||
scrypt = "0.11"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio-test = "0.4"
|
||||
|
||||
+2
-6
@@ -28,12 +28,8 @@ auth:
|
||||
# Authentication method: "none" or "username_password"
|
||||
method: "none"
|
||||
|
||||
# User credentials (only used if auth is enabled)
|
||||
users:
|
||||
- username: "user1"
|
||||
password: "password1"
|
||||
- username: "admin"
|
||||
password: "secure_password"
|
||||
# Path to user configuration file (required if auth is enabled)
|
||||
user_config_file: "users.yml"
|
||||
|
||||
# Logging configuration
|
||||
logging:
|
||||
|
||||
+38
-35
@@ -4,6 +4,9 @@ use std::net::SocketAddr;
|
||||
use std::path::Path;
|
||||
use tracing::info;
|
||||
|
||||
mod user_config;
|
||||
pub use user_config::{UserConfig, HashType};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
pub server: ServerConfig,
|
||||
@@ -26,7 +29,7 @@ pub struct ServerConfig {
|
||||
pub struct AuthConfig {
|
||||
pub enabled: bool,
|
||||
pub method: AuthMethod,
|
||||
pub users: Vec<UserCredentials>,
|
||||
pub user_config_file: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -37,11 +40,6 @@ pub enum AuthMethod {
|
||||
UsernamePassword,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UserCredentials {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct LoggingConfig {
|
||||
@@ -78,7 +76,7 @@ impl Default for Config {
|
||||
auth: AuthConfig {
|
||||
enabled: false,
|
||||
method: AuthMethod::None,
|
||||
users: vec![],
|
||||
user_config_file: None,
|
||||
},
|
||||
logging: LoggingConfig {
|
||||
level: "info".to_string(),
|
||||
@@ -103,78 +101,83 @@ impl Config {
|
||||
info!("Configuration loaded successfully");
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
|
||||
pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||
let content = serde_yaml::to_string(self)?;
|
||||
std::fs::write(path, content)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn validate(&self) -> Result<()> {
|
||||
if self.server.socks5_port == 0 {
|
||||
return Err(anyhow!("Invalid SOCKS5 port: {}", self.server.socks5_port));
|
||||
}
|
||||
|
||||
|
||||
if self.server.http_port == 0 {
|
||||
return Err(anyhow!("Invalid HTTP port: {}", self.server.http_port));
|
||||
}
|
||||
|
||||
|
||||
if self.server.socks5_port == self.server.http_port {
|
||||
return Err(anyhow!("SOCKS5 and HTTP ports cannot be the same"));
|
||||
}
|
||||
|
||||
|
||||
self.server.bind_address.parse::<std::net::IpAddr>()
|
||||
.map_err(|_| anyhow!("Invalid bind address: {}", self.server.bind_address))?;
|
||||
|
||||
|
||||
if self.server.max_connections == 0 {
|
||||
return Err(anyhow!("Max connections must be greater than 0"));
|
||||
}
|
||||
|
||||
|
||||
if self.server.buffer_size < 1024 {
|
||||
return Err(anyhow!("Buffer size must be at least 1024 bytes"));
|
||||
}
|
||||
|
||||
if self.auth.enabled && self.auth.users.is_empty() {
|
||||
return Err(anyhow!("Authentication enabled but no users configured"));
|
||||
|
||||
if self.auth.enabled && self.auth.user_config_file.is_none() {
|
||||
return Err(anyhow!("Authentication enabled but no user config file specified"));
|
||||
}
|
||||
|
||||
for user in &self.auth.users {
|
||||
if user.username.is_empty() || user.password.is_empty() {
|
||||
return Err(anyhow!("Username and password cannot be empty"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for network in &self.security.allowed_networks {
|
||||
if !network.contains('/') {
|
||||
network.parse::<std::net::IpAddr>()
|
||||
.map_err(|_| anyhow!("Invalid network address: {}", network))?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if !["trace", "debug", "info", "warn", "error"].contains(&self.logging.level.as_str()) {
|
||||
return Err(anyhow!("Invalid log level: {}", self.logging.level));
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn socks5_bind_addr(&self) -> Result<SocketAddr> {
|
||||
let addr = format!("{}:{}", self.server.bind_address, self.server.socks5_port);
|
||||
addr.parse().map_err(|e| anyhow!("Failed to parse SOCKS5 bind address: {}", e))
|
||||
}
|
||||
|
||||
|
||||
pub fn http_bind_addr(&self) -> Result<SocketAddr> {
|
||||
let addr = format!("{}:{}", self.server.bind_address, self.server.http_port);
|
||||
addr.parse().map_err(|e| anyhow!("Failed to parse HTTP bind address: {}", e))
|
||||
}
|
||||
|
||||
pub fn validate_user(&self, username: &str, password: &str) -> bool {
|
||||
|
||||
pub fn validate_user(&self, username: &str, password: &str) -> Result<bool> {
|
||||
if !self.auth.enabled {
|
||||
return true;
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Some(user_config_path) = &self.auth.user_config_file {
|
||||
let user_config = UserConfig::load_from_file(user_config_path)?;
|
||||
Ok(user_config.verify_password(username, password))
|
||||
} else {
|
||||
Err(anyhow!("Authentication enabled but no user config file specified"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_user_config(&self) -> Result<Option<UserConfig>> {
|
||||
if let Some(user_config_path) = &self.auth.user_config_file {
|
||||
Ok(Some(UserConfig::load_from_file(user_config_path)?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
self.auth.users.iter().any(|user| {
|
||||
user.username == username && user.password == password
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use argon2::{PasswordHash, PasswordHasher, PasswordVerifier};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UserConfig {
|
||||
pub hash_type: HashType,
|
||||
pub users: HashMap<String, UserEntry>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum HashType {
|
||||
#[serde(rename = "argon2")]
|
||||
Argon2,
|
||||
#[serde(rename = "bcrypt")]
|
||||
Bcrypt,
|
||||
#[serde(rename = "scrypt")]
|
||||
Scrypt,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UserEntry {
|
||||
pub password_hash: String,
|
||||
pub salt: Option<String>,
|
||||
pub created_at: String,
|
||||
pub last_modified: String,
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
impl Default for UserConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
hash_type: HashType::Argon2,
|
||||
users: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UserConfig {
|
||||
pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
let config: UserConfig = serde_yaml::from_str(&content)?;
|
||||
config.validate()?;
|
||||
info!("User configuration loaded successfully");
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||
let content = serde_yaml::to_string(self)?;
|
||||
std::fs::write(path, content)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> Result<()> {
|
||||
for (username, user) in &self.users {
|
||||
if username.is_empty() {
|
||||
return Err(anyhow!("Username cannot be empty"));
|
||||
}
|
||||
if user.password_hash.is_empty() {
|
||||
return Err(anyhow!("Password hash cannot be empty for user: {}", username));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_user(&mut self, username: String, password: &str) -> Result<()> {
|
||||
if self.users.contains_key(&username) {
|
||||
return Err(anyhow!("User already exists: {}", username));
|
||||
}
|
||||
|
||||
let (password_hash, salt) = self.hash_password(password)?;
|
||||
let now = chrono::Utc::now().to_rfc3339();
|
||||
|
||||
let user_entry = UserEntry {
|
||||
password_hash,
|
||||
salt,
|
||||
created_at: now.clone(),
|
||||
last_modified: now,
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
self.users.insert(username, user_entry);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_user(&mut self, username: &str) -> Result<()> {
|
||||
if !self.users.contains_key(username) {
|
||||
return Err(anyhow!("User not found: {}", username));
|
||||
}
|
||||
self.users.remove(username);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_password(&mut self, username: &str, new_password: &str) -> Result<()> {
|
||||
let (password_hash, salt) = self.hash_password(new_password)?;
|
||||
|
||||
let user = self.users.get_mut(username)
|
||||
.ok_or_else(|| anyhow!("User not found: {}", username))?;
|
||||
|
||||
user.password_hash = password_hash;
|
||||
user.salt = salt;
|
||||
user.last_modified = chrono::Utc::now().to_rfc3339();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enable_user(&mut self, username: &str, enabled: bool) -> Result<()> {
|
||||
let user = self.users.get_mut(username)
|
||||
.ok_or_else(|| anyhow!("User not found: {}", username))?;
|
||||
|
||||
user.enabled = enabled;
|
||||
user.last_modified = chrono::Utc::now().to_rfc3339();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn verify_password(&self, username: &str, password: &str) -> bool {
|
||||
if let Some(user) = self.users.get(username) {
|
||||
if !user.enabled {
|
||||
return false;
|
||||
}
|
||||
|
||||
match self.hash_type {
|
||||
HashType::Argon2 => self.verify_argon2_password(password, &user.password_hash),
|
||||
HashType::Bcrypt => self.verify_bcrypt_password(password, &user.password_hash),
|
||||
HashType::Scrypt => self.verify_scrypt_password(password, &user.password_hash, &user.salt),
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_password(&self, password: &str) -> Result<(String, Option<String>)> {
|
||||
match self.hash_type {
|
||||
HashType::Argon2 => self.hash_argon2_password(password),
|
||||
HashType::Bcrypt => self.hash_bcrypt_password(password),
|
||||
HashType::Scrypt => self.hash_scrypt_password(password),
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_argon2_password(&self, password: &str) -> Result<(String, Option<String>)> {
|
||||
use argon2::Argon2;
|
||||
use argon2::password_hash::{SaltString, rand_core::OsRng};
|
||||
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let argon2 = Argon2::default();
|
||||
let password_hash = argon2.hash_password(password.as_bytes(), &salt)
|
||||
.map_err(|e| anyhow!("Failed to hash password: {}", e))?;
|
||||
|
||||
Ok((password_hash.to_string(), None))
|
||||
}
|
||||
|
||||
fn verify_argon2_password(&self, password: &str, hash: &str) -> bool {
|
||||
use argon2::Argon2;
|
||||
|
||||
if let Ok(parsed_hash) = PasswordHash::new(hash) {
|
||||
Argon2::default().verify_password(password.as_bytes(), &parsed_hash).is_ok()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_bcrypt_password(&self, password: &str) -> Result<(String, Option<String>)> {
|
||||
use bcrypt::{hash, DEFAULT_COST};
|
||||
|
||||
let hash = hash(password, DEFAULT_COST)
|
||||
.map_err(|e| anyhow!("Failed to hash password: {}", e))?;
|
||||
|
||||
Ok((hash, None))
|
||||
}
|
||||
|
||||
fn verify_bcrypt_password(&self, password: &str, hash: &str) -> bool {
|
||||
use bcrypt::verify;
|
||||
verify(password, hash).unwrap_or(false)
|
||||
}
|
||||
|
||||
fn hash_scrypt_password(&self, password: &str) -> Result<(String, Option<String>)> {
|
||||
use scrypt::Scrypt;
|
||||
use scrypt::password_hash::{SaltString, rand_core::OsRng};
|
||||
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let password_hash = Scrypt.hash_password(password.as_bytes(), &salt)
|
||||
.map_err(|e| anyhow!("Failed to hash password: {}", e))?;
|
||||
|
||||
Ok((password_hash.to_string(), Some(salt.to_string())))
|
||||
}
|
||||
|
||||
fn verify_scrypt_password(&self, password: &str, hash: &str, _salt: &Option<String>) -> bool {
|
||||
use scrypt::Scrypt;
|
||||
|
||||
if let Ok(parsed_hash) = PasswordHash::new(hash) {
|
||||
Scrypt.verify_password(password.as_bytes(), &parsed_hash).is_ok()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,5 +3,5 @@ pub mod http_proxy;
|
||||
pub mod server;
|
||||
pub mod socks5;
|
||||
|
||||
pub use config::Config;
|
||||
pub use config::{Config, UserConfig, HashType};
|
||||
pub use server::ProxyServer;
|
||||
+250
-13
@@ -1,6 +1,7 @@
|
||||
use anyhow::Result;
|
||||
use clap::{Arg, Command};
|
||||
use rusty_socks::{Config, ProxyServer};
|
||||
use clap::{Arg, Command, ArgMatches};
|
||||
use rusty_socks::{Config, ProxyServer, UserConfig, HashType};
|
||||
use std::io::{self, Write};
|
||||
use tracing::{error, info, Level};
|
||||
use tracing_appender::non_blocking::WorkerGuard;
|
||||
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
|
||||
@@ -43,6 +44,95 @@ async fn main() -> Result<()> {
|
||||
.help("Suppress all output except errors")
|
||||
.conflicts_with("verbose"),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("user")
|
||||
.about("User management commands")
|
||||
.arg(
|
||||
Arg::new("user-config")
|
||||
.long("user-config")
|
||||
.value_name("FILE")
|
||||
.help("User configuration file path")
|
||||
.default_value("users.yml"),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("add")
|
||||
.about("Add a new user")
|
||||
.arg(
|
||||
Arg::new("username")
|
||||
.help("Username")
|
||||
.required(true)
|
||||
.index(1),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("password")
|
||||
.help("Password (will prompt if not provided)")
|
||||
.index(2),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("hash-type")
|
||||
.long("hash-type")
|
||||
.value_name("TYPE")
|
||||
.help("Password hash type: argon2, bcrypt, scrypt")
|
||||
.default_value("argon2"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("remove")
|
||||
.about("Remove a user")
|
||||
.arg(
|
||||
Arg::new("username")
|
||||
.help("Username to remove")
|
||||
.required(true)
|
||||
.index(1),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("list")
|
||||
.about("List all users"),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("update")
|
||||
.about("Update user password")
|
||||
.arg(
|
||||
Arg::new("username")
|
||||
.help("Username")
|
||||
.required(true)
|
||||
.index(1),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("password")
|
||||
.help("New password (will prompt if not provided)")
|
||||
.index(2),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("enable")
|
||||
.about("Enable/disable a user")
|
||||
.arg(
|
||||
Arg::new("username")
|
||||
.help("Username")
|
||||
.required(true)
|
||||
.index(1),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("enabled")
|
||||
.help("Enable (true) or disable (false)")
|
||||
.required(true)
|
||||
.index(2),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("init")
|
||||
.about("Initialize a new user configuration file")
|
||||
.arg(
|
||||
Arg::new("hash-type")
|
||||
.long("hash-type")
|
||||
.value_name("TYPE")
|
||||
.help("Default password hash type: argon2, bcrypt, scrypt")
|
||||
.default_value("argon2"),
|
||||
),
|
||||
),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
if let Some(config_path) = matches.get_one::<String>("generate-config") {
|
||||
@@ -50,8 +140,13 @@ async fn main() -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(user_matches) = matches.subcommand_matches("user") {
|
||||
handle_user_command(user_matches)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let config_path = matches.get_one::<String>("config").unwrap();
|
||||
|
||||
|
||||
let config = if std::path::Path::new(config_path).exists() {
|
||||
match Config::load_from_file(config_path) {
|
||||
Ok(config) => config,
|
||||
@@ -62,7 +157,7 @@ async fn main() -> Result<()> {
|
||||
};
|
||||
|
||||
let _guard = setup_logging(&config, &matches);
|
||||
|
||||
|
||||
if std::path::Path::new(config_path).exists() {
|
||||
match Config::load_from_file(config_path) {
|
||||
Ok(_) => {
|
||||
@@ -82,7 +177,7 @@ async fn main() -> Result<()> {
|
||||
info!("HTTP proxy will listen on {}:{}", config.server.bind_address, config.server.http_port);
|
||||
|
||||
let server = ProxyServer::new(config);
|
||||
|
||||
|
||||
if let Err(e) = server.start().await {
|
||||
error!("Server error: {}", e);
|
||||
std::process::exit(1);
|
||||
@@ -94,10 +189,10 @@ async fn main() -> Result<()> {
|
||||
fn generate_default_config(path: &str) -> Result<()> {
|
||||
let config = Config::default();
|
||||
config.save_to_file(path)?;
|
||||
|
||||
|
||||
println!("Generated default configuration file: {}", path);
|
||||
println!("Edit this file to customize your proxy server settings.");
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -121,7 +216,7 @@ fn setup_logging(config: &Config, matches: &clap::ArgMatches) -> Option<WorkerGu
|
||||
|
||||
let filter = EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| EnvFilter::new(log_level.to_string()));
|
||||
|
||||
|
||||
let registry = tracing_subscriber::registry().with(filter);
|
||||
|
||||
match (&config.logging.file, config.logging.console) {
|
||||
@@ -131,12 +226,12 @@ fn setup_logging(config: &Config, matches: &clap::ArgMatches) -> Option<WorkerGu
|
||||
std::path::Path::new(log_file).file_name().unwrap()
|
||||
);
|
||||
let (non_blocking_file, guard) = tracing_appender::non_blocking(file_appender);
|
||||
|
||||
|
||||
registry
|
||||
.with(fmt::layer().with_writer(std::io::stdout))
|
||||
.with(fmt::layer().with_writer(non_blocking_file).with_ansi(false))
|
||||
.init();
|
||||
Some(guard)
|
||||
Some(guard)
|
||||
},
|
||||
(Some(log_file), false) => {
|
||||
let file_appender = tracing_appender::rolling::never(
|
||||
@@ -144,11 +239,11 @@ fn setup_logging(config: &Config, matches: &clap::ArgMatches) -> Option<WorkerGu
|
||||
std::path::Path::new(log_file).file_name().unwrap()
|
||||
);
|
||||
let (non_blocking_file, guard) = tracing_appender::non_blocking(file_appender);
|
||||
|
||||
|
||||
registry
|
||||
.with(fmt::layer().with_writer(non_blocking_file).with_ansi(false))
|
||||
.init();
|
||||
Some(guard)
|
||||
Some(guard)
|
||||
},
|
||||
(None, true) => {
|
||||
registry
|
||||
@@ -157,7 +252,149 @@ fn setup_logging(config: &Config, matches: &clap::ArgMatches) -> Option<WorkerGu
|
||||
None
|
||||
},
|
||||
(None, false) => {
|
||||
None
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_user_command(matches: &ArgMatches) -> Result<()> {
|
||||
let user_config_path = matches.get_one::<String>("user-config").unwrap();
|
||||
|
||||
match matches.subcommand() {
|
||||
Some(("init", sub_matches)) => {
|
||||
let hash_type = parse_hash_type(sub_matches.get_one::<String>("hash-type").unwrap())?;
|
||||
init_user_config(user_config_path, hash_type)?;
|
||||
}
|
||||
Some(("add", sub_matches)) => {
|
||||
let username = sub_matches.get_one::<String>("username").unwrap();
|
||||
let password = get_password_from_args_or_prompt(sub_matches, "password")?;
|
||||
let hash_type = parse_hash_type(sub_matches.get_one::<String>("hash-type").unwrap())?;
|
||||
add_user(user_config_path, username, &password, hash_type)?;
|
||||
}
|
||||
Some(("remove", sub_matches)) => {
|
||||
let username = sub_matches.get_one::<String>("username").unwrap();
|
||||
remove_user(user_config_path, username)?;
|
||||
}
|
||||
Some(("list", _)) => {
|
||||
list_users(user_config_path)?;
|
||||
}
|
||||
Some(("update", sub_matches)) => {
|
||||
let username = sub_matches.get_one::<String>("username").unwrap();
|
||||
let password = get_password_from_args_or_prompt(sub_matches, "password")?;
|
||||
update_user_password(user_config_path, username, &password)?;
|
||||
}
|
||||
Some(("enable", sub_matches)) => {
|
||||
let username = sub_matches.get_one::<String>("username").unwrap();
|
||||
let enabled = sub_matches.get_one::<String>("enabled").unwrap().parse::<bool>()?;
|
||||
enable_user(user_config_path, username, enabled)?;
|
||||
}
|
||||
_ => {
|
||||
eprintln!("No valid user subcommand provided. Use --help for usage information.");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_hash_type(hash_type_str: &str) -> Result<HashType> {
|
||||
match hash_type_str.to_lowercase().as_str() {
|
||||
"argon2" => Ok(HashType::Argon2),
|
||||
"bcrypt" => Ok(HashType::Bcrypt),
|
||||
"scrypt" => Ok(HashType::Scrypt),
|
||||
_ => Err(anyhow::anyhow!("Invalid hash type: {}. Valid options are: argon2, bcrypt, scrypt", hash_type_str)),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_password_from_args_or_prompt(matches: &ArgMatches, arg_name: &str) -> Result<String> {
|
||||
if let Some(password) = matches.get_one::<String>(arg_name) {
|
||||
Ok(password.clone())
|
||||
} else {
|
||||
print!("Enter password: ");
|
||||
io::stdout().flush()?;
|
||||
let mut password = String::new();
|
||||
io::stdin().read_line(&mut password)?;
|
||||
Ok(password.trim().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn init_user_config(path: &str, hash_type: HashType) -> Result<()> {
|
||||
if std::path::Path::new(path).exists() {
|
||||
return Err(anyhow::anyhow!("User config file already exists: {}", path));
|
||||
}
|
||||
|
||||
let mut user_config = UserConfig::default();
|
||||
user_config.hash_type = hash_type;
|
||||
user_config.save_to_file(path)?;
|
||||
|
||||
println!("Initialized user configuration file: {}", path);
|
||||
println!("Hash type: {:?}", user_config.hash_type);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_user(path: &str, username: &str, password: &str, hash_type: HashType) -> Result<()> {
|
||||
let mut user_config = if std::path::Path::new(path).exists() {
|
||||
UserConfig::load_from_file(path)?
|
||||
} else {
|
||||
let mut config = UserConfig::default();
|
||||
config.hash_type = hash_type;
|
||||
config
|
||||
};
|
||||
|
||||
user_config.add_user(username.to_string(), password)?;
|
||||
user_config.save_to_file(path)?;
|
||||
|
||||
println!("Added user: {}", username);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_user(path: &str, username: &str) -> Result<()> {
|
||||
let mut user_config = UserConfig::load_from_file(path)?;
|
||||
user_config.remove_user(username)?;
|
||||
user_config.save_to_file(path)?;
|
||||
|
||||
println!("Removed user: {}", username);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn list_users(path: &str) -> Result<()> {
|
||||
let user_config = UserConfig::load_from_file(path)?;
|
||||
|
||||
println!("Hash type: {:?}", user_config.hash_type);
|
||||
println!("Users:");
|
||||
|
||||
if user_config.users.is_empty() {
|
||||
println!(" No users configured");
|
||||
} else {
|
||||
for (username, user) in &user_config.users {
|
||||
let status = if user.enabled { "enabled" } else { "disabled" };
|
||||
println!(" {} ({}) - created: {}, modified: {}",
|
||||
username, status, user.created_at, user.last_modified);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_user_password(path: &str, username: &str, password: &str) -> Result<()> {
|
||||
let mut user_config = UserConfig::load_from_file(path)?;
|
||||
user_config.update_password(username, password)?;
|
||||
user_config.save_to_file(path)?;
|
||||
|
||||
println!("Updated password for user: {}", username);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn enable_user(path: &str, username: &str, enabled: bool) -> Result<()> {
|
||||
let mut user_config = UserConfig::load_from_file(path)?;
|
||||
user_config.enable_user(username, enabled)?;
|
||||
user_config.save_to_file(path)?;
|
||||
|
||||
let status = if enabled { "enabled" } else { "disabled" };
|
||||
println!("User {} {}", username, status);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+1
-1
@@ -149,7 +149,7 @@ impl ProxyServer {
|
||||
}
|
||||
|
||||
async fn handle_socks5_connection(mut stream: TcpStream, config: Arc<Config>) -> Result<()> {
|
||||
let handler = Socks5Handler;
|
||||
let handler = Socks5Handler::new(config.clone());
|
||||
|
||||
let auth_required = config.auth.enabled;
|
||||
if !handler.handle_handshake(&mut stream, auth_required).await? {
|
||||
|
||||
+18
-4
@@ -1,8 +1,11 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||
use tracing::{debug, trace};
|
||||
use tracing::{debug, trace, warn};
|
||||
|
||||
use crate::Config;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum AuthMethod {
|
||||
@@ -126,9 +129,14 @@ impl Socks5Response {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Socks5Handler;
|
||||
pub struct Socks5Handler {
|
||||
config: Arc<Config>,
|
||||
}
|
||||
|
||||
impl Socks5Handler {
|
||||
pub fn new(config: Arc<Config>) -> Self {
|
||||
Self { config }
|
||||
}
|
||||
pub async fn handle_handshake<T>(&self, stream: &mut T, auth_required: bool) -> Result<bool>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite + Unpin,
|
||||
@@ -221,8 +229,14 @@ impl Socks5Handler {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_credentials(&self, _username: &str, _password: &str) -> bool {
|
||||
true
|
||||
fn validate_credentials(&self, username: &str, password: &str) -> bool {
|
||||
match self.config.validate_user(username, password) {
|
||||
Ok(valid) => valid,
|
||||
Err(e) => {
|
||||
warn!("Authentication error for user '{}': {}", username, e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_request<T>(&self, stream: &mut T) -> Result<Socks5Request>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# User Configuration File for Rusty SOCKS Proxy
|
||||
# This file contains user credentials with secure password hashing
|
||||
|
||||
# Password hash type: argon2, bcrypt, or scrypt
|
||||
hash_type: argon2
|
||||
|
||||
# User accounts
|
||||
users:
|
||||
# Example users (these are generated using secure hash functions)
|
||||
# Use the 'rusty-socks user' commands to manage users
|
||||
|
||||
# Sample user entry structure:
|
||||
# username:
|
||||
# password_hash: "$argon2id$v=19$m=65536,t=3,p=4$..."
|
||||
# salt: null # Some hash types embed salt in the hash
|
||||
# created_at: "2023-01-01T12:00:00Z"
|
||||
# last_modified: "2023-01-01T12:00:00Z"
|
||||
# enabled: true
|
||||
|
||||
# To add users, use: rusty-socks user add <username>
|
||||
# To list users, use: rusty-socks user list
|
||||
# To remove users, use: rusty-socks user remove <username>
|
||||
Reference in New Issue
Block a user