diff --git a/Cargo.lock b/Cargo.lock index 0018e5cd..ea18945f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -283,9 +283,13 @@ dependencies = [ "bytes", "bzip2", "compact_str", + "default-net", "flate2", "futures-util", "httpdate", + "hyper", + "ipconfig", + "once_cell", "percent-encoding", "reqwest", "serde", @@ -786,6 +790,23 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +[[package]] +name = "default-net" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d1b93f7700c45c26856522aed3982b685edb0532e4dbdd3a4ec84bb4185526" +dependencies = [ + "dlopen2", + "libc", + "memalloc", + "netlink-packet-core", + "netlink-packet-route", + "netlink-sys", + "once_cell", + "system-configuration", + "windows 0.48.0", +] + [[package]] name = "deranged" version = "0.3.8" @@ -852,6 +873,17 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "dlopen2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" +dependencies = [ + "libc", + "once_cell", + "winapi", +] + [[package]] name = "dunce" version = "1.0.4" @@ -2402,6 +2434,12 @@ dependencies = [ "serde", ] +[[package]] +name = "memalloc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df39d232f5c40b0891c10216992c2f250c054105cb1e56f0fc9032db6203ecc1" + [[package]] name = "memchr" version = "2.6.3" @@ -2511,6 +2549,54 @@ dependencies = [ "tempfile", ] +[[package]] +name = "netlink-packet-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" +dependencies = [ + "anyhow", + "byteorder", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053998cea5a306971f88580d0829e90f270f940befd7cf928da179d4187a5a66" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror", +] + +[[package]] +name = "netlink-sys" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" +dependencies = [ + "bytes", + "libc", + "log", +] + [[package]] name = "nix" version = "0.26.4" @@ -2664,6 +2750,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "percent-encoding" version = "2.3.0" @@ -3465,6 +3557,27 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "target-lexicon" version = "0.12.11" diff --git a/crates/binstalk-downloader/Cargo.toml b/crates/binstalk-downloader/Cargo.toml index d6503e35..8f441233 100644 --- a/crates/binstalk-downloader/Cargo.toml +++ b/crates/binstalk-downloader/Cargo.toml @@ -37,7 +37,9 @@ tokio-tar = "0.3.0" tokio-util = { version = "0.7.8", features = ["io"] } tracing = "0.1.37" # trust-dns-resolver must be kept in sync with the version reqwest uses -trust-dns-resolver = { version = "0.22.0", optional = true, default-features = false, features = ["dnssec-ring"] } +trust-dns-resolver = { version = "0.22.0", optional = true, features = ["dnssec-ring"] } +hyper = { version = "0.14.27", optional = true } +once_cell = { version = "1.18.0", optional = true } url = "2.3.1" xz2 = "0.1.7" @@ -78,7 +80,7 @@ native-tls = [ ] # Enable trust-dns-resolver so that features on it will also be enabled. -trust-dns = ["trust-dns-resolver", "reqwest/trust-dns"] +trust-dns = ["trust-dns-resolver", "default-net", "ipconfig", "hyper", "once_cell"] # Experimental HTTP/3 client, this would require `--cfg reqwest_unstable` # to be passed to `rustc`. @@ -91,6 +93,10 @@ cross-lang-fat-lto = ["zstd/fat-lto"] gh-api-client = ["json"] json = ["serde", "serde_json"] +[target."cfg(windows)".dependencies] +default-net = { version = "0.17.0", optional = true } +ipconfig = { version = "0.3.2", optional = true, default-features = false } + [package.metadata.docs.rs] features = ["gh-api-client"] rustdoc-args = ["--cfg", "docsrs"] diff --git a/crates/binstalk-downloader/src/lib.rs b/crates/binstalk-downloader/src/lib.rs index c4a23c84..94f5434d 100644 --- a/crates/binstalk-downloader/src/lib.rs +++ b/crates/binstalk-downloader/src/lib.rs @@ -12,4 +12,7 @@ pub mod gh_api_client; pub mod remote; +#[cfg(feature = "trust-dns")] +mod resolver; + mod utils; diff --git a/crates/binstalk-downloader/src/remote.rs b/crates/binstalk-downloader/src/remote.rs index 98486a6e..9da79e3b 100644 --- a/crates/binstalk-downloader/src/remote.rs +++ b/crates/binstalk-downloader/src/remote.rs @@ -18,6 +18,9 @@ use tracing::{debug, info, instrument}; pub use reqwest::{header, Error as ReqwestError, Method, StatusCode}; pub use url::Url; +#[cfg(feature = "trust-dns")] +use crate::resolver::TrustDnsResolver; + mod delay_request; use delay_request::DelayRequest; @@ -107,6 +110,11 @@ impl Client { .https_only(true) .tcp_nodelay(false); + #[cfg(feature = "trust-dns")] + { + builder = builder.dns_resolver(Arc::new(TrustDnsResolver::default())); + } + #[cfg(feature = "__tls")] { let tls_ver = min_tls diff --git a/crates/binstalk-downloader/src/resolver.rs b/crates/binstalk-downloader/src/resolver.rs new file mode 100644 index 00000000..b0f331e7 --- /dev/null +++ b/crates/binstalk-downloader/src/resolver.rs @@ -0,0 +1,64 @@ +use std::{net::SocketAddr, sync::Arc}; + +use hyper::client::connect::dns::Name; +use once_cell::sync::OnceCell; +use reqwest::dns::{Addrs, Resolve}; +use trust_dns_resolver::config::{NameServerConfig, Protocol, ResolverConfig, ResolverOpts}; +use trust_dns_resolver::TokioAsyncResolver; + +#[derive(Debug, Default, Clone)] +pub struct TrustDnsResolver(Arc>); + +impl Resolve for TrustDnsResolver { + fn resolve(&self, name: Name) -> reqwest::dns::Resolving { + let resolver = self.clone(); + Box::pin(async move { + let resolver = resolver.0.get_or_try_init(new_resolver)?; + + let lookup = resolver.lookup_ip(name.as_str()).await?; + let addrs: Addrs = Box::new(lookup.into_iter().map(|ip| SocketAddr::new(ip, 0))); + Ok(addrs) + }) + } +} + +fn new_resolver() -> Result> { + #[cfg(unix)] + { + let (config, opts) = trust_dns_resolver::system_conf::read_system_conf()?; + Ok(TokioAsyncResolver::tokio(config, opts)?) + } + #[cfg(windows)] + { + let mut config = ResolverConfig::new(); + let opts = ResolverOpts::default(); + + let current_interface = default_net::get_default_interface()?; + ipconfig::get_adapters()? + .iter() + .filter_map(|adapter| { + if adapter.adapter_name() == current_interface.name { + Some(adapter.dns_servers()) + } else { + None + } + }) + .flatten() + .for_each(|addr| { + let socket_addr = SocketAddr::new(*addr, 53); + for protocol in [Protocol::Udp, Protocol::Tcp] { + config.add_name_server(NameServerConfig { + socket_addr, + protocol, + tls_dns_name: None, + trust_nx_responses: false, + #[cfg(feature = "rustls")] + tls_config: None, + bind_addr: None, + }) + } + }); + + Ok(TokioAsyncResolver::tokio(config, opts)?) + } +}