diff --git a/plugins/dmarc b/plugins/dmarc index 60db367..6f41234 100644 --- a/plugins/dmarc +++ b/plugins/dmarc @@ -296,9 +296,16 @@ sub get_organizational_domain { # $self->log( LOGINFO, "i: $i, $tld" ); #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; + 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 @@ -327,7 +334,16 @@ sub exists_in_dns { # Since this search gets repeated for the Organizational Name, if it # fails for the O.N., there's no delegation from the TLD. 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') { $self->log(LOGDEBUG, "fail, non-existent domain: $domain"); return; @@ -337,14 +353,14 @@ sub exists_in_dns { }; my $matches = 0; for my $rr ($query->answer) { - next if $rr->type !~ /(?:NS|MX|A|AAAA)/; + next if $rr->type ne $type; $matches++; } if (0 == $matches) { - $self->log(LOGDEBUG, "fail, no records for $domain"); + $self->log(LOGDEBUG, "no $type records for $domain"); } return $matches; -} +}; sub fetch_dmarc_record { my ($self, $zone) = @_; diff --git a/plugins/sender_permitted_from b/plugins/sender_permitted_from index e9a1f9e..87d418d 100644 --- a/plugins/sender_permitted_from +++ b/plugins/sender_permitted_from @@ -96,28 +96,17 @@ sub mail_handler { 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 $helo = $self->qp->connection->hello_host; my $scope = $from ? 'mfrom' : 'helo'; my %req_params = ( versions => [1, 2], # optional scope => $scope, - ip_address => $client_ip, + ip_address => $self->qp->connection->remote_ip, ); if ($scope =~ /^mfrom|pra$/) { - $req_params{identity} = $from; + $req_params{identity} = $from; $req_params{helo_identity} = $helo if $helo; } elsif ($scope eq 'helo') { @@ -144,28 +133,24 @@ sub mail_handler { return (DECLINED, "SPF - no response"); } - if (!$reject) { - $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') { + if ($code eq 'pass') { $self->adjust_karma(1); $transaction->notes('spf_pass_host', lc $sender->host); $self->log(LOGINFO, "pass, $code: $why"); 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"); return (DENY, "SPF - $code: $why") if $reject >= 5; } @@ -196,33 +181,37 @@ sub handle_code_none { return (DENY, "SPF - none: $why"); } - $self->log(LOGINFO, "pass, none, $why"); + $self->log(LOGINFO, "skip, tolerated, none, $why"); return DECLINED; } sub handle_code_fail { my ($self, $reject, $why) = @_; + $self->adjust_karma(-1); + if ($reject >= 2) { $self->log(LOGINFO, "fail, $why"); return (DENY, "SPF - forgery: $why") if $reject >= 3; return (DENYSOFT, "SPF - fail: $why"); } - $self->log(LOGINFO, "pass, fail tolerated, $why"); + $self->log(LOGINFO, "fail, tolerated, $why"); return DECLINED; } sub handle_code_softfail { my ($self, $reject, $why) = @_; + $self->adjust_karma(-1); + if ($reject >= 3) { $self->log(LOGINFO, "fail, soft, $why"); return (DENY, "SPF - fail: $why") if $reject >= 4; return (DENYSOFT, "SPF - fail: $why") if $reject >= 3; } - $self->log(LOGINFO, "pass, softfail tolerated, $why"); + $self->log(LOGINFO, "fail, soft, tolerated, $why"); return DECLINED; }