Skip to main content

socks5_impl/server/connection/
bind.rs

1use crate::{
2    Address, AsyncStreamOperation,
3    protocol::{Reply, Response},
4};
5use std::{
6    marker::PhantomData,
7    net::{SocketAddr, ToSocketAddrs},
8    pin::Pin,
9    task::{Context, Poll},
10};
11use tokio::{
12    io::{AsyncRead, AsyncWrite, AsyncWriteExt, ReadBuf},
13    net::{
14        TcpListener, TcpStream,
15        tcp::{ReadHalf, WriteHalf},
16    },
17};
18
19/// Socks5 command type `Bind`
20///
21/// By [`wait_request`](crate::server::connection::Authenticated::wait_request)
22/// on an [`Authenticated`](crate::server::connection::Authenticated) from SOCKS5 client,
23/// you may get a `Bind<NeedFirstReply>`. After replying the client 2 times
24/// using [`reply()`](crate::server::connection::Bind::reply),
25/// you will get a `Bind<Ready>`, which can be used as a regular async TCP stream.
26///
27/// A `Bind<S>` can be converted to a regular tokio [`TcpStream`](https://docs.rs/tokio/latest/tokio/net/struct.TcpStream.html) by using the `From` trait.
28#[derive(Debug)]
29pub struct Bind<S> {
30    stream: TcpStream,
31    _state: PhantomData<S>,
32}
33
34/// Marker type indicating that the connection needs its first reply.
35#[derive(Debug, Default)]
36pub struct NeedFirstReply;
37
38/// Marker type indicating that the connection needs its second reply.
39#[derive(Debug, Default)]
40pub struct NeedSecondReply;
41
42/// Marker type indicating that the connection is ready to use as a regular TCP stream.
43#[derive(Debug, Default)]
44pub struct Ready;
45
46impl Bind<NeedFirstReply> {
47    #[inline]
48    pub(super) fn new(stream: TcpStream) -> Self {
49        Self {
50            stream,
51            _state: PhantomData,
52        }
53    }
54
55    /// Reply to the SOCKS5 client with the given reply and address.
56    ///
57    /// If encountered an error while writing the reply, the error alongside the original `TcpStream` is returned.
58    pub async fn reply(mut self, reply: Reply, addr: Address) -> std::io::Result<Bind<NeedSecondReply>> {
59        let resp = Response::new(reply, addr);
60        resp.write_to_async_stream(&mut self.stream).await?;
61        Ok(Bind::<NeedSecondReply>::new(self.stream))
62    }
63
64    /// Accept an incoming connection for SOCKS5 BIND.
65    ///
66    /// This binds a TCP listener to the requested `bind_addr`, sends the first BIND
67    /// reply with the actual bound address, then waits for the remote peer to connect.
68    /// The returned `Bind<NeedSecondReply>` can be used to send the second reply.
69    pub async fn accept(self, bind_addr: Address) -> std::io::Result<(Bind<NeedSecondReply>, TcpStream)> {
70        let bind_addr = bind_addr
71            .to_socket_addrs()?
72            .next()
73            .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::InvalidInput, "invalid bind address"))?;
74
75        let listener = match TcpListener::bind(bind_addr).await {
76            Ok(listener) => listener,
77            Err(err) => {
78                let _ = self.reply(Reply::GeneralFailure, Address::unspecified()).await;
79                return Err(err);
80            }
81        };
82
83        let local_addr = listener.local_addr()?;
84        let bind = self.reply(Reply::Succeeded, Address::from(local_addr)).await?;
85        let (incoming, _) = listener.accept().await?;
86        Ok((bind, incoming))
87    }
88
89    /// Fully complete BIND handling, including first reply, accept, and second reply.
90    pub async fn bind(self, bind_addr: Address) -> std::io::Result<(Bind<Ready>, TcpStream)> {
91        let (bind, incoming) = self.accept(bind_addr).await?;
92        let remote_addr = incoming.peer_addr()?;
93        let conn = match bind.reply(Reply::Succeeded, Address::from(remote_addr)).await {
94            Ok(conn) => conn,
95            Err((err, _stream)) => return Err(err),
96        };
97        Ok((conn, incoming))
98    }
99
100    /// 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.
101    #[inline]
102    pub async fn shutdown(&mut self) -> std::io::Result<()> {
103        self.stream.shutdown().await
104    }
105
106    /// Returns the local address that this stream is bound to.
107    #[inline]
108    pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
109        self.stream.local_addr()
110    }
111
112    /// Returns the remote address that this stream is connected to.
113    #[inline]
114    pub fn peer_addr(&self) -> std::io::Result<SocketAddr> {
115        self.stream.peer_addr()
116    }
117
118    /// Gets the value of the `TCP_NODELAY` option on this socket.
119    ///
120    /// For more information about this option, see [`set_nodelay`](crate::server::connection::Bind::set_nodelay).
121    #[inline]
122    pub fn nodelay(&self) -> std::io::Result<bool> {
123        self.stream.nodelay()
124    }
125
126    /// Sets the value of the `TCP_NODELAY` option on this socket.
127    ///
128    /// If set, this option disables the Nagle algorithm. This means that segments are always sent as soon as possible,
129    /// 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,
130    /// thereby avoiding the frequent sending of small packets.
131    pub fn set_nodelay(&self, nodelay: bool) -> std::io::Result<()> {
132        self.stream.set_nodelay(nodelay)
133    }
134
135    /// Gets the value of the `IP_TTL` option for this socket.
136    ///
137    /// For more information about this option, see [`set_ttl`](crate::server::connection::Bind::set_ttl).
138    pub fn ttl(&self) -> std::io::Result<u32> {
139        self.stream.ttl()
140    }
141
142    /// Sets the value for the `IP_TTL` option on this socket.
143    ///
144    /// This value sets the time-to-live field that is used in every packet sent from this socket.
145    pub fn set_ttl(&self, ttl: u32) -> std::io::Result<()> {
146        self.stream.set_ttl(ttl)
147    }
148}
149
150impl Bind<NeedSecondReply> {
151    #[inline]
152    fn new(stream: TcpStream) -> Self {
153        Self {
154            stream,
155            _state: PhantomData,
156        }
157    }
158
159    /// Reply to the SOCKS5 client with the given reply and address.
160    ///
161    /// If encountered an error while writing the reply, the error alongside the original `TcpStream` is returned.
162    pub async fn reply(mut self, reply: Reply, addr: Address) -> Result<Bind<Ready>, (std::io::Error, TcpStream)> {
163        let resp = Response::new(reply, addr);
164
165        if let Err(err) = resp.write_to_async_stream(&mut self.stream).await {
166            return Err((err, self.stream));
167        }
168
169        Ok(Bind::<Ready>::new(self.stream))
170    }
171
172    /// 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.
173    #[inline]
174    pub async fn shutdown(&mut self) -> std::io::Result<()> {
175        self.stream.shutdown().await
176    }
177
178    /// Returns the local address that this stream is bound to.
179    #[inline]
180    pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
181        self.stream.local_addr()
182    }
183
184    /// Returns the remote address that this stream is connected to.
185    #[inline]
186    pub fn peer_addr(&self) -> std::io::Result<SocketAddr> {
187        self.stream.peer_addr()
188    }
189
190    /// Gets the value of the `TCP_NODELAY` option on this socket.
191    ///
192    /// For more information about this option, see
193    /// [`set_nodelay`](crate::server::connection::Bind::set_nodelay).
194    #[inline]
195    pub fn nodelay(&self) -> std::io::Result<bool> {
196        self.stream.nodelay()
197    }
198
199    /// Sets the value of the `TCP_NODELAY` option on this socket.
200    ///
201    /// If set, this option disables the Nagle algorithm. This means that segments are always sent as soon as possible,
202    /// 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,
203    /// thereby avoiding the frequent sending of small packets.
204    pub fn set_nodelay(&self, nodelay: bool) -> std::io::Result<()> {
205        self.stream.set_nodelay(nodelay)
206    }
207
208    /// Gets the value of the `IP_TTL` option for this socket.
209    ///
210    /// For more information about this option, see [`set_ttl`](crate::server::connection::Bind::set_ttl).
211    pub fn ttl(&self) -> std::io::Result<u32> {
212        self.stream.ttl()
213    }
214
215    /// Sets the value for the `IP_TTL` option on this socket.
216    ///
217    /// This value sets the time-to-live field that is used in every packet sent from this socket.
218    pub fn set_ttl(&self, ttl: u32) -> std::io::Result<()> {
219        self.stream.set_ttl(ttl)
220    }
221}
222
223impl Bind<Ready> {
224    #[inline]
225    fn new(stream: TcpStream) -> Self {
226        Self {
227            stream,
228            _state: PhantomData,
229        }
230    }
231
232    /// Split the connection into a read and a write half.
233    #[inline]
234    pub fn split(&mut self) -> (ReadHalf<'_>, WriteHalf<'_>) {
235        self.stream.split()
236    }
237}
238
239impl std::ops::Deref for Bind<Ready> {
240    type Target = TcpStream;
241
242    #[inline]
243    fn deref(&self) -> &Self::Target {
244        &self.stream
245    }
246}
247
248impl std::ops::DerefMut for Bind<Ready> {
249    #[inline]
250    fn deref_mut(&mut self) -> &mut Self::Target {
251        &mut self.stream
252    }
253}
254
255impl AsyncRead for Bind<Ready> {
256    #[inline]
257    fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<std::io::Result<()>> {
258        Pin::new(&mut self.stream).poll_read(cx, buf)
259    }
260}
261
262impl AsyncWrite for Bind<Ready> {
263    #[inline]
264    fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<std::io::Result<usize>> {
265        Pin::new(&mut self.stream).poll_write(cx, buf)
266    }
267
268    #[inline]
269    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
270        Pin::new(&mut self.stream).poll_flush(cx)
271    }
272
273    #[inline]
274    fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
275        Pin::new(&mut self.stream).poll_shutdown(cx)
276    }
277}
278
279impl<S> From<Bind<S>> for TcpStream {
280    #[inline]
281    fn from(conn: Bind<S>) -> Self {
282        conn.stream
283    }
284}