File Coverage

blib/lib/Net/DNS/Check/Host.pm
Criterion Covered Total %
statement 15 187 8.0
branch 0 78 0.0
condition 0 56 0.0
subroutine 5 19 26.3
pod 0 10 0.0
total 20 350 5.7


line stmt bran cond sub pod time code
1             package Net::DNS::Check::Host;
2            
3 1     1   12 use strict;
  1         1  
  1         27  
4              
5 1     1   5 use Net::DNS;
  1         1  
  1         87  
6 1     1   6 use Net::DNS::Resolver::Recurse;
  1         1  
  1         18  
7 1     1   5 use Net::DNS::Check::Config;
  1         1  
  1         21  
8 1     1   5 use Carp;
  1         1  
  1         2059  
9            
10             sub new {
11 0     0 0   my ($class, %param) = @_;
12            
13 0           my $self = {};
14              
15 0           $self->{class} = $class;
16              
17             # Hostname
18 0           $self->{host} = lc($param{host});
19            
20             # Nameserver IP Address to query
21 0   0       $self->{ip} = $param{ip} || [];
22              
23             # Original IP
24 0   0       $self->{ip_orig} = $param{ip_orig} || [];
25              
26             # If there isn't a config we create a new one
27 0   0       $self->{config} = $param{config} || new Net::DNS::Check::Config;
28              
29 0 0         if ( defined $param{debug} ) {
30 0           $self->{debug} = $param{debug};
31             } else {
32 0           $self->{debug} = $self->{config}->debug_default();
33             }
34              
35             # True if we want to create a statc host without query
36 0           $self->{init_only} = $param{init_only};
37              
38 0   0       $self->{qtype} = uc($param{qtype}) || 'A';
39 0           $self->{query_AAAA} = $self->{config}->query_AAAA();
40 0 0         $self->{query_AAAA} = 0 if ($self->{qtype} eq 'PTR');
41              
42              
43             # max_depth for cname resolution (endless loop protection)
44 0           $self->{depth} = 0;
45 0           $self->{max_depth} = 10;
46              
47             # This is set to 1 if we found the IP address of $self->{host} with recursion
48             # or set to 2 if we found IP with init_only
49 0           $self->{recurse} = 0;
50              
51              
52 0           bless $self, $class;
53              
54              
55 0 0 0       if ($self->{debug} && 0 ) {
56 0           my ($ips) = '';
57 0           my ($init_only) = '';
58              
59 0           $ips = join(' ', @{ $self->{ip} });
  0            
60              
61 0 0         if ( $self->{init_only} )
62             {
63 0           $init_only = 'init_only';
64             }
65              
66              
67 0           print <
68              
69              
70             ****************************************************
71             Location: $self->{class}::new $init_only
72             Looking for host: $self->{host}
73             IP to query: $ips
74             Query type: A
75             ****************************************************
76              
77             END_OF_TEXT
78             }
79              
80              
81             # init_only is used when we want to set an host object with predefined
82             # value
83 0 0         if ( ! $self->{init_only} ) {
84              
85 0 0         if ( $self->{host} ) {
86             # If we have an IP we use it to make a direct query using _queryIP function
87 0 0         if ( scalar @{$self->{ip}} > 0) {
  0            
88              
89 0           $self->_queryIP(
90             host => $self->{host},
91             ip => $self->{ip},
92             qtype => $self->{qtype}
93             );
94              
95             # Check for AAAA records
96 0 0         if ($self->{query_AAAA}) {
97 0           $self->_queryIP(
98             host => $self->{host},
99             ip => $self->{ip},
100             qtype => 'AAAA'
101             );
102             }
103             } else {
104             # If there isn't an IP we use recursion
105 0           $self->_queryIPrecurse(
106             host => $self->{host},
107             qtype => $self->{qtype}
108             );
109              
110             # Check for AAAA records
111 0 0         if ($self->{query_AAAA}) {
112 0           $self->_queryIPrecurse(
113             host => $self->{host},
114             qtype => 'AAAA'
115             );
116             }
117             }
118             } else {
119 0           confess(<<"ERROR");
120              
121             FATAL ERROR
122             ===============
123             Wrong call of constructor: $class
124             host param not found!
125              
126             ERROR
127             }
128             } else {
129 0           $self->{ipfound} = $self->{ip};
130 0           $self->{type} = 'A';
131 0           $self->{recurse} = 2;
132             }
133            
134 0           return $self;
135             }
136              
137              
138              
139             # Query for A RR for $self->{host}
140             # using $self->{ip} as resolver
141             sub _queryIP() {
142 0     0     my $self = shift;
143 0           my %param = @_;
144 0   0       my $host = $param{host} || $self->{host};
145 0   0       my $ip = $param{ip} || $self->{ip};
146 0   0       my $qtype = $param{qtype} || $self->{qtype};
147              
148 0 0 0       return undef if (! $host || ! $ip);
149              
150 0           $self->{recurse} = 0;
151              
152 0 0         if ($self->{debug} > 0) {
153 0           my $ips = join(' ', @{ $ip });
  0            
154              
155 0           print <
156             Trying to resolve $host using [ $ips ]
157             END_OF_TEXT
158            
159             }
160              
161 0           my $res = Net::DNS::Resolver->new(
162             nameservers => $ip,
163             recurse => 0,
164             debug => ($self->{debug} > 2),
165             retrans => $self->{config}->query_retrans(),
166             retry => $self->{config}->query_retry(),
167             tcp_timeout => $self->{config}->query_tcp_timeout(),
168             );
169              
170 0           my $packet = $res->send($host, $qtype);
171              
172              
173 0 0 0       if ( ! $packet && $qtype ne 'AAAA') {
174              
175 0 0         if ($self->{debug} > 0) {
176 0           my $qerror = $res->errorstring;
177 0           print <
178             Query Error: $qerror
179             END_OF_TEXT
180             }
181              
182 0           $self->{error} = 'NOANSWER';
183              
184             } else {
185 0           return $self->_decodePacket(
186             packet => $packet,
187             host => $host,
188             qtype => $qtype
189             );
190             }
191             }
192              
193              
194             #
195             # We use recursion
196             sub _queryIPrecurse() {
197 0     0     my $self = shift;
198 0           my %param = @_;
199 0   0       my $host = $param{host} || $self->{host};
200 0   0       my $qtype = $param{qtype} || $self->{qtype};
201              
202              
203 0 0         return undef if (!$host);
204              
205 0           $self->{recurse} = 1;
206              
207 0 0         if ($self->{debug} > 0) {
208 0           print <
209             Trying to resolve $host using RECURSION
210             END_OF_TEXT
211              
212             }
213              
214 0           my $res = Net::DNS::Resolver::Recurse->new(
215             recurse => 1,
216             debug => ($self->{debug} > 2),
217             retrans => $self->{config}->query_retrans(),
218             retry => $self->{config}->query_retry(),
219             tcp_timeout => $self->{config}->query_tcp_timeout(),
220             );
221              
222 0           $res->hints( @{$self->{config}->rootservers()} );
  0            
223              
224 0           my $packet = $res->query_dorecursion( $host , $qtype);
225              
226 0 0 0       if ( ! $packet && $qtype ne 'AAAA') {
227 0 0         if ($self->{debug} > 0 ) {
228 0           my $qerror = $res->errorstring;
229 0           print <
230             Query Error: $qerror
231             END_OF_TEXT
232             }
233 0           $self->{error} = 'NOANSWER';
234             } else {
235 0           return $self->_decodePacket(
236             packet => $packet,
237             host => $host,
238             qtype => $qtype
239             );
240             }
241             }
242              
243              
244              
245             sub _decodePacket() {
246 0     0     my $self = shift;
247              
248 0           my %param = @_;
249 0           my $packet = $param{packet};
250 0   0       my $host = $param{host} || $self->{host};
251 0   0       my $qtype = $param{qtype} || $self->{qtype};
252              
253 0 0         return undef if (! $packet);
254              
255 0           my $cname;
256 0           my $iscname = 0;
257 0           my $ip = [];
258              
259 0           foreach my $rr ( $packet->answer ) {
260             # Saltiamo risposte sulla base della cache
261             # ovvero risposte che non si riferiscono
262             # al record che stiamo chiedendo ($host)
263             # Attenzione nel caso di PTR questo non e' corretto
264             # 193.205.245.5 -> 5.245.205.193.in-addr.arpa
265 0 0         next if ($rr->name() ne $host);
266              
267 0 0         if ($rr->type() eq 'A') {
268 0           push(@{$ip}, $rr->address);
  0            
269 0           next;
270             }
271              
272 0 0         if ($rr->type() eq 'AAAA') {
273 0           push(@{$ip}, $rr->address);
  0            
274 0           next;
275             }
276              
277 0 0         if ($rr->type() eq 'PTR') {
278 0           push(@{$ip}, $rr->ptrdname);
  0            
279 0           next;
280             }
281              
282 0 0         if ($rr->type() eq 'CNAME') {
283 0           $cname = $rr->cname;
284 0           $iscname = 1;
285 0           next;
286             }
287             }
288              
289             # Se abbiamo un CNAME ma non IP
290             # bisogna fare la risoluzione del cname host trovato
291             # L'algoritmo e ricorsivo fintanto che non trovo un record A
292             # Viene fermata la ricerca dopo 'max_depth' ricorsioni
293 0 0 0       if ($cname && ! scalar @{$ip} && $self->{depth} <= $self->{max_depth}) {
  0   0        
294 0           $self->{depth}++;
295              
296 0 0         if ($self->{debug} > 0 ) {
297 0           print <
298             Found RR CNAME: $cname
299              
300             END_OF_TEXT
301             }
302            
303             # return undef;
304            
305             # Se abbiamo un IP di nameserver da interrogare e se il cname host
306             # fa parte del dominio che stiamo analizzando facciamo
307             # un query diretta utilizzando _queryIP altrimenti andiamo
308             # per ricorsione partendo dai root nameservers
309 0 0         if ( scalar @{$self->{ip}} > 0 ) {
  0            
310 0           $ip = $self->_queryIP(
311             host => $cname,
312             ip => $self->{ip}
313             );
314             } else {
315 0           $ip = $self->_queryIPrecurse( host => $cname );
316             }
317 0 0         $ip = [] if (!$ip); # Forziamo $ip ad essere almeno un puntatore vuoto
318             }
319              
320              
321 0 0         if ($iscname) {
322 0           $self->{type} = 'CNAME';
323 0           $self->{cname} = $cname;
324             }
325              
326 0 0         if ( scalar @{$ip} ) {
  0            
327              
328 0           $self->{type} = 'AAAA';
329              
330 0           my $ips = join(' ', @{ $ip });
  0            
331 0 0         if ($qtype eq "AAAA") {
332              
333 0           $self->{ip6found} = $ip;
334              
335 0 0 0       if ($self->{debug} > 0 && !$iscname) { # added && !$iscname for better debug output
336 0           print <
337             Found RR AAAA: $ips
338              
339             END_OF_TEXT
340             }
341              
342             } else {
343              
344 0           $self->{type} = 'A';
345 0           $self->{ipfound} = $ip;
346              
347 0 0 0       if ($self->{debug} > 0 && !$iscname) { # added && !$iscname for better debug output
348 0           print <
349             Found RR A: $ips
350            
351             END_OF_TEXT
352             }
353             }
354              
355 0           return $ip;
356              
357             } else {
358             # Nessun IP trovato
359 0           $self->{error} = 'NXDOMAIN';
360             # $self->{type} = '';
361 0 0 0       if ($self->{debug} > 0 && !$iscname) { # added && !$iscname for better debug output
362 0           print <
363             No Record Found
364              
365             END_OF_TEXT
366             }
367 0           return undef;
368             }
369             }
370              
371              
372             # Effettua la risoluzione inversa per il momento solo di IPv4
373             # il supporto del reverse IPv6 di Net::DNS e' limitato
374             sub _queryReverse() {
375 0     0     my $self = shift;
376              
377 0 0         return undef if (! $self->{ipfound});
378              
379 0           my $res = Net::DNS::Resolver::Recurse->new(
380             recurse => 1,
381             debug => ($self->{debug} > 2),
382             retrans => $self->{config}->query_retrans(),
383             retry => $self->{config}->query_retry(),
384             tcp_timeout => $self->{config}->query_tcp_timeout(),
385             );
386 0           $res->hints( @{$self->{config}->rootservers()} );
  0            
387              
388 0           foreach my $ip (@{$self->{ipfound}}) {
  0            
389 0           warn("Reverse di $ip\n");
390              
391 0           my $packet = $res->query_dorecursion( $ip , 'PTR' );
392              
393 0 0         if ($packet) {
394 0           foreach my $rr ( $packet->answer ) {
395 0 0         if ($rr->type() eq 'PTR') {
396 0           $self->{reverse}->{$ip} = $rr->ptrdname;
397             }
398             }
399             } else {
400             # Query error
401             }
402             }
403              
404 0           return 1;
405             }
406              
407              
408             # Ritorna il tipo di record trovato: A o CNAME
409             sub get_type() {
410 0     0 0   my $self = shift;
411              
412 0 0         return undef if (!$self->{type});
413            
414 0           return $self->{type};
415             }
416              
417              
418             # Ritorna una array ref degli IP trovati (se ce ne sono)
419             sub get_ip() {
420 0     0 0   my $self = shift;
421              
422 0 0         return [] if (!$self->{ipfound});
423            
424 0           return $self->{ipfound};
425             }
426              
427             # Ritorna una array ref degli IP trovati (se ce ne sono)
428             sub get_ip_orig() {
429 0     0 0   my $self = shift;
430              
431 0           return $self->{ip_orig};
432             }
433              
434              
435             # Ritorna una array ref degli IPV6 trovati (se ce ne sono)
436             sub get_ip6() {
437 0     0 0   my $self = shift;
438              
439 0 0         return [] if (!$self->{ip6found});
440            
441 0           return $self->{ip6found};
442             }
443              
444              
445            
446             sub get_cname() {
447 0     0 0   my $self = shift;
448              
449 0           return $self->{cname};
450             }
451              
452              
453             sub found() {
454 0     0 0   my $self = shift;
455              
456 0           return ( scalar @{$self->{ip}} );
  0            
457             }
458              
459             sub error() {
460 0     0 0   my $self = shift;
461              
462 0           return $self->{error};
463             }
464              
465              
466             sub get_recurse() {
467 0     0 0   my $self = shift;
468              
469 0           return $self->{recurse};
470             }
471              
472             sub get_hostname() {
473 0     0 0   my $self = shift;
474              
475 0           return $self->{host};
476             }
477              
478             1;
479              
480             __END__