Milter: keep the reply code and text in delivery traces #293
No files matched your search
@@ -2,6 +2,8 @@
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*
|
||||
* Modified by Coffey Labs in 2026 for INBUXA.
|
||||
*/
|
||||
|
||||
use super::{Action, Error, Macros, Modification};
|
||||
@@ -77,23 +79,36 @@ impl<T: SessionStream> Session<T> {
|
||||
}
|
||||
}
|
||||
Err(Rejection::Action(action)) => {
|
||||
trc::event!(
|
||||
Milter(match &action {
|
||||
Action::Discard => MilterEvent::ActionDiscard,
|
||||
Action::Reject => MilterEvent::ActionReject,
|
||||
Action::TempFail => MilterEvent::ActionTempFail,
|
||||
Action::ReplyCode { .. } => {
|
||||
MilterEvent::ActionReplyCode
|
||||
}
|
||||
Action::Shutdown => MilterEvent::ActionShutdown,
|
||||
Action::ConnectionFailure => MilterEvent::ActionConnectionFailure,
|
||||
Action::Accept | Action::Continue => unreachable!(),
|
||||
}),
|
||||
SpanId = self.data.session_id,
|
||||
QueueId = queue_id,
|
||||
Id = milter.id.to_string(),
|
||||
Elapsed = time.elapsed(),
|
||||
);
|
||||
if let Action::ReplyCode { code, text } = &action {
|
||||
trc::event!(
|
||||
Milter(MilterEvent::ActionReplyCode),
|
||||
SpanId = self.data.session_id,
|
||||
QueueId = queue_id,
|
||||
Id = milter.id.to_string(),
|
||||
Code = std::str::from_utf8(code)
|
||||
.ok()
|
||||
.and_then(|code| code.parse::<u16>().ok()),
|
||||
Details = text.trim_end().to_string(),
|
||||
Elapsed = time.elapsed(),
|
||||
);
|
||||
} else {
|
||||
trc::event!(
|
||||
Milter(match &action {
|
||||
Action::Discard => MilterEvent::ActionDiscard,
|
||||
Action::Reject => MilterEvent::ActionReject,
|
||||
Action::TempFail => MilterEvent::ActionTempFail,
|
||||
Action::Shutdown => MilterEvent::ActionShutdown,
|
||||
Action::ConnectionFailure => MilterEvent::ActionConnectionFailure,
|
||||
Action::ReplyCode { .. } | Action::Accept | Action::Continue => {
|
||||
unreachable!()
|
||||
}
|
||||
}),
|
||||
SpanId = self.data.session_id,
|
||||
QueueId = queue_id,
|
||||
Id = milter.id.to_string(),
|
||||
Elapsed = time.elapsed(),
|
||||
);
|
||||
}
|
||||
|
||||
return Err(match action {
|
||||
Action::Discard => FilterResponse::accept(),
|
||||
|
||||
@@ -52,6 +52,7 @@ use tokio::{
|
||||
net::{TcpListener, TcpStream},
|
||||
sync::watch,
|
||||
};
|
||||
use trc::{Collector, EventType, Key, MilterEvent, ipc::subscriber::SubscriberBuilder};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct HeaderTest {
|
||||
@@ -145,17 +146,51 @@ async fn milter_session() {
|
||||
.await;
|
||||
test.assert_no_events();
|
||||
|
||||
// Test reply code
|
||||
// Capture the actual event emitted by the SMTP session, not a reconstructed event.
|
||||
let subscriber_id = "smtp-milter-reply-code".to_string();
|
||||
let subscriber = SubscriberBuilder::new(subscriber_id.clone())
|
||||
.set_interests([EventType::Milter(MilterEvent::ActionReplyCode)])
|
||||
.with_lossy(false);
|
||||
Collector::union_interests(subscriber.interests.clone());
|
||||
let (_, mut events) = subscriber.register();
|
||||
tokio::time::timeout(Duration::from_secs(5), async {
|
||||
while !Collector::get_subscribers().contains(&subscriber_id) {
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
}
|
||||
})
|
||||
.await
|
||||
.expect("Milter trace subscriber was not registered");
|
||||
|
||||
// Test reply code: the SMTP response and its trace retain the Milter's code/text.
|
||||
session
|
||||
.send_message(
|
||||
"[email protected]",
|
||||
&["[email protected]"],
|
||||
"test:no_dkim",
|
||||
"321",
|
||||
"321 test",
|
||||
)
|
||||
.await;
|
||||
test.assert_no_events();
|
||||
|
||||
let event = tokio::time::timeout(Duration::from_secs(5), async {
|
||||
loop {
|
||||
for event in events.recv().await.expect("Milter trace subscriber closed") {
|
||||
if event.span_id() == Some(session.data.session_id) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
.expect("Milter reply-code event was not emitted");
|
||||
Collector::remove_subscriber(subscriber_id);
|
||||
assert_eq!(
|
||||
event.inner.typ,
|
||||
EventType::Milter(MilterEvent::ActionReplyCode)
|
||||
);
|
||||
assert_eq!(event.value_as_uint(Key::Code), Some(321));
|
||||
assert_eq!(event.value_as_str(Key::Details), Some("test"));
|
||||
|
||||
// Test accept with header addition
|
||||
session
|
||||
.send_message(
|
||||
|
||||
Reference in new issue
Block a user