use crate::error::*;
use crate::utils::*;
use crate::*;
use async_trait::async_trait;
use std::borrow::Cow;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;
#[async_trait]
impl SocksBind for Client {
async fn bind(&mut self, target_ip: &str, target_port: u16) -> Result<(), SocksError> {
match self {
Client::Socks4(inner) | Client::Socks4a(inner) => {
let mut stream = TcpStream::connect(&inner.proxy_addr).await.map_err(|e| SocksError::BindError(e.to_string()))?;
let username: Cow<[u8]> = match inner.username.as_ref() {
Some(username) => Cow::Borrowed(username.as_bytes()),
None => Cow::Owned(String::new().into_bytes()),
};
let target = target_ip.parse::<Ipv4Addr>().map_err(|e| SocksError::BindError(e.to_string()))?;
inner.buf.clear();
let request = &mut inner.buf;
request.extend_from_slice(&[0x04, SOCKS_CMD_BIND]);
request.extend_from_slice(&target_port.to_be_bytes());
request.extend_from_slice(&target.octets());
request.extend_from_slice(&username);
request.push(0x00);
stream.write_all(request).await.map_err(|e| SocksError::BindError(e.to_string()))?;
inner.buf.resize(8, 0);
let response = &mut inner.buf;
stream.read_exact(response).await.map_err(|e| SocksError::BindError(e.to_string()))?;
if response[0] != 0x00 {
return Err(SocksError::BindError(format!(
"SOCKS4 bind request failed, error {}",
"the version of the reply code should be 0"
)));
}
if response[1] != 0x5A {
return Err(SocksError::BindError(format!(
"SOCKS4 bind request failed, error {}:{}",
response[1],
translate_socks4_error(response[1])
)));
}
if response[4] == 0 && response[5] == 0 && response[6] == 0 && response[7] == 0 {
let mut proxy_ip = stream.peer_addr().map_err(|e| SocksError::BindError(e.to_string()))?;
let bind_port = u16::from_be_bytes([response[2], response[3]]);
proxy_ip.set_port(bind_port);
inner.stream = Some(stream);
inner.bindaddr = Some(proxy_ip);
return Ok(());
}
let bind_ip = format!("{}.{}.{}.{}", response[4], response[5], response[6], response[7]);
let bind_port = u16::from_be_bytes([response[2], response[3]]);
let bind_addr =
format!("{}:{}", bind_ip, bind_port).parse::<SocketAddr>().map_err(|e| SocksError::BindError(e.to_string()))?;
inner.stream = Some(stream);
inner.bindaddr = Some(bind_addr);
return Ok(());
}
Client::Socks5(inner) => {
let mut stream = TcpStream::connect(&inner.proxy_addr).await.map_err(|e| SocksError::BindError(e.to_string()))?;
let target = target_ip.parse::<IpAddr>().map_err(|e| SocksError::BindError(e.to_string()))?;
socks5_authenticate(&mut stream, inner).await?;
inner.buf.clear();
let request = &mut inner.buf;
match target {
IpAddr::V4(addr) => {
request.extend_from_slice(&[0x05, SOCKS_CMD_BIND, 0x00, SOCKS_ADDR_TYPE_IPV4]);
request.extend_from_slice(&addr.octets());
request.extend_from_slice(&target_port.to_be_bytes());
stream.write_all(request).await.map_err(|e| SocksError::BindError(e.to_string()))?;
}
IpAddr::V6(addr) => {
request.extend_from_slice(&[0x05, SOCKS_CMD_BIND, 0x00, SOCKS_ADDR_TYPE_IPV6]);
request.extend_from_slice(&addr.octets());
request.extend_from_slice(&target_port.to_be_bytes());
stream.write_all(request).await.map_err(|e| SocksError::BindError(e.to_string()))?;
}
}
inner.buf.resize(22, 0);
let bind_response = &mut inner.buf;
stream.read_exact(&mut bind_response[..4]).await.map_err(|e| SocksError::BindError(e.to_string()))?;
if bind_response[0] != 0x05 || bind_response[1] != 0x00 {
return Err(SocksError::BindError(format!(
"SOCKS5 BIND request failed, error {}:{}",
bind_response[1],
translate_socks5_error(bind_response[1])
)));
}
let addr_type = bind_response[3];
let addr_len;
if addr_type == SOCKS_ADDR_TYPE_IPV4 {
addr_len = 4;
} else if addr_type == SOCKS_ADDR_TYPE_IPV6 {
addr_len = 16;
} else {
return Err(SocksError::BindError(format!("Unsupported address type: {:02X}", addr_type)));
}
stream.read_exact(&mut bind_response[4..4 + addr_len + 2]).await.map_err(|e| SocksError::BindError(e.to_string()))?;
let bnd_addr = match addr_type {
SOCKS_ADDR_TYPE_IPV4 => {
if bind_response[4] == 0 && bind_response[5] == 0 && bind_response[6] == 0 && bind_response[7] == 0 {
let mut proxy_ip = stream.peer_addr().map_err(|e| SocksError::BindError(e.to_string()))?;
let bind_port = u16::from_be_bytes([bind_response[8], bind_response[9]]);
proxy_ip.set_port(bind_port);
proxy_ip
} else {
let mut addr = [0u8; 4];
addr.copy_from_slice(&bind_response[4..8]);
SocketAddr::from((std::net::Ipv4Addr::from(addr), u16::from_be_bytes([bind_response[8], bind_response[9]])))
}
}
SOCKS_ADDR_TYPE_IPV6 => {
if bind_response[4..20].iter().all(|&elem| elem == 0) {
let mut proxy_ip = stream.peer_addr().map_err(|e| SocksError::BindError(e.to_string()))?;
let bind_port = u16::from_be_bytes([bind_response[20], bind_response[21]]);
proxy_ip.set_port(bind_port);
proxy_ip
} else {
let mut addr = [0u8; 16];
addr.copy_from_slice(&bind_response[4..20]);
SocketAddr::from((std::net::Ipv6Addr::from(addr), u16::from_be_bytes([bind_response[20], bind_response[21]])))
}
}
_ => return Err(SocksError::BindError("Unsupported address type".into())),
};
inner.stream = Some(stream);
inner.bindaddr = Some(bnd_addr);
return Ok(());
}
}
}
fn get_proxy_bind_addr(&mut self) -> Option<SocketAddr> {
match self {
Client::Socks4(inner) | Client::Socks4a(inner) | Client::Socks5(inner) => inner.bindaddr,
}
}
async fn accept(&mut self) -> Result<SocksTcpStream, SocksError> {
match self {
Client::Socks4(inner) | Client::Socks4a(inner) => {
let bindaddr: SocketAddr = inner.bindaddr.take().ok_or(SocksError::BindError("accept not ready".into()))?;
let mut stream = inner.stream.take().ok_or(SocksError::BindError("accept not ready".into()))?;
let mut second_bind_response_header = [0; 8];
stream.read_exact(&mut second_bind_response_header).await.map_err(|e| SocksError::BindError(e.to_string()))?;
if second_bind_response_header[0] != 0x00 {
return Err(SocksError::BindError(format!(
"SOCKS4 bind request failed, error {}",
"the version of the reply code should be 0"
)));
}
if second_bind_response_header[1] != 0x5A {
return Err(SocksError::BindError(format!(
"SOCKS4 bind request failed, error {}:{}",
second_bind_response_header[1],
translate_socks4_error(second_bind_response_header[1])
)));
}
Ok(SocksTcpStream::new(stream, bindaddr))
}
Client::Socks5(inner) => {
let bindaddr: SocketAddr = inner.bindaddr.take().ok_or(SocksError::BindError("accept not ready".into()))?;
let mut stream = inner.stream.take().ok_or(SocksError::BindError("accept not ready".into()))?;
let mut second_bind_response_header = [0; 4];
stream.read_exact(&mut second_bind_response_header).await.map_err(|e| SocksError::BindError(e.to_string()))?;
if second_bind_response_header[0] != 0x05 || second_bind_response_header[1] != 0x00 {
return Err(SocksError::BindError(format!(
"SOCKS5 BIND accept failed with code: {:02X}",
second_bind_response_header[1]
)));
}
let addr_type = second_bind_response_header[3];
let mut bind_response = vec![
0;
match addr_type {
SOCKS_ADDR_TYPE_IPV4 => 10,
SOCKS_ADDR_TYPE_IPV6 => 22,
_ => return Err(SocksError::BindError("Unsupported address type".into())),
}
];
bind_response[..4].copy_from_slice(&second_bind_response_header);
stream.read_exact(&mut bind_response[4..]).await.map_err(|e| SocksError::BindError(e.to_string()))?;
Ok(SocksTcpStream::new(stream, bindaddr))
}
}
}
}