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    /// Set a timeout for the SOCKS5 handshake.
98    pub async fn authenticate_with_timeout(self, timeout: Duration) -> crate::Result<(Authenticated, O)> {
99        tokio::time::timeout(timeout, self.authenticate())
100            .await
101            .map_err(|_| crate::Error::String("handshake timeout".into()))?
102    }
103
104    /// Perform a SOCKS5 authentication handshake using the given
105    /// [`AuthExecutor`](crate::server::auth::AuthExecutor) adapter.
106    ///
107    /// If the handshake succeeds, an [`Authenticated`]
108    /// alongs with the output of the [`AuthExecutor`](crate::server::auth::AuthExecutor) adapter is returned.
109    /// Otherwise, the error and the original [`TcpStream`](https://docs.rs/tokio/latest/tokio/net/struct.TcpStream.html) is returned.
110    ///
111    /// Note that this method will not implicitly close the connection even if the handshake failed.
112    pub async fn authenticate(mut self) -> crate::Result<(Authenticated, O)> {
113        let request = handshake::Request::retrieve_from_async_stream(&mut self.stream).await?;
114        if let Some(method) = self.evaluate_request(&request) {
115            let response = handshake::Response::new(method);
116            response.write_to_async_stream(&mut self.stream).await?;
117            let output = self.auth.execute(&mut self.stream).await;
118            Ok((Authenticated::new(self.stream), output))
119        } else {
120            let response = handshake::Response::new(AuthMethod::NoAcceptableMethods);
121            response.write_to_async_stream(&mut self.stream).await?;
122            let err = "No available handshake method provided by client";
123            Err(crate::Error::Io(std::io::Error::new(std::io::ErrorKind::Unsupported, err)))
124        }
125    }
126
127    fn evaluate_request(&self, req: &handshake::Request) -> Option<AuthMethod> {
128        let method = self.auth.auth_method();
129        if req.evaluate_method(method) { Some(method) } else { None }
130    }
131}
132
133impl<O> std::fmt::Debug for IncomingConnection<O> {
134    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135        f.debug_struct("IncomingConnection").field("stream", &self.stream).finish()
136    }
137}
138
139impl<O> From<IncomingConnection<O>> for TcpStream {
140    #[inline]
141    fn from(conn: IncomingConnection<O>) -> Self {
142        conn.stream
143    }
144}
145
146/// A TCP stream that has been authenticated.
147///
148/// To get the command from the SOCKS5 client, use
149/// [`wait_request`](crate::server::connection::Authenticated::wait_request).
150///
151/// It can also be converted back into a raw [`tokio::TcpStream`](https://docs.rs/tokio/latest/tokio/net/struct.TcpStream.html) with `From` trait.
152pub struct Authenticated(TcpStream);
153
154impl Authenticated {
155    #[inline]
156    fn new(stream: TcpStream) -> Self {
157        Self(stream)
158    }
159
160    /// Waits the SOCKS5 client to send a request.
161    ///
162    /// This method will return a [`Command`] if the client sends a valid command.
163    ///
164    /// When encountering an error, the stream will be returned alongside the error.
165    ///
166    /// Note that this method will not implicitly close the connection even if the client sends an invalid request.
167    pub async fn wait_request(mut self) -> crate::Result<ClientConnection> {
168        let req = protocol::Request::retrieve_from_async_stream(&mut self.0).await?;
169
170        match req.command {
171            Command::UdpAssociate => Ok(ClientConnection::UdpAssociate(
172                UdpAssociate::<associate::NeedReply>::new(self.0),
173                req.address,
174            )),
175            Command::Bind => Ok(ClientConnection::Bind(Bind::<bind::NeedFirstReply>::new(self.0), req.address)),
176            Command::Connect => Ok(ClientConnection::Connect(Connect::<connect::NeedReply>::new(self.0), req.address)),
177        }
178    }
179
180    /// 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.
181    #[inline]
182    pub async fn shutdown(&mut self) -> std::io::Result<()> {
183        self.0.shutdown().await
184    }
185
186    /// Returns the local address that this stream is bound to.
187    #[inline]
188    pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
189        self.0.local_addr()
190    }
191
192    /// Returns the remote address that this stream is connected to.
193    #[inline]
194    pub fn peer_addr(&self) -> std::io::Result<SocketAddr> {
195        self.0.peer_addr()
196    }
197
198    /// Reads the linger duration for this socket by getting the `SO_LINGER` option.
199    ///
200    /// For more information about this option, see
201    /// [`set_linger`](crate::server::connection::Authenticated::set_linger).
202    #[inline]
203    pub fn linger(&self) -> std::io::Result<Option<Duration>> {
204        self.0.linger()
205    }
206
207    /// Sets the linger duration of this socket by setting the `SO_LINGER` option.
208    ///
209    /// This option controls the action taken when a stream has unsent messages and the stream is closed.
210    /// If `SO_LINGER` is set, the system shall block the process until it can transmit the data or until the time expires.
211    ///
212    /// If `SO_LINGER` is not specified, and the stream is closed, the system handles the call in a way
213    /// that allows the process to continue as quickly as possible.
214    #[inline]
215    pub fn set_linger(&self, dur: Option<Duration>) -> std::io::Result<()> {
216        self.0.set_linger(dur)
217    }
218
219    /// Gets the value of the `TCP_NODELAY` option on this socket.
220    ///
221    /// For more information about this option, see
222    /// [`set_nodelay`](crate::server::connection::Authenticated::set_nodelay).
223    #[inline]
224    pub fn nodelay(&self) -> std::io::Result<bool> {
225        self.0.nodelay()
226    }
227
228    /// Sets the value of the `TCP_NODELAY` option on this socket.
229    ///
230    /// If set, this option disables the Nagle algorithm. This means that segments are always sent as soon as possible,
231    /// 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,
232    /// thereby avoiding the frequent sending of small packets.
233    pub fn set_nodelay(&self, nodelay: bool) -> std::io::Result<()> {
234        self.0.set_nodelay(nodelay)
235    }
236
237    /// Gets the value of the `IP_TTL` option for this socket.
238    ///
239    /// For more information about this option, see
240    /// [`set_ttl`](crate::server::connection::Authenticated::set_ttl).
241    pub fn ttl(&self) -> std::io::Result<u32> {
242        self.0.ttl()
243    }
244
245    /// Sets the value for the `IP_TTL` option on this socket.
246    ///
247    /// This value sets the time-to-live field that is used in every packet sent from this socket.
248    pub fn set_ttl(&self, ttl: u32) -> std::io::Result<()> {
249        self.0.set_ttl(ttl)
250    }
251}
252
253impl From<Authenticated> for TcpStream {
254    #[inline]
255    fn from(conn: Authenticated) -> Self {
256        conn.0
257    }
258}
259
260/// After the socks5 handshake succeeds, the connection may become:
261///
262/// - Associate
263/// - Bind
264/// - Connect
265#[derive(Debug)]
266pub enum ClientConnection {
267    UdpAssociate(UdpAssociate<associate::NeedReply>, Address),
268    Bind(Bind<bind::NeedFirstReply>, Address),
269    Connect(Connect<connect::NeedReply>, Address),
270}