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.
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::core::Session;
|
||||
use ahash::AHashMap;
|
||||
use common::USER_AGENT;
|
||||
use mail_auth::report::{
|
||||
ActionDisposition, AuthFailureType, DeliveryResult, DmarcResult, Feedback, FeedbackType,
|
||||
Report, tlsrpt::TlsReport,
|
||||
};
|
||||
use std::{collections::hash_map::Entry, time::SystemTime};
|
||||
use store::write::now;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use trc::IncomingReportEvent;
|
||||
|
||||
impl<T: AsyncWrite + AsyncRead + Unpin> Session<T> {
|
||||
pub fn new_auth_failure(&self, ft: AuthFailureType, rejected: bool) -> Feedback<'_> {
|
||||
Feedback::new(FeedbackType::AuthFailure)
|
||||
.with_auth_failure(ft)
|
||||
.with_arrival_date(
|
||||
SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map_or(0, |d| d.as_secs()) as i64,
|
||||
)
|
||||
.with_source_ip(self.data.remote_ip)
|
||||
.with_reporting_mta(&self.hostname)
|
||||
.with_user_agent(USER_AGENT)
|
||||
.with_delivery_result(if rejected {
|
||||
DeliveryResult::Reject
|
||||
} else {
|
||||
DeliveryResult::Unspecified
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_report(&self) -> bool {
|
||||
let analysis = &self.server.core.smtp.report.analysis;
|
||||
|
||||
self.data
|
||||
.rcpt_to
|
||||
.iter()
|
||||
.any(|addr| analysis.is_report_address(addr.report_address()))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait LogReport {
|
||||
fn log(&self);
|
||||
}
|
||||
|
||||
impl LogReport for Report {
|
||||
fn log(&self) {
|
||||
let mut dmarc_pass = 0;
|
||||
let mut dmarc_quarantine = 0;
|
||||
let mut dmarc_reject = 0;
|
||||
let mut dmarc_none = 0;
|
||||
let mut dkim_pass = 0;
|
||||
let mut dkim_fail = 0;
|
||||
let mut dkim_none = 0;
|
||||
let mut spf_pass = 0;
|
||||
let mut spf_fail = 0;
|
||||
let mut spf_none = 0;
|
||||
|
||||
for record in self.records() {
|
||||
let count = std::cmp::min(record.count(), 1);
|
||||
|
||||
match record.action_disposition() {
|
||||
ActionDisposition::Pass => {
|
||||
dmarc_pass += count;
|
||||
}
|
||||
ActionDisposition::Quarantine => {
|
||||
dmarc_quarantine += count;
|
||||
}
|
||||
ActionDisposition::Reject => {
|
||||
dmarc_reject += count;
|
||||
}
|
||||
ActionDisposition::None | ActionDisposition::Unspecified => {
|
||||
dmarc_none += count;
|
||||
}
|
||||
}
|
||||
match record.dmarc_dkim_result() {
|
||||
DmarcResult::Pass => {
|
||||
dkim_pass += count;
|
||||
}
|
||||
DmarcResult::Fail => {
|
||||
dkim_fail += count;
|
||||
}
|
||||
DmarcResult::Unspecified => {
|
||||
dkim_none += count;
|
||||
}
|
||||
}
|
||||
match record.dmarc_spf_result() {
|
||||
DmarcResult::Pass => {
|
||||
spf_pass += count;
|
||||
}
|
||||
DmarcResult::Fail => {
|
||||
spf_fail += count;
|
||||
}
|
||||
DmarcResult::Unspecified => {
|
||||
spf_none += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trc::event!(
|
||||
IncomingReport(
|
||||
if (dmarc_reject + dmarc_quarantine + dkim_fail + spf_fail) > 0 {
|
||||
IncomingReportEvent::DmarcReportWithWarnings
|
||||
} else {
|
||||
IncomingReportEvent::DmarcReport
|
||||
}
|
||||
),
|
||||
RangeFrom = trc::Value::Timestamp(self.date_range_begin()),
|
||||
RangeTo = trc::Value::Timestamp(self.date_range_end()),
|
||||
Domain = self.domain().to_string(),
|
||||
From = self.email().to_string(),
|
||||
Id = self.report_id().to_string(),
|
||||
DmarcPass = dmarc_pass,
|
||||
DmarcQuarantine = dmarc_quarantine,
|
||||
DmarcReject = dmarc_reject,
|
||||
DmarcNone = dmarc_none,
|
||||
DkimPass = dkim_pass,
|
||||
DkimFail = dkim_fail,
|
||||
DkimNone = dkim_none,
|
||||
SpfPass = spf_pass,
|
||||
SpfFail = spf_fail,
|
||||
SpfNone = spf_none,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl LogReport for TlsReport {
|
||||
fn log(&self) {
|
||||
for policy in self.policies.iter().take(5) {
|
||||
let mut details = AHashMap::with_capacity(policy.failure_details.len());
|
||||
for failure in &policy.failure_details {
|
||||
let num_failures = std::cmp::min(1, failure.failed_session_count);
|
||||
match details.entry(failure.result_type) {
|
||||
Entry::Occupied(mut e) => {
|
||||
*e.get_mut() += num_failures;
|
||||
}
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(num_failures);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trc::event!(
|
||||
IncomingReport(if policy.summary.total_failure > 0 {
|
||||
IncomingReportEvent::TlsReportWithWarnings
|
||||
} else {
|
||||
IncomingReportEvent::TlsReport
|
||||
}),
|
||||
RangeFrom =
|
||||
trc::Value::Timestamp(self.date_range.start_datetime.to_timestamp() as u64),
|
||||
RangeTo = trc::Value::Timestamp(self.date_range.end_datetime.to_timestamp() as u64),
|
||||
Domain = policy.policy.policy_domain.clone(),
|
||||
From = self.contact_info.as_deref().unwrap_or_default().to_string(),
|
||||
Id = self.report_id.clone(),
|
||||
Policy = format!("{:?}", policy.policy.policy_type),
|
||||
TotalSuccesses = policy.summary.total_success,
|
||||
TotalFailures = policy.summary.total_failure,
|
||||
Details = format!("{details:?}"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LogReport for Feedback<'_> {
|
||||
fn log(&self) {
|
||||
trc::event!(
|
||||
IncomingReport(match self.feedback_type() {
|
||||
mail_auth::report::FeedbackType::Abuse => IncomingReportEvent::AbuseReport,
|
||||
mail_auth::report::FeedbackType::AuthFailure =>
|
||||
IncomingReportEvent::AuthFailureReport,
|
||||
mail_auth::report::FeedbackType::Fraud => IncomingReportEvent::FraudReport,
|
||||
mail_auth::report::FeedbackType::NotSpam => IncomingReportEvent::NotSpamReport,
|
||||
mail_auth::report::FeedbackType::Other => IncomingReportEvent::OtherReport,
|
||||
mail_auth::report::FeedbackType::Virus => IncomingReportEvent::VirusReport,
|
||||
}),
|
||||
RangeFrom = trc::Value::Timestamp(
|
||||
self.arrival_date()
|
||||
.map(|d| d as u64)
|
||||
.unwrap_or_else(|| { now() })
|
||||
),
|
||||
Domain = self
|
||||
.reported_domain()
|
||||
.iter()
|
||||
.map(|d| trc::Value::String(d.as_ref().into()))
|
||||
.collect::<Vec<_>>(),
|
||||
Hostname = self.reporting_mta().map(|d| trc::Value::String(d.into())),
|
||||
Url = self
|
||||
.reported_uri()
|
||||
.iter()
|
||||
.map(|d| trc::Value::String(d.as_ref().into()))
|
||||
.collect::<Vec<_>>(),
|
||||
RemoteIp = self.source_ip(),
|
||||
Total = self.incidents(),
|
||||
Result = format!("{:?}", self.delivery_result()),
|
||||
Details = self
|
||||
.authentication_results()
|
||||
.iter()
|
||||
.map(|d| trc::Value::String(d.as_ref().into()))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user