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}