Mailing List Archive

svn commit: rev 36272 - in spamassassin/trunk: lib/Mail/SpamAssassin rules
Author: quinlan
Date: Wed Aug 11 22:45:22 2004
New Revision: 36272

Modified:
spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Dns.pm
spamassassin/trunk/lib/Mail/SpamAssassin/EvalTests.pm
spamassassin/trunk/rules/20_dnsbl_tests.cf
spamassassin/trunk/rules/20_head_tests.cf
spamassassin/trunk/rules/50_scores.cf
Log:
bug 3494: rewrite NO_DNS_FOR_FROM to use DNS-in-background code


Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm Wed Aug 11 22:45:22 2004
@@ -1278,9 +1278,9 @@

=item rbl_timeout n (default: 15)

-All RBL queries are made at the beginning of a check and we try to read the
+All DNS queries are made at the beginning of a check and we try to read the
results at the end. This value specifies the maximum period of time to wait
-for an RBL query. If most of the RBL queries have succeeded for a particular
+for an DNS query. If most of the DNS queries have succeeded for a particular
message, then SpamAssassin will not wait for the full period to avoid wasting
time on unresponsive server(s). For the default 15 second timeout, here is a
chart of queries remaining versus the effective timeout in seconds:
@@ -1304,31 +1304,6 @@
type => $CONF_TYPE_NUMERIC
});

-=item check_mx_attempts n (default: 2)
-
-By default, SpamAssassin checks the From: address for a valid MX this many
-times, waiting 5 seconds each time.
-
-=cut
-
- push (@cmds, {
- setting => 'check_mx_attempts',
- default => 2,
- type => $CONF_TYPE_NUMERIC
- });
-
-=item check_mx_delay n (default: 5)
-
-How many seconds to wait before retrying an MX check.
-
-=cut
-
- push (@cmds, {
- setting => 'check_mx_delay',
- default => 5,
- type => $CONF_TYPE_NUMERIC
- });
-
=item dns_available { yes | test[: name1 name2...] | no } (default: test)

By default, SpamAssassin will query some default hosts on the internet to
@@ -2197,7 +2172,7 @@
if ($value =~ /^(\S+)\s+(?:rbl)?eval:(.*)$/) {
my ($name, $fn) = ($1, $2);

- if ($fn =~ /^check_rbl/) {
+ if ($fn =~ /^check_(?:rbl|dns)/) {
$self->{parser}->add_test ($name, $fn, $TYPE_RBL_EVALS);
}
else {
@@ -2410,7 +2385,7 @@

=item priority SYMBOLIC_TEST_NAME n

-Assign a specific priority to a test. All tests, except for RBL and Meta
+Assign a specific priority to a test. All tests, except for DNS and Meta
tests, are run in priority order. The default test priority is 0 (zero).

=cut

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Dns.pm
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Dns.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Dns.pm Wed Aug 11 22:45:22 2004
@@ -131,6 +131,19 @@
$self->{dnspost}->{$set}->{$subtest} = $rule;
}

+sub do_dns_lookup {
+ my ($self, $rule, $type, $host) = @_;
+
+ # only make a specific query once
+ if (!defined $self->{dnspending}->{$type}->{$host}->[BGSOCK]) {
+ dbg("dns: launching DNS $type query for $host in background", "rbl", -1);
+ $self->{rbl_launch} = time;
+ $self->{dnspending}->{$type}->{$host}->[BGSOCK] =
+ $self->{res}->bgsend($host, $type);
+ }
+ push @{$self->{dnspending}->{$type}->{$host}->[RULES]}, $rule;
+}
+
###########################################################################

sub dnsbl_hit {
@@ -176,6 +189,19 @@
return if !defined $packet;

my $question = ($packet->question)[0];
+
+ # NO_DNS_FOR_FROM
+ if ($self->{sender_host} &&
+ $question->qname eq $self->{sender_host} &&
+ $question->qtype =~ /^(?:A|MX)$/ &&
+ $packet->header->rcode =~ /^(?:NXDOMAIN|SERVFAIL)$/ &&
+ ++$self->{sender_host_fail} == 2)
+ {
+ for my $rule (@{$query->[RULES]}) {
+ $self->got_hit($rule, "DNS: ");
+ }
+ }
+ # DNSBL tests are here
foreach my $answer ($packet->answer) {
# track all responses
$self->dnsbl_uri($question, $answer);
@@ -257,6 +283,7 @@

my $timeout = $self->{conf}->{rbl_timeout} + $self->{rbl_launch};
my @waiting = (values %{ $self->{dnspending}->{A} },
+ values %{ $self->{dnspending}->{MX} },
values %{ $self->{dnspending}->{TXT} });
my @left;
my $total;
@@ -290,9 +317,15 @@
dbg("RBL: success for " . ($total - @left) . " of $total queries", "rbl", 0);
# timeouts
for my $query (@left) {
- my $sets = join(",", @{$query->[SETS]});
+ my $string = '';
+ if (defined @{$query->[SETS]}) {
+ $string = join(",", grep defined, @{$query->[SETS]});
+ }
+ elsif (defined @{$query->[RULES]}) {
+ $string = join(",", grep defined, @{$query->[RULES]});
+ }
my $delay = time - $self->{rbl_launch};
- dbg("RBL: timeout for $sets after $delay seconds", "rbl", 0);
+ dbg("DNS: timeout for $string after $delay seconds", "rbl", 0);
undef $query->[BGSOCK];
}
# register hits

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/EvalTests.pm
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/EvalTests.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/EvalTests.pm Wed Aug 11 22:45:22 2004
@@ -76,64 +76,6 @@
# HEAD TESTS:
###########################################################################

-sub check_for_from_dns {
- my ($self) = @_;
-
- if (!defined ($self->{checked_for_from_dns})) {
- $self->{checked_for_from_dns} = $self->_check_for_from_dns();
- }
-
- return $self->{checked_for_from_dns};
-}
-
-sub _check_for_from_dns {
- my ($self) = @_;
-
- my $from;
- foreach $from ($self->get('Reply-To:addr'), $self->get('From:addr')) {
- next unless defined $from;
-
- # bug 3366
- $from =~ tr/././s;
-
- if ($from =~ /\@(\S+\.\S+)/) {
- $from = $1;
- last;
- }
- undef $from;
- }
- return 0 unless (defined $from);
- $from = $1;
-
- # First check that DNS is available, if not do not perform this check
- return 0 unless $self->is_dns_available();
- $self->load_resolver();
-
- if ($from eq 'compiling.spamassassin.taint.org') {
- # only used when compiling
- return 0;
- }
-
- if ($self->{conf}->{check_mx_attempts} < 1) {
- return 0;
- }
-
- # Try check_mx_attempts times to protect against temporary outages.
- # sleep between checks to give the DNS a chance to recover.
- for my $i (1 .. $self->{conf}->{check_mx_attempts}) {
- return 0 if ($self->lookup_mx_exists ($from));
- return 0 if ($self->lookup_a ($from));
- if ($i < $self->{conf}->{check_mx_attempts}) {
- sleep $self->{conf}->{check_mx_delay};
- }
- }
-
- $self->set_server_failed_to_respond_for_domain($from);
- return 1;
-}
-
-###########################################################################
-
# From and To have same address, but are not exactly the same and
# neither contains intermediate spaces.
sub check_for_from_to_same {
@@ -1467,6 +1409,50 @@
$self->load_resolver();
for my $host (keys %hosts) {
$self->do_rbl_lookup($rule, $set, 'A', $rbl_server, "$host.$rbl_server");
+ }
+}
+
+sub check_dns_sender {
+ my ($self, $rule) = @_;
+
+ my $host;
+ for my $from ($self->get('EnvelopeFrom:addr')) {
+ next unless defined $from;
+
+ $from =~ tr/././s; # bug 3366
+ if ($from =~ /\@(\S+\.\S+)/) {
+ $host = lc($1);
+ last;
+ }
+ }
+ return 0 unless defined $host;
+
+ # First check that DNS is available, if not do not perform this check
+ # TODO: need a way to skip DNS checks as a whole in configuration
+ return 0 unless $self->is_dns_available();
+ $self->load_resolver();
+
+ if ($host eq 'compiling.spamassassin.taint.org') {
+ # only used when compiling
+ return 0;
+ }
+
+ dbg ("checking A and MX for host $host", "rbl", -1);
+
+ $self->do_dns_lookup($rule, 'A', $host);
+ $self->do_dns_lookup($rule, 'MX', $host);
+
+ # cache name of host for later checking
+ $self->{sender_host} = $host;
+
+ return 0;
+}
+
+# interface called by SPF plugin
+sub check_for_from_dns {
+ my ($self) = @_;
+ if (defined $self->{sender_host_fail}) {
+ return ($self->{sender_host_fail} == 2); # both MX and A need to fail
}
}


Modified: spamassassin/trunk/rules/20_dnsbl_tests.cf
==============================================================================
--- spamassassin/trunk/rules/20_dnsbl_tests.cf (original)
+++ spamassassin/trunk/rules/20_dnsbl_tests.cf Wed Aug 11 22:45:22 2004
@@ -268,3 +268,10 @@
#header RCVD_IN_MAPS_OPS eval:check_rbl_sub('rblplus', '8')
#describe RCVD_IN_MAPS_OPS Relay in OPS, http://www.mail-abuse.org/ops/
#tflags RCVD_IN_MAPS_OPS net
+
+# ---------------------------------------------------------------------------
+# Other DNS tests
+
+header NO_DNS_FOR_FROM eval:check_dns_sender()
+describe NO_DNS_FOR_FROM Envelope sender has no MX or A DNS records
+tflags NO_DNS_FOR_FROM net

Modified: spamassassin/trunk/rules/20_head_tests.cf
==============================================================================
--- spamassassin/trunk/rules/20_head_tests.cf (original)
+++ spamassassin/trunk/rules/20_head_tests.cf Wed Aug 11 22:45:22 2004
@@ -287,10 +287,6 @@
header FRIEND_PUBLIC ALL =~ /^(?:to|cc|from):.*friend\@public\.com/im
describe FRIEND_PUBLIC sent from or to friend@public.com

-header NO_DNS_FOR_FROM eval:check_for_from_dns()
-describe NO_DNS_FOR_FROM Domain in From header has no MX or A DNS records
-tflags NO_DNS_FOR_FROM net
-
header FROM_AND_TO_SAME eval:check_for_from_to_same()
describe FROM_AND_TO_SAME From and To are the same, but not exactly


Modified: spamassassin/trunk/rules/50_scores.cf
==============================================================================
--- spamassassin/trunk/rules/50_scores.cf (original)
+++ spamassassin/trunk/rules/50_scores.cf Wed Aug 11 22:45:22 2004
@@ -555,7 +555,7 @@
score NO_COST 0.078 0.002 0.335 0.000
score NO_CREDIT_CHECK 0 0.000 1.990 0.037 # n=0
score NO_DISAPPOINTMENT 0 1.498 1.609 0.410 # n=0
-score NO_DNS_FOR_FROM 0 # n=0 n=1 n=2 n=3
+score NO_DNS_FOR_FROM 0 1.1 0 1.6
score NO_EXPERIENCE 0 # n=0 n=1
score NO_FEE 0 # n=0 n=1
score NO_FORMS 1.622 0.973 0.912 0.011