diff --git a/CHANGELOG.md b/CHANGELOG.md index 55093c05c..88e85963f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - refactor peerstate handling to ensure no duplicate peerstates #3776 - Fetch messages in order of their INTERNALDATE (fixes reactions for Gmail f.e.) #3789 - python: do not pass NULL to ffi.gc if the context can't be created #3818 +- Add read/write timeouts to IMAP sockets #3820 ## 1.102.0 diff --git a/Cargo.lock b/Cargo.lock index 6339a235f..e6875e093 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -929,6 +929,7 @@ dependencies = [ "textwrap", "thiserror", "tokio", + "tokio-io-timeout", "tokio-stream", "tokio-tar", "toml", @@ -3550,6 +3551,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-macros" version = "1.8.0" diff --git a/Cargo.toml b/Cargo.toml index 53ff47ef5..a3418ae46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,6 +81,7 @@ textwrap = "0.16.0" async-channel = "1.8.0" futures-lite = "1.12.0" tokio-stream = { version = "0.1.11", features = ["fs"] } +tokio-io-timeout = "1.2.0" reqwest = { version = "0.11.13", features = ["json"] } async_zip = { version = "0.0.9", default-features = false, features = ["deflate"] } diff --git a/src/imap/client.rs b/src/imap/client.rs index 807ebf3ff..24bcb73ca 100644 --- a/src/imap/client.rs +++ b/src/imap/client.rs @@ -10,6 +10,7 @@ use async_imap::Session as ImapSession; use async_smtp::ServerAddress; use tokio::net::{self, TcpStream}; +use tokio_io_timeout::TimeoutStream; use super::capabilities::Capabilities; use super::session::Session; @@ -95,9 +96,15 @@ impl Client { domain: &str, strict_tls: bool, ) -> Result { - let stream = TcpStream::connect(addr).await?; + let tcp_stream = TcpStream::connect(addr).await?; + let mut timeout_stream = TimeoutStream::new(tcp_stream); + timeout_stream.set_write_timeout(Some(Duration::new(IMAP_TIMEOUT, 0))); + timeout_stream.set_read_timeout(Some(Duration::new(IMAP_TIMEOUT, 0))); + let timeout_stream = Box::pin(timeout_stream); + let tls = build_tls(strict_tls); - let tls_stream: Box = Box::new(tls.connect(domain, stream).await?); + let tls_stream: Box = + Box::new(tls.connect(domain, timeout_stream).await?); let mut client = ImapClient::new(tls_stream); let _greeting = client @@ -112,7 +119,12 @@ impl Client { } pub async fn connect_insecure(addr: impl net::ToSocketAddrs) -> Result { - let stream: Box = Box::new(TcpStream::connect(addr).await?); + let tcp_stream = TcpStream::connect(addr).await?; + let mut timeout_stream = TimeoutStream::new(tcp_stream); + timeout_stream.set_write_timeout(Some(Duration::new(IMAP_TIMEOUT, 0))); + timeout_stream.set_read_timeout(Some(Duration::new(IMAP_TIMEOUT, 0))); + let timeout_stream = Box::pin(timeout_stream); + let stream: Box = Box::new(timeout_stream); let mut client = ImapClient::new(stream); let _greeting = client diff --git a/src/imap/session.rs b/src/imap/session.rs index 6bc6ac200..2897aa09a 100644 --- a/src/imap/session.rs +++ b/src/imap/session.rs @@ -1,10 +1,12 @@ use std::ops::{Deref, DerefMut}; +use std::pin::Pin; use async_imap::types::Mailbox; use async_imap::Session as ImapSession; use async_native_tls::TlsStream; use fast_socks5::client::Socks5Stream; use tokio::net::TcpStream; +use tokio_io_timeout::TimeoutStream; use super::capabilities::Capabilities; @@ -29,8 +31,10 @@ pub(crate) trait SessionStream: } impl SessionStream for TlsStream> {} +impl SessionStream for TlsStream>>> {} impl SessionStream for TlsStream {} impl SessionStream for TcpStream {} +impl SessionStream for Pin>> {} impl SessionStream for Socks5Stream {} impl Deref for Session {