updated plugins to use QP::Plugins::is_immune

This commit is contained in:
Matt Simerson 2012-06-02 21:44:46 -04:00
parent 3a016b1da8
commit 57a0e4ba7b
13 changed files with 82 additions and 66 deletions

View File

@ -0,0 +1,2 @@
# test entry for dnsbl plugin
192.168.99.5

View File

@ -58,7 +58,8 @@ sub hook_mail {
@badmailfrom = @{$self->{_badmailfrom_config}};
};
return DECLINED if $self->is_immune( $sender, \@badmailfrom );
return DECLINED if $self->is_immune();
return DECLINED if $self->is_immune_sender( $sender, \@badmailfrom );
my $host = lc $sender->host;
my $from = lc($sender->user) . '@' . $host;
@ -104,7 +105,7 @@ sub hook_rcpt {
return (DENY, $note);
}
sub is_immune {
sub is_immune_sender {
my ($self, $sender, $badmf ) = @_;
if ( ! scalar @$badmf ) {

View File

@ -49,12 +49,15 @@ use Qpsmtpd::DSN;
sub hook_rcpt {
my ($self, $transaction, $recipient, %param) = @_;
return (DECLINED) if $self->qp->connection->relay_client();
return (DECLINED) if $self->is_immune();
my ($host, $to) = $self->get_host_and_to( $recipient )
or return (DECLINED);
my @badrcptto = $self->qp->config("badrcptto") or return (DECLINED);
my @badrcptto = $self->qp->config("badrcptto") or do {
$self->log(LOGINFO, "skip: empty config");
return (DECLINED);
};
for my $line (@badrcptto) {
$line =~ s/^\s+//g; # trim leading whitespace

View File

@ -119,7 +119,7 @@ sub apr_connect_handler {
my ($self, $transaction) = @_;
return DECLINED unless $self->{_args}{'check-at'}{CONNECT};
return DECLINED if $self->qp->connection->notes('whitelisthost');
return DECLINED if $self->is_immune();
my $c = $self->qp->{conn} or return DECLINED;
my $socket = $c->client_socket or return DECLINED;
@ -140,7 +140,7 @@ sub apr_data_handler {
my ($self, $transaction) = @_;
return DECLINED unless $self->{_args}{'check-at'}{DATA};
return DECLINED if $self->qp->connection->notes('whitelisthost');
return DECLINED if $self->is_immune();
my $c = $self->qp->{conn} or return DECLINED;
my $socket = $c->client_socket or return DECLINED;

View File

@ -136,6 +136,7 @@ sub hook_connect {
# perform RBLSMTPD checks to mimic Dan Bernstein's rblsmtpd
return DECLINED if $self->is_set_rblsmtpd();
return DECLINED if $self->is_immune();
return DECLINED if $self->ip_whitelisted();
my %dnsbl_zones = map { (split /:/, $_, 2)[0,1] } $self->qp->config('dnsbl_zones');
@ -196,23 +197,12 @@ sub is_set_rblsmtpd {
};
sub ip_whitelisted {
my ($self) = @_;
my $self = shift;
my $remote_ip = $self->qp->connection->remote_ip;
my $white = $self->connection->notes('whitelisthost');
if ( $white ) {
$self->log(LOGDEBUG, "skip: whitelist overrode blacklist: $white");
return 1;
};
my $remote_ip = shift || $self->qp->connection->remote_ip;
if ( $self->qp->connection->relay_client() ) {
$self->log(LOGWARN, "skip: don't blacklist relay/auth clients");
return 1;
};
return grep { s/\.?$/./;
$_ eq substr($remote_ip . '.', 0, length $_)
}
return
grep { s/\.?$/./; $_ eq substr($remote_ip . '.', 0, length $_) }
$self->qp->config('dnsbl_allow');
};
@ -306,6 +296,8 @@ sub process_sockets {
sub hook_rcpt {
my ($self, $transaction, $rcpt, %param) = @_;
return DECLINED if $self->is_immune();
# RBLSMTPD being non-empty means it contains the failure message to return
if (defined $ENV{'RBLSMTPD'} && $ENV{'RBLSMTPD'} ne '') {
my $result = $ENV{'RBLSMTPD'};
@ -346,6 +338,6 @@ sub get_reject_type {
return $self->{_args}{reject_type} eq 'temp' ? DENYSOFT
: $self->{_args}{reject_type} eq 'disconnect' ? DENY_DISCONNECT
: DENY;
: $default;
};

View File

@ -88,6 +88,8 @@ sub data_post_handler {
return DECLINED;
};
return DECLINED if $self->is_immune();
my $body = $self->assemble_body( $transaction );
my $message = load Mail::DomainKeys::Message(

View File

@ -17,7 +17,7 @@ has configurable timeout periods (black/grey/white) to control whether
connections are allowed, instead of using connection counts or rates.
Automatic whitelisting is enabled for relayclients, whitelisted hosts,
whitelisted senders, TLS connections, p0f matches, and geoip matches.
whitelisted senders, p0f matches, and geoip matches.
=head1 TRIPLETS
@ -169,7 +169,7 @@ use strict;
use warnings;
use Qpsmtpd::Constants;
my $VERSION = '0.10';
my $VERSION = '0.11';
BEGIN { @AnyDBM_File::ISA = qw(DB_File GDBM_File NDBM_File) }
use AnyDBM_File;
@ -268,6 +268,8 @@ sub greylist {
join(',',map { $_ . '=' . $config->{$_} } sort keys %$config));
return DECLINED if $self->is_immune();
return DECLINED if ! $self->is_p0f_match();
return DECLINED if $self->geoip_match();
my $db = $self->get_db_location();
my $lock = $self->get_db_lock( $db ) or return DECLINED;
@ -516,6 +518,8 @@ sub prune_db {
sub p0f_match {
my $self = shift;
return if ! $self->{_args}{p0f};
my $p0f = $self->connection->notes('p0f');
if ( !$p0f || !ref $p0f ) { # p0f fingerprint info not found
$self->LOGINFO(LOGERROR, "p0f info missing");
@ -559,6 +563,8 @@ sub p0f_match {
sub geoip_match {
my $self = shift;
return if ! $self->{_args}{geoip};
my $country = $self->connection->notes('geoip_country');
my $c_name = $self->connection->notes('geoip_country_name') || '';

View File

@ -25,6 +25,10 @@ to return in the SMTP conversation e.g.
=cut
use strict;
use warnings;
use Qpsmtpd::Constants;
sub register {
my ($self, $qp, $denial ) = @_;
@ -34,12 +38,25 @@ sub register {
else {
$self->{_rhsbl}->{DENY} = DENY;
}
}
sub hook_mail {
my ($self, $transaction, $sender, %param) = @_;
return DECLINED if $self->is_immune();
if ($sender->format eq '<>') {
$self->log(LOGINFO, 'skip, null sender');
return DECLINED;
};
my %rhsbl_zones = map { (split /\s+/, $_, 2)[0,1] } $self->qp->config('rhsbl_zones');
if ( ! %rhsbl_zones ) {
$self->log(LOGINFO, 'skip, no zones');
return DECLINED;
};
my $res = new Net::DNS::Resolver;
my $sel = IO::Select->new();
my %rhsbl_zones_map = ();
@ -48,9 +65,6 @@ sub hook_mail {
# here and pick up any results in the RCPT handler.
# MTAs gets confused when you reject mail during MAIL FROM:
my %rhsbl_zones = map { (split /\s+/, $_, 2)[0,1] } $self->qp->config('rhsbl_zones');
if ($sender->format ne '<>' and %rhsbl_zones) {
push(my @hosts, $sender->host);
#my $helo = $self->qp->connection->hello_host;
#push(@hosts, $helo) if $helo && $helo ne $sender->host;
@ -70,28 +84,29 @@ sub hook_mail {
%{$self->{_rhsbl_zones_map}} = %rhsbl_zones_map;
$transaction->notes('rhsbl_sockets', $sel);
} else {
$self->log(LOGDEBUG, 'no RHS checks necessary');
}
return DECLINED;
}
sub hook_rcpt {
my ($self, $transaction, $rcpt) = @_;
my $host = $transaction->sender->host;
my $hello = $self->qp->connection->hello_host;
my $result = $self->process_sockets;
if ($result && defined($self->{_rhsbl_zones_map}{$result})) {
my $result = $self->process_sockets or do {
$self->log(LOGINFO, "pass");
return DECLINED;
};
if ( defined($self->{_rhsbl_zones_map}{$result}) ) {
my $host = $transaction->sender->host;
if ($result =~ /^$host\./ ) {
return ($self->{_rhsbl}->{DENY}, "Mail from $host rejected because it " . $self->{_rhsbl_zones_map}{$result});
} else {
my $hello = $self->qp->connection->hello_host;
return ($self->{_rhsbl}->{DENY}, "Mail from HELO $hello rejected because it " . $self->{_rhsbl_zones_map}{$result});
}
}
return ($self->{_rhsbl}->{DENY}, $result) if $result;
return DECLINED;
return ($self->{_rhsbl}->{DENY}, $result);
}
sub process_sockets {

View File

@ -80,6 +80,8 @@ sub register {
sub hook_mail {
my ($self, $transaction, $sender, %param) = @_;
return (DECLINED) if $self->is_immune();
if ( ! $self->{_args}{reject} ) {
$self->log( LOGINFO, "skip: disabled in config" );
return (DECLINED);
@ -91,7 +93,7 @@ sub hook_mail {
return (DECLINED, "SPF - null sender");
};
if ( $self->is_relayclient() ) {
if ( $self->is_in_relayclients() ) {
return (DECLINED, "SPF - relaying permitted");
};
@ -189,16 +191,11 @@ sub hook_data_post {
return DECLINED;
}
sub is_relayclient {
sub is_in_relayclients {
my $self = shift;
# If we are receiving from a relay permitted host, then we are probably
# not the delivery system, and so we shouldn't check
if ( $self->qp->connection->relay_client() ) {
$self->log( LOGINFO, "skip: relaying permitted (relay_client)" );
return 1;
};
my $client_ip = $self->qp->connection->remote_ip;
my @relay_clients = $self->qp->config('relayclients');
my $more_relay_clients = $self->qp->config('morerelayclients', 'map');

View File

@ -163,15 +163,12 @@ sub register {
sub hook_data_post {
my ($self, $transaction) = @_;
return (DECLINED) if $self->is_immune();
if ( $transaction->data_size > 500_000 ) {
$self->log(LOGINFO, "skip: too large (".$transaction->data_size.")");
return (DECLINED);
};
if ( $self->{_args}{relayclient} && $self->{_args}{relayclient} eq 'skip'
&& $self->qp->connection->relay_client() ) {
$self->log(LOGINFO, "skip: relayclient" );
return (DECLINED);
};
my $SPAMD = $self->connect_to_spamd() or return (DECLINED);
my $username = $self->select_spamd_username( $transaction );

View File

@ -478,6 +478,8 @@ sub collect_results {
sub data_handler {
my ($self, $transaction) = @_;
return (DECLINED) if $self->is_immune();
my $queries = $self->lookup_start($transaction, sub {
my ($self, $name) = @_;
return $self->send_query($name);

View File

@ -8,36 +8,36 @@ use Qpsmtpd::Address;
sub register_tests {
my $self = shift;
$self->register_test("test_badmailfrom_is_immune", 5);
$self->register_test("test_badmailfrom_is_immune_sender", 5);
$self->register_test("test_badmailfrom_match", 7);
$self->register_test("test_badmailfrom_hook_mail", 4);
$self->register_test("test_badmailfrom_hook_rcpt", 2);
}
sub test_badmailfrom_is_immune {
sub test_badmailfrom_is_immune_sender {
my $self = shift;
my $transaction = $self->qp->transaction;
my $test_email = 'matt@test.com';
my $address = Qpsmtpd::Address->new( "<$test_email>" );
$transaction->sender($address);
ok( $self->is_immune( $transaction->sender, [] ), "is_immune, empty list");
ok( $self->is_immune_sender( $transaction->sender, [] ), "empty list");
$address = Qpsmtpd::Address->new( '<>' );
$transaction->sender($address);
ok( $self->is_immune( $transaction->sender, ['bad@example.com'] ), "is_immune, null sender");
ok( $self->is_immune_sender( $transaction->sender, ['bad@example.com'] ), "null sender");
$address = Qpsmtpd::Address->new( '<matt@>' );
$transaction->sender($address);
ok( $self->is_immune( $transaction->sender, ['bad@example.com'] ), "is_immune, missing host");
ok( $self->is_immune_sender( $transaction->sender, ['bad@example.com'] ), "missing host");
$address = Qpsmtpd::Address->new( '<@example.com>' );
$transaction->sender($address);
ok( $self->is_immune( $transaction->sender, ['bad@example.com'] ), "is_immune, missing user");
ok( $self->is_immune_sender( $transaction->sender, ['bad@example.com'] ), "missing user");
$address = Qpsmtpd::Address->new( '<matt@example.com>' );
$transaction->sender($address);
ok( ! $self->is_immune( $transaction->sender, ['bad@example.com'] ), "is_immune, false");
ok( ! $self->is_immune_sender( $transaction->sender, ['bad@example.com'] ), "false");
};
sub test_badmailfrom_hook_mail {

View File

@ -19,17 +19,16 @@ sub register_tests {
sub test_ip_whitelisted {
my $self = shift;
$self->qp->connection->remote_ip('10.1.1.1');
$self->qp->connection->remote_ip('192.168.99.5');
ok( $self->ip_whitelisted(), "+");
$self->qp->connection->relay_client(1);
ok( $self->ip_whitelisted('10.1.1.1'), "yes, +");
$self->qp->connection->remote_ip('192.168.99.6');
ok( ! $self->ip_whitelisted(), "-");
$self->qp->connection->relay_client(0);
ok( ! $self->ip_whitelisted('10.1.1.1'), "no, -");
$self->connection->notes('whitelisthost', 'hello honey!');
ok( $self->ip_whitelisted('10.1.1.1'), "yes, +");
$self->connection->notes('whitelisthost', undef);
$self->qp->connection->remote_ip('192.168.99.5');
$self->qp->connection->notes('whitelisthost', 'hello honey!');
ok( $self->ip_whitelisted(), "+");
$self->qp->connection->notes('whitelisthost', undef);
};
sub test_is_set_rblsmtpd {