diff options
| author | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-01-24 20:34:35 +0100 |
|---|---|---|
| committer | Ruben Beltran del Rio <git@r.bdr.sh> | 2025-01-24 20:34:35 +0100 |
| commit | dc3d68214e2cd4b5f86279a7fa7b7d64c341b446 (patch) | |
| tree | 30da7fdfcf612f00705e87acdf379a0334d6cb08 /src | |
First approach
Diffstat (limited to 'src')
| -rw-r--r-- | src/configuration.rs | 45 | ||||
| -rw-r--r-- | src/main.rs | 15 | ||||
| -rw-r--r-- | src/proxy.rs | 86 |
3 files changed, 146 insertions, 0 deletions
diff --git a/src/configuration.rs b/src/configuration.rs new file mode 100644 index 0000000..1437594 --- /dev/null +++ b/src/configuration.rs @@ -0,0 +1,45 @@ +use std::env; +use std::sync::Arc; + +pub struct ProxyConfiguration { + pub local_port: u16, + pub remote_domain: String, + pub remote_port: u16, + pub protocol: &'static str, +} + +pub struct Configuration { + pub imap_configuration: Arc<ProxyConfiguration>, + pub smtp_configuration: Arc<ProxyConfiguration>, +} + +impl Configuration { + pub fn new() -> Self { + Configuration { + imap_configuration: Arc::new(ProxyConfiguration { + local_port: env::var("LOCAL_IMAP_PORT") + .expect("LOCAL_IMAP_PORT not set") + .parse() + .expect("Invalid LOCAL_IMAP_PORT"), + remote_domain: env::var("REMOTE_IMAP_DOMAIN").expect("REMOTE_IMAP_DOMAIN not set"), + remote_port: env::var("REMOTE_IMAP_PORT") + .expect("REMOTE_IMAP_PORT not set") + .parse() + .expect("Invalid REMOTE_IMAP_PORT"), + protocol: "IMAP", + }), + smtp_configuration: Arc::new(ProxyConfiguration { + local_port: env::var("LOCAL_SMTP_PORT") + .expect("LOCAL_SMTP_PORT not set") + .parse() + .expect("Invalid LOCAL_SMTP_PORT"), + remote_domain: env::var("REMOTE_SMTP_DOMAIN").expect("REMOTE_SMTP_DOMAIN not set"), + remote_port: env::var("REMOTE_SMTP_PORT") + .expect("REMOTE_SMTP_PORT not set") + .parse() + .expect("Invalid REMOTE_SMTP_PORT"), + protocol: "SMTP", + }), + } + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..858e460 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,15 @@ +mod configuration; +mod proxy; + +use configuration::Configuration; +use proxy::create_proxy; + +fn main() { + let configuration = Configuration::new(); + + let imap_proxy = create_proxy(configuration.imap_configuration); + let smtp_proxy = create_proxy(configuration.smtp_configuration); + + imap_proxy.join().unwrap(); + smtp_proxy.join().unwrap(); +} 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; + } + } + } +} |