updated plugins to use QP::Plugins::is_immune
This commit is contained in:
parent
3a016b1da8
commit
57a0e4ba7b
2
config.sample/dnsbl_allow
Normal file
2
config.sample/dnsbl_allow
Normal file
@ -0,0 +1,2 @@
|
||||
# test entry for dnsbl plugin
|
||||
192.168.99.5
|
@ -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 ) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,24 +197,13 @@ 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 $_)
|
||||
}
|
||||
$self->qp->config('dnsbl_allow');
|
||||
return
|
||||
grep { s/\.?$/./; $_ eq substr($remote_ip . '.', 0, length $_) }
|
||||
$self->qp->config('dnsbl_allow');
|
||||
};
|
||||
|
||||
sub process_sockets {
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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') || '';
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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');
|
||||
|
@ -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 );
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user