#!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_load_exclude_files"); $self->register_test('test_hook_data'); $self->register_test('test_get_greylist_key'); $self->register_test('test_exclude'); $self->register_test("test_greylist_geoip"); $self->register_test("test_greylist_p0f_genre"); $self->register_test("test_greylist_p0f_distance"); $self->register_test("test_greylist_p0f_link"); $self->register_test("test_greylist_p0f_uptime"); $self->register_test('test_exclude_file_match'); } sub test_load_exclude_files { my ( $self ) = @_; delete $self->{$_} for qw( _exclude_ip _exclude_hostname exclude_re ); $self->load_exclude_files(); ok( $self->{_exclude_ip}{'194.7.234.142'}, 'Excluded IPs populated by load_exclude_files()' ); ok( $self->{_exclude_hostname}{'yahoo.com'}, 'Excluded hostnames populated by load_exclude_files()' ); ok( ( grep { $_ eq qr/^mta[12].siol.net$/ } @{ $self->{_exclude_re} || [] } ), 'Excluded REs populated by load_exlude_files()' ); } sub test_exclude_file_match { my ( $self ) = @_; my @test_data = ( { ip => 192.168.1.1, hostname => 'mta1234.siol.net', expected => 0, descr => 'miss', }, { ip => '194.7.234.142', hostname => 'mta1234.siol.net', expected => 1, descr => 'IP match', }, { ip => 192.168.1.1, hostname => 'postini.com', expected => 1, descr => 'Hostname match', }, { ip => 192.168.1.1, hostname => 'mta2.siol.net', expected => 1, descr => 'Regex match', }, ); for my $t ( @test_data ) { $self->connection->remote_ip( $t->{ip} ); $self->connection->remote_host( $t->{hostname} ); is( $self->exclude_file_match(), $t->{expected}, "exclude_file_match(): $t->{descr}" ); } } 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_get_greylist_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_greylist_key(); ok( ! $key, "db key empty: -"); $self->{_args}{remote_ip} = 1; $key = $self->get_greylist_key( $address, $address ); cmp_ok( $key, 'eq', '3232235777', "db key: $key"); $self->{_args}{sender} = 1; $key = $self->get_greylist_key( $address, $address ); cmp_ok( $key, 'eq', "3232235777:$test_email", "db key: $key"); $self->{_args}{recipient} = 1; $key = $self->get_greylist_key( $address, $address ); cmp_ok( $key, 'eq', "3232235777:$test_email:$test_email", "db key: $key"); } sub test_exclude { my ( $self ) = @_; $self->connection->relay_client(1); ok( $self->exclude(), "Relay client results in exclude() hit" ); $self->connection->relay_client(0); ok( ! $self->exclude(), "Non-relay client results in exclude() miss" ); my $old_p0f = $self->connection->notes('p0f'); $self->connection->notes('p0f'=> { genre => 'windows' } ); delete $self->{_args}{p0f}; ok( ! $self->exclude(), 'no p0f args = no exclusion' ); $self->{_args}{'p0f'} = 'genre,Lindows'; ok( $self->exclude(), 'p0f miss = exclusion' ); $self->{_args}{'p0f'} = 'genre,Windows'; ok( ! $self->exclude(), 'p0f hit = no exclusion' ); $self->connection->notes( p0f => $old_p0f ); } 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)"); ok( $self->exclude(), "match + ($cc) results in exclude() hit"); } foreach my $cc ( @invalid ) { $self->connection->notes('geoip_country', $cc ); ok( ! $self->geoip_match(), "bad - ($cc)"); ok( ! $self->exclude(), "miss - ($cc) results in exclude() miss"); } } 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'); ok( ! $self->exclude(), 'p0f link hit results in exclude() miss' ); $self->{_args}{'p0f'} = 'link,dsl'; $self->connection->notes('p0f'=> { link=>'Ethernet' } ); ok( ! $self->p0f_match(), 'p0f link miss'); ok( $self->exclude(), 'p0f link miss results in exclude() hit' ); } 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'); } sub _reset_transaction { my $self = shift; $self->qp->connection->relay_client(0); $self->qp->transaction->notes('whitelistsender',0); $self->connection->notes('whitelisthost',0); $self->qp->transaction->notes('tls_enabled',0); $self->{_args}{p0f} = undef; $self->{_args}{geoip} = undef; }