diff --git a/Cargo.toml b/Cargo.toml index 672dfce..cbde7d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sslrelay" -version = "0.4.0" +version = "0.4.1" authors = ["PinkP4nther "] edition = "2018" diff --git a/src/data.rs b/src/data.rs index 9e5a3fc..0a16fd6 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,38 +1,18 @@ -use std::time::Duration; -use openssl::ssl::{SslConnector, SslMethod, SslStream, SslVerifyMode}; -use std::io::{self, Read, Write}; -use std::net::{TcpStream, Shutdown}; -use std::sync::mpsc::{self, Receiver, Sender}; -use std::thread; -use std::result::Result; -use std::sync::{Arc, Mutex}; - -use crate::{HandlerCallbacks, CallbackRet, InnerHandlers, TCPDataType}; - -#[derive(Debug)] -enum FullDuplexTcpState { - DownStreamWrite(Vec), - UpStreamWrite(Vec), - DownStreamShutDown, - UpStreamShutDown, -} - -#[derive(Debug)] -enum DataPipe { - DataWrite(Vec), +use crate::{ + DownStreamInner, + UpStreamInner, + FullDuplexTcpState, + DataPipe, + DataStreamType, + Sender, + Receiver, Shutdown, -} - -pub enum DataStreamType { - RAW(TcpStream), - TLS(SslStream), -} - -struct DownStreamInner -{ - ds_stream: DataStreamType, - internal_data_buffer: Vec, -} + mpsc, + Duration, + Read, + Write, + io, +}; impl DownStreamInner { @@ -248,11 +228,6 @@ impl DownStreamInner { } } -struct UpStreamInner -{ - us_stream: DataStreamType, - internal_data_buffer: Vec -} impl UpStreamInner { @@ -456,252 +431,4 @@ impl UpStreamInner { } return Some(data_length); } -} - -#[allow(dead_code)] -pub struct FullDuplexTcp -where - 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, -} - -impl FullDuplexTcp { - - pub fn new(ds_tcp_stream: DataStreamType, us_tcp_stream_type: TCPDataType, remote_host: String, remote_port: String, handlers: InnerHandlers) -> 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))); }, - } - - 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); - } - }; - - 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, - }) - } - - pub fn handle(&mut self) { - - 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(); - - let ds_method_pointer = self.ds_inner_m.clone(); - let ds_state_bc = state_sender.clone(); - - let us_method_pointer = self.us_inner_m.clone(); - let us_state_bc = state_sender.clone(); - - thread::spawn(move || { - ds_method_pointer.lock().unwrap().take().unwrap().ds_handler(ds_state_bc, ds_data_pipe_receiver); - }); - - thread::spawn(move || { - us_method_pointer.lock().unwrap().take().unwrap().us_handler(us_state_bc, us_data_pipe_receiver); - }); - - 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) - */ - - let inner_handlers_clone = self.inner_handlers.clone(); - let in_data = data.clone(); - - thread::spawn(move || { - inner_handlers_clone.cb.us_nb_callback(in_data); - }); - - 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) => { - - /* - Callbacks that work with data from DownStream go here - */ - - let inner_handlers_clone = self.inner_handlers.clone(); - let in_data = data.clone(); - - 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 diff --git a/src/lib.rs b/src/lib.rs index d754942..1f0bb18 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,71 @@ -use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; -use std::net::{TcpListener}; -use std::sync::Arc; -use std::{process, thread}; -use std::env; -use std::fs; -use std::path::Path; +use openssl::ssl::{ + SslVerifyMode, + SslConnector, + SslAcceptor, + SslStream, + SslFiletype, + SslMethod +}; + +use std::net::{ + TcpListener, + TcpStream, + Shutdown +}; + +use std::sync::{ + Arc, + Mutex +}; + +use std::{ + process, + thread +}; + +use std::{ + env, + fs, + path::Path, + time::Duration, +}; + +use std::io::{ + self, + Read, + Write +}; + +use std::sync::mpsc::{ + self, + Receiver, + Sender +}; use toml::Value as TValue; mod data; -use data::{FullDuplexTcp, DataStreamType}; +mod tcp; +mod relay; + +#[derive(Debug)] +enum FullDuplexTcpState { + DownStreamWrite(Vec), + UpStreamWrite(Vec), + DownStreamShutDown, + UpStreamShutDown, +} + +#[derive(Debug)] +enum DataPipe { + DataWrite(Vec), + Shutdown, +} + +enum DataStreamType { + RAW(TcpStream), + TLS(SslStream), +} #[derive(Copy, Clone)] pub enum TCPDataType { @@ -17,6 +73,13 @@ pub enum TCPDataType { RAW, } +pub enum ConfigType { + Env, + Path(T), + Conf(RelayConfig), + Default, +} + #[derive(Clone)] pub struct RelayConfig { pub downstream_data_type: TCPDataType, @@ -29,20 +92,6 @@ pub struct RelayConfig { pub ssl_cert_path: String, } -pub trait HandlerCallbacks { - fn ds_b_callback(&self, _in_data: Vec) -> CallbackRet {CallbackRet::Relay(_in_data)} - fn ds_nb_callback(&self, _in_data: Vec){} - fn us_b_callback(&self, _in_data: Vec) -> CallbackRet {CallbackRet::Relay(_in_data)} - fn us_nb_callback(&self, _in_data: Vec){} -} - -pub enum ConfigType { - Env, - Path(T), - Conf(RelayConfig), - Default, -} - #[derive(Debug)] pub enum CallbackRet { Relay(Vec),// Relay data @@ -51,6 +100,14 @@ pub enum CallbackRet { Freeze,// Dont send data (pretend as if stream never was recieved) } +pub trait HandlerCallbacks { + fn ds_b_callback(&self, _in_data: Vec) -> CallbackRet {CallbackRet::Relay(_in_data)} + fn ds_nb_callback(&self, _in_data: Vec){} + fn us_b_callback(&self, _in_data: Vec) -> CallbackRet {CallbackRet::Relay(_in_data)} + fn us_nb_callback(&self, _in_data: Vec){} +} + + #[derive(Clone)] pub struct SSLRelay where @@ -60,180 +117,34 @@ where handlers: Option>, } +#[allow(dead_code)] +struct FullDuplexTcp +where + 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, +} + #[derive(Clone)] -pub struct InnerHandlers +struct InnerHandlers where H: HandlerCallbacks + std::marker::Sync + std::marker::Send + Clone + 'static, { cb: H } -impl SSLRelay { +struct DownStreamInner +{ + ds_stream: DataStreamType, + internal_data_buffer: Vec, +} - pub fn new(handlers: H, config_path: ConfigType) -> Self { - - SSLRelay { - config: Self::load_relay_config(config_path), - handlers: Some(InnerHandlers{cb: handlers}), - } - } - - pub fn start(&mut self) { - - let rhost = self.config.remote_host.clone(); - let rport = self.config.remote_port.clone(); - let listener = TcpListener::bind(format!("{}:{}", self.config.bind_host.clone(), self.config.bind_port.clone())).unwrap(); - let upstream_data_stream_type = self.config.upstream_data_type; - - match self.config.downstream_data_type { - - TCPDataType::TLS => { - let acceptor = self.setup_ssl_config(self.config.ssl_private_key_path.clone(), self.config.ssl_cert_path.clone()); - - 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) => {} - } - }, - 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(); - - 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) => {}, - } - - }); - }, - Err(e) => {println!("[Error] Tcp Connection Failed: {}", e)} - } - } - } - } - } - - fn load_relay_config(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::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 { - println!("[SSLRelay Error] Unrecognized TCPDataType for upstream_data_type. Data type received was not 'tcp' or 'tls'!"); - process::exit(1); // 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 { - println!("[SSLRelay Error] Unrecognized TCPDataType for downstream_data_type. Data type received was not 'tcp' or 'tls'!"); - process::exit(1); // Create error handling for load_relay_config() - } - - RelayConfig { - upstream_data_type, - downstream_data_type, - 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(), - } - } - - fn setup_ssl_config(&self, priv_key: String, cert: String) -> Arc { - - if !Path::new(priv_key.as_str()).exists() { - println!("[-] [{}] does not exist!", priv_key); - process::exit(-1); - } else if !Path::new(cert.as_str()).exists() { - println!("[-] [{}] does not exist!", cert); - process::exit(-1); - } - - 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 \ No newline at end of file +struct UpStreamInner +{ + us_stream: DataStreamType, + internal_data_buffer: Vec +} \ No newline at end of file diff --git a/src/relay.rs b/src/relay.rs new file mode 100644 index 0000000..14fc6b9 --- /dev/null +++ b/src/relay.rs @@ -0,0 +1,191 @@ +use crate::{ + SSLRelay, + HandlerCallbacks, + InnerHandlers, + TCPDataType, + ConfigType, + TcpListener, + thread, + FullDuplexTcp, + DataStreamType, + RelayConfig, + env, + TValue, + fs, + process, + Arc, + SslAcceptor, + Path, + SslMethod, + SslFiletype, +}; + +impl SSLRelay { + + pub fn new(handlers: H, config_path: ConfigType) -> Self { + + SSLRelay { + config: Self::load_relay_config(config_path), + handlers: Some(InnerHandlers{cb: handlers}), + } + } + + pub fn start(&mut self) { + + let rhost = self.config.remote_host.clone(); + let rport = self.config.remote_port.clone(); + let listener = TcpListener::bind(format!("{}:{}", self.config.bind_host.clone(), self.config.bind_port.clone())).unwrap(); + let upstream_data_stream_type = self.config.upstream_data_type; + + match self.config.downstream_data_type { + + TCPDataType::TLS => { + let acceptor = self.setup_ssl_config(self.config.ssl_private_key_path.clone(), self.config.ssl_cert_path.clone()); + + 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) => {} + } + }, + 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(); + + 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) => {}, + } + + }); + }, + Err(e) => {println!("[Error] Tcp Connection Failed: {}", e)} + } + } + } + } + } + + fn load_relay_config(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::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 { + println!("[SSLRelay Error] Unrecognized TCPDataType for upstream_data_type. Data type received was not 'tcp' or 'tls'!"); + process::exit(1); // 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 { + println!("[SSLRelay Error] Unrecognized TCPDataType for downstream_data_type. Data type received was not 'tcp' or 'tls'!"); + process::exit(1); // Create error handling for load_relay_config() + } + + RelayConfig { + upstream_data_type, + downstream_data_type, + 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(), + } + } + + fn setup_ssl_config(&self, priv_key: String, cert: String) -> Arc { + + if !Path::new(priv_key.as_str()).exists() { + println!("[-] [{}] does not exist!", priv_key); + process::exit(-1); + } else if !Path::new(cert.as_str()).exists() { + println!("[-] [{}] does not exist!", cert); + process::exit(-1); + } + + 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 \ No newline at end of file diff --git a/src/tcp.rs b/src/tcp.rs new file mode 100644 index 0000000..1d12d20 --- /dev/null +++ b/src/tcp.rs @@ -0,0 +1,260 @@ +use crate::{ + FullDuplexTcp, + HandlerCallbacks, + DataStreamType, + TCPDataType, + Duration, + Arc, + Mutex, + DownStreamInner, + UpStreamInner, + InnerHandlers, + Shutdown, + Sender, + Receiver, + FullDuplexTcpState, + DataPipe, + mpsc, + thread, + CallbackRet, + TcpStream, + SslVerifyMode, + SslConnector, + SslMethod, +}; + +impl FullDuplexTcp { + + pub fn new(ds_tcp_stream: DataStreamType, us_tcp_stream_type: TCPDataType, remote_host: String, remote_port: String, handlers: InnerHandlers) -> 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))); }, + } + + 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); + } + }; + + 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, + }) + } + + pub fn handle(&mut self) { + + 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(); + + let ds_method_pointer = self.ds_inner_m.clone(); + let ds_state_bc = state_sender.clone(); + + let us_method_pointer = self.us_inner_m.clone(); + let us_state_bc = state_sender.clone(); + + thread::spawn(move || { + ds_method_pointer.lock().unwrap().take().unwrap().ds_handler(ds_state_bc, ds_data_pipe_receiver); + }); + + thread::spawn(move || { + us_method_pointer.lock().unwrap().take().unwrap().us_handler(us_state_bc, us_data_pipe_receiver); + }); + + 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) + */ + + let inner_handlers_clone = self.inner_handlers.clone(); + let in_data = data.clone(); + + thread::spawn(move || { + inner_handlers_clone.cb.us_nb_callback(in_data); + }); + + 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) => { + + /* + Callbacks that work with data from DownStream go here + */ + + let inner_handlers_clone = self.inner_handlers.clone(); + let in_data = data.clone(); + + 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