use std::{io, net::SocketAddr};
use futures::future::BoxFuture;
use log::*;
use super::{DnsResolver, DnsResolverError};
use crate::{
multiaddr::Multiaddr,
socks::Socks5Client,
transports::{SocksConfig, SocksTransport, TcpTransport, Transport, dns::common},
};
const LOG_TARGET: &str = "comms::dns::tor_resolver";
#[derive(Clone)]
pub struct TorDnsResolver {
socks_config: SocksConfig,
}
type TcpSocks5Client = Socks5Client<<TcpTransport as Transport>::Output>;
impl TorDnsResolver {
pub fn new(socks_config: SocksConfig) -> Self {
Self { socks_config }
}
pub async fn connect(self) -> Result<TcpSocks5Client, DnsResolverError> {
let mut client = connect_inner(&self.socks_config.proxy_address)
.await
.map_err(DnsResolverError::ProxyConnectFailed)?;
client.with_authentication(self.socks_config.authentication)?;
Ok(client)
}
}
async fn connect_inner(addr: &Multiaddr) -> io::Result<TcpSocks5Client> {
let socket = SocksTransport::create_socks_tcp_transport().dial(addr).await?;
Ok(Socks5Client::new(socket))
}
impl DnsResolver for TorDnsResolver {
fn resolve(&self, addr: Multiaddr) -> BoxFuture<'static, Result<SocketAddr, DnsResolverError>> {
let resolver = self.clone();
Box::pin(async move {
let addr = if common::is_dns4_addr(&addr) {
let mut client = resolver.connect().await?;
debug!(target: LOG_TARGET, "Resolving address `{addr}` using tor" );
let resolved_address = match client.tor_resolve(&addr).await {
Ok(address) => address,
Err(err) => {
error!(target: LOG_TARGET, "Error resolving address: {err}");
return Err(err.into());
},
};
debug!(target: LOG_TARGET, "Resolved address `{resolved_address}` using tor");
resolved_address
} else {
addr
};
common::convert_tcpip_multiaddr_to_socketaddr(&addr)
})
}
}
#[cfg(test)]
mod test {
use std::sync::Arc;
use super::*;
use crate::transports::predicate::FalsePredicate;
#[ignore]
#[tokio::test]
async fn resolve() {
let resolver = TorDnsResolver::new(SocksConfig {
proxy_address: "/ip4/127.0.0.1/tcp/9050".parse().unwrap(),
authentication: Default::default(),
proxy_bypass_predicate: Arc::new(FalsePredicate::new()),
});
let addr = resolver
.resolve("/dns4/tari.com/tcp/443".parse().unwrap())
.await
.unwrap();
assert_eq!(addr.port(), 443);
let addr = resolver
.resolve("/dns/tari.com/tcp/443".parse().unwrap())
.await
.unwrap();
assert_eq!(addr.port(), 443);
}
}