From dfd65f7fe88e55b6e013c980012c2d14d46d6314 Mon Sep 17 00:00:00 2001 From: ivulit Date: Thu, 26 Feb 2026 13:11:40 +0300 Subject: [PATCH] fix: send PROXY protocol header during TLS emulation fetch --- src/main.rs | 3 +++ src/tls_front/fetcher.rs | 26 +++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index c2b8c34..e4f7a79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -474,6 +474,7 @@ async fn main() -> std::result::Result<(), Box> { &domain, Duration::from_secs(5), Some(upstream_manager.clone()), + config.censorship.mask_proxy_protocol, ) .await { @@ -486,6 +487,7 @@ async fn main() -> std::result::Result<(), Box> { let cache_clone = cache.clone(); let domains = tls_domains.clone(); let upstream_for_task = upstream_manager.clone(); + let proxy_protocol = config.censorship.mask_proxy_protocol; tokio::spawn(async move { loop { let base_secs = rand::rng().random_range(4 * 3600..=6 * 3600); @@ -498,6 +500,7 @@ async fn main() -> std::result::Result<(), Box> { domain, Duration::from_secs(5), Some(upstream_for_task.clone()), + proxy_protocol, ) .await { diff --git a/src/tls_front/fetcher.rs b/src/tls_front/fetcher.rs index 7ac4b42..561d4cc 100644 --- a/src/tls_front/fetcher.rs +++ b/src/tls_front/fetcher.rs @@ -19,6 +19,7 @@ use x509_parser::certificate::X509Certificate; use crate::crypto::SecureRandom; use crate::protocol::constants::{TLS_RECORD_APPLICATION, TLS_RECORD_HANDSHAKE}; +use crate::transport::proxy_protocol::{ProxyProtocolV1Builder, ProxyProtocolV2Builder}; use crate::tls_front::types::{ ParsedCertificateInfo, ParsedServerHello, @@ -366,6 +367,7 @@ async fn fetch_via_raw_tls( port: u16, sni: &str, connect_timeout: Duration, + proxy_protocol: u8, ) -> Result { let addr = format!("{host}:{port}"); let mut stream = timeout(connect_timeout, TcpStream::connect(addr)).await??; @@ -373,6 +375,13 @@ async fn fetch_via_raw_tls( let rng = SecureRandom::new(); let client_hello = build_client_hello(sni, &rng); timeout(connect_timeout, async { + if proxy_protocol > 0 { + let header = match proxy_protocol { + 2 => ProxyProtocolV2Builder::new().build(), + _ => ProxyProtocolV1Builder::new().build(), + }; + stream.write_all(&header).await?; + } stream.write_all(&client_hello).await?; stream.flush().await?; Ok::<(), std::io::Error>(()) @@ -424,9 +433,10 @@ async fn fetch_via_rustls( sni: &str, connect_timeout: Duration, upstream: Option>, + proxy_protocol: u8, ) -> Result { // rustls handshake path for certificate and basic negotiated metadata. - let stream = if let Some(manager) = upstream { + let mut stream = if let Some(manager) = upstream { // Resolve host to SocketAddr if let Ok(mut addrs) = tokio::net::lookup_host((host, port)).await { if let Some(addr) = addrs.find(|a| a.is_ipv4()) { @@ -447,6 +457,15 @@ async fn fetch_via_rustls( timeout(connect_timeout, TcpStream::connect((host, port))).await?? }; + if proxy_protocol > 0 { + let header = match proxy_protocol { + 2 => ProxyProtocolV2Builder::new().build(), + _ => ProxyProtocolV1Builder::new().build(), + }; + stream.write_all(&header).await?; + stream.flush().await?; + } + let config = build_client_config(); let connector = TlsConnector::from(config); @@ -527,8 +546,9 @@ pub async fn fetch_real_tls( sni: &str, connect_timeout: Duration, upstream: Option>, + proxy_protocol: u8, ) -> Result { - let raw_result = match fetch_via_raw_tls(host, port, sni, connect_timeout).await { + let raw_result = match fetch_via_raw_tls(host, port, sni, connect_timeout, proxy_protocol).await { Ok(res) => Some(res), Err(e) => { warn!(sni = %sni, error = %e, "Raw TLS fetch failed"); @@ -536,7 +556,7 @@ pub async fn fetch_real_tls( } }; - match fetch_via_rustls(host, port, sni, connect_timeout, upstream).await { + match fetch_via_rustls(host, port, sni, connect_timeout, upstream, proxy_protocol).await { Ok(rustls_result) => { if let Some(mut raw) = raw_result { raw.cert_info = rustls_result.cert_info;