use tokio::net::TcpStream;
#[cfg(feature = "socks5")]
use tokio_socks::tcp::Socks5Stream;
use crate::error::ConnectError;
#[derive(Clone, Debug)]
pub struct Socks5Config {
pub proxy_addr: String,
pub auth: Option<(String, String)>,
}
impl Socks5Config {
pub fn new(proxy_addr: impl Into<String>) -> Self {
Self {
proxy_addr: proxy_addr.into(),
auth: None,
}
}
pub fn with_auth(
proxy_addr: impl Into<String>,
username: impl Into<String>,
password: impl Into<String>,
) -> Self {
Self {
proxy_addr: proxy_addr.into(),
auth: Some((username.into(), password.into())),
}
}
#[cfg(feature = "socks5")]
pub async fn connect(&self, target: &str) -> Result<TcpStream, ConnectError> {
tracing::debug!(
"[ferogram::connect] SOCKS5: relaying through {} to {target}",
self.proxy_addr
);
let stream = match &self.auth {
None => Socks5Stream::connect(self.proxy_addr.as_str(), target)
.await
.map_err(|e| ConnectError::Io(std::io::Error::other(e)))?,
Some((user, pass)) => Socks5Stream::connect_with_password(
self.proxy_addr.as_str(),
target,
user.as_str(),
pass.as_str(),
)
.await
.map_err(|e| ConnectError::Io(std::io::Error::other(e)))?,
};
Ok(stream.into_inner())
}
#[cfg(not(feature = "socks5"))]
pub async fn connect(&self, _target: &str) -> Result<TcpStream, ConnectError> {
Err(ConnectError::Io(std::io::Error::new(
std::io::ErrorKind::Unsupported,
"SOCKS5 proxy requested but ferogram-connect was built without the \"socks5\" feature",
)))
}
}