fix: send PROXY protocol header during TLS emulation fetch

This commit is contained in:
ivulit 2026-02-26 13:11:40 +03:00
parent 47f4bd24ef
commit dfd65f7fe8
No known key found for this signature in database
2 changed files with 26 additions and 3 deletions

View File

@ -474,6 +474,7 @@ async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
&domain, &domain,
Duration::from_secs(5), Duration::from_secs(5),
Some(upstream_manager.clone()), Some(upstream_manager.clone()),
config.censorship.mask_proxy_protocol,
) )
.await .await
{ {
@ -486,6 +487,7 @@ async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
let cache_clone = cache.clone(); let cache_clone = cache.clone();
let domains = tls_domains.clone(); let domains = tls_domains.clone();
let upstream_for_task = upstream_manager.clone(); let upstream_for_task = upstream_manager.clone();
let proxy_protocol = config.censorship.mask_proxy_protocol;
tokio::spawn(async move { tokio::spawn(async move {
loop { loop {
let base_secs = rand::rng().random_range(4 * 3600..=6 * 3600); let base_secs = rand::rng().random_range(4 * 3600..=6 * 3600);
@ -498,6 +500,7 @@ async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
domain, domain,
Duration::from_secs(5), Duration::from_secs(5),
Some(upstream_for_task.clone()), Some(upstream_for_task.clone()),
proxy_protocol,
) )
.await .await
{ {

View File

@ -19,6 +19,7 @@ use x509_parser::certificate::X509Certificate;
use crate::crypto::SecureRandom; use crate::crypto::SecureRandom;
use crate::protocol::constants::{TLS_RECORD_APPLICATION, TLS_RECORD_HANDSHAKE}; use crate::protocol::constants::{TLS_RECORD_APPLICATION, TLS_RECORD_HANDSHAKE};
use crate::transport::proxy_protocol::{ProxyProtocolV1Builder, ProxyProtocolV2Builder};
use crate::tls_front::types::{ use crate::tls_front::types::{
ParsedCertificateInfo, ParsedCertificateInfo,
ParsedServerHello, ParsedServerHello,
@ -366,6 +367,7 @@ async fn fetch_via_raw_tls(
port: u16, port: u16,
sni: &str, sni: &str,
connect_timeout: Duration, connect_timeout: Duration,
proxy_protocol: u8,
) -> Result<TlsFetchResult> { ) -> Result<TlsFetchResult> {
let addr = format!("{host}:{port}"); let addr = format!("{host}:{port}");
let mut stream = timeout(connect_timeout, TcpStream::connect(addr)).await??; 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 rng = SecureRandom::new();
let client_hello = build_client_hello(sni, &rng); let client_hello = build_client_hello(sni, &rng);
timeout(connect_timeout, async { 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.write_all(&client_hello).await?;
stream.flush().await?; stream.flush().await?;
Ok::<(), std::io::Error>(()) Ok::<(), std::io::Error>(())
@ -424,9 +433,10 @@ async fn fetch_via_rustls(
sni: &str, sni: &str,
connect_timeout: Duration, connect_timeout: Duration,
upstream: Option<std::sync::Arc<crate::transport::UpstreamManager>>, upstream: Option<std::sync::Arc<crate::transport::UpstreamManager>>,
proxy_protocol: u8,
) -> Result<TlsFetchResult> { ) -> Result<TlsFetchResult> {
// rustls handshake path for certificate and basic negotiated metadata. // 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 // Resolve host to SocketAddr
if let Ok(mut addrs) = tokio::net::lookup_host((host, port)).await { if let Ok(mut addrs) = tokio::net::lookup_host((host, port)).await {
if let Some(addr) = addrs.find(|a| a.is_ipv4()) { 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?? 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 config = build_client_config();
let connector = TlsConnector::from(config); let connector = TlsConnector::from(config);
@ -527,8 +546,9 @@ pub async fn fetch_real_tls(
sni: &str, sni: &str,
connect_timeout: Duration, connect_timeout: Duration,
upstream: Option<std::sync::Arc<crate::transport::UpstreamManager>>, upstream: Option<std::sync::Arc<crate::transport::UpstreamManager>>,
proxy_protocol: u8,
) -> Result<TlsFetchResult> { ) -> Result<TlsFetchResult> {
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), Ok(res) => Some(res),
Err(e) => { Err(e) => {
warn!(sni = %sni, error = %e, "Raw TLS fetch failed"); 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) => { Ok(rustls_result) => {
if let Some(mut raw) = raw_result { if let Some(mut raw) = raw_result {
raw.cert_info = rustls_result.cert_info; raw.cert_info = rustls_result.cert_info;