use socks5_server::{ auth::NoAuth, connection::state::NeedAuthenticate, proto::{Address, Error, Reply}, Command, IncomingConnection, Server, }; use std::{io::Error as IoError, sync::Arc}; use tokio::{ io::{self, AsyncWriteExt}, net::{TcpListener, TcpStream}, }; #[tokio::main] async fn main() -> Result<(), IoError> { let listener = TcpListener::bind("127.0.0.1:5000").await?; let auth = Arc::new(NoAuth) as Arc<_>; let server = Server::new(listener, auth); while let Ok((conn, _)) = server.accept().await { tokio::spawn(async move { match handle(conn).await { Ok(()) => {} Err(err) => eprintln!("{err}"), } }); } Ok(()) } async fn handle(conn: IncomingConnection<(), NeedAuthenticate>) -> Result<(), Error> { let conn = match conn.authenticate().await { Ok((conn, _)) => conn, Err((err, mut conn)) => { let _ = conn.shutdown().await; return Err(err); } }; match conn.wait().await { Ok(Command::Associate(associate, _)) => { let replied = associate .reply(Reply::CommandNotSupported, Address::unspecified()) .await; let mut conn = match replied { Ok(conn) => conn, Err((err, mut conn)) => { let _ = conn.shutdown().await; return Err(Error::Io(err)); } }; let _ = conn.close().await; } Ok(Command::Bind(bind, _)) => { let replied = bind .reply(Reply::CommandNotSupported, Address::unspecified()) .await; let mut conn = match replied { Ok(conn) => conn, Err((err, mut conn)) => { let _ = conn.shutdown().await; return Err(Error::Io(err)); } }; let _ = conn.close().await; } Ok(Command::Connect(connect, addr)) => { let target = match addr { Address::DomainAddress(domain, port) => { let domain = String::from_utf8_lossy(&domain); TcpStream::connect((domain.as_ref(), port)).await } Address::SocketAddress(addr) => TcpStream::connect(addr).await, }; if let Ok(mut target) = target { let replied = connect .reply(Reply::Succeeded, Address::unspecified()) .await; let mut conn = match replied { Ok(conn) => conn, Err((err, mut conn)) => { let _ = conn.shutdown().await; return Err(Error::Io(err)); } }; let res = io::copy_bidirectional(&mut target, &mut conn).await; let _ = conn.shutdown().await; let _ = target.shutdown().await; res?; } else { let replied = connect .reply(Reply::HostUnreachable, Address::unspecified()) .await; let mut conn = match replied { Ok(conn) => conn, Err((err, mut conn)) => { let _ = conn.shutdown().await; return Err(Error::Io(err)); } }; let _ = conn.shutdown().await; } } Err((err, mut conn)) => { let _ = conn.shutdown().await; return Err(err); } } Ok(()) }