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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
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]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -47,6 +68,16 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
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]]
|
[[package]]
|
||||||
name = "colored"
|
name = "colored"
|
||||||
version = "1.9.3"
|
version = "1.9.3"
|
||||||
@@ -59,19 +90,52 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types"
|
name = "cpufeatures"
|
||||||
version = "0.3.2"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"foreign-types-shared",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types-shared"
|
name = "data-encoding"
|
||||||
version = "0.1.1"
|
version = "2.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
@@ -122,20 +186,32 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gemserv"
|
name = "gemserv"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"log",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
"new_mime_guess",
|
"new_mime_guess",
|
||||||
"openssl",
|
"rustls-pemfile",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
|
"sha2",
|
||||||
"simple_logger",
|
"simple_logger",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-openssl",
|
"tokio-rustls",
|
||||||
"toml",
|
"toml",
|
||||||
"url",
|
"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]]
|
[[package]]
|
||||||
@@ -179,6 +255,15 @@ version = "0.4.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
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]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -227,6 +312,12 @@ version = "0.3.16"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.7.14"
|
version = "0.7.14"
|
||||||
@@ -261,6 +352,17 @@ dependencies = [
|
|||||||
"unicase",
|
"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]]
|
[[package]]
|
||||||
name = "ntapi"
|
name = "ntapi"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
@@ -270,6 +372,36 @@ dependencies = [
|
|||||||
"winapi",
|
"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]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
@@ -280,6 +412,15 @@ dependencies = [
|
|||||||
"libc",
|
"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]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
@@ -287,31 +428,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "opaque-debug"
|
||||||
version = "0.10.38"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
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",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
@@ -356,12 +476,6 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pkg-config"
|
|
||||||
version = "0.3.22"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.32"
|
version = "1.0.32"
|
||||||
@@ -389,12 +503,67 @@ dependencies = [
|
|||||||
"bitflags",
|
"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]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
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]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.130"
|
version = "1.0.130"
|
||||||
@@ -412,6 +581,19 @@ dependencies = [
|
|||||||
"syn",
|
"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]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -446,6 +628,12 @@ version = "1.7.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.82"
|
version = "1.0.82"
|
||||||
@@ -457,6 +645,26 @@ dependencies = [
|
|||||||
"unicode-xid",
|
"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]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
@@ -521,15 +729,14 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-openssl"
|
name = "tokio-rustls"
|
||||||
version = "0.6.3"
|
version = "0.23.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08f9ffb7809f1b20c1b398d92acf4cc719874b3b2b2d9ea2f09b4a80350878a"
|
checksum = "4baa378e417d780beff82bf54ceb0d195193ea6a00c14e22359e7f39456b5689"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
"rustls",
|
||||||
"openssl",
|
|
||||||
"openssl-sys",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"webpki",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -541,6 +748,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
@@ -571,6 +784,12 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.2.2"
|
version = "2.2.2"
|
||||||
@@ -583,18 +802,86 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vcpkg"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
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]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
@@ -616,3 +903,20 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
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]
|
[package]
|
||||||
name = "gemserv"
|
name = "gemserv"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
authors = ["int 80h <int@80h.dev>"]
|
authors = ["int 80h <int@80h.dev>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "A gemini server"
|
description = "A gemini server"
|
||||||
@@ -15,8 +15,7 @@ license = "MIT"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tokio = { version = "1.14", features = [ "full" ] }
|
tokio = { version = "1.14", features = [ "full" ] }
|
||||||
openssl = "0.10.38"
|
rustls-pemfile = "0.2.1"
|
||||||
tokio-openssl = "0.6.3"
|
|
||||||
futures-util = "0.3.18"
|
futures-util = "0.3.18"
|
||||||
toml = "0.5.8"
|
toml = "0.5.8"
|
||||||
serde = "1.0.130"
|
serde = "1.0.130"
|
||||||
@@ -26,6 +25,13 @@ new_mime_guess = "3.0.2"
|
|||||||
mime = "0.3.16"
|
mime = "0.3.16"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
simple_logger = "1.15"
|
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]
|
[features]
|
||||||
default = [ "cgi", "scgi", "proxy" ]
|
default = [ "cgi", "scgi", "proxy" ]
|
||||||
|
|||||||
2
README
2
README
@@ -13,8 +13,6 @@ A gemini server written in rust.
|
|||||||
|
|
||||||
## Installation and running
|
## 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
|
To run either run "cargo run /path/to/config" or if no configuration is
|
||||||
specified it will look for "/usr/local/etc/gemserv.conf"
|
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::io;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
#[cfg(feature = "cgi")]
|
|
||||||
use tokio::process::Command;
|
|
||||||
#[cfg(feature = "cgi")]
|
#[cfg(feature = "cgi")]
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
#[cfg(feature = "cgi")]
|
||||||
|
use tokio::process::Command;
|
||||||
|
|
||||||
|
use tokio_rustls::rustls::ServerConnection;
|
||||||
|
|
||||||
#[cfg(feature = "scgi")]
|
#[cfg(feature = "scgi")]
|
||||||
use std::net::ToSocketAddrs;
|
use std::net::ToSocketAddrs;
|
||||||
@@ -22,39 +24,51 @@ use crate::status::Status;
|
|||||||
use crate::util;
|
use crate::util;
|
||||||
|
|
||||||
#[cfg(any(feature = "cgi", feature = "scgi"))]
|
#[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();
|
let mut envs = HashMap::new();
|
||||||
envs.insert("GATEWAY_INTERFACE".to_string(), "CGI/1.1".to_string());
|
envs.insert("GATEWAY_INTERFACE".to_string(), "CGI/1.1".to_string());
|
||||||
envs.insert("GEMINI_URL".to_string(), url.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());
|
envs.insert("SERVER_PROTOCOL".to_string(), "GEMINI".to_string());
|
||||||
let addr = peer_addr.ip().to_string();
|
let addr = peer_addr.ip().to_string();
|
||||||
envs.insert("REMOTE_ADDR".to_string(), addr.clone());
|
envs.insert("REMOTE_ADDR".to_string(), addr.clone());
|
||||||
envs.insert("REMOTE_HOST".to_string(), addr);
|
envs.insert("REMOTE_HOST".to_string(), addr);
|
||||||
let port = peer_addr.port().to_string();
|
let port = peer_addr.port().to_string();
|
||||||
envs.insert("REMOTE_PORT".to_string(), port);
|
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() {
|
if let Some(q) = url.query() {
|
||||||
envs.insert("QUERY_STRING".to_string(), q.to_string());
|
envs.insert("QUERY_STRING".to_string(), q.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
match x509 {
|
if let Some(cert) = session.peer_certificates() {
|
||||||
Some(x) => {
|
let cert = tokio_rustls::rustls::Certificate::as_ref(&cert[0]);
|
||||||
envs.insert("AUTH_TYPE".to_string(), "Certificate".to_string());
|
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);
|
envs.insert("AUTH_TYPE".to_string(), "Certificate".to_string());
|
||||||
for c in cn {
|
envs.insert("REMOTE_USER".to_string(), user.to_string());
|
||||||
let cd = match c.data().as_utf8() {
|
envs.insert("TLS_CLIENT_HASH".to_string(), util::fingerhex(&cert));
|
||||||
Ok(n) => n.to_string(),
|
|
||||||
_ => "".to_string(),
|
|
||||||
};
|
|
||||||
envs.insert("REMOTE_USER".to_string(), cd);
|
|
||||||
}
|
}
|
||||||
|
Err(_) => {}
|
||||||
envs.insert("TLS_CLIENT_HASH".to_string(), util::fingerhex(&x));
|
}
|
||||||
},
|
|
||||||
None => {},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match &srv.server.cgienv {
|
match &srv.server.cgienv {
|
||||||
@@ -73,15 +87,15 @@ fn check(byt: u8, peer_addr: SocketAddr, u: &url::Url) -> bool {
|
|||||||
match byt {
|
match byt {
|
||||||
49 => {
|
49 => {
|
||||||
logger::logger(peer_addr, Status::Input, u.as_str());
|
logger::logger(peer_addr, Status::Input, u.as_str());
|
||||||
},
|
}
|
||||||
50 => {
|
50 => {
|
||||||
logger::logger(peer_addr, Status::Success, u.as_str());
|
logger::logger(peer_addr, Status::Success, u.as_str());
|
||||||
},
|
}
|
||||||
51..=54 => {}
|
51..=54 => {}
|
||||||
_ => {
|
_ => {
|
||||||
logger::logger(peer_addr, Status::CGIError, u.as_str());
|
logger::logger(peer_addr, Status::CGIError, u.as_str());
|
||||||
return false;
|
return false;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -92,19 +106,18 @@ pub async fn cgi(
|
|||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
url: &url::Url,
|
url: &url::Url,
|
||||||
script_name: String,
|
script_name: String,
|
||||||
path_info: String
|
path_info: String,
|
||||||
) -> Result<(), io::Error> {
|
) -> Result<(), io::Error> {
|
||||||
|
let (_, session) = con.stream.get_ref();
|
||||||
let x509 = con.stream.ssl().peer_certificate();
|
let mut envs = envs(con.peer_addr, session, &con.srv, &url);
|
||||||
let mut envs = envs(con.peer_addr, x509, &con.srv, &url);
|
|
||||||
envs.insert("SCRIPT_NAME".into(), script_name);
|
envs.insert("SCRIPT_NAME".into(), script_name);
|
||||||
envs.insert("PATH_INFO".into(), path_info);
|
envs.insert("PATH_INFO".into(), path_info);
|
||||||
|
|
||||||
match path.parent() {
|
match path.parent() {
|
||||||
Some(p) => {
|
Some(p) => {
|
||||||
std::env::set_current_dir(p)?;
|
std::env::set_current_dir(p)?;
|
||||||
},
|
}
|
||||||
None => {},
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let cmd = Command::new(path.to_str().unwrap())
|
let cmd = Command::new(path.to_str().unwrap())
|
||||||
@@ -113,22 +126,20 @@ pub async fn cgi(
|
|||||||
.output();
|
.output();
|
||||||
|
|
||||||
let cmd = match tokio::time::timeout(tokio::time::Duration::from_secs(5), cmd).await {
|
let cmd = match tokio::time::timeout(tokio::time::Duration::from_secs(5), cmd).await {
|
||||||
Ok(c) => {
|
Ok(c) => match c {
|
||||||
match c {
|
Ok(cc) => cc,
|
||||||
Ok(cc) => cc,
|
|
||||||
|
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
logger::logger(con.peer_addr, Status::CGIError, url.as_str());
|
logger::logger(con.peer_addr, Status::CGIError, url.as_str());
|
||||||
con.send_status(Status::CGIError, None).await?;
|
con.send_status(Status::CGIError, None).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
logger::logger(con.peer_addr, Status::CGIError, url.as_str());
|
logger::logger(con.peer_addr, Status::CGIError, url.as_str());
|
||||||
con.send_status(Status::CGIError, None).await?;
|
con.send_status(Status::CGIError, None).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cmd.status.success() {
|
if !cmd.status.success() {
|
||||||
@@ -161,11 +172,15 @@ pub async fn scgi(addr: String, u: url::Url, mut con: conn::Connection) -> Resul
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let x509 = con.stream.ssl().peer_certificate();
|
let (_, session) = con.stream.get_ref();
|
||||||
let envs = envs(con.peer_addr, x509, &con.srv, &u);
|
let envs = envs(con.peer_addr, session, &con.srv, &u);
|
||||||
let len = 0usize;
|
let len = 0usize;
|
||||||
let mut byt = String::from(format!("CONTENT_LENGTH\x00{}\x00SCGI\x001\x00
|
let mut byt = String::from(format!(
|
||||||
RQUEST_METHOD\x00POST\x00REQUEST_URI\x00{}\x00", len, u.path()));
|
"CONTENT_LENGTH\x00{}\x00SCGI\x001\x00
|
||||||
|
RQUEST_METHOD\x00POST\x00REQUEST_URI\x00{}\x00",
|
||||||
|
len,
|
||||||
|
u.path()
|
||||||
|
));
|
||||||
for (k, v) in envs.iter() {
|
for (k, v) in envs.iter() {
|
||||||
byt.push_str(&format!("{}\x00{}\x00", k, v));
|
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![];
|
let mut buf = vec![];
|
||||||
if let Err(_) = tokio::time::timeout(
|
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());
|
logger::logger(con.peer_addr, Status::CGIError, u.as_str());
|
||||||
con.send_status(Status::CGIError, None).await?;
|
con.send_status(Status::CGIError, None).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|||||||
@@ -6,14 +6,16 @@ use std::os::unix::fs::PermissionsExt;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::util;
|
#[cfg(any(feature = "cgi", feature = "scgi"))]
|
||||||
use crate::conn;
|
|
||||||
use crate::status::Status;
|
|
||||||
use crate::cgi;
|
use crate::cgi;
|
||||||
|
use crate::conn;
|
||||||
use crate::logger;
|
use crate::logger;
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
use crate::revproxy;
|
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 {
|
fn get_mime(path: &PathBuf) -> String {
|
||||||
let mut mime = "text/gemini".to_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<()> {
|
async fn get_binary(mut con: conn::Connection, path: PathBuf, meta: String) -> io::Result<()> {
|
||||||
let fd = File::open(path)?;
|
let fd = File::open(path)?;
|
||||||
let mut reader = BufReader::with_capacity(1024 * 1024, fd);
|
let mut reader = BufReader::with_capacity(1024 * 1024, fd);
|
||||||
con.send_status(Status::Success, Some(&meta))
|
con.send_status(Status::Success, Some(&meta)).await?;
|
||||||
.await?;
|
|
||||||
loop {
|
loop {
|
||||||
let len = {
|
let len = {
|
||||||
let buf = reader.fill_buf()?;
|
let buf = reader.fill_buf()?;
|
||||||
@@ -132,33 +133,30 @@ async fn handle_cgi(
|
|||||||
|
|
||||||
match &con.srv.server.cgipath {
|
match &con.srv.server.cgipath {
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
if path.starts_with(c) {
|
if path.starts_with(c) {
|
||||||
if perm.mode() & 0o0111 == 0o0111 {
|
if perm.mode() & 0o0111 == 0o0111 {
|
||||||
cgi::cgi(con, path, url, script_name, path_info).await?;
|
cgi::cgi(con, path, url, script_name, path_info).await?;
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
} else {
|
} else {
|
||||||
logger::logger(con.peer_addr, Status::CGIError, request);
|
logger::logger(con.peer_addr, Status::CGIError, request);
|
||||||
con.send_status(Status::CGIError, None).await?;
|
con.send_status(Status::CGIError, None).await?;
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
None => {
|
None => {
|
||||||
if meta.is_file() && perm.mode() & 0o0111 == 0o0111 {
|
if meta.is_file() && perm.mode() & 0o0111 == 0o0111 {
|
||||||
cgi::cgi(con, path, url, script_name, path_info).await?;
|
cgi::cgi(con, path, url, script_name, path_info).await?;
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Rewrite this monster.
|
// TODO Rewrite this monster.
|
||||||
pub async fn handle_connection(
|
pub async fn handle_connection(mut con: conn::Connection, url: url::Url) -> Result {
|
||||||
mut con: conn::Connection,
|
|
||||||
url: url::Url
|
|
||||||
) -> Result {
|
|
||||||
let index = match &con.srv.server.index {
|
let index = match &con.srv.server.index {
|
||||||
Some(i) => i.clone(),
|
Some(i) => i.clone(),
|
||||||
None => "index.gemini".to_string(),
|
None => "index.gemini".to_string(),
|
||||||
@@ -223,18 +221,17 @@ pub async fn handle_connection(
|
|||||||
"/" => "/",
|
"/" => "/",
|
||||||
_ => url.path().trim_end_matches("/"),
|
_ => url.path().trim_end_matches("/"),
|
||||||
};
|
};
|
||||||
match sc.get(u) {
|
match sc.get(u) {
|
||||||
Some(r) => {
|
Some(r) => {
|
||||||
cgi::scgi(r.to_string(), url, con).await?;
|
cgi::scgi(r.to_string(), url, con).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
None => {}
|
|
||||||
}
|
}
|
||||||
},
|
None => {}
|
||||||
None => {},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let mut path = PathBuf::new();
|
let mut path = PathBuf::new();
|
||||||
|
|
||||||
if url.path().starts_with("/~") && con.srv.server.usrdir.unwrap_or(false) {
|
if url.path().starts_with("/~") && con.srv.server.usrdir.unwrap_or(false) {
|
||||||
@@ -246,7 +243,12 @@ pub async fn handle_connection(
|
|||||||
path.push("/home/");
|
path.push("/home/");
|
||||||
}
|
}
|
||||||
if usr.len() == 2 {
|
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 {
|
} else {
|
||||||
path.push(format!("{}/{}/", usr[0], "public_gemini"));
|
path.push(format!("{}/{}/", usr[0], "public_gemini"));
|
||||||
}
|
}
|
||||||
@@ -304,13 +306,13 @@ pub async fn handle_connection(
|
|||||||
return Ok(());
|
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());
|
logger::logger(con.peer_addr, Status::NotFound, &url.as_str());
|
||||||
con.send_status(Status::NotFound, None).await?;
|
con.send_status(Status::NotFound, None).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if perm.mode() & 0o0444 != 0o0444 {
|
if perm.mode() & 0o0444 != 0o0444 {
|
||||||
logger::logger(con.peer_addr, Status::NotFound, &url.as_str());
|
logger::logger(con.peer_addr, Status::NotFound, &url.as_str());
|
||||||
con.send_status(Status::NotFound, None).await?;
|
con.send_status(Status::NotFound, None).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
use tokio::fs;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::path;
|
|
||||||
use std::env;
|
|
||||||
use crate::lib::errors;
|
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)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
@@ -43,7 +43,7 @@ pub struct Server {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ServerCfg {
|
pub struct ServerCfg {
|
||||||
// pub port: u16,
|
// pub port: u16,
|
||||||
pub server: Server,
|
pub server: Server,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,9 @@ impl Config {
|
|||||||
if !p.exists() {
|
if !p.exists() {
|
||||||
return Err(Box::new(errors::GemError(
|
return Err(Box::new(errors::GemError(
|
||||||
"Please run with the path to the config file. \
|
"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 {
|
} else {
|
||||||
p.push(&args[1]);
|
p.push(&args[1]);
|
||||||
@@ -67,22 +69,30 @@ impl Config {
|
|||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => return Err(Box::new(e)),
|
Err(e) => return Err(Box::new(e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
if config.host.is_some() || config.port.is_some() {
|
if config.host.is_some() || config.port.is_some() {
|
||||||
eprintln!("The host/port keys are depricated in favor \
|
eprintln!(
|
||||||
of interface and may be removed in the future.");
|
"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()) {
|
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() {
|
} 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() {
|
} else if config.host.is_some() && config.port.is_some() {
|
||||||
return Ok(config);
|
return Ok(config);
|
||||||
} else if config.interface.is_some() {
|
} else if config.interface.is_some() {
|
||||||
return Ok(config);
|
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> {
|
pub fn to_map(&self) -> HashMap<String, ServerCfg> {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
@@ -90,11 +100,11 @@ impl Config {
|
|||||||
map.insert(
|
map.insert(
|
||||||
srv.hostname.clone(),
|
srv.hostname.clone(),
|
||||||
ServerCfg {
|
ServerCfg {
|
||||||
// port: self.port.clone(),
|
// port: self.port.clone(),
|
||||||
server: srv.clone(),
|
server: srv.clone(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,15 @@ use std::io;
|
|||||||
use std::marker::Unpin;
|
use std::marker::Unpin;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
use tokio::net::TcpStream;
|
|
||||||
use tokio::io::AsyncRead;
|
use tokio::io::AsyncRead;
|
||||||
use tokio::io::{AsyncWrite, AsyncWriteExt};
|
use tokio::io::{AsyncWrite, AsyncWriteExt};
|
||||||
use tokio_openssl::SslStream;
|
use tokio::net::TcpStream;
|
||||||
|
use tokio_rustls::server::TlsStream;
|
||||||
|
|
||||||
use crate::status::Status;
|
use crate::status::Status;
|
||||||
|
|
||||||
pub struct Connection {
|
pub struct Connection {
|
||||||
pub stream: SslStream<TcpStream>,
|
pub stream: TlsStream<TcpStream>,
|
||||||
pub local_addr: SocketAddr,
|
pub local_addr: SocketAddr,
|
||||||
pub peer_addr: SocketAddr,
|
pub peer_addr: SocketAddr,
|
||||||
pub srv: crate::config::ServerCfg,
|
pub srv: crate::config::ServerCfg,
|
||||||
@@ -38,7 +38,11 @@ impl Connection {
|
|||||||
self.send_raw(b.as_bytes()).await?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -49,9 +53,16 @@ impl Connection {
|
|||||||
Ok(())
|
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?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct GemError(pub String);
|
pub struct GemError(pub String);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
pub mod util;
|
|
||||||
pub mod status;
|
|
||||||
pub mod conn;
|
pub mod conn;
|
||||||
pub mod tls;
|
|
||||||
pub mod server;
|
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
pub mod server;
|
||||||
|
pub mod status;
|
||||||
|
pub mod tls;
|
||||||
|
pub mod util;
|
||||||
|
|||||||
@@ -1,26 +1,35 @@
|
|||||||
#![allow(unreachable_code)]
|
#![allow(unreachable_code)]
|
||||||
use tokio::net::TcpListener;
|
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
use openssl::ssl::SslAcceptor;
|
use tokio::net::TcpListener;
|
||||||
use openssl::error::ErrorStack;
|
use tokio_rustls::server::TlsStream;
|
||||||
use openssl::ssl::NameType;
|
use tokio_rustls::TlsAcceptor;
|
||||||
|
|
||||||
//use futures_util::future::TryFutureExt;
|
//use futures_util::future::TryFutureExt;
|
||||||
use url::Url;
|
|
||||||
use std::io;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::sync::Arc;
|
use std::io;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use crate::config;
|
use crate::config;
|
||||||
use crate::conn;
|
use crate::conn;
|
||||||
|
use crate::errors::{GemError, Result};
|
||||||
use crate::logger;
|
use crate::logger;
|
||||||
use crate::status::Status;
|
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 {}
|
pub trait Handler:
|
||||||
impl<T> Handler for T
|
FnMut(conn::Connection, url::Url) -> Pin<Box<dyn Future<Output = Result> + Send>>
|
||||||
where T: FnMut(conn::Connection, url::Url) -> Pin<Box<dyn Future<Output = Result> + Send>> + Send + Sync + Copy
|
+ 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 struct Server {
|
||||||
pub listener: Vec<TcpListener>,
|
pub listener: Vec<TcpListener>,
|
||||||
pub acceptor: SslAcceptor,
|
pub acceptor: TlsAcceptor,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
pub async fn bind(addr: Vec<std::net::SocketAddr>,
|
pub async fn bind(
|
||||||
acceptor: fn(config::Config) -> std::result::Result<SslAcceptor, ErrorStack>,
|
addr: Vec<std::net::SocketAddr>,
|
||||||
cfg: config::Config) -> io::Result<Server>
|
acceptor: fn(config::Config) -> std::io::Result<TlsAcceptor>,
|
||||||
{
|
cfg: config::Config,
|
||||||
|
) -> Result<Server> {
|
||||||
if addr.len() == 1 {
|
if addr.len() == 1 {
|
||||||
Ok(Server {
|
Ok(Server {
|
||||||
listener: vec![TcpListener::bind(addr[0].to_owned()).await?],
|
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,
|
pub async fn serve(
|
||||||
handler: impl Handler + 'static + Copy) -> Result
|
self,
|
||||||
{
|
cmap: HashMap<String, config::ServerCfg>,
|
||||||
for listen in self.listener {
|
default: String,
|
||||||
|
handler: impl Handler + 'static + Copy,
|
||||||
|
) -> Result {
|
||||||
|
for listen in self.listener {
|
||||||
let cmap = cmap.clone();
|
let cmap = cmap.clone();
|
||||||
let default = default.clone();
|
let default = default.clone();
|
||||||
let listen = Arc::new(listen);
|
let listen = Arc::new(listen);
|
||||||
let acceptor = Arc::new(self.acceptor.clone());
|
let acceptor = Arc::new(self.acceptor.clone());
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
let (stream, peer_addr) = listen.accept().await?;
|
let (stream, peer_addr) = listen.accept().await?;
|
||||||
@@ -75,31 +89,37 @@ impl Server {
|
|||||||
let default = default.clone();
|
let default = default.clone();
|
||||||
let mut handler = handler.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 {
|
tokio::spawn(async move {
|
||||||
match Pin::new(&mut stream).accept().await {
|
let mut stream = match acceptor.accept(stream).await {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Error: {}",e);
|
log::error!("Error: {}", e);
|
||||||
return Ok(());
|
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 {
|
let (con, url) = match get_request(con).await {
|
||||||
Ok((c, u)) => (c, u),
|
Ok((c, u)) => (c, u),
|
||||||
Err(_) => return Ok(()) as io::Result<()>,
|
Err(_) => return Ok(()) as io::Result<()>,
|
||||||
};
|
};
|
||||||
|
|
||||||
match handler(con, url).await {
|
match handler(con, url).await {
|
||||||
Ok(o) => o,
|
Ok(o) => o,
|
||||||
Err(_) => return Ok(()) as io::Result<()>,
|
Err(_) => return Ok(()) as io::Result<()>,
|
||||||
@@ -111,18 +131,27 @@ impl Server {
|
|||||||
Ok(()) as io::Result<()>
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_request(mut con: conn::Connection) -> Result<(conn::Connection, url::Url)> {
|
pub async fn get_request(mut con: conn::Connection) -> Result<(conn::Connection, url::Url)> {
|
||||||
let mut buffer = [0; 1024];
|
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(),
|
Ok(result) => result.unwrap(),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logger::logger(con.peer_addr, Status::BadRequest, "");
|
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));
|
return Err(Box::new(e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -130,7 +159,9 @@ pub async fn get_request(mut con: conn::Connection) -> Result<(conn::Connection,
|
|||||||
Ok(request) => request,
|
Ok(request) => request,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logger::logger(con.peer_addr, Status::BadRequest, "");
|
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));
|
return Err(Box::new(e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -149,7 +180,9 @@ pub async fn get_request(mut con: conn::Connection) -> Result<(conn::Connection,
|
|||||||
Ok(url) => url,
|
Ok(url) => url,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logger::logger(con.peer_addr, Status::BadRequest, &request);
|
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));
|
return Err(Box::new(e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -158,10 +191,12 @@ pub async fn get_request(mut con: conn::Connection) -> Result<(conn::Connection,
|
|||||||
Some(h) => {
|
Some(h) => {
|
||||||
if con.srv.server.hostname.as_str() != h.to_lowercase() {
|
if con.srv.server.hostname.as_str() != h.to_lowercase() {
|
||||||
logger::logger(con.peer_addr, Status::ProxyRequestRefused, &url.as_str());
|
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())));
|
return Err(Box::new(GemError("Wrong host".into())));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
match url.port() {
|
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() {
|
if p != con.local_addr.port() {
|
||||||
logger::logger(con.peer_addr, Status::ProxyRequestRefused, &url.as_str());
|
logger::logger(con.peer_addr, Status::ProxyRequestRefused, &url.as_str());
|
||||||
con.send_status(Status::ProxyRequestRefused, None)
|
con.send_status(Status::ProxyRequestRefused, None)
|
||||||
.await.map_err(|e| e.to_string())?;
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
if url.scheme() != "gemini" {
|
if url.scheme() != "gemini" {
|
||||||
logger::logger(con.peer_addr, Status::ProxyRequestRefused, &url.as_str());
|
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 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;
|
use std::fs::File;
|
||||||
extern crate tokio_openssl;
|
use std::io::{self, BufReader};
|
||||||
use std::collections::HashMap;
|
use std::sync::Arc;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use openssl::error::ErrorStack;
|
use rustls::client::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier, ServerName};
|
||||||
use openssl::ssl::NameType;
|
use rustls::internal::msgs::enums::SignatureScheme;
|
||||||
use openssl::ssl::SniError;
|
use rustls::internal::msgs::handshake::DigitallySignedStruct;
|
||||||
use openssl::ssl::SslContextBuilder;
|
use rustls::internal::msgs::handshake::DistinguishedNames;
|
||||||
use openssl::ssl::SslVersion;
|
use rustls::server::{ClientCertVerified, ClientCertVerifier, ResolvesServerCertUsingSni};
|
||||||
use openssl::ssl::SslVerifyMode;
|
use rustls::sign::{self, CertifiedKey};
|
||||||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
use rustls::{Certificate, Error, PrivateKey};
|
||||||
|
use rustls_pemfile::{certs, pkcs8_private_keys};
|
||||||
|
use tokio_rustls::rustls;
|
||||||
|
use tokio_rustls::TlsAcceptor;
|
||||||
|
|
||||||
use crate::config;
|
use crate::config;
|
||||||
|
|
||||||
pub fn acceptor_conf(cfg: config::Config) -> Result<SslAcceptor, ErrorStack> {
|
pub fn tls_acceptor_conf(cfg: config::Config) -> io::Result<TlsAcceptor> {
|
||||||
let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls_server())?;
|
let resolver = load_keypair(cfg)?;
|
||||||
acceptor.set_min_proto_version(Some(SslVersion::TLS1_2))?;
|
let config = rustls::server::ServerConfig::builder()
|
||||||
let mut map = HashMap::new();
|
.with_safe_defaults()
|
||||||
let mut num = 1;
|
.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() {
|
for server in cfg.server.iter() {
|
||||||
let mut ctx = SslContextBuilder::new(SslMethod::tls_server())?;
|
let key = load_key(&server.key)?.remove(0);
|
||||||
ctx.set_verify(SslVerifyMode::NONE);
|
let certs = load_certs(&server.cert)?;
|
||||||
match ctx.set_private_key_file(&server.key, SslFiletype::PEM) {
|
let signing_key = sign::any_supported_type(&key).expect("error loading key");
|
||||||
Ok(c) => c,
|
|
||||||
Err(e) => {
|
resolver
|
||||||
log::error!("Error: Can't load key file");
|
.add(
|
||||||
return Err(e);
|
&server.hostname.clone(),
|
||||||
}
|
CertifiedKey::new(certs, signing_key),
|
||||||
};
|
)
|
||||||
match ctx.set_certificate_chain_file(&server.cert) {
|
.expect("error loading key");
|
||||||
Ok(c) => c,
|
}
|
||||||
Err(e) => {
|
Ok(resolver)
|
||||||
log::error!("Error: Can't load cert file");
|
}
|
||||||
return Err(e);
|
|
||||||
}
|
struct GeminiClientAuth;
|
||||||
};
|
|
||||||
let ctx = ctx.build();
|
impl ClientCertVerifier for GeminiClientAuth {
|
||||||
map.insert(server.hostname.clone(), ctx.clone());
|
fn client_auth_root_subjects(&self) -> Option<DistinguishedNames> {
|
||||||
if num == 1 {
|
Some(Vec::new())
|
||||||
map.insert("default".to_string(), ctx);
|
|
||||||
num += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let ctx_builder = &mut *acceptor;
|
fn verify_client_cert(
|
||||||
ctx_builder.set_servername_callback(move |ssl, _alert| -> Result<(), SniError> {
|
&self,
|
||||||
ssl.set_ssl_context({
|
_end_entity: &Certificate,
|
||||||
let hostname = ssl.servername(NameType::HOST_NAME);
|
_intermidiates: &[Certificate],
|
||||||
if let Some(host) = hostname {
|
_now: SystemTime,
|
||||||
if let Some(ctx) = map.get(host) {
|
) -> Result<ClientCertVerified, Error> {
|
||||||
&ctx
|
Ok(ClientCertVerified::assertion())
|
||||||
} 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
|
|
||||||
});
|
|
||||||
|
|
||||||
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;
|
use url::form_urlencoded;
|
||||||
|
|
||||||
pub fn url_decode(url: &[u8]) -> String {
|
pub fn url_decode(url: &[u8]) -> String {
|
||||||
let decoded: String = form_urlencoded::parse(url)
|
let decoded: String = form_urlencoded::parse(url)
|
||||||
.map(|(key, val)| [key, val].concat())
|
.map(|(key, val)| [key, val].concat())
|
||||||
.collect();
|
.collect();
|
||||||
return decoded
|
return decoded;
|
||||||
}
|
}
|
||||||
|
pub fn fingerhex(x509: &[u8]) -> String {
|
||||||
pub fn fingerhex(x509: &openssl::x509::X509) -> String {
|
let mut finger = sha2::Sha256::new();
|
||||||
let finger = match x509.digest(openssl::hash::MessageDigest::sha256()) {
|
finger.update(&x509);
|
||||||
Ok(f) => f,
|
let finger = finger.finalize();
|
||||||
_ => return "".to_string(),
|
|
||||||
};
|
|
||||||
let mut hex: String = String::from("SHA256:");
|
let mut hex: String = String::from("SHA256:");
|
||||||
for f in finger.as_ref() {
|
for f in finger {
|
||||||
hex.push_str(&format!("{:02X}", f));
|
hex.push_str(&format!("{:02X}", f));
|
||||||
}
|
}
|
||||||
hex
|
hex
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
use crate::status;
|
|
||||||
use crate::lib::errors;
|
use crate::lib::errors;
|
||||||
|
use crate::status;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
pub fn init(loglev: &Option<String>) -> errors::Result {
|
pub fn init(loglev: &Option<String>) -> errors::Result {
|
||||||
let loglev = match loglev {
|
let loglev = match loglev {
|
||||||
None => log::Level::Info,
|
None => log::Level::Info,
|
||||||
Some(l) => {
|
Some(l) => match l.as_str() {
|
||||||
match l.as_str() {
|
"error" => log::Level::Error,
|
||||||
"error" => log::Level::Error,
|
"warn" => log::Level::Warn,
|
||||||
"warn" => log::Level::Warn,
|
"info" => log::Level::Info,
|
||||||
"info" => log::Level::Info,
|
_ => {
|
||||||
_ => {
|
return Err(Box::new(errors::GemError(
|
||||||
return Err(Box::new(errors::GemError("Incorrect log level in config file.".to_string())));
|
"Incorrect log level in config file.".to_string(),
|
||||||
},
|
)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
simple_logger::init_with_level(loglev).unwrap();
|
simple_logger::init_with_level(loglev).unwrap();
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn logger(addr: SocketAddr, stat: status::Status, req: &str) {
|
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::io;
|
||||||
use std::net::ToSocketAddrs;
|
use std::net::ToSocketAddrs;
|
||||||
|
|
||||||
mod lib;
|
#[cfg(any(feature = "cgi", feature = "scgi"))]
|
||||||
mod cgi;
|
mod cgi;
|
||||||
mod config;
|
|
||||||
mod logger;
|
|
||||||
mod revproxy;
|
|
||||||
mod con_handler;
|
mod con_handler;
|
||||||
|
mod config;
|
||||||
|
mod lib;
|
||||||
|
mod logger;
|
||||||
|
#[cfg(feature = "proxy")]
|
||||||
|
mod revproxy;
|
||||||
|
|
||||||
use lib::util;
|
|
||||||
use lib::conn;
|
use lib::conn;
|
||||||
use lib::status;
|
|
||||||
use lib::tls;
|
|
||||||
use lib::server;
|
|
||||||
use lib::errors;
|
use lib::errors;
|
||||||
|
use lib::server;
|
||||||
|
use lib::status;
|
||||||
|
use lib::tls::{self, tls_acceptor_conf};
|
||||||
|
use lib::util;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> errors::Result {
|
async fn main() -> errors::Result {
|
||||||
@@ -25,39 +27,51 @@ async fn main() -> errors::Result {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Config error: {}", e);
|
eprintln!("Config error: {}", e);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
logger::init(&cfg.log)?;
|
logger::init(&cfg.log)?;
|
||||||
|
|
||||||
let cmap = cfg.to_map();
|
let cmap = cfg.to_map();
|
||||||
let default = &cfg.server[0].hostname;
|
let default = &cfg.server[0].hostname;
|
||||||
println!("Serving {} vhosts", cfg.server.len());
|
println!("Serving {} vhosts", cfg.server.len());
|
||||||
|
|
||||||
let mut addr: Vec<std::net::SocketAddr> = Vec::new();
|
let mut addr: Vec<std::net::SocketAddr> = Vec::new();
|
||||||
if cfg.host.is_some() && cfg.port.is_some() {
|
if cfg.host.is_some() && cfg.port.is_some() {
|
||||||
addr.push(format!("{}:{}", &cfg.host.to_owned().unwrap(), &cfg.port.unwrap())
|
addr.push(
|
||||||
.to_socket_addrs()?.next()
|
format!("{}:{}", &cfg.host.to_owned().unwrap(), &cfg.port.unwrap())
|
||||||
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?);
|
.to_socket_addrs()?
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
match &cfg.interface {
|
match &cfg.interface {
|
||||||
Some(i) => {
|
Some(i) => {
|
||||||
for iface in i {
|
for iface in i {
|
||||||
addr.push(iface
|
addr.push(
|
||||||
.to_socket_addrs()?.next()
|
iface
|
||||||
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?);
|
.to_socket_addrs()?
|
||||||
}
|
.next()
|
||||||
},
|
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?,
|
||||||
None => {},
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addr.sort_by(|a, b| a.port().cmp(&b.port()));
|
addr.sort_by(|a, b| a.port().cmp(&b.port()));
|
||||||
addr.dedup();
|
addr.dedup();
|
||||||
|
let server = server::Server::bind(addr, tls_acceptor_conf, cfg.clone()).await?;
|
||||||
let server = server::Server::bind(addr, tls::acceptor_conf, cfg.clone()).await?;
|
if let Err(e) = server
|
||||||
if let Err(e) = server.serve(cmap, default.to_string(), server::force_boxed(con_handler::handle_connection)).await {
|
.serve(
|
||||||
return Err(e)
|
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")]
|
#![cfg(feature = "proxy")]
|
||||||
use openssl::ssl::{SslConnector, SslMethod};
|
use std::convert::TryFrom;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::ToSocketAddrs;
|
use std::net::ToSocketAddrs;
|
||||||
use std::pin::Pin;
|
use std::sync::Arc;
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
|
|
||||||
|
use tokio_rustls::rustls;
|
||||||
|
use tokio_rustls::TlsConnector;
|
||||||
|
|
||||||
use crate::conn;
|
use crate::conn;
|
||||||
use crate::logger;
|
use crate::logger;
|
||||||
use crate::status::Status;
|
use crate::status::Status;
|
||||||
|
use crate::tls;
|
||||||
|
|
||||||
pub async fn proxy(addr: String, u: url::Url, mut con: conn::Connection) -> Result<(), io::Error> {
|
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();
|
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?;
|
con.send_status(Status::NotFound, None).await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
let domain = &addr;
|
||||||
let addr = addr
|
let addr = addr
|
||||||
.to_socket_addrs()?
|
.to_socket_addrs()?
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?;
|
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?;
|
||||||
|
|
||||||
let mut connector = SslConnector::builder(SslMethod::tls()).unwrap();
|
let config = rustls::ClientConfig::builder()
|
||||||
connector.set_verify(openssl::ssl::SslVerifyMode::NONE);
|
.with_safe_defaults()
|
||||||
let config = connector.build().configure().unwrap().into_ssl("localhost").unwrap();
|
.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.write_all(p[1].as_bytes()).await?;
|
||||||
stream.flush().await?;
|
stream.flush().await?;
|
||||||
|
|
||||||
@@ -58,32 +55,25 @@ pub async fn proxy(addr: String, u: url::Url, mut con: conn::Connection) -> Resu
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn proxy_all(addr: &str, u: url::Url, mut con: conn::Connection) -> Result<(), io::Error> {
|
pub async fn proxy_all(
|
||||||
let mut connector = SslConnector::builder(SslMethod::tls()).unwrap();
|
addr: &str,
|
||||||
connector.set_verify(openssl::ssl::SslVerifyMode::NONE);
|
u: url::Url,
|
||||||
|
mut con: conn::Connection,
|
||||||
|
) -> Result<(), io::Error> {
|
||||||
let domain = addr.splitn(2, ':').next().unwrap();
|
let domain = addr.splitn(2, ':').next().unwrap();
|
||||||
let config = connector.build().configure().unwrap().into_ssl(domain).unwrap();
|
|
||||||
|
|
||||||
// TCP handshake
|
let config = rustls::ClientConfig::builder()
|
||||||
let stream = match TcpStream::connect(&addr).await {
|
.with_safe_defaults()
|
||||||
Ok(s) => s,
|
.with_custom_certificate_verifier(Arc::new(tls::GeminiServerAuth))
|
||||||
Err(_) => {
|
.with_no_client_auth();
|
||||||
logger::logger(con.peer_addr, Status::ProxyError, u.as_str());
|
let connector = TlsConnector::from(Arc::new(config));
|
||||||
con.send_status(Status::ProxyError, None).await?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// TLS handshake with SNI
|
let stream = TcpStream::connect(&addr).await?;
|
||||||
let mut stream = tokio_openssl::SslStream::new(config, stream).unwrap();
|
|
||||||
match Pin::new(&mut stream).connect().await {
|
let domain = rustls::ServerName::try_from(domain)
|
||||||
Ok(s) => s,
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid dnsname"))?;
|
||||||
Err(_) => {
|
|
||||||
logger::logger(con.peer_addr, Status::ProxyError, u.as_str());
|
let mut stream = connector.connect(domain, stream).await?;
|
||||||
con.send_status(Status::ProxyError, None).await?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// send request: URL + CRLF
|
// send request: URL + CRLF
|
||||||
stream.write_all(u.as_ref().as_bytes()).await?;
|
stream.write_all(u.as_ref().as_bytes()).await?;
|
||||||
|
|||||||
Reference in New Issue
Block a user