hickory-resolver 0.26.0

hickory-resolver is a safe and secure DNS stub resolver library intended to be a high-level library for DNS record resolution.
Documentation
#[cfg(all(
    any(feature = "webpki-roots", feature = "rustls-platform-verifier"),
    feature = "__https"
))]
use hickory_resolver::config::CLOUDFLARE;
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
use {
    hickory_resolver::{
        ConnectionProvider, Resolver,
        config::{GOOGLE, ResolverConfig},
        net::runtime::{RuntimeProvider, TokioHandle, TokioTime, iocompat::AsyncIoTokioAsStd},
    },
    std::future::Future,
    std::io,
    std::net::SocketAddr,
    std::pin::Pin,
    std::time::Duration,
    tokio::net::{TcpSocket, TcpStream, UdpSocket},
    tokio::time::timeout,
};

#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
#[derive(Clone, Default)]
struct PrintProvider {
    handle: TokioHandle,
}

#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
impl RuntimeProvider for PrintProvider {
    type Handle = TokioHandle;
    type Timer = TokioTime;
    type Udp = UdpSocket;
    type Tcp = AsyncIoTokioAsStd<TcpStream>;

    fn create_handle(&self) -> Self::Handle {
        self.handle.clone()
    }

    fn connect_tcp(
        &self,
        server_addr: SocketAddr,
        bind_addr: Option<SocketAddr>,
        wait_for: Option<Duration>,
    ) -> Pin<Box<dyn Send + Future<Output = Result<Self::Tcp, io::Error>>>> {
        Box::pin(async move {
            let socket = match server_addr {
                SocketAddr::V4(_) => TcpSocket::new_v4(),
                SocketAddr::V6(_) => TcpSocket::new_v6(),
            }?;

            if let Some(bind_addr) = bind_addr {
                socket.bind(bind_addr)?;
            }

            socket.set_nodelay(true)?;
            let future = socket.connect(server_addr);
            let wait_for = wait_for.unwrap_or_else(|| Duration::from_secs(5));
            match timeout(wait_for, future).await {
                Ok(Ok(socket)) => Ok(AsyncIoTokioAsStd(socket)),
                Ok(Err(e)) => Err(e),
                Err(_) => Err(io::Error::new(
                    io::ErrorKind::TimedOut,
                    "TCP connect timed out",
                )),
            }
        })
    }

    fn bind_udp(
        &self,
        local_addr: SocketAddr,
        server_addr: SocketAddr,
    ) -> Pin<Box<dyn Send + Future<Output = Result<Self::Udp, io::Error>>>> {
        // The server_addr parameter is used only when you need to establish a tunnel or something similar.
        // For example, you try to use a http proxy and encapsulate UDP packets inside a TCP stream.
        println!("Create udp local_addr: {local_addr}, server_addr: {server_addr}");
        Box::pin(async move { UdpSocket::bind(local_addr).await })
    }
}

#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
async fn lookup_test<R: ConnectionProvider>(resolver: Resolver<R>) {
    let response = resolver.lookup_ip("www.example.com.").await.unwrap();

    assert_ne!(response.iter().count(), 0, "no addresses returned!");
}

#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
#[tokio::main]
async fn main() {
    tracing_subscriber::fmt::init();
    run().await;
}

#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
async fn run() {
    let resolver = Resolver::builder_with_config(
        ResolverConfig::udp_and_tcp(&GOOGLE),
        PrintProvider::default(),
    )
    .build()
    .unwrap();

    lookup_test(resolver).await;

    #[cfg(feature = "__https")]
    {
        let resolver2 = Resolver::builder_with_config(
            ResolverConfig::https(&CLOUDFLARE),
            PrintProvider::default(),
        )
        .build()
        .unwrap();
        lookup_test(resolver2).await;
    }

    println!("Hello, world!");
}

#[cfg(not(any(feature = "webpki-roots", feature = "rustls-platform-verifier")))]
fn main() {
    println!("either `webpki-roots` or `rustls-platform-verifier` feature must be enabled")
}

#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
#[tokio::test]
async fn test_custom_provider() {
    test_support::subscribe();
    run().await;
}