SPF: arrage flow so if a pass result is possible,

we will get it and set the note for DMARC plugin
This commit is contained in:
Matt Simerson 2013-04-24 03:09:02 -04:00
parent effb4e2269
commit c0210a7877
2 changed files with 43 additions and 38 deletions

View File

@ -296,9 +296,16 @@ sub get_organizational_domain {
# $self->log( LOGINFO, "i: $i, $tld" ); # $self->log( LOGINFO, "i: $i, $tld" );
#warn "i: $i - tld: $tld\n"; #warn "i: $i - tld: $tld\n";
if (grep /$tld/, $self->qp->config('public_suffix_list')) { if (grep /^$tld/, $self->qp->config('public_suffix_list')) {
$greatest = $i + 1; $greatest = $i + 1;
next;
} }
# check for wildcards (ex: *.uk should match co.uk)
$tld = join '.', '\*', reverse((@labels)[0 .. $i-1]);
if (grep /^$tld/, $self->qp->config('public_suffix_list')) {
$greatest = $i + 1;
};
} }
return $from_host if $greatest == scalar @labels; # same return $from_host if $greatest == scalar @labels; # same
@ -327,7 +334,16 @@ sub exists_in_dns {
# Since this search gets repeated for the Organizational Name, if it # Since this search gets repeated for the Organizational Name, if it
# fails for the O.N., there's no delegation from the TLD. # fails for the O.N., there's no delegation from the TLD.
my $res = $self->init_resolver(8); my $res = $self->init_resolver(8);
my $query = $res->query($domain, 'NS') or do { return 1 if $self->host_has_rr('NS', $res, $domain);
return 1 if $self->host_has_rr('MX', $res, $domain);
return 1 if $self->host_has_rr('A', $res, $domain);
return 1 if $self->host_has_rr('AAAA', $res, $domain);
}
sub host_has_rr {
my ($self, $type, $res, $domain) = @_;
my $query = $res->query($domain, $type) or do {
if ($res->errorstring eq 'NXDOMAIN') { if ($res->errorstring eq 'NXDOMAIN') {
$self->log(LOGDEBUG, "fail, non-existent domain: $domain"); $self->log(LOGDEBUG, "fail, non-existent domain: $domain");
return; return;
@ -337,14 +353,14 @@ sub exists_in_dns {
}; };
my $matches = 0; my $matches = 0;
for my $rr ($query->answer) { for my $rr ($query->answer) {
next if $rr->type !~ /(?:NS|MX|A|AAAA)/; next if $rr->type ne $type;
$matches++; $matches++;
} }
if (0 == $matches) { if (0 == $matches) {
$self->log(LOGDEBUG, "fail, no records for $domain"); $self->log(LOGDEBUG, "no $type records for $domain");
} }
return $matches; return $matches;
} };
sub fetch_dmarc_record { sub fetch_dmarc_record {
my ($self, $zone) = @_; my ($self, $zone) = @_;

View File

@ -96,28 +96,17 @@ sub mail_handler {
return (DECLINED, "SPF - null sender"); return (DECLINED, "SPF - null sender");
} }
if ($self->qp->connection->relay_client) {
$self->log(LOGINFO, "skip, relay_client");
return (DECLINED, "SPF - relaying permitted");
}
if (!$self->{_args}{reject}) {
$self->log(LOGINFO, "skip, reject disabled");
return (DECLINED);
}
my $client_ip = $self->qp->connection->remote_ip;
my $from = $sender->user . '@' . lc($sender->host); my $from = $sender->user . '@' . lc($sender->host);
my $helo = $self->qp->connection->hello_host; my $helo = $self->qp->connection->hello_host;
my $scope = $from ? 'mfrom' : 'helo'; my $scope = $from ? 'mfrom' : 'helo';
my %req_params = ( my %req_params = (
versions => [1, 2], # optional versions => [1, 2], # optional
scope => $scope, scope => $scope,
ip_address => $client_ip, ip_address => $self->qp->connection->remote_ip,
); );
if ($scope =~ /^mfrom|pra$/) { if ($scope =~ /^mfrom|pra$/) {
$req_params{identity} = $from; $req_params{identity} = $from;
$req_params{helo_identity} = $helo if $helo; $req_params{helo_identity} = $helo if $helo;
} }
elsif ($scope eq 'helo') { elsif ($scope eq 'helo') {
@ -144,28 +133,24 @@ sub mail_handler {
return (DECLINED, "SPF - no response"); return (DECLINED, "SPF - no response");
} }
if (!$reject) { if ($code eq 'pass') {
$self->log(LOGINFO, "fail, no reject policy ($code: $why)");
return (DECLINED, "SPF - $code: $why");
}
# SPF result codes: pass fail softfail neutral none error permerror temperror
return $self->handle_code_none($reject, $why) if $code eq 'none';
if ($code eq 'fail') {
$self->adjust_karma(-1);
return $self->handle_code_fail($reject, $why);
}
elsif ($code eq 'softfail') {
$self->adjust_karma(-1);
return $self->handle_code_softfail($reject, $why);
}
elsif ($code eq 'pass') {
$self->adjust_karma(1); $self->adjust_karma(1);
$transaction->notes('spf_pass_host', lc $sender->host); $transaction->notes('spf_pass_host', lc $sender->host);
$self->log(LOGINFO, "pass, $code: $why"); $self->log(LOGINFO, "pass, $code: $why");
return (DECLINED); return (DECLINED);
} }
elsif ($code eq 'neutral') {
if (!$reject) {
$self->log(LOGINFO, "skip, tolerated ($code: $why)");
return (DECLINED, "SPF - $code: $why");
}
# SPF result codes: pass fail softfail neutral none error permerror temperror
return $self->handle_code_none($reject, $why) if $code eq 'none';
return $self->handle_code_fail($reject, $why) if $code eq 'fail';
return $self->handle_code_softfail($reject, $why) if $code eq 'softfail';
if ($code eq 'neutral') {
$self->log(LOGINFO, "fail, $code, $why"); $self->log(LOGINFO, "fail, $code, $why");
return (DENY, "SPF - $code: $why") if $reject >= 5; return (DENY, "SPF - $code: $why") if $reject >= 5;
} }
@ -196,33 +181,37 @@ sub handle_code_none {
return (DENY, "SPF - none: $why"); return (DENY, "SPF - none: $why");
} }
$self->log(LOGINFO, "pass, none, $why"); $self->log(LOGINFO, "skip, tolerated, none, $why");
return DECLINED; return DECLINED;
} }
sub handle_code_fail { sub handle_code_fail {
my ($self, $reject, $why) = @_; my ($self, $reject, $why) = @_;
$self->adjust_karma(-1);
if ($reject >= 2) { if ($reject >= 2) {
$self->log(LOGINFO, "fail, $why"); $self->log(LOGINFO, "fail, $why");
return (DENY, "SPF - forgery: $why") if $reject >= 3; return (DENY, "SPF - forgery: $why") if $reject >= 3;
return (DENYSOFT, "SPF - fail: $why"); return (DENYSOFT, "SPF - fail: $why");
} }
$self->log(LOGINFO, "pass, fail tolerated, $why"); $self->log(LOGINFO, "fail, tolerated, $why");
return DECLINED; return DECLINED;
} }
sub handle_code_softfail { sub handle_code_softfail {
my ($self, $reject, $why) = @_; my ($self, $reject, $why) = @_;
$self->adjust_karma(-1);
if ($reject >= 3) { if ($reject >= 3) {
$self->log(LOGINFO, "fail, soft, $why"); $self->log(LOGINFO, "fail, soft, $why");
return (DENY, "SPF - fail: $why") if $reject >= 4; return (DENY, "SPF - fail: $why") if $reject >= 4;
return (DENYSOFT, "SPF - fail: $why") if $reject >= 3; return (DENYSOFT, "SPF - fail: $why") if $reject >= 3;
} }
$self->log(LOGINFO, "pass, softfail tolerated, $why"); $self->log(LOGINFO, "fail, soft, tolerated, $why");
return DECLINED; return DECLINED;
} }