Dear list members,

upgrading to Debian Jessie has brought SpamAssassin 3.4.0 to a private
server of mine.  For its particular use case, I like to directly assign
scores to autonomous systems whose owners provide snowshoe spamming
services.  (I realize this strategy may be less useful for large mail
hosts, but for this system, it works perfectly.)

Unfortunately, this breaks in 3.4.0.

I use rules such as these:

header   __LOCAL_ASN eval:check_rbl_txt('asn-lastexternal', 
'asn.routeviews.org')
describe __LOCAL_ASN Successful ASN lookup from routeviews.org
tflags   __LOCAL_ASN net

header   LOCAL_SPAMMER_BADISP eval:check_rbl_sub('asn-lastexternal', '"4321"')
describe LOCAL_SPAMMER_BADISP AS4321 (Bad ISP, Inc.)
score    LOCAL_SPAMMER_BADISP 3

[... and some more check_rbl_sub tests ...]

The problem is that asn.routeviews.org returns ASN data as TXT records
in this format:

        "4321" "82.200.196.0" "24"

Up to 3.3.2, SpamAssassin made this available to check_rbl_sub as-is, so
the rule given above worked.  3.4.0 however has the following in Dns.pm
(and it's still identical in the nightlies distributed for mass-check):

> sub process_dnsbl_set {
>   [...]
>   my $rdatastr = $answer->UNIVERSAL::can('txtdata') ? 
> join('',$answer->txtdata)
>                                                     : $answer->rdatastr;

As a result, the record given above becomes

        432182.200.196.024

which is impossible to parse (it could be AS 43218 with IP range
2.200.196.0/24, or AS 4321 with IP range 82.200.196.0/24, or even AS
432 with IP range 182.200.196.0/24).

Patching that line to join with a space (join(' ', $answer->txtdata)...)
makes my immediate problem go away, provided that I now look for
'^54321 ' instead of '"54321"' in check_rbl_sub().

Questions:

Why does process_dnsbl_set() join the elements of TXT records directly,
instead of separating them with something?  Is there any chance of having
the old behaviour restored in official releases, or at least having some
separation character in there?

Is there a better way to do what I want?  (I know about Plugin::ASN,
of course, but IIUC it can only be used for tagging, not for assigning
direct scores?)

Full patch appended (there are two more similar cases, one of which is
merely cosmetic).

Regards

Marc
--- Dns.pm.orig	2015-01-31 19:08:37.000000000 +0000
+++ Dns.pm	2015-05-08 09:00:12.082711483 +0000
@@ -174,7 +174,7 @@
     # txtdata returns a non- zone-file-format encoded result, unlike rdatastr;
     # avoid space-separated RDATA <character-string> fields if possible,
     # txtdata provides a list of strings in a list context since Net::DNS 0.69
-    $log = join('',$answer->txtdata);
+    $log = join(' ',$answer->txtdata);
     local $1;
     $log =~ s{ (?<! [<(\[] ) (https? : // \S+)}{<$1>}xgi;
   } else {  # assuming $answer->type eq 'A'
@@ -219,7 +219,7 @@
   # avoid space-separated RDATA <character-string> fields if possible,
   # txtdata provides a list of strings in a list context since Net::DNS 0.69
   #
-  my $rdatastr = $answer->UNIVERSAL::can('txtdata') ? join('',$answer->txtdata)
+  my $rdatastr = $answer->UNIVERSAL::can('txtdata') ? join(' ',$answer->txtdata)
                                                     : $answer->rdatastr;
   if (defined $qname && defined $rdatastr) {
     my $qclass = $question->qclass;
@@ -288,7 +288,7 @@
   # avoid space-separated RDATA <character-string> fields if possible,
   # txtdata provides a list of strings in a list context since Net::DNS 0.69
   #
-  my $rdatastr = $answer->UNIVERSAL::can('txtdata') ? join('',$answer->txtdata)
+  my $rdatastr = $answer->UNIVERSAL::can('txtdata') ? join(' ',$answer->txtdata)
                                                     : $answer->rdatastr;
 
   while (my ($subtest, $rule) = each %{ $self->{dnspost}->{$set} }) {

Reply via email to