mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-29 18:12:10 +08:00
refactor(net): reuse webpki tls config and fallback
Extract build_webpki_rooted_tls_config so the delay-test TLS connector and the reqwest clients share one static-webpki-roots builder; ALPN stays caller-specific (only reqwest offers h2). Collapse the duplicated platform-verifier -> static-webpki-roots retry in get/get_bytes into request_with_static_webpki_fallback, gated by the caller's certificate-verification setting.
This commit is contained in:
@@ -14,15 +14,8 @@ use smartstring::alias::String;
|
||||
use std::sync::{Arc, LazyLock};
|
||||
|
||||
#[allow(clippy::expect_used)]
|
||||
static TLS_CONFIG: LazyLock<Arc<rustls::ClientConfig>> = LazyLock::new(|| {
|
||||
let root_store = rustls::RootCertStore::from_iter(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
|
||||
let config = rustls::ClientConfig::builder_with_provider(Arc::new(rustls::crypto::ring::default_provider()))
|
||||
.with_safe_default_protocol_versions()
|
||||
.expect("Failed to set TLS versions")
|
||||
.with_root_certificates(root_store)
|
||||
.with_no_client_auth();
|
||||
Arc::new(config)
|
||||
});
|
||||
static TLS_CONFIG: LazyLock<Arc<rustls::ClientConfig>> =
|
||||
LazyLock::new(|| Arc::new(utils::network::build_webpki_rooted_tls_config().expect("Failed to set TLS versions")));
|
||||
|
||||
pub async fn restart_clash_core() {
|
||||
match CoreManager::global().restart_core().await {
|
||||
|
||||
@@ -48,6 +48,17 @@ enum TlsRootMode {
|
||||
StaticWebpkiRoots,
|
||||
}
|
||||
|
||||
/// ALPN stays unset: raw TLS connectors offer none, while reqwest needs the h2 offer.
|
||||
pub(crate) fn build_webpki_rooted_tls_config() -> Result<rustls::ClientConfig> {
|
||||
let root_store = rustls::RootCertStore::from_iter(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
|
||||
let config = rustls::ClientConfig::builder_with_provider(Arc::new(rustls::crypto::ring::default_provider()))
|
||||
.with_safe_default_protocol_versions()?
|
||||
.with_root_certificates(root_store)
|
||||
.with_no_client_auth();
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub struct NetworkManager;
|
||||
|
||||
impl NetworkManager {
|
||||
@@ -102,13 +113,7 @@ impl NetworkManager {
|
||||
}
|
||||
|
||||
fn build_static_webpki_tls_config() -> Result<rustls::ClientConfig> {
|
||||
let root_store = rustls::RootCertStore::from_iter(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
|
||||
let mut config =
|
||||
rustls::ClientConfig::builder_with_provider(Arc::new(rustls::crypto::ring::default_provider()))
|
||||
.with_safe_default_protocol_versions()?
|
||||
.with_root_certificates(root_store)
|
||||
.with_no_client_auth();
|
||||
|
||||
let mut config = build_webpki_rooted_tls_config()?;
|
||||
config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
|
||||
|
||||
Ok(config)
|
||||
@@ -155,6 +160,23 @@ impl NetworkManager {
|
||||
detail.contains("protocolversion") || detail.contains("protocol version")
|
||||
}
|
||||
|
||||
/// `allow_fallback` stays false when the caller already disabled certificate verification.
|
||||
async fn request_with_static_webpki_fallback<T, F, Fut>(allow_fallback: bool, mut request: F) -> Result<T>
|
||||
where
|
||||
F: FnMut(TlsRootMode) -> Fut,
|
||||
Fut: std::future::Future<Output = Result<T>>,
|
||||
{
|
||||
match request(TlsRootMode::PlatformVerifier).await {
|
||||
Ok(value) => Ok(value),
|
||||
Err(err) if allow_fallback && Self::should_retry_with_static_webpki_roots(&err) => {
|
||||
request(TlsRootMode::StaticWebpkiRoots).await.map_err(|fallback_err| {
|
||||
fallback_err.context("static webpki roots fallback failed after platform TLS verifier failed")
|
||||
})
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_with_tls_mode(
|
||||
&self,
|
||||
url: &str,
|
||||
@@ -264,34 +286,21 @@ impl NetworkManager {
|
||||
user_agent: Option<String>,
|
||||
accept_invalid_certs: bool,
|
||||
) -> Result<HttpResponse> {
|
||||
let platform_result = self
|
||||
.get_with_tls_mode(
|
||||
url,
|
||||
proxy_type,
|
||||
timeout_secs,
|
||||
user_agent.clone(),
|
||||
accept_invalid_certs,
|
||||
TlsRootMode::PlatformVerifier,
|
||||
)
|
||||
.await;
|
||||
|
||||
match platform_result {
|
||||
Ok(response) => Ok(response),
|
||||
Err(err) if !accept_invalid_certs && Self::should_retry_with_static_webpki_roots(&err) => self
|
||||
.get_with_tls_mode(
|
||||
Self::request_with_static_webpki_fallback(!accept_invalid_certs, |tls_root_mode| {
|
||||
let user_agent = user_agent.clone();
|
||||
async move {
|
||||
self.get_with_tls_mode(
|
||||
url,
|
||||
proxy_type,
|
||||
timeout_secs,
|
||||
user_agent,
|
||||
accept_invalid_certs,
|
||||
TlsRootMode::StaticWebpkiRoots,
|
||||
tls_root_mode,
|
||||
)
|
||||
.await
|
||||
.map_err(|fallback_err| {
|
||||
fallback_err.context("static webpki roots fallback failed after platform TLS verifier failed")
|
||||
}),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_bytes_with_tls_mode(
|
||||
@@ -340,19 +349,10 @@ impl NetworkManager {
|
||||
timeout_secs: Option<u64>,
|
||||
max_bytes: usize,
|
||||
) -> Result<Vec<u8>> {
|
||||
let platform_result = self
|
||||
.get_bytes_with_tls_mode(url, proxy_type, timeout_secs, max_bytes, TlsRootMode::PlatformVerifier)
|
||||
.await;
|
||||
|
||||
match platform_result {
|
||||
Ok(body) => Ok(body),
|
||||
Err(err) if Self::should_retry_with_static_webpki_roots(&err) => self
|
||||
.get_bytes_with_tls_mode(url, proxy_type, timeout_secs, max_bytes, TlsRootMode::StaticWebpkiRoots)
|
||||
Self::request_with_static_webpki_fallback(true, |tls_root_mode| async move {
|
||||
self.get_bytes_with_tls_mode(url, proxy_type, timeout_secs, max_bytes, tls_root_mode)
|
||||
.await
|
||||
.map_err(|fallback_err| {
|
||||
fallback_err.context("static webpki roots fallback failed after platform TLS verifier failed")
|
||||
}),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user