From: Christian Ebner <c.ebner@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH v2 proxmox-backup 5/5] client: http: Use custom resolver for statically linked binary
Date: Mon, 13 Jan 2025 15:42:26 +0100 [thread overview]
Message-ID: <20250113144226.467408-6-c.ebner@proxmox.com> (raw)
In-Reply-To: <20250113144226.467408-1-c.ebner@proxmox.com>
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>
---
changes since version 1:
- do not depend on Windows subdependencies by registering a dummy crate
Cargo.toml | 3 ++
pbs-client/Cargo.toml | 1 +
pbs-client/src/http_client.rs | 81 +++++++++++++++++++++++++++++++++--
3 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index 9354fb175..98b5b8193 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -161,6 +161,7 @@ walkdir = "2"
xdg = "2.2"
zstd = { version = "0.12", features = [ "bindgen" ] }
zstd-safe = "6.0"
+hickory-resolver = { git = "https://github.com/hickory-dns/hickory-dns", tag = "v0.24.1", default-features = false }
[dependencies]
anyhow.workspace = true
@@ -256,6 +257,8 @@ proxmox-rrd-api-types.workspace = true
# Local path overrides
# NOTE: You must run `cargo update` after changing this for it to take effect!
[patch.crates-io]
+hickory-proto = { git = "https://github.com/hickory-dns/hickory-dns", tag = "v0.24.1" }
+ipconfig = { path = "cargo-stubs/ipconfig", version = "0.3.2" }
#proxmox-apt = { path = "../proxmox/proxmox-apt" }
#proxmox-apt-api-types = { path = "../proxmox/proxmox-apt-api-types" }
diff --git a/pbs-client/Cargo.toml b/pbs-client/Cargo.toml
index 212f62f2a..faa0cffe4 100644
--- a/pbs-client/Cargo.toml
+++ b/pbs-client/Cargo.toml
@@ -28,6 +28,7 @@ tokio = { workspace = true, features = [ "fs", "signal" ] }
tokio-stream.workspace = true
tower-service.workspace = true
xdg.workspace = true
+hickory-resolver = { workspace = true, features = [ "system-config", "tokio-runtime" ] }
pathpatterns.workspace = true
diff --git a/pbs-client/src/http_client.rs b/pbs-client/src/http_client.rs
index e97b4e549..9f3419eb6 100644
--- a/pbs-client/src/http_client.rs
+++ b/pbs-client/src/http_client.rs
@@ -7,6 +7,8 @@ use futures::*;
use http::header::HeaderValue;
use http::Uri;
use http::{Request, Response};
+#[cfg(not(target_feature = "crt-static"))]
+use hyper::client::connect::dns::GaiResolver;
use hyper::client::{Client, HttpConnector};
use hyper::Body;
use openssl::{
@@ -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
@@ -815,7 +888,7 @@ impl HttpClient {
}
async fn credentials(
- client: Client<HttpsConnector>,
+ client: Client<HttpsConnector<DnsResolver>>,
server: String,
port: u16,
username: Userid,
@@ -860,7 +933,7 @@ impl HttpClient {
}
async fn api_request(
- client: Client<HttpsConnector>,
+ client: Client<HttpsConnector<DnsResolver>>,
req: Request<Body>,
) -> Result<Value, Error> {
Self::api_response(
--
2.39.5
_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel
prev parent reply other threads:[~2025-01-13 14:43 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-13 14:42 [pbs-devel] [PATCH v2 proxmox-backup 0/5] fix 4788: statically linked proxmox-backup-client Christian Ebner
2025-01-13 14:42 ` [pbs-devel] [PATCH v2 proxmox 1/1] http: client: make https connector generic over resolver Christian Ebner
2025-01-13 14:42 ` [pbs-devel] [PATCH v2 proxmox-backup 2/5] fix: 4788: Makefile: target for statically linked client binary Christian Ebner
2025-01-13 14:42 ` [pbs-devel] [PATCH v2 proxmox-backup 3/5] Makefile: switch path based on build mode and target Christian Ebner
2025-01-13 14:42 ` [pbs-devel] [PATCH v2 proxmox-backup 4/5] cargo: add stubs for `ipconfig` windows build dependency Christian Ebner
2025-01-13 14:42 ` Christian Ebner [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250113144226.467408-6-c.ebner@proxmox.com \
--to=c.ebner@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox