Switched from openssl to Rustls
This commit is contained in:
408
Cargo.lock
generated
408
Cargo.lock
generated
@@ -23,12 +23,33 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.1.0"
|
||||
@@ -47,6 +68,16 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "1.9.3"
|
||||
@@ -59,19 +90,52 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
name = "cpufeatures"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
name = "data-encoding"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
|
||||
|
||||
[[package]]
|
||||
name = "der-oid-macro"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c73af209b6a5dc8ca7cbaba720732304792cddc933cfea3d74509c2b1ef2f436"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der-parser"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9807efb310ce4ea172924f3a69d82f9fd6c9c3a19336344591153e665b31c43e"
|
||||
dependencies = [
|
||||
"der-oid-macro",
|
||||
"nom",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"rusticata-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
@@ -122,20 +186,32 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gemserv"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"mime",
|
||||
"new_mime_guess",
|
||||
"openssl",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"sha2",
|
||||
"simple_logger",
|
||||
"tokio",
|
||||
"tokio-openssl",
|
||||
"tokio-rustls",
|
||||
"toml",
|
||||
"url",
|
||||
"x509-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -179,6 +255,15 @@ version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@@ -227,6 +312,12 @@ version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.7.14"
|
||||
@@ -261,6 +352,17 @@ dependencies = [
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.3.6"
|
||||
@@ -270,6 +372,36 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
@@ -280,6 +412,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oid-registry"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe554cb2393bc784fd678c82c84cc0599c31ceadc7f03a594911f822cb8d1815"
|
||||
dependencies = [
|
||||
"der-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
@@ -287,31 +428,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.38"
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
@@ -356,12 +476,6 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.32"
|
||||
@@ -389,12 +503,67 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusticata-macros"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65c52377bb2288aa522a0c8208947fada1e0c76397f108cc08f57efe6077b50d"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
"sct",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9"
|
||||
dependencies = [
|
||||
"base64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
@@ -412,6 +581,19 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
@@ -446,6 +628,12 @@ version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.82"
|
||||
@@ -457,6 +645,26 @@ dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.5"
|
||||
@@ -521,15 +729,14 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-openssl"
|
||||
version = "0.6.3"
|
||||
name = "tokio-rustls"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08f9ffb7809f1b20c1b398d92acf4cc719874b3b2b2d9ea2f09b4a80350878a"
|
||||
checksum = "4baa378e417d780beff82bf54ceb0d195193ea6a00c14e22359e7f39456b5689"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"openssl",
|
||||
"openssl-sys",
|
||||
"rustls",
|
||||
"tokio",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -541,6 +748,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
@@ -571,6 +784,12 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.2.2"
|
||||
@@ -583,18 +802,86 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@@ -616,3 +903,20 @@ name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "x509-parser"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffc90836a84cb72e6934137b1504d0cae304ef5d83904beb0c8d773bbfe256ed"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"chrono",
|
||||
"data-encoding",
|
||||
"der-parser",
|
||||
"lazy_static",
|
||||
"nom",
|
||||
"oid-registry",
|
||||
"rusticata-macros",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
12
Cargo.toml
12
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "gemserv"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
authors = ["int 80h <int@80h.dev>"]
|
||||
edition = "2018"
|
||||
description = "A gemini server"
|
||||
@@ -15,8 +15,7 @@ license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.14", features = [ "full" ] }
|
||||
openssl = "0.10.38"
|
||||
tokio-openssl = "0.6.3"
|
||||
rustls-pemfile = "0.2.1"
|
||||
futures-util = "0.3.18"
|
||||
toml = "0.5.8"
|
||||
serde = "1.0.130"
|
||||
@@ -26,6 +25,13 @@ new_mime_guess = "3.0.2"
|
||||
mime = "0.3.16"
|
||||
log = "0.4.14"
|
||||
simple_logger = "1.15"
|
||||
sha2 = "0.9.8"
|
||||
x509-parser = "0.12"
|
||||
|
||||
[dependencies.tokio-rustls]
|
||||
version = "0.23.1"
|
||||
optional = false
|
||||
features = ["dangerous_configuration"]
|
||||
|
||||
[features]
|
||||
default = [ "cgi", "scgi", "proxy" ]
|
||||
|
||||
2
README
2
README
@@ -13,8 +13,6 @@ A gemini server written in rust.
|
||||
|
||||
## Installation and running
|
||||
|
||||
It's recommended that you build with Libressl instead of Openssl.
|
||||
|
||||
To run either run "cargo run /path/to/config" or if no configuration is
|
||||
specified it will look for "/usr/local/etc/gemserv.conf"
|
||||
|
||||
|
||||
103
src/cgi.rs
103
src/cgi.rs
@@ -3,10 +3,12 @@ use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
#[cfg(feature = "cgi")]
|
||||
use tokio::process::Command;
|
||||
#[cfg(feature = "cgi")]
|
||||
use std::path::PathBuf;
|
||||
#[cfg(feature = "cgi")]
|
||||
use tokio::process::Command;
|
||||
|
||||
use tokio_rustls::rustls::ServerConnection;
|
||||
|
||||
#[cfg(feature = "scgi")]
|
||||
use std::net::ToSocketAddrs;
|
||||
@@ -22,39 +24,51 @@ use crate::status::Status;
|
||||
use crate::util;
|
||||
|
||||
#[cfg(any(feature = "cgi", feature = "scgi"))]
|
||||
fn envs(peer_addr: SocketAddr, x509: Option<openssl::x509::X509>, srv: &config::ServerCfg, url: &url::Url) -> HashMap<String, String> {
|
||||
fn envs(
|
||||
peer_addr: SocketAddr,
|
||||
session: &ServerConnection,
|
||||
srv: &config::ServerCfg,
|
||||
url: &url::Url,
|
||||
) -> HashMap<String, String> {
|
||||
let mut envs = HashMap::new();
|
||||
envs.insert("GATEWAY_INTERFACE".to_string(), "CGI/1.1".to_string());
|
||||
envs.insert("GEMINI_URL".to_string(), url.to_string());
|
||||
envs.insert("SERVER_NAME".to_string(), url.host_str().unwrap().to_string());
|
||||
envs.insert(
|
||||
"SERVER_NAME".to_string(),
|
||||
url.host_str().unwrap().to_string(),
|
||||
);
|
||||
envs.insert("SERVER_PROTOCOL".to_string(), "GEMINI".to_string());
|
||||
let addr = peer_addr.ip().to_string();
|
||||
envs.insert("REMOTE_ADDR".to_string(), addr.clone());
|
||||
envs.insert("REMOTE_HOST".to_string(), addr);
|
||||
let port = peer_addr.port().to_string();
|
||||
envs.insert("REMOTE_PORT".to_string(), port);
|
||||
envs.insert("SERVER_SOFTWARE".to_string(), env!("CARGO_PKG_NAME").to_string());
|
||||
envs.insert(
|
||||
"SERVER_SOFTWARE".to_string(),
|
||||
env!("CARGO_PKG_NAME").to_string(),
|
||||
);
|
||||
|
||||
if let Some(q) = url.query() {
|
||||
envs.insert("QUERY_STRING".to_string(), q.to_string());
|
||||
}
|
||||
|
||||
match x509 {
|
||||
Some(x) => {
|
||||
envs.insert("AUTH_TYPE".to_string(), "Certificate".to_string());
|
||||
if let Some(cert) = session.peer_certificates() {
|
||||
let cert = tokio_rustls::rustls::Certificate::as_ref(&cert[0]);
|
||||
match x509_parser::parse_x509_certificate(cert) {
|
||||
Ok((_, x509)) => {
|
||||
let user = x509
|
||||
.subject()
|
||||
.iter_common_name()
|
||||
.next()
|
||||
.and_then(|cn| cn.as_str().ok())
|
||||
.unwrap();
|
||||
|
||||
let cn = x.subject_name().entries_by_nid(openssl::nid::Nid::COMMONNAME);
|
||||
for c in cn {
|
||||
let cd = match c.data().as_utf8() {
|
||||
Ok(n) => n.to_string(),
|
||||
_ => "".to_string(),
|
||||
};
|
||||
envs.insert("REMOTE_USER".to_string(), cd);
|
||||
envs.insert("AUTH_TYPE".to_string(), "Certificate".to_string());
|
||||
envs.insert("REMOTE_USER".to_string(), user.to_string());
|
||||
envs.insert("TLS_CLIENT_HASH".to_string(), util::fingerhex(&cert));
|
||||
}
|
||||
|
||||
envs.insert("TLS_CLIENT_HASH".to_string(), util::fingerhex(&x));
|
||||
},
|
||||
None => {},
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
match &srv.server.cgienv {
|
||||
@@ -73,15 +87,15 @@ fn check(byt: u8, peer_addr: SocketAddr, u: &url::Url) -> bool {
|
||||
match byt {
|
||||
49 => {
|
||||
logger::logger(peer_addr, Status::Input, u.as_str());
|
||||
},
|
||||
}
|
||||
50 => {
|
||||
logger::logger(peer_addr, Status::Success, u.as_str());
|
||||
},
|
||||
}
|
||||
51..=54 => {}
|
||||
_ => {
|
||||
logger::logger(peer_addr, Status::CGIError, u.as_str());
|
||||
return false;
|
||||
},
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
@@ -92,19 +106,18 @@ pub async fn cgi(
|
||||
path: PathBuf,
|
||||
url: &url::Url,
|
||||
script_name: String,
|
||||
path_info: String
|
||||
path_info: String,
|
||||
) -> Result<(), io::Error> {
|
||||
|
||||
let x509 = con.stream.ssl().peer_certificate();
|
||||
let mut envs = envs(con.peer_addr, x509, &con.srv, &url);
|
||||
let (_, session) = con.stream.get_ref();
|
||||
let mut envs = envs(con.peer_addr, session, &con.srv, &url);
|
||||
envs.insert("SCRIPT_NAME".into(), script_name);
|
||||
envs.insert("PATH_INFO".into(), path_info);
|
||||
|
||||
match path.parent() {
|
||||
Some(p) => {
|
||||
std::env::set_current_dir(p)?;
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
let cmd = Command::new(path.to_str().unwrap())
|
||||
@@ -113,22 +126,20 @@ pub async fn cgi(
|
||||
.output();
|
||||
|
||||
let cmd = match tokio::time::timeout(tokio::time::Duration::from_secs(5), cmd).await {
|
||||
Ok(c) => {
|
||||
match c {
|
||||
Ok(cc) => cc,
|
||||
Ok(c) => match c {
|
||||
Ok(cc) => cc,
|
||||
|
||||
Err(_) => {
|
||||
logger::logger(con.peer_addr, Status::CGIError, url.as_str());
|
||||
con.send_status(Status::CGIError, None).await?;
|
||||
return Ok(());
|
||||
},
|
||||
Err(_) => {
|
||||
logger::logger(con.peer_addr, Status::CGIError, url.as_str());
|
||||
con.send_status(Status::CGIError, None).await?;
|
||||
return Ok(());
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
logger::logger(con.peer_addr, Status::CGIError, url.as_str());
|
||||
con.send_status(Status::CGIError, None).await?;
|
||||
return Ok(());
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
if !cmd.status.success() {
|
||||
@@ -161,11 +172,15 @@ pub async fn scgi(addr: String, u: url::Url, mut con: conn::Connection) -> Resul
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let x509 = con.stream.ssl().peer_certificate();
|
||||
let envs = envs(con.peer_addr, x509, &con.srv, &u);
|
||||
let (_, session) = con.stream.get_ref();
|
||||
let envs = envs(con.peer_addr, session, &con.srv, &u);
|
||||
let len = 0usize;
|
||||
let mut byt = String::from(format!("CONTENT_LENGTH\x00{}\x00SCGI\x001\x00
|
||||
RQUEST_METHOD\x00POST\x00REQUEST_URI\x00{}\x00", len, u.path()));
|
||||
let mut byt = String::from(format!(
|
||||
"CONTENT_LENGTH\x00{}\x00SCGI\x001\x00
|
||||
RQUEST_METHOD\x00POST\x00REQUEST_URI\x00{}\x00",
|
||||
len,
|
||||
u.path()
|
||||
));
|
||||
for (k, v) in envs.iter() {
|
||||
byt.push_str(&format!("{}\x00{}\x00", k, v));
|
||||
}
|
||||
@@ -176,7 +191,11 @@ pub async fn scgi(addr: String, u: url::Url, mut con: conn::Connection) -> Resul
|
||||
|
||||
let mut buf = vec![];
|
||||
if let Err(_) = tokio::time::timeout(
|
||||
tokio::time::Duration::from_secs(5), stream.read_to_end(&mut buf)).await {
|
||||
tokio::time::Duration::from_secs(5),
|
||||
stream.read_to_end(&mut buf),
|
||||
)
|
||||
.await
|
||||
{
|
||||
logger::logger(con.peer_addr, Status::CGIError, u.as_str());
|
||||
con.send_status(Status::CGIError, None).await?;
|
||||
return Ok(());
|
||||
|
||||
@@ -6,14 +6,16 @@ use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::PathBuf;
|
||||
use url::Url;
|
||||
|
||||
use crate::util;
|
||||
use crate::conn;
|
||||
use crate::status::Status;
|
||||
#[cfg(any(feature = "cgi", feature = "scgi"))]
|
||||
use crate::cgi;
|
||||
use crate::conn;
|
||||
use crate::logger;
|
||||
#[cfg(feature = "proxy")]
|
||||
use crate::revproxy;
|
||||
use crate::status::Status;
|
||||
use crate::util;
|
||||
|
||||
type Result<T=()> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
|
||||
fn get_mime(path: &PathBuf) -> String {
|
||||
let mut mime = "text/gemini".to_string();
|
||||
@@ -36,8 +38,7 @@ fn get_mime(path: &PathBuf) -> String {
|
||||
async fn get_binary(mut con: conn::Connection, path: PathBuf, meta: String) -> io::Result<()> {
|
||||
let fd = File::open(path)?;
|
||||
let mut reader = BufReader::with_capacity(1024 * 1024, fd);
|
||||
con.send_status(Status::Success, Some(&meta))
|
||||
.await?;
|
||||
con.send_status(Status::Success, Some(&meta)).await?;
|
||||
loop {
|
||||
let len = {
|
||||
let buf = reader.fill_buf()?;
|
||||
@@ -132,33 +133,30 @@ async fn handle_cgi(
|
||||
|
||||
match &con.srv.server.cgipath {
|
||||
Some(c) => {
|
||||
if path.starts_with(c) {
|
||||
if perm.mode() & 0o0111 == 0o0111 {
|
||||
cgi::cgi(con, path, url, script_name, path_info).await?;
|
||||
return Ok(true);
|
||||
} else {
|
||||
logger::logger(con.peer_addr, Status::CGIError, request);
|
||||
con.send_status(Status::CGIError, None).await?;
|
||||
return Ok(true);
|
||||
if path.starts_with(c) {
|
||||
if perm.mode() & 0o0111 == 0o0111 {
|
||||
cgi::cgi(con, path, url, script_name, path_info).await?;
|
||||
return Ok(true);
|
||||
} else {
|
||||
logger::logger(con.peer_addr, Status::CGIError, request);
|
||||
con.send_status(Status::CGIError, None).await?;
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
if meta.is_file() && perm.mode() & 0o0111 == 0o0111 {
|
||||
cgi::cgi(con, path, url, script_name, path_info).await?;
|
||||
return Ok(true);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
// TODO Rewrite this monster.
|
||||
pub async fn handle_connection(
|
||||
mut con: conn::Connection,
|
||||
url: url::Url
|
||||
) -> Result {
|
||||
pub async fn handle_connection(mut con: conn::Connection, url: url::Url) -> Result {
|
||||
let index = match &con.srv.server.index {
|
||||
Some(i) => i.clone(),
|
||||
None => "index.gemini".to_string(),
|
||||
@@ -223,18 +221,17 @@ pub async fn handle_connection(
|
||||
"/" => "/",
|
||||
_ => url.path().trim_end_matches("/"),
|
||||
};
|
||||
match sc.get(u) {
|
||||
Some(r) => {
|
||||
cgi::scgi(r.to_string(), url, con).await?;
|
||||
return Ok(());
|
||||
match sc.get(u) {
|
||||
Some(r) => {
|
||||
cgi::scgi(r.to_string(), url, con).await?;
|
||||
return Ok(());
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
},
|
||||
None => {},
|
||||
None => {}
|
||||
}
|
||||
|
||||
|
||||
let mut path = PathBuf::new();
|
||||
|
||||
if url.path().starts_with("/~") && con.srv.server.usrdir.unwrap_or(false) {
|
||||
@@ -246,7 +243,12 @@ pub async fn handle_connection(
|
||||
path.push("/home/");
|
||||
}
|
||||
if usr.len() == 2 {
|
||||
path.push(format!("{}/{}/{}", usr[0], "public_gemini", util::url_decode(usr[1].as_bytes())));
|
||||
path.push(format!(
|
||||
"{}/{}/{}",
|
||||
usr[0],
|
||||
"public_gemini",
|
||||
util::url_decode(usr[1].as_bytes())
|
||||
));
|
||||
} else {
|
||||
path.push(format!("{}/{}/", usr[0], "public_gemini"));
|
||||
}
|
||||
@@ -304,13 +306,13 @@ pub async fn handle_connection(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if meta.is_file() && perm.mode() & 0o0111 == 0o0111 {
|
||||
if meta.is_file() && perm.mode() & 0o0111 == 0o0111 {
|
||||
logger::logger(con.peer_addr, Status::NotFound, &url.as_str());
|
||||
con.send_status(Status::NotFound, None).await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if perm.mode() & 0o0444 != 0o0444 {
|
||||
if perm.mode() & 0o0444 != 0o0444 {
|
||||
logger::logger(con.peer_addr, Status::NotFound, &url.as_str());
|
||||
con.send_status(Status::NotFound, None).await?;
|
||||
return Ok(());
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
extern crate serde_derive;
|
||||
extern crate toml;
|
||||
use tokio::fs;
|
||||
use std::collections::HashMap;
|
||||
use std::path;
|
||||
use std::env;
|
||||
use crate::lib::errors;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::path;
|
||||
use tokio::fs;
|
||||
|
||||
type Result<T=()> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct Config {
|
||||
@@ -43,7 +43,7 @@ pub struct Server {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ServerCfg {
|
||||
// pub port: u16,
|
||||
// pub port: u16,
|
||||
pub server: Server,
|
||||
}
|
||||
|
||||
@@ -56,7 +56,9 @@ impl Config {
|
||||
if !p.exists() {
|
||||
return Err(Box::new(errors::GemError(
|
||||
"Please run with the path to the config file. \
|
||||
Or create the config as /usr/local/etc/gemserv.conf".to_string())));
|
||||
Or create the config as /usr/local/etc/gemserv.conf"
|
||||
.to_string(),
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
p.push(&args[1]);
|
||||
@@ -67,22 +69,30 @@ impl Config {
|
||||
Ok(c) => c,
|
||||
Err(e) => return Err(Box::new(e)),
|
||||
};
|
||||
|
||||
|
||||
if config.host.is_some() || config.port.is_some() {
|
||||
eprintln!("The host/port keys are depricated in favor \
|
||||
of interface and may be removed in the future.");
|
||||
eprintln!(
|
||||
"The host/port keys are depricated in favor \
|
||||
of interface and may be removed in the future."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if config.interface.is_some() && (config.host.is_some() || config.port.is_some()) {
|
||||
return Err(Box::new(errors::GemError("You need to specify either host/port or interface".into())));
|
||||
return Err(Box::new(errors::GemError(
|
||||
"You need to specify either host/port or interface".into(),
|
||||
)));
|
||||
} else if config.interface.is_none() && config.host.is_none() && config.port.is_none() {
|
||||
return Err(Box::new(errors::GemError("You need to specify either host/port or interface".into())));
|
||||
return Err(Box::new(errors::GemError(
|
||||
"You need to specify either host/port or interface".into(),
|
||||
)));
|
||||
} else if config.host.is_some() && config.port.is_some() {
|
||||
return Ok(config);
|
||||
} else if config.interface.is_some() {
|
||||
return Ok(config);
|
||||
}
|
||||
return Err(Box::new(errors::GemError("You need to specify either host/port or interface".into())));
|
||||
}
|
||||
return Err(Box::new(errors::GemError(
|
||||
"You need to specify either host/port or interface".into(),
|
||||
)));
|
||||
}
|
||||
pub fn to_map(&self) -> HashMap<String, ServerCfg> {
|
||||
let mut map = HashMap::new();
|
||||
@@ -90,11 +100,11 @@ impl Config {
|
||||
map.insert(
|
||||
srv.hostname.clone(),
|
||||
ServerCfg {
|
||||
// port: self.port.clone(),
|
||||
// port: self.port.clone(),
|
||||
server: srv.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
map
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@ use std::io;
|
||||
use std::marker::Unpin;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::io::AsyncRead;
|
||||
use tokio::io::{AsyncWrite, AsyncWriteExt};
|
||||
use tokio_openssl::SslStream;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_rustls::server::TlsStream;
|
||||
|
||||
use crate::status::Status;
|
||||
|
||||
pub struct Connection {
|
||||
pub stream: SslStream<TcpStream>,
|
||||
pub stream: TlsStream<TcpStream>,
|
||||
pub local_addr: SocketAddr,
|
||||
pub peer_addr: SocketAddr,
|
||||
pub srv: crate::config::ServerCfg,
|
||||
@@ -38,7 +38,11 @@ impl Connection {
|
||||
self.send_raw(b.as_bytes()).await?;
|
||||
}
|
||||
|
||||
futures_util::future::poll_fn(|ctx| std::pin::Pin::new(&mut self.stream).poll_shutdown(ctx)).await.unwrap();
|
||||
futures_util::future::poll_fn(|ctx| {
|
||||
std::pin::Pin::new(&mut self.stream).poll_shutdown(ctx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -49,9 +53,16 @@ impl Connection {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_stream<S: AsyncRead + Unpin>(&mut self, reader: &mut S) -> Result<(), io::Error> {
|
||||
pub async fn send_stream<S: AsyncRead + Unpin>(
|
||||
&mut self,
|
||||
reader: &mut S,
|
||||
) -> Result<(), io::Error> {
|
||||
tokio::io::copy(reader, &mut self.stream).await?;
|
||||
futures_util::future::poll_fn(|ctx| std::pin::Pin::new(&mut self.stream).poll_shutdown(ctx)).await.unwrap();
|
||||
futures_util::future::poll_fn(|ctx| {
|
||||
std::pin::Pin::new(&mut self.stream).poll_shutdown(ctx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
pub type Result<T=()> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
pub type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GemError(pub String);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
pub mod util;
|
||||
pub mod status;
|
||||
pub mod conn;
|
||||
pub mod tls;
|
||||
pub mod server;
|
||||
pub mod errors;
|
||||
pub mod server;
|
||||
pub mod status;
|
||||
pub mod tls;
|
||||
pub mod util;
|
||||
|
||||
@@ -1,26 +1,35 @@
|
||||
#![allow(unreachable_code)]
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use openssl::ssl::SslAcceptor;
|
||||
use openssl::error::ErrorStack;
|
||||
use openssl::ssl::NameType;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio_rustls::server::TlsStream;
|
||||
use tokio_rustls::TlsAcceptor;
|
||||
|
||||
//use futures_util::future::TryFutureExt;
|
||||
use url::Url;
|
||||
use std::io;
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::sync::Arc;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use url::Url;
|
||||
|
||||
use crate::config;
|
||||
use crate::conn;
|
||||
use crate::errors::{GemError, Result};
|
||||
use crate::logger;
|
||||
use crate::status::Status;
|
||||
use crate::errors::{GemError, Result};
|
||||
|
||||
pub trait Handler: FnMut(conn::Connection, url::Url) -> Pin<Box<dyn Future<Output = Result> + Send>> + Send + Sync + Copy {}
|
||||
impl<T> Handler for T
|
||||
where T: FnMut(conn::Connection, url::Url) -> Pin<Box<dyn Future<Output = Result> + Send>> + Send + Sync + Copy
|
||||
pub trait Handler:
|
||||
FnMut(conn::Connection, url::Url) -> Pin<Box<dyn Future<Output = Result> + Send>>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ Copy
|
||||
{
|
||||
}
|
||||
impl<T> Handler for T where
|
||||
T: FnMut(conn::Connection, url::Url) -> Pin<Box<dyn Future<Output = Result> + Send>>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ Copy
|
||||
{
|
||||
}
|
||||
|
||||
@@ -33,14 +42,15 @@ where
|
||||
|
||||
pub struct Server {
|
||||
pub listener: Vec<TcpListener>,
|
||||
pub acceptor: SslAcceptor,
|
||||
pub acceptor: TlsAcceptor,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub async fn bind(addr: Vec<std::net::SocketAddr>,
|
||||
acceptor: fn(config::Config) -> std::result::Result<SslAcceptor, ErrorStack>,
|
||||
cfg: config::Config) -> io::Result<Server>
|
||||
{
|
||||
pub async fn bind(
|
||||
addr: Vec<std::net::SocketAddr>,
|
||||
acceptor: fn(config::Config) -> std::io::Result<TlsAcceptor>,
|
||||
cfg: config::Config,
|
||||
) -> Result<Server> {
|
||||
if addr.len() == 1 {
|
||||
Ok(Server {
|
||||
listener: vec![TcpListener::bind(addr[0].to_owned()).await?],
|
||||
@@ -58,14 +68,18 @@ impl Server {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn serve(self, cmap: HashMap<String, config::ServerCfg>, default: String,
|
||||
handler: impl Handler + 'static + Copy) -> Result
|
||||
{
|
||||
for listen in self.listener {
|
||||
pub async fn serve(
|
||||
self,
|
||||
cmap: HashMap<String, config::ServerCfg>,
|
||||
default: String,
|
||||
handler: impl Handler + 'static + Copy,
|
||||
) -> Result {
|
||||
for listen in self.listener {
|
||||
let cmap = cmap.clone();
|
||||
let default = default.clone();
|
||||
let listen = Arc::new(listen);
|
||||
let acceptor = Arc::new(self.acceptor.clone());
|
||||
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
let (stream, peer_addr) = listen.accept().await?;
|
||||
@@ -75,31 +89,37 @@ impl Server {
|
||||
let default = default.clone();
|
||||
let mut handler = handler.clone();
|
||||
|
||||
let ssl = openssl::ssl::Ssl::new(acceptor.context()).unwrap();
|
||||
let mut stream = tokio_openssl::SslStream::new(ssl, stream).unwrap();
|
||||
|
||||
tokio::spawn(async move {
|
||||
match Pin::new(&mut stream).accept().await {
|
||||
let mut stream = match acceptor.accept(stream).await {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
log::error!("Error: {}",e);
|
||||
log::error!("Error: {}", e);
|
||||
return Ok(());
|
||||
},
|
||||
}
|
||||
};
|
||||
let (_, sni) = TlsStream::get_mut(&mut stream);
|
||||
let sni = match sni.sni_hostname() {
|
||||
Some(s) => s,
|
||||
None => return Ok(()),
|
||||
};
|
||||
let srv = match stream.ssl().servername(NameType::HOST_NAME) {
|
||||
Some(s) => match cmap.get(s) {
|
||||
Some(ss) => ss,
|
||||
None => cmap.get(&default).unwrap(),
|
||||
},
|
||||
None => cmap.get(&default).unwrap(),
|
||||
}.to_owned();
|
||||
|
||||
let con = conn::Connection { stream, local_addr, peer_addr, srv };
|
||||
let srv = match cmap.get(sni) {
|
||||
Some(h) => h,
|
||||
None => cmap.get(&default).unwrap(),
|
||||
}
|
||||
.to_owned();
|
||||
|
||||
let con = conn::Connection {
|
||||
stream,
|
||||
local_addr,
|
||||
peer_addr,
|
||||
srv,
|
||||
};
|
||||
let (con, url) = match get_request(con).await {
|
||||
Ok((c, u)) => (c, u),
|
||||
Err(_) => return Ok(()) as io::Result<()>,
|
||||
};
|
||||
|
||||
|
||||
match handler(con, url).await {
|
||||
Ok(o) => o,
|
||||
Err(_) => return Ok(()) as io::Result<()>,
|
||||
@@ -111,18 +131,27 @@ impl Server {
|
||||
Ok(()) as io::Result<()>
|
||||
});
|
||||
}
|
||||
tokio::signal::ctrl_c().await.expect("failed to listen for event");
|
||||
tokio::signal::ctrl_c()
|
||||
.await
|
||||
.expect("failed to listen for event");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_request(mut con: conn::Connection) -> Result<(conn::Connection, url::Url)> {
|
||||
let mut buffer = [0; 1024];
|
||||
let len = match tokio::time::timeout(tokio::time::Duration::from_secs(5), con.stream.read(&mut buffer)).await {
|
||||
let len = match tokio::time::timeout(
|
||||
tokio::time::Duration::from_secs(5),
|
||||
con.stream.read(&mut buffer),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(result) => result.unwrap(),
|
||||
Err(e) => {
|
||||
logger::logger(con.peer_addr, Status::BadRequest, "");
|
||||
con.send_status(Status::BadRequest, None).await.map_err(|e| e.to_string())?;
|
||||
con.send_status(Status::BadRequest, None)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
return Err(Box::new(e));
|
||||
}
|
||||
};
|
||||
@@ -130,7 +159,9 @@ pub async fn get_request(mut con: conn::Connection) -> Result<(conn::Connection,
|
||||
Ok(request) => request,
|
||||
Err(e) => {
|
||||
logger::logger(con.peer_addr, Status::BadRequest, "");
|
||||
con.send_status(Status::BadRequest, None).await.map_err(|e| e.to_string())?;
|
||||
con.send_status(Status::BadRequest, None)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
return Err(Box::new(e));
|
||||
}
|
||||
};
|
||||
@@ -149,7 +180,9 @@ pub async fn get_request(mut con: conn::Connection) -> Result<(conn::Connection,
|
||||
Ok(url) => url,
|
||||
Err(e) => {
|
||||
logger::logger(con.peer_addr, Status::BadRequest, &request);
|
||||
con.send_status(Status::BadRequest, None).await.map_err(|e| e.to_string())?;
|
||||
con.send_status(Status::BadRequest, None)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
return Err(Box::new(e));
|
||||
}
|
||||
};
|
||||
@@ -158,10 +191,12 @@ pub async fn get_request(mut con: conn::Connection) -> Result<(conn::Connection,
|
||||
Some(h) => {
|
||||
if con.srv.server.hostname.as_str() != h.to_lowercase() {
|
||||
logger::logger(con.peer_addr, Status::ProxyRequestRefused, &url.as_str());
|
||||
con.send_status(Status::ProxyRequestRefused, None).await.map_err(|e| e.to_string())?;
|
||||
con.send_status(Status::ProxyRequestRefused, None)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
return Err(Box::new(GemError("Wrong host".into())));
|
||||
}
|
||||
},
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
match url.port() {
|
||||
@@ -169,16 +204,19 @@ pub async fn get_request(mut con: conn::Connection) -> Result<(conn::Connection,
|
||||
if p != con.local_addr.port() {
|
||||
logger::logger(con.peer_addr, Status::ProxyRequestRefused, &url.as_str());
|
||||
con.send_status(Status::ProxyRequestRefused, None)
|
||||
.await.map_err(|e| e.to_string())?;
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
if url.scheme() != "gemini" {
|
||||
logger::logger(con.peer_addr, Status::ProxyRequestRefused, &url.as_str());
|
||||
con.send_status(Status::ProxyRequestRefused, None).await.map_err(|e| e.to_string())?;
|
||||
con.send_status(Status::ProxyRequestRefused, None)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
return Err(Box::new(GemError("scheme not gemini".into())));
|
||||
}
|
||||
|
||||
return Ok((con, url))
|
||||
}
|
||||
|
||||
return Ok((con, url));
|
||||
}
|
||||
|
||||
212
src/lib/tls.rs
212
src/lib/tls.rs
@@ -1,69 +1,163 @@
|
||||
extern crate openssl;
|
||||
extern crate tokio_openssl;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufReader};
|
||||
use std::sync::Arc;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use openssl::error::ErrorStack;
|
||||
use openssl::ssl::NameType;
|
||||
use openssl::ssl::SniError;
|
||||
use openssl::ssl::SslContextBuilder;
|
||||
use openssl::ssl::SslVersion;
|
||||
use openssl::ssl::SslVerifyMode;
|
||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||||
use rustls::client::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier, ServerName};
|
||||
use rustls::internal::msgs::enums::SignatureScheme;
|
||||
use rustls::internal::msgs::handshake::DigitallySignedStruct;
|
||||
use rustls::internal::msgs::handshake::DistinguishedNames;
|
||||
use rustls::server::{ClientCertVerified, ClientCertVerifier, ResolvesServerCertUsingSni};
|
||||
use rustls::sign::{self, CertifiedKey};
|
||||
use rustls::{Certificate, Error, PrivateKey};
|
||||
use rustls_pemfile::{certs, pkcs8_private_keys};
|
||||
use tokio_rustls::rustls;
|
||||
use tokio_rustls::TlsAcceptor;
|
||||
|
||||
use crate::config;
|
||||
|
||||
pub fn acceptor_conf(cfg: config::Config) -> Result<SslAcceptor, ErrorStack> {
|
||||
let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls_server())?;
|
||||
acceptor.set_min_proto_version(Some(SslVersion::TLS1_2))?;
|
||||
let mut map = HashMap::new();
|
||||
let mut num = 1;
|
||||
pub fn tls_acceptor_conf(cfg: config::Config) -> io::Result<TlsAcceptor> {
|
||||
let resolver = load_keypair(cfg)?;
|
||||
let config = rustls::server::ServerConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_client_cert_verifier(Arc::new(GeminiClientAuth))
|
||||
.with_cert_resolver(Arc::new(resolver));
|
||||
let acceptor = TlsAcceptor::from(Arc::new(config));
|
||||
|
||||
Ok(acceptor)
|
||||
}
|
||||
|
||||
pub fn load_certs(path: &String) -> io::Result<Vec<Certificate>> {
|
||||
certs(&mut BufReader::new(File::open(path)?))
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))
|
||||
.map(|mut certs| certs.drain(..).map(Certificate).collect())
|
||||
}
|
||||
|
||||
fn load_key(path: &String) -> io::Result<Vec<PrivateKey>> {
|
||||
pkcs8_private_keys(&mut std::io::BufReader::new(std::fs::File::open(path)?))
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))
|
||||
.map(|mut keys| keys.drain(..).map(PrivateKey).collect())
|
||||
}
|
||||
|
||||
fn load_keypair(cfg: config::Config) -> io::Result<ResolvesServerCertUsingSni> {
|
||||
let mut resolver = rustls::server::ResolvesServerCertUsingSni::new();
|
||||
|
||||
for server in cfg.server.iter() {
|
||||
let mut ctx = SslContextBuilder::new(SslMethod::tls_server())?;
|
||||
ctx.set_verify(SslVerifyMode::NONE);
|
||||
match ctx.set_private_key_file(&server.key, SslFiletype::PEM) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
log::error!("Error: Can't load key file");
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
match ctx.set_certificate_chain_file(&server.cert) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
log::error!("Error: Can't load cert file");
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
let ctx = ctx.build();
|
||||
map.insert(server.hostname.clone(), ctx.clone());
|
||||
if num == 1 {
|
||||
map.insert("default".to_string(), ctx);
|
||||
num += 1;
|
||||
}
|
||||
let key = load_key(&server.key)?.remove(0);
|
||||
let certs = load_certs(&server.cert)?;
|
||||
let signing_key = sign::any_supported_type(&key).expect("error loading key");
|
||||
|
||||
resolver
|
||||
.add(
|
||||
&server.hostname.clone(),
|
||||
CertifiedKey::new(certs, signing_key),
|
||||
)
|
||||
.expect("error loading key");
|
||||
}
|
||||
Ok(resolver)
|
||||
}
|
||||
|
||||
struct GeminiClientAuth;
|
||||
|
||||
impl ClientCertVerifier for GeminiClientAuth {
|
||||
fn client_auth_root_subjects(&self) -> Option<DistinguishedNames> {
|
||||
Some(Vec::new())
|
||||
}
|
||||
|
||||
let ctx_builder = &mut *acceptor;
|
||||
ctx_builder.set_servername_callback(move |ssl, _alert| -> Result<(), SniError> {
|
||||
ssl.set_ssl_context({
|
||||
let hostname = ssl.servername(NameType::HOST_NAME);
|
||||
if let Some(host) = hostname {
|
||||
if let Some(ctx) = map.get(host) {
|
||||
&ctx
|
||||
} else {
|
||||
&map.get(&"default".to_string()).expect("Can't get default")
|
||||
}
|
||||
} else {
|
||||
&map.get(&"default".to_string()).expect("Can't get default")
|
||||
}
|
||||
})
|
||||
.expect("Can't get sni");
|
||||
// for client certs we don't have anything to verify right now?
|
||||
ssl.set_verify_callback(SslVerifyMode::PEER, |_ver, _store| -> bool {
|
||||
return true
|
||||
});
|
||||
fn verify_client_cert(
|
||||
&self,
|
||||
_end_entity: &Certificate,
|
||||
_intermidiates: &[Certificate],
|
||||
_now: SystemTime,
|
||||
) -> Result<ClientCertVerified, Error> {
|
||||
Ok(ClientCertVerified::assertion())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
fn offer_client_auth(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
Ok(acceptor.build())
|
||||
fn client_auth_mandatory(&self) -> Option<bool> {
|
||||
Some(false)
|
||||
}
|
||||
|
||||
fn verify_tls12_signature(
|
||||
&self,
|
||||
_message: &[u8],
|
||||
_cert: &Certificate,
|
||||
_dss: &DigitallySignedStruct,
|
||||
) -> Result<HandshakeSignatureValid, Error> {
|
||||
Ok(HandshakeSignatureValid::assertion())
|
||||
}
|
||||
|
||||
fn verify_tls13_signature(
|
||||
&self,
|
||||
_message: &[u8],
|
||||
_cert: &Certificate,
|
||||
_dss: &DigitallySignedStruct,
|
||||
) -> Result<HandshakeSignatureValid, Error> {
|
||||
Ok(HandshakeSignatureValid::assertion())
|
||||
}
|
||||
|
||||
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
|
||||
tokio_rustls::rustls::client::WebPkiVerifier::verification_schemes()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GeminiServerAuth;
|
||||
|
||||
impl ServerCertVerifier for GeminiServerAuth {
|
||||
fn verify_server_cert(
|
||||
&self,
|
||||
_end_entity: &Certificate,
|
||||
_intermediates: &[Certificate],
|
||||
_server_name: &ServerName,
|
||||
_scts: &mut dyn Iterator<Item = &[u8]>,
|
||||
_ocsp_response: &[u8],
|
||||
_now: SystemTime,
|
||||
) -> Result<ServerCertVerified, Error> {
|
||||
Ok(ServerCertVerified::assertion())
|
||||
}
|
||||
}
|
||||
// This was pull out of the depths of git.
|
||||
// Rustls won't let self signed certs be used with sni which gemini requires.
|
||||
// At 1.4.2 in https://gemini.circumlunar.space/docs/spec-spec.txt
|
||||
/*
|
||||
pub struct CertResolver {
|
||||
map: HashMap<String, Box<CertifiedKey>>,
|
||||
}
|
||||
|
||||
impl CertResolver {
|
||||
pub fn from_config(cfg: config::Config) -> errors::Result<Self> {
|
||||
let mut map = HashMap::new();
|
||||
|
||||
for server in cfg.server.iter() {
|
||||
let key = load_key(&server.key)?;
|
||||
let certs = load_certs(&server.cert)?;
|
||||
let signing_key = RsaSigningKey::new(&key).unwrap();
|
||||
|
||||
//let signing_key_boxed: Arc<Box<dyn SigningKey>> = Arc::new(Box::new(signing_key));
|
||||
let signing_key_boxed = Arc::new(signing_key);
|
||||
map.insert(
|
||||
server.hostname.clone(),
|
||||
Box::new(CertifiedKey::new(certs, signing_key_boxed)),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(CertResolver { map })
|
||||
}
|
||||
}
|
||||
|
||||
impl ResolvesServerCert for CertResolver {
|
||||
fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
|
||||
if let Some(hostname) = client_hello.server_name() {
|
||||
if let Some(cert) = self.map.get(hostname.into()) {
|
||||
let cert_box = Arc::new(cert);
|
||||
return Some(&cert_box);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
use sha2::Digest;
|
||||
use url::form_urlencoded;
|
||||
|
||||
pub fn url_decode(url: &[u8]) -> String {
|
||||
let decoded: String = form_urlencoded::parse(url)
|
||||
.map(|(key, val)| [key, val].concat())
|
||||
.collect();
|
||||
return decoded
|
||||
return decoded;
|
||||
}
|
||||
|
||||
pub fn fingerhex(x509: &openssl::x509::X509) -> String {
|
||||
let finger = match x509.digest(openssl::hash::MessageDigest::sha256()) {
|
||||
Ok(f) => f,
|
||||
_ => return "".to_string(),
|
||||
};
|
||||
pub fn fingerhex(x509: &[u8]) -> String {
|
||||
let mut finger = sha2::Sha256::new();
|
||||
finger.update(&x509);
|
||||
let finger = finger.finalize();
|
||||
let mut hex: String = String::from("SHA256:");
|
||||
for f in finger.as_ref() {
|
||||
for f in finger {
|
||||
hex.push_str(&format!("{:02X}", f));
|
||||
}
|
||||
hex
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
use crate::status;
|
||||
use crate::lib::errors;
|
||||
use crate::status;
|
||||
use log::{info, warn};
|
||||
use std::net::SocketAddr;
|
||||
|
||||
pub fn init(loglev: &Option<String>) -> errors::Result {
|
||||
let loglev = match loglev {
|
||||
None => log::Level::Info,
|
||||
Some(l) => {
|
||||
match l.as_str() {
|
||||
"error" => log::Level::Error,
|
||||
"warn" => log::Level::Warn,
|
||||
"info" => log::Level::Info,
|
||||
_ => {
|
||||
return Err(Box::new(errors::GemError("Incorrect log level in config file.".to_string())));
|
||||
},
|
||||
Some(l) => match l.as_str() {
|
||||
"error" => log::Level::Error,
|
||||
"warn" => log::Level::Warn,
|
||||
"info" => log::Level::Info,
|
||||
_ => {
|
||||
return Err(Box::new(errors::GemError(
|
||||
"Incorrect log level in config file.".to_string(),
|
||||
)));
|
||||
}
|
||||
},
|
||||
};
|
||||
simple_logger::init_with_level(loglev).unwrap();
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub fn logger(addr: SocketAddr, stat: status::Status, req: &str) {
|
||||
|
||||
64
src/main.rs
64
src/main.rs
@@ -4,19 +4,21 @@ extern crate serde_derive;
|
||||
use std::io;
|
||||
use std::net::ToSocketAddrs;
|
||||
|
||||
mod lib;
|
||||
#[cfg(any(feature = "cgi", feature = "scgi"))]
|
||||
mod cgi;
|
||||
mod config;
|
||||
mod logger;
|
||||
mod revproxy;
|
||||
mod con_handler;
|
||||
mod config;
|
||||
mod lib;
|
||||
mod logger;
|
||||
#[cfg(feature = "proxy")]
|
||||
mod revproxy;
|
||||
|
||||
use lib::util;
|
||||
use lib::conn;
|
||||
use lib::status;
|
||||
use lib::tls;
|
||||
use lib::server;
|
||||
use lib::errors;
|
||||
use lib::server;
|
||||
use lib::status;
|
||||
use lib::tls::{self, tls_acceptor_conf};
|
||||
use lib::util;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> errors::Result {
|
||||
@@ -25,39 +27,51 @@ async fn main() -> errors::Result {
|
||||
Err(e) => {
|
||||
eprintln!("Config error: {}", e);
|
||||
return Ok(());
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
logger::init(&cfg.log)?;
|
||||
|
||||
|
||||
let cmap = cfg.to_map();
|
||||
let default = &cfg.server[0].hostname;
|
||||
println!("Serving {} vhosts", cfg.server.len());
|
||||
|
||||
let mut addr: Vec<std::net::SocketAddr> = Vec::new();
|
||||
if cfg.host.is_some() && cfg.port.is_some() {
|
||||
addr.push(format!("{}:{}", &cfg.host.to_owned().unwrap(), &cfg.port.unwrap())
|
||||
.to_socket_addrs()?.next()
|
||||
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?);
|
||||
addr.push(
|
||||
format!("{}:{}", &cfg.host.to_owned().unwrap(), &cfg.port.unwrap())
|
||||
.to_socket_addrs()?
|
||||
.next()
|
||||
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?,
|
||||
);
|
||||
} else {
|
||||
match &cfg.interface {
|
||||
Some(i) => {
|
||||
for iface in i {
|
||||
addr.push(iface
|
||||
.to_socket_addrs()?.next()
|
||||
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?);
|
||||
}
|
||||
},
|
||||
None => {},
|
||||
addr.push(
|
||||
iface
|
||||
.to_socket_addrs()?
|
||||
.next()
|
||||
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?,
|
||||
);
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
addr.sort_by(|a, b| a.port().cmp(&b.port()));
|
||||
addr.dedup();
|
||||
|
||||
let server = server::Server::bind(addr, tls::acceptor_conf, cfg.clone()).await?;
|
||||
if let Err(e) = server.serve(cmap, default.to_string(), server::force_boxed(con_handler::handle_connection)).await {
|
||||
return Err(e)
|
||||
let server = server::Server::bind(addr, tls_acceptor_conf, cfg.clone()).await?;
|
||||
if let Err(e) = server
|
||||
.serve(
|
||||
cmap,
|
||||
default.to_string(),
|
||||
server::force_boxed(con_handler::handle_connection),
|
||||
)
|
||||
.await
|
||||
{
|
||||
return Err(e);
|
||||
};
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
#![cfg(feature = "proxy")]
|
||||
use openssl::ssl::{SslConnector, SslMethod};
|
||||
use std::convert::TryFrom;
|
||||
use std::io;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpStream;
|
||||
|
||||
use tokio_rustls::rustls;
|
||||
use tokio_rustls::TlsConnector;
|
||||
|
||||
use crate::conn;
|
||||
use crate::logger;
|
||||
use crate::status::Status;
|
||||
use crate::tls;
|
||||
|
||||
pub async fn proxy(addr: String, u: url::Url, mut con: conn::Connection) -> Result<(), io::Error> {
|
||||
let p: Vec<&str> = u.path().trim_start_matches("/").splitn(2, "/").collect();
|
||||
@@ -22,32 +26,25 @@ pub async fn proxy(addr: String, u: url::Url, mut con: conn::Connection) -> Resu
|
||||
con.send_status(Status::NotFound, None).await?;
|
||||
return Ok(());
|
||||
}
|
||||
let domain = &addr;
|
||||
let addr = addr
|
||||
.to_socket_addrs()?
|
||||
.next()
|
||||
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?;
|
||||
|
||||
let mut connector = SslConnector::builder(SslMethod::tls()).unwrap();
|
||||
connector.set_verify(openssl::ssl::SslVerifyMode::NONE);
|
||||
let config = connector.build().configure().unwrap().into_ssl("localhost").unwrap();
|
||||
let config = rustls::ClientConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_custom_certificate_verifier(Arc::new(tls::GeminiServerAuth))
|
||||
.with_no_client_auth();
|
||||
let connector = TlsConnector::from(Arc::new(config));
|
||||
|
||||
let stream = TcpStream::connect(&addr).await?;
|
||||
|
||||
let domain = rustls::ServerName::try_from(domain.as_str())
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid dnsname"))?;
|
||||
|
||||
let mut stream = connector.connect(domain, stream).await?;
|
||||
|
||||
let stream = match TcpStream::connect(&addr).await {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
logger::logger(con.peer_addr, Status::ProxyError, u.as_str());
|
||||
con.send_status(Status::ProxyError, None).await?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let mut stream = tokio_openssl::SslStream::new(config, stream).unwrap();
|
||||
match Pin::new(&mut stream).connect().await {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
logger::logger(con.peer_addr, Status::ProxyError, u.as_str());
|
||||
con.send_status(Status::ProxyError, None).await?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
stream.write_all(p[1].as_bytes()).await?;
|
||||
stream.flush().await?;
|
||||
|
||||
@@ -58,32 +55,25 @@ pub async fn proxy(addr: String, u: url::Url, mut con: conn::Connection) -> Resu
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn proxy_all(addr: &str, u: url::Url, mut con: conn::Connection) -> Result<(), io::Error> {
|
||||
let mut connector = SslConnector::builder(SslMethod::tls()).unwrap();
|
||||
connector.set_verify(openssl::ssl::SslVerifyMode::NONE);
|
||||
pub async fn proxy_all(
|
||||
addr: &str,
|
||||
u: url::Url,
|
||||
mut con: conn::Connection,
|
||||
) -> Result<(), io::Error> {
|
||||
let domain = addr.splitn(2, ':').next().unwrap();
|
||||
let config = connector.build().configure().unwrap().into_ssl(domain).unwrap();
|
||||
|
||||
// TCP handshake
|
||||
let stream = match TcpStream::connect(&addr).await {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
logger::logger(con.peer_addr, Status::ProxyError, u.as_str());
|
||||
con.send_status(Status::ProxyError, None).await?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let config = rustls::ClientConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_custom_certificate_verifier(Arc::new(tls::GeminiServerAuth))
|
||||
.with_no_client_auth();
|
||||
let connector = TlsConnector::from(Arc::new(config));
|
||||
|
||||
// TLS handshake with SNI
|
||||
let mut stream = tokio_openssl::SslStream::new(config, stream).unwrap();
|
||||
match Pin::new(&mut stream).connect().await {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
logger::logger(con.peer_addr, Status::ProxyError, u.as_str());
|
||||
con.send_status(Status::ProxyError, None).await?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let stream = TcpStream::connect(&addr).await?;
|
||||
|
||||
let domain = rustls::ServerName::try_from(domain)
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid dnsname"))?;
|
||||
|
||||
let mut stream = connector.connect(domain, stream).await?;
|
||||
|
||||
// send request: URL + CRLF
|
||||
stream.write_all(u.as_ref().as_bytes()).await?;
|
||||
|
||||
Reference in New Issue
Block a user