feat: use streams for tls
This commit is contained in:
parent
be3f8f4cff
commit
c3f3321a57
369
Cargo.lock
generated
369
Cargo.lock
generated
@ -1,29 +1,174 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
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 = "bumpalo"
|
||||
version = "3.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"proc-macro-hack",
|
||||
"proc-macro-nested",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
@ -48,6 +193,21 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.88"
|
||||
@ -157,6 +317,24 @@ version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
@ -184,12 +362,59 @@ 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 = "rustls"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "064fd21ff87c6e87ed4506e68beb42459caa4a0e2eb144932e6776768556980b"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"log",
|
||||
"ring",
|
||||
"sct",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09700171bbcc799d113f2c675314d6005c3dc035f3e7307cf3e7fd459ccbe246"
|
||||
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.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.3.0"
|
||||
@ -199,6 +424,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.6.1"
|
||||
@ -216,6 +447,18 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.64"
|
||||
@ -228,17 +471,33 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tls-forward-proxy"
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tlsproxy"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"futures",
|
||||
"httparse",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"tokio",
|
||||
"webpki",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.2.0"
|
||||
source = "git+https://github.com/conblem/tokio/?branch=bidi_copy#6fe69cd16aa24623697f5f44ce4c6fabe85245b2"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d56477f6ed99e10225f38f9f75f872f29b8b8bd8c0b946f63345bb144e9eeda"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
@ -257,19 +516,121 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/conblem/tokio?branch=bidi_copy#6fe69cd16aa24623697f5f44ce4c6fabe85245b2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki"
|
||||
version = "0.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376"
|
||||
dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
11
Cargo.toml
11
Cargo.toml
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "tls-forward-proxy"
|
||||
name = "tlsproxy"
|
||||
version = "0.1.0"
|
||||
authors = ["Mahdi Dibaiee <mdibaiee@pm.me>"]
|
||||
edition = "2018"
|
||||
@ -7,6 +7,11 @@ edition = "2018"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
# tokio = { version = "1", features = ["full"] }
|
||||
tokio = { git = "https://github.com/conblem/tokio", branch = "bidi_copy", features = ["full"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
httparse = "1.3.4"
|
||||
futures = "0.3.13"
|
||||
rustls = { version = "0.19.0", features = ["dangerous_configuration"] }
|
||||
webpki = "0.21.4"
|
||||
webpki-roots = "0.21.0"
|
||||
rustls-pemfile = "0.2.0"
|
||||
clap = "2.33.3"
|
||||
|
16
src/cert.rs
Normal file
16
src/cert.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use rustls::{Certificate, RootCertStore, ServerCertVerified, ServerCertVerifier, TLSError};
|
||||
use webpki;
|
||||
|
||||
pub struct NoCertificateVerification {}
|
||||
|
||||
impl ServerCertVerifier for NoCertificateVerification {
|
||||
fn verify_server_cert(
|
||||
&self,
|
||||
_roots: &RootCertStore,
|
||||
_presented_certs: &[Certificate],
|
||||
_dns_name: webpki::DNSNameRef<'_>,
|
||||
_ocsp_response: &[u8],
|
||||
) -> Result<ServerCertVerified, TLSError> {
|
||||
Ok(ServerCertVerified::assertion())
|
||||
}
|
||||
}
|
107
src/command.rs
Normal file
107
src/command.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use rustls_pemfile;
|
||||
use std::io::BufReader;
|
||||
use std::{fs, str};
|
||||
|
||||
use clap::{App, Arg};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Args {
|
||||
pub port: u16,
|
||||
pub certs: String,
|
||||
pub key: String,
|
||||
pub replaces: Vec<String>,
|
||||
pub verbose: bool,
|
||||
}
|
||||
|
||||
pub fn args() -> Args {
|
||||
let version = env!("CARGO_PKG_NAME").to_string() + ", version: " + env!("CARGO_PKG_VERSION");
|
||||
|
||||
let matches = App::new("tlsproxy")
|
||||
.version(&*version)
|
||||
.author("Mahdi Dibaiee <mdibaiee@pm.me>")
|
||||
.about("A simple TLS forward proxy capable of replacing parts of the outgoing traffic")
|
||||
.arg(Arg::with_name("port")
|
||||
.short("p")
|
||||
.long("port")
|
||||
.value_name("PORT")
|
||||
.help("Listen on PORT [default: 8080]")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("certs")
|
||||
.long("certs")
|
||||
.value_name("FILE")
|
||||
.help("Read server certificates from FILE. This should contain PEM-format certificates in the right order. The first certificate should certify KEYFILE, the last should be a root CA.")
|
||||
.required(true)
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("key")
|
||||
.long("key")
|
||||
.value_name("FILE")
|
||||
.help("Read private key from FILE. This should be a RSA private key or PKCS8-encoded private key, in PEM format.")
|
||||
.required(true)
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("replace")
|
||||
.long("replace")
|
||||
.value_name("PATTERN")
|
||||
.help("Replace data in outgoing requests according to patterns specified in the s/MATCH/REPLACEMENT format.")
|
||||
.multiple(true)
|
||||
.use_delimiter(true)
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("verbose")
|
||||
.short("v")
|
||||
.long("verbose")
|
||||
.help("Be noisy"))
|
||||
.get_matches();
|
||||
|
||||
return Args {
|
||||
port: matches
|
||||
.value_of("port")
|
||||
.unwrap_or("8080")
|
||||
.parse::<u16>()
|
||||
.unwrap(),
|
||||
certs: matches
|
||||
.value_of("certs")
|
||||
.map(|a| a.to_owned())
|
||||
.expect("--certs must be specified"),
|
||||
key: matches
|
||||
.value_of("key")
|
||||
.map(|a| a.to_owned())
|
||||
.expect("--key must be specified"),
|
||||
verbose: matches.is_present("verbose"),
|
||||
replaces: matches
|
||||
.values_of("replace")
|
||||
.map_or(vec![], |a| a.map(|b| b.to_owned()).collect()),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn load_certs(filename: &str) -> Vec<rustls::Certificate> {
|
||||
let certfile = fs::File::open(filename).expect("cannot open certificate file");
|
||||
let mut reader = BufReader::new(certfile);
|
||||
rustls_pemfile::certs(&mut reader)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|v| rustls::Certificate(v.clone()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn read_file(filename: &str) -> BufReader<fs::File> {
|
||||
let certfile = fs::File::open(filename).expect("cannot open certificate file");
|
||||
BufReader::new(certfile)
|
||||
}
|
||||
|
||||
pub fn load_private_key(filename: &str) -> rustls::PrivateKey {
|
||||
let keyfile = fs::File::open(filename).expect("cannot open private key file");
|
||||
let mut reader = BufReader::new(keyfile);
|
||||
|
||||
loop {
|
||||
match rustls_pemfile::read_one(&mut reader).expect("cannot parse private key .pem file") {
|
||||
Some(rustls_pemfile::Item::RSAKey(key)) => return rustls::PrivateKey(key),
|
||||
Some(rustls_pemfile::Item::PKCS8Key(key)) => return rustls::PrivateKey(key),
|
||||
None => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
panic!(
|
||||
"no keys found in {:?} (encrypted keys not supported)",
|
||||
filename
|
||||
);
|
||||
}
|
138
src/main.rs
138
src/main.rs
@ -1,117 +1,51 @@
|
||||
use std::sync::Arc;
|
||||
use std::net::SocketAddr;
|
||||
use tokio::net::{TcpListener,TcpStream};
|
||||
use tokio::io::{copy_bidirectional};
|
||||
use std::error::Error;
|
||||
use std::{str, io};
|
||||
use httparse::Request;
|
||||
use tokio::net::{TcpListener};
|
||||
use rustls::{ServerConfig, ClientConfig, NoClientAuth};
|
||||
use webpki_roots;
|
||||
|
||||
async fn read(stream: &TcpStream, buf: &mut Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||
loop {
|
||||
// Wait for the socket to be readable
|
||||
stream.readable().await?;
|
||||
|
||||
// Try to read data, this may still fail with `WouldBlock`
|
||||
// if the readiness event is a false positive.
|
||||
match stream.try_read(buf) {
|
||||
Ok(n) => {
|
||||
buf.truncate(n);
|
||||
break;
|
||||
}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error reading from stream: {:#?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn write(stream: &TcpStream, buf: &[u8]) -> Result<(), Box<dyn Error>> {
|
||||
loop {
|
||||
// Wait for the socket to be writable
|
||||
stream.writable().await?;
|
||||
|
||||
// Try to write data, this may still fail with `WouldBlock`
|
||||
// if the readiness event is a false positive.
|
||||
match stream.try_write(buf) {
|
||||
Ok(_) => {
|
||||
break;
|
||||
}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error writing to stream: {:#?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn proxy(mut incoming: TcpStream) -> Result<(), Box<dyn Error>> {
|
||||
let mut buf = vec![0; 1024];
|
||||
read(&incoming, &mut buf).await.unwrap();
|
||||
|
||||
let mut headers = [httparse::EMPTY_HEADER; 16];
|
||||
let mut req = Request::new(&mut headers);
|
||||
req.parse(&buf).unwrap();
|
||||
|
||||
println!("{}\r\n------", str::from_utf8(&buf)?);
|
||||
|
||||
match (req.method, req.path) {
|
||||
(Some("CONNECT"), Some(ref path)) => {
|
||||
println!("CONNECT {:#?}", path);
|
||||
let mut outgoing = TcpStream::connect(path).await?;
|
||||
|
||||
write(&incoming, b"HTTP/1.1 200 OK\r\n\r\n").await?;
|
||||
|
||||
copy_bidirectional(&mut incoming, &mut outgoing).await?;
|
||||
|
||||
/* A naive implementation of a bidirectional copy:
|
||||
* I am actually concerned about this implementation since both reads happen at the
|
||||
* same time, if in any case two streams are writing at the same time, some of the data
|
||||
* of one of those writes might get discarded.
|
||||
*
|
||||
* let mut tmp = vec![0; 1024];
|
||||
* let mut tmp2 = vec![0; 1024];
|
||||
* loop {
|
||||
* let r = select! {
|
||||
* _ = read(&mut incoming, &mut tmp).fuse() =>
|
||||
* write(&mut outgoing, &tmp).fuse(),
|
||||
* _ = read(&mut outgoing, &mut tmp2).fuse() =>
|
||||
* write(&mut incoming, &tmp2).fuse()
|
||||
* };
|
||||
|
||||
* r.await?
|
||||
* }
|
||||
*/
|
||||
}
|
||||
|
||||
_ => {
|
||||
println!("Not What I Expected!!");
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(())
|
||||
}
|
||||
mod command;
|
||||
mod proxy;
|
||||
mod cert;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let args = command::args();
|
||||
|
||||
// We'll bind to 127.0.0.1:3000
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], args.port));
|
||||
println!("Listening on {:#?}", addr);
|
||||
|
||||
let mut server_config = ServerConfig::new(NoClientAuth::new());
|
||||
let certs = command::load_certs(&args.certs);
|
||||
let privkey = command::load_private_key(&args.key);
|
||||
server_config
|
||||
.set_single_cert(certs.clone(), privkey.clone())
|
||||
.expect("bad certificates/private key");
|
||||
|
||||
let mut client_config = ClientConfig::new();
|
||||
client_config.key_log = Arc::new(rustls::KeyLogFile::new());
|
||||
|
||||
client_config
|
||||
.dangerous()
|
||||
.set_certificate_verifier(Arc::new(cert::NoCertificateVerification {}));
|
||||
|
||||
client_config
|
||||
.root_store
|
||||
.add_pem_file(&mut command::read_file(&args.certs)).unwrap();
|
||||
|
||||
//client_config
|
||||
//.root_store
|
||||
//.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
||||
|
||||
let tcp_listener = TcpListener::bind(addr).await?;
|
||||
loop {
|
||||
let (tcp_stream, _) = tcp_listener.accept().await?;
|
||||
let cc = client_config.clone();
|
||||
let sc = server_config.clone();
|
||||
let args_copy = args.clone();
|
||||
tokio::task::spawn(async move {
|
||||
match proxy(tcp_stream).await {
|
||||
match proxy::proxy(tcp_stream, cc, sc, args_copy).await {
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
println!("error: {:#?}", e);
|
||||
|
73
src/proxy.rs
Normal file
73
src/proxy.rs
Normal file
@ -0,0 +1,73 @@
|
||||
use std::sync::Arc;
|
||||
use tokio::net::{TcpStream};
|
||||
use std::error::Error;
|
||||
use httparse::Request;
|
||||
use webpki;
|
||||
use std::str;
|
||||
use std::io::{Write, Read};
|
||||
use rustls::{ServerConfig, ClientConfig, Session};
|
||||
|
||||
mod ops;
|
||||
|
||||
pub async fn proxy(mut incoming: TcpStream, client_config: ClientConfig, server_config: ServerConfig, args: super::command::Args) -> Result<(), Box<dyn Error>> {
|
||||
let mut buf = vec![0; 1024];
|
||||
ops::read(&incoming, &mut buf).await.unwrap();
|
||||
|
||||
let mut headers = [httparse::EMPTY_HEADER; 16];
|
||||
let mut req = Request::new(&mut headers);
|
||||
req.parse(&buf).unwrap();
|
||||
|
||||
if args.verbose {
|
||||
println!("{}\r\n------", str::from_utf8(&buf)?);
|
||||
}
|
||||
|
||||
match (req.method, req.path) {
|
||||
(Some("CONNECT"), Some(ref path)) => {
|
||||
ops::write(&mut incoming, b"HTTP/1.1 200 OK\r\n\r\n").await?;
|
||||
let host = path.split(":").next().expect("Hostname must be valid");
|
||||
let dns_name = webpki::DNSNameRef::try_from_ascii_str(host).unwrap();
|
||||
println!("{:#?}", dns_name);
|
||||
|
||||
let mut server_session = rustls::ServerSession::new(&Arc::new(server_config));
|
||||
let mut incoming_std = incoming.into_std()?;
|
||||
let mut incoming_tls = rustls::Stream::new(&mut server_session, &mut incoming_std);
|
||||
|
||||
let mut client_session = rustls::ClientSession::new(&Arc::new(client_config), dns_name);
|
||||
let outgoing = TcpStream::connect(path).await?;
|
||||
let mut outgoing_std = outgoing.into_std()?;
|
||||
let mut outgoing_tls = rustls::Stream::new(&mut client_session, &mut outgoing_std);
|
||||
|
||||
let mut tmp = vec![0; 1024^2];
|
||||
let mut tmp2 = vec![0; 1024^2];
|
||||
//let ciphersuite = incoming_tls.sess.get_negotiated_ciphersuite().unwrap();
|
||||
//println!("{:#?}", ciphersuite);
|
||||
loop {
|
||||
println!("incoming");
|
||||
let incoming_read = ops::sync_read(&mut incoming_tls, &mut tmp);
|
||||
println!("incoming {:#?}", str::from_utf8(&tmp)?);
|
||||
match incoming_read {
|
||||
Ok(n) if n > 0 => ops::sync_write(&mut outgoing_tls, &tmp),
|
||||
Ok(0) => return Ok(()),
|
||||
e => e
|
||||
}.unwrap();
|
||||
|
||||
let outgoing_read = ops::sync_read(&mut outgoing_tls, &mut tmp2);
|
||||
|
||||
println!("outgoing {:#?}", str::from_utf8(&tmp2)?);
|
||||
|
||||
match outgoing_read {
|
||||
Ok(n) if n > 0 => ops::sync_write(&mut incoming_tls, &tmp2),
|
||||
Ok(0) => return Ok(()),
|
||||
|
||||
e => e
|
||||
}.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
println!("Not What I Expected!!");
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(())
|
||||
}
|
117
src/proxy/ops.rs
Normal file
117
src/proxy/ops.rs
Normal file
@ -0,0 +1,117 @@
|
||||
use tokio::net::{TcpStream};
|
||||
use std::error::Error;
|
||||
use std::{io};
|
||||
use std::io::{Read, Write};
|
||||
use rustls::{Session};
|
||||
|
||||
pub async fn read(stream: &TcpStream, buf: &mut Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||
loop {
|
||||
stream.readable().await?;
|
||||
|
||||
match stream.try_read(buf) {
|
||||
Ok(n) => {
|
||||
buf.truncate(n);
|
||||
break;
|
||||
}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error reading from stream: {:#?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn write(stream: &TcpStream, buf: &[u8]) -> Result<(), Box<dyn Error>> {
|
||||
loop {
|
||||
stream.writable().await?;
|
||||
|
||||
match stream.try_write(buf) {
|
||||
Ok(_) => {
|
||||
break;
|
||||
}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error writing to stream: {:#?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sync_read<T: Read>(stream: &mut T, buf: &mut Vec<u8>) -> Result<usize, Box<dyn Error>> {
|
||||
loop {
|
||||
match stream.read(buf) {
|
||||
Ok(n) => {
|
||||
buf.truncate(n);
|
||||
return Ok(n);
|
||||
}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error reading from stream: {:#?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sync_write<T: Write>(stream: &mut T, buf: &[u8]) -> Result<usize, Box<dyn Error>> {
|
||||
loop {
|
||||
match stream.write(buf) {
|
||||
Ok(n) => {
|
||||
return Ok(n);
|
||||
}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error writing to stream: {:#?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tls_read<T: Session, R: Read>(stream: &mut T, buf: &mut R) -> Result<usize, Box<dyn Error>> {
|
||||
loop {
|
||||
match stream.read_tls(buf) {
|
||||
Ok(n) => {
|
||||
return Ok(n);
|
||||
}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error reading from stream: {:#?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tls_write<T: Session, W: Write>(stream: &mut T, buf: &mut W) -> Result<usize, Box<dyn Error>> {
|
||||
loop {
|
||||
match stream.write_tls(buf) {
|
||||
Ok(n) => {
|
||||
return Ok(n);
|
||||
}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error writing to stream: {:#?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user