You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by mm...@apache.org on 2011/06/20 20:27:33 UTC

svn commit: r1137734 - in /spamassassin/trunk/lib/Mail/SpamAssassin: PerMsgStatus.pm Plugin/ASN.pm Plugin/AskDNS.pm Plugin/DKIM.pm Plugin/URIDNSBL.pm

Author: mmartinec
Date: Mon Jun 20 18:27:33 2011
New Revision: 1137734

URL: http://svn.apache.org/viewvc?rev=1137734&view=rev
Log:
- Bug 6518: AskDNS - allow a list of rr_types (including ANY) in an askdns directive;
- set_tag tweaks in DNS and ASN plugins: make use of a listref as a tag value;
- let URIDNSBL make available its list of URI hosts and domains as tags

Modified:
    spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ASN.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/AskDNS.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm?rev=1137734&r1=1137733&r2=1137734&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm Mon Jun 20 18:27:33 2011
@@ -1889,6 +1889,7 @@ sub get_uri_list {
   }
 
   $self->{uri_list} = \@uris;
+# $self->set_tag('URILIST', @uris == 1 ? $uris[0] : \@uris)  if @uris;
 
   return @uris;
 }

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ASN.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ASN.pm?rev=1137734&r1=1137733&r2=1137734&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ASN.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ASN.pm Mon Jun 20 18:27:33 2011
@@ -419,11 +419,13 @@ sub process_dns_result {
     $pms->{msg}->put_metadata('X-ASN', join(' ',@asn_tag_data));
     my $prefix = $pms->{conf}->{asn_prefix};
     if (defined $prefix && $prefix ne '') { s/^/$prefix/ for @asn_tag_data }
-    $pms->set_tag($asn_tag, join(' ',@asn_tag_data));
+    $pms->set_tag($asn_tag,
+                  @asn_tag_data == 1 ? $asn_tag_data[0] : \@asn_tag_data);
   }
   if ($any_route_updates && @route_tag_data) {
     $pms->{msg}->put_metadata('X-ASN-Route', join(' ',@route_tag_data));
-    $pms->set_tag($route_tag, join(' ',@route_tag_data));
+    $pms->set_tag($route_tag,
+                  @route_tag_data == 1 ? $route_tag_data[0] : \@route_tag_data);
   }
 }
 

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/AskDNS.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/AskDNS.pm?rev=1137734&r1=1137733&r2=1137734&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/AskDNS.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/AskDNS.pm Mon Jun 20 18:27:33 2011
@@ -97,14 +97,23 @@ and B is (xx,yy,zz), will result in quer
 22.xx.example.22.com, 11.yy.example.11.com, 22.yy.example.22.com,
 11.zz.example.11.com, 22.zz.example.22.com .
 
-A parameter following the query template is a DNS resource record (RR)
-type. A DNS result may bring resource records of multiple types, but only
-those resource records matching the type specified in a rule are considered,
-returned resource records with non-matching types are ignored for this rule.
-Currently the RR type parameter determines the DNS query type as well as a
-filter for the resulting RR types, although in future similar queries could
-be combined, launching a query of type 'ANY'. Currently allowed RR types
-are: A, AAAA, MX, TXT, PTR, NS, SOA, CNAME, HINFO, MINFO, WKS, SRV, SPF.
+A parameter rr_type following the query template is a comma-separated list
+of expected DNS resource record (RR) types. Missing rr_type parameter implies
+an 'A'. A DNS result may bring resource records of multiple types, but only
+resource records of a type found in the rr_type parameter list are considered,
+other resource records found in the answer section of a DNS reply are ignored
+for this rule. A value ANY in the rr_type parameter list matches any resource
+record type. An empty DNS answer section does not match ANY.
+
+The rr_type parameter not only provides a filter for RR types found in
+the DNS answer, but also determines the DNS query type. If only a single
+RR type is specified in the parameter (e.g. TXT), than this is also the RR
+type of a query. When more than one RR type is specified (e.g. A,AAAA,TXT)
+or if ANY is specified, then the DNS query type will be ANY and the rr_type
+parameter will only act as a filter on a result.
+
+Currently allowed RR types in the rr_type parameter are: ANY, A, AAAA, MX,
+TXT, PTR, NS, SOA, CNAME, HINFO, MINFO, WKS, SRV, SPF.
 
 The last optional parameter of a rule is a filtering expression, a.k.a. a
 subrule. Its function is much like the subrule in URIDNSBL plugin rules,
@@ -294,14 +303,19 @@ sub set_config {
       if (!defined $value || $value =~ /^$/) {
         return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
       } elsif ($value !~ /^ (\S+) \s+ (\S+)
-                            (?: \s+ (A|AAAA|MX|TXT|PTR|NS|SOA|CNAME|
-                                     HINFO|MINFO|WKS|SRV|SPF)
+                            (?: \s+ ([A-Za-z0-9,]+)
                                 (?: \s+ (.*?) )?  )? \s* $/xs) {
         return $Mail::SpamAssassin::Conf::INVALID_VALUE;
       } else {
         my($rulename,$query_template,$query_type,$subtest) = ($1,$2,$3,$4);
         $query_type = 'A' if !defined $query_type;
         $query_type = uc $query_type;
+        my @answer_types = split(/,/, $query_type);
+        if (grep(!/^(?:ANY|A|AAAA|MX|TXT|PTR|NS|SOA|CNAME|
+                       HINFO|MINFO|WKS|SRV|SPF)\z/x, @answer_types)) {
+          return $Mail::SpamAssassin::Conf::INVALID_VALUE;
+        }
+        $query_type = 'ANY' if @answer_types > 1 || $answer_types[0] eq 'ANY';
         if (defined $subtest) {
           $subtest = parse_and_canonicalize_subtest($subtest);
           defined $subtest or return $Mail::SpamAssassin::Conf::INVALID_VALUE;
@@ -317,7 +331,10 @@ sub set_config {
         my $query_template_key = $query_type . ':' . $query_template;
 
         $self->{askdns}{$depends_on_tags}{$query_template_key} ||=
-          { query => $query_template, type => $query_type, rules => {} };
+          { query => $query_template, rules => {}, q_type => $query_type,
+            a_types =>  # optimization: undef means "same as q_type"
+              @answer_types == 1 && $answer_types[0] eq $query_type ? undef
+                                                           : \@answer_types };
         $self->{askdns}{$depends_on_tags}{$query_template_key}{rules}{$rulename}
           = $subtest;
       # dbg("askdns: rule: %s, config dep: %s, domkey: %s, subtest: %s",
@@ -383,19 +400,22 @@ sub launch_queries {
   # and launch DNS queries
   while ( my($query_template_key, $struct) =
             each %{$conf->{askdns}{$depends_on_tags}} ) {
-    my($query_template, $query_type, $rules) = @$struct{qw(query type rules)};
+    my($query_template, $query_type, $answer_types_ref, $rules) =
+      @$struct{qw(query q_type a_types rules)};
 
     my @rulenames = keys %$rules;
     if (grep($conf->{scores}->{$_}, @rulenames)) {
       dbg("askdns: query template %s, type %s, rules: %s",
-          $query_template, $query_type, join(', ', @rulenames));
+          $query_template,
+          !$answer_types_ref ? $query_type
+            : $query_type.'/'.join(',',@$answer_types_ref),
+          join(', ', @rulenames));
     } else {
       dbg("askdns: query template %s, type %s, all rules disabled: %s",
           $query_template, $query_type, join(', ', @rulenames));
       next;
     }
 
-    local $1;
     # collect all tag names from a template, each may occur more than once
     my @templ_tags = $query_template =~ /_([A-Z][A-Z0-9]*)_/gs;
 
@@ -412,7 +432,7 @@ sub launch_queries {
       $templ_vals{$t} = [ grep(!$seen{$_}++, split(' ',$tags{$t})) ];
     }
 
-    # count through all tag values
+    # count through all tag value tuples
     my @digit = (0) x @templ_tags;  # counting accumulator
 OUTER:
     for (;;) {
@@ -421,22 +441,27 @@ OUTER:
         my $t = $templ_tags[$j];
         $current_tag_val{$t} = $templ_vals{$t}[$digit[$j]];
       }
+      local $1;
       my $query_domain = $query_template;
-      $query_domain =~ s{_([A-Z][A-Z0-9]*)_}{$current_tag_val{$1}}g;
+      $query_domain =~ s{_([A-Z][A-Z0-9]*)_}
+                        { defined $current_tag_val{$1} ? $current_tag_val{$1}
+                                                       : '' }ge;
 
       # the $dnskey identifies this query in AsyncLoop's pending_lookups
       my $dnskey = join(':', 'askdns', $query_type, $query_domain);
       dbg("askdns: expanded query %s, dns key %s", $query_domain, $dnskey);
 
-      if ($pms->{async}->get_lookup($dnskey)) {  # already underway?
+      if ($query_domain eq '') {
+        # ignore, just in case
+      } elsif ($pms->{async}->get_lookup($dnskey)) {  # already underway?
         warn "askdns: such lookup has already been issued: ".$dnskey;
       } else {
         if (!exists $pms->{askdns_map_dnskey_to_rules}{$dnskey}) {
           $pms->{askdns_map_dnskey_to_rules}{$dnskey} =
-             [ [$query_type, $rules] ];
+             [ [$query_type, $answer_types_ref, $rules] ];
         } else {
           push(@{$pms->{askdns_map_dnskey_to_rules}{$dnskey}},
-               [$query_type, $rules] );
+               [$query_type, $answer_types_ref, $rules] );
         }
         if (exists $pms->{askdns_dnskey_to_response}{$dnskey}) {
           # answer already available by some earlier query, or query underway
@@ -524,6 +549,7 @@ sub process_response_packet {
         }
       }
       # decode DNS presentation format as returned by Net::DNS
+      local $1;
       $rr_rdatastr =~ s/\\([0-9]{3}|.)/length($1)==1 ? $1 : chr($1)/gse;
     # dbg("askdns: received rr type %s, data: %s", $rr_type, $rr_rdatastr);
     }
@@ -531,8 +557,10 @@ sub process_response_packet {
     my $j = 0;
     for my $q_tuple (!ref $queries_ref ? () : @$queries_ref) {
       next  if !$q_tuple;
-      my($query_type, $rules) = @$q_tuple;
+      my($query_type, $answer_types_ref, $rules) = @$q_tuple;
+
       next  if $query_type ne $qtype;
+      $answer_types_ref = [$query_type]  if !defined $answer_types_ref;
 
       # mark rule as done
       $pms->{askdns_map_dnskey_to_rules}{$dnskey}[$j++] = undef;
@@ -542,8 +570,10 @@ sub process_response_packet {
         local($1,$2,$3);
         if (ref $subtest eq 'HASH') {  # a list of DNS rcodes (as hash keys)
           $match = 1  if $subtest->{$rcode};
-        } elsif ($rcode != 0 || $rr_type ne $query_type) {
-          # skip remaining tests on DNS error or wrong RR type
+        } elsif ($rcode != 0) {
+          # skip remaining tests on DNS error
+        } elsif (!grep($_ eq 'ANY' || $_ eq $rr_type, @$answer_types_ref) ) {
+          # skip remaining tests on wrong RR type
         } elsif (!defined $subtest) {
           $match = 1;  # any valid response of the requested RR type matches
         } elsif (ref $subtest eq 'Regexp') {  # a regular expression

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm?rev=1137734&r1=1137733&r2=1137734&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm Mon Jun 20 18:27:33 2011
@@ -848,12 +848,10 @@ sub _check_dkim_signature {
                             map($_->identity, @valid_signatures));
       @domain_list =   grep(defined $_ && $_ ne '' && !$seen2{$_}++,
                             map($_->domain, @valid_signatures));
-      $pms->set_tag('DKIMIDENTITY', !@identity_list ? ''
-                                  :  @identity_list == 1 ? $identity_list[0]
-                                  : \@identity_list);
-      $pms->set_tag('DKIMDOMAIN',   !@domain_list ? ''
-                                  :  @domain_list == 1 ? $domain_list[0]
-                                  : \@domain_list);
+      $pms->set_tag('DKIMIDENTITY',
+                    @identity_list == 1 ? $identity_list[0] : \@identity_list);
+      $pms->set_tag('DKIMDOMAIN',
+                    @domain_list == 1   ? $domain_list[0]   : \@domain_list);
     } elsif (@signatures) {
       $pms->{dkim_signed} = 1;
       my $sig = $signatures[0];

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm?rev=1137734&r1=1137733&r2=1137734&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm Mon Jun 20 18:27:33 2011
@@ -482,6 +482,13 @@ sub parsed_metadata {
     }
   }
 
+  my @hnames = keys %hostlist;
+  $scanner->set_tag('URIHOSTS',
+                    @hnames == 1 ? $hnames[0] : \@hnames)  if @hnames;
+  my @dnames = values %hostlist;
+  $scanner->set_tag('URIDOMAINS',
+                    @dnames == 1 ? $dnames[0] : \@dnames)  if @dnames;
+
   # and query
   $self->query_hosts_or_domains($scanner, \%hostlist);