simple_server/
simple_server.rs

1use simple_socks5::conn::request::CMD;
2use simple_socks5::{ATYP, Socks5, conn::reply::Rep, error::SocksError, parse::AddrPort};
3use std::net::{IpAddr, Ipv4Addr};
4use std::sync::Arc;
5use tokio::io;
6use tokio::io::AsyncWriteExt;
7use tokio::net::TcpStream;
8use tracing::{error, info, warn};
9
10#[tokio::main]
11async fn main() -> Result<(), SocksError> {
12    tracing_subscriber::fmt()
13        .with_target(false)
14        .with_level(true)
15        .compact()
16        .init();
17
18    // Both IPv4 and IPv6 work
19    let mut server = Socks5::bind("127.0.0.1:1080").await?;
20    server.allow_no_auth();
21
22    // Example with a username and password if you need authentication
23    // server.allow_userpass(|u, p| u == "admin" && p == "admin");
24
25    let server = Arc::new(server);
26
27    info!("SOCKS5 proxy listening on {}", server.local_addr()?);
28
29    loop {
30        let (client, addr) = server.accept().await?;
31        let server_ref = Arc::clone(&server);
32
33        tokio::spawn(async move {
34            if let Err(e) = handle_client(server_ref, client, addr).await {
35                error!("Client {addr} error: {e}");
36            }
37        });
38    }
39}
40
41async fn handle_client(
42    server: Arc<Socks5>,
43    mut stream: TcpStream,
44    addr: std::net::SocketAddr,
45) -> Result<(), SocksError> {
46    info!("New client connected from {addr}");
47
48    if let Err(e) = server.authenticate(&mut stream).await {
49        warn!("Authentication failed for {addr}: {e}");
50        let _ = stream.shutdown().await;
51        return Ok(());
52    }
53    info!("Authentication succeeded for {addr}");
54
55    let req = match Socks5::read_conn_request(&mut stream).await {
56        Ok(r) => {
57            info!(client=%addr, "Connection request");
58            info!(request=%r, "Request format");
59            r
60        }
61        Err(e) => {
62            error!("Failed to read connection request from {addr}: {e}");
63            let _ = stream.shutdown().await;
64            return Ok(());
65        }
66    };
67
68    match req.cmd {
69        CMD::Connect => {
70            info!(client=%addr, dest=%req.dst, "Connecting to destination");
71
72            let mut target = match req.dst {
73                AddrPort::V4(ip, port) => TcpStream::connect((ip, port)).await?,
74                AddrPort::V6(ip, port) => TcpStream::connect((ip, port)).await?,
75                AddrPort::Domain(ref host, port) => {
76                    TcpStream::connect((host.as_str(), port)).await?
77                }
78            };
79
80            let local_addr = target.local_addr()?;
81            let bnd = match local_addr.ip() {
82                IpAddr::V4(ip) => AddrPort::V4(ip, local_addr.port()),
83                IpAddr::V6(ip) => AddrPort::V6(ip, local_addr.port()),
84            };
85
86            let atyp = match bnd {
87                AddrPort::V4(_, _) => ATYP::V4,
88                AddrPort::V6(_, _) => ATYP::V6,
89                _ => ATYP::DomainName,
90            };
91
92            info!(client=%addr, bind=%bnd, atyp=%atyp, "Connection established");
93
94            Socks5::send_conn_reply(&mut stream, Rep::Succeeded, atyp, bnd).await?;
95
96            if let Err(e) = io::copy_bidirectional(&mut stream, &mut target).await {
97                warn!("TCP connection with {addr} closed with error: {e}");
98            } else {
99                info!("TCP connection with {addr} closed");
100            }
101        }
102
103        _ => {
104            warn!("Unsupported command from {addr}: {}", req.cmd);
105            Socks5::send_conn_reply(
106                &mut stream,
107                Rep::CommandNotSupported,
108                ATYP::V4,
109                AddrPort::V4(Ipv4Addr::UNSPECIFIED, 0),
110            )
111            .await?;
112        }
113    }
114
115    Ok(())
116}