Skip to main content

ferogram_connect/
socks5.rs

1// Copyright (c) Ankit Chaubey <ankitchaubey.dev@gmail.com>
2//
3// ferogram: async Telegram MTProto client in Rust
4// https://github.com/ankit-chaubey/ferogram
5//
6// Licensed under either the MIT License or the Apache License 2.0.
7// See the LICENSE-MIT or LICENSE-APACHE file in this repository:
8// https://github.com/ankit-chaubey/ferogram
9//
10// Feel free to use, modify, and share this code.
11// Please keep this notice when redistributing.
12
13use tokio::net::TcpStream;
14use tokio_socks::tcp::Socks5Stream;
15
16use crate::error::ConnectError;
17
18/// SOCKS5 proxy configuration.
19#[derive(Clone, Debug)]
20pub struct Socks5Config {
21    /// Host:port of the SOCKS5 proxy server.
22    pub proxy_addr: String,
23    /// Optional username and password for proxy authentication.
24    pub auth: Option<(String, String)>,
25}
26
27impl Socks5Config {
28    /// Create an unauthenticated SOCKS5 config.
29    pub fn new(proxy_addr: impl Into<String>) -> Self {
30        Self {
31            proxy_addr: proxy_addr.into(),
32            auth: None,
33        }
34    }
35
36    /// Create a SOCKS5 config with username/password authentication.
37    pub fn with_auth(
38        proxy_addr: impl Into<String>,
39        username: impl Into<String>,
40        password: impl Into<String>,
41    ) -> Self {
42        Self {
43            proxy_addr: proxy_addr.into(),
44            auth: Some((username.into(), password.into())),
45        }
46    }
47
48    /// Establish a TCP connection through this SOCKS5 proxy.
49    pub async fn connect(&self, target: &str) -> Result<TcpStream, ConnectError> {
50        tracing::info!("[socks5] Connecting via {} -> {target}", self.proxy_addr);
51        let stream = match &self.auth {
52            None => Socks5Stream::connect(self.proxy_addr.as_str(), target)
53                .await
54                .map_err(|e| ConnectError::Io(std::io::Error::other(e)))?,
55            Some((user, pass)) => Socks5Stream::connect_with_password(
56                self.proxy_addr.as_str(),
57                target,
58                user.as_str(),
59                pass.as_str(),
60            )
61            .await
62            .map_err(|e| ConnectError::Io(std::io::Error::other(e)))?,
63        };
64        Ok(stream.into_inner())
65    }
66}