async_proxy/clients/socks5/
no_auth.rs

1use crate::proxy::ProxyConstructor;
2use crate::clients::socks5;
3use crate::general::ConnectionTimeouts;
4use tokio::io::{AsyncReadExt, AsyncWriteExt};
5use tokio::io::{AsyncRead, AsyncWrite};
6use tokio::net::TcpStream;
7use tokio::time::timeout;
8use core::task::{Poll, Context};
9use byteorder::{ByteOrder, BigEndian};
10use std::str::FromStr;
11use std::pin::Pin;
12use std::fmt;
13use std::io;
14
15/// Represents the proxy constructor
16/// that builds a stream when the function
17/// `connect` is invoked
18pub struct TcpNoAuth {
19    /// Represents an address of 
20    /// a service to what user
21    /// wants to connect through a proxy
22    destination: socks5::Destination,
23    /// The port of the destination service
24    port: u16,
25    /// Timeouts for the connection
26    timeouts: ConnectionTimeouts
27}
28
29/// An error that can occur when connecting
30/// to a service through a socks5 proxy client
31pub enum ErrorKind {
32    /// Indicates that an operation
33    /// took too much time so that
34    /// timeouts has been reached
35    OperationTimeoutReached,
36    /// Indicates an I/O error
37    IOError(std::io::Error),
38    /// Indicates that a socks5-proxy
39    /// server has replied with a bad buffer
40    BadBuffer,
41    /// May occur only if a destination
42    /// is a domain name and indicates
43    /// that the domain name is too long.
44    /// The maximal length is 255
45    DomainNameTooLong,
46    /// Indicates that it is unable
47    /// to establish a connection
48    /// due to that fact that a socks5-proxy
49    /// server is currently unavailable
50    SocksServerFailure,
51    /// Indicates that the connection request
52    /// was denied due to the server rules
53    RequestDenied,
54    /// Indicates that it is unable to
55    /// establish a connection due to that fact
56    /// that the network is unreachable
57    NetworkUnreachable,
58    /// Indicates that a host is unreachable
59    /// so that it is unable to establish a connection
60    HostUnreachable,
61    /// Indicates that a connection is refused
62    /// so that it is unable to establish a connection
63    ConnectionRefused,
64    /// Indicates that it is unable to establish a connection
65    /// due to that fact that a TTL is expired
66    TTLExpired,
67    /// Indicates that the command sent on the server
68    /// is not currently supported, or the protocol
69    /// is broken on a server side
70    NotSupported,
71    /// Indicates that the type of a destination
72    /// address is not supported
73    DestinationNotSupported
74}
75
76/// Represents an error that
77/// can occur during `from_str`
78/// parsing
79#[derive(Debug)]
80pub enum StrParsingError {
81    /// Indicates that the string is not
82    /// formatted appropriately for parsing
83    /// process
84    SyntaxError,
85    /// Indicates that a destination
86    /// address cannot be parsed
87    InvalidDestination,
88    /// Indicates that a port (u16)
89    /// is invalid and it is unable to parse it
90    InvalidPort,
91    /// Indicates that timeouts
92    /// cannot be parsed
93    InvalidTimeouts
94}
95
96/// Represents the socks5-tcp 
97/// proxy client stream implementation
98pub struct TcpNoAuthStream {
99    /// The tcp stream on which
100    /// the client operates on
101    wrapped_stream: TcpStream
102}
103
104impl TcpNoAuth {
105    pub fn new(destination: socks5::Destination, port: u16, timeouts: ConnectionTimeouts)
106        -> TcpNoAuth
107    {
108        TcpNoAuth { destination, port, timeouts }
109    }
110}
111
112/// Impl for parsing a `Socks4General`
113/// from a string
114impl FromStr for TcpNoAuth {
115    type Err = StrParsingError;
116
117    /// Parses a `Socks4General` from a
118    /// string in format:
119    ///   (ipv4 or ipv6 or domain.com) port timeouts 
120    fn from_str(s: &str) -> Result<TcpNoAuth, Self::Err> {
121        // Splitting the string on spaces
122        let mut s = s.split(" ");
123
124        // Parsing an address and timeouts
125        let (destination, port, timeouts) = (s.next()
126                                                .ok_or(StrParsingError::SyntaxError)?
127                                                .parse::<socks5::Destination>()
128                                                .map_err(|_| StrParsingError::InvalidDestination)?,
129                                             s.next()
130                                                .ok_or(StrParsingError::SyntaxError)?
131                                                .parse::<u16>()
132                                                .map_err(|_| StrParsingError::InvalidPort)?,
133                                             s.next()
134                                                .ok_or(StrParsingError::SyntaxError)?
135                                                .parse::<ConnectionTimeouts>()
136                                                .map_err(|_| StrParsingError::InvalidTimeouts)?);
137
138        Ok(TcpNoAuth::new(destination, port, timeouts))
139    }
140}
141
142impl fmt::Display for ErrorKind {
143    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
144        match self {
145            ErrorKind::DomainNameTooLong => f.write_str("domain name is too long"),
146            ErrorKind::IOError(e) 
147                => f.write_str(&format!("I/O error: {}", e)),
148            ErrorKind::BadBuffer => f.write_str("bad buffer has been received"),
149            ErrorKind::RequestDenied => f.write_str("request denied"),
150            ErrorKind::SocksServerFailure => f.write_str("SOCKS5 server is unavailable"),
151            ErrorKind::NetworkUnreachable => f.write_str("network is unreachable"),
152            ErrorKind::HostUnreachable => f.write_str("destination host is unreachable"),
153            ErrorKind::ConnectionRefused => f.write_str("connection refused"),
154            ErrorKind::TTLExpired => f.write_str("TTL is expired"),
155            ErrorKind::NotSupported => f.write_str("operation is not supported by the SOCKS server"),
156            ErrorKind::DestinationNotSupported => f.write_str("the type of passed destination is not supported"),
157            ErrorKind::OperationTimeoutReached => f.write_str("operation timeout reached")
158        }
159    }
160}
161
162#[async_trait::async_trait]
163impl ProxyConstructor for TcpNoAuth {
164    type Stream = TcpStream;
165    type ProxyStream = TcpNoAuthStream;
166    type ErrorKind = ErrorKind;
167
168    async fn connect(&mut self, mut stream: Self::Stream)
169        -> Result<Self::ProxyStream, Self::ErrorKind>
170    {
171        // The length of the initial Socks5 request's buffer
172        const BUF_LEN: usize = 3;
173
174        // Creating the payload buffer
175        let mut buf = Vec::<u8>::with_capacity(BUF_LEN);
176
177        // The number of the Socks protocol version
178        // (0x05 or just 5 in this case)
179        buf.push(5);
180
181        // The number of supported authentication methods
182        // (1 in this case)
183        buf.push(1);
184
185        // The only one value of the supported
186        // authentication method.
187        // (0x00 or just 0 — No authentication)
188        buf.push(0);
189
190        // Writing the initial payload to the server
191        let future = stream.write_all(&buf);
192        let future = timeout(self.timeouts.write_timeout, future);
193        let _ = future.await.map_err(|_| ErrorKind::OperationTimeoutReached)?
194                            .map_err(|e| ErrorKind::IOError(e))?;
195
196        // Reading a reply from the server
197        let future = stream.read(&mut buf);
198        let future = timeout(self.timeouts.read_timeout, future);
199        let read_bytes = future.await.map_err(|_| ErrorKind::OperationTimeoutReached)?
200                                      .map_err(|e| ErrorKind::IOError(e))?;
201
202        // The server must send reply
203        // with the length of 2 bytes.
204        // Anything else is a sense of an error
205        if read_bytes != 2 {
206            return Err(ErrorKind::BadBuffer)
207        }
208
209        // The former read byte must be 0x05,
210        // while the latter must not be 0xFF
211        if buf[0] != 0x05 || buf[1] == 0xFF {
212            return Err(ErrorKind::BadBuffer)
213        }
214
215        // Computing the length of a Socks5 request
216        // The buffer length is computed this way:
217        //  (+1) for the number of the version of the socks protocol (4 in this case)
218        //  (+1) for the command number (1 or 2)
219        //  (+1) for the reserved byte, must be 0x00
220        //  (+1) for the destination address type,
221        //       must be 0x01, 0x03 or 0x04,
222        //       where 0x01 stands for an IPv4 address,
223        //       0x03 stands for a domain name and
224        //       0x04 stands for an IPv6 address
225        //  [+4]* if the type of the address is IPv4,
226        //  [+n]* if the type of the address is domain
227        //  [+16]* if the type of the address is IPv6 
228        //  (+2) for port (in the network byte order)
229        let dest_buf_len = self.destination.len_as_buffer();
230        let buf_len = 1 + 1 + 1 + dest_buf_len + 2;
231
232        // Reallocating the payload buffer
233        buf.resize(buf_len, 0);
234
235        // Setting the version of the socks protocol
236        // being used in the payload buffer
237        buf[0] = 5;
238
239        // Setting the tcp connection establishment command
240        buf[1] = socks5::Command::TcpConnectionEstablishment as u8;
241
242        // Setting a 0x00 byte as it is
243        // rule of the socks5 protocol
244        // buf[2] = 0;
245
246        // Filling the buffer with the destiation
247        self.destination.extend_buffer(&mut buf[3..]).unwrap();
248
249        // Writing port as a big endian short
250        BigEndian::write_u16(&mut buf[3 + dest_buf_len .. 3 + dest_buf_len + 2], self.port);
251
252        // println!("{:?}", buf);
253
254        // Sending our generated payload
255        // to the Socks5 server
256        let future = stream.write_all(&buf);
257        let future = timeout(self.timeouts.write_timeout, future);
258        let _ = future.await.map_err(|_| ErrorKind::OperationTimeoutReached)?
259                            .map_err(|e| ErrorKind::IOError(e))?;
260
261        // Reading a reply from the server
262        let future = stream.read(&mut buf);
263        let future = timeout(self.timeouts.read_timeout, future);
264        let read_bytes = future.await.map_err(|_| ErrorKind::OperationTimeoutReached)?
265                                     .map_err(|e| ErrorKind::IOError(e))?;
266
267        // We should receive exatly `buf_len` bytes from the server,
268        // unless there is something wrong with the
269        // received reply
270        if read_bytes < 2 {
271            return Err(ErrorKind::BadBuffer)
272        }
273
274        // Analyzing the received reply
275        // and returning a socks4 general proxy client
276        // instance if everything was successful
277        match buf[1] {
278            // Means that request accepted
279            0x00 => Ok(TcpNoAuthStream { wrapped_stream: stream }),
280            0x01 => Err(ErrorKind::SocksServerFailure),
281            0x02 => Err(ErrorKind::RequestDenied),
282            0x03 => Err(ErrorKind::NetworkUnreachable),
283            0x04 => Err(ErrorKind::HostUnreachable),
284            0x05 => Err(ErrorKind::ConnectionRefused),
285            0x06 => Err(ErrorKind::TTLExpired),
286            0x07 => Err(ErrorKind::NotSupported),
287            0x08 => Err(ErrorKind::DestinationNotSupported),
288            _ => Err(ErrorKind::BadBuffer)
289        }
290    }
291}
292
293impl AsyncRead for TcpNoAuthStream {
294    fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8])
295        -> Poll<io::Result<usize>>
296    {
297        let pinned = &mut Pin::into_inner(self).wrapped_stream;
298        Pin::new(pinned).poll_read(cx, buf)
299    }
300}
301
302impl AsyncWrite for TcpNoAuthStream {
303    fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8])
304        -> Poll<Result<usize, io::Error>>
305    { 
306        let stream = &mut Pin::into_inner(self).wrapped_stream;
307        Pin::new(stream).poll_write(cx, buf)
308    }
309
310    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>)
311        -> Poll<Result<(), io::Error>>
312    {
313        let stream = &mut Pin::into_inner(self).wrapped_stream;
314        Pin::new(stream).poll_flush(cx)
315    }
316
317    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>)
318        -> Poll<Result<(), io::Error>>
319    {
320        let stream = &mut Pin::into_inner(self).wrapped_stream;
321        Pin::new(stream).poll_shutdown(cx)
322    }
323}
324
325impl Into<TcpStream> for TcpNoAuthStream {
326    fn into(self) -> TcpStream {
327        self.wrapped_stream
328    }
329}