socksx 0.1.1

A SOCKS toolkit for Rust
Documentation
use crate::addresses::{self, Address};
use crate::constants::*;
use anyhow::Result;
use num_traits::FromPrimitive;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};

mod s5_client;
mod s5_handler;

pub use s5_client::Socks5Client;
pub use s5_handler::Socks5Handler;

#[repr(u8)]
#[derive(Clone, Debug, FromPrimitive, PartialEq)]
pub enum Socks5Command {
    Connect = 0x01,
    Bind = 0x02,
    UdpAssociate = 0x03,
}

#[derive(Clone, Debug)]
pub struct Socks5Request {
    pub command: Socks5Command,
    pub destination: Address,
}

impl Socks5Request {
    ///
    ///
    ///
    pub fn new(
        command: u8,
        destination: Address,
    ) -> Self {
        Socks5Request {
            command: Socks5Command::from_u8(command).unwrap(),
            destination,
        }
    }

    ///
    ///
    ///
    pub fn into_socks_bytes(self) -> Vec<u8> {
        let mut data = vec![SOCKS_VER_5, SOCKS_CMD_CONNECT, SOCKS_RSV];
        data.extend(self.destination.as_socks_bytes());

        data
    }
}

#[repr(u8)]
#[derive(Clone, Debug, FromPrimitive, PartialEq)]
pub enum Socks5Reply {
    Success = 0x00,
    GeneralFailure = 0x01,
    ConnectionNotAllowed = 0x02,
    NetworkUnreachable = 0x03,
    HostUnreachable = 0x04,
    ConnectionRefused = 0x05,
    TTLExpired = 0x06,
    CommandNotSupported = 0x07,
    AddressTypeNotSupported = 0x08,
    ConnectionAttemptTimeOut = 0x09,
}

///
///
///
pub async fn write_reply<S>(
    stream: &mut S,
    reply: Socks5Reply,
) -> Result<()>
where
    S: AsyncWrite + Unpin,
{
    let reply = [
        SOCKS_VER_5,
        reply as u8,
        SOCKS_RSV,
        SOCKS_ATYP_IPV4,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
    ];

    stream.write(&reply).await?;

    Ok(())
}

///
///
///
pub async fn read_reply<S>(stream: &mut S) -> Result<Address>
where
    S: AsyncRead + Unpin,
{
    let mut operation_reply = [0; 3];
    stream.read_exact(&mut operation_reply).await?;

    let reply_code = operation_reply[1];
    ensure!(
        reply_code == SOCKS_REP_SUCCEEDED,
        "CONNECT operation failed: {}",
        reply_code
    );

    let binding = addresses::read_address(stream).await?;

    Ok(binding)
}