From 426c073b255dd2909e7c9d9a4b5ac3f42d0ef0fb Mon Sep 17 00:00:00 2001 From: mdecimus Date: Fri, 25 Aug 2023 20:05:41 +0200 Subject: [PATCH] Fallback to plain-text when STARTTLS is optional --- crates/smtp/src/inbound/data.rs | 1 + crates/smtp/src/outbound/delivery.rs | 21 +++++++++++++++++---- crates/smtp/src/queue/dsn.rs | 11 +++++++++++ crates/smtp/src/queue/mod.rs | 1 + crates/smtp/src/queue/serialize.rs | 1 + crates/smtp/src/queue/spool.rs | 1 + tests/src/smtp/queue/dsn.rs | 1 + tests/src/smtp/queue/manager.rs | 1 + tests/src/smtp/queue/serialize.rs | 2 ++ 9 files changed, 36 insertions(+), 4 deletions(-) diff --git a/crates/smtp/src/inbound/data.rs b/crates/smtp/src/inbound/data.rs index aee2d4bc..b17cc95d 100644 --- a/crates/smtp/src/inbound/data.rs +++ b/crates/smtp/src/inbound/data.rs @@ -632,6 +632,7 @@ impl Session { expires, status: queue::Status::Scheduled, domain: rcpt.domain, + disable_tls: false, changed: false, }); } diff --git a/crates/smtp/src/outbound/delivery.rs b/crates/smtp/src/outbound/delivery.rs index 004efe95..4bd98b19 100644 --- a/crates/smtp/src/outbound/delivery.rs +++ b/crates/smtp/src/outbound/delivery.rs @@ -187,6 +187,7 @@ impl DeliveryAttempt { }; // Prepare TLS strategy + let mut disable_tls = false; let mut tls_strategy = TlsStrategy { mta_sts: *queue_config.tls.mta_sts.eval(&envelope).await, ..Default::default() @@ -668,7 +669,7 @@ impl DeliveryAttempt { }; // Try starting TLS - if tls_strategy.try_start_tls() { + if tls_strategy.try_start_tls() && !domain.disable_tls { smtp_client.timeout = *queue_config.timeout.tls.eval(&envelope).await; match try_start_tls( @@ -821,18 +822,29 @@ impl DeliveryAttempt { }) .await; } - last_status = Status::from_tls_error(envelope.mx, error); + + last_status = if tls_strategy.is_tls_required() + || (self.message.flags & MAIL_REQUIRETLS) != 0 + || mta_sts_policy.is_some() + || dane_policy.is_some() + { + Status::from_tls_error(envelope.mx, error) + } else { + disable_tls = true; + Status::from_tls_error(envelope.mx, error) + .into_temporary() + }; continue 'next_host; } } } else { - // TLS has been disabled in the configuration file + // TLS has been disabled tracing::info!( parent: &span, context = "tls", event = "disabled", mx = envelope.mx, - reason = "TLS is disabled for this host", + reason = if domain.disable_tls {"TLS is disabled for this host"} else {"TLS is unavailable for this host, falling back to plain-text."}, ); self.message @@ -893,6 +905,7 @@ impl DeliveryAttempt { }; // Update status for the current domain and continue with the next one + domain.disable_tls = disable_tls; domain .set_status(delivery_result, queue_config.retry.eval(&envelope).await); continue 'next_domain; diff --git a/crates/smtp/src/queue/dsn.rs b/crates/smtp/src/queue/dsn.rs index 55e6eafb..3a58e2de 100644 --- a/crates/smtp/src/queue/dsn.rs +++ b/crates/smtp/src/queue/dsn.rs @@ -525,6 +525,17 @@ impl Status { } } + pub fn into_temporary(self) -> Self { + match self { + Status::PermanentFailure(err) => Status::TemporaryFailure(err), + other => other, + } + } + + pub fn is_permanent(&self) -> bool { + matches!(self, Status::PermanentFailure(_)) + } + fn write_dsn_action(&self, dsn: &mut String) { dsn.push_str("Action: "); dsn.push_str(match self { diff --git a/crates/smtp/src/queue/mod.rs b/crates/smtp/src/queue/mod.rs index b80e87c5..9a0b8434 100644 --- a/crates/smtp/src/queue/mod.rs +++ b/crates/smtp/src/queue/mod.rs @@ -102,6 +102,7 @@ pub struct Domain { pub notify: Schedule, pub expires: Instant, pub status: Status<(), Error>, + pub disable_tls: bool, pub changed: bool, } diff --git a/crates/smtp/src/queue/serialize.rs b/crates/smtp/src/queue/serialize.rs index 11a31b37..e056888b 100644 --- a/crates/smtp/src/queue/serialize.rs +++ b/crates/smtp/src/queue/serialize.rs @@ -211,6 +211,7 @@ impl Message { retry: Schedule::now(), notify: Schedule::now(), status: Status::Scheduled, + disable_tls: false, changed: false, }); } diff --git a/crates/smtp/src/queue/spool.rs b/crates/smtp/src/queue/spool.rs index dfe0222c..69a5a173 100644 --- a/crates/smtp/src/queue/spool.rs +++ b/crates/smtp/src/queue/spool.rs @@ -215,6 +215,7 @@ impl Message { notify: Schedule::later(expires + Duration::from_secs(10)), expires: Instant::now() + expires, status: Status::Scheduled, + disable_tls: false, changed: false, }); idx diff --git a/tests/src/smtp/queue/dsn.rs b/tests/src/smtp/queue/dsn.rs index 0bc12e29..eb25de82 100644 --- a/tests/src/smtp/queue/dsn.rs +++ b/tests/src/smtp/queue/dsn.rs @@ -91,6 +91,7 @@ async fn generate_dsn() { entity: "mx.domain.org".to_string(), details: "Connection timeout".to_string(), })), + disable_tls: false, changed: false, }], flags: 0, diff --git a/tests/src/smtp/queue/manager.rs b/tests/src/smtp/queue/manager.rs index 3b6ac7f0..72037531 100644 --- a/tests/src/smtp/queue/manager.rs +++ b/tests/src/smtp/queue/manager.rs @@ -152,6 +152,7 @@ fn domain(domain: &str, retry: u64, notify: u64, expires: u64) -> Domain { notify: Schedule::later(Duration::from_secs(notify)), expires: Instant::now() + Duration::from_secs(expires), status: Status::Scheduled, + disable_tls: false, changed: false, } } diff --git a/tests/src/smtp/queue/serialize.rs b/tests/src/smtp/queue/serialize.rs index 3bf625d5..37fb1a24 100644 --- a/tests/src/smtp/queue/serialize.rs +++ b/tests/src/smtp/queue/serialize.rs @@ -79,6 +79,7 @@ async fn queue_serialize() { notify: Schedule::now(), expires: Instant::now() + Duration::from_secs(10), status: Status::Scheduled, + disable_tls: false, changed: false, }, Domain { @@ -87,6 +88,7 @@ async fn queue_serialize() { notify: Schedule::now(), expires: Instant::now() + Duration::from_secs(10), status: Status::Scheduled, + disable_tls: false, changed: false, }, ],