line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::DNS::Check; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
47347
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
38
|
|
4
|
1
|
|
|
1
|
|
5
|
use vars qw($VERSION $AUTOLOAD); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
65
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
$VERSION = '0.45'; |
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
5
|
use Carp; |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
78
|
|
9
|
1
|
|
|
1
|
|
1007
|
use Net::DNS; |
|
1
|
|
|
|
|
121612
|
|
|
1
|
|
|
|
|
106
|
|
10
|
1
|
|
|
1
|
|
872
|
use Net::DNS::Resolver::Recurse; |
|
1
|
|
|
|
|
2045
|
|
|
1
|
|
|
|
|
32
|
|
11
|
1
|
|
|
1
|
|
662
|
use Net::DNS::Check::Config; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
27
|
|
12
|
1
|
|
|
1
|
|
515
|
use Net::DNS::Check::HostsList; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
29
|
|
13
|
1
|
|
|
1
|
|
7
|
use Net::DNS::Check::Host; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
18
|
|
14
|
1
|
|
|
1
|
|
616
|
use Net::DNS::Check::NSQuery; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
25
|
|
15
|
1
|
|
|
1
|
|
523
|
use Net::DNS::Check::Test; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
24
|
|
16
|
1
|
|
|
1
|
|
1133
|
use Data::Dumper; |
|
1
|
|
|
|
|
9707
|
|
|
1
|
|
|
|
|
2925
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my %PUBLIC_ARGS = map { $_ => 1 } qw( |
20
|
|
|
|
|
|
|
config |
21
|
|
|
|
|
|
|
config_file |
22
|
|
|
|
|
|
|
domain |
23
|
|
|
|
|
|
|
nserver debug); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub new { |
27
|
0
|
|
|
0
|
1
|
|
my ($class) = shift; |
28
|
|
|
|
|
|
|
|
29
|
0
|
|
|
|
|
|
my $self = {}; |
30
|
|
|
|
|
|
|
|
31
|
0
|
|
|
|
|
|
bless $self, $class; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Hash ref of auth nameservers # {$nsname}->{ip} array ref of found ip address # {$nsname}->{ip_orig} array ref of decoded ip address from nserver param |
34
|
|
|
|
|
|
|
# {$nsname}->{host} host object created |
35
|
|
|
|
|
|
|
# {$nsname}->{status} status information about nserver.. it can contains |
36
|
|
|
|
|
|
|
# the error from host object or the error from nsquery object |
37
|
0
|
|
|
|
|
|
$self->{nsauth} = {}; |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# Contains the summary of test: |
40
|
|
|
|
|
|
|
# Ex: |
41
|
|
|
|
|
|
|
# OK 10 |
42
|
|
|
|
|
|
|
# E 3 |
43
|
|
|
|
|
|
|
# W 1 |
44
|
|
|
|
|
|
|
# $self->{test_summary} = {}; |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# Contains the object ref of executed tests |
47
|
0
|
|
|
|
|
|
$self->{test_obj} = {}; |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# Array Ref that contains the NSQuery objects |
50
|
0
|
|
|
|
|
|
$self->{nsquery} = []; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# Default true |
54
|
0
|
|
|
|
|
|
$self->{check_status} = 1; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Process arguments. Return false if not mandatory arguments exist |
57
|
0
|
0
|
|
|
|
|
unless ($self->_process_args(@_)) { |
58
|
0
|
|
|
|
|
|
croak("\nnserver param not found!\n"); |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# General HostsList: contains the Host object of |
64
|
|
|
|
|
|
|
# hosts outside of the domain name |
65
|
0
|
|
|
|
|
|
$self->{hostslist} = new Net::DNS::Check::HostsList( |
66
|
|
|
|
|
|
|
domain => $self->{domain}, |
67
|
|
|
|
|
|
|
config => $self->{config} |
68
|
|
|
|
|
|
|
); |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# Decode $self->{nserver} string and create $self->{nsauth} hash ref; |
72
|
|
|
|
|
|
|
# If there isn't a nserver string we try to find ns from recursion |
73
|
0
|
0
|
|
|
|
|
if ( $self->{nserver} ) { |
74
|
|
|
|
|
|
|
# Decode nserver string |
75
|
0
|
|
|
|
|
|
$self->{nsauth} = $self->_decode_ns($self->{nserver}); |
76
|
|
|
|
|
|
|
} else { |
77
|
|
|
|
|
|
|
# Search for ns record |
78
|
0
|
|
|
|
|
|
$self->{nsauth} = $self->_auth_finder(); |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# authoritative nameservers check (at least one must exists) |
82
|
0
|
0
|
|
|
|
|
unless ( keys %{$self->{nsauth}} ) { |
|
0
|
|
|
|
|
|
|
83
|
0
|
|
|
|
|
|
$self->{error} = 'NXDOMAIN'; |
84
|
0
|
|
|
|
|
|
$self->{check_status} = 0; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# if we haven't any error we proceed with _ns_query |
88
|
0
|
0
|
|
|
|
|
unless ( $self->{error} ) { |
89
|
0
|
|
|
|
|
|
$self->_ns_query(); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
0
|
|
|
|
|
|
return $self; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# Process input arguments. Only %PUBLIC_ARGS keys are |
98
|
|
|
|
|
|
|
# accepted and copy valid arguments to $self hash/object |
99
|
|
|
|
|
|
|
sub _process_args { |
100
|
0
|
|
|
0
|
|
|
my ($self, %args) = @_; |
101
|
|
|
|
|
|
|
|
102
|
0
|
|
|
|
|
|
foreach my $attr ( keys %args) { |
103
|
0
|
0
|
|
|
|
|
next unless $PUBLIC_ARGS{$attr}; |
104
|
|
|
|
|
|
|
|
105
|
0
|
|
|
|
|
|
$self->{$attr} = $args{$attr}; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# Create a default config object if no one is passed |
109
|
0
|
|
0
|
|
|
|
$self->{config} ||= new Net::DNS::Check::Config(); |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# Load a configuration from a config file. |
113
|
|
|
|
|
|
|
# The config file override the default params contained |
114
|
|
|
|
|
|
|
# in Config object or Config object passed. |
115
|
0
|
0
|
|
|
|
|
if ( $self->{config_file} ) { |
116
|
|
|
|
|
|
|
# Not yet implemented |
117
|
|
|
|
|
|
|
# $self->{config}->load_conf_file(); |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# If there is not a debug param we get it from Config |
121
|
0
|
0
|
|
|
|
|
unless (defined $self->{debug} ) { |
122
|
0
|
|
|
|
|
|
$self->{debug} = $self->{config}->debug_default(); |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
0
|
|
|
|
|
|
$self->{domain} = lc $self->{domain}; |
126
|
0
|
|
|
|
|
|
$self->{qdomain} = $self->{domain}; |
127
|
0
|
|
|
|
|
|
$self->{qdomain} =~ s/\./\\./g; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# Return the mandatory arguments |
130
|
0
|
|
|
|
|
|
return $self->{domain}; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# Decode nsstring and transform it to hash ref |
136
|
|
|
|
|
|
|
# Example: |
137
|
|
|
|
|
|
|
# "dns.foo.com=10.10.10.2,192.168.1.2;dns2.foo.com=10.11.2.2" |
138
|
|
|
|
|
|
|
# Created HASH: |
139
|
|
|
|
|
|
|
# dns.foo.com => [ 10.10.10.2, 192.168.1.2 ], |
140
|
|
|
|
|
|
|
# dns2.foo.com => [ 10.11.2.2 ] |
141
|
|
|
|
|
|
|
sub _decode_ns() { |
142
|
0
|
|
|
0
|
|
|
my $self = shift; |
143
|
0
|
|
|
|
|
|
my $nsstr = lc shift; |
144
|
|
|
|
|
|
|
|
145
|
0
|
|
|
|
|
|
my %nshash; |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# We need a regexp check of $nsstr |
148
|
0
|
0
|
|
|
|
|
if ($nsstr) { |
149
|
0
|
|
|
|
|
|
my @nsarray = split(';', $nsstr); |
150
|
0
|
|
|
|
|
|
foreach my $ns ( @nsarray ) { |
151
|
0
|
|
|
|
|
|
my ($nsname, $nsip) = split('=',$ns); |
152
|
0
|
|
|
|
|
|
my @ip; |
153
|
|
|
|
|
|
|
|
154
|
0
|
0
|
|
|
|
|
if ( $nsname ) { |
155
|
0
|
0
|
|
|
|
|
if ( $nsip ) { |
156
|
0
|
|
|
|
|
|
@ip = split(',',$nsip); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
$nshash{$nsname}->{ip_orig} = [ @ip ]; |
160
|
|
|
|
|
|
|
|
161
|
0
|
|
|
|
|
|
my $host; |
162
|
0
|
0
|
|
|
|
|
if ( $nsname =~ /^(.*\.$self->{qdomain}|$self->{qdomain})$/ ) { |
163
|
0
|
|
|
|
|
|
$host = new Net::DNS::Check::Host( |
164
|
|
|
|
|
|
|
debug => $self->{debug}, |
165
|
|
|
|
|
|
|
host => $nsname, |
166
|
|
|
|
|
|
|
config => $self->{config}, |
167
|
|
|
|
|
|
|
ip => [ @ip ], |
168
|
|
|
|
|
|
|
ip_orig => [ @ip ] |
169
|
|
|
|
|
|
|
); |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
} else { |
172
|
0
|
|
|
|
|
|
$host = $self->{hostslist}->add_host( hostname => $nsname, ip => [ @ip ], ip_orig => [ @ip ] ); |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
0
|
|
|
|
|
|
$nshash{$nsname}->{ip} = $host->get_ip(); |
176
|
0
|
|
|
|
|
|
$nshash{$nsname}->{status} = $host->error(); |
177
|
0
|
|
|
|
|
|
$nshash{$nsname}->{host} = $host; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
0
|
|
|
|
|
|
return \%nshash; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# FIXED? PRENDENDO l'authority section a volte prendiamo i root ns se |
187
|
|
|
|
|
|
|
# ad esempio il nameserver a cui poniamo lo damanda non e' autoritativo |
188
|
|
|
|
|
|
|
# per la zona |
189
|
|
|
|
|
|
|
################################### |
190
|
|
|
|
|
|
|
# This function try to find the dns servers of a domain. |
191
|
|
|
|
|
|
|
# This function doesn't use any local resolver but starts |
192
|
|
|
|
|
|
|
# query using Net::DNS::Resolver::Recurse facility. |
193
|
|
|
|
|
|
|
# The main goal of the function is to find delagated nameservers |
194
|
|
|
|
|
|
|
# (some time delegated are not the same of authoritative na) of a domain |
195
|
|
|
|
|
|
|
# asking them to auth ns of the upper domain. |
196
|
|
|
|
|
|
|
# For example if I need to find the auth nservers of foo.com domain |
197
|
|
|
|
|
|
|
# I ask them to .com auth nservers and not to foo.com nserver. |
198
|
|
|
|
|
|
|
# We found different implementation in the answer from bind8 |
199
|
|
|
|
|
|
|
# to bind9. BIND8 answers with the information contained in |
200
|
|
|
|
|
|
|
# the delegated zones, while bind9 returns the reference |
201
|
|
|
|
|
|
|
# to auth nservers of the zone and so I get the answer from them |
202
|
|
|
|
|
|
|
# (Authority section). |
203
|
|
|
|
|
|
|
# For example: if I ask for the NS records for foo.com |
204
|
|
|
|
|
|
|
# I got the answer directly from auth nservers of .com because |
205
|
|
|
|
|
|
|
# .com auth nservers (Root NS) use BIND8, but if I ask for |
206
|
|
|
|
|
|
|
# foo.it I get the ns list from auth ns of foo.it and |
207
|
|
|
|
|
|
|
# not from .it auth ns because the majority of them use BIND9. |
208
|
|
|
|
|
|
|
# This function so try to get the answer always from delegating |
209
|
|
|
|
|
|
|
# nservers. |
210
|
|
|
|
|
|
|
sub _auth_finder() { |
211
|
0
|
|
|
0
|
|
|
my $self = shift; |
212
|
|
|
|
|
|
|
|
213
|
0
|
|
|
|
|
|
my @split = split('\.', $self->{domain}); |
214
|
0
|
|
|
|
|
|
shift(@split); |
215
|
0
|
|
|
|
|
|
my $parent = join ('.', @split ); |
216
|
0
|
|
|
|
|
|
my @ns; |
217
|
|
|
|
|
|
|
my $packet; |
218
|
0
|
|
|
|
|
|
my %nshash; |
219
|
|
|
|
|
|
|
|
220
|
0
|
0
|
|
|
|
|
if ($self->{debug} > 0) { |
221
|
0
|
|
|
|
|
|
print <
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
Searching for delegated nameservers of $self->{domain} |
224
|
|
|
|
|
|
|
============================================ |
225
|
|
|
|
|
|
|
DEBUG |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# We create an object for Resolver |
230
|
0
|
|
|
|
|
|
my $resolver = Net::DNS::Resolver->new( |
231
|
|
|
|
|
|
|
recurse => 0, |
232
|
|
|
|
|
|
|
debug => ($self->{debug} > 2), |
233
|
|
|
|
|
|
|
retrans => $self->{config}->query_retrans(), |
234
|
|
|
|
|
|
|
retry => $self->{config}->query_retry(), |
235
|
|
|
|
|
|
|
tcp_timeout => $self->{config}->query_tcp_timeout(), |
236
|
|
|
|
|
|
|
); |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
# We create an object for Resolver Recurse |
240
|
0
|
|
|
|
|
|
my $recurse = Net::DNS::Resolver::Recurse->new( |
241
|
|
|
|
|
|
|
debug => ($self->{debug} > 2), |
242
|
|
|
|
|
|
|
retrans => $self->{config}->query_retrans(), |
243
|
|
|
|
|
|
|
retry => $self->{config}->query_retry(), |
244
|
|
|
|
|
|
|
tcp_timeout => $self->{config}->query_tcp_timeout(), |
245
|
|
|
|
|
|
|
); |
246
|
0
|
|
|
|
|
|
$recurse->hints( @{$self->{config}->rootservers()} ); |
|
0
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# We ask for NS records of parent domain |
249
|
0
|
|
|
|
|
|
$packet = $recurse->query_dorecursion( $parent , "NS"); |
250
|
|
|
|
|
|
|
|
251
|
0
|
0
|
|
|
|
|
if ($self->{debug} > 0) { |
252
|
0
|
|
|
|
|
|
print <
|
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
Looking for authoritative nameservers of parent domain: $parent |
255
|
|
|
|
|
|
|
DEBUG |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
|
259
|
0
|
0
|
|
|
|
|
if ($packet) { |
260
|
0
|
|
|
|
|
|
foreach my $rr ( $packet->answer ) { |
261
|
0
|
0
|
|
|
|
|
if ($rr->type eq 'NS') { |
262
|
0
|
0
|
|
|
|
|
push(@ns, $rr->nsdname()) if ($rr->nsdname); |
263
|
0
|
0
|
|
|
|
|
if ($self->{debug} > 0) { |
264
|
0
|
|
|
|
|
|
my $ns = $rr->nsdname(); |
265
|
0
|
|
|
|
|
|
print <
|
266
|
|
|
|
|
|
|
$parent NS $ns |
267
|
|
|
|
|
|
|
DEBUG |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
} else { |
272
|
|
|
|
|
|
|
# No answer from root nameserver.... link problem |
273
|
0
|
|
|
|
|
|
$self->{error} = 'NOANSWER'; |
274
|
0
|
|
|
|
|
|
return {}; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# Unresolvable domain $parent and then $self->{domain} |
278
|
0
|
0
|
|
|
|
|
unless (@ns) { |
279
|
0
|
|
|
|
|
|
$self->{error} = 'NXDOMAIN'; |
280
|
0
|
|
|
|
|
|
return {}; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
# We are looking for $self->{domain} delegated ns list (querying the authoritative |
285
|
|
|
|
|
|
|
# nameservers of father of $self->{domain}) |
286
|
|
|
|
|
|
|
# We stop to the first answer found |
287
|
0
|
|
|
|
|
|
foreach my $qns ( @ns ) { |
288
|
0
|
|
|
|
|
|
my $address; |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Try to get the address of auth nameservers of father domain |
291
|
0
|
|
|
|
|
|
$packet = $recurse->query_dorecursion( $qns , "A"); |
292
|
0
|
0
|
|
|
|
|
if ($self->{debug} > 0) { |
293
|
0
|
|
|
|
|
|
print <
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
Looking for A RR of $qns |
296
|
|
|
|
|
|
|
DEBUG |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
|
301
|
0
|
0
|
|
|
|
|
if ($packet) { |
302
|
0
|
|
|
|
|
|
foreach my $rr ( $packet->answer ) { |
303
|
0
|
0
|
|
|
|
|
if ($rr->type eq 'A') { |
304
|
0
|
|
|
|
|
|
$address = $rr->address; |
305
|
0
|
0
|
|
|
|
|
if ($self->{debug} > 0) { |
306
|
0
|
|
|
|
|
|
my $ip = $rr->address(); |
307
|
0
|
|
|
|
|
|
print <
|
308
|
|
|
|
|
|
|
$qns A $ip |
309
|
|
|
|
|
|
|
DEBUG |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
# if we found an address we try to query it, otherwise we look for another dns |
317
|
0
|
0
|
|
|
|
|
if ($address) { |
318
|
0
|
|
|
|
|
|
$resolver->nameservers( ( $address ) ); |
319
|
0
|
|
|
|
|
|
$packet = $resolver->send( $self->{domain}, "NS"); |
320
|
0
|
0
|
|
|
|
|
if ($self->{debug} > 0) { |
321
|
0
|
|
|
|
|
|
print <
|
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
Query $address for NS RR of $self->{domain} |
324
|
|
|
|
|
|
|
DEBUG |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# If we haven't an answer we try with another dns |
328
|
0
|
0
|
|
|
|
|
if ($packet) { |
329
|
0
|
|
|
|
|
|
my @nsresult; |
330
|
|
|
|
|
|
|
|
331
|
0
|
0
|
|
|
|
|
if ( $packet->answer() ) { |
332
|
0
|
|
|
|
|
|
@nsresult = grep { $_->type eq 'NS' } $packet->answer(); |
|
0
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
} else { |
334
|
0
|
|
|
|
|
|
foreach my $rr ( $packet->authority() ) { |
335
|
|
|
|
|
|
|
# We consider valid only authority information |
336
|
|
|
|
|
|
|
# about the domain we are looking for: |
337
|
|
|
|
|
|
|
# sometime we got authority section with root nameservers |
338
|
|
|
|
|
|
|
# and usually is not the answer we want (lame delegation). |
339
|
|
|
|
|
|
|
# If one $rr->name is equal to $parent probably all |
340
|
|
|
|
|
|
|
# name are equal to parent... anyway we check all of them |
341
|
0
|
0
|
0
|
|
|
|
if ( lc($rr->name) eq lc($self->{domain}) and $rr->type eq 'NS' ) { |
342
|
0
|
|
|
|
|
|
push(@nsresult, $rr); |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
#@nsresult = grep { $_->type eq 'NS' } $packet->authority(); |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
|
349
|
0
|
0
|
|
|
|
|
if (@nsresult) { |
350
|
|
|
|
|
|
|
# Splitted in two foreach loop a better debug output |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
# We get all NS RR for every nameservers found, |
353
|
|
|
|
|
|
|
# we add them to nshash and, at present, we add them to |
354
|
|
|
|
|
|
|
# general hostslist. Note: not all hosts should be added |
355
|
|
|
|
|
|
|
# to general hostslist |
356
|
0
|
|
|
|
|
|
foreach my $rr ( @nsresult ) { |
357
|
0
|
|
|
|
|
|
my $nsname = lc $rr->nsdname(); |
358
|
0
|
0
|
|
|
|
|
if ($nsname) { |
359
|
0
|
0
|
|
|
|
|
if ($self->{debug} > 0) { |
360
|
0
|
|
|
|
|
|
print " NS Found $nsname\n"; |
361
|
|
|
|
|
|
|
} |
362
|
0
|
|
|
|
|
|
$nshash{$nsname}->{ip_orig} = []; |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
0
|
0
|
|
|
|
|
if ($self->{debug} > 0 ) { |
367
|
0
|
|
|
|
|
|
print <
|
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
Searching for IP of delegated nameservers of $self->{domain} |
370
|
|
|
|
|
|
|
============================================ |
371
|
|
|
|
|
|
|
DEBUG |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
|
374
|
0
|
|
|
|
|
|
foreach my $nsname ( keys %nshash ) { |
375
|
|
|
|
|
|
|
|
376
|
0
|
|
|
|
|
|
my $host; |
377
|
0
|
0
|
|
|
|
|
if ( $nsname =~ /^(.*\.$self->{qdomain}|$self->{qdomain})$/ ) { |
378
|
0
|
|
|
|
|
|
$host = new Net::DNS::Check::Host( |
379
|
|
|
|
|
|
|
debug => $self->{debug}, |
380
|
|
|
|
|
|
|
host => $nsname, |
381
|
|
|
|
|
|
|
config => $self->{config}, |
382
|
|
|
|
|
|
|
); |
383
|
|
|
|
|
|
|
} else { |
384
|
0
|
|
|
|
|
|
$host = $self->{hostslist}->add_host( hostname => $nsname ); |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
|
387
|
0
|
|
|
|
|
|
$nshash{$nsname}->{ip} = $host->get_ip(); |
388
|
0
|
|
|
|
|
|
$nshash{$nsname}->{status} = $host->error(); |
389
|
0
|
|
|
|
|
|
$nshash{$nsname}->{host} = $host; |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
0
|
|
|
|
|
|
last; |
393
|
|
|
|
|
|
|
} else { |
394
|
0
|
0
|
|
|
|
|
if ($self->{debug} > 0) { |
395
|
0
|
|
|
|
|
|
print <
|
396
|
|
|
|
|
|
|
Not Authoritative answer |
397
|
|
|
|
|
|
|
DEBUG |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
} else { |
402
|
0
|
0
|
|
|
|
|
if ($self->{debug} > 0) { |
403
|
0
|
|
|
|
|
|
print <
|
404
|
|
|
|
|
|
|
No answer: time out |
405
|
|
|
|
|
|
|
DEBUG |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
0
|
|
|
|
|
|
return \%nshash; |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# Create NSQuery object, one for every auth nameservers |
416
|
|
|
|
|
|
|
sub _ns_query { |
417
|
0
|
|
|
0
|
|
|
my $self = shift; |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
#print Dumper $self->{nsauth}; |
420
|
0
|
|
|
|
|
|
foreach my $nsname ( keys %{ $self->{nsauth} } ) { |
|
0
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
# next if ($nsname eq 'dns3.nic.it' || $nsname eq 'dns2.nic.it' ); |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
# If we have the IP address |
425
|
0
|
0
|
|
|
|
|
if ( scalar @{$self->{nsauth}->{$nsname}->{ip}} > 0 ) { |
|
0
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
|
427
|
0
|
|
|
|
|
|
my $queryobj = new Net::DNS::Check::NSQuery( |
428
|
|
|
|
|
|
|
config => $self->{config}, |
429
|
|
|
|
|
|
|
domain => $self->{domain}, |
430
|
|
|
|
|
|
|
nserver => $nsname, |
431
|
|
|
|
|
|
|
ip => $self->{nsauth}->{$nsname}->{ip}, |
432
|
|
|
|
|
|
|
hostslist => $self->{hostslist} |
433
|
|
|
|
|
|
|
); |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
# If there is an error in Net::DNS::Check::NSQuery |
436
|
0
|
0
|
|
|
|
|
unless ( $queryobj->error() ) { |
437
|
0
|
|
|
|
|
|
push(@{$self->{nsquery}}, $queryobj); |
|
0
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
} else { |
439
|
0
|
|
|
|
|
|
$self->{check_status} = 0; |
440
|
0
|
|
|
|
|
|
$self->{nsauth}->{$nsname}->{status} = $queryobj->error(); |
441
|
0
|
0
|
|
|
|
|
if ($self->{debug} > 0 ) { |
442
|
0
|
|
|
|
|
|
my $error = $queryobj->error(); |
443
|
0
|
|
|
|
|
|
print <
|
444
|
|
|
|
|
|
|
Error: $error |
445
|
|
|
|
|
|
|
DEBUG |
446
|
|
|
|
|
|
|
} |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
} else { |
449
|
0
|
0
|
|
|
|
|
if ($self->{debug} > 0 ) { |
450
|
0
|
|
|
|
|
|
my $error; |
451
|
0
|
0
|
|
|
|
|
if ( $self->{nsauth}->{$nsname}->{host} ) { |
452
|
0
|
|
|
|
|
|
$error = $self->{nsauth}->{$nsname}->{host}->error(); |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
|
455
|
0
|
|
|
|
|
|
print <
|
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
Query for RR ANY for $self->{domain} to $nsname |
458
|
|
|
|
|
|
|
======================================================= |
459
|
|
|
|
|
|
|
$nsname IP: not found |
460
|
|
|
|
|
|
|
Error: $error |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
SKIP |
463
|
|
|
|
|
|
|
DEBUG |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
|
466
|
0
|
|
|
|
|
|
$self->{check_status} = 0; |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
sub check { |
474
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
475
|
|
|
|
|
|
|
|
476
|
0
|
|
|
|
|
|
my $result; |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
# Return and set check_status to false if nsquery array is empty |
479
|
0
|
0
|
|
|
|
|
unless ( @{$self->{nsquery}} ) { |
|
0
|
|
|
|
|
|
|
480
|
0
|
|
|
|
|
|
$self->{check_status} = 0; |
481
|
|
|
|
|
|
|
|
482
|
0
|
|
|
|
|
|
return; |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
|
486
|
0
|
|
|
|
|
|
foreach my $test_name ( keys %{ $self->{config}->test_configured() } ) { |
|
0
|
|
|
|
|
|
|
487
|
0
|
|
|
|
|
|
my $test = new Net::DNS::Check::Test( |
488
|
|
|
|
|
|
|
type => $test_name, |
489
|
|
|
|
|
|
|
nsquery => $self->{nsquery}, |
490
|
0
|
|
|
|
|
|
nsauth => [ keys %{$self->{nsauth}} ], |
491
|
|
|
|
|
|
|
config => $self->{config}, |
492
|
|
|
|
|
|
|
hostslist => $self->{hostslist} |
493
|
|
|
|
|
|
|
); |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
|
496
|
0
|
|
|
|
|
|
$self->{test_obj}->{$test_name} = $test; |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
# If test_status is true or in other word the test doesn't fail |
499
|
0
|
0
|
|
|
|
|
if ( $test->test_status() ) { |
500
|
0
|
|
|
|
|
|
$self->{test_obj}->{$test_name}->{status} = $self->{config}->ok_status(); |
501
|
0
|
|
|
|
|
|
$self->{test_summary}->{$self->{config}->ok_status()}++; |
502
|
|
|
|
|
|
|
} else { |
503
|
|
|
|
|
|
|
|
504
|
0
|
|
0
|
|
|
|
my $status = $self->{config}->test_conf( test => $test_name ) || $self->{config}->default_status();; |
505
|
|
|
|
|
|
|
|
506
|
0
|
|
|
|
|
|
$self->{test_obj}->{$test_name}->{status} = $status; |
507
|
0
|
|
|
|
|
|
$self->{test_summary}->{$status}++; |
508
|
|
|
|
|
|
|
|
509
|
0
|
0
|
|
|
|
|
if ( grep { $_ eq $status } @{$self->{config}->error_status()} ) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
510
|
0
|
|
|
|
|
|
$self->{check_status} = 0; |
511
|
|
|
|
|
|
|
} |
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
|
515
|
0
|
|
|
|
|
|
return $self->{check_status}; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
# Returns the list of executed tests or the list of executed test in a specific status |
520
|
|
|
|
|
|
|
sub test_list() { |
521
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
522
|
0
|
|
|
|
|
|
my $status = shift; |
523
|
|
|
|
|
|
|
|
524
|
0
|
0
|
0
|
|
|
|
unless ( defined $self->{test_obj} || defined $self->{config}->{$status} ) { |
525
|
0
|
|
|
|
|
|
return; |
526
|
|
|
|
|
|
|
} |
527
|
|
|
|
|
|
|
|
528
|
0
|
0
|
|
|
|
|
if ($status) { |
529
|
0
|
|
|
|
|
|
my @status_array; |
530
|
0
|
|
|
|
|
|
foreach my $test_name (keys %{$self->{test_obj}}) { |
|
0
|
|
|
|
|
|
|
531
|
0
|
0
|
|
|
|
|
if ($self->{test_obj}->{$test_name}->{status} eq $status) { |
532
|
0
|
|
|
|
|
|
push(@status_array, $test_name); |
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
} |
535
|
0
|
|
|
|
|
|
return @status_array; |
536
|
|
|
|
|
|
|
} else { |
537
|
0
|
|
|
|
|
|
return keys %{$self->{test_obj}}; |
|
0
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
} |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
# Returns the status of $test_name test |
542
|
|
|
|
|
|
|
sub test_status() { |
543
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
544
|
0
|
|
|
|
|
|
my $test_name = shift; |
545
|
|
|
|
|
|
|
|
546
|
0
|
0
|
|
|
|
|
unless ( $test_name ) { |
547
|
0
|
|
|
|
|
|
return; |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
|
550
|
0
|
|
|
|
|
|
return $self->{test_obj}->{$test_name}->{status}; |
551
|
|
|
|
|
|
|
} |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
# Returns the Net::DNS::Check::Test object of $test_name test |
554
|
|
|
|
|
|
|
sub test_object() { |
555
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
556
|
0
|
|
|
|
|
|
my $test_name = shift; |
557
|
|
|
|
|
|
|
|
558
|
0
|
0
|
|
|
|
|
unless ( $test_name ) { |
559
|
0
|
|
|
|
|
|
return; |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
|
562
|
0
|
|
|
|
|
|
return $self->{test_obj}->{$test_name}; |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
# Returns the result of Net::DNS::Check::Test::test_detail() for $test_name test |
566
|
|
|
|
|
|
|
sub test_detail() { |
567
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
568
|
0
|
|
|
|
|
|
my $test_name = shift; |
569
|
|
|
|
|
|
|
|
570
|
0
|
0
|
|
|
|
|
return unless $test_name; |
571
|
|
|
|
|
|
|
|
572
|
0
|
0
|
0
|
|
|
|
unless ( $test_name or $self->{test_obj}->{$test_name} ) { |
573
|
0
|
|
|
|
|
|
return; |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
|
576
|
0
|
|
|
|
|
|
return $self->{test_obj}->{$test_name}->test_detail(); |
577
|
|
|
|
|
|
|
} |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
# Return the number of executed test of the requested status. |
584
|
|
|
|
|
|
|
# For Example: if $status = OK the function return the number of ok tests |
585
|
|
|
|
|
|
|
# If no status = '' returns an hash containing the number of all result for |
586
|
|
|
|
|
|
|
# every level ( OK => 5, E => 1, F => 0, W => 0); |
587
|
|
|
|
|
|
|
sub test_summary() { |
588
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
589
|
0
|
|
|
|
|
|
my $status = shift; |
590
|
|
|
|
|
|
|
|
591
|
0
|
0
|
|
|
|
|
unless ( defined $self->{test_summary} ) { |
592
|
0
|
|
|
|
|
|
return {}; |
593
|
|
|
|
|
|
|
} |
594
|
|
|
|
|
|
|
|
595
|
0
|
0
|
|
|
|
|
if ( $status ) { |
596
|
0
|
|
|
|
|
|
return $self->{test_summary}->{$status}; |
597
|
|
|
|
|
|
|
} else { |
598
|
0
|
|
|
|
|
|
return $self->{test_summary}; |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
# Used to knows if the global process of checking the dns of the domain |
604
|
|
|
|
|
|
|
# is ok or not |
605
|
|
|
|
|
|
|
# It Returns true if check_status is true and if there is an error returns |
606
|
|
|
|
|
|
|
# an empty value |
607
|
|
|
|
|
|
|
sub check_status() { |
608
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
609
|
|
|
|
|
|
|
|
610
|
0
|
|
0
|
|
|
|
return ( $self->{check_status} && not $self->{error} ); |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
# Returns the array of authoritative/delegated nameserver |
615
|
|
|
|
|
|
|
sub nsauth() { |
616
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
617
|
0
|
|
|
|
|
|
my $nsname = shift; |
618
|
|
|
|
|
|
|
|
619
|
0
|
|
|
|
|
|
return keys %{$self->{nsauth}}; |
|
0
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
} |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
# This function returns status information about a nameserver |
624
|
|
|
|
|
|
|
sub ns_status() { |
625
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
626
|
0
|
|
|
|
|
|
my $nsname = shift; |
627
|
|
|
|
|
|
|
|
628
|
0
|
0
|
|
|
|
|
return unless ( $nsname ); |
629
|
|
|
|
|
|
|
|
630
|
0
|
|
|
|
|
|
return $self->{nsauth}->{$nsname}->{status}; |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
# Return the domain checked or we want to check |
635
|
|
|
|
|
|
|
sub domain() { |
636
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
637
|
|
|
|
|
|
|
|
638
|
0
|
|
|
|
|
|
return $self->{domain}; |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
sub error() { |
643
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
644
|
|
|
|
|
|
|
|
645
|
0
|
|
|
|
|
|
return $self->{error}; |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
1; |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
__END__ |