Index: MANIFEST =================================================================== --- MANIFEST (revision 918482) +++ MANIFEST (working copy) @@ -530,3 +530,8 @@ t/whitelist_to.t t/zz_cleanup.t t/spamc_bug6176.t +t/data/spam/dnsbl_domsonly.eml +t/uribl_domains_only.t +t/data/spam/dnsbl_ipsonly.eml +t/uribl_all_types.t +t/uribl_ips_only.t Index: lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm =================================================================== --- lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm (revision 918482) +++ lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm (working copy) @@ -187,6 +187,16 @@ Note that, as with C, you must also define a body-eval rule calling C to use this. +=item tflags NAME_OF_RULE ips_only + +Only URIs containing IP addresses as the "host" component will be matched +against the named "urirhsbl"/"urirhssub" rule. + +=item tflags NAME_OF_RULE domains_only + +Only URIs containing a non-IP-address "host" component will be matched against +the named "urirhsbl"/"urirhssub" rule. + =back =head1 ADMINISTRATOR SETTINGS @@ -273,6 +283,8 @@ # only hit DNSBLs for active rules (defined and score != 0) $scanner->{'uridnsbl_active_rules_rhsbl'} = { }; + $scanner->{'uridnsbl_active_rules_rhsbl_ipsonly'} = { }; + $scanner->{'uridnsbl_active_rules_rhsbl_domsonly'} = { }; $scanner->{'uridnsbl_active_rules_nsrhsbl'} = { }; $scanner->{'uridnsbl_active_rules_fullnsrhsbl'} = { }; $scanner->{'uridnsbl_active_rules_revipbl'} = { }; @@ -281,7 +293,13 @@ next unless ($scanner->{conf}->is_rule_active('body_evals',$rulename)); my $rulecf = $scanner->{conf}->{uridnsbls}->{$rulename}; - if ($rulecf->{is_rhsbl}) { + my $tflags = $scanner->{conf}->{tflags}->{$rulename}; + + if ($rulecf->{is_rhsbl} && $tflags =~ /\b ips_only \b/x) { + $scanner->{uridnsbl_active_rules_rhsbl_ipsonly}->{$rulename} = 1; + } elsif ($rulecf->{is_rhsbl} && $tflags =~ /\b domains_only \b/x) { + $scanner->{uridnsbl_active_rules_rhsbl_domsonly}->{$rulename} = 1; + } elsif ($rulecf->{is_rhsbl}) { $scanner->{uridnsbl_active_rules_rhsbl}->{$rulename} = 1; } elsif ($rulecf->{is_fullnsrhsbl}) { $scanner->{uridnsbl_active_rules_fullnsrhsbl}->{$rulename} = 1; @@ -370,7 +388,6 @@ } else { # trim down to a limited number - pick randomly - my $i; while (@domains && keys %domlist < $umd) { my $r = int rand (scalar @domains); $domlist{splice (@domains, $r, 1)} = 1; @@ -644,7 +661,10 @@ my $obj = { dom => $dom }; - my $single_dnsbl = 0; + my $tflags = $scanner->{conf}->{tflags}; + my $cf = $scanner->{uridnsbl_active_rules_revipbl}; + + my ($is_ip, $single_dnsbl); if ($dom =~ /^\d+\.\d+\.\d+\.\d+$/) { my $IPV4_ADDRESS = IPV4_ADDRESS; my $IP_PRIVATE = IP_PRIVATE; @@ -655,6 +675,7 @@ if ($dom =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) { $dom = "$4.$3.$2.$1"; $single_dnsbl = 1; + $is_ip = 1; } } } @@ -663,13 +684,24 @@ } my $rhsblrules = $scanner->{uridnsbl_active_rules_rhsbl}; + my $rhsbliprules = $scanner->{uridnsbl_active_rules_rhsbl_ipsonly}; + my $rhsbldomrules = $scanner->{uridnsbl_active_rules_rhsbl_domsonly}; my $nsrhsblrules = $scanner->{uridnsbl_active_rules_nsrhsbl}; my $fullnsrhsblrules = $scanner->{uridnsbl_active_rules_fullnsrhsbl}; my $reviprules = $scanner->{uridnsbl_active_rules_revipbl}; if ($single_dnsbl) { - # look up the domain in the RHSBL subset - foreach my $rulename (keys %{$rhsblrules}) { + # look up the domain in the basic RHSBL subset + my @rhsbldoms = keys %{$rhsblrules}; + + # and add the "domains_only" and "ips_only" subsets as appropriate + if ($is_ip) { + push @rhsbldoms, keys %{$rhsbliprules}; + } else { + push @rhsbldoms, keys %{$rhsbldomrules}; + } + + foreach my $rulename (@rhsbldoms) { my $rulecf = $scanner->{conf}->{uridnsbls}->{$rulename}; $self->lookup_single_dnsbl($scanner, $obj, $rulename, $dom, $rulecf->{zone}, $rulecf->{type}); @@ -804,9 +836,14 @@ $ip =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/; my $revip = "$4.$3.$2.$1"; + my $tflags = $scanner->{conf}->{tflags}; my $cf = $scanner->{uridnsbl_active_rules_revipbl}; foreach my $rulename (keys %{$cf}) { my $rulecf = $scanner->{conf}->{uridnsbls}->{$rulename}; + + # ips_only/domains_only lookups should not act on this kind of BL + next if ($tflags->{$rulename} =~ /\b(?:ips_only|domains_only)\b/); + $self->lookup_single_dnsbl($scanner, $obj, $rulename, $revip, $rulecf->{zone}, $rulecf->{type}); } @@ -894,7 +931,9 @@ if ($scanner->{uridnsbl_active_rules_revipbl}->{$rulename} || $scanner->{uridnsbl_active_rules_nsrhsbl}->{$rulename} || $scanner->{uridnsbl_active_rules_fullnsrhsbl}->{$rulename} - || $scanner->{uridnsbl_active_rules_rhsbl}->{$rulename}) + || $scanner->{uridnsbl_active_rules_rhsbl}->{$rulename} + || $scanner->{uridnsbl_active_rules_rhsbl_ipsonly}->{$rulename} + || $scanner->{uridnsbl_active_rules_rhsbl_domsonly}->{$rulename}) { # TODO: this needs to handle multiple domain hits per rule $scanner->clear_test_state(); Index: rules/50_scores.cf =================================================================== --- rules/50_scores.cf (revision 918482) +++ rules/50_scores.cf (working copy) @@ -1021,6 +1021,7 @@ score URIBL_WS_SURBL 0 1.659 0 1.608 # n=0 n=2 score URIBL_BLACK 0 1.775 0 1.725 # n=0 n=2 score URIBL_GREY 0 1.084 0 0.424 # n=0 n=2 +score URIBL_DBL 0 1.7 0 1.7 # # score URIBL_GREY 0.25 score URIBL_RED 0.001 Index: rules/25_uribl.cf =================================================================== --- rules/25_uribl.cf (revision 918482) +++ rules/25_uribl.cf (working copy) @@ -31,7 +31,7 @@ ifplugin Mail::SpamAssassin::Plugin::URIDNSBL ########################################################################### -## SBL +## Spamhaus uridnssub URIBL_SBL zen.spamhaus.org. A 127.0.0.2 body URIBL_SBL eval:check_uridnsbl('URIBL_SBL') @@ -39,6 +39,13 @@ tflags URIBL_SBL net reuse URIBL_SBL +# DBL, http://www.spamhaus.org/dbl/ . Note that hits return 127.0.1.x +# A records, so we use a 32-bit mask to match that /24 range. +urirhssub URIBL_DBL dbl.spamhaus.org. A 2130706688 +body URIBL_DBL eval:check_uridnsbl('URIBL_DBL') +describe URIBL_DBL Contains an URL listed in the DBL blocklist +tflags URIBL_DBL net domains_only + ########################################################################### ## SURBL Index: t/uribl_all_types.t =================================================================== --- t/uribl_all_types.t (revision 0) +++ t/uribl_all_types.t (revision 0) @@ -0,0 +1,46 @@ +#!/usr/bin/perl +# +# bug 6335: ensure that both domains_only and ips_only URIDNSBL rules can coexist + +use lib '.'; use lib 't'; +use SATest; sa_t_init("uribl_all_types"); + +use constant TEST_ENABLED => conf_bool('run_net_tests') && conf_bool('run_long_tests'); +use constant DO_RUN => TEST_ENABLED && can_use_net_dns_safely(); +use Test; + +BEGIN { + plan tests => (DO_RUN ? 3 : 0), +}; + +exit unless (DO_RUN); + +# --------------------------------------------------------------------------- + +%patterns = ( + + q{ X_URIBL_IPSONLY [URIs: 144.137.3.98] } => 'X_URIBL_IPSONLY', + q{ X_URIBL_DOMSONLY [URIs: uribl-example-c.com] } => 'X_URIBL_DOMSONLY', + +); + +tstlocalrules(q{ + + rbl_timeout 30 + + urirhssub X_URIBL_IPSONLY dnsbltest.spamassassin.org. A 2 + body X_URIBL_IPSONLY eval:check_uridnsbl('X_URIBL_IPSONLY') + tflags X_URIBL_IPSONLY net ips_only + + urirhssub X_URIBL_DOMSONLY dnsbltest.spamassassin.org. A 4 + body X_URIBL_DOMSONLY eval:check_uridnsbl('X_URIBL_DOMSONLY') + tflags X_URIBL_DOMSONLY net domains_only + + add_header all RBL _RBL_ + +}); + +# note: don't leave -D here, it causes spurious passes +ok sarun ("-t < data/spam/dnsbl.eml 2>&1", \&patterns_run_cb); +ok_all_patterns(); + Index: t/uribl_ips_only.t =================================================================== --- t/uribl_ips_only.t (revision 0) +++ t/uribl_ips_only.t (revision 0) @@ -0,0 +1,38 @@ +#!/usr/bin/perl +# bug 6335: ips_only URIDNSBL rules + +use lib '.'; use lib 't'; +use SATest; sa_t_init("uribl_ips_only"); + +use constant TEST_ENABLED => conf_bool('run_net_tests') && conf_bool('run_long_tests'); +use constant DO_RUN => TEST_ENABLED && can_use_net_dns_safely(); +use Test; + +BEGIN { + plan tests => (DO_RUN ? 2 : 0), +}; + +exit unless (DO_RUN); + +# --------------------------------------------------------------------------- + +%anti_patterns = ( + q{ X_URIBL_IPSONLY } => 'A', +); + +tstlocalrules(q{ + + rbl_timeout 30 + + urirhssub X_URIBL_IPSONLY dnsbltest.spamassassin.org. A 2 + body X_URIBL_IPSONLY eval:check_uridnsbl('X_URIBL_IPSONLY') + tflags X_URIBL_IPSONLY net ips_only + + add_header all RBL _RBL_ + +}); + +# note: don't leave -D here, it causes spurious passes +ok sarun ("-t < data/spam/dnsbl_ipsonly.eml 2>&1", \&patterns_run_cb); +ok_all_patterns(); + Index: t/uribl_domains_only.t =================================================================== --- t/uribl_domains_only.t (revision 0) +++ t/uribl_domains_only.t (revision 0) @@ -0,0 +1,38 @@ +#!/usr/bin/perl +# bug 6335: domains_only URIDNSBL rules + +use lib '.'; use lib 't'; +use SATest; sa_t_init("uribl_domains_only"); + +use constant TEST_ENABLED => conf_bool('run_net_tests') && conf_bool('run_long_tests'); +use constant DO_RUN => TEST_ENABLED && can_use_net_dns_safely(); +use Test; + +BEGIN { + plan tests => (DO_RUN ? 2 : 0), +}; + +exit unless (DO_RUN); + +# --------------------------------------------------------------------------- + +%anti_patterns = ( + q{ X_URIBL_DOMSONLY } => 'A', +); + +tstlocalrules(q{ + + rbl_timeout 30 + + urirhssub X_URIBL_DOMSONLY dnsbltest.spamassassin.org. A 2 + body X_URIBL_DOMSONLY eval:check_uridnsbl('X_URIBL_DOMSONLY') + tflags X_URIBL_DOMSONLY net domains_only + + add_header all RBL _RBL_ + +}); + +# note: don't leave -D here, it causes spurious passes +ok sarun ("-t < data/spam/dnsbl_domsonly.eml 2>&1", \&patterns_run_cb); +ok_all_patterns(); + Index: t/dnsbl.t =================================================================== --- t/dnsbl.t (revision 918482) +++ t/dnsbl.t (working copy) @@ -4,21 +4,7 @@ use SATest; sa_t_init("dns"); use constant TEST_ENABLED => conf_bool('run_net_tests') && conf_bool('run_long_tests'); -use constant HAS_NET_DNS => eval { require Net::DNS; }; -# bug 3806: -# Do not run this test with version of Sys::Hostname::Long older than 1.4 -# on non-Linux unices as root, due to a bug in Sys::Hostname::Long -# (which is used by Net::DNS) -use constant IS_LINUX => $^O eq 'linux'; -use constant IS_WINDOWS => ($^O =~ /^(mswin|dos|os2)/oi); -use constant AM_ROOT => $< == 0; -use constant HAS_SAFE_HOSTNAME => - eval { require Sys::Hostname::Long; Sys::Hostname::Long->VERSION(1.4) }; - -use constant DO_RUN => - TEST_ENABLED && HAS_NET_DNS && - (HAS_SAFE_HOSTNAME || !AM_ROOT || IS_LINUX || IS_WINDOWS); - +use constant DO_RUN => TEST_ENABLED && can_use_net_dns_safely(); use Test; BEGIN { Index: t/SATest.pm =================================================================== --- t/SATest.pm (revision 918482) +++ t/SATest.pm (working copy) @@ -21,6 +21,7 @@ our $SKIP_SPAMC_TESTS; our $SSL_AVAILABLE; our $SKIP_SETUID_NOBODY_TESTS = 0; + our $SKIP_DNSBL_TESTS = 0; } # Set up for testing. Exports (as global vars): @@ -961,4 +962,18 @@ sub dbgprint { print STDOUT "[".time()."] ".$_[0]; } +sub can_use_net_dns_safely { + return unless eval { require Net::DNS; }; + + # bug 3806: + # Do not run this test with version of Sys::Hostname::Long older than 1.4 + # on non-Linux unices as root, due to a bug in Sys::Hostname::Long + # (which is used by Net::DNS) + + return 1 if eval { require Sys::Hostname::Long; Sys::Hostname::Long->VERSION(1.4) }; + return 1 if ($< != 0); + return 1 if ($^O =~ /^(linux|mswin|dos|os2)/oi); + return; +} + 1; Index: t/uribl.t =================================================================== --- t/uribl.t (revision 918482) +++ t/uribl.t (working copy) @@ -4,25 +4,11 @@ use SATest; sa_t_init("uribl"); use constant TEST_ENABLED => conf_bool('run_net_tests') && conf_bool('run_long_tests'); -use constant HAS_NET_DNS => eval { require Net::DNS; }; -# bug 3806: -# Do not run this test with version of Sys::Hostname::Long older than 1.4 -# on non-Linux unices as root, due to a bug in Sys::Hostname::Long -# (which is used by Net::DNS) -use constant IS_LINUX => $^O eq 'linux'; -use constant IS_WINDOWS => ($^O =~ /^(mswin|dos|os2)/oi); -use constant AM_ROOT => $< == 0; -use constant HAS_SAFE_HOSTNAME => - eval { require Sys::Hostname::Long; Sys::Hostname::Long->VERSION(1.4) }; - -use constant DO_RUN => - TEST_ENABLED && HAS_NET_DNS && - (HAS_SAFE_HOSTNAME || !AM_ROOT || IS_LINUX || IS_WINDOWS); - +use constant DO_RUN => TEST_ENABLED && can_use_net_dns_safely(); use Test; BEGIN { - plan tests => (DO_RUN ? 5 : 0), + plan tests => (DO_RUN ? 6 : 0), }; exit unless (DO_RUN); @@ -34,6 +20,7 @@ q{ X_URIBL_B } => 'B', q{ X_URIBL_NS } => 'NS', q{ X_URIBL_FULL_NS } => 'FULL_NS', + q{ X_URIBL_DOMSONLY } => 'X_URIBL_DOMSONLY', ); tstlocalrules(q{ @@ -56,6 +43,10 @@ body X_URIBL_FULL_NS eval:check_uridnsbl('X_URIBL_FULL_NS') tflags X_URIBL_FULL_NS net + urirhssub X_URIBL_DOMSONLY dnsbltest.spamassassin.org. A 2 + body X_URIBL_DOMSONLY eval:check_uridnsbl('X_URIBL_DOMSONLY') + tflags X_URIBL_DOMSONLY net domains_only + add_header all RBL _RBL_ }); Index: t/dnsbl_sc_meta.t =================================================================== --- t/dnsbl_sc_meta.t (revision 918482) +++ t/dnsbl_sc_meta.t (working copy) @@ -4,21 +4,7 @@ use SATest; sa_t_init("dnsbl_sc_meta"); use constant TEST_ENABLED => conf_bool('run_net_tests'); -use constant HAS_NET_DNS => eval { require Net::DNS; }; -# bug 3806: -# Do not run this test with version of Sys::Hostname::Long older than 1.4 -# on non-Linux unices as root, due to a bug in Sys::Hostname::Long -# (which is used by Net::DNS) -use constant IS_LINUX => $^O eq 'linux'; -use constant IS_WINDOWS => ($^O =~ /^(mswin|dos|os2)/oi); -use constant AM_ROOT => $< == 0; -use constant HAS_SAFE_HOSTNAME => - eval { require Sys::Hostname::Long; Sys::Hostname::Long->VERSION(1.4) }; - -use constant DO_RUN => - TEST_ENABLED && HAS_NET_DNS && - (HAS_SAFE_HOSTNAME || !AM_ROOT || IS_LINUX || IS_WINDOWS); - +use constant DO_RUN => TEST_ENABLED && can_use_net_dns_safely(); use Test; BEGIN { Index: t/data/spam/dnsbl_ipsonly.eml =================================================================== --- t/data/spam/dnsbl_ipsonly.eml (revision 0) +++ t/data/spam/dnsbl_ipsonly.eml (revision 0) @@ -0,0 +1,11 @@ +From spammer@example.net Fri Dec 7 11:07:10 2001 +Received: from evil.example.net [144.137.3.98] by chaos.example.net + for someone@example.com; Fri, 07 Dec 2001 11:07:15 +1100 (EST) +From: "DNSBL Testing" +To: someone@example.com +Subject: no subject needed +Date: Fri, 7 Dec 2001 07:01:03 +Message-Id: <20011206235802.4FD6F1143D6@mail.netnoteinc.com> + +I should not be listed: http://foo.bar.baz.uribl-example-a.com/ + Index: t/data/spam/dnsbl_domsonly.eml =================================================================== --- t/data/spam/dnsbl_domsonly.eml (revision 0) +++ t/data/spam/dnsbl_domsonly.eml (revision 0) @@ -0,0 +1,11 @@ +From spammer@example.net Fri Dec 7 11:07:10 2001 +Received: from evil.example.net [144.137.3.98] by chaos.example.net + for someone@example.com; Fri, 07 Dec 2001 11:07:15 +1100 (EST) +From: "DNSBL Testing" +To: someone@example.com +Subject: no subject needed +Date: Fri, 7 Dec 2001 07:01:03 +Message-Id: <20011206235802.4FD6F1143D6@mail.netnoteinc.com> + +I should not be listed: http://144.137.3.98/blah + Index: t/data/spam/dnsbl.eml =================================================================== --- t/data/spam/dnsbl.eml (revision 918482) +++ t/data/spam/dnsbl.eml (working copy) @@ -24,4 +24,5 @@ me too: http://uribl-example-c.com/ Also -- http://spamassassin.org/ +And -- http://144.137.3.98/blah