use std::net::SocketAddr;
use tokio::io::{self, AsyncReadExt, AsyncWriteExt};
use super::addr_type::Socks5AddrType;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum Socks5Reply {
Succeeded = 0x00,
Failure = 0x01,
NotAllowed = 0x02,
NetworkUnreachable = 0x03,
HostUnreachable = 0x04,
ConnectionRefused = 0x05,
TTLExpired = 0x06,
UnsupportedCommand = 0x07,
UnsupportedAddressType = 0x08,
Unassigned(u8),
}
impl From<u8> for Socks5Reply {
fn from(value: u8) -> Self {
match value {
0x00 => Self::Succeeded,
0x01 => Self::Failure,
0x02 => Self::NotAllowed,
0x03 => Self::NetworkUnreachable,
0x04 => Self::HostUnreachable,
0x05 => Self::ConnectionRefused,
0x06 => Self::TTLExpired,
0x07 => Self::UnsupportedCommand,
0x08 => Self::UnsupportedAddressType,
val => Self::Unassigned(val),
}
}
}
impl Into<u8> for Socks5Reply {
fn into(self) -> u8 {
match self {
Self::Succeeded => 0x00,
Self::Failure => 0x01,
Self::NotAllowed => 0x02,
Self::NetworkUnreachable => 0x03,
Self::HostUnreachable => 0x04,
Self::ConnectionRefused => 0x05,
Self::TTLExpired => 0x06,
Self::UnsupportedCommand => 0x07,
Self::UnsupportedAddressType => 0x08,
Self::Unassigned(val) => val,
}
}
}
impl Socks5Reply {
pub(super) const VERSION: u8 = 0x05;
pub async fn reply<S>(
&self,
stream: &mut S,
bind_addr: SocketAddr,
) -> Result<(), io::Error>
where
S: AsyncReadExt + AsyncWriteExt + Unpin + Send,
{
let (address_type, ip, port) = match bind_addr {
SocketAddr::V4(addr) => (
Socks5AddrType::IPV4,
addr.ip().octets().to_vec(),
addr.port(),
),
SocketAddr::V6(addr) => (
Socks5AddrType::IPV6,
addr.ip().octets().to_vec(),
addr.port(),
),
};
let mut buf = vec![Self::VERSION, (*self).into(), 0x00, address_type.into()];
buf.extend(ip);
buf.extend(port.to_be_bytes());
stream.write_all(&buf).await?;
Ok(())
}
}