svn commit: r1927705 - in spamassassin/trunk: lib/Mail/SpamAssassin lib/Mail/SpamAssassin/Plugin t
[email protected] Fri, 08 Aug 2025 20:01:04 -0000
Newsgroups
gmane.mail.spam.spamassassin.cvs
Message-ID
<175468326439.214148.17413401968534344796@svn02-us-east.apache.org>
Author: fkento
Date: Fri Aug 8 20:01:04 2025
New Revision: 1927705
Log:
Bug 8340: DMARC Avoidance
Added:
spamassassin/trunk/t/util_parse_header_addresses.t
Modified:
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DMARC.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Util.pm
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DMARC.pm
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DMARC.pm Fri Aug 8 18:50:51 2025 (r1927704)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DMARC.pm Fri Aug 8 20:01:04 2025 (r1927705)
@@ -69,6 +69,7 @@ my $VERSION = 0.2;
use Mail::SpamAssassin;
use Mail::SpamAssassin::Plugin;
+use Mail::SpamAssassin::Util qw(is_fqdn_valid);
our @ISA = qw(Mail::SpamAssassin::Plugin);
@@ -274,6 +275,10 @@ sub _check_dmarc {
return if !defined $mfrom_domain;
dbg("EnvelopeFrom header not found, using From");
}
+ if(!is_fqdn_valid($mfrom_domain)) {
+ dbg("Invalid domain name $mfrom_domain");
+ return;
+ }
my $spf_status = 'none';
if ($pms->{spf_pass}) { $spf_status = 'pass'; }
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Util.pm
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Util.pm Fri Aug 8 18:50:51 2025 (r1927704)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Util.pm Fri Aug 8 20:01:04 2025 (r1927705)
@@ -2635,6 +2635,7 @@ sub _parse_header_addresses {
my $comment = defined $5 ? $5 : undef;
my ($user, $host, $invalid);
+ $invalid = 0;
# Check relaxed <> capture
if (defined $2) {
@@ -2642,7 +2643,7 @@ sub _parse_header_addresses {
$address =~ s/\((?:|(?:[^()\\]++|\\.)*+)\)//gs;
# Validate as somewhat email looking
if ($address !~ /^$header_address_mailre$/) {
- $address = undef;
+ $invalid = 1;
}
}
@@ -2670,6 +2671,7 @@ sub _parse_header_addresses {
}
}
$phrase = $newphrase;
+ $phrase =~ s/^\s+|\s+\z//gs; # Trim whitespace
# If we only have phrase which looks email, swap when valid
# Check all in one if, either swap or don't
@@ -2710,7 +2712,7 @@ sub _parse_header_addresses {
($user, $host) = ($2, $3);
}
- $invalid = !defined $host || !is_fqdn_valid(idn_to_ascii($host), 1);
+ $invalid = 1 if !defined $host || !is_fqdn_valid(idn_to_ascii($host), 1);
push @results, {
'phrase' => $phrase,
'user' => $user,
Added: spamassassin/trunk/t/util_parse_header_addresses.t
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ spamassassin/trunk/t/util_parse_header_addresses.t Fri Aug 8 20:01:04 2025 (r1927705)
@@ -0,0 +1,149 @@
+#!/usr/bin/perl -T
+use utf8;
+use open qw( :std :encoding(UTF-8) );
+use lib '.'; use lib 't';
+use SATest; sa_t_init("util_parse_header_addresses");
+use Test::More;
+
+use strict;
+require Mail::SpamAssassin::Util;
+
+my @data = (
+ {
+ in => 'companyname <"no reply"@example.com>',
+ out => [
+ {
+ 'phrase' => 'companyname',
+ 'user' => '"no reply"',
+ 'host' => 'example.com',
+ 'address' => '"no reply"@example.com',
+ 'comment' => undef,
+ 'invalid' => 0
+ }
+ ],
+ },
+ {
+ in => 'companyname <no [email protected] >',
+ out => [
+ {
+ 'phrase' => 'companyname',
+ 'user' => 'no reply',
+ 'host' => 'example.com',
+ 'address' => 'no [email protected] ',
+ 'comment' => undef,
+ 'invalid' => 1
+ }
+ ],
+ },
+ {
+ in => 'Support <[email protected] _bar.com>',
+ out => [
+ {
+ 'phrase' => 'Support',
+ 'user' => 'support',
+ 'host' => 'foo.com_bar.com',
+ 'address' => '[email protected] _bar.com',
+ 'comment' => undef,
+ 'invalid' => 1
+ }
+ ],
+ },
+ {
+ in => 'user@example.みんな',
+ out => [
+ {
+ 'phrase' => undef,
+ 'user' => 'user',
+ 'host' => 'example.みんな',
+ 'address' => 'user@example.みんな',
+ 'comment' => undef,
+ 'invalid' => 0
+ }
+ ],
+ },
+ {
+ in => 'John Doe <[email protected] > (Support Team)',
+ out => [
+ {
+ 'phrase' => 'John Doe',
+ 'user' => 'jdoe',
+ 'host' => 'example.com',
+ 'address' => '[email protected] ',
+ 'comment' => 'Support Team',
+ 'invalid' => 0
+ }
+ ],
+ },
+ {
+ in => 'Alice <[email protected] >, Bob <[email protected] >',
+ out => [
+ {
+ 'phrase' => 'Alice',
+ 'user' => 'alice',
+ 'host' => 'example.com',
+ 'address' => '[email protected] ',
+ 'comment' => undef,
+ 'invalid' => 0
+ },
+ {
+ 'phrase' => 'Bob',
+ 'user' => 'bob',
+ 'host' => 'example.org',
+ 'address' => '[email protected] ',
+ 'comment' => undef,
+ 'invalid' => 0
+ }
+ ],
+ },
+ {
+ in => 'Root User <root>',
+ out => [
+ {
+ 'phrase' => 'Root User',
+ 'user' => 'root',
+ 'host' => undef,
+ 'address' => 'root',
+ 'comment' => undef,
+ 'invalid' => 1
+ }
+ ],
+ },
+ {
+ in => 'Invalid <[email protected] >',
+ out => [
+ {
+ 'phrase' => 'Invalid',
+ 'user' => 'user',
+ 'host' => 'domain..com',
+ 'address' => '[email protected] ',
+ 'comment' => undef,
+ 'invalid' => 1
+ }
+ ],
+ },
+ {
+ in => '<invalid@address>',
+ out => [
+ {
+ 'phrase' => undef,
+ 'user' => 'invalid',
+ 'host' => 'address',
+ 'address' => 'invalid@address',
+ 'comment' => undef,
+ 'invalid' => 1
+ }
+ ],
+ },
+);
+
+plan tests => scalar @data;
+
+foreach my $test (@data) {
+ my $in = $test->{in};
+ my $out = $test->{out};
+
+ my @addresses = Mail::SpamAssassin::Util::parse_header_addresses($in);
+
+ is_deeply(\@addresses, $out, "parse_header_addresses('$in')");
+}
+