ppaass-agent 0.1.35

The agent part of the ppaass application
Documentation
use bytes::{Buf, BufMut, Bytes, BytesMut};

use crate::error::AgentServerError;
use tokio_util::codec::{Decoder, Encoder};
use tracing::error;

use crate::SOCKS_V5;

use super::message::{
    Socks5Address, Socks5AuthCommand, Socks5AuthCommandResult, Socks5AuthMethod, Socks5InitCommand,
    Socks5InitCommandResult, Socks5InitCommandType,
};

#[derive(Debug, Default)]
pub(crate) struct Socks5AuthCommandContentCodec;

impl Decoder for Socks5AuthCommandContentCodec {
    type Item = Socks5AuthCommand;
    type Error = AgentServerError;

    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        if src.len() < 2 {
            return Ok(None);
        }
        let version = src.get_u8();
        if version != SOCKS_V5 {
            error!("The incoming protocol is not for socks 5: {version}.");
            return Err(AgentServerError::Other(format!(
                "The incoming protocol is not for socks 5: {version}."
            )));
        }
        let methods_number = src.get_u8();
        let mut methods = Vec::<Socks5AuthMethod>::new();
        (0..methods_number).for_each(|_| {
            methods.push(Socks5AuthMethod::from(src.get_u8()));
        });
        Ok(Some(Socks5AuthCommand::new(methods)))
    }
}

impl Encoder<Socks5AuthCommandResult> for Socks5AuthCommandContentCodec {
    type Error = AgentServerError;

    fn encode(
        &mut self,
        item: Socks5AuthCommandResult,
        dst: &mut BytesMut,
    ) -> Result<(), Self::Error> {
        dst.put_u8(SOCKS_V5);
        dst.put_u8(item.method.into());
        Ok(())
    }
}

#[derive(Debug, Default)]
pub(crate) struct Socks5InitCommandContentCodec;

impl Decoder for Socks5InitCommandContentCodec {
    type Item = Socks5InitCommand;
    type Error = AgentServerError;

    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        if src.len() < 4 {
            return Ok(None);
        }
        let version = src.get_u8();
        if version != SOCKS_V5 {
            error!("The incoming protocol is not for socks 5: {version}.");
            return Err(AgentServerError::Other(format!(
                "The incoming protocol is not for socks 5: {version}."
            )));
        }
        let request_type: Socks5InitCommandType = src.get_u8().try_into()?;
        src.get_u8();
        let dst_address = Socks5Address::parse(src)?;
        Ok(Some(Socks5InitCommand::new(request_type, dst_address)))
    }
}

impl Encoder<Socks5InitCommandResult> for Socks5InitCommandContentCodec {
    type Error = AgentServerError;

    fn encode(
        &mut self,
        item: Socks5InitCommandResult,
        dst: &mut BytesMut,
    ) -> Result<(), Self::Error> {
        dst.put_u8(5);
        dst.put_u8(item.status.into());
        dst.put_u8(0);
        if let Some(bind_address) = item.bind_address {
            dst.put::<Bytes>(bind_address.into());
        }
        Ok(())
    }
}