feat: set imap ALPN when connecting to IMAP servers

IMAP has a registered protocol ID
listed at <https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids>

Requesting specific ALPN on the client
should allow the server to
multiplex multiple protocols on the same
port and dispatch
requests to the correct backend on the proxy such as HAProxy.
This commit is contained in:
link2xt
2024-07-10 23:20:41 +00:00
parent f84e603318
commit bd83fb3d38
3 changed files with 14 additions and 12 deletions

View File

@@ -105,7 +105,7 @@ impl Client {
strict_tls: bool, strict_tls: bool,
) -> Result<Self> { ) -> Result<Self> {
let tcp_stream = connect_tcp(context, hostname, port, IMAP_TIMEOUT, strict_tls).await?; let tcp_stream = connect_tcp(context, hostname, port, IMAP_TIMEOUT, strict_tls).await?;
let tls_stream = wrap_tls(strict_tls, hostname, tcp_stream).await?; let tls_stream = wrap_tls(strict_tls, hostname, &["imap"], tcp_stream).await?;
let buffered_stream = BufWriter::new(tls_stream); let buffered_stream = BufWriter::new(tls_stream);
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream); let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
let mut client = Client::new(session_stream); let mut client = Client::new(session_stream);
@@ -150,7 +150,7 @@ impl Client {
let buffered_tcp_stream = client.into_inner(); let buffered_tcp_stream = client.into_inner();
let tcp_stream = buffered_tcp_stream.into_inner(); let tcp_stream = buffered_tcp_stream.into_inner();
let tls_stream = wrap_tls(strict_tls, hostname, tcp_stream) let tls_stream = wrap_tls(strict_tls, hostname, &["imap"], tcp_stream)
.await .await
.context("STARTTLS upgrade failed")?; .context("STARTTLS upgrade failed")?;
@@ -170,7 +170,7 @@ impl Client {
let socks5_stream = socks5_config let socks5_stream = socks5_config
.connect(context, domain, port, IMAP_TIMEOUT, strict_tls) .connect(context, domain, port, IMAP_TIMEOUT, strict_tls)
.await?; .await?;
let tls_stream = wrap_tls(strict_tls, domain, socks5_stream).await?; let tls_stream = wrap_tls(strict_tls, domain, &["imap"], socks5_stream).await?;
let buffered_stream = BufWriter::new(tls_stream); let buffered_stream = BufWriter::new(tls_stream);
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream); let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
let mut client = Client::new(session_stream); let mut client = Client::new(session_stream);
@@ -225,7 +225,7 @@ impl Client {
let buffered_socks5_stream = client.into_inner(); let buffered_socks5_stream = client.into_inner();
let socks5_stream: Socks5Stream<_> = buffered_socks5_stream.into_inner(); let socks5_stream: Socks5Stream<_> = buffered_socks5_stream.into_inner();
let tls_stream = wrap_tls(strict_tls, hostname, socks5_stream) let tls_stream = wrap_tls(strict_tls, hostname, &["imap"], socks5_stream)
.await .await
.context("STARTTLS upgrade failed")?; .context("STARTTLS upgrade failed")?;
let buffered_stream = BufWriter::new(tls_stream); let buffered_stream = BufWriter::new(tls_stream);

View File

@@ -14,9 +14,10 @@ static LETSENCRYPT_ROOT: Lazy<Certificate> = Lazy::new(|| {
.unwrap() .unwrap()
}); });
pub fn build_tls(strict_tls: bool) -> TlsConnector { pub fn build_tls(strict_tls: bool, alpns: &[&str]) -> TlsConnector {
let tls_builder = TlsConnector::new() let tls_builder = TlsConnector::new()
.min_protocol_version(Some(Protocol::Tlsv12)) .min_protocol_version(Some(Protocol::Tlsv12))
.request_alpns(alpns)
.add_root_certificate(LETSENCRYPT_ROOT.clone()); .add_root_certificate(LETSENCRYPT_ROOT.clone());
if strict_tls { if strict_tls {
@@ -31,9 +32,10 @@ pub fn build_tls(strict_tls: bool) -> TlsConnector {
pub async fn wrap_tls<T: AsyncRead + AsyncWrite + Unpin>( pub async fn wrap_tls<T: AsyncRead + AsyncWrite + Unpin>(
strict_tls: bool, strict_tls: bool,
hostname: &str, hostname: &str,
alpns: &[&str],
stream: T, stream: T,
) -> Result<TlsStream<T>> { ) -> Result<TlsStream<T>> {
let tls = build_tls(strict_tls); let tls = build_tls(strict_tls, alpns);
let tls_stream = tls.connect(hostname, stream).await?; let tls_stream = tls.connect(hostname, stream).await?;
Ok(tls_stream) Ok(tls_stream)
} }
@@ -46,7 +48,7 @@ mod tests {
fn test_build_tls() { fn test_build_tls() {
// we are using some additional root certificates. // we are using some additional root certificates.
// make sure, they do not break construction of TlsConnector // make sure, they do not break construction of TlsConnector
let _ = build_tls(true); let _ = build_tls(true, &[]);
let _ = build_tls(false); let _ = build_tls(false, &[]);
} }
} }

View File

@@ -120,7 +120,7 @@ impl Smtp {
let socks5_stream = socks5_config let socks5_stream = socks5_config
.connect(context, hostname, port, SMTP_TIMEOUT, strict_tls) .connect(context, hostname, port, SMTP_TIMEOUT, strict_tls)
.await?; .await?;
let tls_stream = wrap_tls(strict_tls, hostname, socks5_stream).await?; let tls_stream = wrap_tls(strict_tls, hostname, &[], socks5_stream).await?;
let buffered_stream = BufStream::new(tls_stream); let buffered_stream = BufStream::new(tls_stream);
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream); let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
let client = smtp::SmtpClient::new().smtp_utf8(true); let client = smtp::SmtpClient::new().smtp_utf8(true);
@@ -144,7 +144,7 @@ impl Smtp {
let client = smtp::SmtpClient::new().smtp_utf8(true); let client = smtp::SmtpClient::new().smtp_utf8(true);
let transport = SmtpTransport::new(client, BufStream::new(socks5_stream)).await?; let transport = SmtpTransport::new(client, BufStream::new(socks5_stream)).await?;
let tcp_stream = transport.starttls().await?.into_inner(); let tcp_stream = transport.starttls().await?.into_inner();
let tls_stream = wrap_tls(strict_tls, hostname, tcp_stream) let tls_stream = wrap_tls(strict_tls, hostname, &[], tcp_stream)
.await .await
.context("STARTTLS upgrade failed")?; .context("STARTTLS upgrade failed")?;
let buffered_stream = BufStream::new(tls_stream); let buffered_stream = BufStream::new(tls_stream);
@@ -179,7 +179,7 @@ impl Smtp {
strict_tls: bool, strict_tls: bool,
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> { ) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
let tcp_stream = connect_tcp(context, hostname, port, SMTP_TIMEOUT, false).await?; let tcp_stream = connect_tcp(context, hostname, port, SMTP_TIMEOUT, false).await?;
let tls_stream = wrap_tls(strict_tls, hostname, tcp_stream).await?; let tls_stream = wrap_tls(strict_tls, hostname, &[], tcp_stream).await?;
let buffered_stream = BufStream::new(tls_stream); let buffered_stream = BufStream::new(tls_stream);
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream); let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
let client = smtp::SmtpClient::new().smtp_utf8(true); let client = smtp::SmtpClient::new().smtp_utf8(true);
@@ -200,7 +200,7 @@ impl Smtp {
let client = smtp::SmtpClient::new().smtp_utf8(true); let client = smtp::SmtpClient::new().smtp_utf8(true);
let transport = SmtpTransport::new(client, BufStream::new(tcp_stream)).await?; let transport = SmtpTransport::new(client, BufStream::new(tcp_stream)).await?;
let tcp_stream = transport.starttls().await?.into_inner(); let tcp_stream = transport.starttls().await?.into_inner();
let tls_stream = wrap_tls(strict_tls, hostname, tcp_stream) let tls_stream = wrap_tls(strict_tls, hostname, &[], tcp_stream)
.await .await
.context("STARTTLS upgrade failed")?; .context("STARTTLS upgrade failed")?;
let buffered_stream = BufStream::new(tls_stream); let buffered_stream = BufStream::new(tls_stream);