Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions src/client/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ use super::{
response::Response,
};
#[cfg(feature = "hickory-dns")]
use crate::dns::hickory::{HickoryDnsResolver, LookupIpStrategy};
use crate::dns::hickory::HickoryDnsResolver;
use crate::{
IntoUrl, Method, Proxy,
client::{
Expand Down Expand Up @@ -254,9 +254,7 @@ impl ClientBuilder {
let mut resolver: Arc<dyn Resolve> = match config.dns_resolver {
Some(dns_resolver) => dns_resolver,
#[cfg(feature = "hickory-dns")]
None if config.hickory_dns => {
Arc::new(HickoryDnsResolver::new(LookupIpStrategy::Ipv4thenIpv6)?)
}
None if config.hickory_dns => Arc::new(HickoryDnsResolver::new()),
None => Arc::new(GaiResolver::new()),
};

Expand Down
90 changes: 31 additions & 59 deletions src/core/client/connect/dns/hickory.rs
Original file line number Diff line number Diff line change
@@ -1,82 +1,54 @@
//! DNS resolution via the [hickory-resolver](https://github.com/hickory-dns/hickory-dns) crate

use std::{net::SocketAddr, sync::Arc};
use std::{net::SocketAddr, sync::LazyLock};

use hickory_resolver::{
TokioResolver,
config::{LookupIpStrategy as HickoryLookupIpStrategy, ResolverConfig},
config::{LookupIpStrategy, ResolverConfig},
lookup_ip::LookupIpIntoIter,
name_server::TokioConnectionProvider,
};

use super::{Addrs, Name, Resolve, Resolving};

/// The lookup ip strategy
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum LookupIpStrategy {
/// Only query for A (Ipv4) records
Ipv4Only,
/// Only query for AAAA (Ipv6) records
Ipv6Only,
/// Query for A and AAAA in parallel
#[default]
Ipv4AndIpv6,
/// Query for Ipv6 if that fails, query for Ipv4
Ipv6thenIpv4,
/// Query for Ipv4 if that fails, query for Ipv6
Ipv4thenIpv6,
}

impl LookupIpStrategy {
const fn to_hickory(self) -> HickoryLookupIpStrategy {
match self {
LookupIpStrategy::Ipv4Only => HickoryLookupIpStrategy::Ipv4Only,
LookupIpStrategy::Ipv6Only => HickoryLookupIpStrategy::Ipv6Only,
LookupIpStrategy::Ipv4AndIpv6 => HickoryLookupIpStrategy::Ipv4AndIpv6,
LookupIpStrategy::Ipv6thenIpv4 => HickoryLookupIpStrategy::Ipv6thenIpv4,
LookupIpStrategy::Ipv4thenIpv6 => HickoryLookupIpStrategy::Ipv4thenIpv6,
}
}
}

/// Wrapper around an `AsyncResolver`, which implements the `Resolve` trait.
/// Wrapper around an [`TokioResolver`], which implements the `Resolve` trait.
#[derive(Debug, Clone)]
pub struct HickoryDnsResolver {
/// Since we might not have been called in the context of a
/// Tokio Runtime in initialization, so we must delay the actual
/// construction of the resolver.
state: Arc<TokioResolver>,
/// Shared, lazily-initialized Tokio-based DNS resolver.
///
/// Backed by [`LazyLock`] to guarantee thread-safe, one-time creation.
/// On initialization, it attempts to load the system's DNS configuration;
/// if unavailable, it falls back to sensible default settings.
resolver: &'static LazyLock<TokioResolver>,
}

impl HickoryDnsResolver {
/// Create a new resolver with the default configuration,
/// which reads from `/etc/resolve.conf`. The options are
/// overriden to look up for both IPv4 and IPv6 addresses
/// to work with "happy eyeballs" algorithm.
pub fn new<S>(strategy: S) -> crate::Result<Self>
where
S: Into<Option<LookupIpStrategy>>,
{
let mut resolver = match TokioResolver::builder_tokio() {
Ok(resolver) => resolver,
Err(_err) => {
debug!("error reading DNS system conf: {}", _err);
TokioResolver::builder_with_config(
ResolverConfig::default(),
TokioConnectionProvider::default(),
)
}
};

resolver.options_mut().ip_strategy = strategy
.into()
.map(LookupIpStrategy::to_hickory)
.unwrap_or_default();
pub fn new() -> HickoryDnsResolver {
static RESOLVER: LazyLock<TokioResolver> = LazyLock::new(|| {
let mut builder = match TokioResolver::builder_tokio() {
Ok(resolver) => {
debug!("using system DNS configuration");
resolver
}
Err(_err) => {
debug!("error reading DNS system conf: {}, using defaults", _err);
Comment thread
0x676e67 marked this conversation as resolved.
TokioResolver::builder_with_config(
ResolverConfig::default(),
TokioConnectionProvider::default(),
)
}
};
builder.options_mut().ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
builder.build()
Comment thread
0x676e67 marked this conversation as resolved.
});

Ok(Self {
state: Arc::new(resolver.build()),
})
HickoryDnsResolver {
resolver: &RESOLVER,
}
}
}

Expand All @@ -88,7 +60,7 @@ impl Resolve for HickoryDnsResolver {
fn resolve(&self, name: Name) -> Resolving {
let resolver = self.clone();
Box::pin(async move {
let lookup = resolver.state.lookup_ip(name.as_str()).await?;
let lookup = resolver.resolver.lookup_ip(name.as_str()).await?;
let addrs: Addrs = Box::new(SocketAddrs {
iter: lookup.into_iter(),
});
Expand Down
6 changes: 3 additions & 3 deletions src/core/client/connect/dns/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! DNS resolution

mod gai;
pub(crate) mod gai;
#[cfg(feature = "hickory-dns")]
pub mod hickory;
mod resolve;
pub(crate) mod hickory;
pub(crate) mod resolve;

pub use resolve::{Addrs, Name, Resolve, Resolving};

Expand Down
Loading