socks5_impl/server/connection/mod.rs
1use self::{associate::UdpAssociate, bind::Bind, connect::Connect};
2use crate::{
3 protocol::{self, Address, AsyncStreamOperation, AuthMethod, Command, handshake},
4 server::AuthAdaptor,
5};
6use std::{net::SocketAddr, time::Duration};
7use tokio::{io::AsyncWriteExt, net::TcpStream};
8
9pub mod associate;
10pub mod bind;
11pub mod connect;
12
13/// An incoming connection. This may not be a valid socks5 connection. You need to call [`authenticate()`](#method.authenticate)
14/// to perform the socks5 handshake. It will be converted to a proper socks5 connection after the handshake succeeds.
15pub struct IncomingConnection<O> {
16 stream: TcpStream,
17 auth: AuthAdaptor<O>,
18}
19
20impl<O: 'static> IncomingConnection<O> {
21 #[inline]
22 pub(crate) fn new(stream: TcpStream, auth: AuthAdaptor<O>) -> Self {
23 IncomingConnection { stream, auth }
24 }
25
26 /// Returns the local address that this stream is bound to.
27 #[inline]
28 pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
29 self.stream.local_addr()
30 }
31
32 /// Returns the remote address that this stream is connected to.
33 #[inline]
34 pub fn peer_addr(&self) -> std::io::Result<SocketAddr> {
35 self.stream.peer_addr()
36 }
37
38 /// Shutdown the TCP stream.
39 #[inline]
40 pub async fn shutdown(&mut self) -> std::io::Result<()> {
41 self.stream.shutdown().await
42 }
43
44 /// Reads the linger duration for this socket by getting the `SO_LINGER` option.
45 ///
46 /// For more information about this option, see [`set_linger`](crate::server::connection::IncomingConnection::set_linger).
47 #[inline]
48 pub fn linger(&self) -> std::io::Result<Option<Duration>> {
49 self.stream.linger()
50 }
51
52 /// Sets the linger duration of this socket by setting the `SO_LINGER` option.
53 ///
54 /// This option controls the action taken when a stream has unsent messages and the stream is closed.
55 /// If `SO_LINGER` is set, the system shall block the process until it can transmit the data or until the time expires.
56 ///
57 /// If `SO_LINGER` is not specified, and the stream is closed, the system handles the call in a way
58 /// that allows the process to continue as quickly as possible.
59 #[inline]
60 pub fn set_linger(&self, dur: Option<Duration>) -> std::io::Result<()> {
61 self.stream.set_linger(dur)
62 }
63
64 /// Gets the value of the `TCP_NODELAY` option on this socket.
65 ///
66 /// For more information about this option, see
67 /// [`set_nodelay`](#method.set_nodelay).
68 #[inline]
69 pub fn nodelay(&self) -> std::io::Result<bool> {
70 self.stream.nodelay()
71 }
72
73 /// Sets the value of the `TCP_NODELAY` option on this socket.
74 ///
75 /// If set, this option disables the Nagle algorithm. This means that segments are always sent as soon as possible,
76 /// even if there is only a small amount of data. When not set, data is buffered until there is a sufficient amount
77 /// to send out, thereby avoiding the frequent sending of small packets.
78 pub fn set_nodelay(&self, nodelay: bool) -> std::io::Result<()> {
79 self.stream.set_nodelay(nodelay)
80 }
81
82 /// Gets the value of the `IP_TTL` option for this socket.
83 ///
84 /// For more information about this option, see
85 /// [`set_ttl`](#method.set_ttl).
86 pub fn ttl(&self) -> std::io::Result<u32> {
87 self.stream.ttl()
88 }
89
90 /// Sets the value for the `IP_TTL` option on this socket.
91 ///
92 /// This value sets the time-to-live field that is used in every packet sent from this socket.
93 pub fn set_ttl(&self, ttl: u32) -> std::io::Result<()> {
94 self.stream.set_ttl(ttl)
95 }
96
97 /// Perform a SOCKS5 authentication handshake using the given
98 /// [`AuthExecutor`](crate::server::auth::AuthExecutor) adapter.
99 ///
100 /// If the handshake succeeds, an [`Authenticated`]
101 /// alongs with the output of the [`AuthExecutor`](crate::server::auth::AuthExecutor) adapter is returned.
102 /// Otherwise, the error and the original [`TcpStream`](https://docs.rs/tokio/latest/tokio/net/struct.TcpStream.html) is returned.
103 ///
104 /// Note that this method will not implicitly close the connection even if the handshake failed.
105 pub async fn authenticate(mut self) -> std::io::Result<(Authenticated, O)> {
106 let request = handshake::Request::retrieve_from_async_stream(&mut self.stream).await?;
107 if let Some(method) = self.evaluate_request(&request) {
108 let response = handshake::Response::new(method);
109 response.write_to_async_stream(&mut self.stream).await?;
110 let output = self.auth.execute(&mut self.stream).await;
111 Ok((Authenticated::new(self.stream), output))
112 } else {
113 let response = handshake::Response::new(AuthMethod::NoAcceptableMethods);
114 response.write_to_async_stream(&mut self.stream).await?;
115 let err = "No available handshake method provided by client";
116 Err(std::io::Error::new(std::io::ErrorKind::Unsupported, err))
117 }
118 }
119
120 fn evaluate_request(&self, req: &handshake::Request) -> Option<AuthMethod> {
121 let method = self.auth.auth_method();
122 if req.evaluate_method(method) { Some(method) } else { None }
123 }
124}
125
126impl<O> std::fmt::Debug for IncomingConnection<O> {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 f.debug_struct("IncomingConnection").field("stream", &self.stream).finish()
129 }
130}
131
132impl<O> From<IncomingConnection<O>> for TcpStream {
133 #[inline]
134 fn from(conn: IncomingConnection<O>) -> Self {
135 conn.stream
136 }
137}
138
139/// A TCP stream that has been authenticated.
140///
141/// To get the command from the SOCKS5 client, use
142/// [`wait_request`](crate::server::connection::Authenticated::wait_request).
143///
144/// It can also be converted back into a raw [`tokio::TcpStream`](https://docs.rs/tokio/latest/tokio/net/struct.TcpStream.html) with `From` trait.
145pub struct Authenticated(TcpStream);
146
147impl Authenticated {
148 #[inline]
149 fn new(stream: TcpStream) -> Self {
150 Self(stream)
151 }
152
153 /// Waits the SOCKS5 client to send a request.
154 ///
155 /// This method will return a [`Command`] if the client sends a valid command.
156 ///
157 /// When encountering an error, the stream will be returned alongside the error.
158 ///
159 /// Note that this method will not implicitly close the connection even if the client sends an invalid request.
160 pub async fn wait_request(mut self) -> crate::Result<ClientConnection> {
161 let req = protocol::Request::retrieve_from_async_stream(&mut self.0).await?;
162
163 match req.command {
164 Command::UdpAssociate => Ok(ClientConnection::UdpAssociate(
165 UdpAssociate::<associate::NeedReply>::new(self.0),
166 req.address,
167 )),
168 Command::Bind => Ok(ClientConnection::Bind(Bind::<bind::NeedFirstReply>::new(self.0), req.address)),
169 Command::Connect => Ok(ClientConnection::Connect(Connect::<connect::NeedReply>::new(self.0), req.address)),
170 }
171 }
172
173 /// Causes the other peer to receive a read of length 0, indicating that no more data will be sent. This only closes the stream in one direction.
174 #[inline]
175 pub async fn shutdown(&mut self) -> std::io::Result<()> {
176 self.0.shutdown().await
177 }
178
179 /// Returns the local address that this stream is bound to.
180 #[inline]
181 pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
182 self.0.local_addr()
183 }
184
185 /// Returns the remote address that this stream is connected to.
186 #[inline]
187 pub fn peer_addr(&self) -> std::io::Result<SocketAddr> {
188 self.0.peer_addr()
189 }
190
191 /// Reads the linger duration for this socket by getting the `SO_LINGER` option.
192 ///
193 /// For more information about this option, see
194 /// [`set_linger`](crate::server::connection::Authenticated::set_linger).
195 #[inline]
196 pub fn linger(&self) -> std::io::Result<Option<Duration>> {
197 self.0.linger()
198 }
199
200 /// Sets the linger duration of this socket by setting the `SO_LINGER` option.
201 ///
202 /// This option controls the action taken when a stream has unsent messages and the stream is closed.
203 /// If `SO_LINGER` is set, the system shall block the process until it can transmit the data or until the time expires.
204 ///
205 /// If `SO_LINGER` is not specified, and the stream is closed, the system handles the call in a way
206 /// that allows the process to continue as quickly as possible.
207 #[inline]
208 pub fn set_linger(&self, dur: Option<Duration>) -> std::io::Result<()> {
209 self.0.set_linger(dur)
210 }
211
212 /// Gets the value of the `TCP_NODELAY` option on this socket.
213 ///
214 /// For more information about this option, see
215 /// [`set_nodelay`](crate::server::connection::Authenticated::set_nodelay).
216 #[inline]
217 pub fn nodelay(&self) -> std::io::Result<bool> {
218 self.0.nodelay()
219 }
220
221 /// Sets the value of the `TCP_NODELAY` option on this socket.
222 ///
223 /// If set, this option disables the Nagle algorithm. This means that segments are always sent as soon as possible,
224 /// even if there is only a small amount of data. When not set, data is buffered until there is a sufficient amount to send out,
225 /// thereby avoiding the frequent sending of small packets.
226 pub fn set_nodelay(&self, nodelay: bool) -> std::io::Result<()> {
227 self.0.set_nodelay(nodelay)
228 }
229
230 /// Gets the value of the `IP_TTL` option for this socket.
231 ///
232 /// For more information about this option, see
233 /// [`set_ttl`](crate::server::connection::Authenticated::set_ttl).
234 pub fn ttl(&self) -> std::io::Result<u32> {
235 self.0.ttl()
236 }
237
238 /// Sets the value for the `IP_TTL` option on this socket.
239 ///
240 /// This value sets the time-to-live field that is used in every packet sent from this socket.
241 pub fn set_ttl(&self, ttl: u32) -> std::io::Result<()> {
242 self.0.set_ttl(ttl)
243 }
244}
245
246impl From<Authenticated> for TcpStream {
247 #[inline]
248 fn from(conn: Authenticated) -> Self {
249 conn.0
250 }
251}
252
253/// After the socks5 handshake succeeds, the connection may become:
254///
255/// - Associate
256/// - Bind
257/// - Connect
258#[derive(Debug)]
259pub enum ClientConnection {
260 UdpAssociate(UdpAssociate<associate::NeedReply>, Address),
261 Bind(Bind<bind::NeedFirstReply>, Address),
262 Connect(Connect<connect::NeedReply>, Address),
263}