socks5x

Crates.iosocks5x
lib.rssocks5x
version0.1.3
created_at2025-08-31 12:53:14.563192+00
updated_at2025-09-01 17:22:38.832121+00
descriptionA simple, async SOCKS5 proxy library for Rust
homepagehttps://github.com/i64/socks5x-rs
repositoryhttps://github.com/i64/socks5x-rs
max_upload_size
id1818517
size73,594
(i64)

documentation

https://docs.rs/socks5x

README

socks5x

Documentation crates

A simple, async SOCKS5 proxy library for Rust. Check the exmaples folder for more examples

Features

  • Async client and server implementations
  • No-auth and username/password authentication
  • Support for IPv4, IPv6, and domain name addresses
  • Custom stream connectors for extensibility

Quick Start

Add this to your Cargo.toml:

[dependencies]
socks5x = "0.1.2"

Client Usage

Simple Connection (No Authentication)

use socks5x::client::Socks5Client;
use socks5x::Socks5Address;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to SOCKS5 proxy
    let client = Socks5Client::connect("127.0.0.1:1080", None).await?;
    
    // Request connection to destination
    let mut stream = client
        .request_connect(Socks5Address::from("httpbin.org"), 80)
        .await?;
    
    // Use the stream normally - data is transparently proxied
    let request = "GET /ip HTTP/1.1\r\nHost: httpbin.org\r\nConnection: close\r\n\r\n";
    stream.write_all(request.as_bytes()).await?;
    
    let mut response = Vec::new();
    stream.read_to_end(&mut response).await?;
    println!("Response: {}", String::from_utf8_lossy(&response));
    
    Ok(())
}

Authenticated Connection

    let client = Socks5Client::connect(
        "127.0.0.1:1080",
        Some(("username".to_string(), "password".to_string())),
    )
    .await?;

Server Usage

Basic Server (No Authentication)

use std::sync::Arc;

use socks5x::server::{ClientHandler, DefaultConnectionCreator};
use tokio::net::TcpListener;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let listener = TcpListener::bind("127.0.0.1:1080").await?;
    println!("SOCKS5 proxy server listening on 127.0.0.1:1080");

    let client_handler = Arc::new(ClientHandler::no_auth(DefaultConnectionCreator));

    loop {
        let (socket, addr) = listener.accept().await?;
        println!("New client connection from: {}", addr);
        let client_handler = client_handler.clone();

        tokio::spawn(async move {
            if let Err(e) = client_handler.handle(socket).await {
                eprintln!("Error handling client {}: {}", addr, e);
            } else {
                println!("Client {} disconnected", addr);
            }
        });
    }
}

Server with Authentication

use socks5x::server::{ClientHandler, DefaultConnectionCreator, Auth, AuthValidator};

struct MyAuthValidator;

impl AuthValidator for MyAuthValidator {
    async fn validate(&self, username: &str, password: &str) -> bool {
        // Implement your authentication logic
        username == "admin" && password == "secret"
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let listener = TcpListener::bind("127.0.0.1:1080").await?;
    let auth = Auth::UserPassword(MyAuthValidator);
    let handler = ClientHandler::new(auth, DefaultConnectionCreator);
    
    loop {
        let (socket, _) = listener.accept().await?;
        let handler = &handler;
        tokio::spawn(async move {
            if let Err(e) = handler.handle(socket).await {
                eprintln!("Connection error: {}", e);
            }
        });
    }
}

Address Types

The Socks5Address enum supports all SOCKS5 address types:

use socks5x::Socks5Address;
use std::net::{Ipv4Addr, Ipv6Addr};

// From string (automatically detects type)
let addr1 = Socks5Address::from("example.com");    // Domain
let addr2 = Socks5Address::from("192.168.1.1");    // IPv4  
let addr3 = Socks5Address::from("2001:db8::1");    // IPv6

// Explicit construction
let addr4 = Socks5Address::IPv4(Ipv4Addr::new(127, 0, 0, 1));
let addr5 = Socks5Address::IPv6(Ipv6Addr::LOCALHOST);
let addr6 = Socks5Address::Domain("github.com".to_string());

Advanced Usage

Custom Connection Handler

Implement custom connection logic by providing your own ConnectionCreator:

use socks5x::server::{ConnectionCreator, SocksSplitable};
use socks5x::Socks5Address;
use tokio::net::TcpStream;
use std::io;

struct CustomConnectionCreator;

impl ConnectionCreator for CustomConnectionCreator {
    type Stream = TcpStream;
    
    async fn create_stream(
        &self, 
        address: Socks5Address, 
        port: u16
    ) -> io::Result<Self::Stream> {
        // Add custom logic: logging, filtering, routing, etc.
        println!("Connecting to {}:{}", address, port);
        
        // You could implement:
        // - Connection filtering/blocking
        // - Custom DNS resolution
        // - Traffic routing through different interfaces
        // - Connection pooling
        
        TcpStream::connect((address.to_string(), port)).await
    }
}

Feature Flags

  • client - Enable SOCKS5 client functionality (enabled by default)
  • server - Enable SOCKS5 server functionality (enabled by default)
[dependencies]
# Client only
socks5x = { version = "0.1.2", default-features = false, features = ["client"] }

# Server only  
socks5x = { version = "0.1.2", default-features = false, features = ["server"] }
Commit count: 5

cargo fmt