qpsmtpd/plugins/bogus_bounce

97 lines
2.2 KiB
Plaintext
Raw Normal View History

#!perl -w
=head1 NAME
bogus_bounce - Check that a bounce message isn't bogus
=head1 DESCRIPTION
This plugin is designed to reject bogus bounce messages.
In our case a bogus bounce message is defined as a bounce message
which has more than a single recipient.
=head1 CONFIGURATION
Only a single argument is recognized and is assumed to be the default
action. Valid settings are:
=over 8
=item log
Merely log the receipt of the bogus bounce (the default behaviour).
=item deny
Deny with a hard error code.
=item denysoft
Deny with a soft error code.
=back
=head1 AUTHOR
2010 - Steve Kemp - http://steve.org.uk/Software/qpsmtpd/
2013 - Matt Simerson - added Return Path check
=cut
sub register {
my ($self, $qp) = (shift, shift);
if ( @_ % 2 ) {
$self->{_args}{action} = shift;
}
else {
$self->{_args} = { @_ };
};
if ( ! defined $self->{_args}{reject} ) {
$self->{_args}{reject} = 0; # legacy default
};
# we only need to check for deferral, default is DENY
if ( $self->{_args}{action} && $self->{_args}{action} =~ /soft/i ) {
$self->{_args}{reject_type} = 'temp';
}
}
sub hook_data_post {
my ($self, $transaction) = (@_);
#
# Find the sender, quit processing if this isn't a bounce.
#
my $sender = $transaction->sender->address || undef;
if ( $sender && $sender ne '<>') {
$self->log(LOGINFO, "pass, not a null sender");
return DECLINED;
};
# at this point we know it is a bounce, via the null-envelope.
#
# Count the recipients. Valid bounces have a single recipient
#
my @to = $transaction->recipients || ();
if (scalar @to != 1) {
$self->log(LOGINFO, "fail, bogus bounce to: " . join(',', @to));
return $self->get_reject( "fail, this bounce message does not have 1 recipient" );
};
# validate that Return-Path is empty, RFC 3834
my $rp = $transaction->header->get('Return-Path');
if ( $rp && $rp ne '<>' ) {
$self->log(LOGINFO, "fail, bounce messages must not have a Return-Path");
return $self->get_reject( "a bounce return path must be empty (RFC 3834)" );
};
$self->log(LOGINFO, "pass, single recipient, empty Return-Path");
return DECLINED;
}