# socks5x
[](https://docs.rs/socks5x/)
[](https://crates.io/crates/socks5x)
A simple, async SOCKS5 proxy library for Rust. Check the exmaples folder for more [examples](./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`:
```toml
[dependencies]
socks5x = "0.1.2"
```
### Client Usage
#### Simple Connection (No Authentication)
```rust
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
```rust
let client = Socks5Client::connect(
"127.0.0.1:1080",
Some(("username".to_string(), "password".to_string())),
)
.await?;
```
### Server Usage
#### Basic Server (No Authentication)
```rust
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
```rust
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:
```rust
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`:
```rust
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)
```toml
[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"] }
```