1package Net::DNS::Check::NSQuery; 2 3use strict; 4 5use Net::DNS; 6use Net::DNS::Check::Host; 7use Net::DNS::Check::HostsList; 8use Net::DNS::Check::Config; 9use Carp; 10# use Data::Dumper; 11 12sub new { 13 my ($class, %param) = @_; 14 15 16 return 0 if (!$param{domain} || ! $param{nserver}); 17 18 my $self = {}; 19 20 # Nome del dominio 21 $self->{domain} = $param{domain}; 22 $self->{qdomain} = $param{domain}; 23 $self->{qdomain} =~ s/\./\\./g; 24 25 # Nome del namserver da interrogare 26 $self->{nserver} = $param{nserver}; 27 28 my $fatal = 0; 29 my $msg_error =<<ERROR; 30 31FATAL ERROR 32=============== 33Wrong call of constructor: $class 34ERROR 35 36 37 unless ( $self->{domain} ) { 38 $fatal = 1; 39 $msg_error .= "\ndomain param not found!\n"; 40 } 41 42 unless ( $self->{nserver} ) { 43 $fatal = 1; 44 $msg_error .= "\nnserver param not found!\n"; 45 } 46 47 if ( $fatal ) { 48 confess($msg_error . "\n"); 49 } 50 51 52 53 # IP del namserver da interrogare 54 # il parametro e' facoltativo. Se non viene passato 55 # viene utilizzata la ricorsione per determinare 56 # l'IP. Ovviamente per i nameserver appartenenti al dominio 57 # sul quale staimo operando DOVREBBE essere passato l'IP. 58 # Se non viene passato l'IP per quest'ultimi si utilizza 59 # la ricorsione che funzionera' solo se il dominio e' gia' 60 # esistente 61 $self->{ip} = $param{ip}; 62 63 64 $self->{config} = $param{config} || new Net::DNS::Check::Config; 65 66 if ( defined $param{debug} ) { 67 $self->{debug} = $param{debug}; 68 } else { 69 $self->{debug} = $self->{config}->debug_default(); 70 } 71 72 73 74 # External/General Hostslist. 75 $self->{hostslist} = $param{hostslist} || new Net::DNS::Check::HostsList( 76 domain => $self->{domain}, 77 debug => ($self->{debug} > 2), 78 config => $self->{config} 79 ); 80 81 # Internal HostsList 82 $self->{myhostslist} = new Net::DNS::Check::HostsList( 83 domain => $self->{domain}, 84 debug => ($self->{debug} > 2), 85 config => $self->{config} 86 ); 87 88 89 90 91 # Array of NS or MX hostnames 92 $self->{result}->{NS} = []; 93 $self->{result}->{MX} = []; 94 95 96 bless $self, $class; 97 98 if ($self->{debug} > 0 ) { 99 print <<DEBUG; 100 101Query for RR ANY for $self->{domain} to $self->{nserver} 102======================================================= 103DEBUG 104 } 105 106 107 108 # Creiamo l'oggetto resolver usando il resolver di sistema 109 $self->{res} = Net::DNS::Resolver->new( 110 recurse => 0, 111 debug => ($self->{debug} > 2), 112 retrans => $self->{config}->query_retrans, 113 retry => $self->{config}->query_retry, 114 tcp_timeout => $self->{config}->query_tcp_timeout 115 ); 116 117 118 # La add_host crea un oggetto host e lo aggiunge alla lista se non esiste 119 # o ritorna l'oggetto host gia' presente nella hostslist 120 # $self->{host} = $self->{hostslist}->add_host( $self->{nserver}, $self->{ip} ); 121 122 123 # if an ip doesn't exist we try to find it using add_host function 124 # (that it uses hostslist object functions) 125 unless ( @{$self->{ip}} ) { 126 127 if ($self->{debug} > 0 ) { 128 my $ips = join(' ', @{$self->{ip}}); 129 print <<DEBUG; 130 Search for $self->{nserver} IP 131 132DEBUG 133 } 134 135 $self->{host} = $self->_add_host( $self->{nserver} ); 136 $self->{ip} = $self->{host}->get_ip(); 137 138 } 139 140 # We found an IP address to query so we make query 141 # .... otherwise we have an error 142 if ( @{$self->{ip}} ) { 143 # $self->{type} = $type; 144 145 if ($self->{debug} > 0 ) { 146 my $ips = join(' ', @{$self->{ip}}); 147 print <<DEBUG; 148 $self->{nserver} IP : $ips 149DEBUG 150 } 151 152 # We set resolver to the ip found 153 $self->{res}->nameservers(@{ $self->{ip} }); 154 155 if ($self->{debug} > 2) { 156 print "\n\n"; 157 $self->{res}->print; 158 } 159 160 # Query of type ANY for $self->{domain} to $self->{ip} 161 $self->_queryANY(); 162 163 } else { 164 165 $self->{error} = 'NOIP'; 166 167 if ($self->{debug} > 0 ) { 168 my $ips = join(' ', @{$self->{ip}}); 169 print <<DEBUG; 170 $self->{nserver} IP : Not Found 171DEBUG 172 } 173 } 174 175 return $self; 176} 177 178 179sub _queryANY() { 180 my $self = shift; 181 182 # Creazione query per il dominio 183 my $packet = $self->{res}->send($self->{domain},'ANY'); 184 185 if ($packet) { 186 $self->{result}->{header} = $packet->header; 187 188 if ($self->{debug} > 0 ) { 189 print <<DEBUG; 190 Getting query answer 191 192DEBUG 193 } 194 195 if ($self->{debug} > 1 ) { 196 my $result = $packet->string; 197 print <<DEBUG; 198$result 199DEBUG 200 } 201 202 203 if ( $self->header_aa() && scalar $packet->answer() ) { 204 foreach my $rr ( $packet->answer ) { 205 206 if ($rr->type eq 'SOA') { 207 $self->{result}->{SOA} = $rr; 208 next; 209 } 210 211 if ($rr->type eq 'NS') { 212 push (@{$self->{result}->{NS}}, lc($rr->{nsdname})); 213 $self->_add_host( lc($rr->{nsdname}) ); 214 next; 215 } 216 217 if ($rr->type eq 'MX') { 218 push (@{$self->{result}->{MX}}, lc($rr->{exchange})); 219 $self->_add_host( lc($rr->{exchange}) ); 220 next; 221 } 222 } 223 } else { 224 $self->{error} = 'NOAUTH'; 225 } 226 } else { 227 228 # Query Error... no answer (time out) 229 $self->{error} = 'NOANSWER'; 230 231 if ($self->{debug} > 0 ) { 232 my $qerror = $self->{res}->errorstring; 233 print <<DEBUG; 234 Query Error: $qerror 235DEBUG 236 } 237 238 } 239} 240 241 242 243sub _add_host() { 244 my $self = shift; 245 my ($hostname) = shift; 246 247 unless ($hostname) { 248 confess("hostname parm not found!\n"); 249 } 250 251 my ($host, @temp); 252 253 @temp = split('\.', $self->{domain}); 254 my $domcount = scalar @temp; 255 256 @temp = split('\.', $hostname); 257 my $hostcount = (scalar @temp)-1; 258 259 260 # Questo e' da rivedere. 261 if ( ($hostname eq $self->{domain}) || $hostname =~ /.*$self->{qdomain}$/ && $domcount == $hostcount ) { 262 # Se l'hostname fa parte del dominio lo aggiungiamo alla hostslist 263 # locale e usiamo per la risluzione l'ip del namserver 264 # con cui abbiamo creato l'oggetto NSQuery 265 #print "inside "; 266 $host = $self->{myhostslist}->add_host( hostname => $hostname, ip => $self->{ip} ); 267 } else { 268 # Se l'hostname non fa parte del dominio lo aggiungiamo alla 269 # hostslist globale 270 #print "outside "; 271 $host = $self->{hostslist}->add_host( hostname => $hostname ); 272 } 273 return $host; 274} 275 276 277 278# Riporta 1 se le risposte del dns sono autoritativo 279# Riporta 0 se la risposta non e' autoritativa 280# Riporta -1 se non c'e' nessun header 281sub header_aa() { 282 my $self = shift; 283 284 return undef if (! defined $self->{result}->{header}); 285 286 return $self->{result}->{header}->aa(); 287} 288 289 290# Riporta l'oggetto Net::DNS::Header oppure false se non c'e' l'oggetto 291sub header() { 292 my $self = shift; 293 294 return 0 if (! defined $self->{result}->{header}); 295 296 return $self->{result}->{header}; 297} 298 299 300# Riporta un array vuoto se non ci sono record NS altrimenti riporta 301# l'array contenente la lista dei DNS autoritativi 302sub ns_list() { 303 my $self = shift; 304 305 return () unless defined $self->{result}->{NS}; 306 307 return @{ $self->{result}->{NS} }; 308} 309 310 311# Riporta un array vuoto se non ci sono record MX altrimenti 312# Altrimenti riporta l'array dei contenente la lista degli 313# exchange server 314sub mx_list() { 315 my $self = shift; 316 317 return () unless defined $self->{result}->{MX}; 318 319 return @{ $self->{result}->{MX} }; 320} 321 322# Riporta undef se non esiste un'oggetto SOA o non esiste un master altrimenti riporta il master nameserver che appare nel SOA 323sub soa_mname() { 324 my $self = shift; 325 326 return if (! defined $self->{result}->{SOA} ); 327 328 return lc($self->{result}->{SOA}->mname()); 329} 330 331# Riporta undef se non esiste un'oggetto SOA altrimenti 332# Riporta il serial che appare nel SOA 333sub soa_serial() { 334 my $self = shift; 335 336 return if (! defined $self->{result}->{SOA} ); 337 338 return $self->{result}->{SOA}->serial(); 339} 340 341 342 343# Riporta 0 se non esiste un'oggetto SOA o non esiste un refresh 344# Riporta il refresh che che appare nel SOA 345sub soa_refresh() { 346 my $self = shift; 347 348 return 0 if (! defined $self->{result}->{SOA} ); 349 350 return $self->{result}->{SOA}->refresh(); 351} 352 353# Riporta 0 se non esiste un'oggetto SOA o non esiste un retry 354# Riporta il retry che che appare nel SOA 355sub soa_retry() { 356 my $self = shift; 357 358 return 0 if (! defined $self->{result}->{SOA} ); 359 360 return $self->{result}->{SOA}->retry(); 361} 362 363# Riporta 0 se non esiste un'oggetto SOA o non esiste un expire 364# Riporta il expire che che appare nel SOA 365sub soa_expire() { 366 my $self = shift; 367 368 return 0 if (! defined $self->{result}->{SOA} ); 369 370 return $self->{result}->{SOA}->expire(); 371} 372 373# Riporta 0 se non esiste un'oggetto SOA o non esiste un minimum 374# Riporta il minimum che che appare nel SOA 375sub soa_minimum() { 376 my $self = shift; 377 378 return 0 if (! defined $self->{result}->{SOA} ); 379 380 return $self->{result}->{SOA}->minimum(); 381} 382 383# Riporta 0 se non esiste un'oggetto SOA o non esiste un minimum 384# Riporta il minimum che che appare nel SOA 385sub soa_mail() { 386 my $self = shift; 387 388 return 0 if (! defined $self->{result}->{SOA} ); 389 390 return $self->{result}->{SOA}->rname(); 391} 392 393# Riporta il nome del nameserver che stiamo interrogando 394sub ns_name() { 395 my $self = shift; 396 397 return $self->{nserver}; 398} 399 400 401sub error() { 402 my $self = shift; 403 404 return $self->{error}; 405} 406 407sub hostslist() { 408 my $self = shift; 409 410 return $self->{myhostslist}; 411} 412 4131; 414 415__END__ 416 417=head1 NAME 418 419Net::DNS::Check::NSQuery - Class to query authoritative nameservers for the domain name you want to check. 420 421=head1 DESCRIPTION 422 423This class is used to query nameservers for the domain name you want to check. 424 425The are several methods implemented by this class, but at present are all for internal use only and L<Net::DNS::Check> users don't need to directly create Net::DNS::Check::NSQuery object and call his methods. 426 427Anyway a complete documentation of all methods will be released as soon as possible. 428 429=head1 COPYRIGHT 430 431Copyright (c) 2005 Lorenzo Luconi Trombacchi - IIT-CNR 432 433All rights reserved. This program is free software; you may redistribute 434it and/or modify it under the same terms as Perl itself. 435 436=head1 SEE ALSO 437 438L<perl(1)> 439 440=cut 441 442 443 444