Lines 42-48
Link Here
|
42 |
use Mail::SpamAssassin::Logger; |
42 |
use Mail::SpamAssassin::Logger; |
43 |
|
43 |
|
44 |
use IO::Socket::INET; |
44 |
use IO::Socket::INET; |
|
|
45 |
use Errno qw(EINVAL EADDRINUSE); |
45 |
|
46 |
|
|
|
47 |
use constant HAS_SOCKET_INET6 => eval { require IO::Socket::INET6 }; |
48 |
|
46 |
our @ISA = qw(); |
49 |
our @ISA = qw(); |
47 |
|
50 |
|
48 |
########################################################################### |
51 |
########################################################################### |
Lines 144-164
Link Here
|
144 |
|
147 |
|
145 |
$self->{sock}->close() if $self->{sock}; |
148 |
$self->{sock}->close() if $self->{sock}; |
146 |
my $sock; |
149 |
my $sock; |
|
|
150 |
my $errno; |
151 |
|
152 |
# IO::Socket::INET6 may choose wrong LocalAddr if family is unspecified, |
153 |
# causing EINVAL failure when automatically assigned local IP address |
154 |
# and remote address do not belong to the same address family: |
155 |
use Mail::SpamAssassin::Constants qw(:ip); |
156 |
my $ip64 = IP_ADDRESS; |
157 |
my $ip4 = IPV4_ADDRESS; |
158 |
my $ns = $self->{res}->{nameservers}[0]; |
159 |
|
160 |
# note: if the use of "AF_INET6" as a bare word here causes trouble |
161 |
# on your platform, just comment the line and replace with |
162 |
# "my $family = AF_INET;" instead |
163 |
my $family = (HAS_SOCKET_INET6 && $ns=~/^${ip64}$/o && $ns!~/^${ip4}$/o) |
164 |
? AF_INET6 : AF_INET; |
165 |
|
166 |
dbg("dns: name server: $ns, family: $family"); |
167 |
|
147 |
# find next available unprivileged port (1024 - 65535) |
168 |
# find next available unprivileged port (1024 - 65535) |
148 |
# starting at a random value to spread out use of ports |
169 |
# starting at a random value to spread out use of ports |
149 |
my $port_offset = int(rand(64511)); # 65535 - 1024 |
170 |
my $port_offset = int(rand(64511)); # 65535 - 1024 |
150 |
for (my $i = 0; (!$sock && ($i<64511)); $i++) { |
171 |
for (my $i = 0; $i<64511; $i++) { |
151 |
my $lport = 1024 + (($port_offset + $i) % 64511); |
172 |
my $lport = 1024 + (($port_offset + $i) % 64511); |
152 |
$sock = IO::Socket::INET->new ( |
173 |
|
153 |
Proto => 'udp', |
174 |
my %args = ( |
154 |
LocalPort => $lport, |
175 |
PeerAddr => $ns, |
155 |
Type => SOCK_DGRAM, |
176 |
PeerPort => $self->{res}->{port}, |
156 |
); |
177 |
Proto => 'udp', |
|
|
178 |
LocalPort => $lport, |
179 |
Type => SOCK_DGRAM, |
180 |
Domain => $family, |
181 |
); |
182 |
|
183 |
if (HAS_SOCKET_INET6) { |
184 |
$sock = IO::Socket::INET6->new(%args); |
185 |
} else { |
186 |
$sock = IO::Socket::INET->new(%args); |
187 |
} |
188 |
$errno = $!; |
189 |
if (defined $sock) { # ok, got it |
190 |
last; |
191 |
} elsif ($! == EADDRINUSE) { # in use, let's try another source port |
192 |
dbg("dns: UDP port $lport already in use, trying another port"); |
193 |
} else { |
194 |
# did we fail due to the attempted use of an IPv6 nameserver? |
195 |
$self->_ipv6_ns_warning() if !HAS_SOCKET_INET6 && $errno==EINVAL; |
196 |
die "Error creating a DNS resolver socket: $errno"; |
197 |
} |
157 |
} |
198 |
} |
|
|
199 |
defined $sock or die "Can't create a DNS resolver socket: $errno"; |
158 |
|
200 |
|
159 |
$self->{sock} = $sock; |
201 |
$self->{sock} = $sock; |
160 |
$self->{dest} = sockaddr_in($self->{res}->{port}, |
|
|
161 |
inet_aton($self->{res}->{nameservers}[0])); |
162 |
|
202 |
|
163 |
$self->{sock_as_vec} = $self->fhs_to_vec($self->{sock}); |
203 |
$self->{sock_as_vec} = $self->fhs_to_vec($self->{sock}); |
164 |
} |
204 |
} |
Lines 269-277
Link Here
|
269 |
my $pkt = $self->new_dns_packet($host, $type, $class); |
309 |
my $pkt = $self->new_dns_packet($host, $type, $class); |
270 |
|
310 |
|
271 |
my $data = $pkt->data; |
311 |
my $data = $pkt->data; |
272 |
my $dest = $self->{dest}; |
|
|
273 |
$self->connect_sock() if !$self->{sock}; |
312 |
$self->connect_sock() if !$self->{sock}; |
274 |
if (!$self->{sock}->send ($pkt->data, 0, $self->{dest})) { |
313 |
if (!$self->{sock}->send ($pkt->data, 0)) { |
275 |
warn "dns: sendto() failed: $@"; |
314 |
warn "dns: sendto() failed: $@"; |
276 |
return; |
315 |
return; |
277 |
} |
316 |
} |
Lines 427-432
Link Here
|
427 |
$self->connect_sock(); |
466 |
$self->connect_sock(); |
428 |
} |
467 |
} |
429 |
|
468 |
|
|
|
469 |
sub _ipv6_ns_warning { |
470 |
my ($self) = @_; |
471 |
|
472 |
# warn about the attempted use of an IPv6 nameserver without |
473 |
# IO::Socket::INET6 installed (bug 4412) |
474 |
my $firstns = $self->{res}->{nameservers}[0]; |
475 |
|
476 |
use Mail::SpamAssassin::Constants qw(:ip); |
477 |
my $ip64 = IP_ADDRESS; |
478 |
my $ip4 = IPV4_ADDRESS; |
479 |
|
480 |
# was the nameserver in IPv6 format? |
481 |
if ($firstns =~ /^${ip64}$/o && $firstns !~ /^${ip4}$/o) { |
482 |
my $addr = inet_aton($firstns); |
483 |
if (!defined $addr) { |
484 |
die "IO::Socket::INET6 module is required to use IPv6 nameservers such as '$firstns': $@\n"; |
485 |
} |
486 |
} |
487 |
} |
488 |
|
430 |
1; |
489 |
1; |
431 |
|
490 |
|
432 |
=back |
491 |
=back |