From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 8D8421FF16F for ; Tue, 19 Aug 2025 13:53:10 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 3AFB7133CD; Tue, 19 Aug 2025 13:54:55 +0200 (CEST) Date: Tue, 19 Aug 2025 13:54:51 +0200 Message-Id: To: "Proxmox Datacenter Manager development discussion" , "Dominik Csapak" From: "Lukas Wagner" Mime-Version: 1.0 X-Mailer: aerc 0.20.1-0-g2ecb8770224a References: <20250516133611.3499075-1-d.csapak@proxmox.com> <20250516133611.3499075-4-d.csapak@proxmox.com> In-Reply-To: <20250516133611.3499075-4-d.csapak@proxmox.com> X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1755604449475 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.022 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [connection.rs] Subject: Re: [pdm-devel] [PATCH datacenter-manager 03/21] server: connection: add probe_tls_connection helper X-BeenThere: pdm-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Datacenter Manager development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Datacenter Manager development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pdm-devel-bounces@lists.proxmox.com Sender: "pdm-devel" Hey, looks mostly good, two suggestions inline. On Fri May 16, 2025 at 3:35 PM CEST, Dominik Csapak wrote: > this is intended to help us probe a remote/host before using it to check > whether the tls connection is working fine, or it returns the > certificate information so we can show it to the user. > > Signed-off-by: Dominik Csapak > --- > server/src/connection.rs | 79 ++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 79 insertions(+) > > diff --git a/server/src/connection.rs b/server/src/connection.rs > index 0be9033..c7b2558 100644 > --- a/server/src/connection.rs > +++ b/server/src/connection.rs > @@ -15,8 +15,10 @@ use std::time::{Duration, SystemTime}; > use anyhow::{bail, format_err, Error}; > use http::uri::Authority; > use http::Method; > +use openssl::x509::X509StoreContextRef; > use serde::Serialize; > > +use proxmox_acme_api::CertificateInfo; > use proxmox_client::{Client, HttpApiClient, HttpApiResponse, HttpApiResponseStream, TlsOptions}; > > use pdm_api_types::remotes::{NodeUrl, Remote, RemoteType}; > @@ -799,3 +801,80 @@ impl HttpApiClient for MultiClient { > try_request! { self, method, path_and_query, params, streaming_request } > } > } > + > +/// Checks TLS connection to the given remote > +/// > +/// Returns `Ok(None)` if connecting with the given parameters works > +/// Returns `Ok(Some(cert))` if no fingerprint was given and some certificate could not be validated > +/// Returns `Err(err)` if some other error occurred The intent could be maybe a bit more clear if you used some kind of enum instead of the Option: e.g. enum ProbeOutcome { Success, UntrustedCertificate(CertificateInfo), } (Maybe there's a better name than 'Success' for the first variant, this is just what came to mind right now). > +/// > +/// # Example > +/// > +/// ``` > +/// use server::connection::probe_tls_connection; > +/// use pdm_api_types::remotes::RemoteType; > +/// > +/// # async fn function() { > +/// let result = probe_tls_connection(RemoteType::Pve, "192.168.2.100".to_string(), None).await; > +/// match result { > +/// Ok(None) => { /* everything ok */ }, > +/// Ok(Some(cert)) => { /* do something with cert */ }, > +/// Err(err) => { /* do something with error */ }, > +/// } > +/// # } > +/// ``` > +pub async fn probe_tls_connection( > + remote_type: RemoteType, > + hostname: String, > + fingerprint: Option, > +) -> Result, Error> { > + let host_port: Authority = hostname.parse()?; > + > + let uri: http::uri::Uri = format!( > + "https://{}:{}", > + host_port.host(), > + host_port.port_u16().unwrap_or(remote_type.default_port()) > + ) > + .parse()?; > + > + // to save the invalid cert we find > + let invalid_cert = Arc::new(StdMutex::new(None)); > + > + let options = if let Some(fp) = &fingerprint { > + TlsOptions::parse_fingerprint(fp)? > + } else { > + TlsOptions::Callback(Box::new({ > + let invalid_cert = invalid_cert.clone(); > + move |valid: bool, chain: &mut X509StoreContextRef| { > + if let Some(cert) = chain.current_cert() { > + if !valid { > + let cert = cert.to_pem().map(|pem| CertificateInfo::from_pem("", &pem)); > + *invalid_cert.lock().unwrap() = Some(cert); > + } > + } > + true > + } > + })) > + }; > + let client = proxmox_client::Client::with_options(uri, options, Default::default())?; > + > + // set fake auth info. we don't need any, but the proxmox client will return unauthenticated if > + // none is set. > + client.set_authentication(proxmox_client::Token { > + userid: "".to_string(), > + value: "".to_string(), > + prefix: "".to_string(), > + perl_compat: false, > + }); > + > + client.request(Method::GET, "/", None::<()>).await?; > + > + let cert = invalid_cert.lock().unwrap().take(); > + if let Some(cert) = cert { > + let cert = cert?; > + let cert = cert?; I think doing a let cert = cert??; or Ok(Some(cert??)) is better here. Otherwise it reads a bit like a copy-paste mistake. > + Ok(Some(cert)) > + } else { > + Ok(None) > + } > +} _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel