Skip to content

Commit

Permalink
Silently ignore TLS EOF errors (#1025)
Browse files Browse the repository at this point in the history
  • Loading branch information
rukai authored Feb 8, 2023
1 parent a0e7645 commit 9fe3316
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 56 deletions.
8 changes: 6 additions & 2 deletions shotover-proxy/src/server.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::message::Messages;
use crate::tls::TlsAcceptor;
use crate::tls::{AcceptError, TlsAcceptor};
use crate::transforms::chain::{TransformChain, TransformChainBuilder};
use crate::transforms::Wrapper;
use anyhow::{anyhow, Context, Result};
Expand Down Expand Up @@ -457,7 +457,11 @@ impl<C: Codec + 'static> Handler<C> {
let local_addr = stream.local_addr()?;

if let Some(tls) = &self.tls {
let tls_stream = tls.accept(stream).await?;
let tls_stream = match tls.accept(stream).await {
Ok(x) => x,
Err(AcceptError::Disconnected) => return Ok(()),
Err(AcceptError::Failure(err)) => return Err(err),
};
let (rx, tx) = tokio::io::split(tls_stream);
spawn_read_write_tasks(
self.codec.clone(),
Expand Down
29 changes: 22 additions & 7 deletions shotover-proxy/src/tls.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::tcp;
use anyhow::{anyhow, Result};
use openssl::ssl::Ssl;
use anyhow::{anyhow, Error, Result};
use openssl::ssl::{ErrorCode, Ssl};
use openssl::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod};
use serde::{Deserialize, Serialize};
use std::fmt::Write;
Expand Down Expand Up @@ -28,6 +28,13 @@ pub struct TlsAcceptor {
acceptor: Arc<SslAcceptor>,
}

pub enum AcceptError {
/// The client decided it didnt need the connection anymore and politely disconnected before the handshake completed.
/// This can occur during regular use and indicates the connection should be quietly discarded.
Disconnected,
Failure(Error),
}

pub fn check_file_field(field_name: &str, file_path: &str) -> Result<()> {
if Path::new(file_path).exists() {
Ok(())
Expand Down Expand Up @@ -68,13 +75,21 @@ impl TlsAcceptor {
})
}

pub async fn accept(&self, tcp_stream: TcpStream) -> Result<SslStream<TcpStream>> {
let ssl = Ssl::new(self.acceptor.context()).map_err(openssl_stack_error_to_anyhow)?;
let mut ssl_stream =
SslStream::new(ssl, tcp_stream).map_err(openssl_stack_error_to_anyhow)?;
pub async fn accept(&self, tcp_stream: TcpStream) -> Result<SslStream<TcpStream>, AcceptError> {
let ssl = Ssl::new(self.acceptor.context())
.map_err(|e| AcceptError::Failure(openssl_stack_error_to_anyhow(e)))?;
let mut ssl_stream = SslStream::new(ssl, tcp_stream)
.map_err(|e| AcceptError::Failure(openssl_stack_error_to_anyhow(e)))?;

Pin::new(&mut ssl_stream).accept().await.map_err(|e| {
openssl_ssl_error_to_anyhow(e).context("Failed to accept TLS connection")
// This is the internal logic that results in the "unexpected EOF" error in the ssl::error::Error display impl
if e.code() == ErrorCode::SYSCALL && e.io_error().is_none() {
AcceptError::Disconnected
} else {
AcceptError::Failure(
openssl_ssl_error_to_anyhow(e).context("Failed to accept TLS connection"),
)
}
})?;
Ok(ssl_stream)
}
Expand Down
36 changes: 2 additions & 34 deletions shotover-proxy/tests/cassandra_int_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,23 +122,7 @@ async fn source_tls_and_single_tls(#[case] driver: CassandraDriver) {

standard_test_suite(&connection, driver).await;

if let CassandraDriver::Scylla | CassandraDriver::CdrsTokio = driver {
shotover.shutdown_and_then_consume_events(&[]).await;
} else {
shotover
.shutdown_and_then_consume_events(&[EventMatcher::new()
.with_level(Level::Error)
.with_target("shotover_proxy::server")
.with_message(
r#"connection was unexpectedly terminated
Caused by:
0: Failed to accept TLS connection
1: unexpected EOF"#,
)
.with_count(Count::Any)])
.await;
}
shotover.shutdown_and_then_consume_events(&[]).await;
}

#[rstest]
Expand Down Expand Up @@ -368,23 +352,7 @@ async fn source_tls_and_cluster_tls(#[case] driver: CassandraDriver) {
standard_test_suite(&connection, driver).await;
cluster::single_rack_v4::test(&connection().await, driver).await;

if let CassandraDriver::Scylla | CassandraDriver::CdrsTokio = driver {
shotover.shutdown_and_then_consume_events(&[]).await;
} else {
shotover
.shutdown_and_then_consume_events(&[EventMatcher::new()
.with_level(Level::Error)
.with_target("shotover_proxy::server")
.with_message(
r#"connection was unexpectedly terminated
Caused by:
0: Failed to accept TLS connection
1: unexpected EOF"#,
)
.with_count(Count::Any)])
.await;
}
shotover.shutdown_and_then_consume_events(&[]).await;
}

cluster::single_rack_v4::test_topology_task(Some(ca_cert), None).await;
Expand Down
14 changes: 1 addition & 13 deletions shotover-proxy/tests/redis_int_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,19 +120,7 @@ async fn source_tls_and_single_tls() {

run_all(&mut connection, &mut flusher).await;

shotover
.shutdown_and_then_consume_events(&[EventMatcher::new()
.with_level(Level::Error)
.with_target("shotover_proxy::server")
.with_message(
r#"connection was unexpectedly terminated
Caused by:
0: Failed to accept TLS connection
1: unexpected EOF"#,
)
.with_count(Count::Times(2))])
.await;
shotover.shutdown_and_then_consume_events(&[]).await;
}

#[tokio::test(flavor = "multi_thread")]
Expand Down

0 comments on commit 9fe3316

Please sign in to comment.