From a06e3bc81e7ae804cf13eafc0e7ad5440fd6924d Mon Sep 17 00:00:00 2001 From: KaranGauswami Date: Fri, 17 Jun 2022 23:02:44 +0530 Subject: [PATCH] added support for authentication with username and password --- src/main.rs | 49 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index acd13d1..448ed65 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ use hyper::client::HttpConnector; use hyper::service::{make_service_fn, service_fn}; use hyper::upgrade::Upgraded; use hyper::{Body, Request, Response, Server}; -use hyper_socks2::SocksConnector; +use hyper_socks2::{Auth, SocksConnector}; use log::debug; use std::convert::Infallible; use std::net::SocketAddr; @@ -22,6 +22,14 @@ struct Cli { /// Socks5 proxy address #[clap(short, long, default_value = "127.0.0.1:1080")] socks_address: SocketAddr, + + /// Socks5 username + #[clap(short = 'u', long)] + username: Option, + + /// Socks5 username + #[clap(short = 'P', long)] + password: Option, } #[tokio::main] @@ -31,9 +39,18 @@ async fn main() -> Result<()> { let args = Cli::parse(); let socks_address = args.socks_address; let port = args.port; + + let username = args.username; + let password = args.password; + let auth = if let (Some(username), Some(password)) = (username, password) { + Some(Auth::new(username, password)) + } else { + None + }; + let auth = &*Box::leak(Box::new(auth)); let addr = SocketAddr::from(([0, 0, 0, 0], port)); let make_service = make_service_fn(move |_| async move { - Ok::<_, Infallible>(service_fn(move |req| proxy(req, socks_address))) + Ok::<_, Infallible>(service_fn(move |req| proxy(req, socks_address, auth))) }); let server = Server::bind(&addr) .http1_preserve_header_case(true) @@ -48,7 +65,11 @@ async fn main() -> Result<()> { fn host_addr(uri: &http::Uri) -> Option { uri.authority().map(|auth| auth.to_string()) } -async fn proxy(req: Request, socks_address: SocketAddr) -> Result> { +async fn proxy( + req: Request, + socks_address: SocketAddr, + auth: &'static Option, +) -> Result> { let mut connector = HttpConnector::new(); connector.enforce_http(false); let proxy_addr = Box::leak(Box::new(format!("socks://{}", socks_address))); @@ -58,7 +79,7 @@ async fn proxy(req: Request, socks_address: SocketAddr) -> Result { - if let Err(e) = tunnel(upgraded, plain, socks_address).await { + if let Err(e) = tunnel(upgraded, plain, socks_address, auth).await { debug!("server io error: {}", e); }; } @@ -68,7 +89,8 @@ async fn proxy(req: Request, socks_address: SocketAddr) -> Result, socks_address: SocketAddr) -> Result(mut upgraded: Upgraded, plain: T, socks_address: P) -> Result<()> +async fn tunnel<'t, P, T>( + mut upgraded: Upgraded, + plain: T, + socks_address: P, + auth: &Option, +) -> Result<()> where P: ToProxyAddrs, T: IntoTargetAddr<'t>, { - let mut stream = Socks5Stream::connect(socks_address, plain).await?; + let mut stream = if let Some(auth) = auth { + let username = &auth.username; + let password = &auth.password; + Socks5Stream::connect_with_password(socks_address, plain, username, password).await? + } else { + Socks5Stream::connect(socks_address, plain).await? + }; // Proxying data let (from_client, from_server) =