use std::{
fmt::Display,
net::{SocketAddr, ToSocketAddrs},
};
use futures::{FutureExt, future, future::BoxFuture};
use log::*;
use super::{DnsResolver, DnsResolverError};
use crate::{
multiaddr::{Multiaddr, Protocol},
transports::dns::common,
};
const LOG_TARGET: &str = "comms::dns::system_resolver";
pub struct SystemDnsResolver;
impl DnsResolver for SystemDnsResolver {
fn resolve(&self, addr: Multiaddr) -> BoxFuture<'static, Result<SocketAddr, DnsResolverError>> {
let protos = match common::extract_protocols(&addr) {
Ok(p) => p,
Err(err) => return boxed_ready(Err(err)),
};
match protos {
(Protocol::Dns(domain), Protocol::Tcp(port)) | (Protocol::Dns4(domain), Protocol::Tcp(port)) => {
dns_lookup(format!("{domain}:{port}")).boxed()
},
(Protocol::Ip4(host), Protocol::Tcp(port)) => boxed_ready(Ok((host, port).into())),
(Protocol::Ip6(host), Protocol::Tcp(port)) => boxed_ready(Ok((host, port).into())),
_ => boxed_ready(Err(DnsResolverError::UnsupportedAddress(addr))),
}
}
}
async fn dns_lookup<T>(addr: T) -> Result<SocketAddr, DnsResolverError>
where T: ToSocketAddrs + Display + Send + Sync + 'static {
tokio::task::spawn_blocking(move || {
debug!(target: LOG_TARGET, "Resolving address `{addr}` using system resolver");
addr.to_socket_addrs()
.map_err(|err| DnsResolverError::NameResolutionFailed {
source: err,
address_str: addr.to_string(),
})?
.next()
.ok_or(DnsResolverError::DnsAddressNotFound)
})
.await?
}
#[inline]
fn boxed_ready<T: Send + 'static>(t: T) -> BoxFuture<'static, T> {
Box::pin(future::ready(t))
}