Index: INSTALL =================================================================== --- INSTALL (revision 233103) +++ INSTALL (working copy) @@ -278,6 +278,13 @@ to install this module. + - IO::Socket::INET6 (from CPAN) + + This is required if the first nameserver listed in your IP + configuration or /etc/resolv.conf file is available only via an IPv6 + address. + + - IO::Socket::SSL (from CPAN) If you wish to use SSL encryption to communicate between spamc and Index: lib/Mail/SpamAssassin/Util/DependencyInfo.pm =================================================================== --- lib/Mail/SpamAssassin/Util/DependencyInfo.pm (revision 233103) +++ lib/Mail/SpamAssassin/Util/DependencyInfo.pm (working copy) @@ -109,6 +109,13 @@ to install this module.', }, { + module => 'IO::Socket::INET6', + version => '0.00', + desc => 'This is required if the first nameserver listed in your IP + configuration or /etc/resolv.conf file is available only via + an IPv6 address.', +}, +{ module => 'IO::Socket::SSL', version => '0.00', desc => 'If you wish to use SSL encryption to communicate between spamc and Index: lib/Mail/SpamAssassin/DnsResolver.pm =================================================================== --- lib/Mail/SpamAssassin/DnsResolver.pm (revision 233103) +++ lib/Mail/SpamAssassin/DnsResolver.pm (working copy) @@ -43,6 +43,8 @@ use IO::Socket::INET; +use constant HAS_SOCKET_INET6 => eval { require IO::Socket::INET6 }; + our @ISA = qw(); ########################################################################### @@ -149,16 +151,28 @@ my $port_offset = int(rand(64511)); # 65535 - 1024 for (my $i = 0; (!$sock && ($i<64511)); $i++) { my $lport = 1024 + (($port_offset + $i) % 64511); - $sock = IO::Socket::INET->new ( - Proto => 'udp', - LocalPort => $lport, - Type => SOCK_DGRAM, - ); + + my %args = ( + PeerAddr => $self->{res}->{nameservers}[0], + PeerPort => $self->{res}->{port}, + Proto => 'udp', + LocalPort => $lport, + Type => SOCK_DGRAM + ); + + if (HAS_SOCKET_INET6) { + $sock = IO::Socket::INET6->new(%args); + } else { + $sock = IO::Socket::INET->new(%args); + + # did we fail due to the attempted use of an IPv6 nameserver? + if (!$sock) { + $self->_ipv6_ns_warning(); + } + } } $self->{sock} = $sock; - $self->{dest} = sockaddr_in($self->{res}->{port}, - inet_aton($self->{res}->{nameservers}[0])); $self->{sock_as_vec} = $self->fhs_to_vec($self->{sock}); } @@ -268,9 +282,8 @@ my $pkt = $self->new_dns_packet($host, $type, $class); my $data = $pkt->data; - my $dest = $self->{dest}; $self->connect_sock() if !$self->{sock}; - if (!$self->{sock}->send ($pkt->data, 0, $self->{dest})) { + if (!$self->{sock}->send ($pkt->data, 0)) { warn "dns: sendto() failed: $@"; return; } @@ -426,6 +439,26 @@ $self->connect_sock(); } +sub _ipv6_ns_warning { + my ($self) = @_; + + # warn about the attempted use of an IPv6 nameserver without + # IO::Socket::INET6 installed (bug 4412) + my $firstns = $self->{res}->{nameservers}[0]; + + use Mail::SpamAssassin::Constants qw(:ip); + my $ip64 = IP_ADDRESS; + my $ip4 = IPV4_ADDRESS; + + # was the nameserver in IPv6 format? + if ($firstns =~ /^${ip64}$/o && $firstns !~ /^${ip4}$/o) { + my $addr = inet_aton($firstns); + if (!defined $addr) { + die "IO::Socket::INET6 module is required to use IPv6 nameservers such as '$firstns': $@\n"; + } + } +} + 1; =back