aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuben Beltran del Rio <git@r.bdr.sh>2025-01-24 20:34:35 +0100
committerRuben Beltran del Rio <git@r.bdr.sh>2025-01-24 20:34:35 +0100
commitdc3d68214e2cd4b5f86279a7fa7b7d64c341b446 (patch)
tree30da7fdfcf612f00705e87acdf379a0334d6cb08 /src
First approach
Diffstat (limited to 'src')
-rw-r--r--src/configuration.rs45
-rw-r--r--src/main.rs15
-rw-r--r--src/proxy.rs86
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;
+ }
+ }
+ }
+}