[Mimedefang] [Patch] relay_is_* not ipv6 friendly

Michiel Brandenburg apex at xepa.nl
Mon Feb 1 15:26:24 EST 2010


Hiya all,

I recently noticed the relay_is_* functions within mimdefang.pl do not 
playing nice with ipv6 addresses.  This patch fixes it.  Not that a lot 
of mail is running ipv6 over here but there is always hope :)

--
Michiel Brandenburg
-------------- next part --------------
--- mimedefang.pl.original	2010-01-31 23:10:14.000000000 +0100
+++ mimedefang.pl	2010-02-01 01:58:43.000000000 +0100
@@ -1487,6 +1487,104 @@ sub action_notify_administrator ($) {
 }
 
 #***********************************************************************
+# %PROCEDURE: ip_expand_address
+# %ARGUMENTS:
+#  ip -- IPv6 / IPv4 address.
+#  ip_version -- what kind of ip is it ? 4 or 6
+#  pad -- pad fully optional 1 or 0 (only for ip 6) defaul 0
+# %RETURNS:
+#  the fully expanded version of ipv6
+# %EXAMPLE:
+#   2001:888:1f59::1:7d,6   => 2001:888:1f59:0:0:0:1:7d
+#   2001:888:1f59::1:7d,6,1 => 2001:0888:1f59:0000:0000:0000:0001:007d
+#   ::ffff:192.168.89.9,6	=> 0:0:0:0:0:ffff:c0a8:5909
+#***********************************************************************
+# taken from Net::IP, and converted to use no external, and handle no padding
+sub ip_expand_address
+{
+    my $ip = shift;
+    my $ip_version = shift;
+    my $pad = shift || 0;
+    
+    unless( $ip_version ) {
+        return $ip;
+    }
+    
+    # v4 : add .0 for missing quads
+    if ($ip_version == 4) {
+        my @quads = split /\./, $ip;
+        my @clean_quads = (0, 0, 0, 0);
+        foreach my $q (reverse @quads) {
+            unshift(@clean_quads, $q + 1 - 1);
+        }
+        return (join '.', @clean_quads[ 0 .. 3 ]);
+    }
+    
+    # reuse our pad var.
+    if ( $pad ) { $pad = 4;    }
+    else { $pad = 1; }
+    
+    # tag ::
+    $ip =~ s/::/:!:/;
+    my @ip = split(/:/,$ip);
+    my $num = scalar(@ip) - 1;
+    foreach( 0 .. (scalar(@ip) -1 )) {
+        if( $ip[$_] =~ /\./ ) {
+            # ipv4 mapped as ipv6
+            my @extraOcts = unpack('H4H4', pack('C4C4C4C4', split(/\./, ip_expand_address($ip[$_], 4))));
+            # remove leading 0's if not padding to 4
+            if ( $pad eq 1 ) {
+                $extraOcts[0] =~ s/^0*(.+)$/$1/;
+                $extraOcts[1] =~ s/^0*(.+)$/$1/;
+            }
+            $ip[$_] = join(':', @extraOcts);
+            # converting creates one more octet increase to compensate
+            $num++;
+            next();
+        }
+        $ip[$_] = ('0' x ($pad - length($ip[$_]))) . $ip[$_];
+    }
+    $ip = join(':', @ip);
+    # handle the :: (now converted to 000! or stayed !)
+    my $search =  '0' x ($pad - 1) . '!:';
+    my $missing = ( ('0' x $pad . ':') x (8 - $num));
+    $ip =~ s/$search/$missing/;
+    return $ip;
+}
+
+#***********************************************************************
+# %PROCEDURE: reverse_addr
+# %ARGUMENTS:
+#  addr -- IPv4 / IPv6 Address
+# %RETURNS:
+#  the fully expanded reverse of addr suitable for rbl lookups
+# %EXAMPLE:
+#   2001:888:1f59::1:7d => 
+#    6.2.4.1.0.2.e.f.f.f.1.2.3.1.2.0.b.e.d.0.2.0.2.0.8.b.1.4.1.0.0.2
+#   127.0.0.1 => 1.0.0.127
+#***********************************************************************
+sub reverse_addr
+{
+    my ($addr) = @_;
+    my $type = 4;
+    if ( $Features{"Net::DNS"} && Net::DNS::Resolver::Base::_ip_is_ipv6($addr) ) {
+    	$type = 6;
+    }
+    elsif ( !$Features{"Net::DNS"} && $addr =~ /:/) {
+    	# no Net::DNS available guessed instead
+        $type = 6;
+    }
+    if ( $type eq 6 ) {
+        $addr = ip_expand_address($addr, 6, 1);
+        $addr =~ s/://g;
+        return join('.', split(//, reverse($addr)));
+    }
+    # ipv4 
+    my($a, $b, $c, $d) = split(/\./, $addr);
+    return "$d.$c.$b.$a";
+}
+
+#***********************************************************************
 # %PROCEDURE: relay_is_blacklisted
 # %ARGUMENTS:
 #  addr -- IP address of relay host.
@@ -1497,8 +1595,7 @@ sub action_notify_administrator ($) {
 sub relay_is_blacklisted ($$) {
     my($addr, $domain) = @_;
     # Reverse IP address
-    my($a, $b, $c, $d) = split(/\./, $addr);
-    $addr = "$d.$c.$b.$a.$domain";
+    $addr = reverse_addr( $addr ) . ".$domain";
     my $hn;
     $hn = gethostbyname($addr);
     return 0 unless defined($hn);
@@ -1543,8 +1640,7 @@ sub relay_is_blacklisted_multi ($$$$;$) 
     my %sock_to_domain;
 
     # Reverse the address
-    my($a, $b, $c, $d) = split(/\./, $addr);
-    $addr = "$d.$c.$b.$a";
+    $addr = reverse_addr($addr);
 
     # If user did not pass in a Net::DNS::Resolver object, generate one.
     unless (defined($res and (UNIVERSAL::isa($res, "Net::DNS::Resolver")))) {


More information about the MIMEDefang mailing list