Skip to content

Commit 0d91505

Browse files
authored
fix: standardize X-Mailer, version string, and forensic relay tracing (#429)
* fix: use X-Mailer instead of User-Agent in milter failure reports opendmarc-reports already labels aggregate reports with X-Mailer: opendmarc-reports v<version>. The milter's own AFRF failure-report path used User-Agent instead, so the two report types disagreed on which header identifies the generating software. Standardize both on X-Mailer. * fix: align opendmarc-reports version string and mark forensic relay hop opendmarc-reports' $version used the plain release version with no git-describe logic, while the milter's DMARCF_VERSION already includes a dirty-build hash suffix; identical dev builds reported different version strings depending on which program authored a report. configure.ac now AC_SUBST's DMARCF_VERSION for use in opendmarc-reports.in. Also: --forensic mode relays the milter-composed message via Net::SMTP without ever picking up a Received: header, unlike the direct sendmail -t path which gets one for free from the local MTA. Prepend a single Received: line identifying the relay hop, added before archiving so --archive-dir captures what was actually sent.
1 parent 9553894 commit 0d91505

4 files changed

Lines changed: 13 additions & 2 deletions

File tree

CHANGES-202605.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ Significant gaps between the generated aggregate report XML and RFC 7489 require
9090
- **Distinct `ReportCommand` exit code for fully-suppressed reports**: When every recipient of a forensic report is suppressed by `NoReportsList`, StaleMARC, or the suppressions table, `opendmarc-reports --forensic` now exits `2` instead of `0`, and the milter logs this at `LOG_INFO` rather than treating it as a `ReportCommand` failure (previously indistinguishable from a normal send in the logs). (#424)
9191
- **`--archive-dir`**: New option saves a copy of every outbound report -- the full message as handed to SMTP, not just the gzipped XML or AFRF attachment -- to a directory for later review (e.g. RFC-compliance checking). Applies to both aggregate and forensic modes; suppressed and `--test`-mode reports are not archived. (#424)
9292
- **Bare `NoReportsList` domain entries now also suppress `--forensic` reports**: Previously a bare sending-domain entry only suppressed aggregate reports (via `--skipdomains`); the manpage explicitly noted "no effect on failure report (ruf=) suppression in the milter itself." `opendmarc-reports --forensic` now reads the `Reported-Domain` field from the AFRF message and checks it against the same `--skipdomains`/`NoReportsList`, StaleMARC, and suppressions-DB logic the aggregate path uses, discarding the report (exit code 2) if the domain is suppressed. Still has no effect when `ReportCommand` pipes directly to `sendmail` rather than through `opendmarc-reports`, since only the latter performs the check. (#425)
93+
- **Milter-generated failure reports now use `X-Mailer` instead of `User-Agent` for version identification**: `opendmarc-reports` already labelled aggregate reports with `X-Mailer: opendmarc-reports v<version>`, the long-established email convention for identifying the software that generated a message. The milter's own AFRF failure-report path used `User-Agent: %s/%s` instead, so the two report types disagreed on which header to use. Both now use `X-Mailer`.
94+
- **`opendmarc-reports`' version string now includes the git hash on development builds**: The milter's `DMARCF_VERSION` already ran `git describe --tags --dirty` at configure time so dev builds show a hash suffix (e.g. `1.4.2-3-gabc1234-dirty`); `opendmarc-reports` used the plain release version with no such logic, so identical dev builds reported different version strings depending on which program authored the report. `configure.ac` now `AC_SUBST`s `DMARCF_VERSION`, and `opendmarc-reports.in` uses it in place of `@VERSION@`.
95+
- **`opendmarc-reports --forensic` now leaves a `Received:` trace when relaying**: A report relayed by the milter's `ReportCommand` directly to `sendmail -t` picks up a normal `Received:` header from the local MTA, but `--forensic` mode talks to the configured SMTP server directly via `Net::SMTP` and otherwise passes the milter-composed message through completely untouched, leaving no indication the message passed through `opendmarc-reports` at all. A single `Received: by <host> (opendmarc-reports v<version>) via forensic relay; <date>` line is now prepended before sending (and before the message is archived via `--archive-dir`, so the archived copy matches what was actually sent), applied identically regardless of `--verp`.
9396

9497
---
9598

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ fi
8282
AC_MSG_RESULT([$DMARCF_VERSION])
8383
AC_DEFINE_UNQUOTED([DMARCF_VERSION], ["$DMARCF_VERSION"],
8484
[Version string, including git hash on development builds])
85+
AC_SUBST([DMARCF_VERSION])
8586

8687
#
8788
# Hexadecimal version, for use in generating dmarc.h

opendmarc/opendmarc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3635,7 +3635,7 @@ mlfi_eom(SMFICTX *ctx)
36353635
"Version: 1\n");
36363636

36373637
dmarcf_dstring_printf(dfc->mctx_afrf,
3638-
"User-Agent: %s/%s\n",
3638+
"X-Mailer: %s/%s\n",
36393639
DMARCF_PRODUCTNS, DMARCF_VERSION);
36403640

36413641
dmarcf_dstring_cat(dfc->mctx_afrf,

reports/opendmarc-reports.in

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ require LWP::UserAgent;
3030

3131
# general
3232
my $progname = basename($0);
33-
my $version = "@VERSION@";
33+
my $version = "@DMARCF_VERSION@";
3434
my $verbose = 0;
3535
my $helponly = 0;
3636
my $showversion = 0;
@@ -753,6 +753,13 @@ if ($forensic)
753753
$smtp = smtp_connect();
754754
exit(1) unless defined($smtp);
755755

756+
# Mark the relay hop so a recipient (or an admin troubleshooting
757+
# delivery) can tell this report passed through opendmarc-reports
758+
# rather than going straight out via the milter's ReportCommand
759+
# (e.g. "sendmail -t"), which leaves no such trace of its own.
760+
my $received_datestr = strftime("%a, %e %b %Y %H:%M:%S %z (%Z)", localtime);
761+
$message = "Received: by " . hostfqdn() . " (opendmarc-reports v$version) via forensic relay; $received_datestr\n" . $message;
762+
756763
my $archive_label = $rcpts[0];
757764
$archive_label .= "+" . (scalar(@rcpts) - 1) if @rcpts > 1;
758765
archive_report($archive_label, $message);

0 commit comments

Comments
 (0)