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) -> JoinHandle<()> { let cloned_configuration = Arc::clone(&configuration); spawn(move || { run_proxy(cloned_configuration); }) } fn run_proxy(configuration: Arc) { 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) { 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( from: &mut R, to: &mut W, configuration: Arc, ) { 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; } } } }