[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