dmarc: add error handling and tests
This commit is contained in:
parent
376498f2e8
commit
8185d33fa5
@ -72,6 +72,7 @@ https://github.com/smtpd/qpsmtpd/wiki/DMARC-FAQ
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
use English qw/-no_match_vars/;
|
||||||
use Qpsmtpd::Constants;
|
use Qpsmtpd::Constants;
|
||||||
|
|
||||||
sub register {
|
sub register {
|
||||||
@ -90,16 +91,16 @@ sub register {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$self->{_dmarc} = Mail::DMARC::PurePerl->new();
|
$self->{_dmarc} = Mail::DMARC::PurePerl->new();
|
||||||
$self->register_hook('data_post_headers', 'data_post_handler');
|
$self->register_hook('data_post_headers', 'check_dmarc');
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub data_post_handler {
|
sub check_dmarc {
|
||||||
my ($self, $transaction) = @_;
|
my ($self, $transaction) = @_;
|
||||||
|
|
||||||
if ( $self->qp->connection->relay_client() ) {
|
if ( $self->qp->connection->relay_client() ) {
|
||||||
$self->log(LOGINFO, "skip, relay client" );
|
$self->log(LOGINFO, "skip, relay client" );
|
||||||
return DECLINED; # disable reporting to ourself
|
return DECLINED; # don't report to ourself
|
||||||
};
|
};
|
||||||
|
|
||||||
my $dmarc = $self->{_dmarc};
|
my $dmarc = $self->{_dmarc};
|
||||||
@ -117,19 +118,15 @@ sub data_post_handler {
|
|||||||
my @recipients = $transaction->recipients;
|
my @recipients = $transaction->recipients;
|
||||||
eval { $dmarc->envelope_to( lc $recipients[0]->host ); }; # optional
|
eval { $dmarc->envelope_to( lc $recipients[0]->host ); }; # optional
|
||||||
eval { $dmarc->envelope_from( $transaction->sender->host ); }; # may be <>
|
eval { $dmarc->envelope_from( $transaction->sender->host ); }; # may be <>
|
||||||
$dmarc->spf( $transaction->notes('dmarc_spf') );
|
eval { $dmarc->spf( $transaction->notes('dmarc_spf') ); };
|
||||||
my $dkim = $self->connection->notes('dkim_verifier');
|
my $dkim = $self->connection->notes('dkim_verifier');
|
||||||
if ( $dkim ) {
|
if ( $dkim ) { eval { $dmarc->dkim( $dkim ); }; };
|
||||||
eval { $dmarc->dkim( $dkim ); }
|
|
||||||
};
|
|
||||||
$dmarc->source_ip( $self->qp->connection->remote_ip );
|
$dmarc->source_ip( $self->qp->connection->remote_ip );
|
||||||
eval { $dmarc->validate(); };
|
eval { $dmarc->validate(); };
|
||||||
if ( $@ ) {
|
if ( $EVAL_ERROR ) {
|
||||||
$self->log(LOGERROR, $@ );
|
$self->log(LOGERROR, $@ );
|
||||||
return DECLINED if $self->is_immune;
|
return DECLINED if $self->is_immune;
|
||||||
$self->log(LOGINFO, "TODO: handle this validation failure");
|
return $self->get_reject( $@ );
|
||||||
return DECLINED;
|
|
||||||
return $self->get_reject( $@, $@ );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#$self->log(LOGINFO, "result: " . Dumper( $dmarc ) );
|
#$self->log(LOGINFO, "result: " . Dumper( $dmarc ) );
|
||||||
|
@ -1,64 +1,46 @@
|
|||||||
#!perl -w
|
#!perl -w
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
use English qw/-no_match_vars/;
|
||||||
use POSIX qw(strftime);
|
use POSIX qw(strftime);
|
||||||
|
|
||||||
use Qpsmtpd::Address;
|
use Qpsmtpd::Address;
|
||||||
use Qpsmtpd::Constants;
|
use Qpsmtpd::Constants;
|
||||||
|
|
||||||
|
my $remote_ip = '66.128.51.165';
|
||||||
my $test_email = 'matt@tnpi.net';
|
my $test_email = 'matt@tnpi.net';
|
||||||
|
|
||||||
sub register_tests {
|
sub register_tests {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
# TODO: test against newer DMARC plugin that uses Mail::DMARC
|
eval 'use Mail::DMARC';
|
||||||
}
|
if ($EVAL_ERROR) {
|
||||||
|
warn 'unable to load Mail::DMARC';
|
||||||
sub setup_test_headers {
|
return;
|
||||||
my $self = shift;
|
|
||||||
|
|
||||||
my $transaction = $self->qp->transaction;
|
|
||||||
my $address = Qpsmtpd::Address->new( "<$test_email>" );
|
|
||||||
my $header = Mail::Header->new(Modify => 0, MailFrom => "COERCE");
|
|
||||||
my $now = strftime "%a %b %e %H:%M:%S %Y", localtime time;
|
|
||||||
|
|
||||||
$transaction->sender($address);
|
|
||||||
$transaction->header($header);
|
|
||||||
$transaction->header->add('From', "<$test_email>");
|
|
||||||
$transaction->header->add('Date', $now );
|
|
||||||
$transaction->body_write( "test message body " );
|
|
||||||
|
|
||||||
$self->qp->connection->relay_client(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub test_fetch_dmarc_record {
|
|
||||||
my $self = shift;
|
|
||||||
|
|
||||||
foreach ( qw/ tnpi.net nictool.com / ) {
|
|
||||||
my @matches = $self->fetch_dmarc_record($_);
|
|
||||||
cmp_ok( scalar @matches, '==', 1, 'fetch_dmarc_record');
|
|
||||||
}
|
|
||||||
foreach ( qw/ example.com / ) {
|
|
||||||
my @matches = $self->fetch_dmarc_record($_);
|
|
||||||
cmp_ok( scalar @matches, '==', 0, 'fetch_dmarc_record');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$self->register_test('_check_dmarc');
|
||||||
}
|
}
|
||||||
|
|
||||||
sub test_get_organizational_domain {
|
sub _check_dmarc {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
$self->setup_test_headers();
|
$self->qp->connection->remote_ip($remote_ip);
|
||||||
my $transaction = $self->qp->transaction;
|
my $t = $self->qp->transaction;
|
||||||
|
$t->header(Mail::Header->new(Modify => 0, MailFrom => "COERCE"));
|
||||||
|
$t->sender(Qpsmtpd::Address->new( "<$test_email>" ));
|
||||||
|
$t->header->add('Date', strftime "%a %b %e %H:%M:%S %Y", localtime time);
|
||||||
|
$t->body_write( "test message body " );
|
||||||
|
|
||||||
cmp_ok( $self->get_organizational_domain('test.www.tnpi.net'), 'eq', 'tnpi.net' );
|
# no From header, reject as invalid message
|
||||||
cmp_ok( $self->get_organizational_domain('www.example.co.uk'), 'eq', 'example.co.uk' );
|
my ($rc, $msg) = $self->check_dmarc($t);
|
||||||
cmp_ok( $self->get_organizational_domain('plus.google.com'), 'eq', 'google.com' );
|
cmp_ok($rc, '==', DENY, "no From header, $msg");
|
||||||
}
|
|
||||||
|
|
||||||
sub test_discover_policy {
|
$t->header->add('From', "<$test_email>");
|
||||||
my $self = shift;
|
($rc, $msg) = $self->check_dmarc($t);
|
||||||
|
cmp_ok($rc, '==', DENY, "$msg");
|
||||||
$self->setup_test_headers();
|
cmp_ok($msg, 'eq', 'failed DMARC policy', 'check_dmarc, no SPF');
|
||||||
|
|
||||||
ok( $self->discover_policy( 'tnpi.net' ), 'discover_policy' );
|
#warn $self->qp->connection->notes('authentication_results');
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user