fix(xhttp): suppress inherited SNI inside the carrier

Retain the hop identity for certificate verification while restoring the absent default wire SNI for inner protocols. Extend the TLS identity matrix through the XHTTP builder to cover omitted, null, and explicit SNI.
This commit is contained in:
cfal
2026-10-31 13:12:43 +00:00
parent 681db3f4ee
commit e7680ff47e
3 changed files with 28 additions and 12 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ pub(crate) fn tls_verification_name(
rustls::pki_types::ServerName::try_from(identity).map_err(std::io::Error::other)
}
fn create_with_hop_context(
pub(crate) fn create_with_hop_context(
client_proxy_config: ClientProxyConfig,
hop_location: &NetLocation,
default_sni_hostname: Option<String>,
+25 -10
View File
@@ -167,15 +167,20 @@ mod tests {
#[tokio::test]
async fn verification_uses_hop_identity_even_without_wire_sni() {
check_hop_identity(false).await;
check_hop_identity(false, false).await;
}
#[tokio::test]
async fn udp_verification_uses_hop_identity_even_without_wire_sni() {
check_hop_identity(true).await;
check_hop_identity(true, false).await;
}
async fn check_hop_identity(udp: bool) {
#[tokio::test]
async fn xhttp_inner_tls_keeps_hop_identity_without_default_sni() {
check_hop_identity(false, true).await;
}
async fn check_hop_identity(udp: bool, xhttp: bool) {
use crate::address::NetLocation;
use crate::async_stream::{AsyncFlushMessage, AsyncReadMessage, AsyncWriteMessage};
use crate::tcp::tcp_client_handler_factory::create_tcp_client_handler;
@@ -208,7 +213,7 @@ mod tests {
"localhost:443",
"",
"localhost",
if nested { None } else { Some("localhost") },
if nested || xhttp { None } else { Some("localhost") },
),
("localhost:443", "sni_hostname: null", "localhost", None),
("127.0.0.1:443", "", "127.0.0.1", None),
@@ -269,12 +274,22 @@ mod tests {
yaml
};
let handler = crate::rustls_config_util::with_test_roots(roots, || {
create_tcp_client_handler(
serde_yaml::from_str(&yaml).unwrap(),
&hop,
Arc::new(crate::resolver::NativeResolver::new()),
)
.unwrap()
let protocol: crate::config::ClientProxyConfig =
serde_yaml::from_str(&yaml).unwrap();
let resolver = Arc::new(crate::resolver::NativeResolver::new());
if xhttp {
let config = serde_json::from_value(serde_json::json!({
"address": hop.to_string(),
"protocol": {"type": "xhttp", "protocol": protocol}
}))
.unwrap();
crate::xhttp::connector::build(&config, resolver)
.unwrap()
.unwrap()
.1
} else {
create_tcp_client_handler(protocol, &hop, resolver).unwrap()
}
});
let (io, peer) = tokio::io::duplex(65536);
let server_task = tokio::spawn(async move {
+2 -1
View File
@@ -264,9 +264,10 @@ pub(crate) fn build_with_limits(
"XHTTP split modes require at least two request lanes",
));
}
let inner = crate::tcp::tcp_client_handler_factory::create_tcp_client_handler(
let inner = crate::tcp::tcp_client_handler_factory::create_with_hop_context(
*xhttp.protocol.clone(),
&config.address,
None,
resolver,
)?;
let client = Client::new(