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} }) {