socks_lib/v5/
response.rs

1use bytes::{BufMut, BytesMut};
2
3use crate::v5::Address;
4
5/// # Response
6///
7/// ```text
8///  +-----+-------+------+----------+----------+
9///  | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
10///  +-----+-------+------+----------+----------+
11///  |  1  | X'00' |  1   | Variable |    2     |
12///  +-----+-------+------+----------+----------+
13/// ```
14///
15#[derive(Debug, Clone)]
16pub enum Response<'a> {
17    Success(&'a Address),
18    GeneralFailure,
19    ConnectionNotAllowed,
20    NetworkUnreachable,
21    HostUnreachable,
22    ConnectionRefused,
23    TTLExpired,
24    CommandNotSupported,
25    AddressTypeNotSupported,
26    Unassigned(u8),
27}
28
29#[rustfmt::skip]
30impl Response<'_> {
31    const SOCKS5_REPLY_SUCCEEDED:                  u8 = 0x00;
32    const SOCKS5_REPLY_GENERAL_FAILURE:            u8 = 0x01;
33    const SOCKS5_REPLY_CONNECTION_NOT_ALLOWED:     u8 = 0x02;
34    const SOCKS5_REPLY_NETWORK_UNREACHABLE:        u8 = 0x03;
35    const SOCKS5_REPLY_HOST_UNREACHABLE:           u8 = 0x04;
36    const SOCKS5_REPLY_CONNECTION_REFUSED:         u8 = 0x05;
37    const SOCKS5_REPLY_TTL_EXPIRED:                u8 = 0x06;
38    const SOCKS5_REPLY_COMMAND_NOT_SUPPORTED:      u8 = 0x07;
39    const SOCKS5_REPLY_ADDRESS_TYPE_NOT_SUPPORTED: u8 = 0x08;
40}
41
42impl Response<'_> {
43    #[inline]
44    pub fn to_bytes(&self) -> BytesMut {
45        let mut bytes = BytesMut::new();
46
47        let (reply, address) = match &self {
48            Self::GeneralFailure
49            | Self::ConnectionNotAllowed
50            | Self::NetworkUnreachable
51            | Self::HostUnreachable
52            | Self::ConnectionRefused
53            | Self::TTLExpired
54            | Self::CommandNotSupported
55            | Self::AddressTypeNotSupported => (self.as_u8(), Address::unspecified()),
56            Self::Unassigned(code) => (*code, Address::unspecified()),
57            Self::Success(address) => (self.as_u8(), *address),
58        };
59
60        bytes.put_u8(reply);
61        bytes.put_u8(0x00);
62        bytes.extend(address.to_bytes());
63
64        bytes
65    }
66
67    #[rustfmt::skip]
68    #[inline]
69    fn as_u8(&self) -> u8 {
70        match self {
71            Self::Success(_)                 => Self::SOCKS5_REPLY_SUCCEEDED,
72            Self::GeneralFailure             => Self::SOCKS5_REPLY_GENERAL_FAILURE,
73            Self::ConnectionNotAllowed       => Self::SOCKS5_REPLY_CONNECTION_NOT_ALLOWED,
74            Self::NetworkUnreachable         => Self::SOCKS5_REPLY_NETWORK_UNREACHABLE,
75            Self::HostUnreachable            => Self::SOCKS5_REPLY_HOST_UNREACHABLE,
76            Self::ConnectionRefused          => Self::SOCKS5_REPLY_CONNECTION_REFUSED,
77            Self::TTLExpired                 => Self::SOCKS5_REPLY_TTL_EXPIRED,
78            Self::CommandNotSupported        => Self::SOCKS5_REPLY_COMMAND_NOT_SUPPORTED,
79            Self::AddressTypeNotSupported    => Self::SOCKS5_REPLY_ADDRESS_TYPE_NOT_SUPPORTED,
80            Self::Unassigned(code)           => *code
81        }
82    }
83}