badmailfromto: added strictures, tests, and

rearranged portionsn of logic for ease of reading
This commit is contained in:
Matt Simerson 2012-05-05 01:04:33 -04:00 committed by Robert
parent c44db8c9e2
commit 1910fabf0e
2 changed files with 81 additions and 21 deletions

View File

@ -17,14 +17,14 @@ Based heavily on check_badmailfrom.
=cut =cut
use strict;
use Qpsmtpd::Constants;
sub hook_mail { sub hook_mail {
my ($self, $transaction, $sender, %param) = @_; my ($self, $transaction, $sender, %param) = @_;
my @badmailfromto = $self->qp->config("badmailfromto") my @badmailfromto = $self->qp->config("badmailfromto");
or return (DECLINED); return DECLINED if $self->is_sender_immune( $sender, \@badmailfromto );
return (DECLINED) unless ($sender->format ne "<>"
and $sender->host && $sender->user);
my $host = lc $sender->host; my $host = lc $sender->host;
my $from = lc($sender->user) . '@' . $host; my $from = lc($sender->user) . '@' . $host;
@ -33,27 +33,51 @@ sub hook_mail {
$bad =~ s/^\s*(\S+).*/$1/; $bad =~ s/^\s*(\S+).*/$1/;
next unless $bad; next unless $bad;
$bad = lc $bad; $bad = lc $bad;
$self->log(LOGWARN, "Bad badmailfromto config: No \@ sign in $bad") and next unless $bad =~ m/\@/; if ( $bad !~ m/\@/ ) {
$transaction->notes('badmailfromto', "$bad") $self->log(LOGWARN, 'badmailfromto: bad config, no @ sign in '. $bad);
if ($bad eq $from) next;
|| (substr($bad,0,1) eq '@' && $bad eq "\@$host"); };
if ( $bad eq $from || (substr($bad,0,1) eq '@' && $bad eq "\@$host") ) {
$transaction->notes('badmailfromto', $bad);
};
} }
return (DECLINED); return (DECLINED);
} }
sub hook_rcpt { sub hook_rcpt {
my ($self, $transaction, $rcpt, %param) = @_; my ($self, $transaction, $rcpt, %param) = @_;
my $recipient = lc($rcpt->user) . '@' . lc($rcpt->host); my $recipient = lc($rcpt->user) . '@' . lc($rcpt->host);
my $sender = $transaction->notes('badmailfromto'); my $sender = $transaction->notes('badmailfromto') or do {
if ($sender) { $self->log(LOGDEBUG, "pass: sender not listed");
my @badmailfromto = $self->qp->config("badmailfromto") return (DECLINED);
or return (DECLINED); };
foreach (@badmailfromto) { foreach ( $self->qp->config("badmailfromto") ) {
my ($from, $to) = m/^\s*(\S+)\t(\S+).*/; my ($from, $to) = m/^\s*(\S+)\t(\S+).*/;
return (DENY, "mail to $recipient not accepted here") return (DENY, "mail to $recipient not accepted here")
if lc($from) eq $sender and lc($to) eq $recipient; if lc($from) eq $sender && lc($to) eq $recipient;
} }
} $self->log(LOGDEBUG, "pass: recipient not listed");
return (DECLINED); return (DECLINED);
} }
sub is_sender_immune {
my ($self, $sender, $badmf ) = @_;
if ( ! scalar @$badmf ) {
$self->log(LOGDEBUG, 'skip: empty list');
return 1;
};
if ( ! $sender || $sender->format eq '<>' ) {
$self->log(LOGDEBUG, 'skip: null sender');
return 1;
};
if ( ! $sender->host || ! $sender->user ) {
$self->log(LOGDEBUG, 'skip: missing user or host');
return 1;
};
return;
};

View File

@ -0,0 +1,36 @@
#!perl -w
use strict;
use Data::Dumper;
use Qpsmtpd::Address;
sub register_tests {
my $self = shift;
$self->register_test("test_badmailfromto_is_sender_immune", 5);
}
sub test_badmailfromto_is_sender_immune {
my $self = shift;
my $transaction = $self->qp->transaction;
my $test_email = 'matt@test.com';
$transaction->sender( Qpsmtpd::Address->new( "<$test_email>" ) );
ok( $self->is_sender_immune( $transaction->sender, [] ), "is_immune, empty list");
$transaction->sender( Qpsmtpd::Address->new( '<>' ) );
ok( $self->is_sender_immune( $transaction->sender, ['bad@example.com'] ), "is_immune, null sender");
my $address = Qpsmtpd::Address->new( '<matt@>' );
$transaction->sender($address);
ok( $self->is_sender_immune( $transaction->sender, ['bad@example.com'] ), "is_immune, missing host");
$address = Qpsmtpd::Address->new( '<@example.com>' );
$transaction->sender($address);
ok( $self->is_sender_immune( $transaction->sender, ['bad@example.com'] ), "is_immune, missing user");
$transaction->sender( Qpsmtpd::Address->new( '<matt@example.com>' ) );
ok( ! $self->is_sender_immune( $transaction->sender, ['bad@example.com'] ), "is_immune, false");
};