fix: send TLS alerts on handshake timeout and unrecognized SNI

This commit is contained in:
Aiden McClelland
2026-03-19 00:06:25 -06:00
parent 34e01d4223
commit 9a58568053

View File

@@ -182,13 +182,14 @@ where
let (metadata, stream) = ready!(self.accept.poll_accept(cx)?); let (metadata, stream) = ready!(self.accept.poll_accept(cx)?);
let mut tls_handler = self.tls_handler.clone(); let mut tls_handler = self.tls_handler.clone();
let mut fut = async move { let mut fut = async move {
let res = match tokio::time::timeout(Duration::from_secs(15), async { let res = async {
// Phase 1: Accept ClientHello
let mut acceptor = let mut acceptor =
LazyConfigAcceptor::new(Acceptor::default(), BackTrackingIO::new(stream)); LazyConfigAcceptor::new(Acceptor::default(), BackTrackingIO::new(stream));
let mut mid: tokio_rustls::StartHandshake<BackTrackingIO<AcceptStream>> = let mut mid: tokio_rustls::StartHandshake<BackTrackingIO<AcceptStream>> =
match (&mut acceptor).await { match tokio::time::timeout(Duration::from_secs(5), &mut acceptor).await {
Ok(a) => a, Ok(Ok(a)) => a,
Err(e) => { Ok(Err(e)) => {
let mut stream = acceptor.take_io().or_not_found("acceptor io")?; let mut stream = acceptor.take_io().or_not_found("acceptor io")?;
let (_, buf) = stream.rewind(); let (_, buf) = stream.rewind();
if std::str::from_utf8(buf) if std::str::from_utf8(buf)
@@ -212,40 +213,59 @@ where
return Err(e).with_kind(ErrorKind::Network); return Err(e).with_kind(ErrorKind::Network);
} }
} }
Err(_) => {
tracing::debug!("TLS ClientHello timed out");
return Ok(None);
}
}; };
// Phase 2: Resolve TLS config (scoped timeout so mid
// remains accessible for sending a TLS alert on timeout)
let hello = mid.client_hello(); let hello = mid.client_hello();
let sni = hello.server_name().map(InternedString::intern); let sni = hello.server_name().map(InternedString::intern);
match tls_handler.get_config(&hello, &metadata).await { let action = tls_handler.get_config(&hello, &metadata).await;
drop(hello);
match action {
Some(TlsHandlerAction::Tls(cfg)) => { Some(TlsHandlerAction::Tls(cfg)) => {
let buffered = mid.io.stop_buffering(); let buffered = mid.io.stop_buffering();
mid.io mid.io
.write_all(&buffered) .write_all(&buffered)
.await .await
.with_kind(ErrorKind::Network)?; .with_kind(ErrorKind::Network)?;
return Ok(match mid.into_stream(Arc::new(cfg)).await { return Ok(
Ok(stream) => { match tokio::time::timeout(
let s = stream.get_ref().1; Duration::from_secs(15),
Some(( mid.into_stream(Arc::new(cfg)),
TlsMetadata { )
inner: metadata, .await
tls_info: TlsHandshakeInfo { .with_kind(ErrorKind::Timeout)
sni: s .and_then(|e| e.map_err(Error::from))
.server_name() {
.map(InternedString::intern), Ok(stream) => {
alpn: s let s = stream.get_ref().1;
.alpn_protocol() Some((
.map(|a| MaybeUtf8String(a.to_vec())), TlsMetadata {
inner: metadata,
tls_info: TlsHandshakeInfo {
sni: s
.server_name()
.map(InternedString::intern),
alpn: s
.alpn_protocol()
.map(|a| MaybeUtf8String(a.to_vec())),
},
}, },
}, Box::pin(stream) as AcceptStream,
Box::pin(stream) as AcceptStream, ))
)) }
} Err(e) => {
Err(e) => { tracing::trace!("Error completing TLS handshake: {e}");
tracing::trace!("Error completing TLS handshake: {e}"); tracing::trace!("{e:?}");
tracing::trace!("{e:?}"); None
None }
} },
}); );
} }
Some(TlsHandlerAction::Passthrough) => { Some(TlsHandlerAction::Passthrough) => {
let (dummy, _drop) = tokio::io::duplex(1); let (dummy, _drop) = tokio::io::duplex(1);
@@ -263,19 +283,26 @@ where
Box::pin(bt) as AcceptStream, Box::pin(bt) as AcceptStream,
))); )));
} }
None => {} None => {
tracing::debug!("no certificate for SNI {:?}", sni);
let _ = mid
.io
.write_all(&[
0x15, // ContentType: Alert
0x03,
0x03, // ProtocolVersion: TLS 1.2 (also used by TLS 1.3)
0x00, 0x02, // Length: 2
0x02, // AlertLevel: Fatal
0x70, // AlertDescription: unrecognized_name (112)
])
.await;
let _ = mid.io.flush().await;
}
} }
Ok(None) Ok(None)
}) }
.await .await;
{
Ok(res) => res,
Err(_) => {
tracing::trace!("TLS handshake timed out");
Ok(None)
}
};
(tls_handler, res) (tls_handler, res)
} }
.boxed(); .boxed();