feat(tls): Add flag to not send SNI during tls handshake
This commit is contained in:
parent
1c393afe4f
commit
3129fe3219
2 changed files with 42 additions and 14 deletions
24
src/main.rs
24
src/main.rs
|
@ -138,6 +138,11 @@ struct Client {
|
||||||
#[arg(long, value_name = "DOMAIN_NAME", value_parser = parse_sni_override, verbatim_doc_comment)]
|
#[arg(long, value_name = "DOMAIN_NAME", value_parser = parse_sni_override, verbatim_doc_comment)]
|
||||||
tls_sni_override: Option<DnsName>,
|
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.
|
/// Enable TLS certificate verification.
|
||||||
/// Disabled by default. The client will happily connect to any server with self signed certificate.
|
/// Disabled by default. The client will happily connect to any server with self signed certificate.
|
||||||
#[arg(long, verbatim_doc_comment)]
|
#[arg(long, verbatim_doc_comment)]
|
||||||
|
@ -557,6 +562,7 @@ fn parse_server_url(arg: &str) -> Result<Url, io::Error> {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TlsClientConfig {
|
pub struct TlsClientConfig {
|
||||||
|
pub tls_sni_disabled: bool,
|
||||||
pub tls_sni_override: Option<DnsName>,
|
pub tls_sni_override: Option<DnsName>,
|
||||||
pub tls_verify_certificate: bool,
|
pub tls_verify_certificate: bool,
|
||||||
pub tls_connector: TlsConnector,
|
pub tls_connector: TlsConnector,
|
||||||
|
@ -680,16 +686,26 @@ async fn main() {
|
||||||
{
|
{
|
||||||
TransportScheme::Ws | TransportScheme::Http => None,
|
TransportScheme::Ws | TransportScheme::Http => None,
|
||||||
TransportScheme::Wss => Some(TlsClientConfig {
|
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(
|
||||||
.expect("Cannot create 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_sni_override: args.tls_sni_override,
|
||||||
tls_verify_certificate: args.tls_verify_certificate,
|
tls_verify_certificate: args.tls_verify_certificate,
|
||||||
|
tls_sni_disabled: args.tls_sni_disable,
|
||||||
}),
|
}),
|
||||||
TransportScheme::Https => Some(TlsClientConfig {
|
TransportScheme::Https => Some(TlsClientConfig {
|
||||||
tls_connector: tls::tls_connector(args.tls_verify_certificate, Some(vec![b"h2".to_vec()]))
|
tls_connector: tls::tls_connector(
|
||||||
.expect("Cannot create 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_sni_override: args.tls_sni_override,
|
||||||
tls_verify_certificate: args.tls_verify_certificate,
|
tls_verify_certificate: args.tls_verify_certificate,
|
||||||
|
tls_sni_disabled: args.tls_sni_disable,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
32
src/tls.rs
32
src/tls.rs
|
@ -66,6 +66,7 @@ pub fn load_private_key_from_file(path: &Path) -> anyhow::Result<PrivateKey> {
|
||||||
pub fn tls_connector(
|
pub fn tls_connector(
|
||||||
tls_verify_certificate: bool,
|
tls_verify_certificate: bool,
|
||||||
alpn_protocols: Option<Vec<Vec<u8>>>,
|
alpn_protocols: Option<Vec<Vec<u8>>>,
|
||||||
|
enable_sni: bool,
|
||||||
) -> anyhow::Result<TlsConnector> {
|
) -> anyhow::Result<TlsConnector> {
|
||||||
let mut root_store = rustls::RootCertStore::empty();
|
let mut root_store = rustls::RootCertStore::empty();
|
||||||
|
|
||||||
|
@ -74,7 +75,7 @@ pub fn tls_connector(
|
||||||
for cert in certs {
|
for cert in certs {
|
||||||
if let Err(err) = root_store.add(&Certificate(cert.as_ref().to_vec())) {
|
if let Err(err) = root_store.add(&Certificate(cert.as_ref().to_vec())) {
|
||||||
warn!("cannot load a system certificate: {:?}", err);
|
warn!("cannot load a system certificate: {:?}", err);
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +84,8 @@ pub fn tls_connector(
|
||||||
.with_root_certificates(root_store)
|
.with_root_certificates(root_store)
|
||||||
.with_no_client_auth();
|
.with_no_client_auth();
|
||||||
|
|
||||||
|
config.enable_sni = enable_sni;
|
||||||
|
|
||||||
// To bypass certificate verification
|
// To bypass certificate verification
|
||||||
if !tls_verify_certificate {
|
if !tls_verify_certificate {
|
||||||
config.dangerous().set_certificate_verifier(Arc::new(NullVerifier));
|
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>> {
|
pub async fn connect(client_cfg: &WsClientConfig, tcp_stream: TcpStream) -> anyhow::Result<TlsStream<TcpStream>> {
|
||||||
let sni = client_cfg.tls_server_name();
|
let sni = client_cfg.tls_server_name();
|
||||||
info!(
|
let (tls_connector, sni_disabled) = match &client_cfg.remote_addr {
|
||||||
"Doing TLS handshake using sni {sni:?} with the server {}:{}",
|
TransportAddr::Wss { tls, .. } => (&tls.tls_connector, tls.tls_sni_disabled),
|
||||||
client_cfg.remote_addr.host(),
|
TransportAddr::Https { tls, .. } => (&tls.tls_connector, tls.tls_sni_disabled),
|
||||||
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,
|
|
||||||
TransportAddr::Http { .. } | TransportAddr::Ws { .. } => {
|
TransportAddr::Http { .. } | TransportAddr::Ws { .. } => {
|
||||||
return Err(anyhow!("Transport does not support TLS: {}", client_cfg.remote_addr.scheme()))
|
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(|| {
|
let tls_stream = tls_connector.connect(sni, tcp_stream).await.with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"failed to do TLS handshake with the server {}:{}",
|
"failed to do TLS handshake with the server {}:{}",
|
||||||
|
|
Loading…
Reference in a new issue