From cc8198aaf687708ec071360a6ecafec61c9ee719 Mon Sep 17 00:00:00 2001 From: PinkP4nther <0x0090@protonmail.com> Date: Fri, 8 Oct 2021 21:47:16 -0700 Subject: [PATCH 01/10] Fix README typo --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1ec62f2..972e97f 100644 --- a/README.md +++ b/README.md @@ -28,4 +28,5 @@ A TCP relay library that can handle raw TCP and SSL/TLS connections. You can rea > 10/06/2021 | **v0.4.2** | Added documentation. > > 10/07/2021 | **v0.4.3** | Blocking callbacks now pass self as a mutable reference. This can allow the developer to create structures that can be accessed every stream write. (ONLY in the BLOCKING callback). The self object is refreshed per TCP connection. Separate TCP connections can not touch eachothers data. +> > 10/08/2021 | **v0.4.4** | Added ability to set TLS certificate and certificate private key to nothing. When passing RelayConfig to the relay object use the 'None' variant of Option enum. In a config file put the cert path and key path as an empty 'String' to specify 'None'. \ No newline at end of file From 2691138ee5625f6c6202d1e7702e8530c4804093 Mon Sep 17 00:00:00 2001 From: PinkP4nther <0x0090@protonmail.com> Date: Fri, 8 Oct 2021 22:05:27 -0700 Subject: [PATCH 02/10] V 5 No changes --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c2eeeff..def355c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sslrelay" -version = "0.4.4" +version = "0.5" authors = ["PinkP4nther @Pink_P4nther"] edition = "2018" description = "A TCP relay library for relaying/modifying/spoofing TCP traffic by implementing callback code." From edb41aaf5415174b50c32665430f66dc53e7d0f9 Mon Sep 17 00:00:00 2001 From: PinkP4nther <0x0090@protonmail.com> Date: Fri, 8 Oct 2021 22:06:57 -0700 Subject: [PATCH 03/10] V 5 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index def355c..9ffd48f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sslrelay" -version = "0.5" +version = "0.5.0" authors = ["PinkP4nther @Pink_P4nther"] edition = "2018" description = "A TCP relay library for relaying/modifying/spoofing TCP traffic by implementing callback code." From 32645a48c3006bcf99cee30d468e25c319bbea52 Mon Sep 17 00:00:00 2001 From: PinkP4nther <0x0090@protonmail.com> Date: Fri, 8 Oct 2021 22:08:39 -0700 Subject: [PATCH 04/10] No longer need process import --- src/lib.rs | 1 - src/relay.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fbc543d..fda89c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,7 +100,6 @@ use std::sync::{ }; use std::{ - process, thread }; diff --git a/src/relay.rs b/src/relay.rs index 71ee2f9..ffb121f 100644 --- a/src/relay.rs +++ b/src/relay.rs @@ -14,7 +14,6 @@ use crate::{ env, TValue, fs, - process, Arc, SslAcceptor, Path, From 61217ed351b430bee4f9df97bd1d394a3e610549 Mon Sep 17 00:00:00 2001 From: PinkP4nther <0x0090@protonmail.com> Date: Sat, 9 Oct 2021 22:05:03 -0700 Subject: [PATCH 05/10] New configuration method. Version 0.6.0. Examples updated to new configuration method. Configuration files removed. --- Cargo.toml | 7 +- README.md | 4 +- examples/basic/src/main.rs | 13 ++- examples/modifydata/relay_config.toml | 8 -- examples/modifydata/src/main.rs | 18 +++- relay_config.example.toml | 8 -- src/lib.rs | 57 +++++------ src/relay.rs | 136 +++++++------------------- 8 files changed, 91 insertions(+), 160 deletions(-) delete mode 100644 examples/modifydata/relay_config.toml delete mode 100644 relay_config.example.toml diff --git a/Cargo.toml b/Cargo.toml index 9ffd48f..1ee0feb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sslrelay" -version = "0.5.0" +version = "0.6.0" authors = ["PinkP4nther @Pink_P4nther"] edition = "2018" description = "A TCP relay library for relaying/modifying/spoofing TCP traffic by implementing callback code." @@ -10,7 +10,4 @@ categories = ["reverse-engineering", "network-relay", "tcp"] license = "Apache-2.0" [dependencies.openssl] -version = "0.10.36" - -[dependencies.toml] -version = "0.5.8" \ No newline at end of file +version = "0.10.36" \ No newline at end of file diff --git a/README.md b/README.md index 972e97f..3aa255e 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,6 @@ A TCP relay library that can handle raw TCP and SSL/TLS connections. You can rea > > 10/07/2021 | **v0.4.3** | Blocking callbacks now pass self as a mutable reference. This can allow the developer to create structures that can be accessed every stream write. (ONLY in the BLOCKING callback). The self object is refreshed per TCP connection. Separate TCP connections can not touch eachothers data. > -> 10/08/2021 | **v0.4.4** | Added ability to set TLS certificate and certificate private key to nothing. When passing RelayConfig to the relay object use the 'None' variant of Option enum. In a config file put the cert path and key path as an empty 'String' to specify 'None'. \ No newline at end of file +> 10/08/2021 | **v0.4.4** | Added ability to set TLS certificate and certificate private key to nothing. When passing RelayConfig to the relay object use the 'None' variant of Option enum. In a config file put the cert path and key path as an empty 'String' to specify 'None'. +> +> 10/09/2021 | **v0.6.0** | Gone away with 'ConfigType'! No more specifying config files unless the developer implements it themself. A new config enum 'TLSConfig' has been introduced. This has 3 variants FILE(Specify the cert and pk file paths), DATA(Pass the cert(PEM) data and the pk(PEM) data as bytes), NONE(This is when you are not using TLS on the listening/downstream side of the relay). \ No newline at end of file diff --git a/examples/basic/src/main.rs b/examples/basic/src/main.rs index 4117c4e..cf8ff14 100644 --- a/examples/basic/src/main.rs +++ b/examples/basic/src/main.rs @@ -1,4 +1,4 @@ -use sslrelay::{self, ConfigType, RelayConfig, HandlerCallbacks, CallbackRet, TCPDataType}; +use sslrelay::{self, RelayConfig, HandlerCallbacks, CallbackRet, TCPDataType, TLSConfig}; // Handler object #[derive(Clone)] // Must have Clone trait implemented. @@ -38,17 +38,20 @@ fn main() { // Create new SSLRelay object let mut relay = sslrelay::SSLRelay::new( Handler, - ConfigType::Conf(RelayConfig { + RelayConfig { downstream_data_type: TCPDataType::TLS, upstream_data_type: TCPDataType::TLS, bind_host: "0.0.0.0".to_string(), bind_port: "443".to_string(), remote_host: "remote.com".to_string(), remote_port: "443".to_string(), - ssl_private_key_path: Some("./remote.com.key".to_string()), - ssl_cert_path: Some("./remote.com.crt".to_string()), - }) + tls_config: TLSConfig::FILE{ + certificate_path: "./tls.crt".to_string(), + private_key_path: "./tls.key".to_string(), + }, + } ); + // Start listening relay.start(); } \ No newline at end of file diff --git a/examples/modifydata/relay_config.toml b/examples/modifydata/relay_config.toml deleted file mode 100644 index feb1885..0000000 --- a/examples/modifydata/relay_config.toml +++ /dev/null @@ -1,8 +0,0 @@ -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" -downstream_data_type = "tls" -upstream_data_type = "tls" \ No newline at end of file diff --git a/examples/modifydata/src/main.rs b/examples/modifydata/src/main.rs index eaf2c5a..1d79117 100644 --- a/examples/modifydata/src/main.rs +++ b/examples/modifydata/src/main.rs @@ -1,4 +1,4 @@ -use sslrelay::{self, ConfigType, HandlerCallbacks, CallbackRet}; +use sslrelay::{self, TLSConfig, TCPDataType, RelayConfig, HandlerCallbacks, CallbackRet}; // Handler object #[derive(Clone)] // Must have Clone trait implemented. @@ -38,7 +38,21 @@ impl HandlerCallbacks for Handler { fn main() { // Create new SSLRelay object - let mut relay = sslrelay::SSLRelay::new(Handler, ConfigType::Default); + let mut relay = sslrelay::SSLRelay::new( + Handler, + RelayConfig { + downstream_data_type: TCPDataType::TLS, + upstream_data_type: TCPDataType::TLS, + bind_host: "0.0.0.0".to_string(), + bind_port: "443".to_string(), + remote_host: "remote.com".to_string(), + remote_port: "443".to_string(), + tls_config: TLSConfig::FILE{ + certificate_path: "./tls.crt".to_string(), + private_key_path: "./tls.key".to_string(), + }, + } + ); // Start listening relay.start(); diff --git a/relay_config.example.toml b/relay_config.example.toml deleted file mode 100644 index 5bb8f2c..0000000 --- a/relay_config.example.toml +++ /dev/null @@ -1,8 +0,0 @@ -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" -downstream_data_type = "tls" -upstream_data_type = "tls" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index fda89c4..45b76a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,7 @@ //! ``` //! ## Example (basic.rs) //! ``` -//! use sslrelay::{self, ConfigType, RelayConfig, HandlerCallbacks, CallbackRet, TCPDataType}; +//! use sslrelay::{self, RelayConfig, HandlerCallbacks, CallbackRet, TCPDataType, TLSConfig}; //! //! // Handler object //! #[derive(Clone)] // Must have Clone trait implemented. @@ -63,29 +63,36 @@ //! // Create new SSLRelay object //! let mut relay = sslrelay::SSLRelay::new( //! Handler, -//! ConfigType::Conf(RelayConfig { +//! RelayConfig { //! downstream_data_type: TCPDataType::TLS, //! upstream_data_type: TCPDataType::TLS, //! bind_host: "0.0.0.0".to_string(), //! bind_port: "443".to_string(), //! remote_host: "remote.com".to_string(), //! remote_port: "443".to_string(), -//! ssl_private_key_path: Some("./remote.com.key".to_string()), -//! ssl_cert_path: Some("./remote.com.crt".to_string()), -//! }) +//! tls_config: TLSConfig::FILE{ +//! certificate_path: "./tls.crt".to_string(), +//! private_key_path: "./tls.key".to_string(), +//! }, +//! } //! ); +//! //! // Start listening //! relay.start(); //! } //! ``` -use openssl::ssl::{ - SslVerifyMode, - SslConnector, - SslAcceptor, - SslStream, - SslFiletype, - SslMethod +use openssl::{ + x509::X509, + pkey::PKey, + ssl::{ + SslVerifyMode, + SslConnector, + SslAcceptor, + SslStream, + SslFiletype, + SslMethod, + } }; use std::net::{ @@ -104,8 +111,6 @@ use std::{ }; use std::{ - env, - fs, path::Path, time::Duration, }; @@ -122,8 +127,6 @@ use std::sync::mpsc::{ Sender }; -use toml::Value as TValue; - mod data; mod tcp; mod relay; @@ -154,16 +157,15 @@ pub enum TCPDataType { RAW, } -/// The relay configuration type. -/// Env: Uses the SSLRELAY_CONFIG environmental variable for the path to the config file. -/// Path: Specifies the path to the config file. -/// Conf: For passing an instance of the object instead of using a config file. -/// Default: Uses ./relay_config.toml config file. -pub enum ConfigType { - Env, - Path(T), - Conf(RelayConfig), - Default, +/// TLSConfig is used to specify TLS options. +/// FILE is for specifying a path to a certificate and private key. +/// DATA is for passing the certificate and private key bytes directly. +/// NONE is for when you are not using TLS on the listening/downstream side of the relay. +#[derive(Clone)] +pub enum TLSConfig { + FILE {certificate_path: String, private_key_path: String}, + DATA {certificate: Vec, private_key: Vec}, + NONE, } /// Relay Config structure for passing into the SSLRelay::new() config parameter. @@ -175,8 +177,7 @@ pub struct RelayConfig { pub bind_port: String, pub remote_host: String, pub remote_port: String, - pub ssl_private_key_path: Option, - pub ssl_cert_path: Option, + pub tls_config: TLSConfig, } /// CallbackRet for blocking callback functions diff --git a/src/relay.rs b/src/relay.rs index ffb121f..36342bb 100644 --- a/src/relay.rs +++ b/src/relay.rs @@ -5,28 +5,27 @@ use crate::{ HandlerCallbacks, InnerHandlers, TCPDataType, - ConfigType, TcpListener, thread, FullDuplexTcp, DataStreamType, RelayConfig, - env, - TValue, - fs, Arc, SslAcceptor, Path, SslMethod, SslFiletype, + TLSConfig, + PKey, + X509, }; impl SSLRelay { /// Creates new SSLRelay instance. - pub fn new(handlers: H, config: ConfigType) -> Self { + pub fn new(handlers: H, config: RelayConfig) -> Self { SSLRelay { - config: Self::load_relay_config(config), + config, handlers: Some(InnerHandlers{cb: handlers}), } } @@ -35,13 +34,15 @@ impl { - let acceptor = self.setup_ssl_config(self.config.ssl_private_key_path.clone(), self.config.ssl_cert_path.clone()); + + let acceptor = self.setup_ssl_config(self.config.tls_config.clone()); for stream in listener.incoming() { @@ -61,7 +62,7 @@ impl fdtcp.handle(), - Err(_ec) => {} + Err(_ec) => {println!("[SSLRelay Error] Failed to handle TCP(TLS) connection: {}", _ec)} } }, Err(e) => { @@ -93,9 +94,8 @@ impl fdtcp.handle(), - Err(_ec) => {}, + Err(_ec) => println!("[SSLRelay Error] Failed to handle TCP connection: {}", _ec), } - }); }, Err(e) => {println!("[Error] Tcp Connection Failed: {}", e)} @@ -105,103 +105,33 @@ impl) -> RelayConfig { - - let mut resolved_path = String::from("./relay_config.toml"); - match config { - 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::Conf(conf) => { - return conf; - } - 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 upstream_tls_conf = config_parsed["upstream_data_type"].to_string().replace("\"", "").to_lowercase(); - let downstream_tls_conf = config_parsed["downstream_data_type"].to_string().replace("\"", "").to_lowercase(); - - let upstream_data_type: TCPDataType; - let downstream_data_type: TCPDataType; - - if upstream_tls_conf == "tls" { - upstream_data_type = TCPDataType::TLS; - } else if upstream_tls_conf == "raw" { - upstream_data_type = TCPDataType::RAW; - } else { - panic!("[SSLRelay Error] Unrecognized TCPDataType for upstream_data_type. Data type received was not 'tcp' or 'tls'!"); -// Create error handling for load_relay_config() - } - - if downstream_tls_conf == "tls" { - downstream_data_type = TCPDataType::TLS; - } else if downstream_tls_conf == "raw" { - downstream_data_type = TCPDataType::RAW; - } else { - panic!("[SSLRelay Error] Unrecognized TCPDataType for downstream_data_type. Data type received was not 'tcp' or 'tls'!"); -// Create error handling for load_relay_config() - } - - let mut ssl_pk_path = None; - let mut ssl_c_path = None; - - if !ssl_private_key_path.is_empty() { - ssl_pk_path = Some(ssl_private_key_path.clone()); - } - - if !ssl_cert_path.is_empty() { - ssl_c_path = Some(ssl_cert_path.clone()); - } - - RelayConfig { - upstream_data_type, - downstream_data_type, - bind_host: bind_host.clone(), - bind_port: bind_port.clone(), - ssl_private_key_path: ssl_pk_path, - ssl_cert_path: ssl_c_path, - remote_host: remote_host.clone(), - remote_port: remote_port.clone(), - } - } - - fn setup_ssl_config(&self, priv_key: Option, cert: Option) -> Arc { + fn setup_ssl_config(&self, tls_config: TLSConfig) -> Arc { let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - let private_key = priv_key.expect("[SSLRelay Error] No private key file specified!"); - let certificate = cert.expect("[SSLRelay Error] No certificate file specified!"); - - if !Path::new(&private_key).exists() { - panic!("[-] [{}] does not exist!", private_key); - } - acceptor.set_private_key_file(private_key, SslFiletype::PEM).unwrap(); + match tls_config { + TLSConfig::FILE{certificate_path, private_key_path} => { - if !Path::new(&certificate).exists() { - panic!("[-] [{}] does not exist!", certificate); + if !Path::new(&private_key_path).exists() { + panic!("[-] [{}] does not exist!", private_key_path); + } + if !Path::new(&certificate_path).exists() { + panic!("[-] [{}] does not exist!", certificate_path); + } + acceptor.set_private_key_file(private_key_path, SslFiletype::PEM).unwrap(); + acceptor.set_certificate_chain_file(certificate_path).unwrap(); + acceptor.check_private_key().unwrap(); + }, + TLSConfig::DATA{certificate, private_key} => { + let x_509_certificate = X509::from_pem(certificate.as_slice()).unwrap(); + let private_key = PKey::private_key_from_pem(private_key.as_slice()).unwrap(); + acceptor.set_certificate(x_509_certificate.as_ref()).unwrap(); + acceptor.set_private_key(private_key.as_ref()).unwrap(); + }, + TLSConfig::NONE => { + panic!("[SSLRelay Error] Specified NONE for TLSConfig and downstream_data_type as TLS."); + } } - acceptor.set_certificate_chain_file(certificate).unwrap(); - - acceptor.check_private_key().unwrap(); Arc::new(acceptor.build()) } }// SSLRelay \ No newline at end of file From fea7a127b4f7fe1774a286df63a5fcb32abd347a Mon Sep 17 00:00:00 2001 From: PinkP4nther <0x0090@protonmail.com> Date: Sat, 9 Oct 2021 22:29:05 -0700 Subject: [PATCH 06/10] Add to network programming category --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1ee0feb..2938cd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" description = "A TCP relay library for relaying/modifying/spoofing TCP traffic by implementing callback code." repository = "https://github.com/PinkP4nther/SSLRelay-lib" keywords = ["tcp", "networking", "relay", "tls", "ssl"] -categories = ["reverse-engineering", "network-relay", "tcp"] +categories = ["network-programming"] license = "Apache-2.0" [dependencies.openssl] From 1b2ed7a10dfd738d8895923edc495daf2fc9a1ed Mon Sep 17 00:00:00 2001 From: PinkP4nther <0x0090@protonmail.com> Date: Sun, 10 Oct 2021 00:48:53 -0700 Subject: [PATCH 07/10] Silenced channel send error for StreamWrite's to master thread. If client disconnects before server send response the relay will now just silently close the connection. --- Cargo.toml | 2 +- src/data.rs | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2938cd6..395b376 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sslrelay" -version = "0.6.0" +version = "0.6.1" authors = ["PinkP4nther @Pink_P4nther"] edition = "2018" description = "A TCP relay library for relaying/modifying/spoofing TCP traffic by implementing callback code." diff --git a/src/data.rs b/src/data.rs index 0a16fd6..32d2655 100644 --- a/src/data.rs +++ b/src/data.rs @@ -79,7 +79,9 @@ impl DownStreamInner { if byte_count > 0 { if let Err(e) = data_out.send(FullDuplexTcpState::UpStreamWrite(self.internal_data_buffer.clone())) { - Self::handle_error(format!("Failed to send UpStreamWrite to main thread: {}", e).as_str()); + + //Self::handle_error(format!("Failed to send UpStreamWrite to main thread: {}", e).as_str()); + let _ = raw_stream.shutdown(Shutdown::Both); return; } @@ -150,7 +152,8 @@ impl DownStreamInner { if byte_count > 0 { if let Err(e) = data_out.send(FullDuplexTcpState::UpStreamWrite(self.internal_data_buffer.clone())) { - Self::handle_error(format!("Failed to send UpStreamWrite to main thread: {}", e).as_str()); + + //Self::handle_error(format!("Failed to send UpStreamWrite to main thread: {}", e).as_str()); let _ = tls_stream.shutdown(); return; } @@ -292,7 +295,9 @@ impl UpStreamInner { if byte_count > 0 { if let Err(e) = data_out.send(FullDuplexTcpState::DownStreamWrite(self.internal_data_buffer.clone())) { - Self::handle_error(format!("Failed to send DownStreamWrite to main thread: {}", e).as_str()); + + //Self::handle_error(format!("Failed to send DownStreamWrite to main thread: {}", e).as_str()); + let _ = raw_stream.shutdown(Shutdown::Both); return; } @@ -359,7 +364,9 @@ impl UpStreamInner { if byte_count > 0 { if let Err(e) = data_out.send(FullDuplexTcpState::DownStreamWrite(self.internal_data_buffer.clone())) { - Self::handle_error(format!("Failed to send DownStreamWrite to main thread: {}", e).as_str()); + + //Self::handle_error(format!("Failed to send DownStreamWrite to main thread: {}", e).as_str()); + let _ = tls_stream.shutdown(); return; } From b5ef3263c65ac903cfb8136311a0dd0ddbbb409c Mon Sep 17 00:00:00 2001 From: PinkP4nther <0x0090@protonmail.com> Date: Sun, 10 Oct 2021 00:51:30 -0700 Subject: [PATCH 08/10] Warnings gone --- src/data.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data.rs b/src/data.rs index 32d2655..3a20305 100644 --- a/src/data.rs +++ b/src/data.rs @@ -78,7 +78,7 @@ impl DownStreamInner { if let Some(byte_count) = Self::get_data_stream(&mut raw_stream, &mut self.internal_data_buffer) { if byte_count > 0 { - if let Err(e) = data_out.send(FullDuplexTcpState::UpStreamWrite(self.internal_data_buffer.clone())) { + if let Err(_e) = data_out.send(FullDuplexTcpState::UpStreamWrite(self.internal_data_buffer.clone())) { //Self::handle_error(format!("Failed to send UpStreamWrite to main thread: {}", e).as_str()); let _ = raw_stream.shutdown(Shutdown::Both); @@ -151,7 +151,7 @@ impl DownStreamInner { if let Some(byte_count) = Self::get_data_stream(&mut tls_stream, &mut self.internal_data_buffer) { if byte_count > 0 { - if let Err(e) = data_out.send(FullDuplexTcpState::UpStreamWrite(self.internal_data_buffer.clone())) { + if let Err(_e) = data_out.send(FullDuplexTcpState::UpStreamWrite(self.internal_data_buffer.clone())) { //Self::handle_error(format!("Failed to send UpStreamWrite to main thread: {}", e).as_str()); let _ = tls_stream.shutdown(); @@ -294,7 +294,7 @@ impl UpStreamInner { if let Some(byte_count) = Self::get_data_stream(&mut raw_stream, &mut self.internal_data_buffer) { if byte_count > 0 { - if let Err(e) = data_out.send(FullDuplexTcpState::DownStreamWrite(self.internal_data_buffer.clone())) { + if let Err(_e) = data_out.send(FullDuplexTcpState::DownStreamWrite(self.internal_data_buffer.clone())) { //Self::handle_error(format!("Failed to send DownStreamWrite to main thread: {}", e).as_str()); let _ = raw_stream.shutdown(Shutdown::Both); @@ -363,7 +363,7 @@ impl UpStreamInner { if let Some(byte_count) = Self::get_data_stream(&mut tls_stream, &mut self.internal_data_buffer) { if byte_count > 0 { - if let Err(e) = data_out.send(FullDuplexTcpState::DownStreamWrite(self.internal_data_buffer.clone())) { + if let Err(_e) = data_out.send(FullDuplexTcpState::DownStreamWrite(self.internal_data_buffer.clone())) { //Self::handle_error(format!("Failed to send DownStreamWrite to main thread: {}", e).as_str()); let _ = tls_stream.shutdown(); From 0e9b4feaf733d21dbcb561c23b9bd37b7ee5c8d7 Mon Sep 17 00:00:00 2001 From: PinkP4nther <0x0090@protonmail.com> Date: Sun, 10 Oct 2021 00:53:50 -0700 Subject: [PATCH 09/10] Version 0.6.2 --- Cargo.toml | 2 +- README.md | 5 ++++- src/lib.rs | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 395b376..d74ade3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sslrelay" -version = "0.6.1" +version = "0.6.2" authors = ["PinkP4nther @Pink_P4nther"] edition = "2018" description = "A TCP relay library for relaying/modifying/spoofing TCP traffic by implementing callback code." diff --git a/README.md b/README.md index 3aa255e..ef407d8 100644 --- a/README.md +++ b/README.md @@ -31,4 +31,7 @@ A TCP relay library that can handle raw TCP and SSL/TLS connections. You can rea > > 10/08/2021 | **v0.4.4** | Added ability to set TLS certificate and certificate private key to nothing. When passing RelayConfig to the relay object use the 'None' variant of Option enum. In a config file put the cert path and key path as an empty 'String' to specify 'None'. > -> 10/09/2021 | **v0.6.0** | Gone away with 'ConfigType'! No more specifying config files unless the developer implements it themself. A new config enum 'TLSConfig' has been introduced. This has 3 variants FILE(Specify the cert and pk file paths), DATA(Pass the cert(PEM) data and the pk(PEM) data as bytes), NONE(This is when you are not using TLS on the listening/downstream side of the relay). \ No newline at end of file +> 10/09/2021 | **v0.6.0** | Gone away with 'ConfigType'! No more specifying config files unless the developer implements it themself. A new config enum 'TLSConfig' has been introduced. This has 3 variants FILE(Specify the cert and pk file paths), DATA(Pass the cert(PEM) data and the pk(PEM) data as bytes), NONE(This is when you are not using TLS on the listening/downstream side of the relay). +> +> 10/10/2021 | **v0.6.2** | StreamWrite's to master thread are no longer verbose when the opposite stream disconnects randomly. +> \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 45b76a6..e6cfa2f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ //! ## SSLRelay //! Library for relaying TCP traffic as well as TLS encrypted TCP traffic. -//! This Library allows you to implement callback functions for upstream and downstream traffic. +//! This library allows you to implement callback functions for upstream and downstream traffic. //! These callbacks can R/W the data from a stream(Blocking) or only R the data(Non-Blocking). //!``` //!pub trait HandlerCallbacks { From 6828beeb5235d1faa38747676a8b6d40e7e4a4f2 Mon Sep 17 00:00:00 2001 From: ZettaScript Date: Thu, 30 Oct 2025 11:54:08 +0100 Subject: [PATCH 10/10] Fmt, add experimental features --- .vscode/settings.json | 3 + examples/basic.rs | 66 ++++ examples/basic/src/main.rs | 57 --- rustfmt.toml | 8 + src/data.rs | 741 +++++++++++++++++-------------------- src/lib.rs | 274 +++++++------- src/relay.rs | 324 ++++++++++------ src/tcp.rs | 581 +++++++++++++++++------------ 8 files changed, 1091 insertions(+), 963 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 examples/basic.rs delete mode 100644 examples/basic/src/main.rs create mode 100644 rustfmt.toml diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e931c34 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.showUnlinkedFileNotification": false +} \ No newline at end of file diff --git a/examples/basic.rs b/examples/basic.rs new file mode 100644 index 0000000..9a2da22 --- /dev/null +++ b/examples/basic.rs @@ -0,0 +1,66 @@ +use sslrelay::{self, CallbackRet, HandlerCallbacks, RelayConfig, TCPDataType, TLSConfig}; + +// Handler object +#[derive(Clone)] // Must have Clone trait implemented. +struct Handler; + +/* + Callback traits that can be used to read or inject data + into data upstream or downstream. +*/ +impl HandlerCallbacks for Handler { + // DownStream non blocking callback + fn ds_nb_callback(&self, in_data: Vec, _conn_id: u64) { + if let Ok(in_data) = str::from_utf8(&in_data) { + println!("[downstream] {in_data}"); + } else { + //println!("[downstream] {in_data:?}"); + } + } + + // DownStream blocking callback + fn ds_b_callback(&mut self, _in_data: Vec, _conn_id: u64) -> CallbackRet { + //println!("[CALLBACK] Down Stream Blocking CallBack!"); + CallbackRet::Relay(_in_data) + } + + // UpStream non blocking callback + fn us_nb_callback(&self, in_data: Vec, _conn_id: u64) { + if let Ok(in_data) = str::from_utf8(&in_data) { + println!("[upstream] {in_data}"); + } else { + //println!("[upstream] {in_data:?}"); + } + } + + // UpStream blocking callback + fn us_b_callback(&mut self, _in_data: Vec, _conn_id: u64) -> CallbackRet { + //println!("[CALLBACK] Up Stream Blocking CallBack!"); + CallbackRet::Relay(_in_data) + } +} + +fn main() { + // Create new SSLRelay object + let mut relay = sslrelay::SSLRelay::new( + Handler, + RelayConfig { + downstream_data_type: TCPDataType::TLS, + upstream_data_type: TCPDataType::TLS, + bind_host: "127.0.0.1".to_string(), + bind_port: "443".to_string(), + remote_host: |server_name| { + server_name.map_or_else(|| panic!("NO HOST"), str::to_string) + }, + remote_port: "443".to_string(), + tls_config: + TLSConfig::FILE { + certificate_path: "/dev/shm/exp/certs/prime256v1/apple.com.crt".to_string(), + private_key_path: "/dev/shm/exp/certs/prime256v1/apple.com.key".to_string(), + }, + }, + ); + + // Start listening + relay.start(); +} diff --git a/examples/basic/src/main.rs b/examples/basic/src/main.rs deleted file mode 100644 index cf8ff14..0000000 --- a/examples/basic/src/main.rs +++ /dev/null @@ -1,57 +0,0 @@ -use sslrelay::{self, RelayConfig, HandlerCallbacks, CallbackRet, TCPDataType, TLSConfig}; - -// Handler object -#[derive(Clone)] // Must have Clone trait implemented. -struct Handler; - -/* - Callback traits that can be used to read or inject data - into data upstream or downstream. -*/ -impl HandlerCallbacks for Handler { - - // DownStream non blocking callback - fn ds_nb_callback(&self, _in_data: Vec) { - println!("[CALLBACK] Down Stream Non Blocking CallBack!"); - } - - // DownStream blocking callback - fn ds_b_callback(&mut self, _in_data: Vec) -> CallbackRet { - println!("[CALLBACK] Down Stream Blocking CallBack!"); - CallbackRet::Relay(_in_data) - } - - // UpStream non blocking callback - fn us_nb_callback(&self, _in_data: Vec) { - println!("[CALLBACK] Up Stream Non Blocking CallBack!"); - } - - // UpStream blocking callback - fn us_b_callback(&mut self, _in_data: Vec) -> CallbackRet { - println!("[CALLBACK] Up Stream Blocking CallBack!"); - CallbackRet::Relay(_in_data) - } -} - -fn main() { - - // Create new SSLRelay object - let mut relay = sslrelay::SSLRelay::new( - Handler, - RelayConfig { - downstream_data_type: TCPDataType::TLS, - upstream_data_type: TCPDataType::TLS, - bind_host: "0.0.0.0".to_string(), - bind_port: "443".to_string(), - remote_host: "remote.com".to_string(), - remote_port: "443".to_string(), - tls_config: TLSConfig::FILE{ - certificate_path: "./tls.crt".to_string(), - private_key_path: "./tls.key".to_string(), - }, - } - ); - - // Start listening - relay.start(); -} \ No newline at end of file diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..ade1f81 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,8 @@ +hard_tabs = true +newline_style = "unix" + +unstable_features = true +format_code_in_doc_comments = true +format_macro_bodies = true +format_macro_matchers = true +format_strings = true diff --git a/src/data.rs b/src/data.rs index 3a20305..f28fc03 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,441 +1,370 @@ use crate::{ - DownStreamInner, - UpStreamInner, - FullDuplexTcpState, - DataPipe, - DataStreamType, - Sender, - Receiver, - Shutdown, - mpsc, - Duration, - Read, - Write, - io, + io, mpsc, DataPipe, DataStreamType, DownStreamInner, Duration, FullDuplexTcpState, Read, + Receiver, Sender, Shutdown, UpStreamInner, Write, }; impl DownStreamInner { + fn handle_error(error_description: &str) { + println!("[SSLRelay DownStream Thread Error]: {}", error_description); + } - fn handle_error(error_description: &str) { - println!("[SSLRelay DownStream Thread Error]: {}", error_description); - } + pub fn ds_handler(self, data_out: Sender, data_in: Receiver) { + match &self.ds_stream { + DataStreamType::RAW(_) => self.handle_raw(data_out, data_in), + DataStreamType::TLS(_) => self.handle_tls(data_out, data_in), + } + } - pub fn ds_handler(self, data_out: Sender, data_in: Receiver) { + fn handle_raw(mut self, data_out: Sender, data_in: Receiver) { + let mut raw_stream = match &self.ds_stream { + DataStreamType::RAW(ref s) => s, + _ => return, + }; - match &self.ds_stream { - DataStreamType::RAW(_) => self.handle_raw(data_out, data_in), - DataStreamType::TLS(_) => self.handle_tls(data_out, data_in), - } - } + loop { + match data_in.recv_timeout(Duration::from_millis(50)) { + // DataPipe Received + Ok(data_received) => match data_received { + DataPipe::DataWrite(data) => { + match raw_stream.write_all(&data) { + Ok(()) => {} + Err(_e) => { + Self::handle_error( + "Failed to write data to DownStream tcp stream!", + ); + let _ = data_out.send(FullDuplexTcpState::DownStreamShutDown); + let _ = raw_stream.shutdown(Shutdown::Both); + return; + } + } + let _ = raw_stream.flush(); + } + DataPipe::Shutdown => { + let _ = raw_stream.shutdown(Shutdown::Both); + return; + } + }, + Err(_e) => match _e { + mpsc::RecvTimeoutError::Timeout => {} + mpsc::RecvTimeoutError::Disconnected => { + Self::handle_error("DownStream data_in channel is disconnected!"); + return; + } + }, + } // End of data_in receive - fn handle_raw(mut self, data_out: Sender, data_in: Receiver) { + // If received data + if let Some(byte_count) = + Self::get_data_stream(&mut raw_stream, &mut self.internal_data_buffer) + { + if byte_count > 0 { + if let Err(_e) = data_out.send(FullDuplexTcpState::UpStreamWrite( + self.internal_data_buffer.clone(), + )) { + //Self::handle_error(format!("Failed to send UpStreamWrite to main thread: {}", e).as_str()); + let _ = raw_stream.shutdown(Shutdown::Both); + return; + } - let mut raw_stream = match &self.ds_stream { - DataStreamType::RAW(ref s) => s, - _ => return, - }; + self.internal_data_buffer.clear(); + } else if byte_count == 0 || byte_count == -2 { + let _ = data_out.send(FullDuplexTcpState::DownStreamShutDown); + let _ = raw_stream.shutdown(Shutdown::Both); + return; + } else if byte_count == -1 { + continue; + } + } else { + } + } + } - loop { + fn handle_tls(mut self, data_out: Sender, data_in: Receiver) { + let mut tls_stream = match self.ds_stream { + DataStreamType::TLS(ref mut s) => s, + _ => return, + }; - match data_in.recv_timeout(Duration::from_millis(50)) { + loop { + match data_in.recv_timeout(Duration::from_millis(50)) { + // DataPipe Received + Ok(data_received) => match data_received { + DataPipe::DataWrite(data) => { + match tls_stream.write_all(&data) { + Ok(()) => {} + Err(_e) => { + Self::handle_error( + "Failed to write data to DownStream tcp stream!", + ); + let _ = data_out.send(FullDuplexTcpState::DownStreamShutDown); + let _ = tls_stream.shutdown(); + return; + } + } + let _ = tls_stream.flush(); + } + DataPipe::Shutdown => { + let _ = tls_stream.shutdown(); + return; + } + }, + Err(_e) => match _e { + mpsc::RecvTimeoutError::Timeout => {} + mpsc::RecvTimeoutError::Disconnected => { + Self::handle_error("DownStream data_in channel is disconnected!"); + return; + } + }, + } // End of data_in receive - // DataPipe Received - Ok(data_received) => { + // If received data + if let Some(byte_count) = + Self::get_data_stream(&mut tls_stream, &mut self.internal_data_buffer) + { + if byte_count > 0 { + if let Err(_e) = data_out.send(FullDuplexTcpState::UpStreamWrite( + self.internal_data_buffer.clone(), + )) { + //Self::handle_error(format!("Failed to send UpStreamWrite to main thread: {}", e).as_str()); + let _ = tls_stream.shutdown(); + return; + } - match data_received { - DataPipe::DataWrite(data) => { + self.internal_data_buffer.clear(); + } else if byte_count == 0 || byte_count == -2 { + let _ = data_out.send(FullDuplexTcpState::DownStreamShutDown); + let _ = tls_stream.shutdown(); + return; + } else if byte_count == -1 { + continue; + } + } else { + } + } + } - match raw_stream.write_all(&data) { - Ok(()) => {}, - Err(_e) => { - Self::handle_error("Failed to write data to DownStream tcp stream!"); - let _ = data_out.send(FullDuplexTcpState::DownStreamShutDown); - let _ = raw_stream.shutdown(Shutdown::Both); - return; - } - } - let _ = raw_stream.flush(); + fn get_data_stream(stream: &mut S, internal_data_buffer: &mut Vec) -> Option { + let mut data_length: i64 = 0; - }, - DataPipe::Shutdown => { - let _ = raw_stream.shutdown(Shutdown::Both); - return; - }, - } - }, - Err(_e) => { - match _e { - mpsc::RecvTimeoutError::Timeout => {}, - mpsc::RecvTimeoutError::Disconnected => { - Self::handle_error("DownStream data_in channel is disconnected!"); - return; - } - } - } - }// End of data_in receive + loop { + let mut r_buf = [0; 1024]; - // If received data - if let Some(byte_count) = Self::get_data_stream(&mut raw_stream, &mut self.internal_data_buffer) { - if byte_count > 0 { + match stream.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); + */ - if let Err(_e) = data_out.send(FullDuplexTcpState::UpStreamWrite(self.internal_data_buffer.clone())) { - - //Self::handle_error(format!("Failed to send UpStreamWrite to main thread: {}", e).as_str()); - let _ = raw_stream.shutdown(Shutdown::Both); - return; - } + //let _bw = self.internal_data_buffer.write(&tmp_buf).unwrap(); - self.internal_data_buffer.clear(); - - } else if byte_count == 0 || byte_count == -2 { - - let _ = data_out.send(FullDuplexTcpState::DownStreamShutDown); - let _ = raw_stream.shutdown(Shutdown::Both); - return; - - } else if byte_count == -1 { - continue; - } - } else { - - } - } - } - - fn handle_tls(mut self, data_out: Sender, data_in: Receiver) { - - let mut tls_stream = match self.ds_stream { - DataStreamType::TLS(ref mut s) => s, - _ => return, - }; - - loop { - - match data_in.recv_timeout(Duration::from_millis(50)) { - - // DataPipe Received - Ok(data_received) => { - - match data_received { - DataPipe::DataWrite(data) => { - - match tls_stream.write_all(&data) { - Ok(()) => {}, - Err(_e) => { - Self::handle_error("Failed to write data to DownStream tcp stream!"); - let _ = data_out.send(FullDuplexTcpState::DownStreamShutDown); - let _ = tls_stream.shutdown(); - return; - } - } - let _ = tls_stream.flush(); - }, - DataPipe::Shutdown => { - let _ = tls_stream.shutdown(); - return; - }, - } - }, - Err(_e) => { - match _e { - mpsc::RecvTimeoutError::Timeout => {}, - mpsc::RecvTimeoutError::Disconnected => { - Self::handle_error("DownStream data_in channel is disconnected!"); - return; - } - } - } - }// End of data_in receive - - // If received data - if let Some(byte_count) = Self::get_data_stream(&mut tls_stream, &mut self.internal_data_buffer) { - if byte_count > 0 { - - if let Err(_e) = data_out.send(FullDuplexTcpState::UpStreamWrite(self.internal_data_buffer.clone())) { - - //Self::handle_error(format!("Failed to send UpStreamWrite to main thread: {}", e).as_str()); - let _ = tls_stream.shutdown(); - return; - } - - self.internal_data_buffer.clear(); - - } else if byte_count == 0 || byte_count == -2 { - - let _ = data_out.send(FullDuplexTcpState::DownStreamShutDown); - let _ = tls_stream.shutdown(); - return; - - } else if byte_count == -1 { - continue; - } - } else { - - } - } - } - - fn get_data_stream(stream: &mut S, internal_data_buffer: &mut Vec) -> Option { - - let mut data_length: i64 = 0; - - loop { - - let mut r_buf = [0; 1024]; - - match stream.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 = self.internal_data_buffer.write(&tmp_buf).unwrap(); - - let _bw = internal_data_buffer.write(r_buf.split_at(bytes_read).0).unwrap(); - data_length += bytes_read as i64; - - } else { - println!("[+] Else hit!!!!!!!!!!!!!!!!!!!!!!"); - } - }, - Err(e) => { - match e.kind() { - - io::ErrorKind::WouldBlock => { - if data_length == 0 { - - data_length = -1; - } - break; - - }, - io::ErrorKind::ConnectionReset => { - data_length = -2; - break; - }, - _ => {println!("[!!!] Got error: {}",e);} - } - }, - } - } - return Some(data_length); - } + let _bw = internal_data_buffer + .write(r_buf.split_at(bytes_read).0) + .unwrap(); + data_length += bytes_read as i64; + } else { + println!("[+] Else hit!!!!!!!!!!!!!!!!!!!!!!"); + } + } + Err(e) => match e.kind() { + io::ErrorKind::WouldBlock => { + if data_length == 0 { + data_length = -1; + } + break; + } + io::ErrorKind::ConnectionReset => { + data_length = -2; + break; + } + _ => { + println!("[!!!downstream] Got error: {}", e); + } + }, + } + } + return Some(data_length); + } } - impl UpStreamInner { + fn handle_error(error_description: &str) { + println!("[SSLRelay UpStream Thread Error]: {}", error_description); + } - fn handle_error(error_description: &str) { - println!("[SSLRelay UpStream Thread Error]: {}", error_description); - } + pub fn us_handler(self, data_out: Sender, data_in: Receiver) { + match &self.us_stream { + DataStreamType::RAW(_) => self.handle_raw(data_out, data_in), + DataStreamType::TLS(_) => self.handle_tls(data_out, data_in), + } + } - pub fn us_handler(self, data_out: Sender, data_in: Receiver) { + fn handle_raw(mut self, data_out: Sender, data_in: Receiver) { + let mut raw_stream = match self.us_stream { + DataStreamType::RAW(ref s) => s, + _ => return, + }; - match &self.us_stream { - DataStreamType::RAW(_) => self.handle_raw(data_out, data_in), - DataStreamType::TLS(_) => self.handle_tls(data_out, data_in), - } + loop { + match data_in.recv_timeout(Duration::from_millis(50)) { + Ok(data_received) => match data_received { + DataPipe::DataWrite(data) => { + match raw_stream.write_all(&data) { + Ok(()) => {} + Err(_e) => { + Self::handle_error("Failed to write data to UpStream tcp stream!"); + let _ = data_out.send(FullDuplexTcpState::UpStreamShutDown); + let _ = raw_stream.shutdown(Shutdown::Both); + return; + } + } + let _ = raw_stream.flush(); + } + DataPipe::Shutdown => { + let _ = raw_stream.shutdown(Shutdown::Both); + return; + } + }, + Err(e) => match e { + mpsc::RecvTimeoutError::Timeout => {} + mpsc::RecvTimeoutError::Disconnected => { + Self::handle_error("UpStream data_in channel is disconnected!"); + return; + } + }, + } // End of data_in receive - } + if let Some(byte_count) = + Self::get_data_stream(&mut raw_stream, &mut self.internal_data_buffer) + { + if byte_count > 0 { + if let Err(_e) = data_out.send(FullDuplexTcpState::DownStreamWrite( + self.internal_data_buffer.clone(), + )) { + //Self::handle_error(format!("Failed to send DownStreamWrite to main thread: {}", e).as_str()); + let _ = raw_stream.shutdown(Shutdown::Both); + return; + } - fn handle_raw(mut self, data_out: Sender, data_in: Receiver) { + self.internal_data_buffer.clear(); + } else if byte_count == 0 || byte_count == -2 { + let _ = data_out.send(FullDuplexTcpState::UpStreamShutDown); + let _ = raw_stream.shutdown(Shutdown::Both); + return; + } else if byte_count == -1 { + continue; + } + } else { + } + } + } - let mut raw_stream = match self.us_stream { - DataStreamType::RAW(ref s) => s, - _ => return, - }; + fn handle_tls(mut self, data_out: Sender, data_in: Receiver) { + let mut tls_stream = match self.us_stream { + DataStreamType::TLS(ref mut s) => s, + _ => return, + }; - loop { + loop { + match data_in.recv_timeout(Duration::from_millis(50)) { + Ok(data_received) => match data_received { + DataPipe::DataWrite(data) => { + match tls_stream.write_all(&data) { + Ok(()) => {} + Err(_e) => { + Self::handle_error("Failed to write data to UpStream tcp stream!"); + let _ = data_out.send(FullDuplexTcpState::UpStreamShutDown); + let _ = tls_stream.shutdown(); + return; + } + } + let _ = tls_stream.flush(); + } + DataPipe::Shutdown => { + let _ = tls_stream.shutdown(); + return; + } + }, + Err(e) => match e { + mpsc::RecvTimeoutError::Timeout => {} + mpsc::RecvTimeoutError::Disconnected => { + Self::handle_error("UpStream data_in channel is disconnected!"); + return; + } + }, + } // End of data_in receive - match data_in.recv_timeout(Duration::from_millis(50)) { + if let Some(byte_count) = + Self::get_data_stream(&mut tls_stream, &mut self.internal_data_buffer) + { + if byte_count > 0 { + if let Err(_e) = data_out.send(FullDuplexTcpState::DownStreamWrite( + self.internal_data_buffer.clone(), + )) { + //Self::handle_error(format!("Failed to send DownStreamWrite to main thread: {}", e).as_str()); + let _ = tls_stream.shutdown(); + return; + } - Ok(data_received) => { + self.internal_data_buffer.clear(); + } else if byte_count == 0 || byte_count == -2 { + let _ = data_out.send(FullDuplexTcpState::UpStreamShutDown); + let _ = tls_stream.shutdown(); + return; + } else if byte_count == -1 { + continue; + } + } else { + } + } + } - match data_received { - DataPipe::DataWrite(data) => { + fn get_data_stream(stream: &mut S, internal_data_buffer: &mut Vec) -> Option { + let mut data_length: i64 = 0; - match raw_stream.write_all(&data) { - Ok(()) => {}, - Err(_e) => { - Self::handle_error("Failed to write data to UpStream tcp stream!"); - let _ = data_out.send(FullDuplexTcpState::UpStreamShutDown); - let _ = raw_stream.shutdown(Shutdown::Both); - return; - } - } - let _ = raw_stream.flush(); - }, - DataPipe::Shutdown => { - let _ = raw_stream.shutdown(Shutdown::Both); - return; - } - } - }, - Err(e) => { - match e { - mpsc::RecvTimeoutError::Timeout => {}, - mpsc::RecvTimeoutError::Disconnected => { - Self::handle_error("UpStream data_in channel is disconnected!"); - return; - } - } - } - }// End of data_in receive + loop { + let mut r_buf = [0; 1024]; - if let Some(byte_count) = Self::get_data_stream(&mut raw_stream, &mut self.internal_data_buffer) { - if byte_count > 0 { + match stream.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); + */ - if let Err(_e) = data_out.send(FullDuplexTcpState::DownStreamWrite(self.internal_data_buffer.clone())) { - - //Self::handle_error(format!("Failed to send DownStreamWrite to main thread: {}", e).as_str()); - let _ = raw_stream.shutdown(Shutdown::Both); - return; - } + //let _bw = self.internal_data_buffer.write(&tmp_buf).unwrap(); - self.internal_data_buffer.clear(); - - } else if byte_count == 0 || byte_count == -2 { - - let _ = data_out.send(FullDuplexTcpState::UpStreamShutDown); - let _ = raw_stream.shutdown(Shutdown::Both); - return; - } else if byte_count == -1 { - continue; - } - } else { - } - } - } - - fn handle_tls(mut self, data_out: Sender, data_in: Receiver) { - - let mut tls_stream = match self.us_stream { - DataStreamType::TLS(ref mut s) => s, - _ => return, - }; - - loop { - - match data_in.recv_timeout(Duration::from_millis(50)) { - - Ok(data_received) => { - - match data_received { - DataPipe::DataWrite(data) => { - - match tls_stream.write_all(&data) { - Ok(()) => {}, - Err(_e) => { - Self::handle_error("Failed to write data to UpStream tcp stream!"); - let _ = data_out.send(FullDuplexTcpState::UpStreamShutDown); - let _ = tls_stream.shutdown(); - return; - } - } - let _ = tls_stream.flush(); - }, - DataPipe::Shutdown => { - let _ = tls_stream.shutdown(); - return; - } - } - }, - Err(e) => { - match e { - mpsc::RecvTimeoutError::Timeout => {}, - mpsc::RecvTimeoutError::Disconnected => { - Self::handle_error("UpStream data_in channel is disconnected!"); - return; - } - } - } - }// End of data_in receive - - if let Some(byte_count) = Self::get_data_stream(&mut tls_stream, &mut self.internal_data_buffer) { - if byte_count > 0 { - - if let Err(_e) = data_out.send(FullDuplexTcpState::DownStreamWrite(self.internal_data_buffer.clone())) { - - //Self::handle_error(format!("Failed to send DownStreamWrite to main thread: {}", e).as_str()); - let _ = tls_stream.shutdown(); - return; - } - - self.internal_data_buffer.clear(); - - } else if byte_count == 0 || byte_count == -2 { - - let _ = data_out.send(FullDuplexTcpState::UpStreamShutDown); - let _ = tls_stream.shutdown(); - return; - } else if byte_count == -1 { - continue; - } - } else { - } - } - } - - fn get_data_stream(stream: &mut S, internal_data_buffer: &mut Vec) -> Option { - - let mut data_length: i64 = 0; - - loop { - - let mut r_buf = [0; 1024]; - - match stream.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 = self.internal_data_buffer.write(&tmp_buf).unwrap(); - - let _bw = internal_data_buffer.write(r_buf.split_at(bytes_read).0).unwrap(); - data_length += bytes_read as i64; - - } else { - println!("[+] Else hit!!!!!!!!!!!!!!!!!!!!!!"); - } - }, - Err(e) => { - match e.kind() { - - io::ErrorKind::WouldBlock => { - if data_length == 0 { - data_length = -1; - } - break; - }, - io::ErrorKind::ConnectionReset => { - data_length = -2; - break; - }, - _ => {println!("[!!!] Got error: {}",e);} - } - }, - } - } - return Some(data_length); - } -} \ No newline at end of file + let _bw = internal_data_buffer + .write(r_buf.split_at(bytes_read).0) + .unwrap(); + data_length += bytes_read as i64; + } else { + println!("[+] Else hit!!!!!!!!!!!!!!!!!!!!!!"); + } + } + Err(e) => match e.kind() { + io::ErrorKind::WouldBlock => { + if data_length == 0 { + data_length = -1; + } + break; + } + io::ErrorKind::ConnectionReset => { + data_length = -2; + break; + } + _ => { + println!("[!!!upstream] Got error: {}", e); + } + }, + } + } + return Some(data_length); + } +} diff --git a/src/lib.rs b/src/lib.rs index e6cfa2f..b30a64e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,157 +4,132 @@ //! This library allows you to implement callback functions for upstream and downstream traffic. //! These callbacks can R/W the data from a stream(Blocking) or only R the data(Non-Blocking). //!``` -//!pub trait HandlerCallbacks { -//! fn ds_b_callback(&mut self, _in_data: Vec) -> CallbackRet {CallbackRet::Relay(_in_data)} -//! fn ds_nb_callback(&self, _in_data: Vec){} -//! fn us_b_callback(&mut self, _in_data: Vec) -> CallbackRet {CallbackRet::Relay(_in_data)} -//! fn us_nb_callback(&self, _in_data: Vec){} -//!} -//!``` +//! pub trait HandlerCallbacks { +//! fn ds_b_callback(&mut self, _in_data: Vec) -> CallbackRet { +//! CallbackRet::Relay(_in_data) +//! } +//! fn ds_nb_callback(&self, _in_data: Vec) {} +//! fn us_b_callback(&mut self, _in_data: Vec) -> CallbackRet { +//! CallbackRet::Relay(_in_data) +//! } +//! fn us_nb_callback(&self, _in_data: Vec) {} +//! } +//! ``` //! The blocking callbacks return an enum called CallbackRet with four different variants. //! The variants control the flow of the tcp stream. //!``` //! pub enum CallbackRet { -//! Relay(Vec),// Relay data -//! Spoof(Vec),// Skip relaying and send data back -//! Shutdown,// Shutdown TCP connection -//! Freeze,// Dont send data (pretend as if stream never was recieved) +//! Relay(Vec), // Relay data +//! Spoof(Vec), // Skip relaying and send data back +//! Shutdown, // Shutdown TCP connection +//! Freeze, // Dont send data (pretend as if stream never was recieved) //! } //! ``` //! ## Example (basic.rs) //! ``` -//! use sslrelay::{self, RelayConfig, HandlerCallbacks, CallbackRet, TCPDataType, TLSConfig}; -//! +//! use sslrelay::{self, CallbackRet, HandlerCallbacks, RelayConfig, TCPDataType, TLSConfig}; +//! //! // Handler object //! #[derive(Clone)] // Must have Clone trait implemented. //! struct Handler; -//! +//! //! /* -//! Callback traits that can be used to read or inject data -//! into data upstream or downstream. +//! Callback traits that can be used to read or inject data +//! into data upstream or downstream. //! */ //! impl HandlerCallbacks for Handler { -//! -//! // DownStream non blocking callback (Read Only) -//! fn ds_nb_callback(&self, _in_data: Vec) { -//! println!("[CALLBACK] Down Stream Non Blocking CallBack!"); -//! } -//! -//! // DownStream blocking callback (Read & Write) -//! fn ds_b_callback(&mut self, _in_data: Vec) -> CallbackRet { -//! println!("[CALLBACK] Down Stream Blocking CallBack!"); -//! CallbackRet::Relay(_in_data) -//! } -//! -//! // UpStream non blocking callback (Read Only) -//! fn us_nb_callback(&self, _in_data: Vec) { -//! println!("[CALLBACK] Up Stream Non Blocking CallBack!"); -//! } -//! -//! // UpStream blocking callback (Read & Write) -//! fn us_b_callback(&mut self, _in_data: Vec) -> CallbackRet { -//! println!("[CALLBACK] Up Stream Blocking CallBack!"); -//! CallbackRet::Relay(_in_data) -//! } +//! // DownStream non blocking callback (Read Only) +//! fn ds_nb_callback(&self, _in_data: Vec) { +//! println!("[CALLBACK] Down Stream Non Blocking CallBack!"); +//! } +//! +//! // DownStream blocking callback (Read & Write) +//! fn ds_b_callback(&mut self, _in_data: Vec) -> CallbackRet { +//! println!("[CALLBACK] Down Stream Blocking CallBack!"); +//! CallbackRet::Relay(_in_data) +//! } +//! +//! // UpStream non blocking callback (Read Only) +//! fn us_nb_callback(&self, _in_data: Vec) { +//! println!("[CALLBACK] Up Stream Non Blocking CallBack!"); +//! } +//! +//! // UpStream blocking callback (Read & Write) +//! fn us_b_callback(&mut self, _in_data: Vec) -> CallbackRet { +//! println!("[CALLBACK] Up Stream Blocking CallBack!"); +//! CallbackRet::Relay(_in_data) +//! } //! } -//! +//! //! fn main() { -//! -//! // Create new SSLRelay object -//! let mut relay = sslrelay::SSLRelay::new( -//! Handler, -//! RelayConfig { -//! downstream_data_type: TCPDataType::TLS, -//! upstream_data_type: TCPDataType::TLS, -//! bind_host: "0.0.0.0".to_string(), -//! bind_port: "443".to_string(), -//! remote_host: "remote.com".to_string(), -//! remote_port: "443".to_string(), -//! tls_config: TLSConfig::FILE{ -//! certificate_path: "./tls.crt".to_string(), -//! private_key_path: "./tls.key".to_string(), -//! }, -//! } -//! ); -//! -//! // Start listening -//! relay.start(); +//! // Create new SSLRelay object +//! let mut relay = sslrelay::SSLRelay::new( +//! Handler, +//! RelayConfig { +//! downstream_data_type: TCPDataType::TLS, +//! upstream_data_type: TCPDataType::TLS, +//! bind_host: "0.0.0.0".to_string(), +//! bind_port: "443".to_string(), +//! remote_host: |_| "remote.com", +//! remote_port: "443".to_string(), +//! tls_config: TLSConfig::FILE { +//! certificate_path: "./tls.crt".to_string(), +//! private_key_path: "./tls.key".to_string(), +//! }, +//! }, +//! ); +//! +//! // Start listening +//! relay.start(); //! } //! ``` use openssl::{ - x509::X509, - pkey::PKey, - ssl::{ - SslVerifyMode, - SslConnector, - SslAcceptor, - SslStream, - SslFiletype, - SslMethod, - } + pkey::PKey, + ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod, SslStream, SslVerifyMode}, + x509::X509, }; -use std::net::{ - TcpListener, - TcpStream, - Shutdown -}; +use std::net::{Shutdown, TcpListener, TcpStream}; -use std::sync::{ - Arc, - Mutex -}; +use std::sync::{Arc, Mutex}; -use std::{ - thread -}; +use std::thread; -use std::{ - path::Path, - time::Duration, -}; +use std::{path::Path, time::Duration}; -use std::io::{ - self, - Read, - Write -}; +use std::io::{self, Read, Write}; -use std::sync::mpsc::{ - self, - Receiver, - Sender -}; +use std::sync::mpsc::{self, Receiver, Sender}; mod data; -mod tcp; mod relay; +mod tcp; #[derive(Debug)] enum FullDuplexTcpState { - DownStreamWrite(Vec), - UpStreamWrite(Vec), - DownStreamShutDown, - UpStreamShutDown, + DownStreamWrite(Vec), + UpStreamWrite(Vec), + DownStreamShutDown, + UpStreamShutDown, } #[derive(Debug)] enum DataPipe { - DataWrite(Vec), - Shutdown, + DataWrite(Vec), + Shutdown, } enum DataStreamType { - RAW(TcpStream), - TLS(SslStream), + RAW(TcpStream), + TLS(SslStream), } /// Specifies the upstream or downstream data type (TLS or RAW). #[derive(Copy, Clone)] pub enum TCPDataType { - TLS, - RAW, + TLS, + RAW, } /// TLSConfig is used to specify TLS options. @@ -163,78 +138,89 @@ pub enum TCPDataType { /// NONE is for when you are not using TLS on the listening/downstream side of the relay. #[derive(Clone)] pub enum TLSConfig { - FILE {certificate_path: String, private_key_path: String}, - DATA {certificate: Vec, private_key: Vec}, - NONE, + FILE { + certificate_path: String, + private_key_path: String, + }, + DATA { + certificate: Vec, + private_key: Vec, + }, + NONE, } /// Relay Config structure for passing into the SSLRelay::new() config parameter. #[derive(Clone)] pub struct RelayConfig { - pub downstream_data_type: TCPDataType, - pub upstream_data_type: TCPDataType, - pub bind_host: String, - pub bind_port: String, - pub remote_host: String, - pub remote_port: String, - pub tls_config: TLSConfig, + pub downstream_data_type: TCPDataType, + pub upstream_data_type: TCPDataType, + pub bind_host: String, + pub bind_port: String, + pub remote_host: fn(Option<&str>) -> String, + //pub remote_host: String, + pub remote_port: String, + pub tls_config: TLSConfig, } /// CallbackRet for blocking callback functions #[derive(Debug)] pub enum CallbackRet { - Relay(Vec),// Relay data - Spoof(Vec),// Skip relaying and send data back - Shutdown,// Shutdown TCP connection - Freeze,// Dont send data (pretend as if stream never was recieved) + Relay(Vec), // Relay data + Spoof(Vec), // Skip relaying and send data back + Shutdown, // Shutdown TCP connection + Freeze, // Dont send data (pretend as if stream never was recieved) } /// Callback functions a user may or may not implement. pub trait HandlerCallbacks { - fn ds_b_callback(&mut self, _in_data: Vec) -> CallbackRet {CallbackRet::Relay(_in_data)} - fn ds_nb_callback(&self, _in_data: Vec){} - fn us_b_callback(&mut self, _in_data: Vec) -> CallbackRet {CallbackRet::Relay(_in_data)} - fn us_nb_callback(&self, _in_data: Vec){} + fn ds_b_callback(&mut self, _in_data: Vec, _conn_id: u64) -> CallbackRet { + CallbackRet::Relay(_in_data) + } + fn ds_nb_callback(&self, _in_data: Vec, _conn_id: u64) {} + fn us_b_callback(&mut self, _in_data: Vec, _conn_id: u64) -> CallbackRet { + CallbackRet::Relay(_in_data) + } + fn us_nb_callback(&self, _in_data: Vec, _conn_id: u64) {} + fn set_server_name(&mut self, _server_name: Option<&str>) {} } /// The main SSLRelay object. #[derive(Clone)] pub struct SSLRelay where - H: HandlerCallbacks + std::marker::Sync + std::marker::Send + Clone + 'static, + H: HandlerCallbacks + std::marker::Sync + std::marker::Send + Clone + 'static, { - config: RelayConfig, - handlers: Option>, + config: RelayConfig, + handlers: Option>, } #[allow(dead_code)] struct FullDuplexTcp where - H: HandlerCallbacks + std::marker::Sync + std::marker::Send + Clone + 'static, + H: HandlerCallbacks + std::marker::Sync + std::marker::Send + Clone + 'static, { - remote_host: String, - remote_port: String, - ds_inner_m: Arc>>, - us_inner_m: Arc>>, - inner_handlers: InnerHandlers, + remote_host: String, + remote_port: String, + ds_inner_m: Arc>>, + us_inner_m: Arc>>, + inner_handlers: InnerHandlers, + conn_id: u64, } #[derive(Clone)] struct InnerHandlers where - H: HandlerCallbacks + std::marker::Sync + std::marker::Send + Clone + 'static, + H: HandlerCallbacks + std::marker::Sync + std::marker::Send + Clone + 'static, { - cb: H + cb: H, } -struct DownStreamInner -{ - ds_stream: DataStreamType, - internal_data_buffer: Vec, +struct DownStreamInner { + ds_stream: DataStreamType, + internal_data_buffer: Vec, } -struct UpStreamInner -{ - us_stream: DataStreamType, - internal_data_buffer: Vec -} \ No newline at end of file +struct UpStreamInner { + us_stream: DataStreamType, + internal_data_buffer: Vec, +} diff --git a/src/relay.rs b/src/relay.rs index 36342bb..c5be34c 100644 --- a/src/relay.rs +++ b/src/relay.rs @@ -1,137 +1,221 @@ //! SSLRelay use crate::{ - SSLRelay, - HandlerCallbacks, - InnerHandlers, - TCPDataType, - TcpListener, - thread, - FullDuplexTcp, - DataStreamType, - RelayConfig, - Arc, - SslAcceptor, - Path, - SslMethod, - SslFiletype, - TLSConfig, - PKey, - X509, + thread, Arc, DataStreamType, FullDuplexTcp, HandlerCallbacks, InnerHandlers, PKey, Path, + RelayConfig, SSLRelay, SslAcceptor, SslFiletype, SslMethod, TCPDataType, TLSConfig, + TcpListener, X509, }; impl SSLRelay { - /// Creates new SSLRelay instance. - pub fn new(handlers: H, config: RelayConfig) -> Self { + /// Creates new SSLRelay instance. + pub fn new(handlers: H, config: RelayConfig) -> Self { + SSLRelay { + config, + handlers: Some(InnerHandlers { cb: handlers }), + } + } + /// Starts the SSLRelay connection handling. + pub fn start(&mut self) { + let rhost = self.config.remote_host.clone(); + let rport = self.config.remote_port.clone(); + let upstream_data_stream_type = self.config.upstream_data_type; - SSLRelay { - config, - handlers: Some(InnerHandlers{cb: handlers}), - } - } - /// Starts the SSLRelay connection handling. - pub fn start(&mut self) { + let listener = TcpListener::bind(format!( + "{}:{}", + self.config.bind_host.clone(), + self.config.bind_port.clone() + )) + .unwrap(); - let rhost = self.config.remote_host.clone(); - let rport = self.config.remote_port.clone(); - let upstream_data_stream_type = self.config.upstream_data_type; + let mut conn_id = 0; + match self.config.downstream_data_type { + TCPDataType::TLS => { + let acceptor = self.setup_ssl_config(&self.config.tls_config); - let listener = TcpListener::bind(format!("{}:{}", self.config.bind_host.clone(), self.config.bind_port.clone())).unwrap(); + for stream in listener.incoming() { + match stream { + Ok(stream) => { + let acceptor = acceptor.clone(); + let mut handler_clone = self.handlers.as_ref().unwrap().clone(); - match self.config.downstream_data_type { + let r_host = rhost.clone(); + let r_port = rport.clone(); - TCPDataType::TLS => { - - let acceptor = self.setup_ssl_config(self.config.tls_config.clone()); + let this_conn_id = conn_id; + thread::spawn(move || { + match acceptor.accept(stream) { + Ok(stream) => { + let server_name = stream + .ssl() + .servername(openssl::ssl::NameType::HOST_NAME); + handler_clone.cb.set_server_name(server_name); + let remote_host = (r_host)(server_name); + + // FULL DUPLEX OBJECT CREATION HERE + match FullDuplexTcp::new( + DataStreamType::TLS(stream), + upstream_data_stream_type, + remote_host, + r_port, + handler_clone, + this_conn_id, + ) { + Ok(mut fdtcp) => fdtcp.handle(), + Err(_ec) => { + println!( + "[SSLRelay Error] Failed to handle TCP(TLS) \ + connection: {}", + _ec + ) + } + } + } + Err(e) => { + println!("[Error] {}", e); + } + } + }); + conn_id += 1; + } + Err(e) => { + println!("[Error] Tcp Connection Failed: {}", e) + } + } + } + } - for stream in listener.incoming() { - - match stream { - Ok(stream) => { - - let acceptor = acceptor.clone(); - let handler_clone = self.handlers.as_ref().unwrap().clone(); - - let r_host = rhost.clone(); - let r_port = rport.clone(); - - thread::spawn(move || { - - match acceptor.accept(stream) { - Ok(stream) => { - // FULL DUPLEX OBJECT CREATION HERE - match FullDuplexTcp::new(DataStreamType::TLS(stream), upstream_data_stream_type, r_host, r_port, handler_clone) { - Ok(mut fdtcp) => fdtcp.handle(), - Err(_ec) => {println!("[SSLRelay Error] Failed to handle TCP(TLS) connection: {}", _ec)} - } - }, - Err(e) => { - - println!("[Error] {}", e); - } - } - }); - }, - Err(e) => {println!("[Error] Tcp Connection Failed: {}", e)} - } - } - }, + TCPDataType::RAW => { + for stream in listener.incoming() { + match stream { + Ok(stream) => { + let handler_clone = self.handlers.as_ref().unwrap().clone(); - TCPDataType::RAW => { + let r_host = rhost.clone(); + let r_port = rport.clone(); - for stream in listener.incoming() { - - match stream { - Ok(stream) => { - - let handler_clone = self.handlers.as_ref().unwrap().clone(); - - let r_host = rhost.clone(); - let r_port = rport.clone(); - - thread::spawn(move || { - - // FULL DUPLEX OBJECT CREATION HERE - match FullDuplexTcp::new(DataStreamType::RAW(stream), upstream_data_stream_type, r_host, r_port, handler_clone) { - Ok(mut fdtcp) => fdtcp.handle(), - Err(_ec) => println!("[SSLRelay Error] Failed to handle TCP connection: {}", _ec), - } - }); - }, - Err(e) => {println!("[Error] Tcp Connection Failed: {}", e)} - } - } - } - } - } + let this_conn_id = conn_id; + thread::spawn(move || { + // FULL DUPLEX OBJECT CREATION HERE + match FullDuplexTcp::new( + DataStreamType::RAW(stream), + upstream_data_stream_type, + (r_host)(None), + r_port, + handler_clone, + this_conn_id, + ) { + Ok(mut fdtcp) => fdtcp.handle(), + Err(_ec) => println!( + "[SSLRelay Error] Failed to handle TCP connection: {}", + _ec + ), + } + }); + conn_id += 1; + } + Err(e) => { + println!("[Error] Tcp Connection Failed: {}", e) + } + } + } + } + } + } - fn setup_ssl_config(&self, tls_config: TLSConfig) -> Arc { + fn setup_ssl_config(&self, tls_config: &TLSConfig) -> Arc { + let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + match tls_config { + TLSConfig::FILE { + certificate_path, + private_key_path, + } => { + if !Path::new(&private_key_path).exists() { + panic!("[-] [{}] does not exist!", private_key_path); + } + if !Path::new(&certificate_path).exists() { + panic!("[-] [{}] does not exist!", certificate_path); + } + acceptor + .set_private_key_file(private_key_path, SslFiletype::PEM) + .unwrap(); + acceptor + .set_certificate_chain_file(certificate_path) + .unwrap(); + acceptor.check_private_key().unwrap(); + } + TLSConfig::DATA { + certificate, + private_key, + } => { + let x_509_certificate = X509::from_pem(certificate.as_slice()).unwrap(); + let private_key = PKey::private_key_from_pem(private_key.as_slice()).unwrap(); + acceptor + .set_certificate(x_509_certificate.as_ref()) + .unwrap(); + acceptor.set_private_key(private_key.as_ref()).unwrap(); + } + TLSConfig::NONE => { + panic!( + "[SSLRelay Error] Specified NONE for TLSConfig and downstream_data_type as \ + TLS." + ); + } + } + Arc::new(acceptor.build()) + } - let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + // fn setup_ssl_config(&self, tls_configs: &[(&[&str], TLSConfig)]) -> AcceptorDb { + // let mut acceptor_db = AcceptorDb { + // acceptors: HashMap::new(), + // }; + // for (names, tls_config) in tls_configs { + // let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + // match tls_config { + // TLSConfig::FILE { + // certificate_path, + // private_key_path, + // } => { + // if !Path::new(&private_key_path).exists() { + // panic!("[-] [{}] does not exist!", private_key_path); + // } + // if !Path::new(&certificate_path).exists() { + // panic!("[-] [{}] does not exist!", certificate_path); + // } + // acceptor + // .set_private_key_file(private_key_path, SslFiletype::PEM) + // .unwrap(); + // acceptor + // .set_certificate_chain_file(certificate_path) + // .unwrap(); + // acceptor.check_private_key().unwrap(); + // } + // TLSConfig::DATA { + // certificate, + // private_key, + // } => { + // let x_509_certificate = X509::from_pem(certificate.as_slice()).unwrap(); + // let private_key = PKey::private_key_from_pem(private_key.as_slice()).unwrap(); + // acceptor + // .set_certificate(x_509_certificate.as_ref()) + // .unwrap(); + // acceptor.set_private_key(private_key.as_ref()).unwrap(); + // } + // TLSConfig::NONE => { + // panic!( + // "[SSLRelay Error] Specified NONE for TLSConfig and downstream_data_type as \ + // TLS." + // ); + // } + // } + // let acceptor = Arc::new(acceptor.build()); + // for name in *names { + // acceptor_db.acceptors.insert(name.to_string(), acceptor.clone()); + // } + // } + // acceptor_db + // } +} // SSLRelay - match tls_config { - TLSConfig::FILE{certificate_path, private_key_path} => { - - if !Path::new(&private_key_path).exists() { - panic!("[-] [{}] does not exist!", private_key_path); - } - if !Path::new(&certificate_path).exists() { - panic!("[-] [{}] does not exist!", certificate_path); - } - acceptor.set_private_key_file(private_key_path, SslFiletype::PEM).unwrap(); - acceptor.set_certificate_chain_file(certificate_path).unwrap(); - acceptor.check_private_key().unwrap(); - }, - TLSConfig::DATA{certificate, private_key} => { - let x_509_certificate = X509::from_pem(certificate.as_slice()).unwrap(); - let private_key = PKey::private_key_from_pem(private_key.as_slice()).unwrap(); - acceptor.set_certificate(x_509_certificate.as_ref()).unwrap(); - acceptor.set_private_key(private_key.as_ref()).unwrap(); - }, - TLSConfig::NONE => { - panic!("[SSLRelay Error] Specified NONE for TLSConfig and downstream_data_type as TLS."); - } - } - Arc::new(acceptor.build()) - } -}// SSLRelay \ No newline at end of file +// struct AcceptorDb { +// acceptors: HashMap>, +// } diff --git a/src/tcp.rs b/src/tcp.rs index 99d0592..115ae6d 100644 --- a/src/tcp.rs +++ b/src/tcp.rs @@ -1,259 +1,368 @@ use crate::{ - FullDuplexTcp, - HandlerCallbacks, - DataStreamType, - TCPDataType, - Duration, - Arc, - Mutex, - DownStreamInner, - UpStreamInner, - InnerHandlers, - Shutdown, - Sender, - Receiver, - FullDuplexTcpState, - DataPipe, - mpsc, - thread, - CallbackRet, - TcpStream, - SslVerifyMode, - SslConnector, - SslMethod, + mpsc, thread, Arc, CallbackRet, DataPipe, DataStreamType, DownStreamInner, Duration, + FullDuplexTcp, FullDuplexTcpState, HandlerCallbacks, InnerHandlers, Mutex, Receiver, Sender, + Shutdown, SslConnector, SslMethod, SslVerifyMode, TCPDataType, TcpStream, UpStreamInner, }; -impl FullDuplexTcp { +impl + FullDuplexTcp +{ + pub fn new( + ds_tcp_stream: DataStreamType, + us_tcp_stream_type: TCPDataType, + remote_host: String, + remote_port: String, + handlers: InnerHandlers, + conn_id: u64, + ) -> Result { + match ds_tcp_stream { + DataStreamType::RAW(ref s) => { + let _ = s.set_read_timeout(Some(Duration::from_millis(50))); + } + DataStreamType::TLS(ref s) => { + let _ = s + .get_ref() + .set_read_timeout(Some(Duration::from_millis(50))); + } + } - pub fn new(ds_tcp_stream: DataStreamType, us_tcp_stream_type: TCPDataType, remote_host: String, remote_port: String, handlers: InnerHandlers) -> Result { + let us_tcp_stream = match Self::connect_endpoint( + us_tcp_stream_type, + remote_host.clone(), + remote_port.clone(), + ) { + Ok(s) => s, + Err(ec) => { + match ds_tcp_stream { + DataStreamType::RAW(s) => { + let _ = s.shutdown(Shutdown::Both); + } + DataStreamType::TLS(mut s) => { + let _ = s.shutdown(); + } + } + return Err(ec); + } + }; - match ds_tcp_stream { - DataStreamType::RAW(ref s) => { let _ = s.set_read_timeout(Some(Duration::from_millis(50))); }, - DataStreamType::TLS(ref s) => { let _ = s.get_ref().set_read_timeout(Some(Duration::from_millis(50))); }, - } + Ok(FullDuplexTcp { + remote_host, + remote_port, + ds_inner_m: Arc::new(Mutex::new(Some(DownStreamInner { + ds_stream: ds_tcp_stream, + internal_data_buffer: Vec::::new(), + }))), + us_inner_m: Arc::new(Mutex::new(Some(UpStreamInner { + us_stream: us_tcp_stream, + internal_data_buffer: Vec::::new(), + }))), + inner_handlers: handlers, + conn_id, + }) + } - let us_tcp_stream = match Self::connect_endpoint(us_tcp_stream_type, remote_host.clone(), remote_port.clone()) { - Ok(s) => s, - Err(ec) => { - match ds_tcp_stream { - DataStreamType::RAW(s) => { let _ = s.shutdown(Shutdown::Both); }, - DataStreamType::TLS(mut s) => { let _ = s.shutdown(); }, - } - return Err(ec); - } - }; + pub fn handle(&mut self) { + let conn_id = self.conn_id; + let (state_sender, state_receiver): ( + Sender, + Receiver, + ) = mpsc::channel(); + let (ds_data_pipe_sender, ds_data_pipe_receiver): (Sender, Receiver) = + mpsc::channel(); + let (us_data_pipe_sender, us_data_pipe_receiver): (Sender, Receiver) = + mpsc::channel(); - Ok( - FullDuplexTcp { - remote_host, - remote_port, - ds_inner_m: Arc::new(Mutex::new(Some(DownStreamInner{ds_stream: ds_tcp_stream, internal_data_buffer: Vec::::new()}))), - us_inner_m: Arc::new(Mutex::new(Some(UpStreamInner{us_stream: us_tcp_stream, internal_data_buffer: Vec::::new()}))), - inner_handlers: handlers, - }) - } + let ds_method_pointer = self.ds_inner_m.clone(); + let ds_state_bc = state_sender.clone(); - pub fn handle(&mut self) { + let us_method_pointer = self.us_inner_m.clone(); + let us_state_bc = state_sender.clone(); - let (state_sender, state_receiver): (Sender, Receiver) = mpsc::channel(); - let (ds_data_pipe_sender, ds_data_pipe_receiver): (Sender, Receiver) = mpsc::channel(); - let (us_data_pipe_sender, us_data_pipe_receiver): (Sender, Receiver) = mpsc::channel(); + thread::spawn(move || { + ds_method_pointer + .lock() + .unwrap() + .take() + .unwrap() + .ds_handler(ds_state_bc, ds_data_pipe_receiver); + }); - let ds_method_pointer = self.ds_inner_m.clone(); - let ds_state_bc = state_sender.clone(); + thread::spawn(move || { + us_method_pointer + .lock() + .unwrap() + .take() + .unwrap() + .us_handler(us_state_bc, us_data_pipe_receiver); + }); - let us_method_pointer = self.us_inner_m.clone(); - let us_state_bc = state_sender.clone(); + loop { + match state_receiver.recv() { + Ok(state_request) => { + match state_request { + // DownStream Write Request + FullDuplexTcpState::DownStreamWrite(data) => { + /* + Callbacks that work with data from UpStream go here + Add callback return types for blocking callback subroutines + Shutdown - Shutdown TCP connection + Relay - Relay TCP stream + Spoof - Spoof back to received stream direction + Freeze - Freeze data (dont relay and destroy data) + */ - thread::spawn(move || { - ds_method_pointer.lock().unwrap().take().unwrap().ds_handler(ds_state_bc, ds_data_pipe_receiver); - }); + let inner_handlers_clone = self.inner_handlers.clone(); + let in_data = data.clone(); - thread::spawn(move || { - us_method_pointer.lock().unwrap().take().unwrap().us_handler(us_state_bc, us_data_pipe_receiver); - }); + thread::spawn(move || { + inner_handlers_clone.cb.us_nb_callback(in_data, conn_id); + }); - loop { + match self.inner_handlers.cb.us_b_callback(data, conn_id) { + CallbackRet::Relay(retdata) => { + match ds_data_pipe_sender.send(DataPipe::DataWrite(retdata)) { + Ok(()) => {} + Err(e) => { + Self::handle_error( + format!( + "Failed to send data write to DownStream \ + thread: {}", + e + ) + .as_str(), + ); + return; + } + } + } + CallbackRet::Spoof(retdata) => { + match us_data_pipe_sender.send(DataPipe::DataWrite(retdata)) { + Ok(()) => {} + Err(e) => { + Self::handle_error( + format!( + "Failed to send data write to DownStream \ + thread: {}", + e + ) + .as_str(), + ); + return; + } + } + } + CallbackRet::Freeze => {} + CallbackRet::Shutdown => { + if let Err(e) = us_data_pipe_sender.send(DataPipe::Shutdown) { + Self::handle_error( + format!( + "Failed to send Shutdown signal to UpStream \ + thread: {}", + e + ) + .as_str(), + ); + } + if let Err(e) = ds_data_pipe_sender.send(DataPipe::Shutdown) { + Self::handle_error( + format!( + "Failed to send Shutdown signal to DownStream \ + thread: {}", + e + ) + .as_str(), + ); + } + return; + } + } + } + // UpStream Write Request + FullDuplexTcpState::UpStreamWrite(data) => { + /* + Callbacks that work with data from DownStream go here + */ - match state_receiver.recv() { - Ok(state_request) => { - match state_request { + let inner_handlers_clone = self.inner_handlers.clone(); + let in_data = data.clone(); - // DownStream Write Request - FullDuplexTcpState::DownStreamWrite(data) => { + thread::spawn(move || { + inner_handlers_clone.cb.ds_nb_callback(in_data, conn_id); + }); - /* - Callbacks that work with data from UpStream go here - Add callback return types for blocking callback subroutines - Shutdown - Shutdown TCP connection - Relay - Relay TCP stream - Spoof - Spoof back to received stream direction - Freeze - Freeze data (dont relay and destroy data) - */ + match self.inner_handlers.cb.ds_b_callback(data, conn_id) { + CallbackRet::Relay(retdata) => { + match us_data_pipe_sender.send(DataPipe::DataWrite(retdata)) { + Ok(()) => {} + Err(e) => { + Self::handle_error( + format!( + "Failed to send data write to UpStream \ + thread: {}", + e + ) + .as_str(), + ); + return; + } + } + } + CallbackRet::Spoof(retdata) => { + match ds_data_pipe_sender.send(DataPipe::DataWrite(retdata)) { + Ok(()) => {} + Err(e) => { + Self::handle_error( + format!( + "Failed to send data write to DownStream \ + thread: {}", + e + ) + .as_str(), + ); + return; + } + } + } + CallbackRet::Freeze => {} + CallbackRet::Shutdown => { + if let Err(e) = ds_data_pipe_sender.send(DataPipe::Shutdown) { + Self::handle_error( + format!( + "Failed to send Shutdown signal to DownStream \ + thread: {}", + e + ) + .as_str(), + ); + } + if let Err(e) = us_data_pipe_sender.send(DataPipe::Shutdown) { + Self::handle_error( + format!( + "Failed to send Shutdown signal to UpStream \ + thread: {}", + e + ) + .as_str(), + ); + } + return; + } + } + } + // DownStreamShutDown Request + FullDuplexTcpState::DownStreamShutDown => { + if let Err(e) = us_data_pipe_sender.send(DataPipe::Shutdown) { + Self::handle_error( + format!( + "Failed to send Shutdown signal to UpStream thread: {}", + e + ) + .as_str(), + ); + return; + } + return; + } + // UpStreamShutDown Request + FullDuplexTcpState::UpStreamShutDown => { + if let Err(e) = ds_data_pipe_sender.send(DataPipe::Shutdown) { + Self::handle_error( + format!( + "Failed to send Shutdown signal to DownStream thread: {}", + e + ) + .as_str(), + ); + return; + } + return; + } + } + } + Err(_e) => { + Self::handle_error("State receiver communication channel has closed!"); + if let Err(e) = ds_data_pipe_sender.send(DataPipe::Shutdown) { + Self::handle_error( + format!("Failed to send Shutdown signal to DownStream thread: {}", e) + .as_str(), + ); + } + if let Err(e) = us_data_pipe_sender.send(DataPipe::Shutdown) { + Self::handle_error( + format!("Failed to send Shutdown signal to UpStream thread: {}", e) + .as_str(), + ); + } + return; + } + } // State Receiver + } + } - let inner_handlers_clone = self.inner_handlers.clone(); - let in_data = data.clone(); + fn connect_endpoint( + stream_data_type: TCPDataType, + remote_host: String, + remote_port: String, + ) -> Result { + match stream_data_type { + TCPDataType::RAW => { + let s = match TcpStream::connect(format!("{}:{}", remote_host, remote_port)) { + Ok(s) => s, + Err(e) => { + Self::handle_error( + format!( + "Can't connect to remote host: {}\nErr: {}", + format!("{}:{}", remote_host, remote_port), + e + ) + .as_str(), + ); + return Result::Err(-1); + } + }; + let _ = s.set_read_timeout(Some(Duration::from_millis(50))); + return Ok(DataStreamType::RAW(s)); + } + TCPDataType::TLS => { + let mut sslbuilder = SslConnector::builder(SslMethod::tls()).unwrap(); + sslbuilder.set_verify(SslVerifyMode::NONE); - thread::spawn(move || { - inner_handlers_clone.cb.us_nb_callback(in_data); - }); + let connector = sslbuilder.build(); - match self.inner_handlers.cb.us_b_callback(data) { - CallbackRet::Relay(retdata) => { - match ds_data_pipe_sender.send(DataPipe::DataWrite(retdata)) { - Ok(()) => {}, - Err(e) => { - Self::handle_error(format!("Failed to send data write to DownStream thread: {}", e).as_str()); - return; - } - } - }, - CallbackRet::Spoof(retdata) => { - match us_data_pipe_sender.send(DataPipe::DataWrite(retdata)) { - Ok(()) => {}, - Err(e) => { - Self::handle_error(format!("Failed to send data write to DownStream thread: {}", e).as_str()); - return; - } - } - }, - CallbackRet::Freeze => {}, - CallbackRet::Shutdown => { - if let Err(e) = us_data_pipe_sender.send(DataPipe::Shutdown) { - Self::handle_error(format!("Failed to send Shutdown signal to UpStream thread: {}", e).as_str()); - } - if let Err(e) = ds_data_pipe_sender.send(DataPipe::Shutdown) { - Self::handle_error(format!("Failed to send Shutdown signal to DownStream thread: {}", e).as_str()); - } - return; - } - } - }, - // UpStream Write Request - FullDuplexTcpState::UpStreamWrite(data) => { + let s = match TcpStream::connect(format!("{}:{}", remote_host, remote_port)) { + Ok(s) => s, + Err(e) => { + Self::handle_error( + format!( + "Can't connect to remote host: {}\nErr: {}", + format!("{}:{}", remote_host, remote_port), + e + ) + .as_str(), + ); + return Result::Err(-1); + } + }; - /* - Callbacks that work with data from DownStream go here - */ + let s = match connector.connect(remote_host.as_str(), s) { + Ok(s) => s, + Err(e) => { + Self::handle_error( + format!("Failed to accept TLS/SSL handshake: {}", e).as_str(), + ); + return Result::Err(-2); + } + }; - let inner_handlers_clone = self.inner_handlers.clone(); - let in_data = data.clone(); + let _ = s + .get_ref() + .set_read_timeout(Some(Duration::from_millis(50))); + return Ok(DataStreamType::TLS(s)); + } + } + } - thread::spawn(move || { - inner_handlers_clone.cb.ds_nb_callback(in_data); - }); - - match self.inner_handlers.cb.ds_b_callback(data) { - CallbackRet::Relay(retdata) => { - match us_data_pipe_sender.send(DataPipe::DataWrite(retdata)) { - Ok(()) => {}, - Err(e) => { - Self::handle_error(format!("Failed to send data write to UpStream thread: {}", e).as_str()); - return; - } - } - }, - CallbackRet::Spoof(retdata) => { - match ds_data_pipe_sender.send(DataPipe::DataWrite(retdata)) { - Ok(()) => {}, - Err(e) => { - Self::handle_error(format!("Failed to send data write to DownStream thread: {}", e).as_str()); - return; - } - } - }, - CallbackRet::Freeze => {}, - CallbackRet::Shutdown => { - if let Err(e) = ds_data_pipe_sender.send(DataPipe::Shutdown) { - Self::handle_error(format!("Failed to send Shutdown signal to DownStream thread: {}", e).as_str()); - } - if let Err(e) = us_data_pipe_sender.send(DataPipe::Shutdown) { - Self::handle_error(format!("Failed to send Shutdown signal to UpStream thread: {}", e).as_str()); - } - return; - } - } - }, - // DownStreamShutDown Request - FullDuplexTcpState::DownStreamShutDown => { - - if let Err(e) = us_data_pipe_sender.send(DataPipe::Shutdown) { - Self::handle_error(format!("Failed to send Shutdown signal to UpStream thread: {}", e).as_str()); - return; - } - return; - }, - // UpStreamShutDown Request - FullDuplexTcpState::UpStreamShutDown => { - - if let Err(e) = ds_data_pipe_sender.send(DataPipe::Shutdown) { - Self::handle_error(format!("Failed to send Shutdown signal to DownStream thread: {}", e).as_str()); - return; - } - return; - }, - } - }, - Err(_e) => { - Self::handle_error("State receiver communication channel has closed!"); - if let Err(e) = ds_data_pipe_sender.send(DataPipe::Shutdown) { - Self::handle_error(format!("Failed to send Shutdown signal to DownStream thread: {}", e).as_str()); - } - if let Err(e) = us_data_pipe_sender.send(DataPipe::Shutdown) { - Self::handle_error(format!("Failed to send Shutdown signal to UpStream thread: {}", e).as_str()); - } - return; - } - }// State Receiver - } - } - - fn connect_endpoint(stream_data_type: TCPDataType, remote_host: String, remote_port: String) -> Result { - - match stream_data_type { - - TCPDataType::RAW => { - let s = match TcpStream::connect(format!("{}:{}", remote_host, remote_port)) { - Ok(s) => s, - Err(e) => { - Self::handle_error(format!("Can't connect to remote host: {}\nErr: {}", format!("{}:{}", remote_host, remote_port), e).as_str()); - return Result::Err(-1); - } - }; - let _ = s.set_read_timeout(Some(Duration::from_millis(50))); - return Ok(DataStreamType::RAW(s)); - - }, - TCPDataType::TLS => { - - let mut sslbuilder = SslConnector::builder(SslMethod::tls()).unwrap(); - sslbuilder.set_verify(SslVerifyMode::NONE); - - let connector = sslbuilder.build(); - - let s = match TcpStream::connect(format!("{}:{}", remote_host, remote_port)) { - Ok(s) => s, - Err(e) => { - Self::handle_error(format!("Can't connect to remote host: {}\nErr: {}", format!("{}:{}", remote_host, remote_port), e).as_str()); - return Result::Err(-1); - } - }; - - let s = match connector.connect(remote_host.as_str(), s) { - Ok(s) => s, - Err(e) => { - Self::handle_error(format!("Failed to accept TLS/SSL handshake: {}", e).as_str()); - return Result::Err(-2); - } - }; - - let _ = s.get_ref().set_read_timeout(Some(Duration::from_millis(50))); - return Ok(DataStreamType::TLS(s)); - } - } - } - - fn handle_error(error_description: &str) { - println!("[SSLRelay Master Thread Error]: {}", error_description); - } -} \ No newline at end of file + fn handle_error(error_description: &str) { + println!("[SSLRelay Master Thread Error]: {}", error_description); + } +}