Trunk changed for mail:SPF. 1.08.1/debian tags updated for Ubuntu lessons learned.
This commit is contained in:
parent
e81f28bf98
commit
1d57e605d3
9 changed files with 204 additions and 102 deletions
|
|
@ -2,24 +2,40 @@
|
|||
|
||||
# postfix-policyd-spf-perl
|
||||
# http://www.openspf.org/Software
|
||||
# version 1.08.1
|
||||
# version 1.99
|
||||
# $Id$
|
||||
#(C) 2007 Scott Kitterman <scott@kitterman.com>
|
||||
#(C) 2003-2004 Meng Weng Wong <mengwong@pobox.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
use version; our $VERSION = qv('1.08.1');
|
||||
use version; our $VERSION = qv('1.99');
|
||||
|
||||
use strict;
|
||||
|
||||
use Fcntl;
|
||||
use Sys::Syslog qw(:DEFAULT setlogsock);
|
||||
use Mail::SPF::Query;
|
||||
use Mail::SPF;
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# configuration
|
||||
# ----------------------------------------------------------
|
||||
|
||||
my $spf_server = Mail::SPF::Server->new();
|
||||
my @HANDLERS;
|
||||
push @HANDLERS, "testing";
|
||||
push @HANDLERS, "sender_permitted_from";
|
||||
push @HANDLERS, "sender_policy_framework";
|
||||
#Leaving this to make it easier to add others later.
|
||||
|
||||
my $VERBOSE = 0;
|
||||
|
||||
|
|
@ -88,14 +104,17 @@ while (<STDIN>) {
|
|||
foreach my $handler (@HANDLERS) {
|
||||
no strict 'refs';
|
||||
my $response = $handler->(attr=>\%attr);
|
||||
syslog(debug => "handler %s: %s", $handler, $response);
|
||||
if ($VERBOSE) {
|
||||
syslog(debug => "handler %s: %s", $handler, $response);
|
||||
}
|
||||
#Picks whatever response is not dunno
|
||||
if ($response and $response !~ /^dunno/i) {
|
||||
syslog(info => "handler %s: %s is decisive.", $handler, $response);
|
||||
syslog(info => "handler %s: is decisive.", $handler);
|
||||
$action = $response; last;
|
||||
}
|
||||
}
|
||||
|
||||
syslog(info => "decided action=%s", $action);
|
||||
syslog(info => "Policy action=%s", $action);
|
||||
|
||||
print STDOUT "action=$action\n\n";
|
||||
%attr = ();
|
||||
|
|
@ -104,65 +123,71 @@ while (<STDIN>) {
|
|||
# ----------------------------------------------------------
|
||||
# plugin: SPF
|
||||
# ----------------------------------------------------------
|
||||
sub sender_permitted_from {
|
||||
sub sender_policy_framework {
|
||||
local %_ = @_;
|
||||
my %attr = %{ $_{attr} };
|
||||
|
||||
my $query = eval {
|
||||
Mail::SPF::Query->new(
|
||||
ip => $attr{client_address},
|
||||
sender => $attr{sender},
|
||||
helo => $attr{helo_name}
|
||||
)
|
||||
|
||||
#Always do HELO check first. If no HELO policy it's only one lookup.
|
||||
#Avoids the need to do any Mail From processing for null sender.
|
||||
my $helo_request = eval {
|
||||
Mail::SPF::Request->new(
|
||||
scope => 'helo', # 'mfrom' or 'helo', 'pra'
|
||||
identity => $attr{helo_name},
|
||||
ip_address => $attr{client_address},
|
||||
helo_identity # optional,
|
||||
=> $attr{helo_name}
|
||||
);
|
||||
};
|
||||
my $helo_result = $spf_server->process($helo_request);
|
||||
|
||||
my $helo_result_code = $helo_result->code; # 'pass', 'fail', etc.
|
||||
my $helo_local_exp = $helo_result->local_explanation;
|
||||
my $helo_authority_exp = $helo_result->authority_explanation
|
||||
if $helo_result->is_code('fail');
|
||||
my $helo_spf_header = $helo_result->received_spf_header;
|
||||
|
||||
syslog(
|
||||
info => "%s: SPF %s: HELO/EHLO: %s, IP Address: %s, Recipient: %s",
|
||||
$attr{queue_id}, $helo_result, $attr{helo_name}, $attr{client_address}, $attr{recipient}
|
||||
);
|
||||
|
||||
# Reject on HELO fail. Defer on HELO temperror if message would otherwis
|
||||
# be accepted. Use the HELO result and return for null sender.
|
||||
if ($helo_result_code eq "fail") { return "REJECT $helo_authority_exp"; }
|
||||
elsif ($helo_result_code eq "temperror") { return "DEFER_IF_PERMIT SPF-Result=$helo_local_exp"; }
|
||||
elsif ($attr{sender} eq '') { return "PREPEND $helo_spf_header"; }
|
||||
|
||||
#Do mail from is HELO doesn't give a definitive result.
|
||||
my $mfrom_request = eval {
|
||||
Mail::SPF::Request->new(
|
||||
scope => 'mfrom', # 'mfrom' or 'helo', 'pra'
|
||||
identity => $attr{sender},
|
||||
ip_address => $attr{client_address},
|
||||
helo_identity # optional,
|
||||
=> $attr{helo_name} # for %{h} macro expansion
|
||||
);
|
||||
};
|
||||
my $mfrom_result = $spf_server->process($mfrom_request);
|
||||
|
||||
my $mfrom_result_code = $mfrom_result->code; # 'pass', 'fail', etc.
|
||||
my $mfrom_local_exp = $mfrom_result->local_explanation;
|
||||
my $mfrom_authority_exp = $mfrom_result->authority_explanation
|
||||
if $mfrom_result->is_code('fail');
|
||||
my $mfrom_spf_header = $mfrom_result->received_spf_header;
|
||||
if ($@) {
|
||||
syslog(
|
||||
info => "%s: Mail::SPF::Query->new(%s, %s, %s) failed: %s",
|
||||
info => "%s: Mail::SPF->new(%s, %s, %s) failed: %s",
|
||||
$attr{queue_id}, $attr{client_address}, $attr{sender}, $attr{helo_name}, $@
|
||||
);
|
||||
return "DUNNO";
|
||||
}
|
||||
my ($result, $smtp_comment, $header_comment) = $query->result();
|
||||
|
||||
syslog(
|
||||
info => "%s: SPF %s: smtp_comment=%s, header_comment=%s",
|
||||
$attr{queue_id}, $result, $smtp_comment, $header_comment
|
||||
info => "%s: SPF %s: Envelope-from: %s, IP Address: %s, Recipient: %s",
|
||||
$attr{queue_id}, $mfrom_result, $attr{sender}, $attr{client_address}, $attr{recipient}
|
||||
);
|
||||
|
||||
if ($result eq "fail") { return "REJECT $smtp_comment"; }
|
||||
elsif ($result eq "error") { return "DEFER_IF_PERMIT $smtp_comment"; }
|
||||
else { return "PREPEND Received-SPF: $result ($header_comment)"; }
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# plugin: testing
|
||||
# ----------------------------------------------------------
|
||||
sub testing {
|
||||
local %_ = @_;
|
||||
my %attr = %{ $_{attr} };
|
||||
|
||||
if (
|
||||
lc(address_stripped($attr{sender})) eq lc(address_stripped($attr{recipient})) and
|
||||
$attr{recipient} =~ /policyblock/
|
||||
) {
|
||||
|
||||
syslog(info => "%s: testing: will block as requested", $attr{queue_id});
|
||||
return "REJECT smtpd-policy blocking $attr{recipient}";
|
||||
}
|
||||
else {
|
||||
syslog(
|
||||
info => "%s: testing: stripped sender=%s, stripped rcpt=%s",
|
||||
$attr{queue_id},
|
||||
address_stripped($attr{sender}),
|
||||
address_stripped($attr{recipient}),
|
||||
);
|
||||
}
|
||||
return "DUNNO";
|
||||
}
|
||||
|
||||
# my $foo = address_stripped('foo+bar@baz.com'); # returns 'foo@baz.com'
|
||||
sub address_stripped {
|
||||
my $string = shift;
|
||||
$string =~ s/[+-].*\@/\@/;
|
||||
return $string;
|
||||
#Same approach as HELO....
|
||||
if ($mfrom_result_code eq "fail") { return "REJECT $mfrom_authority_exp"; }
|
||||
elsif ($mfrom_result_code eq "mfrom_temperror") { return "DEFER_IF_PERMIT SPF-Result=$mfrom_local_exp"; }
|
||||
else { return "PREPEND $mfrom_spf_header"; }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue