Files
inbuxa-server/tests/src/smtp/inbound/ehlo.rs
T
jcoffey-dev 7dae9b29fd Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f
Enterprise-only files removed or emptied: 63
Enterprise-only snippets removed: 117 in 50 files
Dangling module declarations removed: 5
Cargo edits turning enterprise off: 14
Verification: clean
Enterprise feature gates left for rebuilt features: 19 in 18 files

Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
2026-09-18 10:21:56 -07:00

174 lines
5.5 KiB
Rust

/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use crate::{
smtp::session::{TestSession, VerifyResponse},
utils::{dns::DnsCache, server::TestServerBuilder},
};
use mail_auth::{SpfResult, common::parse::TxtRecordParser, spf::Spf};
use mail_parser::DateTime;
use registry::{
schema::structs::{
Expression, ExpressionMatch, MtaExtensions, MtaStageData, MtaStageEhlo, SenderAuth,
},
types::list::List,
};
use std::time::{Duration, Instant, SystemTime};
#[tokio::test]
async fn ehlo() {
let mut test = TestServerBuilder::new("smtp_ehlo_test")
.await
.with_http_listener(19005)
.await
.disable_services()
.build()
.await;
// Add test settings
let admin = test.account("admin");
admin.mta_no_auth().await;
admin
.registry_create_object(MtaExtensions {
future_release: Expression {
match_: List::from_iter([ExpressionMatch {
if_: "remote_ip = '10.0.0.1'".into(),
then: "1h".into(),
}]),
else_: "false".into(),
},
mt_priority: Expression {
match_: List::from_iter([ExpressionMatch {
if_: "remote_ip = '10.0.0.1'".into(),
then: "nsep".into(),
}]),
else_: "false".into(),
},
..Default::default()
})
.await;
admin
.registry_create_object(MtaStageEhlo {
reject_non_fqdn: Expression {
else_: "starts_with(remote_ip, '10.0.0.')".into(),
..Default::default()
},
..Default::default()
})
.await;
admin
.registry_create_object(MtaStageData {
max_message_size: Expression {
match_: List::from_iter([ExpressionMatch {
if_: "remote_ip = '10.0.0.1'".into(),
then: "1024".into(),
}]),
else_: "2048".into(),
},
..Default::default()
})
.await;
admin
.registry_create_object(SenderAuth {
dmarc_verify: Expression {
else_: "relaxed".into(),
..Default::default()
},
reverse_ip_verify: Expression {
else_: "relaxed".into(),
..Default::default()
},
spf_ehlo_verify: Expression {
match_: List::from_iter([ExpressionMatch {
if_: "remote_ip = '10.0.0.2'".into(),
then: "strict".into(),
}]),
else_: "relaxed".into(),
},
spf_from_verify: Expression {
else_: "relaxed".into(),
..Default::default()
},
..Default::default()
})
.await;
admin.reload_settings().await;
test.reload_core();
test.server.txt_add(
"mx1.foobar.org",
Spf::parse(b"v=spf1 ip4:10.0.0.1 -all").unwrap(),
Instant::now() + Duration::from_secs(5),
);
test.server.txt_add(
"mx2.foobar.org",
Spf::parse(b"v=spf1 ip4:10.0.0.2 -all").unwrap(),
Instant::now() + Duration::from_secs(5),
);
// Reject non-FQDN domains
let mut session = test.new_mta_session();
session.data.remote_ip_str = "10.0.0.1".into();
session.data.remote_ip = session.data.remote_ip_str.parse().unwrap();
session.stream.tls = false;
session.eval_session_params().await;
session.cmd("EHLO domain", "550 5.5.0").await;
// EHLO capabilities evaluation
let response = session
.cmd("EHLO mx1.foobar.org", "250")
.await
.assert_contains("SIZE 1024")
.assert_contains("MT-PRIORITY NSEP")
.assert_contains("FUTURERELEASE 3600 ")
.assert_contains("STARTTLS");
// The advertised max-future-release-date-time is an RFC 3339 date-time
let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.map_or(0, |d| d.as_secs()) as i64;
let max_datetime = response
.iter()
.find_map(|line| line.split("FUTURERELEASE 3600 ").nth(1))
.and_then(|v| v.split_whitespace().next())
.and_then(DateTime::parse_rfc3339)
.expect("FUTURERELEASE did not advertise an RFC 3339 date-time")
.to_timestamp();
assert!(
((now + 3595)..=(now + 3605)).contains(&max_datetime),
"unexpected max-future-release-date-time {max_datetime}, now is {now}"
);
// SPF should be a Pass for 10.0.0.1
assert_eq!(
session.data.spf_ehlo.as_ref().unwrap().result(),
SpfResult::Pass
);
// Test SPF strict mode
session.data.helo_domain = "".into();
session.data.remote_ip_str = "10.0.0.2".into();
session.data.remote_ip = session.data.remote_ip_str.parse().unwrap();
session.stream.tls = true;
session.eval_session_params().await;
session.ingest(b"EHLO mx1.foobar.org\r\n").await.unwrap();
session.response().assert_code("550 5.7.23");
// EHLO capabilities evaluation
session.ingest(b"EHLO mx2.foobar.org\r\n").await.unwrap();
assert_eq!(
session.data.spf_ehlo.as_ref().unwrap().result(),
SpfResult::Pass
);
session
.response()
.assert_code("250")
.assert_contains("SIZE 2048")
.assert_not_contains("MT-PRIORITY")
.assert_not_contains("FUTURERELEASE")
.assert_not_contains("STARTTLS");
}