hyper_util/client/legacy/connect/proxy/socks/
mod.rs

1mod v5;
2pub use v5::{SocksV5, SocksV5Error};
3
4mod v4;
5pub use v4::{SocksV4, SocksV4Error};
6
7use pin_project_lite::pin_project;
8use std::future::Future;
9use std::pin::Pin;
10use std::task::{Context, Poll};
11
12use bytes::BytesMut;
13
14use hyper::rt::Read;
15
16#[derive(Debug)]
17pub enum SocksError<C> {
18    Inner(C),
19    Io(std::io::Error),
20
21    DnsFailure,
22    MissingHost,
23    MissingPort,
24
25    V4(SocksV4Error),
26    V5(SocksV5Error),
27
28    Parsing(ParsingError),
29    Serialize(SerializeError),
30}
31
32#[derive(Debug)]
33pub enum ParsingError {
34    Incomplete,
35    WouldOverflow,
36    Other,
37}
38
39#[derive(Debug)]
40pub enum SerializeError {
41    WouldOverflow,
42}
43
44async fn read_message<T, M, C>(mut conn: &mut T, buf: &mut BytesMut) -> Result<M, SocksError<C>>
45where
46    T: Read + Unpin,
47    M: for<'a> TryFrom<&'a mut BytesMut, Error = ParsingError>,
48{
49    let mut tmp = [0; 513];
50
51    loop {
52        let n = crate::rt::read(&mut conn, &mut tmp).await?;
53        buf.extend_from_slice(&tmp[..n]);
54
55        match M::try_from(buf) {
56            Err(ParsingError::Incomplete) => {
57                if n == 0 {
58                    if buf.spare_capacity_mut().is_empty() {
59                        return Err(SocksError::Parsing(ParsingError::WouldOverflow));
60                    } else {
61                        return Err(std::io::Error::new(
62                            std::io::ErrorKind::UnexpectedEof,
63                            "unexpected eof",
64                        )
65                        .into());
66                    }
67                }
68            }
69            Err(err) => return Err(err.into()),
70            Ok(res) => return Ok(res),
71        }
72    }
73}
74
75impl<C> std::fmt::Display for SocksError<C> {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        f.write_str("SOCKS error: ")?;
78
79        match self {
80            Self::Inner(_) => f.write_str("failed to create underlying connection"),
81            Self::Io(_) => f.write_str("io error during SOCKS handshake"),
82
83            Self::DnsFailure => f.write_str("could not resolve to acceptable address type"),
84            Self::MissingHost => f.write_str("missing destination host"),
85            Self::MissingPort => f.write_str("missing destination port"),
86
87            Self::Parsing(_) => f.write_str("failed parsing server response"),
88            Self::Serialize(_) => f.write_str("failed serialize request"),
89
90            Self::V4(e) => e.fmt(f),
91            Self::V5(e) => e.fmt(f),
92        }
93    }
94}
95
96impl<C: std::fmt::Debug + std::fmt::Display> std::error::Error for SocksError<C> {}
97
98impl<C> From<std::io::Error> for SocksError<C> {
99    fn from(err: std::io::Error) -> Self {
100        Self::Io(err)
101    }
102}
103
104impl<C> From<ParsingError> for SocksError<C> {
105    fn from(err: ParsingError) -> Self {
106        Self::Parsing(err)
107    }
108}
109
110impl<C> From<SerializeError> for SocksError<C> {
111    fn from(err: SerializeError) -> Self {
112        Self::Serialize(err)
113    }
114}
115
116impl<C> From<SocksV4Error> for SocksError<C> {
117    fn from(err: SocksV4Error) -> Self {
118        Self::V4(err)
119    }
120}
121
122impl<C> From<SocksV5Error> for SocksError<C> {
123    fn from(err: SocksV5Error) -> Self {
124        Self::V5(err)
125    }
126}
127
128pin_project! {
129    // Not publicly exported (so missing_docs doesn't trigger).
130    //
131    // We return this `Future` instead of the `Pin<Box<dyn Future>>` directly
132    // so that users don't rely on it fitting in a `Pin<Box<dyn Future>>` slot
133    // (and thus we can change the type in the future).
134    #[must_use = "futures do nothing unless polled"]
135    #[allow(missing_debug_implementations)]
136    pub struct Handshaking<F, T, E> {
137        #[pin]
138        fut: BoxHandshaking<T, E>,
139        _marker: std::marker::PhantomData<F>
140    }
141}
142
143type BoxHandshaking<T, E> = Pin<Box<dyn Future<Output = Result<T, SocksError<E>>> + Send>>;
144
145impl<F, T, E> Future for Handshaking<F, T, E>
146where
147    F: Future<Output = Result<T, E>>,
148{
149    type Output = Result<T, SocksError<E>>;
150
151    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
152        self.project().fut.poll(cx)
153    }
154}