mirror of
https://git.proxmox.com/git/proxmox-backup
synced 2025-04-30 12:34:21 +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-config-digest = "0.1.0"
|
||||||
proxmox-daemon = "0.1.0"
|
proxmox-daemon = "0.1.0"
|
||||||
proxmox-fuse = "0.1.3"
|
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-human-byte = "0.1"
|
||||||
proxmox-io = "1.0.1" # tools and client use "tokio" feature
|
proxmox-io = "1.0.1" # tools and client use "tokio" feature
|
||||||
proxmox-lang = "1.1"
|
proxmox-lang = "1.1"
|
||||||
@ -127,6 +127,7 @@ futures = "0.3"
|
|||||||
h2 = { version = "0.4", features = [ "legacy", "stream" ] }
|
h2 = { version = "0.4", features = [ "legacy", "stream" ] }
|
||||||
handlebars = "3.0"
|
handlebars = "3.0"
|
||||||
hex = "0.4.3"
|
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" ] }
|
hyper = { version = "0.14", features = [ "backports", "deprecated", "full" ] }
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = "0.4.17"
|
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-config-digest-0.1+default-dev,
|
||||||
librust-proxmox-daemon-0.1+default-dev,
|
librust-proxmox-daemon-0.1+default-dev,
|
||||||
librust-proxmox-fuse-0.1+default-dev (>= 0.1.3-~~),
|
librust-proxmox-fuse-0.1+default-dev (>= 0.1.3-~~),
|
||||||
librust-proxmox-http-0.9+client-dev,
|
librust-proxmox-http-0.9+client-dev (>= 0.9.5-~~),
|
||||||
librust-proxmox-http-0.9+client-trait-dev,
|
librust-proxmox-http-0.9+client-trait-dev (>= 0.9.5-~~),
|
||||||
librust-proxmox-http-0.9+default-dev,
|
librust-proxmox-http-0.9+default-dev (>= 0.9.5-~~),
|
||||||
librust-proxmox-http-0.9+http-helpers-dev,
|
librust-proxmox-http-0.9+http-helpers-dev (>= 0.9.5-~~),
|
||||||
librust-proxmox-http-0.9+proxmox-async-dev,
|
librust-proxmox-http-0.9+proxmox-async-dev (>= 0.9.5-~~),
|
||||||
librust-proxmox-http-0.9+rate-limited-stream-dev,
|
librust-proxmox-http-0.9+rate-limited-stream-dev (>= 0.9.5-~~),
|
||||||
librust-proxmox-http-0.9+rate-limiter-dev,
|
librust-proxmox-http-0.9+rate-limiter-dev (>= 0.9.5-~~),
|
||||||
librust-proxmox-http-0.9+websocket-dev,
|
librust-proxmox-http-0.9+websocket-dev (>= 0.9.5-~~),
|
||||||
librust-proxmox-human-byte-0.1+default-dev,
|
librust-proxmox-human-byte-0.1+default-dev,
|
||||||
librust-proxmox-io-1+default-dev (>= 1.0.1-~~),
|
librust-proxmox-io-1+default-dev (>= 1.0.1-~~),
|
||||||
librust-proxmox-io-1+tokio-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
|
tokio-stream.workspace = true
|
||||||
tower-service.workspace = true
|
tower-service.workspace = true
|
||||||
xdg.workspace = true
|
xdg.workspace = true
|
||||||
|
hickory-resolver.workspace = true
|
||||||
|
|
||||||
pathpatterns.workspace = true
|
pathpatterns.workspace = true
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
use futures::*;
|
use futures::*;
|
||||||
|
#[cfg(not(target_feature = "crt-static"))]
|
||||||
|
use hyper::client::connect::dns::GaiResolver;
|
||||||
use hyper::client::{Client, HttpConnector};
|
use hyper::client::{Client, HttpConnector};
|
||||||
use hyper::http::header::HeaderValue;
|
use hyper::http::header::HeaderValue;
|
||||||
use hyper::http::Uri;
|
use hyper::http::Uri;
|
||||||
@ -33,6 +35,74 @@ use pbs_api_types::{Authid, RateLimitConfig, Userid};
|
|||||||
use super::pipe_to_stream::PipeToSendStream;
|
use super::pipe_to_stream::PipeToSendStream;
|
||||||
use super::PROXMOX_BACKUP_TCP_KEEPALIVE_TIME;
|
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
|
/// 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.
|
/// certain error conditions. Keep it generous, to avoid false-positive under high load.
|
||||||
const HTTP_TIMEOUT: Duration = Duration::from_secs(2 * 60);
|
const HTTP_TIMEOUT: Duration = Duration::from_secs(2 * 60);
|
||||||
@ -134,7 +204,7 @@ impl Default for HttpClientOptions {
|
|||||||
|
|
||||||
/// HTTP(S) API client
|
/// HTTP(S) API client
|
||||||
pub struct HttpClient {
|
pub struct HttpClient {
|
||||||
client: Client<HttpsConnector>,
|
client: Client<HttpsConnector<DnsResolver>>,
|
||||||
server: String,
|
server: String,
|
||||||
port: u16,
|
port: u16,
|
||||||
fingerprint: Arc<Mutex<Option<String>>>,
|
fingerprint: Arc<Mutex<Option<String>>>,
|
||||||
@ -365,7 +435,8 @@ impl HttpClient {
|
|||||||
ssl_connector_builder.set_verify(openssl::ssl::SslVerifyMode::NONE);
|
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.set_nodelay(true); // important for h2 download performance!
|
||||||
httpc.enforce_http(false); // we want https...
|
httpc.enforce_http(false); // we want https...
|
||||||
|
|
||||||
@ -526,7 +597,9 @@ impl HttpClient {
|
|||||||
_options: options,
|
_options: options,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HttpClient {
|
||||||
/// Login
|
/// Login
|
||||||
///
|
///
|
||||||
/// Login is done on demand, so this is only required if you need
|
/// Login is done on demand, so this is only required if you need
|
||||||
@ -814,7 +887,7 @@ impl HttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn credentials(
|
async fn credentials(
|
||||||
client: Client<HttpsConnector>,
|
client: Client<HttpsConnector<DnsResolver>>,
|
||||||
server: String,
|
server: String,
|
||||||
port: u16,
|
port: u16,
|
||||||
username: Userid,
|
username: Userid,
|
||||||
@ -859,7 +932,7 @@ impl HttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn api_request(
|
async fn api_request(
|
||||||
client: Client<HttpsConnector>,
|
client: Client<HttpsConnector<DnsResolver>>,
|
||||||
req: Request<Body>,
|
req: Request<Body>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
Self::api_response(
|
Self::api_response(
|
||||||
|
Loading…
Reference in New Issue
Block a user