mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
fix: send TLS alerts on handshake timeout and unrecognized SNI
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user