mirror of
https://git.proxmox.com/git/proxmox-backup
synced 2025-04-28 05:44:39 +00:00
client: http: Use custom resolver for statically linked binary
The dependency on the `getaddrinfo` based `GaiResolver` used by default for the `HttpClient` is not suitable for the statically linked binary of the `proxmox-backup-client`, because of the dependency on glibc NSS libraries, as described in glibc's FAQs [0]. As a workaround, conditionally compile the binary using the `hickory-dns` resolver. [0] https://sourceware.org/glibc/wiki/FAQ#Even_statically_linked_programs_need_some_shared_libraries_which_is_not_acceptable_for_me.__What_can_I_do.3F Suggested-by: Thomas Lamprecht <t.lamprecht@proxmox.com> Signed-off-by: Christian Ebner <c.ebner@proxmox.com> Tested-by: Lukas Wagner <l.wagner@proxmox.com> FG: bump proxmox-http dependency Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
This commit is contained in:
parent
601a84ae74
commit
83e7b9de88
@ -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"
|
||||
|
16
debian/control
vendored
16
debian/control
vendored
@ -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-~~),
|
||||
|
@ -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
|
||||
|
||||
|
@ -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::Item> {
|
||||
self.inner.next().map(|ip_addr| SocketAddr::new(ip_addr, 0))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct HickoryDnsResolver {
|
||||
inner: Arc<TokioAsyncResolver>,
|
||||
}
|
||||
|
||||
impl HickoryDnsResolver {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
inner: Arc::new(TokioAsyncResolver::tokio_from_system_conf().unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Service<Name> for HickoryDnsResolver {
|
||||
type Response = SocketAddrIter;
|
||||
type Error = ResolveError;
|
||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
|
||||
|
||||
fn poll_ready(&mut self, _ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
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<HttpsConnector>,
|
||||
client: Client<HttpsConnector<DnsResolver>>,
|
||||
server: String,
|
||||
port: u16,
|
||||
fingerprint: Arc<Mutex<Option<String>>>,
|
||||
@ -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<HttpsConnector>,
|
||||
client: Client<HttpsConnector<DnsResolver>>,
|
||||
server: String,
|
||||
port: u16,
|
||||
username: Userid,
|
||||
@ -859,7 +932,7 @@ impl HttpClient {
|
||||
}
|
||||
|
||||
async fn api_request(
|
||||
client: Client<HttpsConnector>,
|
||||
client: Client<HttpsConnector<DnsResolver>>,
|
||||
req: Request<Body>,
|
||||
) -> Result<Value, Error> {
|
||||
Self::api_response(
|
||||
|
Loading…
Reference in New Issue
Block a user