use std::net::SocketAddr;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener;
use super::error::Socks4Error;
use super::server::{read_socks4_request, write_socks4_reply, Socks4Status};
#[derive(Debug, Clone)]
pub enum TestServerMode {
Success,
Rejected,
NoIdent,
DifferentUser,
MalformedResponse,
UnknownStatus,
SlowResponse,
DomainSuccess,
NoReply,
}
pub struct TestServerHandle {
pub addr: SocketAddr,
}
impl TestServerHandle {
pub async fn spawn(mode: TestServerMode) -> Self {
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
tokio::spawn(async move {
Self::run(listener, mode).await;
});
Self { addr }
}
async fn run(listener: TcpListener, mode: TestServerMode) {
loop {
let (mut stream, _) = match listener.accept().await {
Ok(v) => v,
Err(_) => break,
};
let mode = mode.clone();
tokio::spawn(async move {
let _ = Self::handle_connection(&mut stream, &mode).await;
});
}
}
async fn handle_connection(
stream: &mut tokio::net::TcpStream,
mode: &TestServerMode,
) -> Result<(), Socks4Error> {
let _request = read_socks4_request(stream).await?;
let bound: SocketAddr = "127.0.0.1:0".parse().unwrap();
match mode {
TestServerMode::Success => {
write_socks4_reply(stream, Socks4Status::Granted, bound).await?;
}
TestServerMode::Rejected => {
write_socks4_reply(stream, Socks4Status::Failed, bound).await?;
}
TestServerMode::NoIdent => {
write_socks4_reply(stream, Socks4Status::FailedNoIdent, bound).await?;
}
TestServerMode::DifferentUser => {
write_socks4_reply(stream, Socks4Status::FailedDifferentUser, bound).await?;
}
TestServerMode::MalformedResponse => {
stream
.write_all(&[0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE])
.await?;
stream.flush().await?;
}
TestServerMode::UnknownStatus => {
let reply: [u8; 8] = [0x00, 99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
stream.write_all(&reply).await?;
stream.flush().await?;
}
TestServerMode::SlowResponse => {
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
write_socks4_reply(stream, Socks4Status::Granted, bound).await?;
}
TestServerMode::DomainSuccess => {
write_socks4_reply(stream, Socks4Status::Granted, bound).await?;
}
TestServerMode::NoReply => {
return Ok(());
}
}
match mode {
TestServerMode::Success | TestServerMode::DomainSuccess => {
let mut buf = [0u8; 1024];
loop {
match stream.read(&mut buf).await {
Ok(0) | Err(_) => break,
Ok(n) => {
let _ = stream.write_all(&buf[..n]).await;
}
}
}
}
_ => {}
}
Ok(())
}
}