Skip to main content

io_proxy/socks/v5/
message.rs

1//! SOCKS5 reply codes ([RFC 1928 §6]).
2//!
3//! [RFC 1928 §6]: https://www.rfc-editor.org/rfc/rfc1928#section-6
4
5use core::fmt;
6
7/// Reply code carried in the `REP` field of a SOCKS5 reply.
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum Socks5Reply {
10    /// `0x00` succeeded.
11    Succeeded,
12    /// `0x01` general SOCKS server failure.
13    GeneralFailure,
14    /// `0x02` connection not allowed by ruleset.
15    ConnectionNotAllowed,
16    /// `0x03` network unreachable.
17    NetworkUnreachable,
18    /// `0x04` host unreachable.
19    HostUnreachable,
20    /// `0x05` connection refused.
21    ConnectionRefused,
22    /// `0x06` TTL expired.
23    TtlExpired,
24    /// `0x07` command not supported.
25    CommandNotSupported,
26    /// `0x08` address type not supported.
27    AddressTypeNotSupported,
28}
29
30impl Socks5Reply {
31    /// Maps a raw `REP` byte to its [`Socks5Reply`], or [`None`] for a
32    /// code outside the RFC 1928 range.
33    pub fn from_u8(byte: u8) -> Option<Socks5Reply> {
34        let reply = match byte {
35            0x00 => Socks5Reply::Succeeded,
36            0x01 => Socks5Reply::GeneralFailure,
37            0x02 => Socks5Reply::ConnectionNotAllowed,
38            0x03 => Socks5Reply::NetworkUnreachable,
39            0x04 => Socks5Reply::HostUnreachable,
40            0x05 => Socks5Reply::ConnectionRefused,
41            0x06 => Socks5Reply::TtlExpired,
42            0x07 => Socks5Reply::CommandNotSupported,
43            0x08 => Socks5Reply::AddressTypeNotSupported,
44            _ => return None,
45        };
46        Some(reply)
47    }
48}
49
50impl fmt::Display for Socks5Reply {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        let msg = match self {
53            Socks5Reply::Succeeded => "succeeded",
54            Socks5Reply::GeneralFailure => "general SOCKS server failure",
55            Socks5Reply::ConnectionNotAllowed => "connection not allowed by ruleset",
56            Socks5Reply::NetworkUnreachable => "network unreachable",
57            Socks5Reply::HostUnreachable => "host unreachable",
58            Socks5Reply::ConnectionRefused => "connection refused",
59            Socks5Reply::TtlExpired => "TTL expired",
60            Socks5Reply::CommandNotSupported => "command not supported",
61            Socks5Reply::AddressTypeNotSupported => "address type not supported",
62        };
63        f.write_str(msg)
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn from_u8_covers_rfc_range() {
73        assert_eq!(Socks5Reply::from_u8(0x00), Some(Socks5Reply::Succeeded));
74        assert_eq!(
75            Socks5Reply::from_u8(0x08),
76            Some(Socks5Reply::AddressTypeNotSupported)
77        );
78        assert_eq!(Socks5Reply::from_u8(0x09), None);
79        assert_eq!(Socks5Reply::from_u8(0xFF), None);
80    }
81}