use std::{collections::HashMap, sync::Arc};
use socks5x::server::{AuthValidator, ClientHandler, DefaultConnectionCreator};
use tokio::net::TcpListener;
#[derive(Default)]
struct Database {
inner: HashMap<String, String>,
}
impl Database {
fn add_user(&mut self, username: &str, password: &str) {
self.inner
.insert(username.to_string(), password.to_string());
}
}
impl AuthValidator for Database {
async fn validate(&self, username: &str, password: &str) -> bool {
self.inner
.get(username)
.map(|p| p == password)
.unwrap_or(false)
}
}
#[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 mut db = Database::default();
db.add_user("admin", "secret");
let client_handler = Arc::new(ClientHandler::new(
socks5x::server::Auth::UserPassword(db),
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);
}
});
}
}