diff options
Diffstat (limited to 'src/proxy.rs')
| -rw-r--r-- | src/proxy.rs | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/src/proxy.rs b/src/proxy.rs new file mode 100644 index 0000000..ce40e6e --- /dev/null +++ b/src/proxy.rs @@ -0,0 +1,86 @@ +use native_tls::TlsConnector; +use std::io::{Read, Write}; +use std::net::{TcpListener, TcpStream}; +use std::sync::Arc; +use std::thread::{spawn, JoinHandle}; + +use crate::configuration::ProxyConfiguration; + +pub fn create_proxy(configuration: Arc<ProxyConfiguration>) -> JoinHandle<()> { + let cloned_configuration = Arc::clone(&configuration); + spawn(move || { + run_proxy(cloned_configuration); + }) +} + +fn run_proxy(configuration: Arc<ProxyConfiguration>) { + let listener = TcpListener::bind(format!("0.0.0.0:{}", configuration.local_port)).unwrap(); + + println!("Proxy listening on port {}", configuration.local_port); + + for stream in listener.incoming() { + match stream { + Ok(stream) => { + let cloned_configuration = Arc::clone(&configuration); + spawn(move || { + handle_client(stream, cloned_configuration); + }); + } + Err(e) => { + eprintln!("Failed to accept connection: {}", e); + } + } + } +} + +fn handle_client(mut client_stream: TcpStream, configuration: Arc<ProxyConfiguration>) { + let connector = TlsConnector::new().unwrap(); + let remote_stream = TcpStream::connect(format!( + "{}:{}", + configuration.remote_domain, configuration.remote_port + )) + .unwrap(); + let mut remote_stream = connector + .connect(&configuration.remote_domain, remote_stream) + .unwrap(); + + let mut client_stream_clone = client_stream.try_clone().unwrap(); + let mut remote_stream_clone = remote_stream.get_ref().try_clone().unwrap(); + + let cloned_configuration = Arc::clone(&configuration); + spawn(move || { + forward_stream(&mut client_stream, &mut remote_stream, cloned_configuration); + }); + forward_stream( + &mut remote_stream_clone, + &mut client_stream_clone, + configuration, + ); +} + +fn forward_stream<R: Read, W: Write>( + from: &mut R, + to: &mut W, + configuration: Arc<ProxyConfiguration>, +) { + let mut buffer = [0; 4096]; + loop { + match from.read(&mut buffer) { + Ok(0) => break, // EOF + Ok(n) => { + if let Err(e) = to.write_all(&buffer[..n]) { + eprintln!("{} proxy write error: {}", configuration.protocol, e); + break; + } + if let Err(e) = to.flush() { + eprintln!("{} proxy flush error: {}", configuration.protocol, e); + break; + } + } + Err(e) => { + eprintln!("{} proxy read error: {}", configuration.protocol, e); + break; + } + } + } +} |