@@ -62,8 +62,10 @@ $self->register_eval_rule ("check_for_spf_helo_fail"); $self->register_eval_rule ("check_for_spf_helo_softfail"); $self->register_eval_rule ("check_for_spf_whitelist_from"); $self->register_eval_rule ("check_for_def_spf_whitelist_from"); + $self->register_eval_rule ("check_for_spf_plus_all"); + $self->register_eval_rule ("check_for_spf_helo_plus_all"); $self->set_config($mailsaobject->{conf}); return $self; @@ -284,10 +286,22 @@ $self->_check_def_spf_whitelist($scanner) unless $scanner->{def_spf_whitelist_from_checked}; $scanner->{def_spf_whitelist_from}; } +sub check_for_spf_plus_all { + my ($self, $scanner) = @_; + $self->_check_spf ($scanner, 0, 1) unless $scanner->{spf_checked}; + $scanner->{spf_plus_all}; +} + +sub check_for_spf_helo_plus_all { + my ($self, $scanner) = @_; + $self->_check_spf ($scanner, 1, 1) unless $scanner->{spf_helo_checked}; + $scanner->{spf_helo_plus_all}; +} + sub _check_spf { - my ($self, $scanner, $ishelo) = @_; + my ($self, $scanner, $ishelo, $must_lookup) = @_; # we can re-use results from any *INTERNAL* Received-SPF header in the message... # we can't use results from trusted but external hosts since (i) spf checks are # supposed to be done "on the domain boundary", (ii) even if an external header @@ -298,8 +312,10 @@ # likely that the trusted+external host really should be defined as part of your # internal network if ($scanner->{conf}->{ignore_received_spf_header}) { dbg("spf: ignoring any Received-SPF headers from internal hosts, by admin setting"); + } elsif ($must_lookup) { + dbg("spf: must perform DNS lookup; existing spf headers will not contain the spf record."); } elsif ($scanner->{checked_for_received_spf_header}) { dbg("spf: already checked for Received-SPF headers, proceeding with DNS based checks"); } else { $scanner->{checked_for_received_spf_header} = 1; @@ -497,9 +513,9 @@ return; } - my ($result, $comment, $text, $err); + my ($result, $comment, $header_comment, $spf_record, $text, $err); # use Mail::SPF if it was available, otherwise use the legacy Mail::SPF::Query if ($self->{has_mail_spf}) { @@ -531,9 +547,10 @@ my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); $err = $timer->run_and_catch(sub { my $query = $self->{spf_server}->process($request); - + my $spf_record_object = $request->record; + $spf_record = $spf_record_object->text(); #to get the text $result = $query->code; $comment = $query->authority_explanation if $query->can("authority_explanation"); $text = $query->text; @@ -567,9 +584,9 @@ my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout }); $err = $timer->run_and_catch(sub { - ($result, $comment) = $query->result(); + ($result, $comment, $header_comment, $spf_record) = $query->result(); }); } # end of differences between Mail::SPF and Mail::SPF::Query @@ -585,14 +602,17 @@ $comment ||= ''; $comment =~ s/\s+/ /gs; # no newlines please $text ||= ''; $text =~ s/\s+/ /gs; # no newlines please + $spf_record ||= ''; + $spf_record =~ s/\s+/ /gs; # no newlines please if ($ishelo) { if ($result eq 'pass') { $scanner->{spf_helo_pass} = 1; } elsif ($result eq 'neutral') { $scanner->{spf_helo_neutral} = 1; } elsif ($result eq 'fail') { $scanner->{spf_helo_fail} = 1; } elsif ($result eq 'softfail') { $scanner->{spf_helo_softfail} = 1; } + if ($spf_record && ($spf_record =~ /\+all/)) { $scanner->{spf_helo_plus_all} = 1; } if ($result eq 'fail') { # RFC 4408 6.2 $scanner->{spf_helo_failure_comment} = "SPF failed: $comment"; } @@ -600,15 +620,15 @@ if ($result eq 'pass') { $scanner->{spf_pass} = 1; } elsif ($result eq 'neutral') { $scanner->{spf_neutral} = 1; } elsif ($result eq 'fail') { $scanner->{spf_fail} = 1; } elsif ($result eq 'softfail') { $scanner->{spf_softfail} = 1; } - + if ($spf_record && ($spf_record =~ /\+all/)) { $scanner->{spf_plus_all} = 1; } if ($result eq 'fail') { # RCF 4408 6.2 $scanner->{spf_failure_comment} = "SPF failed: $comment"; } } - dbg("spf: query for $scanner->{sender}/$ip/$helo: result: $result, comment: $comment, text: $text"); + dbg("spf: query for $scanner->{sender}/$ip/$helo: result: $result, comment: $comment, header comment: $header_comment, spf record: $spf_record, text: $text"); } sub _get_relay { my ($self, $scanner) = @_;