Resolve IP addresses explicitly

This commit is contained in:
link2xt
2023-01-19 14:57:25 +00:00
parent 4615c84f31
commit ed20a23297
4 changed files with 79 additions and 22 deletions

View File

@@ -308,6 +308,7 @@ impl Imap {
if let Some(socks5_config) = &config.socks5_config {
if config.lp.security == Socket::Starttls {
Client::connect_starttls_socks5(
context,
imap_server,
imap_port,
socks5_config.clone(),
@@ -315,13 +316,18 @@ impl Imap {
)
.await
} else {
Client::connect_insecure_socks5(imap_server, imap_port, socks5_config.clone())
.await
Client::connect_insecure_socks5(
context,
imap_server,
imap_port,
socks5_config.clone(),
)
.await
}
} else if config.lp.security == Socket::Starttls {
Client::connect_starttls(imap_server, imap_port, config.strict_tls).await
Client::connect_starttls(context, imap_server, imap_port, config.strict_tls).await
} else {
Client::connect_insecure((imap_server, imap_port)).await
Client::connect_insecure(context, imap_server, imap_port).await
}
} else {
let config = &self.config;
@@ -330,6 +336,7 @@ impl Imap {
if let Some(socks5_config) = &config.socks5_config {
Client::connect_secure_socks5(
context,
imap_server,
imap_port,
config.strict_tls,
@@ -337,7 +344,7 @@ impl Imap {
)
.await
} else {
Client::connect_secure(imap_server, imap_port, config.strict_tls).await
Client::connect_secure(context, imap_server, imap_port, config.strict_tls).await
}
};

View File

@@ -7,11 +7,11 @@ use anyhow::{Context as _, Result};
use async_imap::Client as ImapClient;
use async_imap::Session as ImapSession;
use tokio::io::BufWriter;
use tokio::net::ToSocketAddrs;
use super::capabilities::Capabilities;
use super::session::Session;
use super::session::SessionStream;
use crate::context::Context;
use crate::login_param::build_tls;
use crate::net::connect_tcp;
use crate::socks::Socks5Config;
@@ -88,8 +88,13 @@ impl Client {
Ok(Session::new(session, capabilities))
}
pub async fn connect_secure(hostname: &str, port: u16, strict_tls: bool) -> Result<Self> {
let tcp_stream = connect_tcp((hostname, port), IMAP_TIMEOUT).await?;
pub async fn connect_secure(
context: &Context,
hostname: &str,
port: u16,
strict_tls: bool,
) -> Result<Self> {
let tcp_stream = connect_tcp(context, hostname, port, IMAP_TIMEOUT).await?;
let tls = build_tls(strict_tls);
let tls_stream = tls.connect(hostname, tcp_stream).await?;
let buffered_stream = BufWriter::new(tls_stream);
@@ -104,8 +109,8 @@ impl Client {
Ok(Client { inner: client })
}
pub async fn connect_insecure(addr: impl ToSocketAddrs) -> Result<Self> {
let tcp_stream = connect_tcp(addr, IMAP_TIMEOUT).await?;
pub async fn connect_insecure(context: &Context, hostname: &str, port: u16) -> Result<Self> {
let tcp_stream = connect_tcp(context, hostname, port, IMAP_TIMEOUT).await?;
let buffered_stream = BufWriter::new(tcp_stream);
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
let mut client = ImapClient::new(session_stream);
@@ -117,8 +122,13 @@ impl Client {
Ok(Client { inner: client })
}
pub async fn connect_starttls(hostname: &str, port: u16, strict_tls: bool) -> Result<Self> {
let tcp_stream = connect_tcp((hostname, port), IMAP_TIMEOUT).await?;
pub async fn connect_starttls(
context: &Context,
hostname: &str,
port: u16,
strict_tls: bool,
) -> Result<Self> {
let tcp_stream = connect_tcp(context, hostname, port, IMAP_TIMEOUT).await?;
// Run STARTTLS command and convert the client back into a stream.
let mut client = ImapClient::new(tcp_stream);
@@ -146,12 +156,15 @@ impl Client {
}
pub async fn connect_secure_socks5(
context: &Context,
domain: &str,
port: u16,
strict_tls: bool,
socks5_config: Socks5Config,
) -> Result<Self> {
let socks5_stream = socks5_config.connect(domain, port, IMAP_TIMEOUT).await?;
let socks5_stream = socks5_config
.connect(context, domain, port, IMAP_TIMEOUT)
.await?;
let tls = build_tls(strict_tls);
let tls_stream = tls.connect(domain, socks5_stream).await?;
let buffered_stream = BufWriter::new(tls_stream);
@@ -166,11 +179,14 @@ impl Client {
}
pub async fn connect_insecure_socks5(
context: &Context,
domain: &str,
port: u16,
socks5_config: Socks5Config,
) -> Result<Self> {
let socks5_stream = socks5_config.connect(domain, port, IMAP_TIMEOUT).await?;
let socks5_stream = socks5_config
.connect(context, domain, port, IMAP_TIMEOUT)
.await?;
let buffered_stream = BufWriter::new(socks5_stream);
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
let mut client = ImapClient::new(session_stream);
@@ -183,12 +199,15 @@ impl Client {
}
pub async fn connect_starttls_socks5(
context: &Context,
hostname: &str,
port: u16,
socks5_config: Socks5Config,
strict_tls: bool,
) -> Result<Self> {
let socks5_stream = socks5_config.connect(hostname, port, IMAP_TIMEOUT).await?;
let socks5_stream = socks5_config
.connect(context, hostname, port, IMAP_TIMEOUT)
.await?;
// Run STARTTLS command and convert the client back into a stream.
let mut client = ImapClient::new(socks5_stream);

View File

@@ -1,25 +1,55 @@
///! # Common network utilities.
use std::net::SocketAddr;
use std::pin::Pin;
use std::time::Duration;
use anyhow::{Context as _, Result};
use tokio::net::{TcpStream, ToSocketAddrs};
use tokio::net::{lookup_host, TcpStream};
use tokio::time::timeout;
use tokio_io_timeout::TimeoutStream;
use crate::context::Context;
async fn connect_tcp_inner(addr: SocketAddr, timeout_val: Duration) -> Result<TcpStream> {
let tcp_stream = timeout(timeout_val, TcpStream::connect(addr))
.await
.context("connection timeout")?
.context("connection failure")?;
Ok(tcp_stream)
}
/// Returns a TCP connection stream with read/write timeouts set
/// and Nagle's algorithm disabled with `TCP_NODELAY`.
///
/// `TCP_NODELAY` ensures writing to the stream always results in immediate sending of the packet
/// to the network, which is important to reduce the latency of interactive protocols such as IMAP.
pub(crate) async fn connect_tcp(
addr: impl ToSocketAddrs,
context: &Context,
host: &str,
port: u16,
timeout_val: Duration,
) -> Result<Pin<Box<TimeoutStream<TcpStream>>>> {
let tcp_stream = timeout(timeout_val, TcpStream::connect(addr))
.await
.context("connection timeout")?
.context("connection failure")?;
let mut tcp_stream = None;
for resolved_addr in lookup_host((host, port)).await? {
info!(
context,
"Resolved {}:{} into {}.", host, port, &resolved_addr
);
match connect_tcp_inner(resolved_addr, timeout_val).await {
Ok(stream) => {
tcp_stream = Some(stream);
break;
}
Err(err) => {
warn!(
context,
"Failed to connect to {}: {:#}.", resolved_addr, err
);
}
}
}
let tcp_stream =
tcp_stream.with_context(|| format!("failed to connect to {}:{}", host, port))?;
// Disable Nagle's algorithm.
tcp_stream.set_nodelay(true)?;

View File

@@ -58,11 +58,12 @@ impl Socks5Config {
pub async fn connect(
&self,
context: &Context,
target_host: &str,
target_port: u16,
timeout_val: Duration,
) -> Result<Socks5Stream<Pin<Box<TimeoutStream<TcpStream>>>>> {
let tcp_stream = connect_tcp((self.host.clone(), self.port), timeout_val).await?;
let tcp_stream = connect_tcp(context, &self.host, self.port, timeout_val).await?;
let authentication_method = if let Some((username, password)) = self.user_password.as_ref()
{