s5t 0.1.0

client for s5x crate
#![warn(clippy::pedantic)]

mod prelude;
mod mode;
mod socks5;
mod http;

use prelude::*;
use tokio::net::TcpListener;
use tokio::net::TcpStream;
use tracing_subscriber::fmt;
use tracing_subscriber::EnvFilter;

use crate::socks5::{config::Socks5Config, session::Socks5Session};

#[tokio::main]
async fn main() -> Result<(), AppError> {
    setup_tracing();

    let mut config = Socks5Config::new()?;
    config.validate()?;

    match config.mode {
        Mode::Cli => {
            debug!(config = ?config, "socks5 client started");
            let stream = TcpStream::connect(config.server).await.map_err(|_| AppError::TargetUnreachable)?;
            let mut session = Socks5Session::new(config, stream);

            if session.handshake().await? == consts::auth::AUTH { session.auth().await?; }
            session.connect().await?;
            session.send().await
        },
        Mode::Proxy => {
            let listener = TcpListener::bind(config.listen).await?;
            info!(config = ?config, "socks5 client started");

            loop {
                let (mut client_stream, client_addr) = listener.accept().await?;
                info!(%client_addr, "new connection");

                tokio::spawn(async move {
                    let mut server_stream = TcpStream::connect(config.server).await.map_err(|_| AppError::TargetUnreachable)?;
                    tokio::io::copy_bidirectional(&mut client_stream, &mut server_stream).await?;
                    info!(%client_addr, "connection closed");
                    Ok::<(), AppError>(())
                });
            }
        },
        Mode::_Tun => Err(AppError::Socks5(format!("mode {:?} not yet implemented", config.mode))),
    }
}

#[cfg(debug_assertions)]
fn setup_tracing() {
    fmt()
        .with_target(false)
        .with_env_filter(
            EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| EnvFilter::new("rustls=warn,s5t=trace,s5l=trace"))
        )
        .init();
}

#[cfg(not(debug_assertions))]
fn setup_tracing() {
    fmt()
        .with_target(false)
        .with_env_filter(
            EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| EnvFilter::new("rustls=error,s5t=info"))
        )
        .init();
}