diff --git a/INSTALL b/INSTALL index 86a8e5c..37d04f9 100644 --- a/INSTALL +++ b/INSTALL @@ -6,6 +6,7 @@ postfix-policyd-spf-perl: Perl 5.6 version + NetAddr-IP 4 Mail-SPF (not Mail-SPF-Query) Installing diff --git a/debian/control b/debian/control index f74c9a6..b04b78a 100644 --- a/debian/control +++ b/debian/control @@ -7,7 +7,7 @@ Standards-Version: 3.7.2 Package: postfix-policyd-spf-perl Architecture: all -Depends: libversion-perl, libmail-spf-perl, ${perl:Depends} +Depends: libversion-perl, libnetaddr-ip-perl (>= 4), libmail-spf-perl, ${perl:Depends} Recommends: postfix Description: pure-Perl Postfix policy daemon for RFC 4408 compliant SPF checking postfix-policyd-spf-perl is a Postfix SMTPd policy server for SPF checking. diff --git a/postfix-policyd-spf-perl b/postfix-policyd-spf-perl index 19277b2..9c6c92c 100755 --- a/postfix-policyd-spf-perl +++ b/postfix-policyd-spf-perl @@ -27,6 +27,7 @@ use strict; use IO::Handle; use Sys::Syslog qw(:DEFAULT setlogsock); +use NetAddr::IP; use Mail::SPF; # ---------------------------------------------------------- @@ -37,6 +38,10 @@ my $spf_server = Mail::SPF::Server->new(); # Leaving this to make it easier to add more handlers later: my @HANDLERS = ( + { + name => 'exempt_localhost', + code => \&exempt_localhost + }, { name => 'sender_policy_framework', code => \&sender_policy_framework @@ -58,6 +63,11 @@ my $syslog_facility = 'mail'; my $syslog_options = 'pid'; my $syslog_ident = 'postfix/policy-spf'; +use constant localhost_addresses => map( + NetAddr::IP->new($_), + qw( 127.0.0.0/8 ::ffff:127.0.0.0/104 ::1 ) +); # Does Postfix ever say "client_address=::ffff:"? + # ---------------------------------------------------------- # initialization # ---------------------------------------------------------- @@ -115,26 +125,21 @@ while () { my %responses; # Skip SPF check for local connections - if ($attr{client_address}=~ /^127\./) { - $action = "PREPEND X-SPF skipped - localhost is always allowed." - } - else { - foreach my $handler (@HANDLERS) { - my $handler_name = $handler->{name}; - my $handler_code = $handler->{code}; - - my $response = $handler_code->(attr => \%attr); - - if ($VERBOSE) { - syslog(debug => "handler %s: %s", $handler_name, $response); - } - - # Picks whatever response is not dunno - if ($response and $response !~ /^dunno/i) { - syslog(info => "handler %s: is decisive.", $handler_name); - $action = $response; - last; - } + foreach my $handler (@HANDLERS) { + my $handler_name = $handler->{name}; + my $handler_code = $handler->{code}; + + my $response = $handler_code->(attr => \%attr); + + if ($VERBOSE) { + syslog(debug => "handler %s: %s", $handler_name, $response); + } + + # Picks whatever response is not 'DUNNO' + if ($response and $response !~ /^DUNNO/i) { + syslog(info => "handler %s: is decisive.", $handler_name); + $action = $response; + last; } } @@ -145,8 +150,22 @@ while () { } # ---------------------------------------------------------- -# plugin: SPF +# handler: localhost exemption # ---------------------------------------------------------- + +sub exempt_localhost { + my %options = @_; + my $attr = $options{attr}; + my $client_address = NetAddr::IP->new($attr->{client_address}); + return 'PREPEND X-Comment SPF not applicable to localhost connection, skipped check' + if grep($_->contains($client_address), localhost_addresses); + return 'DUNNO'; +} + +# ---------------------------------------------------------- +# handler: SPF +# ---------------------------------------------------------- + sub sender_policy_framework { my %options = @_; my $attr = $options{attr}; @@ -169,7 +188,7 @@ sub sender_policy_framework { info => "%s:HELO check failed - Mail::SPF->new(%s, %s, %s) failed: %s", $attr->{queue_id}, $attr->{client_address}, $attr->{sender}, $attr->{helo_name}, $errmsg ); - return "DUNNO"; + return 'DUNNO'; } else { my $helo_result = $spf_server->process($helo_request); @@ -217,7 +236,7 @@ sub sender_policy_framework { info => "%s: Mail From (sender) check failed - Mail::SPF->new(%s, %s, %s) failed: %s", $attr->{queue_id}, $attr->{client_address}, $attr->{sender}, $attr->{helo_name}, $errmsg ); - return "DUNNO"; + return 'DUNNO'; } else { my $mfrom_result = $spf_server->process($mfrom_request);