diff --git a/Cargo.toml b/Cargo.toml index fb925bde..74855378 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,7 @@ proxmox-compression = "0.2" proxmox-config-digest = "0.1.0" proxmox-daemon = "0.1.0" proxmox-fuse = "0.1.3" -proxmox-http = { version = "0.9.0", features = [ "client", "http-helpers", "websocket" ] } # see below +proxmox-http = { version = "0.9.5", features = [ "client", "http-helpers", "websocket" ] } # see below proxmox-human-byte = "0.1" proxmox-io = "1.0.1" # tools and client use "tokio" feature proxmox-lang = "1.1" @@ -127,6 +127,7 @@ futures = "0.3" h2 = { version = "0.4", features = [ "legacy", "stream" ] } handlebars = "3.0" hex = "0.4.3" +hickory-resolver = { version = "0.24.1", default-features = false, features = [ "system-config", "tokio-runtime" ] } hyper = { version = "0.14", features = [ "backports", "deprecated", "full" ] } libc = "0.2" log = "0.4.17" diff --git a/debian/control b/debian/control index b8f7cfa4..f5044bd9 100644 --- a/debian/control +++ b/debian/control @@ -61,14 +61,14 @@ Build-Depends: bash-completion, librust-proxmox-config-digest-0.1+default-dev, librust-proxmox-daemon-0.1+default-dev, librust-proxmox-fuse-0.1+default-dev (>= 0.1.3-~~), - librust-proxmox-http-0.9+client-dev, - librust-proxmox-http-0.9+client-trait-dev, - librust-proxmox-http-0.9+default-dev, - librust-proxmox-http-0.9+http-helpers-dev, - librust-proxmox-http-0.9+proxmox-async-dev, - librust-proxmox-http-0.9+rate-limited-stream-dev, - librust-proxmox-http-0.9+rate-limiter-dev, - librust-proxmox-http-0.9+websocket-dev, + librust-proxmox-http-0.9+client-dev (>= 0.9.5-~~), + librust-proxmox-http-0.9+client-trait-dev (>= 0.9.5-~~), + librust-proxmox-http-0.9+default-dev (>= 0.9.5-~~), + librust-proxmox-http-0.9+http-helpers-dev (>= 0.9.5-~~), + librust-proxmox-http-0.9+proxmox-async-dev (>= 0.9.5-~~), + librust-proxmox-http-0.9+rate-limited-stream-dev (>= 0.9.5-~~), + librust-proxmox-http-0.9+rate-limiter-dev (>= 0.9.5-~~), + librust-proxmox-http-0.9+websocket-dev (>= 0.9.5-~~), librust-proxmox-human-byte-0.1+default-dev, librust-proxmox-io-1+default-dev (>= 1.0.1-~~), librust-proxmox-io-1+tokio-dev (>= 1.0.1-~~), diff --git a/pbs-client/Cargo.toml b/pbs-client/Cargo.toml index c28fe87c..b4f78b5f 100644 --- a/pbs-client/Cargo.toml +++ b/pbs-client/Cargo.toml @@ -27,6 +27,7 @@ tokio = { workspace = true, features = [ "fs", "signal" ] } tokio-stream.workspace = true tower-service.workspace = true xdg.workspace = true +hickory-resolver.workspace = true pathpatterns.workspace = true diff --git a/pbs-client/src/http_client.rs b/pbs-client/src/http_client.rs index 8a89031c..c95def07 100644 --- a/pbs-client/src/http_client.rs +++ b/pbs-client/src/http_client.rs @@ -4,6 +4,8 @@ use std::time::Duration; use anyhow::{bail, format_err, Error}; use futures::*; +#[cfg(not(target_feature = "crt-static"))] +use hyper::client::connect::dns::GaiResolver; use hyper::client::{Client, HttpConnector}; use hyper::http::header::HeaderValue; use hyper::http::Uri; @@ -33,6 +35,74 @@ use pbs_api_types::{Authid, RateLimitConfig, Userid}; use super::pipe_to_stream::PipeToSendStream; use super::PROXMOX_BACKUP_TCP_KEEPALIVE_TIME; +#[cfg(not(target_feature = "crt-static"))] +type DnsResolver = GaiResolver; + +#[cfg(target_feature = "crt-static")] +type DnsResolver = resolver::HickoryDnsResolver; + +#[cfg(target_feature = "crt-static")] +mod resolver { + use std::net::SocketAddr; + use std::pin::Pin; + use std::sync::Arc; + use std::task::{Context, Poll}; + + use futures::Future; + use hickory_resolver::error::ResolveError; + use hickory_resolver::lookup_ip::LookupIpIntoIter; + use hickory_resolver::TokioAsyncResolver; + use hyper::client::connect::dns::Name; + use tower_service::Service; + + pub(crate) struct SocketAddrIter { + inner: LookupIpIntoIter, + } + + impl Iterator for SocketAddrIter { + type Item = SocketAddr; + + fn next(&mut self) -> Option { + self.inner.next().map(|ip_addr| SocketAddr::new(ip_addr, 0)) + } + } + + #[derive(Clone)] + pub(crate) struct HickoryDnsResolver { + inner: Arc, + } + + impl HickoryDnsResolver { + pub(crate) fn new() -> Self { + Self { + inner: Arc::new(TokioAsyncResolver::tokio_from_system_conf().unwrap()), + } + } + } + + impl Service for HickoryDnsResolver { + type Response = SocketAddrIter; + type Error = ResolveError; + type Future = Pin> + Send>>; + + fn poll_ready(&mut self, _ctx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, name: Name) -> Self::Future { + let inner = self.inner.clone(); + Box::pin(async move { + inner + .lookup_ip(name.as_str()) + .await + .map(|r| SocketAddrIter { + inner: r.into_iter(), + }) + }) + } + } +} + /// Timeout used for several HTTP operations that are expected to finish quickly but may block in /// certain error conditions. Keep it generous, to avoid false-positive under high load. const HTTP_TIMEOUT: Duration = Duration::from_secs(2 * 60); @@ -134,7 +204,7 @@ impl Default for HttpClientOptions { /// HTTP(S) API client pub struct HttpClient { - client: Client, + client: Client>, server: String, port: u16, fingerprint: Arc>>, @@ -365,7 +435,8 @@ impl HttpClient { ssl_connector_builder.set_verify(openssl::ssl::SslVerifyMode::NONE); } - let mut httpc = HttpConnector::new(); + let resolver = DnsResolver::new(); + let mut httpc = HttpConnector::new_with_resolver(resolver); httpc.set_nodelay(true); // important for h2 download performance! httpc.enforce_http(false); // we want https... @@ -526,7 +597,9 @@ impl HttpClient { _options: options, }) } +} +impl HttpClient { /// Login /// /// Login is done on demand, so this is only required if you need @@ -814,7 +887,7 @@ impl HttpClient { } async fn credentials( - client: Client, + client: Client>, server: String, port: u16, username: Userid, @@ -859,7 +932,7 @@ impl HttpClient { } async fn api_request( - client: Client, + client: Client>, req: Request, ) -> Result { Self::api_response(