diff --git a/Cargo.lock b/Cargo.lock index bdbb295..fc59b94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1600,6 +1600,8 @@ dependencies = [ "reqwest", "reqwest-middleware", "rlimit", + "rustls", + "rustls-platform-verifier", "serde", "serde_json", "smallvec", diff --git a/Cargo.toml b/Cargo.toml index a12ec61..334401c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,13 @@ ratatui = { version = "=0.30.0", default-features = false, features = [ ], optional = true } reqwest = { version = "=0.13.1", features = ["brotli", "gzip", "socks"] } reqwest-middleware = "=0.5.0" +rustls = { version = "=0.23.36", default-features = false, features = [ + "aws_lc_rs", + "prefer-post-quantum", + "std", + "tls12", +] } +rustls-platform-verifier = "=0.6.2" rlimit = "=0.10.2" serde = "=1.0.228" serde_json = "=1.0.149" diff --git a/src/checker.rs b/src/checker.rs index a409a47..98655f5 100644 --- a/src/checker.rs +++ b/src/checker.rs @@ -10,6 +10,7 @@ pub async fn check_all( config: Arc, dns_resolver: R, proxies: Vec, + mut tls_backend: rustls::ClientConfig, token: tokio_util::sync::CancellationToken, #[cfg(feature = "tui")] tx: tokio::sync::mpsc::UnboundedSender, ) -> crate::Result> { @@ -29,11 +30,14 @@ pub async fn check_all( let queue = Arc::new(parking_lot::Mutex::new(proxies)); let checked_proxies = Arc::new(parking_lot::Mutex::new(Vec::new())); + tls_backend.alpn_protocols = vec![b"http/1.1".to_vec()]; + let mut join_set = tokio::task::JoinSet::<()>::new(); for _ in 0..workers_count { let queue = Arc::clone(&queue); let config = Arc::clone(&config); let dns_resolver = dns_resolver.clone(); + let tls_backend = tls_backend.clone(); let checked_proxies = Arc::clone(&checked_proxies); let token = token.clone(); #[cfg(feature = "tui")] @@ -46,7 +50,7 @@ pub async fn check_all( let Some(mut proxy) = queue.lock().pop() else { break; }; - let check_result = proxy.check(&config, dns_resolver.clone()).await; + let check_result = proxy.check(&config, dns_resolver.clone(), tls_backend.clone()).await; #[cfg(feature = "tui")] drop(tx.send(Event::App(AppEvent::ProxyChecked(proxy.protocol)))); match check_result { @@ -74,6 +78,7 @@ pub async fn check_all( drop(config); drop(dns_resolver); drop(queue); + drop(tls_backend); drop(token); #[cfg(feature = "tui")] drop(tx); diff --git a/src/http.rs b/src/http.rs index e5f7618..67fe084 100644 --- a/src/http.rs +++ b/src/http.rs @@ -64,6 +64,18 @@ impl reqwest::dns::Resolve for HickoryDnsResolver { } } +pub fn build_rustls_config() -> crate::Result { + let provider = Arc::new(rustls::crypto::aws_lc_rs::default_provider()); + + Ok(rustls::ClientConfig::builder_with_provider(Arc::clone(&provider)) + .with_protocol_versions(rustls::ALL_VERSIONS)? + .dangerous() + .with_custom_certificate_verifier(Arc::new( + rustls_platform_verifier::Verifier::new(provider)?, + )) + .with_no_client_auth()) +} + fn parse_retry_after(headers: &reqwest::header::HeaderMap) -> Option { if let Some(val) = headers.get("retry-after-ms") && let Ok(s) = val.to_str() @@ -165,11 +177,14 @@ impl reqwest_middleware::Middleware for RetryMiddleware { pub fn create_reqwest_client( config: &Config, dns_resolver: R, -) -> reqwest::Result { + mut tls_backend: rustls::ClientConfig, +) -> crate::Result { + tls_backend.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; let mut builder = reqwest::ClientBuilder::new() .user_agent(config.scraping.user_agent.as_bytes()) .timeout(config.scraping.timeout) .connect_timeout(config.scraping.connect_timeout) + .tls_backend_preconfigured(tls_backend) .dns_resolver(dns_resolver); if let Some(proxy) = config.scraping.proxy.clone() { diff --git a/src/main.rs b/src/main.rs index 3714b0e..2a293a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -172,8 +172,13 @@ async fn main_task( >, ) -> crate::Result<()> { let dns_resolver = http::HickoryDnsResolver::new().await?; - let http_client = - http::create_reqwest_client(&config, dns_resolver.clone())?; + let tls_backend = http::build_rustls_config()?; + + let http_client = http::create_reqwest_client( + &config, + dns_resolver.clone(), + tls_backend.clone(), + )?; let ((), mut proxies) = tokio::try_join!( download_output_dependencies( @@ -196,6 +201,7 @@ async fn main_task( Arc::clone(&config), dns_resolver, proxies, + tls_backend, token, #[cfg(feature = "tui")] tx.clone(), diff --git a/src/proxy.rs b/src/proxy.rs index c3f48da..f44cb3a 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -126,6 +126,7 @@ impl Proxy { &mut self, config: &Config, dns_resolver: R, + tls_backend: rustls::ClientConfig, ) -> crate::Result<()> { if let Some(check_url) = config.checking.check_url.clone() { let builder = reqwest::ClientBuilder::new() @@ -139,6 +140,7 @@ impl Proxy { .tcp_keepalive(None) .tcp_keepalive_interval(Duration::ZERO) .tcp_keepalive_retries(0) + .tls_backend_preconfigured(tls_backend) .dns_resolver(dns_resolver); #[cfg(any( target_os = "android",