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 2015/05/23 15:58:40 UTC

svn commit: r1681350 - in /spamassassin/trunk/lib/Mail/SpamAssassin: Conf.pm Plugin/WLBLEval.pm

Author: mmartinec
Date: Sat May 23 13:58:39 2015
New Revision: 1681350

URL: http://svn.apache.org/r1681350
Log:
Bug 7198: Let whitelist_from_rcvd also accept CIDR notation and IPv6 address

Modified:
    spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/WLBLEval.pm

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm?rev=1681350&r1=1681349&r2=1681350&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm Sat May 23 13:58:39 2015
@@ -360,24 +360,24 @@ for the whitelisting rule to fire. The f
 address to whitelist, and the second is a string to match the relay's rDNS,
 or its IP address. Matching is case-insensitive.
 
-This second parameter is matched against the TCP-info information field as
-provided in a FROM clause of a trace information (i.e. the Received header
+This second parameter is matched against a TCP-info information field as
+provided in a FROM clause of a trace information (i.e. in a Received header
 field, see RFC 5321). Only the Received header fields inserted by trusted
-hosts are considered. This parameter can either be a full hostname, or the
-domain component of that hostname, or an IP address in square brackets.
-The reverse DNS lookup is done by a MTA, not by SpamAssassin.
-
-In case of an IPv4 address in brackets, it may be truncated on classful
-boundaries to cover whole subnets, e.g. C<[10.1.2.3]>, C<[10.1.2]>,
-C<[10.1]>, C<[10]>.  CIDR notation is currently not supported, nor is
-IPv6. The matching on IP address is mainly provided to cover rare cases
-where whitelisting of a sending MTA is desired which does not have a
-correct reverse DNS configured.
+hosts are considered. This parameter can either be a full hostname, or a
+domain component of that hostname, or an IP address (optionally followed
+by a slash and a prefix length) in square brackets. The address prefix
+(mask) length with a slash may stand within brackets along with an address,
+or may follow the bracketed address. Reverse DNS lookup is done by an MTA,
+not by SpamAssassin.
+
+For backward compatibility as an alternative to a CIDR notation, an IPv4
+address in brackets may be truncated on classful boundaries to cover whole
+subnets, e.g. C<[10.1.2.3]>, C<[10.1.2]>, C<[10.1]>, C<[10]>.
 
 In other words, if the host that connected to your MX had an IP address
 192.0.2.123 that mapped to 'sendinghost.example.org', you should specify
-C<sendinghost.example.org>, or C<example.org>, or C<[192.0.2.123]> or
-C<[192.0.2]> here.
+C<sendinghost.example.org>, or C<example.org>, or C<[192.0.2.123]>, or
+C<[192.0.2.0/24]>, or C<[192.0.2]> here.
 
 Note that this requires that C<internal_networks> be correct.  For simple
 cases, it will be, but for a complex network you may get better results
@@ -390,8 +390,12 @@ result in the generated Received header
 e.g.
 
   whitelist_from_rcvd joe@example.com  example.com
-  whitelist_from_rcvd *@axkit.org      sergeant.org
+  whitelist_from_rcvd *@*              mail.example.org
   whitelist_from_rcvd *@axkit.org      [192.0.2.123]
+  whitelist_from_rcvd *@axkit.org      [192.0.2.0/24]
+  whitelist_from_rcvd *@axkit.org      [192.0.2.0]/24
+  whitelist_from_rcvd *@axkit.org      [2001:db8:1234::/48]
+  whitelist_from_rcvd *@axkit.org      [2001:db8:1234::]/48
 
 =item def_whitelist_from_rcvd addr@lists.sourceforge.net sourceforge.net
 

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/WLBLEval.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/WLBLEval.pm?rev=1681350&r1=1681349&r2=1681350&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/WLBLEval.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/WLBLEval.pm Sat May 23 13:58:39 2015
@@ -17,14 +17,16 @@
 
 package Mail::SpamAssassin::Plugin::WLBLEval;
 
-use Mail::SpamAssassin::Plugin;
-use Mail::SpamAssassin::Logger;
-
 use strict;
 use warnings;
 use bytes;
 use re 'taint';
 
+use NetAddr::IP 4.000;
+
+use Mail::SpamAssassin::Plugin;
+use Mail::SpamAssassin::Logger;
+
 use vars qw(@ISA);
 @ISA = qw(Mail::SpamAssassin::Plugin);
 
@@ -310,23 +312,51 @@ sub _check_whitelist_rcvd {
   foreach my $white_addr (keys %{$list}) {
     my $regexp = qr/$list->{$white_addr}{re}/i;
     foreach my $domain (@{$list->{$white_addr}{domain}}) {
+      # $domain is a second param in whitelist_from_rcvd: a domain name or an IP address
       
       if ($addr =~ $regexp) {
+        # From or sender address matching the first param in whitelist_from_rcvd
         my $match;
         foreach my $lastunt (@relays) {
-          local $1;
-          if ($domain =~ m{^ \[ (.*) \] \z}sx) {  # matching by IP address
+          local($1,$2);
+          if ($domain =~ m{^ \[ (.*) \] ( / \d{1,3} )? \z}sx) {
+            # matching by IP address
             my($wl_ip, $rly_ip) = ($1, $lastunt->{ip});
+            $wl_ip .= $2  if defined $2;  # allow prefix len even after bracket
+
             if (!defined $rly_ip || $rly_ip eq '') {
               # relay's IP address not provided or unparseable
-            } elsif ($wl_ip =~ /^\d+\.\d+\.\d+\.\d+\z/) {
+
+            } elsif ($wl_ip  =~ /^\d+\.\d+\.\d+\.\d+\z/s) {
+              # an IPv4 whitelist entry can only be matched by an IPv4 relay
               if ($wl_ip eq $rly_ip) { $match = 1; last }  # exact match
-            } elsif ($wl_ip =~ /^[\d\.]+\z/) {  # assume IPv4 classful subnet
+
+            } elsif ($wl_ip =~ /^[\d\.]+\z/s) {  # an IPv4 classful subnet?
               $wl_ip =~ s/\.*\z/./;  # enforce trailing dot
-              if ($rly_ip =~ /^\Q$wl_ip\E/i) { $match = 1; last }  # subnet
+              if ($rly_ip =~ /^\Q$wl_ip\E/) { $match = 1; last }  # subnet
+
+            } else {  # either an wl entry is an IPv6 addr, or has a prefix len
+              my $rly_ip_obj = NetAddr::IP->new($rly_ip);  # TCP-info field
+              if (!defined $rly_ip_obj) {
+                dbg("rules: bad IP address in relay: %s, sender: %s",
+                    $rly_ip, $addr);
+              } else {
+                my $wl_ip_obj = NetAddr::IP->new($wl_ip); # whitelist 2nd param
+                if (!defined $wl_ip_obj) {
+                  info("rules: bad IP address in whitelist: %s", $wl_ip);
+                } elsif ($wl_ip_obj->contains($rly_ip_obj)) {
+                  # note: an IPv4-compatible IPv6 address can match an IPv4 addr
+                  dbg("rules: relay addr %s matches whitelist %s, sender: %s",
+                      $rly_ip, $wl_ip_obj, $addr);
+                  $match = 1; last;
+                } else {
+                  dbg("rules: relay addr %s does not match wl %s, sender %s",
+                      $rly_ip, $wl_ip_obj, $addr);
+                }
+              }
             }
-            # todo: handle IPv6 and CIDR notation
-          } else {  # match by a rdns name
+
+          } else {  # match by an rdns name
             my $rdns = $lastunt->{lc_rdns};
             if ($rdns =~ /(?:^|\.)\Q${domain}\E$/i) { $match=1; last }
           }