6b9881c32e
fixed the vestiges of old plugin name 'denysoft_greylisting' added ability to bypass greylisting based on geoip deprecated 'mode [denysoft | testonly | off] off wasn't useful testonly & denysoft replaced by reject [ 0 | 1 ] renamed DB from denysoft_greylist to greylist.dbm. Will use existing/legacy DB if present. added DB pruning feature. Automatically prune the DB when qpsmtpd registers the plugin. Perhaps this should be a config option to enable? added DB upgrade feature. Convert dotted quad IP addresses in DB to integers. Makes greylisting IPv6 compatible, since DB records are colon delimited. exempt TLS connections from greylisting. The vast majority (perhaps all) of the SMTP clients that request encryption to my server are legit. We could add a config option for this, but this plugin already has a multitude of config options. refactored much of the greylisting method into discreet subs added 30 tests added additional DEBUG level logging for p0f matches POD changes: replaced over, item N, back, with head2 (better formatted output) better describe the current behavior of the plugin (some past behaviors no longer exist) added TRIPLET section with example added loglevel section
182 lines
5.0 KiB
Perl
182 lines
5.0 KiB
Perl
#!perl -w
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Qpsmtpd::Address;
|
|
use Qpsmtpd::Constants;
|
|
|
|
my $test_email = 'user@example.com';
|
|
|
|
my @greydbs = qw( denysoft_greylist.dbm denysoft_greylist.dbm.lock );
|
|
foreach ( @greydbs ) {
|
|
unlink $_ if -f $_;
|
|
};
|
|
|
|
sub register_tests {
|
|
my $self = shift;
|
|
|
|
$self->register_test('test_hook_data', 4);
|
|
$self->register_test('test_is_immune', 6);
|
|
$self->register_test('test_get_db_key', 4);
|
|
$self->register_test('test_get_db_location', 1);
|
|
$self->register_test("test_greylist_geoip", 7);
|
|
$self->register_test("test_greylist_p0f_genre", 2);
|
|
$self->register_test("test_greylist_p0f_distance", 2);
|
|
$self->register_test("test_greylist_p0f_link", 2);
|
|
$self->register_test("test_greylist_p0f_uptime", 2);
|
|
}
|
|
|
|
sub test_hook_data {
|
|
my $self = shift;
|
|
my $transaction = $self->qp->transaction;
|
|
|
|
my ($code, $mess) = $self->hook_data( $transaction );
|
|
cmp_ok( $code, '==', DECLINED, "no note" );
|
|
|
|
$transaction->notes('greylist', 1);
|
|
|
|
($code, $mess) = $self->hook_data( $transaction );
|
|
cmp_ok( $code, '==', DECLINED, "no recipients");
|
|
|
|
my $address = Qpsmtpd::Address->new( "<$test_email>" );
|
|
$transaction->recipients( $address );
|
|
|
|
$transaction->notes('whitelistrcpt', 2);
|
|
($code, $mess) = $self->hook_data( $transaction );
|
|
cmp_ok( $code, '==', DENYSOFT, "missing recipients");
|
|
|
|
$transaction->notes('whitelistrcpt', 1);
|
|
($code, $mess) = $self->hook_data( $transaction );
|
|
cmp_ok( $code, '==', DECLINED, "missing recipients");
|
|
};
|
|
|
|
sub test_is_immune {
|
|
my $self = shift;
|
|
|
|
$self->qp->connection->relay_client(1);
|
|
ok( $self->is_immune(), 'relayclient');
|
|
$self->qp->connection->relay_client(0);
|
|
ok( ! $self->is_immune(), "nope -" );
|
|
|
|
foreach ( qw/ whitelisthost / ) {
|
|
$self->qp->connection->notes($_, 1);
|
|
ok( $self->is_immune(), $_);
|
|
$self->qp->connection->notes($_, undef);
|
|
};
|
|
|
|
foreach ( qw/ whitelistsender tls_enabled / ) {
|
|
$self->qp->transaction->notes($_, 1);
|
|
ok( $self->is_immune(), $_);
|
|
$self->qp->transaction->notes($_, undef);
|
|
};
|
|
|
|
ok( ! $self->is_immune(), "nope -" );
|
|
};
|
|
|
|
sub test_get_db_key {
|
|
my $self = shift;
|
|
|
|
$self->{_args}{sender} = 0;
|
|
$self->{_args}{recipient} = 0;
|
|
$self->{_args}{remote_ip} = 0;
|
|
|
|
my $test_ip = '192.168.1.1';
|
|
|
|
my $address = Qpsmtpd::Address->new( "<$test_email>" );
|
|
$self->qp->transaction->sender( $address );
|
|
$self->qp->transaction->add_recipient( $address );
|
|
$self->qp->connection->remote_ip($test_ip);
|
|
|
|
my $key = $self->get_db_key();
|
|
ok( ! $key, "db key empty: -");
|
|
|
|
$self->{_args}{remote_ip} = 1;
|
|
$key = $self->get_db_key( $address, $address );
|
|
cmp_ok( $key, 'eq', '3232235777', "db key: $key");
|
|
|
|
$self->{_args}{sender} = 1;
|
|
$key = $self->get_db_key( $address, $address );
|
|
cmp_ok( $key, 'eq', "3232235777:$test_email", "db key: $key");
|
|
|
|
$self->{_args}{recipient} = 1;
|
|
$key = $self->get_db_key( $address, $address );
|
|
cmp_ok( $key, 'eq', "3232235777:$test_email:$test_email", "db key: $key");
|
|
};
|
|
|
|
sub test_get_db_location {
|
|
my $self = shift;
|
|
|
|
my $db = $self->get_db_location();
|
|
ok( $db, "db location: $db");
|
|
};
|
|
|
|
sub test_greylist_geoip {
|
|
my $self = shift;
|
|
|
|
$self->{_args}{'geoip'} = 'US,UK,HU';
|
|
|
|
my @valid = qw/ US us UK hu /;
|
|
my @invalid = qw/ PK RU ru /;
|
|
|
|
foreach my $cc ( @valid ) {
|
|
$self->connection->notes('geoip_country', $cc );
|
|
ok( $self->geoip_match(), "match + ($cc)");
|
|
};
|
|
|
|
foreach my $cc ( @invalid ) {
|
|
$self->connection->notes('geoip_country', $cc );
|
|
ok( ! $self->geoip_match(), "bad - ($cc)");
|
|
};
|
|
};
|
|
|
|
sub test_greylist_p0f_genre {
|
|
my $self = shift;
|
|
|
|
$self->{_args}{'p0f'} = 'genre,Linux';
|
|
$self->connection->notes('p0f'=> { genre => 'windows', link => 'dsl' } );
|
|
ok( ! $self->p0f_match(), 'p0f genre miss');
|
|
|
|
$self->{_args}{'p0f'} = 'genre,Windows';
|
|
$self->connection->notes('p0f'=> { genre => 'windows', link => 'dsl' } );
|
|
ok( $self->p0f_match(), 'p0f genre hit');
|
|
}
|
|
|
|
sub test_greylist_p0f_distance {
|
|
my $self = shift;
|
|
|
|
$self->{_args}{'p0f'} = 'distance,8';
|
|
$self->connection->notes('p0f'=> { distance=>9 } );
|
|
ok( $self->p0f_match(), 'p0f distance hit');
|
|
|
|
$self->{_args}{'p0f'} = 'distance,8';
|
|
$self->connection->notes('p0f'=> { distance=>7 } );
|
|
ok( ! $self->p0f_match(), 'p0f distance miss');
|
|
}
|
|
|
|
sub test_greylist_p0f_link {
|
|
my $self = shift;
|
|
|
|
$self->{_args}{'p0f'} = 'link,dsl';
|
|
$self->connection->notes('p0f'=> { link=>'DSL' } );
|
|
ok( $self->p0f_match(), 'p0f link hit');
|
|
|
|
$self->{_args}{'p0f'} = 'link,dsl';
|
|
$self->connection->notes('p0f'=> { link=>'Ethernet' } );
|
|
ok( ! $self->p0f_match(), 'p0f link miss');
|
|
}
|
|
|
|
sub test_greylist_p0f_uptime {
|
|
my $self = shift;
|
|
|
|
$self->{_args}{'p0f'} = 'uptime,100';
|
|
$self->connection->notes('p0f'=> { uptime=> 99 } );
|
|
ok( $self->p0f_match(), 'p0f uptime hit');
|
|
|
|
$self->{_args}{'p0f'} = 'uptime,100';
|
|
$self->connection->notes('p0f'=> { uptime=>500 } );
|
|
ok( ! $self->p0f_match(), 'p0f uptime miss');
|
|
}
|
|
|
|
|