Skip to main content

rama_socks5/client/
proxy_error.rs

1use super::core::HandshakeError;
2use rama_core::error::BoxError;
3use rama_net::client::{ConnectionError, ConnectionErrorKind};
4use std::fmt;
5
6#[derive(Debug)]
7/// error that can be returned in case a socks5 proxy
8/// did not manage to establish a connection
9pub enum Socks5ProxyError {
10    /// Socks5 handshake error
11    Handshake(HandshakeError),
12    /// I/O error happened as part of Socks5 Proxy Connection Establishment
13    ///
14    /// (e.g. some kind of TCP error)
15    Transport(BoxError),
16}
17
18impl fmt::Display for Socks5ProxyError {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        match self {
21            Self::Handshake(error) => {
22                write!(f, "socks5 proxy error: handshake error [{error}]")
23            }
24            Self::Transport(error) => {
25                write!(f, "socks5 proxy error: transport error: I/O [{error}]")
26            }
27        }
28    }
29}
30
31impl From<std::io::Error> for Socks5ProxyError {
32    fn from(value: std::io::Error) -> Self {
33        Self::Transport(value.into())
34    }
35}
36
37impl std::error::Error for Socks5ProxyError {
38    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
39        match self {
40            Self::Handshake(err) => match err.source() {
41                Some(err_src) if !err_src.is::<std::io::Error>() => Some(err_src),
42                _ => Some(err as &dyn std::error::Error),
43            },
44            Self::Transport(err) => {
45                // filter out generic io errors,
46                // but do allow custom errors (e.g. because IP is blocked)
47                let err_ref = err.source().unwrap_or_else(|| err.as_ref());
48                if err_ref.is::<std::io::Error>() {
49                    Some(self)
50                } else {
51                    Some(err_ref)
52                }
53            }
54        }
55    }
56}
57
58impl From<Socks5ProxyError> for ConnectionError {
59    fn from(error: Socks5ProxyError) -> Self {
60        let kind = match &error {
61            Socks5ProxyError::Handshake(error) => error.connection_error_kind(),
62            Socks5ProxyError::Transport(_) => ConnectionErrorKind::Unavailable,
63        };
64        Self::transport(error, kind)
65    }
66}