|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # <@LICENSE>  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Licensed to the Apache Software Foundation (ASF) under one or more  | 
| 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # contributor license agreements.  See the NOTICE file distributed with  | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # this work for additional information regarding copyright ownership.  | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # The ASF licenses this file to you under the Apache License, Version 2.0  | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # (the "License"); you may not use this file except in compliance with  | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # the License.  You may obtain a copy of the License at:  | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #   | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #     http://www.apache.org/licenses/LICENSE-2.0  | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #   | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Unless required by applicable law or agreed to in writing, software  | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # distributed under the License is distributed on an "AS IS" BASIS,  | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # See the License for the specific language governing permissions and  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # limitations under the License.  | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # </@LICENSE>  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 NAME  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Mail::SpamAssassin::DnsResolver - DNS resolution engine  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 DESCRIPTION  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This is a DNS resolution engine for SpamAssassin, implemented in order to  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 reduce file descriptor usage by Net::DNS and avoid a response collision bug in  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 that module.  | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 METHODS  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =over 4  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # TODO: caching in this layer instead of in callers.  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Mail::SpamAssassin::DnsResolver;  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
38
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
291
 | 
 use strict;  | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
113
 | 
    | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1183
 | 
    | 
| 
39
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
250
 | 
 use warnings;  | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
107
 | 
    | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1227
 | 
    | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # use bytes;  | 
| 
41
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
221
 | 
 use re 'taint';  | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
98
 | 
    | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1671
 | 
    | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 require 5.008001;  # needs utf8::is_utf8()  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
45
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
268
 | 
 use Mail::SpamAssassin;  | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
111
 | 
    | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1019
 | 
    | 
| 
46
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
325
 | 
 use Mail::SpamAssassin::Logger;  | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
136
 | 
    | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2565
 | 
    | 
| 
47
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
307
 | 
 use Mail::SpamAssassin::Constants qw(:ip);  | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
117
 | 
    | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5045
 | 
    | 
| 
48
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
360
 | 
 use Mail::SpamAssassin::Util qw(untaint_var decode_dns_question_entry);  | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
137
 | 
    | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2902
 | 
    | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
50
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
301
 | 
 use Socket;  | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
94
 | 
    | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33757
 | 
    | 
| 
51
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
341
 | 
 use Errno qw(EADDRINUSE EACCES);  | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
105
 | 
    | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3218
 | 
    | 
| 
52
 | 
40
 | 
 
 | 
 
 | 
  
40
  
 | 
 
 | 
317
 | 
 use Time::HiRes qw(time);  | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
101
 | 
    | 
| 
 
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
733
 | 
    | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our @ISA = qw();  | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $io_socket_module_name;  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 BEGIN {  | 
| 
58
 | 
40
 | 
  
 50
  
 | 
 
 | 
  
40
  
 | 
 
 | 
11736
 | 
   if (eval { require IO::Socket::IP }) {  | 
| 
 
 | 
40
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
520
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
59
 | 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
210813
 | 
     $io_socket_module_name = 'IO::Socket::IP';  | 
| 
60
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   } elsif (eval { require IO::Socket::INET6 }) {  | 
| 
61
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $io_socket_module_name = 'IO::Socket::INET6';  | 
| 
62
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   } elsif (eval { require IO::Socket::INET }) {  | 
| 
63
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $io_socket_module_name = 'IO::Socket::INET';  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ###########################################################################  | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub new {  | 
| 
70
 | 
90
 | 
 
 | 
 
 | 
  
90
  
 | 
  
0
  
 | 
298
 | 
   my $class = shift;  | 
| 
71
 | 
90
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
674
 | 
   $class = ref($class) || $class;  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
73
 | 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
250
 | 
   my ($main) = @_;  | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $self = {  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'main'              => $main,  | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'conf'		=> $main->{conf},  | 
| 
77
 | 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
666
 | 
     'id_to_callback'    => { },  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   };  | 
| 
79
 | 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
331
 | 
   bless ($self, $class);  | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
81
 | 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
576
 | 
   $self->load_resolver();  | 
| 
82
 | 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
780
 | 
   $self;  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ###########################################################################  | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $res->load_resolver()  | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Load the C<Net::DNS::Resolver> object.  Returns 0 if Net::DNS cannot be used,  | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1 if it is available.  | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub load_resolver {  | 
| 
95
 | 
91
 | 
 
 | 
 
 | 
  
91
  
 | 
  
1
  
 | 
262
 | 
   my ($self) = @_;  | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
97
 | 
91
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
510
 | 
   if ($self->{res}) { return 1; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
98
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
383
 | 
   $self->{no_resolver} = 1;  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # force only ipv4 if no IO::Socket::INET6 or ipv6 doesn't work  | 
| 
101
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
277
 | 
   my $force_ipv4 = $self->{main}->{force_ipv4};  | 
| 
102
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
232
 | 
   my $force_ipv6 = $self->{main}->{force_ipv6};  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
104
 | 
91
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
803
 | 
   if (!$force_ipv4 && $io_socket_module_name eq 'IO::Socket::INET') {  | 
| 
105
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     dbg("dns: socket module for IPv6 support not available");  | 
| 
106
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     die "Use of IPv6 requested, but not available\n"  if $force_ipv6;  | 
| 
107
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $force_ipv4 = 1; $force_ipv6 = 0;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
109
 | 
91
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
331
 | 
   if (!$force_ipv4) {  # test drive IPv6  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     eval {  | 
| 
111
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
177
 | 
       my $sock6;  | 
| 
112
 | 
91
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
290
 | 
       if ($io_socket_module_name) {  | 
| 
113
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1693
 | 
         $sock6 = $io_socket_module_name->new(LocalAddr=>'::', Proto=>'udp');  | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
115
 | 
91
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
60563
 | 
       if ($sock6) { $sock6->close() or warn "error closing socket: $!" }  | 
| 
 
 | 
  
0
  
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
116
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
526
 | 
       $sock6;  | 
| 
117
 | 
91
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
188
 | 
     } or do {  | 
| 
118
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
451
 | 
       dbg("dns: socket module %s is available, but no host support for IPv6",  | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           $io_socket_module_name);  | 
| 
120
 | 
91
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
293
 | 
       die "Use of IPv6 requested, but not available\n"  if $force_ipv6;  | 
| 
121
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
199
 | 
       $force_ipv4 = 1; $force_ipv6 = 0;  | 
| 
 
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
218
 | 
    | 
| 
122
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   eval {  | 
| 
126
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
954
 | 
     require Net::DNS;  | 
| 
127
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # force_v4 is set in new() to avoid error in older versions of Net::DNS  | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # that don't have it; other options are set by function calls so a typo  | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # or API change will cause an error here  | 
| 
130
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2025
 | 
     my $res = $self->{res} = Net::DNS::Resolver->new(force_v4 => $force_ipv4);  | 
| 
131
 | 
91
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
28955
 | 
     if ($res) {  | 
| 
132
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
258
 | 
       $self->{no_resolver} = 0;  | 
| 
133
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
730
 | 
       $self->{force_ipv4} = $force_ipv4;  | 
| 
134
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
342
 | 
       $self->{force_ipv6} = $force_ipv6;  | 
| 
135
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
328
 | 
       $self->{retry} = 1;       # retries for non-backgrounded query  | 
| 
136
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
259
 | 
       $self->{retrans} = 3;     # initial timeout for "non-backgrounded"  | 
| 
137
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 #   query run in background  | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
139
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1071
 | 
       $res->retry(1);           # If it fails, it fails  | 
| 
140
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3108
 | 
       $res->retrans(0);         # If it fails, it fails  | 
| 
141
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1779
 | 
       $res->dnsrch(0);          # ignore domain search-list  | 
| 
142
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1570
 | 
       $res->defnames(0);        # don't append stuff to end of query  | 
| 
143
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1662
 | 
       $res->tcp_timeout(3);     # timeout of 3 seconds only  | 
| 
144
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1530
 | 
       $res->udp_timeout(3);     # timeout of 3 seconds only  | 
| 
145
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1560
 | 
       $res->persistent_tcp(0);  # bug 3997  | 
| 
146
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1739
 | 
       $res->persistent_udp(0);  # bug 3997  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # RFC 6891 (ex RFC 2671): EDNS0, value is a requestor's UDP payload size  | 
| 
149
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1369
 | 
       my $edns = $self->{conf}->{dns_options}->{edns};  | 
| 
150
 | 
91
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
849
 | 
       if ($edns && $edns > 512) {  | 
| 
151
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
644
 | 
         $res->udppacketsize($edns);  | 
| 
152
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1647
 | 
         dbg("dns: EDNS, UDP payload size %d", $edns);  | 
| 
153
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
155
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # set $res->nameservers for the benefit of plugins which don't use  | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # our send/bgsend infrastructure but rely on Net::DNS::Resolver entirely  | 
| 
157
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
656
 | 
       my @ns_addr_port = $self->available_nameservers();  | 
| 
158
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
311
 | 
       local($1,$2);  | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # drop port numbers, Net::DNS::Resolver can't take them  | 
| 
160
 | 
91
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1218
 | 
       @ns_addr_port = map(/^\[(.*)\]:(\d+)\z/ ? $1 : $_, @ns_addr_port);  | 
| 
161
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
569
 | 
       dbg("dns: nameservers set to %s", join(', ', @ns_addr_port));  | 
| 
162
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
405
 | 
       $res->nameservers(@ns_addr_port);  | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
164
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8942
 | 
     1;  | 
| 
165
 | 
91
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
202
 | 
   } or do {  | 
| 
166
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $eval_stat = $@ ne '' ? $@ : "errno=$!";  chomp $eval_stat;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
167
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     dbg("dns: eval failed: $eval_stat");  | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   };  | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   dbg("dns: using socket module: %s version %s%s",  | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       $io_socket_module_name,  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       $io_socket_module_name->VERSION,  | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       $self->{force_ipv4} ? ', forced IPv4' :  | 
| 
174
 | 
91
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
2347
 | 
       $self->{force_ipv6} ? ', forced IPv6' : '');  | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
175
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   dbg("dns: is Net::DNS::Resolver available? %s",  | 
| 
176
 | 
91
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
629
 | 
       $self->{no_resolver} ? "no" : "yes" );  | 
| 
177
 | 
91
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
771
 | 
   if (!$self->{no_resolver} && defined $Net::DNS::VERSION) {  | 
| 
178
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
422
 | 
     dbg("dns: Net::DNS version: %s", $Net::DNS::VERSION);  | 
| 
179
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
180
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
181
 | 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
262
 | 
   return (!$self->{no_resolver});  | 
| 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
184
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $resolver = $res->get_resolver()  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
186
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Return the C<Net::DNS::Resolver> object.  | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
188
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get_resolver {  | 
| 
191
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
  
1
  
 | 
13
 | 
   my ($self) = @_;  | 
| 
192
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
   return $self->{res};  | 
| 
193
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
194
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
195
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $res->configured_nameservers()  | 
| 
196
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
197
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Get a list of nameservers as configured by dns_server directives  | 
| 
198
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 or as provided by Net::DNS, typically from /etc/resolv.conf  | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub configured_nameservers {  | 
| 
203
 | 
90
 | 
 
 | 
 
 | 
  
90
  
 | 
  
1
  
 | 
254
 | 
   my $self = shift;  | 
| 
204
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
205
 | 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
224
 | 
   my $res = $self->{res};  | 
| 
206
 | 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
178
 | 
   my @ns_addr_port;  # list of name servers: [addr]:port entries  | 
| 
207
 | 
90
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
500
 | 
   if ($self->{conf}->{dns_servers}) {  # specified in a config file  | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
208
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     @ns_addr_port = @{$self->{conf}->{dns_servers}};  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
209
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     dbg("dns: servers set by config to: %s", join(', ',@ns_addr_port));  | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } elsif ($res) {  # default as provided by Net::DNS, e.g. /etc/resolv.conf  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my @ns = $res->UNIVERSAL::can('nameservers') ? $res->nameservers  | 
| 
212
 | 
89
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1201
 | 
                                                  : @{$res->{nameservers}};  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
213
 | 
89
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
3931
 | 
     my $port = $res->UNIVERSAL::can('port') ? $res->port : $res->{port};  | 
| 
214
 | 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
985
 | 
     @ns_addr_port = map(untaint_var("[$_]:" . $port), @ns);  | 
| 
215
 | 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
498
 | 
     dbg("dns: servers obtained from Net::DNS : %s", join(', ',@ns_addr_port));  | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
217
 | 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
592
 | 
   return @ns_addr_port;  | 
| 
218
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $res->available_nameservers()  | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
222
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Get or set a list of currently available nameservers,  | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 which is typically a known-to-be-good subset of configured nameservers  | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
226
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub available_nameservers {  | 
| 
228
 | 
114
 | 
 
 | 
 
 | 
  
114
  
 | 
  
1
  
 | 
301
 | 
   my $self = shift;  | 
| 
229
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
230
 | 
114
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
593
 | 
   if (@_) {  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
231
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $self->{available_dns_servers} = [ @_ ];  # copy  | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     dbg("dns: servers set by a caller to: %s",  | 
| 
233
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
          join(', ',@{$self->{available_dns_servers}}));  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } elsif (!$self->{available_dns_servers}) {  | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # a list of configured name servers: [addr]:port entries  | 
| 
236
 | 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
419
 | 
     $self->{available_dns_servers} = [ $self->configured_nameservers() ];  | 
| 
237
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
238
 | 
114
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
563
 | 
   if ($self->{force_ipv4} || $self->{force_ipv6}) {  | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # filter the list according to a chosen protocol family  | 
| 
240
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
281
 | 
     my $ip4_re = IPV4_ADDRESS;  | 
| 
241
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
215
 | 
     my(@filtered_addr_port);  | 
| 
242
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
214
 | 
     for (@{$self->{available_dns_servers}}) {  | 
| 
 
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
435
 | 
    | 
| 
243
 | 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
561
 | 
       local($1,$2);  | 
| 
244
 | 
203
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1315
 | 
       /^ \[ (.*) \] : (\d+) \z/xs  or next;  | 
| 
245
 | 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
816
 | 
       my($addr,$port) = ($1,$2);  | 
| 
246
 | 
203
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
3070
 | 
       if ($addr =~ /^${ip4_re}\z/o) {  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
247
 | 
203
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1310
 | 
         push(@filtered_addr_port, $_)  unless $self->{force_ipv6};  | 
| 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       } elsif ($addr =~ /:.*:/) {  | 
| 
249
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         push(@filtered_addr_port, $_)  unless $self->{force_ipv4};  | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       } else {  | 
| 
251
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         warn "Unrecognized DNS server specification: $_";  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
254
 | 
114
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
272
 | 
     if (@filtered_addr_port < @{$self->{available_dns_servers}}) {  | 
| 
 
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
438
 | 
    | 
| 
255
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       dbg("dns: filtered DNS servers according to protocol family: %s",  | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           join(", ",@filtered_addr_port));  | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
258
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
254
 | 
     @{$self->{available_dns_servers}} = @filtered_addr_port;  | 
| 
 
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
421
 | 
    | 
| 
259
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
260
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   die "available_nameservers: No DNS servers available!\n"  | 
| 
261
 | 
114
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
211
 | 
     if !@{$self->{available_dns_servers}};  | 
| 
 
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
514
 | 
    | 
| 
262
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
215
 | 
   return @{$self->{available_dns_servers}};  | 
| 
 
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
433
 | 
    | 
| 
263
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
264
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub disable_available_port {  | 
| 
266
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
   my($self, $lport) = @_;  | 
| 
267
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
   if ($lport >= 0 && $lport <= 65535) {  | 
| 
268
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $conf = $self->{conf};  | 
| 
269
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     if (!defined $conf->{dns_available_portscount}) {  | 
| 
270
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $self->pick_random_available_port();  # initialize  | 
| 
271
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
272
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     if (vec($conf->{dns_available_ports_bitset}, $lport, 1)) {  | 
| 
273
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       dbg("dns: disabling local port %d", $lport);  | 
| 
274
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       vec($conf->{dns_available_ports_bitset}, $lport, 1) = 0;  | 
| 
275
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $conf->{dns_available_portscount_buckets}->[$lport >> 8] --;  | 
| 
276
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $conf->{dns_available_portscount} --;  | 
| 
277
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
279
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
280
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
281
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub pick_random_available_port {  | 
| 
282
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
0
  
 | 
5
 | 
   my $self = shift;  | 
| 
283
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
   my $port_number;  # resulting port number, or undef if none available  | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
285
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
   my $conf = $self->{conf};  | 
| 
286
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
   my $available_portscount = $conf->{dns_available_portscount};  | 
| 
287
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
288
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # initialize when called for the first time or after a config change  | 
| 
289
 | 
2
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
9
 | 
   if (!defined $available_portscount) {  | 
| 
290
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $ports_bitset = $conf->{dns_available_ports_bitset};  | 
| 
291
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     if (!defined $ports_bitset) {  # ensure it is initialized  | 
| 
292
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
       Mail::SpamAssassin::Conf::set_ports_range(\$ports_bitset, 0, 0, 0);  | 
| 
293
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
       $conf->{dns_available_ports_bitset} = $ports_bitset;  | 
| 
294
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
295
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # prepare auxiliary data structure to speed up further free-port lookups;  | 
| 
296
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # 256 buckets, each accounting for 256 ports: 8+8 = 16 bit port numbers;  | 
| 
297
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # each bucket holds a count of available ports in its range  | 
| 
298
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
     my @bucket_counts = (0) x 256;  | 
| 
299
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $all_zeroes = "\000" x 32;  # one bucket's worth (256) of zeroes  | 
| 
300
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $all_ones   = "\377" x 32;  # one bucket's worth (256) of ones  | 
| 
301
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $ind = 0;  | 
| 
302
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     $available_portscount = 0;  # number of all available ports  | 
| 
303
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
     foreach my $bucket (0..255) {  | 
| 
304
 | 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
278
 | 
       my $cnt = 0;  | 
| 
305
 | 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
352
 | 
       my $b = substr($ports_bitset, $bucket*32, 32);  # one bucket: 256 bits  | 
| 
306
 | 
256
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
483
 | 
       if  ($b eq $all_zeroes) { $ind += 256 }  | 
| 
 
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
307
 | 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
297
 | 
       elsif ($b eq $all_ones) { $ind += 256; $cnt += 256 }  | 
| 
 
 | 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
274
 | 
    | 
| 
308
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       else {  # count nontrivial cases the slow way  | 
| 
309
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
         vec($ports_bitset, $ind++, 1) && $cnt++  for 0..255;  | 
| 
310
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
311
 | 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
285
 | 
       $available_portscount += $cnt;  | 
| 
312
 | 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
405
 | 
       $bucket_counts[$bucket] = $cnt;  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
314
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     $conf->{dns_available_portscount} = $available_portscount;  | 
| 
315
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
13
 | 
     if ($available_portscount) {  | 
| 
316
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
       $conf->{dns_available_portscount_buckets} = \@bucket_counts;  | 
| 
317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  # save some storage  | 
| 
318
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $conf->{dns_available_portscount_buckets} = undef;  | 
| 
319
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $conf->{dns_available_ports_bitset} = '';  | 
| 
320
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
321
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
323
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # find the n-th port number from the ordered set of available port numbers  | 
| 
324
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
   dbg("dns: %d configured local ports for DNS queries", $available_portscount);  | 
| 
325
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
8
 | 
   if ($available_portscount > 0) {  | 
| 
326
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     my $ports_bitset = $conf->{dns_available_ports_bitset};  | 
| 
327
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     my $n = int(rand($available_portscount));  | 
| 
328
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $bucket_counts_ref = $conf->{dns_available_portscount_buckets};  | 
| 
329
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $ind = 0;  | 
| 
330
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     foreach my $bucket (0..255) {  | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # find the bucket containing n-th turned-on bit  | 
| 
332
 | 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
86
 | 
       my $cnt = $bucket_counts_ref->[$bucket];  | 
| 
333
 | 
65
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
88
 | 
       if ($cnt > $n) { last } else { $n -= $cnt; $ind += 256 }  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
    | 
| 
 
 | 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
69
 | 
    | 
| 
 
 | 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
98
 | 
    | 
| 
334
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
335
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
     while ($ind <= 65535) {  # scans one bucket, runs at most 256 iterations  | 
| 
336
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # find the n-th turned-on bit within the corresponding bucket  | 
| 
337
 | 
320
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
502
 | 
       if (vec($ports_bitset, $ind, 1)) {  | 
| 
338
 | 
320
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
446
 | 
         if ($n <= 0) { $port_number = $ind; last } else { $n-- }  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
 
 | 
318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
377
 | 
    | 
| 
339
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
340
 | 
318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
497
 | 
       $ind++;  | 
| 
341
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
342
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
343
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
   return $port_number;  | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
345
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $res->connect_sock()  | 
| 
347
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
348
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Re-connect to the first nameserver listed in C</etc/resolv.conf> or similar  | 
| 
349
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 platform-dependent source, as provided by C<Net::DNS>.  | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
351
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
353
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub connect_sock {  | 
| 
354
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
5
 | 
   my ($self) = @_;  | 
| 
355
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
356
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
12
 | 
   dbg("dns: connect_sock, resolver: %s", $self->{no_resolver} ? "no" : "yes");  | 
| 
357
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
7
 | 
   return if $self->{no_resolver};  | 
| 
358
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
359
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
12
 | 
   $io_socket_module_name  | 
| 
360
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     or die "No Perl modules for network socket available";  | 
| 
361
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
362
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
8
 | 
   if ($self->{sock}) {  | 
| 
363
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $self->{sock}->close()  | 
| 
364
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       or info("connect_sock: error closing socket %s: %s", $self->{sock}, $!);  | 
| 
365
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $self->{sock} = undef;  | 
| 
366
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
367
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
   my $sock;  | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $errno;  | 
| 
369
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
370
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # list of name servers: [addr]:port entries  | 
| 
371
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
   my @ns_addr_port = $self->available_nameservers();  | 
| 
372
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # use the first name server in a list  | 
| 
373
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
   my($ns_addr,$ns_port); local($1,$2);  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
374
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
33
 | 
   ($ns_addr,$ns_port) = ($1,$2)  if $ns_addr_port[0] =~ /^\[(.*)\]:(\d+)\z/;  | 
| 
375
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Ensure families of src and dest addresses match (bug 4412 comment 29).  | 
| 
377
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Older IO::Socket::INET6 may choose a wrong LocalAddr if protocol family  | 
| 
378
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # is unspecified, causing EINVAL failure when automatically assigned local  | 
| 
379
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # IP address and a remote address do not belong to the same address family.  | 
| 
380
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Let's choose a suitable source address if possible.  | 
| 
381
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
   my $ip4_re = IPV4_ADDRESS;  | 
| 
382
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
   my $srcaddr;  | 
| 
383
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
   if ($self->{force_ipv4}) {  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
384
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     $srcaddr = "0.0.0.0";  | 
| 
385
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } elsif ($self->{force_ipv6}) {  | 
| 
386
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $srcaddr = "::";  | 
| 
387
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } elsif ($ns_addr =~ /^${ip4_re}\z/o) {  | 
| 
388
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $srcaddr = "0.0.0.0";  | 
| 
389
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } elsif ($ns_addr =~ /:.*:/) {  | 
| 
390
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $srcaddr = "::";  | 
| 
391
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } else {  # unrecognized  | 
| 
392
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # unspecified address, unspecified protocol family  | 
| 
393
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
394
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
395
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # find a free local random port from a set of declared-to-be-available ports  | 
| 
396
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
   my $lport;  | 
| 
397
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
   my $attempts = 0;  | 
| 
398
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
   for (;;) {  | 
| 
399
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     $attempts++;  | 
| 
400
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     $lport = $self->pick_random_available_port();  | 
| 
401
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     if (!defined $lport) {  | 
| 
402
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $lport = 0;  | 
| 
403
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       dbg("no configured local ports for DNS queries, letting OS choose");  | 
| 
404
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
405
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     if ($attempts+1 > 50) {  # sanity check  | 
| 
406
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       warn "could not create a DNS resolver socket in $attempts attempts\n";  | 
| 
407
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $errno = 0;  | 
| 
408
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       last;  | 
| 
409
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
410
 | 
2
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
13
 | 
     dbg("dns: LocalAddr: [%s]:%d, name server: [%s]:%d, module %s",  | 
| 
411
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $srcaddr||'x', $lport,  $ns_addr, $ns_port,  $io_socket_module_name);  | 
| 
412
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
     my %args = (  | 
| 
413
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         PeerAddr => $ns_addr,  | 
| 
414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         PeerPort => $ns_port,  | 
| 
415
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         LocalAddr => $srcaddr,  | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         LocalPort => $lport,  | 
| 
417
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         Type => SOCK_DGRAM,  | 
| 
418
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         Proto => 'udp',  | 
| 
419
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
420
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
     $sock = $io_socket_module_name->new(%args);  | 
| 
421
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
422
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1858
 | 
     last if $sock;  # ok, got it  | 
| 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
424
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # IO::Socket::IP constructor provides full error messages in $@  | 
| 
425
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $errno = $io_socket_module_name eq 'IO::Socket::IP' ? $@ : $!;  | 
| 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
427
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
     if ($! == EADDRINUSE || $! == EACCES) {  | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # in use, let's try another source port  | 
| 
429
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       dbg("dns: UDP port $lport already in use, trying another port");  | 
| 
430
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       if ($self->{conf}->{dns_available_portscount} > 100) {  # still abundant  | 
| 
431
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $self->disable_available_port($lport);  | 
| 
432
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
433
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
434
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       warn "error creating a DNS resolver socket: $errno";  | 
| 
435
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       goto no_sock;  | 
| 
436
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
437
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
438
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
   if (!$sock) {  | 
| 
439
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     warn "could not create a DNS resolver socket in $attempts attempts: $errno";  | 
| 
440
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     goto no_sock;  | 
| 
441
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
442
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
443
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   eval {  | 
| 
444
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     my($bufsiz,$newbufsiz);  | 
| 
445
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
45
 | 
     $bufsiz = $sock->sockopt(Socket::SO_RCVBUF)  | 
| 
446
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       or die "cannot get a resolver socket rx buffer size: $!";  | 
| 
447
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
95
 | 
     if ($bufsiz >= 32*1024) {  | 
| 
448
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
       dbg("dns: resolver socket rx buffer size is %d bytes, local port %d",  | 
| 
449
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
            $bufsiz, $lport);  | 
| 
450
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
451
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $sock->sockopt(Socket::SO_RCVBUF, 32*1024)  | 
| 
452
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         or die "cannot set a resolver socket rx buffer size: $!";  | 
| 
453
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $newbufsiz = $sock->sockopt(Socket::SO_RCVBUF)  | 
| 
454
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         or die "cannot get a resolver socket rx buffer size: $!";  | 
| 
455
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       dbg("dns: resolver socket rx buffer size changed from %d to %d bytes, ".  | 
| 
456
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           "local port %d", $bufsiz, $newbufsiz, $lport);  | 
| 
457
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
458
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
     1;  | 
| 
459
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
   } or do {  | 
| 
460
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $eval_stat = $@ ne '' ? $@ : "errno=$!";  chomp $eval_stat;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
461
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     info("dns: socket buffer size error: $eval_stat");  | 
| 
462
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   };  | 
| 
463
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
464
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
   $self->{sock} = $sock;  | 
| 
465
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
   $self->{sock_as_vec} = $self->fhs_to_vec($self->{sock});  | 
| 
466
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
   return;  | 
| 
467
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
468
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 no_sock:  | 
| 
469
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   undef $self->{sock};  | 
| 
470
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   undef $self->{sock_as_vec};  | 
| 
471
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
472
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
473
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub connect_sock_if_reqd {  | 
| 
474
 | 
21
 | 
 
 | 
 
 | 
  
21
  
 | 
  
0
  
 | 
43
 | 
   my ($self) = @_;  | 
| 
475
 | 
21
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
86
 | 
   $self->connect_sock() if !$self->{sock};  | 
| 
476
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
477
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
478
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $res->get_sock()  | 
| 
479
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
480
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Return the C<IO::Socket::INET> object used to communicate with  | 
| 
481
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the nameserver.  | 
| 
482
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
483
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
484
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
485
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get_sock {  | 
| 
486
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
0
 | 
   my ($self) = @_;  | 
| 
487
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   $self->connect_sock_if_reqd();  | 
| 
488
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   return $self->{sock};  | 
| 
489
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
490
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
491
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ###########################################################################  | 
| 
492
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
493
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $packet = new_dns_packet ($domain, $type, $class)  | 
| 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
495
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 A wrapper for C<Net::DNS::Packet::new()> which traps a die thrown by it.  | 
| 
496
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
497
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 To use this, change calls to C<Net::DNS::Resolver::bgsend> from:  | 
| 
498
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
499
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $res->bgsend($domain, $type);  | 
| 
500
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
501
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 to:  | 
| 
502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
503
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $res->bgsend(Mail::SpamAssassin::DnsResolver::new_dns_packet($domain, $type, $class));  | 
| 
504
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
505
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
506
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
507
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # implements draft-vixie-dnsext-dns0x20-00  | 
| 
508
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  | 
| 
509
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub dnsext_dns0x20 {  | 
| 
510
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
   my ($string) = @_;  | 
| 
511
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   my $rnd;  | 
| 
512
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   my $have_rnd_bits = 0;  | 
| 
513
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   my $result = '';  | 
| 
514
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   for my $ic (unpack("C*",$string)) {  | 
| 
515
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     if (chr($ic) =~ /^[A-Za-z]\z/) {  | 
| 
516
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       if ($have_rnd_bits < 1) {  | 
| 
517
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # only reveal few bits at a time, hiding most of the accumulator  | 
| 
518
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $rnd = int(rand(0x7fffffff)) & 0xff;  $have_rnd_bits = 8;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
519
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
520
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $ic ^= 0x20  if $rnd & 1;  # flip the 0x20 bit in name if dice says so  | 
| 
521
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $rnd = $rnd >> 1;  $have_rnd_bits--;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
522
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
523
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $result .= chr($ic);  | 
| 
524
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
525
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   return $result;  | 
| 
526
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
527
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
528
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # this subroutine mimics the Net::DNS::Resolver::Base::make_query_packet()  | 
| 
529
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  | 
| 
530
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub new_dns_packet {  | 
| 
531
 | 
21
 | 
 
 | 
 
 | 
  
21
  
 | 
  
1
  
 | 
72
 | 
   my ($self, $domain, $type, $class) = @_;  | 
| 
532
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
533
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
52
 | 
   return if $self->{no_resolver};  | 
| 
534
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
535
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # construct a PTR query if it looks like an IPv4 address  | 
| 
536
 | 
21
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
144
 | 
   if (!defined($type) || $type eq 'PTR') {  | 
| 
537
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     local($1,$2,$3,$4);  | 
| 
538
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     if ($domain =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {  | 
| 
539
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $domain = "$4.$3.$2.$1.in-addr.arpa.";  | 
| 
540
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $type = 'PTR';  | 
| 
541
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
542
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
543
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
62
 | 
   $type  = 'A'   if !defined $type;   # a Net::DNS::Packet default  | 
| 
544
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
59
 | 
   $class = 'IN'  if !defined $class;  # a Net::DNS::Packet default  | 
| 
545
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
546
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
   my $packet;  | 
| 
547
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   eval {  | 
| 
548
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
549
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
81
 | 
     if (utf8::is_utf8($domain)) {  # since Perl 5.8.1  | 
| 
550
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       dbg("dns: new_dns_packet: domain is utf8 flagged: %s", $domain);  | 
| 
551
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
552
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
553
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
202
 | 
     $domain =~ s/\.*\z/./s;  | 
| 
554
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
196
 | 
     if (length($domain) > 255) {  | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
555
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       die "domain name longer than 255 bytes\n";  | 
| 
556
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif ($domain !~ /^ (?: [^.]{1,63} \. )+ \z/sx) {  | 
| 
557
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       if ($domain !~ /^ (?: [^.]+ \. )+ \z/sx) {  | 
| 
558
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         die "a domain name contains a null label\n";  | 
| 
559
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       } else {  | 
| 
560
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         die "a label in a domain name is longer than 63 bytes\n";  | 
| 
561
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
562
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
563
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
564
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
76
 | 
     if ($self->{conf}->{dns_options}->{dns0x20}) {  | 
| 
565
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $domain = dnsext_dns0x20($domain);  | 
| 
566
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
567
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
62
 | 
       $domain =~ tr/A-Z/a-z/;  # lowercase, limited to plain ASCII  | 
| 
568
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
569
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
570
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Net::DNS expects RFC 1035 zone format encoding even in its API, silly!  | 
| 
571
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Since 0.68 it also assumes that domain names containing characters  | 
| 
572
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # with codes above 0177 imply that IDN translation is to be performed.  | 
| 
573
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Protect also nonprintable characters just in case, ensuring transparency.  | 
| 
574
 | 
21
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
61
 | 
     $domain =~ s{ ( [\000-\037\177-\377\\] ) }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
575
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 { $1 eq '\\' ? "\\$1" : sprintf("\\%03d",ord($1)) }xgse;  | 
| 
576
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
154
 | 
    | 
| 
577
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $packet = Net::DNS::Packet->new($domain, $type, $class);  | 
| 
578
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
579
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # a bit noisy, so commented by default...  | 
| 
580
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #dbg("dns: new DNS packet time=%.3f domain=%s type=%s id=%s",  | 
| 
581
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2917
 | 
     #    time, $domain, $type, $packet->id);  | 
| 
582
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
36
 | 
     1;  | 
| 
583
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } or do {  | 
| 
584
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # get here if a domain name in a query is invalid, or if a timeout signal  | 
| 
585
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     # happened to be trapped by this eval, or if Net::DNS signalled an error  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
586
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $eval_stat = $@ ne '' ? $@ : "errno=$!";  chomp $eval_stat;  | 
| 
587
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     # resignal if alarm went off  | 
| 
588
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     die "dns: (1) $eval_stat\n"  if $eval_stat =~ /__alarm__ignore__\(.*\)/s;  | 
| 
589
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     info("dns: new_dns_packet (domain=%s type=%s class=%s) failed: %s",  | 
| 
590
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
            $domain, $type, $class, $eval_stat);  | 
| 
591
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   };  | 
| 
592
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
57
 | 
    | 
| 
593
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   if ($packet) {  | 
| 
594
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
81
 | 
     # RD flag needs to be set explicitly since Net::DNS 1.01, Bug 7223	  | 
| 
595
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $packet->header->rd(1);  | 
| 
596
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
597
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
613
 | 
   # my $udp_payload_size = $self->{res}->udppacketsize;  | 
| 
598
 | 
21
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
124
 | 
     my $udp_payload_size = $self->{conf}->{dns_options}->{edns};  | 
| 
599
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     if ($udp_payload_size && $udp_payload_size > 512) {  | 
| 
600
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
150
 | 
     # dbg("dns: adding EDNS ext, UDP payload size %d", $udp_payload_size);  | 
| 
601
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
66
 | 
       if ($packet->UNIVERSAL::can('edns')) {  # available since Net::DNS 0.69  | 
| 
602
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $packet->edns->size($udp_payload_size);  | 
| 
603
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       } else {  # legacy mechanism  | 
| 
604
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $optrr = Net::DNS::RR->new(Type => 'OPT', Name => '', TTL => 0,  | 
| 
605
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                                       Class => $udp_payload_size);  | 
| 
606
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $packet->push('additional', $optrr);  | 
| 
607
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
608
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
609
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
610
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9262
 | 
    | 
| 
611
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   return $packet;  | 
| 
612
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
613
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
614
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Internal function used only in this file  | 
| 
615
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## compute a unique ID for a packet to match the query to the reply  | 
| 
616
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## It must use only data that is returned unchanged by the nameserver.  | 
| 
617
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## Argument is a Net::DNS::Packet that has a non-empty question section,  | 
| 
618
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## return is an (opaque) string that can be used as a hash key  | 
| 
619
 | 
42
 | 
 
 | 
 
 | 
  
42
  
 | 
 
 | 
87
 | 
 sub _packet_id {  | 
| 
620
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
110
 | 
   my ($self, $packet) = @_;  | 
| 
621
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
266
 | 
   my $header = $packet->header;  | 
| 
622
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
353
 | 
   my $id = $header->id;  | 
| 
623
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my @questions = $packet->question;  | 
| 
624
 | 
42
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
294
 | 
    | 
| 
625
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   @questions <= 1  | 
| 
626
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     or warn "dns: packet has multiple questions: " . $packet->string . "\n";  | 
| 
627
 | 
42
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
116
 | 
    | 
| 
628
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   if ($questions[0]) {  | 
| 
629
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Bug 6232: Net::DNS::Packet::new is not consistent in keeping data in  | 
| 
630
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # sections of a packet either as original bytes or presentation-encoded:  | 
| 
631
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # creating a query packet as above in new_dns_packet() keeps label in  | 
| 
632
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # non-encoded form, yet on parsing an answer packet, its query section  | 
| 
633
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # is converted to presentation form by Net::DNS::Question::parse calling  | 
| 
634
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Net::DNS::Packet::dn_expand and Net::DNS::wire2presentation in turn.  | 
| 
635
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Let's undo the effect of the wire2presentation routine here to make  | 
| 
636
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # sure the query section of an answer packet matches the query section  | 
| 
637
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # in our packet as formed by new_dns_packet():  | 
| 
638
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
138
 | 
     #  | 
| 
639
 | 
42
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1277
 | 
     my($class,$type,$qname) = decode_dns_question_entry($questions[0]);  | 
| 
640
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
280
 | 
     $qname =~ tr/A-Z/a-z/  if !$self->{conf}->{dns_options}->{dns0x20};  | 
| 
641
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return join('/', $id, $class, $type, $qname);  | 
| 
642
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
643
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } else {  | 
| 
644
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Odd, this should not happen, a DNS servers is supposed to retain  | 
| 
645
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # a question section in its reply.  There is a bug in Net::DNS 0.72  | 
| 
646
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # and earlier where a signal (e.g. a timeout alarm) during decoding  | 
| 
647
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # of a reply packet produces a seemingly valid packet object, but  | 
| 
648
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # with missing sections - see [rt.cpan.org #83451] .  | 
| 
649
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #  | 
| 
650
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Better support it; just return the (safe) ID part, along with  | 
| 
651
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # a text token indicating that the packet had no question part.  | 
| 
652
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     #  | 
| 
653
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return $id . "/NO_QUESTION_IN_PACKET";  | 
| 
654
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
655
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
656
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
657
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ###########################################################################  | 
| 
658
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
659
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $id = $res->bgsend($domain, $type, $class, $cb)  | 
| 
660
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
661
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Quite similar to C<Net::DNS::Resolver::bgsend>, except that when a reply  | 
| 
662
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 packet eventually arrives, and C<poll_responses> is called, the callback  | 
| 
663
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub reference C<$cb> will be called.  | 
| 
664
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
665
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Note that C<$type> and C<$class> may be C<undef>, in which case they  | 
| 
666
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 will default to C<A> and C<IN>, respectively.  | 
| 
667
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
668
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The callback sub will be called with three arguments -- the packet that was  | 
| 
669
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 delivered, and an id string that fingerprints the query packet and the expected  | 
| 
670
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 reply. The third argument is a timestamp (Unix time, floating point), captured  | 
| 
671
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 at the time the packet was collected. It is expected that a closure callback  | 
| 
672
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 be used, like so:  | 
| 
673
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
674
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $id = $self->{resolver}->bgsend($domain, $type, undef, sub {  | 
| 
675
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my ($reply, $reply_id, $timestamp) = @_;  | 
| 
676
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $self->got_a_reply ($reply, $reply_id);  | 
| 
677
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       });  | 
| 
678
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
679
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The callback can ignore the reply as an invalid packet sent to the listening  | 
| 
680
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 port if the reply id does not match the return value from bgsend.  | 
| 
681
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
682
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
683
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
684
 | 
21
 | 
 
 | 
 
 | 
  
21
  
 | 
  
1
  
 | 
99
 | 
 sub bgsend {  | 
| 
685
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
64
 | 
   my ($self, $domain, $type, $class, $cb) = @_;  | 
| 
686
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   return if $self->{no_resolver};  | 
| 
687
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
100
 | 
    | 
| 
688
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   $self->{send_timed_out} = 0;  | 
| 
689
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
62
 | 
    | 
| 
690
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
64
 | 
   my $pkt = $self->new_dns_packet($domain, $type, $class);  | 
| 
691
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   return if !$pkt;  # just bail out, new_dns_packet already reported a failure  | 
| 
692
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
72
 | 
    | 
| 
693
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
96
 | 
   my @ns_addr_port = $self->available_nameservers();  | 
| 
694
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
   dbg("dns: bgsend, DNS servers: %s", join(', ',@ns_addr_port));  | 
| 
695
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $n_servers = scalar @ns_addr_port;  | 
| 
696
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
    | 
| 
697
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
58
 | 
   my $ok;  | 
| 
698
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
65
 | 
   for (my $attempts=1; $attempts <= $n_servers; $attempts++) {  | 
| 
699
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     dbg("dns: attempt %d/%d, trying connect/sendto to %s",  | 
| 
700
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
81
 | 
         $attempts, $n_servers, $ns_addr_port[0]);  | 
| 
701
 | 
21
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
127
 | 
     $self->connect_sock_if_reqd();  | 
| 
702
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7378
 | 
     if ($self->{sock} && defined($self->{sock}->send($pkt->data, 0))) {  | 
| 
 
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
56
 | 
    | 
| 
703
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       $ok = 1; last;  | 
| 
704
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     } else {  # any other DNS servers in a list to try?  | 
| 
705
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       my $msg = !$self->{sock} ? "unable to connect to $ns_addr_port[0]"  | 
| 
706
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                                : "sendto() to $ns_addr_port[0] failed: $!";  | 
| 
707
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $self->finish_socket();  | 
| 
708
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       if ($attempts >= $n_servers) {  | 
| 
709
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         warn "dns: $msg, no more alternatives\n";  | 
| 
710
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         last;  | 
| 
711
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
712
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       # try with a next DNS server, rotate the list left  | 
| 
713
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       warn "dns: $msg, failing over to $ns_addr_port[1]\n";  | 
| 
714
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       push(@ns_addr_port, shift(@ns_addr_port));  | 
| 
715
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       $self->available_nameservers(@ns_addr_port);  | 
| 
716
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
717
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
66
 | 
   }  | 
| 
718
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
81
 | 
   return if !$ok;  | 
| 
719
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
189
 | 
   my $id = $self->_packet_id($pkt);  | 
| 
720
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
67
 | 
   dbg("dns: providing a callback for id: $id");  | 
| 
721
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
206
 | 
   $self->{id_to_callback}->{$id} = $cb;  | 
| 
722
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   return $id;  | 
| 
723
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
724
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
725
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ###########################################################################  | 
| 
726
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
727
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $id = $res->bgread()  | 
| 
728
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
729
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Similar to C<Net::DNS::Resolver::bgread>.  Reads a DNS packet from  | 
| 
730
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 a supplied socket, decodes it, and returns a Net::DNS::Packet object  | 
| 
731
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 if successful.  Dies on error.  | 
| 
732
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
733
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
734
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
735
 | 
21
 | 
 
 | 
 
 | 
  
21
  
 | 
  
1
  
 | 
43
 | 
 sub bgread {  | 
| 
736
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
   my ($self) = @_;  | 
| 
737
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
128
 | 
   my $sock = $self->{sock};  | 
| 
738
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
353
 | 
   my $packetsize = $self->{res}->udppacketsize;  | 
| 
739
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
   $packetsize = 512  if $packetsize < 512;  # just in case  | 
| 
740
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
94
 | 
   my $data = '';  | 
| 
741
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1033
 | 
   my $peeraddr = $sock->recv($data, $packetsize+256);  # with some size margin for troubleshooting  | 
| 
742
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
92
 | 
   defined $peeraddr or die "bgread: recv() failed: $!";  | 
| 
743
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1131
 | 
   my $peerhost = $sock->peerhost;  | 
| 
744
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
124
 | 
   $data ne '' or die "bgread: received empty packet from $peerhost";  | 
| 
745
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
100
 | 
   dbg("dns: bgread: received %d bytes from %s", length($data), $peerhost);  | 
| 
746
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5436
 | 
   my($answerpkt, $decoded_length) = Net::DNS::Packet->new(\$data);  | 
| 
747
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
94
 | 
   $answerpkt or die "bgread: decoding DNS packet failed: $@";  | 
| 
748
 | 
21
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
427
 | 
   $answerpkt->answerfrom($peerhost);  | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
749
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   if (defined $decoded_length && $decoded_length ne "" && $decoded_length != length($data)) {  | 
| 
750
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     warn sprintf("bgread: received a %d bytes packet from %s, decoded %d bytes\n",  | 
| 
751
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                  length($data), $peerhost, $decoded_length);  | 
| 
752
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
110
 | 
   }  | 
| 
753
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   return $answerpkt;  | 
| 
754
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
755
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
756
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ###########################################################################  | 
| 
757
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
758
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $nfound = $res->poll_responses()  | 
| 
759
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
760
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 See if there are any C<bgsend> reply packets ready, and return  | 
| 
761
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the number of such packets delivered to their callbacks.  | 
| 
762
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
763
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
764
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
765
 | 
11
 | 
 
 | 
 
 | 
  
11
  
 | 
  
1
  
 | 
29
 | 
 sub poll_responses {  | 
| 
766
 | 
11
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
31
 | 
   my ($self, $timeout) = @_;  | 
| 
767
 | 
11
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
31
 | 
   return if $self->{no_resolver};  | 
| 
768
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
   return if !$self->{sock};  | 
| 
769
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $cnt = 0;  | 
| 
770
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
    | 
| 
771
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
   my $rin = $self->{sock_as_vec};  | 
| 
772
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $rout;  | 
| 
773
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
    | 
| 
774
 | 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
67
 | 
   for (;;) {  | 
| 
775
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my ($nfound, $timeleft, $eval_stat);  | 
| 
776
 | 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
49
 | 
     eval {  # use eval to catch alarm signal  | 
| 
777
 | 
32
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
144
 | 
       my $timer;  # collects timestamp when variable goes out of scope  | 
| 
778
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
       if (!defined($timeout) || $timeout > 0)  | 
| 
779
 | 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
81
 | 
         { $timer = $self->{main}->time_method("poll_dns_idle") }  | 
| 
780
 | 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24058
 | 
       $! = 0;  | 
| 
781
 | 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
181
 | 
       ($nfound, $timeleft) = select($rout=$rin, undef, undef, $timeout);  | 
| 
782
 | 
32
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
54
 | 
       1;  | 
| 
783
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     } or do {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
784
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       $eval_stat = $@ ne '' ? $@ : "errno=$!";  chomp $eval_stat;  | 
| 
785
 | 
32
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
240
 | 
     };  | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
786
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     if (defined $eval_stat) {  | 
| 
787
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       # most likely due to an alarm signal, resignal if so  | 
| 
788
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       die "dns: (2) $eval_stat\n"  if $eval_stat =~ /__alarm__ignore__\(.*\)/s;  | 
| 
789
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       warn "dns: select aborted: $eval_stat\n";  | 
| 
790
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       return;  | 
| 
791
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     } elsif (!defined $nfound || $nfound < 0) {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
792
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       if ($!) { warn "dns: select failed: $!\n" }  | 
| 
793
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       else    { info("dns: select interrupted") }  # shouldn't happen  | 
| 
794
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       return;  | 
| 
795
 | 
11
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
42
 | 
     } elsif (!$nfound) {  | 
| 
 
 | 
  
0
  
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
796
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       if (!defined $timeout) { warn("dns: select returned empty-handed\n") }  | 
| 
797
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
51
 | 
       elsif ($timeout > 0) { dbg("dns: select timed out %.3f s", $timeout) }  | 
| 
798
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       return;  | 
| 
799
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
800
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
    | 
| 
801
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
     my $now = time;  | 
| 
802
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
56
 | 
     $timeout = 0;  # next time around collect whatever is available, then exit  | 
| 
803
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     last  if $nfound == 0;  | 
| 
804
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
    | 
| 
805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $packet;  | 
| 
806
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Bug 7265, use our own bgread() below  | 
| 
807
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # $packet = $self->{res}->bgread($self->{sock});  | 
| 
808
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
73
 | 
     eval {  | 
| 
809
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
41
 | 
       $packet = $self->bgread();  # Bug 7265, use our own bgread()  | 
| 
810
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     } or do {  | 
| 
811
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       undef $packet;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
812
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       my $eval_stat = $@ ne '' ? $@ : "errno=$!";  chomp $eval_stat;  | 
| 
813
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       # resignal if alarm went off  | 
| 
814
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       die $eval_stat  if $eval_stat =~ /__alarm__ignore__\(.*\)/s;  | 
| 
815
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       info("dns: bad dns reply: %s", $eval_stat);  | 
| 
816
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     };  | 
| 
817
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
63
 | 
    | 
| 
818
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     if (!$packet) {  | 
| 
819
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # error already reported above  | 
| 
820
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #     my $dns_err = $self->{res}->errorstring;  | 
| 
821
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #     die "dns (3) $dns_err\n"  if $dns_err =~ /__alarm__ignore__\(.*\)/s;  | 
| 
822
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #     info("dns: bad dns reply: $dns_err");  | 
| 
823
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
61
 | 
     } else {  | 
| 
824
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
126
 | 
       my $header = $packet->header;  | 
| 
825
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       if (!$header) {  | 
| 
826
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         info("dns: dns reply is missing a header section");  | 
| 
827
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
77
 | 
       } else {  | 
| 
828
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2490
 | 
         my $rcode = $header->rcode;  | 
| 
829
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
210
 | 
         my $packet_id = $header->id;  | 
| 
830
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $id = $self->_packet_id($packet);  | 
| 
831
 | 
21
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
75
 | 
    | 
| 
832
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if ($rcode eq 'NOERROR') {  # success  | 
| 
833
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
           # NOERROR, may or may not have answer records  | 
| 
834
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           dbg("dns: dns reply %s is OK, %d answer records",  | 
| 
835
 | 
10
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
31
 | 
               $packet_id, $header->ancount);  | 
| 
836
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
           if ($header->tc) {  # truncation flag turned on  | 
| 
837
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             my $edns = $self->{conf}->{dns_options}->{edns} || 512;  | 
| 
838
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             info("dns: reply to %s truncated (%s), %d answer records", $id,  | 
| 
839
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                  $edns == 512 ? "EDNS off" : "EDNS $edns bytes",  | 
| 
840
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                  $header->ancount);  | 
| 
841
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           }  | 
| 
842
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
843
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           # some failure, e.g. NXDOMAIN, SERVFAIL, FORMERR, REFUSED, ...  | 
| 
844
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
           # btw, one reason for SERVFAIL is an RR signature failure in DNSSEC  | 
| 
845
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           dbg("dns: dns reply to %s: %s", $id, $rcode);  | 
| 
846
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
847
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
848
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # A hash lookup: the id must match exactly (case-sensitively).  | 
| 
849
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # The domain name part of the id was lowercased if dns0x20 is off,  | 
| 
850
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # and case-randomized when dns0x20 option is on.  | 
| 
851
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
232
 | 
         #  | 
| 
852
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $cb = delete $self->{id_to_callback}->{$id};  | 
| 
853
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
51
 | 
    | 
| 
854
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
82
 | 
         if ($cb) {  | 
| 
855
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
210
 | 
           $cb->($packet, $id, $now);  | 
| 
856
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           $cnt++;  | 
| 
857
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
         } else {  # no match, report the problem  | 
| 
858
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           if ($rcode eq 'REFUSED' || $id =~ m{^\d+/NO_QUESTION_IN_PACKET\z}) {  | 
| 
859
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # the failure was already reported above  | 
| 
860
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
           } else {  | 
| 
861
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             info("dns: no callback for id $id, ignored, packet on next debug line");  | 
| 
862
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             # prevent filling normal logs with huge packet dumps  | 
| 
863
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             dbg("dns: %s", $packet ? $packet->string : "undef");  | 
| 
864
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           }  | 
| 
865
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
           # report a likely matching query for diagnostic purposes  | 
| 
866
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
           local $1;  | 
| 
867
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
           if ($id =~ m{^(\d+)/}) {  | 
| 
868
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my $dnsid = $1;  # the raw DNS packet id  | 
| 
869
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             my @matches =  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
870
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
               grep(m{^\Q$dnsid\E/}, keys %{$self->{id_to_callback}});  | 
| 
871
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             if (!@matches) {  | 
| 
872
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               info("dns: no likely matching queries for id %s", $dnsid);  | 
| 
873
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             } else {  | 
| 
874
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               info("dns: a likely matching query: %s", join(', ', @matches));  | 
| 
875
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
876
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           }  | 
| 
877
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
878
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
879
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
880
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
881
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
882
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   return $cnt;  | 
| 
883
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
884
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
885
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ###########################################################################  | 
| 
886
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
887
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $res->bgabort()  | 
| 
888
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
889
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Call this to release pending requests from memory, when aborting backgrounded  | 
| 
890
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 requests, or when the scan is complete.  | 
| 
891
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 C<Mail::SpamAssassin::PerMsgStatus::check> calls this before returning.  | 
| 
892
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
893
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
894
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
895
 | 
192
 | 
 
 | 
 
 | 
  
192
  
 | 
  
1
  
 | 
484
 | 
 sub bgabort {  | 
| 
896
 | 
192
 | 
 
 | 
 
 | 
 
 | 
 
 | 
681
 | 
   my ($self) = @_;  | 
| 
897
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   $self->{id_to_callback} = {};  | 
| 
898
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
899
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
900
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ###########################################################################  | 
| 
901
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
902
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $packet = $res->send($name, $type, $class)  | 
| 
903
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
904
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Emulates C<Net::DNS::Resolver::send()>.  | 
| 
905
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
906
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This subroutine is a simple synchronous leftover from SpamAssassin version  | 
| 
907
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 3.3 and does not participate in packet query caching and callback grouping  | 
| 
908
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 as implemented by AsyncLoop::bgsend_and_start_lookup().  As such it should  | 
| 
909
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 be avoided for mainstream usage.  Currently used through Mail::SPF::Server  | 
| 
910
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 by the SPF plugin.  | 
| 
911
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
913
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
914
 | 
8
 | 
 
 | 
 
 | 
  
8
  
 | 
  
1
  
 | 
1833
 | 
 sub send {  | 
| 
915
 | 
8
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
30
 | 
   my ($self, $name, $type, $class) = @_;  | 
| 
916
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   return if $self->{no_resolver};  | 
| 
917
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
918
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Avoid passing utf8 character strings to DNS, as it has no notion of  | 
| 
919
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # character set encodings - encode characters somehow to plain bytes  | 
| 
920
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # using some arbitrary encoding (they are normally just 7-bit ascii  | 
| 
921
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # characters anyway, just need to get rid of the utf8 flag).  Bug 6959  | 
| 
922
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Most if not all af these come from a SPF plugin.  | 
| 
923
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
40
 | 
   #  | 
| 
924
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   utf8::encode($name);  | 
| 
925
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
    | 
| 
926
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
   my $retrans = $self->{retrans};  | 
| 
927
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
   my $retries = $self->{retry};  | 
| 
928
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
   my $timeout = $retrans;  | 
| 
929
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
   my $answerpkt;  | 
| 
930
 | 
8
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
77
 | 
   my $answerpkt_avail = 0;  | 
| 
931
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   for (my $i = 0;  | 
| 
932
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
        (($i < $retries) && !defined($answerpkt));  | 
| 
933
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
        ++$i, $retrans *= 2, $timeout = $retrans) {  | 
| 
934
 | 
8
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
25
 | 
    | 
| 
935
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $timeout = 1 if ($timeout < 1);  | 
| 
936
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # note nifty use of a closure here.  I love closures ;)  | 
| 
937
 | 
8
 | 
 
 | 
 
 | 
  
8
  
 | 
 
 | 
31
 | 
     my $id = $self->bgsend($name, $type, $class, sub {  | 
| 
938
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
       my ($reply, $reply_id, $timestamp) = @_;  | 
| 
 
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
    | 
| 
939
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
86
 | 
       $answerpkt = $reply; $answerpkt_avail = 1;  | 
| 
940
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     });  | 
| 
941
 | 
8
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
33
 | 
    | 
| 
942
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     last if !defined $id;  # perhaps a restricted zone or a serious failure  | 
| 
943
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
    | 
| 
944
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
     my $now = time;  | 
| 
945
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $deadline = $now + $timeout;  | 
| 
946
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
    | 
| 
947
 | 
8
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
24
 | 
     while (!$answerpkt_avail) {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
948
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
       if ($now >= $deadline) { $self->{send_timed_out} = 1; last }  | 
| 
949
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
77
 | 
       $self->poll_responses(1);  | 
| 
950
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       $now = time;  | 
| 
951
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
952
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
   }  | 
| 
953
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   return $answerpkt;  | 
| 
954
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
955
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
956
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ###########################################################################  | 
| 
957
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
958
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $res->errorstring()  | 
| 
959
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
960
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Little more than a stub for callers expecting this from C<Net::DNS::Resolver>.  | 
| 
961
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
962
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 If called immediately after a call to $res->send this will return  | 
| 
963
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 C<query timed out> if the $res->send DNS query timed out.  Otherwise   | 
| 
964
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 C<unknown error or no error> will be returned.  | 
| 
965
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
966
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 No other errors are reported.  | 
| 
967
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
968
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
969
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
970
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
0
 | 
 sub errorstring {  | 
| 
971
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   my ($self) = @_;  | 
| 
972
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   return 'query timed out' if $self->{send_timed_out};  | 
| 
973
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   return 'unknown error or no error';  | 
| 
974
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
975
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
976
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ###########################################################################  | 
| 
977
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
978
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $res->finish_socket()  | 
| 
979
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
980
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Reset socket when done with it.  | 
| 
981
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
982
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
983
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
984
 | 
53
 | 
 
 | 
 
 | 
  
53
  
 | 
  
1
  
 | 
145
 | 
 sub finish_socket {  | 
| 
985
 | 
53
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
238
 | 
   my ($self) = @_;  | 
| 
986
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   if ($self->{sock}) {  | 
| 
987
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
21
 | 
     $self->{sock}->close()  | 
| 
988
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
136
 | 
       or warn "finish_socket: error closing socket $self->{sock}: $!";  | 
| 
989
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     undef $self->{sock};  | 
| 
990
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
991
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
992
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
993
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ###########################################################################  | 
| 
994
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
995
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item $res->finish()  | 
| 
996
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
997
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Clean up for destruction.  | 
| 
998
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
999
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
1000
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1001
 | 
52
 | 
 
 | 
 
 | 
  
52
  
 | 
  
1
  
 | 
163
 | 
 sub finish {  | 
| 
1002
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
273
 | 
   my ($self) = @_;  | 
| 
1003
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
127
 | 
   $self->finish_socket();  | 
| 
 
 | 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1046
 | 
    | 
| 
1004
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   %{$self} = ();  | 
| 
1005
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
1006
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1007
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ###########################################################################  | 
| 
1008
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # non-public methods.  | 
| 
1009
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1010
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # should move to Util.pm (TODO)  | 
| 
1011
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
0
  
 | 
9
 | 
 sub fhs_to_vec {  | 
| 
1012
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
   my ($self, @fhlist) = @_;  | 
| 
1013
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
   my $rin = '';  | 
| 
1014
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
   foreach my $sock (@fhlist) {  | 
| 
1015
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     my $fno = fileno($sock);  | 
| 
1016
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     if (!defined $fno) {  | 
| 
1017
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       warn "dns: oops! fileno now undef for $sock";  | 
| 
1018
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     } else {  | 
| 
1019
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       vec ($rin, $fno, 1) = 1;  | 
| 
1020
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
1021
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
   }  | 
| 
1022
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   return $rin;  | 
| 
1023
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
1024
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1025
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # call Mail::SA::init() instead  | 
| 
1026
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
 
 | 
 sub reinit_post_fork {  | 
| 
1027
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my ($self) = @_;  | 
| 
1028
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # release parent's socket, don't want all spamds sharing the same socket  | 
| 
1029
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   $self->finish_socket();  | 
| 
1030
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
1031
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1032
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
1033
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1034
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =back  | 
| 
1035
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1036
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  |