From a8797558656aeea1401b95d3494b51ab11f20716 Mon Sep 17 00:00:00 2001 From: PinkP4nther <0x0090@protonmail.com> Date: Wed, 18 Aug 2021 00:08:06 -0700 Subject: [PATCH] Code Upload --- .gitignore | 1 + Cargo.lock | 180 ++++++++ Cargo.toml | 14 + README.md | 7 + examples/basic/Cargo.toml | 9 + examples/basic/main.rs | 44 ++ examples/basic/relay_config.toml | 7 + relay_config.example.toml | 7 + src/lib.rs | 680 +++++++++++++++++++++++++++++++ 9 files changed, 949 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 examples/basic/Cargo.toml create mode 100644 examples/basic/main.rs create mode 100644 examples/basic/relay_config.toml create mode 100644 relay_config.example.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c41cc9e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..345e810 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,180 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chunked_transfer" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "flate2" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "libz-sys", + "miniz_oxide", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "httparse" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" + +[[package]] +name = "libc" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" + +[[package]] +name = "libz-sys" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "openssl" +version = "0.10.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-sys", +] + +[[package]] +name = "openssl-sys" +version = "0.9.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "serde" +version = "1.0.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" + +[[package]] +name = "sslrelay" +version = "0.1.0" +dependencies = [ + "chunked_transfer", + "flate2", + "httparse", + "openssl", + "toml", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..cd998f6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "sslrelay" +version = "0.1.0" +authors = ["PinkP4nther "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +openssl = "0.10.34" +httparse = "1.4.1" +chunked_transfer = "1.4.0" +flate2 = { version = "1.0.17", features = ["zlib"], default-features = false } +toml = "0.5.8" \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5b9b84d --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# SSLRelay +A relay I wrote to help with intercepting/modifying TLS encrypted network traffic from an application. + +The idea is to generate a certificate and a private key (You may need to generate a CA for your certificate, so that you can tell your system or the application to trust the generated certificate). +Then use this library to continuously rewrite or display encrypted network traffic. + +Right now this library is mostly written to target the HTTP over TLS however I would like to make it work seamlessly with any data over TLS/SSL. \ No newline at end of file diff --git a/examples/basic/Cargo.toml b/examples/basic/Cargo.toml new file mode 100644 index 0000000..a2142a0 --- /dev/null +++ b/examples/basic/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "basic" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +sslrelay = {path = "../SSLRelay-lib"} \ No newline at end of file diff --git a/examples/basic/main.rs b/examples/basic/main.rs new file mode 100644 index 0000000..c366b13 --- /dev/null +++ b/examples/basic/main.rs @@ -0,0 +1,44 @@ +use sslrelay::{self, ConfigType, HandlerCallbacks}; + + +// Handler object +struct Handler; + +/* + Callback traits that can be used to read or inject data + into data upstream or downstream. +*/ +impl HandlerCallbacks for Handler { + + // Request non blocking callback + fn req_nb_callback(&self, _in_data: Vec) { + println!("[+] Request Non Blocking CallBack!"); + } + + // Request blocking callback + fn req_b_callback(&self, _in_data: &mut Vec) { + println!("[+] Request Blocking CallBack!"); + } + + // Response non blocking callback + fn res_nb_callback(&self, _in_data: Vec) { + println!("[+] Response Non Blocking CallBack!"); + } + + // Response blocking callback + fn res_b_callback(&self, _in_data: &mut Vec) { + println!("[+] Response Blocking CallBack!"); + } +} + +fn main() { + + // Create new SSLRelay object + let mut relay = sslrelay::SSLRelay::new(Handler); + + // Load Configuration + relay.load_config(ConfigType::Default); + + // Start listening + relay.start(); +} \ No newline at end of file diff --git a/examples/basic/relay_config.toml b/examples/basic/relay_config.toml new file mode 100644 index 0000000..be4358e --- /dev/null +++ b/examples/basic/relay_config.toml @@ -0,0 +1,7 @@ +bind_host = "0.0.0.0" +bind_port = "443" +ssl_private_key_path = "./remote.com.key" +ssl_cert_path = "./remote.com.crt" +remote_host = "remote.com" +remote_port = "443" +verbose_level = "2" \ No newline at end of file diff --git a/relay_config.example.toml b/relay_config.example.toml new file mode 100644 index 0000000..1003c17 --- /dev/null +++ b/relay_config.example.toml @@ -0,0 +1,7 @@ +bind_host = "0.0.0.0" +bind_port = "443" +ssl_private_key_path = "./ssl.key" +ssl_cert_path = "./ssl.crt" +remote_host = "remote.com" +remote_port = "443" +verbose_level = "2" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..510f3f3 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,680 @@ +use openssl::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod, SslStream, SslVerifyMode}; +use std::io::{self, Read, Write}; +use std::net::{TcpListener, TcpStream}; +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; +use std::env; +use std::fs; + +use toml::Value as TValue; + +use chunked_transfer::Decoder; + +use flate2::read::GzDecoder; + +use httparse::{self, Header}; + +struct RelayedResponse<'a> { + http_version: Option, + http_code: Option, + http_reason: Option, + http_headers: Option>>, + http_body: Option, +} + +struct RelayRequest<'a> { + http_method: Option, + http_path: Option, + http_version: Option, + http_headers: Option>>, + http_body: Option, +} + +#[derive(Clone)] +struct RelayConfig { + bind_host: String, + bind_port: String, + remote_host: String, + remote_port: String, + ssl_private_key_path: String, + ssl_cert_path: String, + verbose_level: i8, + +} + +pub trait HandlerCallbacks { + fn req_b_callback(&self, _in_data: &mut Vec){} + fn req_nb_callback(&self, _in_data: Vec){} + fn res_b_callback(&self, _in_data: &mut Vec){} + fn res_nb_callback(&self, _in_data: Vec){} +} + +pub enum ConfigType { + Env, + Path(T), + Default, +} + +#[derive(Clone)] +pub struct SSLRelay +where + H: HandlerCallbacks + std::marker::Sync + std::marker::Send + 'static, +{ + + config: Option, + handlers: Option, +} + +impl SSLRelay { + + pub fn new(handlers: H) -> Self { + + SSLRelay { + config: None, + handlers: Some(handlers), + } + } + + pub fn load_config(&mut self, config_path: ConfigType) { + self.config = Some(self.load_relay_config(config_path)); + } + + pub fn start(&mut self) { + + let rc_pointer = Arc::new(Mutex::new(self.config.as_ref().unwrap().clone())); + let handler_pointer = Arc::new(Mutex::new(self.handlers.take().unwrap())); + let acceptor = self.setup_ssl_config(self.config.as_ref().unwrap().ssl_private_key_path.clone(), self.config.as_ref().unwrap().ssl_cert_path.clone()); + let listener = TcpListener::bind(format!("{}:{}", self.config.as_ref().unwrap().bind_host.clone(), self.config.as_ref().unwrap().bind_port.clone())).unwrap(); + + for stream in listener.incoming() { + + match stream { + Ok(stream) => { + + let acceptor = acceptor.clone(); + let rc_config = rc_pointer.clone(); + let handler = handler_pointer.clone(); + + thread::spawn(move || { + + match acceptor.accept(stream) { + Ok(stream) => { + + handle_stream(stream, rc_config, handler); + return 0; + }, + Err(e) => { + + println!("[Error] {}", e); + return -1; + } + } + }); + /*let stream = acceptor.accept(stream).unwrap(); + handle_stream(stream, rc_config, handler);*/ + }, + Err(e) => {println!("[Error] Tcp Connection Failed: {}", e)} + } + } + } + + fn load_relay_config(&self, config_path: ConfigType) -> RelayConfig { + + let mut resolved_path = String::from("./relay_config.toml"); + match config_path { + ConfigType::Path(path) => { + resolved_path = path.clone(); + }, + ConfigType::Env => { + resolved_path = match env::var("SSLRELAY_CONFIG") { + Ok(p) => p.clone(), + Err(_e) => { + println!("[-] Environmental variable SSLRELAY_CONFIG does not exist."); + std::process::exit(-1); + } + }; + }, + ConfigType::Default => {} + } + + let bytes = fs::read(resolved_path).unwrap(); + let config_file = String::from_utf8_lossy(&bytes); + let config_parsed = config_file.parse::().unwrap(); + + let bind_host = config_parsed["bind_host"].to_string().replace("\"", ""); + let bind_port = config_parsed["bind_port"].to_string().replace("\"", ""); + let ssl_private_key_path = config_parsed["ssl_private_key_path"].to_string().replace("\"", ""); + let ssl_cert_path = config_parsed["ssl_cert_path"].to_string().replace("\"", ""); + let remote_host = config_parsed["remote_host"].to_string().replace("\"", ""); + let remote_port = config_parsed["remote_port"].to_string().replace("\"", ""); + let verbose_level = config_parsed["verbose_level"].to_string().replace("\"", "").parse().unwrap(); + + RelayConfig { + bind_host: bind_host.clone(), + bind_port: bind_port.clone(), + ssl_private_key_path: ssl_private_key_path.clone(), + ssl_cert_path: ssl_cert_path.clone(), + remote_host: remote_host.clone(), + remote_port: remote_port.clone(), + verbose_level: verbose_level, + } + } + + fn setup_ssl_config(&self, priv_key: String, cert: String) -> Arc { + + let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + acceptor.set_private_key_file(priv_key, SslFiletype::PEM).unwrap(); + acceptor.set_certificate_chain_file(cert).unwrap(); + acceptor.check_private_key().unwrap(); + Arc::new(acceptor.build()) + } + + + + +}// SSLRelay + +#[derive(PartialEq)] +enum StreamDirection { + Upstream,// Data coming from remote host + DownStream,// Data coming from origin host +} + +struct DataHandler { + tcp_stream: Option>, + relay_stream: Option>, + remote_host: String, + stream_direction: StreamDirection, +} + +impl DataHandler { + + fn new(tcp_stream: SslStream, remote_host: String) -> Self { + let _ = tcp_stream.get_ref().set_read_timeout(Some(Duration::from_millis(100))); + DataHandler { + tcp_stream: Some(tcp_stream), + relay_stream: None, + remote_host, + stream_direction: StreamDirection::DownStream, + } + } + + fn get_data_stream(&mut self, data: &mut Vec) -> usize { + + let mut data_length: usize = 0; + if self.stream_direction == StreamDirection::DownStream { + loop { + + let mut r_buf = [0; 1024]; + + match self.tcp_stream.as_mut().unwrap().read(&mut r_buf) { + + Ok(bytes_read) => { + + if bytes_read == 0 { + break; + + } else if bytes_read != 0 && bytes_read <= 1024 { + + let mut tmp_buf = r_buf.to_vec(); + tmp_buf.truncate(bytes_read); + + let _bw = data.write(&tmp_buf).unwrap(); + data_length += bytes_read; + + } else { + println!("[+] Else hit!!!!!!!!!!!!!!!!!!!!!!"); + } + }, + Err(e) => { + match e.kind() { + io::ErrorKind::WouldBlock => { + break; + }, + _ => {println!("[!!!] Got error: {}",e);} + } + }, + } + } + } else if self.stream_direction == StreamDirection::Upstream { + loop { + + let mut r_buf = [0; 1024]; + + match self.relay_stream.as_mut().unwrap().read(&mut r_buf) { + + Ok(bytes_read) => { + + if bytes_read == 0 { + break; + + } else if bytes_read != 0 && bytes_read <= 1024 { + + let mut tmp_buf = r_buf.to_vec(); + tmp_buf.truncate(bytes_read); + + let _bw = data.write(&tmp_buf).unwrap(); + data_length += bytes_read; + + } else { + println!("[+] Else hit!!!!!!!!!!!!!!!!!!!!!!"); + } + }, + Err(e) => { + match e.kind() { + io::ErrorKind::WouldBlock => { + break; + }, + _ => {println!("[!!!] Got error: {}",e);} + } + }, + } + } + } + return data_length; + } + + fn http_req_verbose(&self, data: &Vec, mode: u8) { + + let req_info = self.get_request(&data); + let req_header_list = req_info.http_headers.unwrap(); + let mut req_header_string = String::new(); + + for header in req_header_list { + if header.value.to_vec().len() == 0 {continue;} + req_header_string.push_str(format!("[-->] {}: {}\n", header.name, String::from_utf8(header.value.to_vec()).unwrap()).as_str()); + } + if mode == 1 { + println!("================================\n[-->] HTTP Version: {}\n[-->] HTTP Method: {} {}\n[-->] HTTP Headers:\n{}\n[-->] HTTP Body:\n{}\n" + ,req_info.http_version.unwrap() + ,req_info.http_method.unwrap() + ,req_info.http_path.unwrap() + ,req_header_string + ,req_info.http_body.unwrap() + ); + } else if mode == 2 { + println!("[Req] {} {}", req_info.http_method.unwrap(), req_info.http_path.unwrap()); + } + } + + fn http_res_verbose(&self, response_data: &Vec, mode: u8) { + + let res_info = self.get_response(&response_data); + let header_list = res_info.http_headers.unwrap(); + let mut header_string = String::new(); + + for header in header_list { + if header.value.to_vec().len() == 0 {continue;} + header_string.push_str(format!("[<--] {}: {}\n", header.name, String::from_utf8(header.value.to_vec()).unwrap()).as_str()); + } + if mode == 1 { + println!("\n[<--] HTTP Version: {}\n[<--] HTTP Code: {} {}\n[<--] HTTP Headers:\n{}\n[<--] HTTP Body:\n{}\n================================\n" + ,res_info.http_version.unwrap() + ,res_info.http_code.unwrap() + ,res_info.http_reason.unwrap() + ,header_string + ,res_info.http_body.unwrap() + ); + } else if mode == 2 { + println!("[Res] {} {}", res_info.http_code.unwrap(), res_info.http_reason.unwrap()); + } + } + + fn relay_data(&mut self, data: &Vec) -> Option { + + let mut retries = 3; + loop { + + let mut sslbuild = SslConnector::builder(SslMethod::tls()).unwrap(); + sslbuild.set_verify(SslVerifyMode::NONE); + let connector = sslbuild.build(); + let stream = TcpStream::connect(&self.remote_host).unwrap(); + let _ = stream.set_read_timeout(Some(Duration::from_millis(500))); + let mut stream = match connector.connect(&self.remote_host, stream) { + Ok(s) => s, + Err(e) => { + println!("[Error] {}", e); + if retries == 0 { + println!("[!] Request relay retries: 0"); + return None; + } + retries -= 1; + continue; + } + }; + + stream.write_all(&data).unwrap(); + let _ = stream.flush(); + //println!("[+] Relayed -> {}", host); + + //return Some(stream); Instead of returning we will now set stream object + self.relay_stream = Some(stream); + return Some(0); + } + } + /* + fn get_req_headers<'a>(&self, data: &'a Vec) -> Option>> { + + let mut headers = [httparse::EMPTY_HEADER; 128]; + let mut request = httparse::Request::new(&mut headers); + + let req = request.parse(data).unwrap(); + + if req.is_complete() { + return Some(headers.to_vec()); + } + None + } + + fn get_res_headers(data: &Vec) -> Option> { + + let mut headers = [httparse::EMPTY_HEADER; 128]; + let mut response = httparse::Response::new(&mut headers); + + let res = response.parse(data).unwrap(); + + if res.is_complete() { + return Some(headers.to_vec()); + } + None + } + + fn get_host(&self, data: &Vec) -> Option { + + return Some("137.220.37.67".to_string()); + let mut headers = [httparse::EMPTY_HEADER; 128]; + + let mut request = httparse::Request::new(&mut headers); + + let req = request.parse(data).unwrap(); + + if req.is_complete() { + for header in headers.iter() { + if header.name == "Host" || header.name == "host" { + //println!("Host -> {}", String::from_utf8(header.value.to_vec()).unwrap()); + return Some(String::from_utf8(header.value.to_vec()).unwrap()); + } + } + None + } else if req.is_partial() { + for header in headers.iter() { + if header.name == "Host" || header.name == "host" { + //println!("Host -> {}", String::from_utf8(header.value.to_vec()).unwrap()); + return Some(String::from_utf8(header.value.to_vec()).unwrap()); + } + } + None + } else { + None + } + } + + fn get_cookie(&self, data: &Vec) -> Option { + + let mut headers = [httparse::EMPTY_HEADER; 128]; + + let mut request = httparse::Request::new(&mut headers); + + let req = request.parse(data).unwrap(); + + if req.is_complete() { + for header in headers.iter() { + if header.name == "Cookie" || header.name == "cookie" { + //println!("Host -> {}", String::from_utf8(header.value.to_vec()).unwrap()); + return Some(String::from_utf8(header.value.to_vec()).unwrap()); + } + } + None + } else if req.is_partial() { + for header in headers.iter() { + if header.name == "Cookie" || header.name == "cookie" { + //println!("Host -> {}", String::from_utf8(header.value.to_vec()).unwrap()); + return Some(String::from_utf8(header.value.to_vec()).unwrap()); + } + } + None + } else { + None + } + } + */ + fn get_response<'a>(&self, data: &'a Vec) -> RelayedResponse<'a> { + + let mut headers = [httparse::EMPTY_HEADER; 128]; + let mut res = httparse::Response::new(&mut headers); + + let res_chk = res.parse(data); + + loop { + + if !res_chk.unwrap().is_complete() { + thread::sleep(Duration::from_millis(100)); + continue; + } + + let reason = match res.reason { + Some(r) => Some(r.to_string()), + None => None, + }; + + let header_vec = res.headers.to_vec(); + + let body = self.get_http_body(&data, header_vec).unwrap_or(String::from("[-] Failed to get http response body!").into_bytes()); + let string_body = String::from_utf8(body).unwrap(); + + return RelayedResponse { + http_version: res.version, + http_code: res.code, + http_reason: reason, + http_headers: Some(headers.to_vec()), + http_body: Some(string_body), + }; + } + } + + fn get_request<'a>(&self, data: &'a Vec) -> RelayRequest<'a> { + + let mut headers = [httparse::EMPTY_HEADER; 128]; + let mut req = httparse::Request::new(&mut headers); + + let req_chk = req.parse(data); + + loop { + + if !req_chk.unwrap().is_complete() { + thread::sleep(Duration::from_millis(100)); + continue; + } + + let method = match req.method { + Some(r) => Some(r.to_string()), + None => None, + }; + + let path = match req.path { + Some(p) => Some(p.to_string()), + None => None, + }; + + let header_vec = req.headers.to_vec(); + + let body = self.get_http_body(&data, header_vec).unwrap_or(String::from("[-] Failed to get http request body!").into_bytes()); + let string_body = String::from_utf8(body).unwrap(); + + return RelayRequest { + http_method: method, + http_path: path, + http_version: req.version, + http_headers: Some(headers.to_vec()), + http_body: Some(string_body), + }; + } + } + + fn get_http_body(&self, data: &Vec, headers: Vec
) -> Option> { + + let mut cl: u64 = 0; + let encoding_check = headers.clone(); + for header in headers { + + if header.name == "Content-Length" || header.name == "content-length" { + let length = match String::from_utf8(header.value.to_vec()) { + Ok(s) => s, + Err(e) => { + println!("[!] ERROR: {}",e); + return None; + }, + }; + + cl += length.parse::().unwrap(); + let mut r_body = data.to_vec(); + r_body.reverse(); + r_body.truncate(cl as usize); + r_body.reverse(); + + return Some(r_body); + + } else if header.name == "Transfer-Encoding" || header.name == "transfer-encoding" { + + let te_string = String::from_utf8(header.value.to_vec()).unwrap(); + + if te_string == "chunked" { + + let mut new_vec = data.to_vec(); + let new_vec_iter = new_vec.to_vec(); + let mut new_vec_iter = new_vec_iter.iter(); + let mut i = 0; + + loop { + if let Some(&0x0d) = new_vec_iter.next() { + i += 1; + if let Some(&0x0a) = new_vec_iter.next() { + i += 1; + if let Some(&0x0d) = new_vec_iter.next() { + i += 1; + if let Some(&0x0a) = new_vec_iter.next() { + i += 1; + break; + } else {i += 1;} + } else {i += 1;} + } else {i += 1;} + } else {i += 1;} + } + + new_vec.reverse(); + new_vec.truncate(data.len() - i); + new_vec.reverse(); + + let mut decoder = Decoder::new(new_vec.as_slice()); + let mut blob = Vec::new(); + let _ = decoder.read_to_end(&mut blob); + + let mut g_encoded = false; + for header in encoding_check { + if header.name == "Content-Encoding" || header.name == "content-encoding" { + let s = String::from_utf8(header.value.to_vec()).unwrap(); + if s == "gzip" { + g_encoded = true; + } + } + } + if g_encoded { + let mut gzd = GzDecoder::new(&blob[..]); + let mut unzipped = Vec::new(); + match gzd.read_to_end(&mut unzipped) { + Ok(_) => {}, + Err(_) => return None, + } + + return Some(unzipped); + } else { + return Some(blob); + } + + } + } + } + return Some(String::from("None").into_bytes()); + } +} // DataHandler + + +/* Rewrite this to handle TCP connections until TCP connection is dropped instead of dropping it */ +fn handle_stream(tcp_stream: SslStream, rc_config: Arc>, handlers: Arc>) { + + let conf_lock = rc_config.lock().unwrap(); + let remote_host = format!("{}:{}", conf_lock.remote_host, conf_lock.remote_port); + let verbose_mode = conf_lock.verbose_level; + drop(conf_lock); + + let mut datahandler = DataHandler::new(tcp_stream, remote_host); + + let mut data = Vec::::new(); + let mut response_data = Vec::::new(); + + let data_size = datahandler.get_data_stream(&mut data); + if data_size == 0 { + println!("[!] Got 0 bytes closing tcp stream!"); + return; + } + if verbose_mode == 1 { + datahandler.http_req_verbose(&data, 1); + } else if verbose_mode == 2 { + datahandler.http_req_verbose(&data, 2); + } + + let handlers_p = handlers.clone(); + let d = data.clone(); + + thread::spawn(move || { + let handlers_lock = handlers_p.lock().unwrap(); + handlers_lock.req_nb_callback(d); + drop(handlers_lock); + }); + + let handlers_p = handlers.clone(); + let handlers_lock = handlers_p.lock().unwrap(); + handlers_lock.req_b_callback(&mut data); + drop(handlers_lock); + + + + match datahandler.relay_data(&data) { + Some(_relay_success) => {}, + None => { + println!("[-] relay_data failed!"); + return; + } + } + + // Get Upstream Data + datahandler.stream_direction = StreamDirection::Upstream; + let _response_size = datahandler.get_data_stream(&mut response_data); + + if verbose_mode == 1 { + datahandler.http_res_verbose(&response_data, 1); + } else if verbose_mode == 2 { + datahandler.http_res_verbose(&response_data, 2); + } + + // Switch back to DownStream mode to relay data from remote host back to origin host + datahandler.stream_direction = StreamDirection::DownStream; + + let handlers_p = handlers.clone(); + let d = response_data.clone(); + + thread::spawn(move || { + let handlers_lock = handlers_p.lock().unwrap(); + handlers_lock.res_nb_callback(d); + drop(handlers_lock); + }); + + let handlers_p = handlers.clone(); + let handlers_lock = handlers_p.lock().unwrap(); + handlers_lock.res_b_callback(&mut response_data); + drop(handlers_lock); + + datahandler.tcp_stream.as_mut().unwrap().write_all(&response_data).unwrap(); + let _ = datahandler.tcp_stream.as_mut().unwrap().flush(); +} \ No newline at end of file