hyper_util/client/legacy/connect/proxy/socks/v4/
messages.rs

1use super::super::{ParsingError, SerializeError};
2
3use bytes::{Buf, BufMut, BytesMut};
4use std::net::SocketAddrV4;
5
6/// +-----+-----+----+----+----+----+----+----+-------------+------+------------+------+
7/// |  VN |  CD | DSTPORT |        DSTIP      |    USERID   | NULL |   DOMAIN   | NULL |
8/// +-----+-----+----+----+----+----+----+----+-------------+------+------------+------+
9/// |  1  |  1  |    2    |         4         |   Variable  |  1   |  Variable  |   1  |
10/// +-----+-----+----+----+----+----+----+----+-------------+------+------------+------+
11///                                                                ^^^^^^^^^^^^^^^^^^^^^
12///                                                      optional: only do IP is 0.0.0.X
13#[derive(Debug)]
14pub struct Request<'a>(pub &'a Address);
15
16/// +-----+-----+----+----+----+----+----+----+
17/// |  VN |  CD | DSTPORT |       DSTIP       |
18/// +-----+-----+----+----+----+----+----+----+
19/// |  1  |  1  |    2    |         4         |
20/// +-----+-----+----+----+----+----+----+----+
21///             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
22///              ignore: only for SOCKSv4 BIND
23#[derive(Debug)]
24pub struct Response(pub Status);
25
26#[derive(Debug)]
27pub enum Address {
28    Socket(SocketAddrV4),
29    Domain(String, u16),
30}
31
32#[derive(Debug, PartialEq)]
33pub enum Status {
34    Success = 90,
35    Failed = 91,
36    IdentFailure = 92,
37    IdentMismatch = 93,
38}
39
40impl Request<'_> {
41    pub fn write_to_buf<B: BufMut>(&self, mut buf: B) -> Result<usize, SerializeError> {
42        match self.0 {
43            Address::Socket(socket) => {
44                if buf.remaining_mut() < 10 {
45                    return Err(SerializeError::WouldOverflow);
46                }
47
48                buf.put_u8(0x04); // Version
49                buf.put_u8(0x01); // CONNECT
50
51                buf.put_u16(socket.port()); // Port
52                buf.put_slice(&socket.ip().octets()); // IP
53
54                buf.put_u8(0x00); // USERID
55                buf.put_u8(0x00); // NULL
56
57                Ok(10)
58            }
59
60            Address::Domain(domain, port) => {
61                if buf.remaining_mut() < 10 + domain.len() + 1 {
62                    return Err(SerializeError::WouldOverflow);
63                }
64
65                buf.put_u8(0x04); // Version
66                buf.put_u8(0x01); // CONNECT
67
68                buf.put_u16(*port); // IP
69                buf.put_slice(&[0x00, 0x00, 0x00, 0xFF]); // Invalid IP
70
71                buf.put_u8(0x00); // USERID
72                buf.put_u8(0x00); // NULL
73
74                buf.put_slice(domain.as_bytes()); // Domain
75                buf.put_u8(0x00); // NULL
76
77                Ok(10 + domain.len() + 1)
78            }
79        }
80    }
81}
82
83impl TryFrom<&mut BytesMut> for Response {
84    type Error = ParsingError;
85
86    fn try_from(buf: &mut BytesMut) -> Result<Self, Self::Error> {
87        if buf.remaining() < 8 {
88            return Err(ParsingError::Incomplete);
89        }
90
91        if buf.get_u8() != 0x00 {
92            return Err(ParsingError::Other);
93        }
94
95        let status = buf.get_u8().try_into()?;
96        let _addr = {
97            let port = buf.get_u16();
98            let mut ip = [0; 4];
99            buf.copy_to_slice(&mut ip);
100
101            SocketAddrV4::new(ip.into(), port)
102        };
103
104        return Ok(Self(status));
105    }
106}
107
108impl TryFrom<u8> for Status {
109    type Error = ParsingError;
110
111    fn try_from(byte: u8) -> Result<Self, Self::Error> {
112        Ok(match byte {
113            90 => Self::Success,
114            91 => Self::Failed,
115            92 => Self::IdentFailure,
116            93 => Self::IdentMismatch,
117            _ => return Err(ParsingError::Other),
118        })
119    }
120}
121
122impl std::fmt::Display for Status {
123    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124        f.write_str(match self {
125            Self::Success => "success",
126            Self::Failed => "server failed to execute command",
127            Self::IdentFailure => "server ident service failed",
128            Self::IdentMismatch => "server ident service did not recognise client identifier",
129        })
130    }
131}