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

1use super::super::{ParsingError, SerializeError};
2
3use bytes::{Buf, BufMut, BytesMut};
4use std::net::SocketAddr;
5
6///  +----+----------+----------+
7/// |VER | NMETHODS | METHODS  |
8/// +----+----------+----------+
9/// | 1  |    1     | 1 to 255 |
10/// +----+----------+----------+
11#[derive(Debug)]
12pub struct NegotiationReq<'a>(pub &'a AuthMethod);
13
14/// +----+--------+
15/// |VER | METHOD |
16/// +----+--------+
17/// | 1  |   1    |
18/// +----+--------+
19#[derive(Debug)]
20pub struct NegotiationRes(pub AuthMethod);
21
22/// +----+------+----------+------+----------+
23/// |VER | ULEN |  UNAME   | PLEN |  PASSWD  |
24/// +----+------+----------+------+----------+
25/// | 1  |  1   | 1 to 255 |  1   | 1 to 255 |
26/// +----+------+----------+------+----------+
27#[derive(Debug)]
28pub struct AuthenticationReq<'a>(pub &'a str, pub &'a str);
29
30/// +----+--------+
31/// |VER | STATUS |
32/// +----+--------+
33/// | 1  |   1    |
34/// +----+--------+
35#[derive(Debug)]
36pub struct AuthenticationRes(pub bool);
37
38/// +----+-----+-------+------+----------+----------+
39/// |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
40/// +----+-----+-------+------+----------+----------+
41/// | 1  |  1  | X'00' |  1   | Variable |    2     |
42/// +----+-----+-------+------+----------+----------+
43#[derive(Debug)]
44pub struct ProxyReq<'a>(pub &'a Address);
45
46/// +----+-----+-------+------+----------+----------+
47/// |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
48/// +----+-----+-------+------+----------+----------+
49/// | 1  |  1  | X'00' |  1   | Variable |    2     |
50/// +----+-----+-------+------+----------+----------+
51#[derive(Debug)]
52pub struct ProxyRes(pub Status);
53
54#[repr(u8)]
55#[derive(Debug, Copy, Clone, PartialEq)]
56pub enum AuthMethod {
57    NoAuth = 0x00,
58    UserPass = 0x02,
59    NoneAcceptable = 0xFF,
60}
61
62#[derive(Debug)]
63pub enum Address {
64    Socket(SocketAddr),
65    Domain(String, u16),
66}
67
68#[derive(Debug, Copy, Clone, PartialEq)]
69pub enum Status {
70    Success,
71    GeneralServerFailure,
72    ConnectionNotAllowed,
73    NetworkUnreachable,
74    HostUnreachable,
75    ConnectionRefused,
76    TtlExpired,
77    CommandNotSupported,
78    AddressTypeNotSupported,
79}
80
81impl NegotiationReq<'_> {
82    pub fn write_to_buf(&self, buf: &mut BytesMut) -> Result<usize, SerializeError> {
83        if buf.capacity() - buf.len() < 3 {
84            return Err(SerializeError::WouldOverflow);
85        }
86
87        buf.put_u8(0x05); // Version
88        buf.put_u8(0x01); // Number of authentication methods
89        buf.put_u8(*self.0 as u8); // Authentication method
90
91        Ok(3)
92    }
93}
94
95impl TryFrom<&mut BytesMut> for NegotiationRes {
96    type Error = ParsingError;
97
98    fn try_from(buf: &mut BytesMut) -> Result<Self, ParsingError> {
99        if buf.remaining() < 2 {
100            return Err(ParsingError::Incomplete);
101        }
102
103        if buf.get_u8() != 0x05 {
104            return Err(ParsingError::Other);
105        }
106
107        let method = buf.get_u8().try_into()?;
108        Ok(Self(method))
109    }
110}
111
112impl AuthenticationReq<'_> {
113    pub fn write_to_buf(&self, buf: &mut BytesMut) -> Result<usize, SerializeError> {
114        if buf.capacity() - buf.len() < 3 + self.0.len() + self.1.len() {
115            return Err(SerializeError::WouldOverflow);
116        }
117
118        buf.put_u8(0x01); // Version
119
120        buf.put_u8(self.0.len() as u8); // Username length (guarenteed to be 255 or less)
121        buf.put_slice(self.0.as_bytes()); // Username
122
123        buf.put_u8(self.1.len() as u8); // Password length (guarenteed to be 255 or less)
124        buf.put_slice(self.1.as_bytes()); // Password
125
126        Ok(3 + self.0.len() + self.1.len())
127    }
128}
129
130impl TryFrom<&mut BytesMut> for AuthenticationRes {
131    type Error = ParsingError;
132
133    fn try_from(buf: &mut BytesMut) -> Result<Self, ParsingError> {
134        if buf.remaining() < 2 {
135            return Err(ParsingError::Incomplete);
136        }
137
138        if buf.get_u8() != 0x01 {
139            return Err(ParsingError::Other);
140        }
141
142        if buf.get_u8() == 0 {
143            Ok(Self(true))
144        } else {
145            Ok(Self(false))
146        }
147    }
148}
149
150impl ProxyReq<'_> {
151    pub fn write_to_buf(&self, buf: &mut BytesMut) -> Result<usize, SerializeError> {
152        let addr_len = match self.0 {
153            Address::Socket(SocketAddr::V4(_)) => 1 + 4 + 2,
154            Address::Socket(SocketAddr::V6(_)) => 1 + 16 + 2,
155            Address::Domain(ref domain, _) => 1 + 1 + domain.len() + 2,
156        };
157
158        if buf.capacity() - buf.len() < 3 + addr_len {
159            return Err(SerializeError::WouldOverflow);
160        }
161
162        buf.put_u8(0x05); // Version
163        buf.put_u8(0x01); // TCP tunneling command
164        buf.put_u8(0x00); // Reserved
165        let _ = self.0.write_to_buf(buf); // Address
166
167        Ok(3 + addr_len)
168    }
169}
170
171impl TryFrom<&mut BytesMut> for ProxyRes {
172    type Error = ParsingError;
173
174    fn try_from(buf: &mut BytesMut) -> Result<Self, ParsingError> {
175        if buf.remaining() < 2 {
176            return Err(ParsingError::Incomplete);
177        }
178
179        // VER
180        if buf.get_u8() != 0x05 {
181            return Err(ParsingError::Other);
182        }
183
184        // REP
185        let status = buf.get_u8().try_into()?;
186
187        // RSV
188        if buf.get_u8() != 0x00 {
189            return Err(ParsingError::Other);
190        }
191
192        // ATYP + ADDR
193        Address::try_from(buf)?;
194
195        Ok(Self(status))
196    }
197}
198
199impl Address {
200    pub fn write_to_buf(&self, buf: &mut BytesMut) -> Result<usize, SerializeError> {
201        match self {
202            Self::Socket(SocketAddr::V4(v4)) => {
203                if buf.capacity() - buf.len() < 1 + 4 + 2 {
204                    return Err(SerializeError::WouldOverflow);
205                }
206
207                buf.put_u8(0x01);
208                buf.put_slice(&v4.ip().octets());
209                buf.put_u16(v4.port()); // Network Order/BigEndian for port
210
211                Ok(7)
212            }
213
214            Self::Socket(SocketAddr::V6(v6)) => {
215                if buf.capacity() - buf.len() < 1 + 16 + 2 {
216                    return Err(SerializeError::WouldOverflow);
217                }
218
219                buf.put_u8(0x04);
220                buf.put_slice(&v6.ip().octets());
221                buf.put_u16(v6.port()); // Network Order/BigEndian for port
222
223                Ok(19)
224            }
225
226            Self::Domain(domain, port) => {
227                if buf.capacity() - buf.len() < 1 + 1 + domain.len() + 2 {
228                    return Err(SerializeError::WouldOverflow);
229                }
230
231                buf.put_u8(0x03);
232                buf.put_u8(domain.len() as u8); // Guarenteed to be less than 255
233                buf.put_slice(domain.as_bytes());
234                buf.put_u16(*port);
235
236                Ok(4 + domain.len())
237            }
238        }
239    }
240}
241
242impl TryFrom<&mut BytesMut> for Address {
243    type Error = ParsingError;
244
245    fn try_from(buf: &mut BytesMut) -> Result<Self, Self::Error> {
246        if buf.remaining() < 2 {
247            return Err(ParsingError::Incomplete);
248        }
249
250        Ok(match buf.get_u8() {
251            0x01 => {
252                let mut ip = [0; 4];
253
254                if buf.remaining() < 6 {
255                    return Err(ParsingError::Incomplete);
256                }
257
258                buf.copy_to_slice(&mut ip);
259                let port = buf.get_u16();
260
261                Self::Socket(SocketAddr::new(ip.into(), port))
262            }
263
264            0x03 => {
265                let len = buf.get_u8();
266
267                if len == 0 {
268                    return Err(ParsingError::Other);
269                } else if buf.remaining() < (len as usize) + 2 {
270                    return Err(ParsingError::Incomplete);
271                }
272
273                let domain = std::str::from_utf8(&buf[..len as usize])
274                    .map_err(|_| ParsingError::Other)?
275                    .to_string();
276
277                let port = buf.get_u16();
278
279                Self::Domain(domain, port)
280            }
281
282            0x04 => {
283                let mut ip = [0; 16];
284
285                if buf.remaining() < 6 {
286                    return Err(ParsingError::Incomplete);
287                }
288                buf.copy_to_slice(&mut ip);
289                let port = buf.get_u16();
290
291                Self::Socket(SocketAddr::new(ip.into(), port))
292            }
293
294            _ => return Err(ParsingError::Other),
295        })
296    }
297}
298
299impl TryFrom<u8> for Status {
300    type Error = ParsingError;
301
302    fn try_from(byte: u8) -> Result<Self, Self::Error> {
303        Ok(match byte {
304            0x00 => Self::Success,
305
306            0x01 => Self::GeneralServerFailure,
307            0x02 => Self::ConnectionNotAllowed,
308            0x03 => Self::NetworkUnreachable,
309            0x04 => Self::HostUnreachable,
310            0x05 => Self::ConnectionRefused,
311            0x06 => Self::TtlExpired,
312            0x07 => Self::CommandNotSupported,
313            0x08 => Self::AddressTypeNotSupported,
314            _ => return Err(ParsingError::Other),
315        })
316    }
317}
318
319impl TryFrom<u8> for AuthMethod {
320    type Error = ParsingError;
321
322    fn try_from(byte: u8) -> Result<Self, Self::Error> {
323        Ok(match byte {
324            0x00 => Self::NoAuth,
325            0x02 => Self::UserPass,
326            0xFF => Self::NoneAcceptable,
327
328            _ => return Err(ParsingError::Other),
329        })
330    }
331}
332
333impl std::fmt::Display for Status {
334    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
335        f.write_str(match self {
336            Self::Success => "success",
337            Self::GeneralServerFailure => "general server failure",
338            Self::ConnectionNotAllowed => "connection not allowed",
339            Self::NetworkUnreachable => "network unreachable",
340            Self::HostUnreachable => "host unreachable",
341            Self::ConnectionRefused => "connection refused",
342            Self::TtlExpired => "ttl expired",
343            Self::CommandNotSupported => "command not supported",
344            Self::AddressTypeNotSupported => "address type not supported",
345        })
346    }
347}