sslrelay/src/lib.rs

226 lines
6 KiB
Rust

//! ## SSLRelay
//! Library for relaying TCP traffic as well as TLS encrypted TCP traffic.
//! This library allows you to implement callback functions for upstream and downstream traffic.
//! These callbacks can R/W the data from a stream(Blocking) or only R the data(Non-Blocking).
//!```
//! pub trait HandlerCallbacks {
//! fn ds_b_callback(&mut self, _in_data: Vec<u8>) -> CallbackRet {
//! CallbackRet::Relay(_in_data)
//! }
//! fn ds_nb_callback(&self, _in_data: Vec<u8>) {}
//! fn us_b_callback(&mut self, _in_data: Vec<u8>) -> CallbackRet {
//! CallbackRet::Relay(_in_data)
//! }
//! fn us_nb_callback(&self, _in_data: Vec<u8>) {}
//! }
//! ```
//! The blocking callbacks return an enum called CallbackRet with four different variants.
//! The variants control the flow of the tcp stream.
//!```
//! pub enum CallbackRet {
//! Relay(Vec<u8>), // Relay data
//! Spoof(Vec<u8>), // Skip relaying and send data back
//! Shutdown, // Shutdown TCP connection
//! Freeze, // Dont send data (pretend as if stream never was recieved)
//! }
//! ```
//! ## Example (basic.rs)
//! ```
//! use sslrelay::{self, CallbackRet, HandlerCallbacks, RelayConfig, TCPDataType, TLSConfig};
//!
//! // Handler object
//! #[derive(Clone)] // Must have Clone trait implemented.
//! struct Handler;
//!
//! /*
//! Callback traits that can be used to read or inject data
//! into data upstream or downstream.
//! */
//! impl HandlerCallbacks for Handler {
//! // DownStream non blocking callback (Read Only)
//! fn ds_nb_callback(&self, _in_data: Vec<u8>) {
//! println!("[CALLBACK] Down Stream Non Blocking CallBack!");
//! }
//!
//! // DownStream blocking callback (Read & Write)
//! fn ds_b_callback(&mut self, _in_data: Vec<u8>) -> CallbackRet {
//! println!("[CALLBACK] Down Stream Blocking CallBack!");
//! CallbackRet::Relay(_in_data)
//! }
//!
//! // UpStream non blocking callback (Read Only)
//! fn us_nb_callback(&self, _in_data: Vec<u8>) {
//! println!("[CALLBACK] Up Stream Non Blocking CallBack!");
//! }
//!
//! // UpStream blocking callback (Read & Write)
//! fn us_b_callback(&mut self, _in_data: Vec<u8>) -> CallbackRet {
//! println!("[CALLBACK] Up Stream Blocking CallBack!");
//! CallbackRet::Relay(_in_data)
//! }
//! }
//!
//! fn main() {
//! // Create new SSLRelay object
//! let mut relay = sslrelay::SSLRelay::new(
//! Handler,
//! RelayConfig {
//! downstream_data_type: TCPDataType::TLS,
//! upstream_data_type: TCPDataType::TLS,
//! bind_host: "0.0.0.0".to_string(),
//! bind_port: "443".to_string(),
//! remote_host: |_| "remote.com",
//! remote_port: "443".to_string(),
//! tls_config: TLSConfig::FILE {
//! certificate_path: "./tls.crt".to_string(),
//! private_key_path: "./tls.key".to_string(),
//! },
//! },
//! );
//!
//! // Start listening
//! relay.start();
//! }
//! ```
use openssl::{
pkey::PKey,
ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod, SslStream, SslVerifyMode},
x509::X509,
};
use std::net::{Shutdown, TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use std::thread;
use std::{path::Path, time::Duration};
use std::io::{self, Read, Write};
use std::sync::mpsc::{self, Receiver, Sender};
mod data;
mod relay;
mod tcp;
#[derive(Debug)]
enum FullDuplexTcpState {
DownStreamWrite(Vec<u8>),
UpStreamWrite(Vec<u8>),
DownStreamShutDown,
UpStreamShutDown,
}
#[derive(Debug)]
enum DataPipe {
DataWrite(Vec<u8>),
Shutdown,
}
enum DataStreamType {
RAW(TcpStream),
TLS(SslStream<TcpStream>),
}
/// Specifies the upstream or downstream data type (TLS or RAW).
#[derive(Copy, Clone)]
pub enum TCPDataType {
TLS,
RAW,
}
/// TLSConfig is used to specify TLS options.
/// FILE is for specifying a path to a certificate and private key.
/// DATA is for passing the certificate and private key bytes directly.
/// NONE is for when you are not using TLS on the listening/downstream side of the relay.
#[derive(Clone)]
pub enum TLSConfig {
FILE {
certificate_path: String,
private_key_path: String,
},
DATA {
certificate: Vec<u8>,
private_key: Vec<u8>,
},
NONE,
}
/// Relay Config structure for passing into the SSLRelay::new() config parameter.
#[derive(Clone)]
pub struct RelayConfig {
pub downstream_data_type: TCPDataType,
pub upstream_data_type: TCPDataType,
pub bind_host: String,
pub bind_port: String,
pub remote_host: fn(Option<&str>) -> String,
//pub remote_host: String,
pub remote_port: String,
pub tls_config: TLSConfig,
}
/// CallbackRet for blocking callback functions
#[derive(Debug)]
pub enum CallbackRet {
Relay(Vec<u8>), // Relay data
Spoof(Vec<u8>), // Skip relaying and send data back
Shutdown, // Shutdown TCP connection
Freeze, // Dont send data (pretend as if stream never was recieved)
}
/// Callback functions a user may or may not implement.
pub trait HandlerCallbacks {
fn ds_b_callback(&mut self, _in_data: Vec<u8>, _conn_id: u64) -> CallbackRet {
CallbackRet::Relay(_in_data)
}
fn ds_nb_callback(&self, _in_data: Vec<u8>, _conn_id: u64) {}
fn us_b_callback(&mut self, _in_data: Vec<u8>, _conn_id: u64) -> CallbackRet {
CallbackRet::Relay(_in_data)
}
fn us_nb_callback(&self, _in_data: Vec<u8>, _conn_id: u64) {}
fn set_server_name(&mut self, _server_name: Option<&str>) {}
}
/// The main SSLRelay object.
#[derive(Clone)]
pub struct SSLRelay<H>
where
H: HandlerCallbacks + std::marker::Sync + std::marker::Send + Clone + 'static,
{
config: RelayConfig,
handlers: Option<InnerHandlers<H>>,
}
#[allow(dead_code)]
struct FullDuplexTcp<H>
where
H: HandlerCallbacks + std::marker::Sync + std::marker::Send + Clone + 'static,
{
remote_host: String,
remote_port: String,
ds_inner_m: Arc<Mutex<Option<DownStreamInner>>>,
us_inner_m: Arc<Mutex<Option<UpStreamInner>>>,
inner_handlers: InnerHandlers<H>,
conn_id: u64,
}
#[derive(Clone)]
struct InnerHandlers<H>
where
H: HandlerCallbacks + std::marker::Sync + std::marker::Send + Clone + 'static,
{
cb: H,
}
struct DownStreamInner {
ds_stream: DataStreamType,
internal_data_buffer: Vec<u8>,
}
struct UpStreamInner {
us_stream: DataStreamType,
internal_data_buffer: Vec<u8>,
}