feat(tls): Add flag to not send SNI during tls handshake

This commit is contained in:
Σrebe - Romain GERARD 2024-03-16 22:12:31 +01:00
parent 1c393afe4f
commit 3129fe3219
No known key found for this signature in database
GPG key ID: 7A42B4B97E0332F4
2 changed files with 42 additions and 14 deletions

View file

@ -138,6 +138,11 @@ struct Client {
#[arg(long, value_name = "DOMAIN_NAME", value_parser = parse_sni_override, verbatim_doc_comment)]
tls_sni_override: Option<DnsName>,
/// Disable sending SNI during TLS handshake
/// Warning: Most reverse proxies rely on it
#[arg(long, verbatim_doc_comment)]
tls_sni_disable: bool,
/// Enable TLS certificate verification.
/// Disabled by default. The client will happily connect to any server with self signed certificate.
#[arg(long, verbatim_doc_comment)]
@ -557,6 +562,7 @@ fn parse_server_url(arg: &str) -> Result<Url, io::Error> {
#[derive(Clone)]
pub struct TlsClientConfig {
pub tls_sni_disabled: bool,
pub tls_sni_override: Option<DnsName>,
pub tls_verify_certificate: bool,
pub tls_connector: TlsConnector,
@ -680,16 +686,26 @@ async fn main() {
{
TransportScheme::Ws | TransportScheme::Http => None,
TransportScheme::Wss => Some(TlsClientConfig {
tls_connector: tls::tls_connector(args.tls_verify_certificate, Some(vec![b"http/1.1".to_vec()]))
tls_connector: tls::tls_connector(
args.tls_verify_certificate,
Some(vec![b"http/1.1".to_vec()]),
!args.tls_sni_disable,
)
.expect("Cannot create tls connector"),
tls_sni_override: args.tls_sni_override,
tls_verify_certificate: args.tls_verify_certificate,
tls_sni_disabled: args.tls_sni_disable,
}),
TransportScheme::Https => Some(TlsClientConfig {
tls_connector: tls::tls_connector(args.tls_verify_certificate, Some(vec![b"h2".to_vec()]))
tls_connector: tls::tls_connector(
args.tls_verify_certificate,
Some(vec![b"h2".to_vec()]),
!args.tls_sni_disable,
)
.expect("Cannot create tls connector"),
tls_sni_override: args.tls_sni_override,
tls_verify_certificate: args.tls_verify_certificate,
tls_sni_disabled: args.tls_sni_disable,
}),
};

View file

@ -66,6 +66,7 @@ pub fn load_private_key_from_file(path: &Path) -> anyhow::Result<PrivateKey> {
pub fn tls_connector(
tls_verify_certificate: bool,
alpn_protocols: Option<Vec<Vec<u8>>>,
enable_sni: bool,
) -> anyhow::Result<TlsConnector> {
let mut root_store = rustls::RootCertStore::empty();
@ -74,7 +75,7 @@ pub fn tls_connector(
for cert in certs {
if let Err(err) = root_store.add(&Certificate(cert.as_ref().to_vec())) {
warn!("cannot load a system certificate: {:?}", err);
continue
continue;
}
}
@ -83,6 +84,8 @@ pub fn tls_connector(
.with_root_certificates(root_store)
.with_no_client_auth();
config.enable_sni = enable_sni;
// To bypass certificate verification
if !tls_verify_certificate {
config.dangerous().set_certificate_verifier(Arc::new(NullVerifier));
@ -110,19 +113,28 @@ pub fn tls_acceptor(tls_cfg: &TlsServerConfig, alpn_protocols: Option<Vec<Vec<u8
pub async fn connect(client_cfg: &WsClientConfig, tcp_stream: TcpStream) -> anyhow::Result<TlsStream<TcpStream>> {
let sni = client_cfg.tls_server_name();
info!(
"Doing TLS handshake using sni {sni:?} with the server {}:{}",
client_cfg.remote_addr.host(),
client_cfg.remote_addr.port()
);
let tls_connector = match &client_cfg.remote_addr {
TransportAddr::Wss { tls, .. } => &tls.tls_connector,
TransportAddr::Https { tls, .. } => &tls.tls_connector,
let (tls_connector, sni_disabled) = match &client_cfg.remote_addr {
TransportAddr::Wss { tls, .. } => (&tls.tls_connector, tls.tls_sni_disabled),
TransportAddr::Https { tls, .. } => (&tls.tls_connector, tls.tls_sni_disabled),
TransportAddr::Http { .. } | TransportAddr::Ws { .. } => {
return Err(anyhow!("Transport does not support TLS: {}", client_cfg.remote_addr.scheme()))
}
};
if sni_disabled {
info!(
"Doing TLS handshake without SNI with the server {}:{}",
client_cfg.remote_addr.host(),
client_cfg.remote_addr.port()
);
} else {
info!(
"Doing TLS handshake using SNI {sni:?} with the server {}:{}",
client_cfg.remote_addr.host(),
client_cfg.remote_addr.port()
);
}
let tls_stream = tls_connector.connect(sni, tcp_stream).await.with_context(|| {
format!(
"failed to do TLS handshake with the server {}:{}",