Hi,

Here comes patch hopefully fixing this issue. It needs to be applied in
/usr/share/perl5/Mail/SpamAssassin/Plugin

Here's what's changed:
- IPv6 addresses are validated and accepted
- directories are created from expanded IPv6 addresses, like
  for example 2a01:ff::1 gives 2A01/0000/0000/0000/0000/0000/00FF/0001
  so paths are distinct from IPv4 based ones and easily recognisable
- greylistfourthbyte configuration setting is aliased to
grelistsingleipv4
  and made optional (resolves to false if not defined) to unify it with
  newly added settings
- two new optional configuration settings are defined:
  - greylistsingleipv6 - similar to greylistssingleipv4, if not
defined as true
    whole /64 subnet gets whitelisted
  - greylistsingleip - convenience option for setting both
greylistssingleipv[46] to true
- directory tree creation procedure is cleaned up by using mkpath
- new dependency introduced: netaddr-ip-perl, but as it is
dependency of spamassassin
  already, may be given as Suggests/Recommends only
- IPv4 validation is more strict (still not perfect...) so
additional regexp got dropped

What's left is documenting new options in README.greylisting.gz

Please review and apply if feasible or you may contact me if
something needs
to be improved or fixed.

regards,
  Robert Tasarz
diff --git a/Greylisting.pm b/Greylisting.pm
--- a/Greylisting.pm
+++ b/Greylisting.pm
@@ -21,6 +21,8 @@
 
 use strict;
 use Mail::SpamAssassin::Plugin;
+use NetAddr::IP::Util qw(ipv6_aton ipv6_n2x);
+use File::Path qw(mkpath);
 our @ISA = qw(Mail::SpamAssassin::Plugin);
 
 sub new 
@@ -71,7 +73,7 @@
     $self->{'rangreylisting'}=1;
 
     foreach my $reqoption (qw ( method greylistsecs dontgreylistthreshold
-       connectiphdr envfromhdr rcpttohdr greylistnullfrom greylistfourthbyte ))
+       connectiphdr envfromhdr rcpttohdr greylistnullfrom ))
     {
        die "Greylist option $reqoption missing from SA config" unless (defined $option{$reqoption});
     }
@@ -104,8 +106,19 @@
     }
     chomp($connectip);
     # Clean up input (for security, if you use files/dirs)
-    $connectip =~ /([\d.:]+)/;
-    $connectip = ($1 or "");
+
+    # Checking for valid IPv6 address
+    eval {
+       $connectip = ipv6_n2x ipv6_aton $connectip;
+    };
+    if (not $@) {
+       # Expanding ipv6 with leading zeroes so it is easier to visually differentiate it from ipv4
+       $connectip =~ s/([\da-f]+)/$|x(4-length($1)).$1/gie;
+    }
+    else {
+       $connectip =~ /^([\d.]+)$/;
+       $connectip = ($1 or "");
+    }
 
     # Account for a null envelope from
     if (not defined ($envfrom = $permsgstatus->get($option{'envfromhdr'})))
@@ -170,31 +183,23 @@
 
            die "greylist option dir not passed, even though method was set to dir" unless ($option{'dir'});
            
-           # connectip is supposed to be untainted now, but I was still getting
-           # some insecure dependecy error messages sometimes (perl 5.8 problem apparently)
-           unless ($connectip =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) {
-               warn "Can only handle IPv4 addresses; skipping greylisting call for message $mesgid\n";
+           if (not $connectip) {
+               warn "Can only handle IPv4 and IPv6 addresses; skipping greylisting call for message $mesgid\n";
                return 0;
            }
 
-           my $ipdir1 = "$option{'dir'}/$1";
-           my $ipdir2 = "$ipdir1/$2";
-           my $ipdir3 = "$ipdir2/$3";
-           my $ipdir4;
-           my $tupletdir;
+           my $ipdir = $connectip;
+           $ipdir = substr($ipdir, 0, 19) if not ($option{'greylistsingleipv6'} or $option{'greylistsingleip'});
+           $ipdir =~ s/\.\d+$// if not ($option{'greylistfourthbyte'} or $option{'greylistsingleipv4'} or $option{'greylistsingleip'});
 
-           $ipdir4 = "$ipdir3";
-           $ipdir4 .= "/$4" if ($option{'greylistfourthbyte'});
-           $tupletdir = "$ipdir4/$envfrom";
+           $ipdir =~ s/[:.]/\//g;
+
+           my $tupletdir = "$option{'dir'}/$ipdir/$envfrom";
 
            $tuplet = "$tupletdir/$rcptto";
 
            # make directory whether it's there or not (faster than test and set)
-           mkdir $ipdir1;
-           mkdir $ipdir2;
-           mkdir $ipdir3;
-           mkdir $ipdir4;
-           mkdir $tupletdir;
+           mkpath $tupletdir;
 
            if (not -e $tuplet) 
            {

Reply via email to