View | Details | Raw Unified | Return to bug 4412
Collapse All | Expand All

(-)INSTALL (+7 lines)
Lines 278-283 Link Here
278
    to install this module.
278
    to install this module.
279
279
280
280
281
  - IO::Socket::INET6 (from CPAN)
282
283
    This is required if the first nameserver listed in your IP
284
    configuration or /etc/resolv.conf file is available only via an IPv6
285
    address.
286
287
281
  - IO::Socket::SSL (from CPAN)
288
  - IO::Socket::SSL (from CPAN)
282
289
283
    If you wish to use SSL encryption to communicate between spamc and
290
    If you wish to use SSL encryption to communicate between spamc and
(-)lib/Mail/SpamAssassin/Util/DependencyInfo.pm (+7 lines)
Lines 109-114 Link Here
109
  to install this module.',
109
  to install this module.',
110
},
110
},
111
{
111
{
112
  module => 'IO::Socket::INET6',
113
  version => '0.00',
114
  desc => 'This is required if the first nameserver listed in your IP
115
  configuration or /etc/resolv.conf file is available only via
116
  an IPv6 address.',
117
},
118
{
112
  module => 'IO::Socket::SSL',
119
  module => 'IO::Socket::SSL',
113
  version => '0.00',
120
  version => '0.00',
114
  desc => 'If you wish to use SSL encryption to communicate between spamc and
121
  desc => 'If you wish to use SSL encryption to communicate between spamc and
(-)lib/Mail/SpamAssassin/DnsResolver.pm (-10 / +69 lines)
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

Return to bug 4412