Merge pull request #187 from msimerson/fcrdns

fcrdns: add tests and improved localhost detection
This commit is contained in:
Jared Johnson 2015-01-04 01:34:20 -06:00
commit 07fad0ffd0
3 changed files with 79 additions and 19 deletions

View File

@ -8,7 +8,8 @@ Forward Confirmed RDNS - http://en.wikipedia.org/wiki/FCrDNS
Determine if the SMTP sender has matching forward and reverse DNS.
Sets the connection note fcrdns.
Adds the 'iprev' section to the Authentication-Results header when
there's sufficient DNS (at least rDNS) to be meaningful.
=head1 WHY IT WORKS
@ -141,22 +142,20 @@ sub register {
$self->{_args}{reject} = 0;
}
$self->register_hook('connect', 'connect_handler');
$self->register_hook('connect', 'fcrdns_tests');
}
sub connect_handler {
sub fcrdns_tests {
my ($self) = @_;
return DECLINED if $self->is_immune();
# run a couple cheap tests before the more expensive DNS tests
foreach my $test (qw/ is_valid_localhost is_not_fqdn /) {
# run cheap tests before the more expensive DNS tests
foreach my $test (
qw/ is_valid_localhost is_fqdn has_reverse_dns has_forward_dns / ) {
$self->$test() or return DECLINED;
}
$self->has_reverse_dns() or return DECLINED;
$self->has_forward_dns() or return DECLINED;
$self->log(LOGINFO, "pass");
return DECLINED;
}
@ -168,35 +167,35 @@ sub is_valid_localhost {
$self->adjust_karma(1);
$self->log(LOGDEBUG, "pass, is localhost");
return 1;
};
}
my $rh = $self->qp->connection->remote_host;
if ($rh && lc $self->qp->connection->remote_host eq 'localhost') {
$self->log(LOGDEBUG, "pass, remote_host is localhost");
return 1;
};
return 0 if ! $rh;
return 0 if lc $self->qp->connection->remote_host ne 'localhost';
$self->adjust_karma(-1);
$self->log(LOGINFO, "fail, not localhost");
return;
return 0;
}
sub is_not_fqdn {
sub is_fqdn {
my ($self) = @_;
my $host = $self->qp->connection->remote_host or return 1;
return 1 if $host eq 'Unknown'; # QP assigns this to a "no DNS result"
my $host = $self->qp->connection->remote_host or return 0;
return 0 if $host eq 'Unknown'; # QP assigns this to a "no DNS result"
# Since QP looked it up, perform some quick validation
if ($host !~ /\./) { # has no dots
$self->adjust_karma(-1);
$self->log(LOGINFO, "fail, not FQDN");
return;
return 0;
}
if ($host =~ /[^a-zA-Z0-9\-\.]/) {
$self->adjust_karma(-1);
$self->log(LOGINFO, "fail, invalid FQDN chars");
return;
return 0;
}
$self->log(LOGDEBUG, "pass, is FQDN");
return 1;
}

View File

@ -20,6 +20,7 @@ hosts_allow
ident/geoip
ident/p0f /tmp/.p0f_socket version 3
connection_time
fcrdns
# enable to accept MAIL FROM:/RCPT TO: addresses without surrounding <>
dont_require_anglebrackets

60
t/plugin_tests/fcrdns Normal file
View File

@ -0,0 +1,60 @@
#!perl -w
use strict;
#use POSIX qw(strftime);
#use Qpsmtpd::Address;
use Qpsmtpd::Constants;
my $test_email = 'matt@tnpi.net';
sub register_tests {
my $self = shift;
$self->register_test('_is_valid_localhost');
$self->register_test('_is_fqdn');
}
sub _is_valid_localhost {
my $self = shift;
my @passes = qw/ 127.0.0.1 127.1.1.1 127.255.255.255 /;
my @fails = qw/ 128.0.0.1 126.1.1.1 /;
foreach my $pass (@passes) {
$self->qp->connection->remote_ip($pass);
cmp_ok( $self->is_valid_localhost(), '==', 1, "$pass, true");
}
foreach my $fail (@fails) {
$self->qp->connection->remote_ip($fail);
cmp_ok( $self->is_valid_localhost(), '==', 0, "$fail, false");
}
$self->qp->connection->remote_host('localhost');
cmp_ok( $self->is_valid_localhost(), '==', 0, "localhost, non-loopback IP, false");
$self->qp->connection->remote_ip('127.0.0.1');
$self->qp->connection->remote_host('localhost');
cmp_ok( $self->is_valid_localhost(), '==', 1, "localhost, loop IP, true");
$self->qp->connection->remote_ip('::1');
$self->qp->connection->remote_host('localhost');
cmp_ok( $self->is_valid_localhost(), '==', 1, "localhost, IPv6 loop, true");
}
sub _is_fqdn {
my $self = shift;
my @passes = qw/ foo.com example.com /;
my @fails = qw/ com net edu boogers /;
foreach my $pass (@passes) {
$self->qp->connection->remote_host($pass);
cmp_ok( $self->is_fqdn(), '==', 1, "$pass, true");
}
foreach my $fail (@fails) {
$self->qp->connection->remote_host($fail);
cmp_ok( $self->is_fqdn(), '==', 0, "$fail, false");
}
}