You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by jm...@apache.org on 2006/06/29 20:10:22 UTC

svn commit: r418104 - /spamassassin/trunk/spamd/spamd.raw

Author: jm
Date: Thu Jun 29 11:10:22 2006
New Revision: 418104

URL: http://svn.apache.org/viewvc?rev=418104&view=rev
Log:
bug 4956: IPv6 support in spamd, thanks to Radoslaw Zielinski

Modified:
    spamassassin/trunk/spamd/spamd.raw

Modified: spamassassin/trunk/spamd/spamd.raw
URL: http://svn.apache.org/viewvc/spamassassin/trunk/spamd/spamd.raw?rev=418104&r1=418103&r2=418104&view=diff
==============================================================================
--- spamassassin/trunk/spamd/spamd.raw (original)
+++ spamassassin/trunk/spamd/spamd.raw Thu Jun 29 11:10:22 2006
@@ -33,7 +33,50 @@
 use strict;
 use warnings;
 
-use IO::Socket;
+# Big Ugly Hack; purpose: don't force requirement on IO::Socket::INET6
+BEGIN {
+  use Socket;
+  eval {
+    require IO::Socket::INET6;
+    require Socket6;
+  };
+  if ($@) {    # IPv4 only
+    *new_io_socket_inetx = sub { IO::Socket::INET->new(@_); };
+    *ip_or_name_to_ip    = sub {
+      my $in_addr = (gethostbyname(shift))[4] or return undef;
+      Socket::inet_ntoa($in_addr);
+    };
+    *peer_info_from_socket = sub {
+      my $sock = shift;
+      my ($port, $in_addr) = Socket::sockaddr_in($sock->peername)
+        or return;
+      my $addr = Socket::inet_ntoa($in_addr) or return;
+      my $host = gethostbyaddr($in_addr, Socket::AF_INET()) || $addr;
+      return ($port, $addr, $host);
+    };
+  }
+  else {    # IPv4+IPv6
+    *new_io_socket_inetx = sub { IO::Socket::INET6->new(@_); };
+    *ip_or_name_to_ip    = sub {
+      my $addr = (
+        Socket6::getaddrinfo(
+          shift, '', Socket::AF_UNSPEC(), Socket::SOCK_STREAM()
+        )
+        )[3]
+        or return undef;
+      $addr = (Socket6::getnameinfo($addr, Socket6::NI_NUMERICHOST()))[0];
+    };
+    *peer_info_from_socket = sub {
+      my $sock = shift;
+      my $addr = $sock->peerhost or return;
+      my $host =
+        (Socket6::getnameinfo($sock->peername, Socket6::NI_NAMEREQD()))[0]
+        || $addr;
+      return ($sock->peerport(), $addr, $host);
+    };
+  }
+}
+
 use IO::Handle;
 use IO::Pipe;
 
@@ -296,10 +339,10 @@
 my $allowed_nets = Mail::SpamAssassin::NetSet->new();
 if ( not defined $opt{'socketpath'} ) {
   if ( @{ $opt{'allowed-ip'} } ) {
-    set_allowed_ip( split /,/, join ( ',', @{ $opt{'allowed-ip'} } ) );
+    set_allowed_ip( grep length, map { split /,/ } @{ $opt{'allowed-ip'} } );
   }
   else {
-    set_allowed_ip('127.0.0.1');
+    set_allowed_ip('127.0.0.1'); #, '::1'); M::SA::NetSet needs fixing for IPv6
   }
 }
 
@@ -510,17 +553,16 @@
   $listeninfo = "UNIX domain socket " . $opt{'socketpath'};
 }
 else {
-  $proto = getprotobyname('tcp');
+  $proto = getprotobyname('tcp') or die "getprotobyname(tcp): $!";
 
   $addr = $opt{'listen-ip'};
   if (defined $addr) {
     if ($addr ne '') {
-      $addr = ( gethostbyname($addr) )[4];
+      $addr = ip_or_name_to_ip($addr);
       die "spamd: invalid address: $opt{'listen-ip'}\n" unless $addr;
-      $addr = inet_ntoa($addr);
     }
     else {
-      $addr = '0.0.0.0';
+      $addr = '0.0.0.0';    # FIXME: this won't bind to IPv6 sockets
     }
   }
   else {
@@ -673,7 +715,7 @@
     Listen    => SOMAXCONN
   );
   dbg("spamd: creating INET socket:\n" . join("\n", map { " $_: " . (defined $socket{$_} ? $socket{$_} : "(undef)") } sort keys %socket));
-  $server = new IO::Socket::INET(%socket)
+  $server = new_io_socket_inetx(%socket)
          || die "spamd: could not create INET socket on $addr:$port: $!\n";
 }
 
@@ -1005,8 +1047,7 @@
   # keep track of start time
   my $start = time;
 
-  my $remote_hostname;
-  my $remote_hostaddr;
+  my ($remote_hostname, $remote_hostaddr);
   if ($opt{'socketpath'}) {
     $remote_hostname = 'localhost';
     $remote_hostaddr = '127.0.0.1';
@@ -1014,14 +1055,11 @@
     info("spamd: got connection over " . $opt{'socketpath'});
   }
   else {
-    my ( $port, $ip ) = sockaddr_in( $client->peername );
-    
-    $remote_hostaddr = inet_ntoa($ip);
-    $remote_hostname = gethostbyaddr($ip, AF_INET)
-                    || $remote_hostaddr;
-    $remote_port = $port;
+    ($remote_port, $remote_hostaddr, $remote_hostname) =
+      peer_info_from_socket($client)
+      or die 'failed to obtain port and ip from socket';
 
-    my $msg = "connection from ${remote_hostname} [${remote_hostaddr}] at port ${port}";
+    my $msg = "connection from ${remote_hostname} [${remote_hostaddr}] at port ${remote_port}";
     if (ip_is_allowed($remote_hostaddr)) {
       info("spamd: $msg");
     }