1package Net::DNS::Resolver::Base;
2#
3# $Id: Base.pm 704 2008-02-06 21:30:59Z olaf $
4#
5
6use strict;
7
8BEGIN {
9    eval { require bytes; }
10}
11
12use vars qw(
13	    $VERSION
14	    $has_inet6
15	    $AUTOLOAD
16);
17
18use Carp;
19use Config ();
20use Socket;
21use IO::Socket;
22use IO::Select;
23
24use Net::DNS;
25use Net::DNS::Packet;
26
27$VERSION = (qw$LastChangedRevision: 704 $)[1];
28
29
30#
31#  A few implementation notes wrt IPv6 support.
32#
33#  In general we try to be gracious to those stacks that do not have ipv6 support.
34#  We test that by means of the availability of Socket6 and IO::Socket::INET6
35#
36
37
38#  We have chosen to not use mapped IPv4 addresses, there seem to be
39#  issues with this; as a result we have to use sockets for both
40#  family types.  To be able to deal with persistent sockets and
41#  sockets of both family types we use an array that is indexed by the
42#  socketfamily type to store the socket handlers. I think this could
43#  be done more efficiently.
44
45
46#  inet_pton is not available on WIN32, so we only use the getaddrinfo
47#  call to translate IP addresses to socketaddress
48
49
50
51#  Set the $force_inet4_only variable inside the BEGIN block to force
52#  not to use the IPv6 stuff. You can use this for compatibility
53#  test. We do not see a need to do this from the calling code.
54
55
56# Olaf Kolkman, RIPE NCC, December 2003.
57
58
59BEGIN {
60    if (
61	 eval {require Socket6;} &&
62	 # INET6 prior to 2.01 will not work; sorry.
63	 eval {require IO::Socket::INET6; IO::Socket::INET6->VERSION("2.00");}
64	 ) {
65 	import Socket6;
66 	$has_inet6=1;
67    }else{
68 	$has_inet6=0;
69    }
70 }
71
72
73
74
75
76
77#
78# Set up a closure to be our class data.
79#
80{
81	my %defaults = (
82		nameservers	   => ['127.0.0.1'],
83		port		   => 53,
84		srcaddr        => '0.0.0.0',
85		srcport        => 0,
86		domain	       => '',
87		searchlist	   => [],
88		retrans	       => 5,
89		retry		   => 4,
90		usevc		   => 0,
91		stayopen       => 0,
92		igntc          => 0,
93		recurse        => 1,
94		defnames       => 1,
95		dnsrch         => 1,
96		debug          => 0,
97		errorstring	   => 'unknown error or no error',
98		tsig_rr        => undef,
99		answerfrom     => '',
100		querytime      => undef,
101		tcp_timeout    => 120,
102		udp_timeout    => undef,
103		axfr_sel       => undef,
104		axfr_rr        => [],
105		axfr_soa_count => 0,
106		persistent_tcp => 0,
107		persistent_udp => 0,
108		dnssec         => 0,
109		udppacketsize  => 0,  # The actual default is lower bound by Net::DNS::PACKETSZ
110		cdflag         => 1,  # this is only used when {dnssec} == 1
111		force_v4       => 0,  # force_v4 is only relevant when we have
112                                      # v6 support available
113		ignqrid        => 0,  # normally packets with non-matching ID
114                                      # or with the qr bit of are thrown away
115			              # in 'ignqrid' these packets are
116			              # are accepted.
117			              # USE WITH CARE, YOU ARE VULNARABLE TO
118			              # SPOOFING IF SET.
119			              # This is may be a temporary feature
120	);
121
122	# If we're running under a SOCKSified Perl, use TCP instead of UDP
123	# and keep the sockets open.
124	if ($Config::Config{'usesocks'}) {
125		$defaults{'usevc'} = 1;
126		$defaults{'persistent_tcp'} = 1;
127	}
128
129	sub defaults { \%defaults }
130}
131
132# These are the attributes that we let the user specify in the new().
133# We also deprecate access to these with AUTOLOAD (some may be useful).
134my %public_attr = map { $_ => 1 } qw(
135	nameservers
136	port
137	srcaddr
138	srcport
139	domain
140	searchlist
141	retrans
142	retry
143	usevc
144	stayopen
145	igntc
146	recurse
147	defnames
148	dnsrch
149	debug
150	tcp_timeout
151	udp_timeout
152	persistent_tcp
153	persistent_udp
154	dnssec
155	ignqrid
156);
157
158
159sub new {
160	my $class = shift;
161	my $self = bless({ %{$class->defaults} }, $class);
162
163	$self->_process_args(@_) if @_ and @_ % 2 == 0;
164	return $self;
165}
166
167
168
169sub _process_args {
170	my ($self, %args) = @_;
171
172	if ($args{'config_file'}) {
173		$self->read_config_file($args{'config_file'});
174	}
175
176	foreach my $attr (keys %args) {
177		next unless $public_attr{$attr};
178
179		if ($attr eq 'nameservers' || $attr eq 'searchlist') {
180
181			die "Net::DNS::Resolver->new(): $attr must be an arrayref\n" unless
182			  defined($args{$attr}) &&  UNIVERSAL::isa($args{$attr}, 'ARRAY');
183
184		}
185
186		if ($attr eq 'nameservers') {
187			$self->nameservers(@{$args{$attr}});
188		} else {
189			$self->{$attr} = $args{$attr};
190		}
191	}
192
193
194}
195
196
197
198
199
200#
201# Some people have reported that Net::DNS dies because AUTOLOAD picks up
202# calls to DESTROY.
203#
204sub DESTROY {}
205
206
207sub read_env {
208	my ($invocant) = @_;
209	my $config     = ref $invocant ? $invocant : $invocant->defaults;
210
211	$config->{'nameservers'} = [ $ENV{'RES_NAMESERVERS'} =~ m/(\S+)/g ]
212		if exists $ENV{'RES_NAMESERVERS'};
213
214	$config->{'searchlist'}  = [ split(' ', $ENV{'RES_SEARCHLIST'})  ]
215		if exists $ENV{'RES_SEARCHLIST'};
216
217	$config->{'domain'} = $ENV{'LOCALDOMAIN'}
218		if exists $ENV{'LOCALDOMAIN'};
219
220	if (exists $ENV{'RES_OPTIONS'}) {
221		foreach ($ENV{'RES_OPTIONS'} =~ m/(\S+)/g) {
222			my ($name, $val) = split(m/:/);
223			$val = 1 unless defined $val;
224			$config->{$name} = $val if exists $config->{$name};
225		}
226	}
227}
228
229#
230# $class->read_config_file($filename) or $self->read_config_file($file)
231#
232sub read_config_file {
233	my ($invocant, $file) = @_;
234	my $config            = ref $invocant ? $invocant : $invocant->defaults;
235
236
237	my @ns;
238	my @searchlist;
239
240	local *FILE;
241
242	open(FILE, "< $file") or croak "Could not open $file: $!";
243	local $/ = "\n";
244	local $_;
245
246	while (<FILE>) {
247 		s/\s*[;#].*//;
248
249		# Skip ahead unless there's non-whitespace characters
250		next unless m/\S/;
251
252		SWITCH: {
253			/^\s*domain\s+(\S+)/ && do {
254				$config->{'domain'} = $1;
255				last SWITCH;
256			};
257
258			/^\s*search\s+(.*)/ && do {
259				push(@searchlist, split(' ', $1));
260				last SWITCH;
261			};
262
263			/^\s*nameserver\s+(.*)/ && do {
264				foreach my $ns (split(' ', $1)) {
265					$ns = '0.0.0.0' if $ns eq '0';
266#					next if $ns =~ m/:/;  # skip IPv6 nameservers
267					push @ns, $ns;
268				}
269				last SWITCH;
270			};
271		    }
272		  }
273		close FILE || croak "Could not close $file: $!";
274
275		$config->{'nameservers'} = [ @ns ]         if @ns;
276		$config->{'searchlist'}  = [ @searchlist ] if @searchlist;
277	    }
278
279
280
281
282sub print { print $_[0]->string }
283
284sub string {
285	my $self = shift;
286
287	my $timeout = defined $self->{'tcp_timeout'} ? $self->{'tcp_timeout'} : 'indefinite';
288	my $hasINET6line= $has_inet6 ?" (IPv6 Transport is available)":" (IPv6 Transport is not available)";
289	my $ignqrid=$self->{'ignqrid'} ? "\n;; ACCEPTING ALL PACKETS (IGNQRID)":"";
290	return <<END;
291;; RESOLVER state:
292;;  domain       = $self->{domain}
293;;  searchlist   = @{$self->{searchlist}}
294;;  nameservers  = @{$self->{nameservers}}
295;;  port         = $self->{port}
296;;  srcport      = $self->{srcport}
297;;  srcaddr      = $self->{srcaddr}
298;;  tcp_timeout  = $timeout
299;;  retrans  = $self->{retrans}  retry    = $self->{retry}
300;;  usevc    = $self->{usevc}  stayopen = $self->{stayopen}    igntc = $self->{igntc}
301;;  defnames = $self->{defnames}  dnsrch   = $self->{dnsrch}
302;;  recurse  = $self->{recurse}  debug    = $self->{debug}
303;;  force_v4 = $self->{force_v4} $hasINET6line $ignqrid
304END
305
306}
307
308
309sub searchlist {
310	my $self = shift;
311	$self->{'searchlist'} = [ @_ ] if @_;
312	return @{$self->{'searchlist'}};
313}
314
315sub nameservers {
316    my $self   = shift;
317
318    if (@_) {
319	my @a;
320	foreach my $ns (@_) {
321	    next unless defined($ns);
322	    if ( _ip_is_ipv4($ns) ) {
323		push @a, ($ns eq '0') ? '0.0.0.0' : $ns;
324
325	    } elsif ( _ip_is_ipv6($ns) ) {
326		push @a, ($ns eq '0') ? '::0' : $ns;
327
328	    } else  {
329		my $defres = Net::DNS::Resolver->new;
330		my @names;
331
332		if ($ns !~ /\./) {
333		    if (defined $defres->searchlist) {
334			@names = map { $ns . '.' . $_ }
335			$defres->searchlist;
336		    } elsif (defined $defres->domain) {
337			@names = ($ns . '.' . $defres->domain);
338		    }
339		}
340		else {
341		    @names = ($ns);
342		}
343
344		my $packet = $defres->search($ns);
345		$self->errorstring($defres->errorstring);
346		if (defined($packet)) {
347		    push @a, cname_addr([@names], $packet);
348		}
349	    }
350	}
351
352
353	$self->{'nameservers'} = [ @a ];
354    }
355    my @returnval;
356    foreach my $ns (@{$self->{'nameservers'}}){
357	next if _ip_is_ipv6($ns) && (! $has_inet6 || $self->force_v4() );
358	push @returnval, $ns;
359    }
360
361    return @returnval;
362}
363
364sub nameserver { &nameservers }
365
366sub cname_addr {
367	my $names  = shift;
368	my $packet = shift;
369	my @addr;
370	my @names = @{$names};
371
372	my $oct2 = '(?:2[0-4]\d|25[0-5]|[0-1]?\d\d|\d)';
373
374	RR: foreach my $rr ($packet->answer) {
375		next RR unless grep {$rr->name} @names;
376
377		if ($rr->type eq 'CNAME') {
378			push(@names, $rr->cname);
379		} elsif ($rr->type eq 'A') {
380			# Run a basic taint check.
381			next RR unless $rr->address =~ m/^($oct2\.$oct2\.$oct2\.$oct2)$/o;
382
383			push(@addr, $1)
384		}
385	}
386
387
388	return @addr;
389}
390
391
392# if ($self->{"udppacketsize"}  > Net::DNS::PACKETSZ()
393# then we use EDNS and $self->{"udppacketsize"}
394# should be taken as the maximum packet_data length
395sub _packetsz {
396	my ($self) = @_;
397
398	return $self->{"udppacketsize"} > Net::DNS::PACKETSZ() ?
399		   $self->{"udppacketsize"} : Net::DNS::PACKETSZ();
400}
401
402sub _reset_errorstring {
403	my ($self) = @_;
404
405	$self->errorstring($self->defaults->{'errorstring'});
406}
407
408
409sub search {
410	my $self = shift;
411	my $name = shift || '.';
412
413	my $defdomain = $self->{domain} if $self->{defnames};
414	my @searchlist = @{$self->{searchlist}} if $self->{dnsrch};
415
416	# resolve name by trying as absolute name, then applying searchlist
417	my @list = (undef, @searchlist);
418	for ($name) {
419		# resolve name with no dots or colons by applying searchlist (or domain)
420		@list = @searchlist ? @searchlist : ($defdomain) unless  m/[:.]/;
421		# resolve name with trailing dot as absolute name
422		@list = (undef) if m/\.$/;
423	}
424
425	foreach my $suffix ( @list ) {
426	        my $fqname = join '.', $name, ($suffix || ());
427
428		print ';; search(', join(', ', $fqname, @_), ")\n" if $self->{debug};
429
430		my $packet = $self->send($fqname, @_) || return undef;
431
432		next unless ($packet->header->rcode eq "NOERROR"); # something
433								 #useful happened
434		return $packet if $packet->header->ancount;	# answer found
435		next unless $packet->header->qdcount;           # question empty?
436
437		last if ($packet->question)[0]->qtype eq 'PTR';	# abort search if IP
438	}
439	return undef;
440}
441
442
443sub query {
444	my $self = shift;
445	my $name = shift || '.';
446
447	# resolve name containing no dots or colons by appending domain
448	my @suffix = ($self->{domain} || ()) if $name !~ m/[:.]/ and $self->{defnames};
449
450	my $fqname = join '.', $name, @suffix;
451
452	print ';; query(', join(', ', $fqname, @_), ")\n" if $self->{debug};
453
454	my $packet = $self->send($fqname, @_) || return undef;
455
456	return $packet if $packet->header->ancount;	# answer found
457	return undef;
458}
459
460
461sub send {
462	my $self = shift;
463	my $packet = $self->make_query_packet(@_);
464	my $packet_data = $packet->data;
465
466
467	my $ans;
468
469	if ($self->{'usevc'} || length $packet_data > $self->_packetsz) {
470
471	    $ans = $self->send_tcp($packet, $packet_data);
472
473	} else {
474	    $ans = $self->send_udp($packet, $packet_data);
475
476	    if ($ans && $ans->header->tc && !$self->{'igntc'}) {
477			print ";;\n;; packet truncated: retrying using TCP\n" if $self->{'debug'};
478			$ans = $self->send_tcp($packet, $packet_data);
479	    }
480	}
481
482	return $ans;
483}
484
485
486
487sub send_tcp {
488	my ($self, $packet, $packet_data) = @_;
489	my $lastanswer;
490
491	my $srcport = $self->{'srcport'};
492	my $srcaddr = $self->{'srcaddr'};
493	my $dstport = $self->{'port'};
494
495	unless ( $self->nameservers()) {
496		$self->errorstring('no nameservers');
497		print ";; ERROR: send_tcp: no nameservers\n" if $self->{'debug'};
498		return;
499	}
500
501	$self->_reset_errorstring;
502
503
504      NAMESERVER: foreach my $ns ($self->nameservers()) {
505
506	      print ";; attempt to send_tcp($ns:$dstport) (src port = $srcport)\n"
507		  if $self->{'debug'};
508
509
510
511	      my $sock;
512	      my $sock_key = "$ns:$dstport";
513	      my ($host,$port);
514	      if ($self->persistent_tcp && $self->{'sockets'}[AF_UNSPEC]{$sock_key}) {
515		      $sock = $self->{'sockets'}[AF_UNSPEC]{$sock_key};
516		      print ";; using persistent socket\n"
517			if $self->{'debug'};
518		      unless ($sock->connected){
519			print ";; persistent socket disconnected (trying to reconnect)"
520			  if $self->{'debug'};
521			undef($sock);
522			$sock= $self->_create_tcp_socket($ns);
523			next NAMESERVER unless $sock;
524			$self->{'sockets'}[AF_UNSPEC]{$sock_key} = $sock;
525		      }
526
527	      } else {
528		      $sock= $self->_create_tcp_socket($ns);
529		      next NAMESERVER unless $sock;
530
531		      $self->{'sockets'}[AF_UNSPEC]{$sock_key} = $sock if
532			  $self->persistent_tcp;
533	      }
534
535
536	      my $lenmsg = pack('n', length($packet_data));
537	      print ';; sending ', length($packet_data), " bytes\n"
538		  if $self->{'debug'};
539
540	      # note that we send the length and packet data in a single call
541	      # as this produces a single TCP packet rather than two. This
542	      # is more efficient and also makes things much nicer for sniffers.
543	      # (ethereal doesn't seem to reassemble DNS over TCP correctly)
544
545
546	      unless ($sock->send( $lenmsg . $packet_data)) {
547		      $self->errorstring($!);
548		      print ";; ERROR: send_tcp: data send failed: $!\n"
549			  if $self->{'debug'};
550		      next NAMESERVER;
551	      }
552
553	      my $sel = IO::Select->new($sock);
554	      my $timeout=$self->{'tcp_timeout'};
555	      if ($sel->can_read($timeout)) {
556		      my $buf = read_tcp($sock, Net::DNS::INT16SZ(), $self->{'debug'});
557		      next NAMESERVER unless length($buf); # Failure to get anything
558		      my ($len) = unpack('n', $buf);
559		      next NAMESERVER unless $len;         # Cannot determine size
560
561		      unless ($sel->can_read($timeout)) {
562			      $self->errorstring('timeout');
563			      print ";; TIMEOUT\n" if $self->{'debug'};
564			      next;
565		      }
566
567		      $buf = read_tcp($sock, $len, $self->{'debug'});
568
569		      $self->answerfrom($sock->peerhost);
570
571		      print ';; received ', length($buf), " bytes\n"
572			  if $self->{'debug'};
573
574		      unless (length($buf) == $len) {
575				$self->errorstring("expected $len bytes, " .
576						   'received ' . length($buf));
577				next;
578			}
579
580			my ($ans, $err) = Net::DNS::Packet->new(\$buf, $self->{'debug'});
581			if (defined $ans) {
582				$self->errorstring($ans->header->rcode);
583				$ans->answerfrom($self->answerfrom);
584
585				if ($ans->header->rcode ne "NOERROR" &&
586				    $ans->header->rcode ne "NXDOMAIN"){
587					# Remove this one from the stack
588					print "RCODE: ".$ans->header->rcode ."; trying next nameserver\n" if $self->{'debug'};
589					$lastanswer=$ans;
590					next NAMESERVER ;
591
592				}
593
594			}
595			elsif (defined $err) {
596				$self->errorstring($err);
597			}
598
599			return $ans;
600		}
601		else {
602			$self->errorstring('timeout');
603			next;
604		}
605	}
606
607	if ($lastanswer){
608		$self->errorstring($lastanswer->header->rcode );
609		return $lastanswer;
610
611	}
612
613	return;
614}
615
616
617
618sub send_udp {
619	my ($self, $packet, $packet_data) = @_;
620	my $retrans = $self->{'retrans'};
621	my $timeout = $retrans;
622
623	my $lastanswer;
624
625	my $stop_time = time + $self->{'udp_timeout'} if $self->{'udp_timeout'};
626
627	$self->_reset_errorstring;
628
629 	my @ns;
630  	my $dstport = $self->{'port'};
631  	my $srcport = $self->{'srcport'};
632  	my $srcaddr = $self->{'srcaddr'};
633
634 	my @sock;
635
636
637 	if ($self->persistent_udp){
638 	    if ($has_inet6){
639 		if ( defined ($self->{'sockets'}[AF_INET6()]{'UDP'})) {
640 		    $sock[AF_INET6()] = $self->{'sockets'}[AF_INET6()]{'UDP'};
641 		    print ";; using persistent AF_INET6() family type socket\n"
642			if $self->{'debug'};
643 		}
644 	    }
645 	    if ( defined ($self->{'sockets'}[AF_INET]{'UDP'})) {
646 		$sock[AF_INET] = $self->{'sockets'}[AF_INET]{'UDP'};
647 		print ";; using persistent AF_INET() family type socket\n"
648 		    if $self->{'debug'};
649 	    }
650	}
651
652	if ($has_inet6  && ! $self->force_v4() && !defined( $sock[AF_INET6()] )){
653
654
655	    # '::' Otherwise the INET6 socket will fail.
656
657            my $srcaddr6 = $srcaddr eq '0.0.0.0' ? '::' : $srcaddr;
658
659	    print ";; Trying to set up a AF_INET6() family type UDP socket with srcaddr: $srcaddr ... "
660		if $self->{'debug'};
661
662
663	    # IO::Socket carps on errors if Perl's -w flag is turned on.
664	    # Uncomment the next two lines and the line following the "new"
665	    # call to turn off these messages.
666
667	    #my $old_wflag = $^W;
668	    #$^W = 0;
669
670	    $sock[AF_INET6()] = IO::Socket::INET6->new(
671						       LocalAddr => $srcaddr6,
672						       LocalPort => ($srcport || undef),
673						       Proto     => 'udp',
674						       );
675
676
677
678
679	    print (defined($sock[AF_INET6()])?"done\n":"failed\n") if $has_inet6 && $self->debug();
680
681	}
682
683	# Always set up an AF_INET socket.
684	# It will be used if the address familly of for the endpoint is V4.
685
686	if (!defined( $sock[AF_INET]))
687
688	{
689	    print ";; setting up an AF_INET() family type UDP socket\n"
690		if $self->{'debug'};
691
692	    #my $old_wflag = $^W;
693	    #$^W = 0;
694
695 	    $sock[AF_INET] = IO::Socket::INET->new(
696 						   LocalAddr => $srcaddr,
697 						   LocalPort => ($srcport || undef),
698 						   Proto     => 'udp',
699 						   ) ;
700
701 	    #$^W = $old_wflag;
702	}
703
704
705
706	unless (defined $sock[AF_INET] || ($has_inet6 && defined $sock[AF_INET6()])) {
707
708	    $self->errorstring("could not get socket");   #'
709	    return;
710	}
711
712	$self->{'sockets'}[AF_INET]{'UDP'} = $sock[AF_INET] if ($self->persistent_udp) && defined( $sock[AF_INET] );
713	$self->{'sockets'}[AF_INET6()]{'UDP'} = $sock[AF_INET6()] if $has_inet6 && ($self->persistent_udp) && defined( $sock[AF_INET6()]) && ! $self->force_v4();
714
715 	# Constructing an array of arrays that contain 3 elements: The
716 	# nameserver IP address, its sockaddr and the sockfamily for
717 	# which the sockaddr structure is constructed.
718
719	my $nmbrnsfailed=0;
720      NSADDRESS: foreach my $ns_address ($self->nameservers()){
721	  # The logic below determines the $dst_sockaddr.
722	  # If getaddrinfo is available that is used for both INET4 and INET6
723	  # If getaddrinfo is not avialable (Socket6 failed to load) we revert
724	  # to the 'classic mechanism
725	  if ($has_inet6  && ! $self->force_v4() ){
726	      # we can use getaddrinfo
727	      no strict 'subs';   # Because of the eval statement in the BEGIN
728	      # AI_NUMERICHOST is not available at compile time.
729	      # The AI_NUMERICHOST surpresses lookups.
730
731	      my $old_wflag = $^W; 		#circumvent perl -w warnings about 'udp'
732	      $^W = 0;
733
734
735
736	      my @res = getaddrinfo($ns_address, $dstport, AF_UNSPEC, SOCK_DGRAM,
737				    0, AI_NUMERICHOST);
738
739	      $^W=$old_wflag ;
740
741
742	      use strict 'subs';
743
744	      my ($sockfamily, $socktype_tmp,
745		  $proto_tmp, $dst_sockaddr, $canonname_tmp) = @res;
746
747	      if (scalar(@res) < 5) {
748		  die ("can't resolve \"$ns_address\" to address");
749	      }
750
751	      push @ns,[$ns_address,$dst_sockaddr,$sockfamily];
752
753	  }else{
754	      next NSADDRESS unless( _ip_is_ipv4($ns_address));
755	      my $dst_sockaddr = sockaddr_in($dstport, inet_aton($ns_address));
756	      push @ns, [$ns_address,$dst_sockaddr,AF_INET];
757	  }
758
759      }
760
761      	unless (@ns) {
762	    print "No nameservers" if $self->debug();
763	    $self->errorstring('no nameservers');
764	    return;
765	}
766
767 	my $sel = IO::Select->new() ;
768	# We allready tested that one of the two socket exists
769
770 	$sel->add($sock[AF_INET]) if defined ($sock[AF_INET]);
771 	$sel->add($sock[AF_INET6()]) if $has_inet6 &&  defined ($sock[AF_INET6()]) && ! $self->force_v4();
772
773
774	# Perform each round of retries.
775	for (my $i = 0;
776	     $i < $self->{'retry'};
777	     ++$i, $retrans *= 2, $timeout = int($retrans / (@ns || 1))) {
778
779		$timeout = 1 if ($timeout < 1);
780
781		# Try each nameserver.
782	      NAMESERVER: foreach my $ns (@ns) {
783		  next if defined $ns->[3];
784			if ($stop_time) {
785				my $now = time;
786				if ($stop_time < $now) {
787					$self->errorstring('query timed out');
788					return;
789				}
790				if ($timeout > 1 && $timeout > ($stop_time-$now)) {
791					$timeout = $stop_time-$now;
792				}
793			}
794			my $nsname = $ns->[0];
795			my $nsaddr = $ns->[1];
796   	                my $nssockfamily = $ns->[2];
797
798			# If we do not have a socket for the transport
799			# we are supposed to reach the namserver on we
800			# should skip it.
801			unless (defined ($sock[ $nssockfamily ])){
802			    print "Send error: cannot reach $nsname (".
803
804				( ($has_inet6 && $nssockfamily == AF_INET6()) ? "IPv6" : "" ).
805				( ($nssockfamily == AF_INET) ? "IPv4" : "" ).
806				") not available"
807				if $self->debug();
808
809
810			    $self->errorstring("Send error: cannot reach $nsname (" .
811					       ( ($has_inet6 && $nssockfamily == AF_INET6()) ? "IPv6" : "" ).
812					       ( ($nssockfamily == AF_INET) ? "IPv4" : "" ).
813					       ") not available"
814
815);
816			    next NAMESERVER ;
817			    }
818
819			print ";; send_udp($nsname:$dstport)\n"
820				if $self->{'debug'};
821
822			unless ($sock[$nssockfamily]->send($packet_data, 0, $nsaddr)) {
823				print ";; send error: $!\n" if $self->{'debug'};
824				$self->errorstring("Send error: $!");
825				$nmbrnsfailed++;
826				$ns->[3]="Send error".$self->errorstring();
827				next;
828			}
829
830			# See ticket 11931 but this works not quite yet
831			my $oldpacket_timeout=time+$timeout;
832			until ( $oldpacket_timeout && ($oldpacket_timeout < time())) {
833			    my @ready = $sel->can_read($timeout);
834			  SELECTOR: foreach my $ready (@ready) {
835			      my $buf = '';
836
837			      if ($ready->recv($buf, $self->_packetsz)) {
838
839				  $self->answerfrom($ready->peerhost);
840
841				  print ';; answer from ',
842				  $ready->peerhost, ':',
843				  $ready->peerport, ' : ',
844				  length($buf), " bytes\n"
845				      if $self->{'debug'};
846
847				  my ($ans, $err) = Net::DNS::Packet->new(\$buf, $self->{'debug'});
848
849				  if (defined $ans) {
850				      next SELECTOR unless ( $ans->header->qr || $self->{'ignqrid'});
851				      next SELECTOR unless  ( ($ans->header->id == $packet->header->id) || $self->{'ignqrid'} );
852				      $self->errorstring($ans->header->rcode);
853				      $ans->answerfrom($self->answerfrom);
854				      if ($ans->header->rcode ne "NOERROR" &&
855					  $ans->header->rcode ne "NXDOMAIN"){
856					  # Remove this one from the stack
857
858					  print "RCODE: ".$ans->header->rcode ."; trying next nameserver\n" if $self->{'debug'};
859					  $nmbrnsfailed++;
860					  $ns->[3]="RCODE: ".$ans->header->rcode();
861					  $lastanswer=$ans;
862					  next NAMESERVER ;
863
864				      }
865				  } elsif (defined $err) {
866				      $self->errorstring($err);
867				  }
868				  return $ans;
869			      } else {
870				  $self->errorstring($!);
871      				  print ';; recv ERROR(',
872				  $ready->peerhost, ':',
873				  $ready->peerport, '): ',
874				  $self->errorstring, "\n"
875				      if $self->{'debug'};
876				  $ns->[3]="Recv error ".$self->errorstring();
877				  $nmbrnsfailed++;
878				  # We want to remain in the SELECTOR LOOP...
879				  # unless there are no more nameservers
880				  return unless ($nmbrnsfailed < @ns);
881				  print ';; Number of failed nameservers: $nmbrnsfailed out of '.scalar @ns."\n" if $self->{'debug'};
882
883			      }
884			  } #SELECTOR LOOP
885			} # until stop_time loop
886		    } #NAMESERVER LOOP
887
888	}
889
890	if ($lastanswer){
891		$self->errorstring($lastanswer->header->rcode );
892		return $lastanswer;
893
894	}
895	if ($sel->handles) {
896	    # If there are valid hanndles than we have either a timeout or
897	    # a send error.
898	    $self->errorstring('query timed out') unless ($self->errorstring =~ /Send error:/);
899	}
900	else {
901	    if ($nmbrnsfailed < @ns){
902		$self->errorstring('Unexpected Error') ;
903	    }else{
904		$self->errorstring('all nameservers failed');
905	    }
906	}
907	return;
908}
909
910
911sub bgsend {
912	my $self = shift;
913
914	unless ($self->nameservers()) {
915		$self->errorstring('no nameservers');
916		return;
917	}
918
919		$self->_reset_errorstring;
920
921	my $packet = $self->make_query_packet(@_);
922	my $packet_data = $packet->data;
923
924	my $srcaddr = $self->{'srcaddr'};
925	my $srcport = $self->{'srcport'};
926
927
928	my (@res, $sockfamily, $dst_sockaddr);
929	my $ns_address = ($self->nameservers())[0];
930	my $dstport = $self->{'port'};
931
932
933	# The logic below determines ther $dst_sockaddr.
934	# If getaddrinfo is available that is used for both INET4 and INET6
935	# If getaddrinfo is not avialable (Socket6 failed to load) we revert
936	# to the 'classic mechanism
937	if ($has_inet6  && ! $self->force_v4()){
938
939	    my ( $socktype_tmp, $proto_tmp, $canonname_tmp);
940
941	    no strict 'subs';   # Because of the eval statement in the BEGIN
942	                      # AI_NUMERICHOST is not available at compile time.
943
944	    # The AI_NUMERICHOST surpresses lookups.
945	    my @res = getaddrinfo($ns_address, $dstport, AF_UNSPEC, SOCK_DGRAM,
946				  0 , AI_NUMERICHOST);
947
948	    use strict 'subs';
949
950	    ($sockfamily, $socktype_tmp,
951	     $proto_tmp, $dst_sockaddr, $canonname_tmp) = @res;
952
953	    if (scalar(@res) < 5) {
954		die ("can't resolve \"$ns_address\" to address (it could have been an IP address)");
955	    }
956
957	}else{
958	    $sockfamily=AF_INET;
959
960	    if (! _ip_is_ipv4($ns_address)){
961		$self->errorstring("bgsend(ipv4 only):$ns_address does not seem to be a valid IPv4 address");
962		return;
963	    }
964
965	    $dst_sockaddr = sockaddr_in($dstport, inet_aton($ns_address));
966	}
967	my @socket;
968
969	if ($sockfamily == AF_INET) {
970	    $socket[$sockfamily] = IO::Socket::INET->new(
971							 Proto => 'udp',
972							 Type => SOCK_DGRAM,
973							 LocalAddr => $srcaddr,
974							 LocalPort => ($srcport || undef),
975					    );
976	} elsif ($has_inet6 && $sockfamily == AF_INET6() ) {
977	    # Otherwise the INET6 socket will just fail
978	    my $srcaddr6 = $srcaddr eq "0.0.0.0" ? '::' : $srcaddr;
979	    $socket[$sockfamily] = IO::Socket::INET6->new(
980							  Proto => 'udp',
981							  Type => SOCK_DGRAM,
982							  LocalAddr => $srcaddr6,
983							  LocalPort => ($srcport || undef),
984					     );
985	} else {
986	    die ref($self)." bgsend:Unsoported Socket Family: $sockfamily";
987	}
988
989	unless (scalar(@socket)) {
990		$self->errorstring("could not get socket");   #'
991		return;
992	}
993
994	print ";; bgsend($ns_address : $dstport)\n" if $self->{'debug'}	;
995
996	foreach my $socket (@socket){
997	    next if !defined $socket;
998
999	    unless ($socket->send($packet_data,0,$dst_sockaddr)){
1000		my $err = $!;
1001		print ";; send ERROR($ns_address): $err\n" if $self->{'debug'};
1002
1003		$self->errorstring("Send: ".$err);
1004		return;
1005	    }
1006	    return $socket;
1007	}
1008	$self->errorstring("Could not find a socket to send on");
1009	return;
1010
1011}
1012
1013sub bgread {
1014	my ($self, $sock) = @_;
1015
1016	my $buf = '';
1017
1018	my $peeraddr = $sock->recv($buf, $self->_packetsz);
1019
1020	if ($peeraddr) {
1021		print ';; answer from ', $sock->peerhost, ':',
1022		      $sock->peerport, ' : ', length($buf), " bytes\n"
1023			if $self->{'debug'};
1024
1025		my ($ans, $err) = Net::DNS::Packet->new(\$buf, $self->{'debug'});
1026
1027		if (defined $ans) {
1028			$self->errorstring($ans->header->rcode);
1029			$ans->answerfrom($sock->peerhost);
1030		} elsif (defined $err) {
1031			$self->errorstring($err);
1032		}
1033
1034		return $ans;
1035	} else {
1036		$self->errorstring($!);
1037		return;
1038	}
1039}
1040
1041sub bgisready {
1042	my $self = shift;
1043	my $sel = IO::Select->new(@_);
1044	my @ready = $sel->can_read(0.0);
1045	return @ready > 0;
1046}
1047
1048sub make_query_packet {
1049	my $self = shift;
1050	my $packet;
1051
1052	if (ref($_[0]) and $_[0]->isa('Net::DNS::Packet')) {
1053		$packet = shift;
1054	} else {
1055		$packet = Net::DNS::Packet->new(@_);
1056	}
1057
1058	if ($packet->header->opcode eq 'QUERY') {
1059		$packet->header->rd($self->{'recurse'});
1060	}
1061
1062    if ($self->{'dnssec'}) {
1063	    # RFC 3225
1064    	print ";; Adding EDNS extention with UDP packetsize $self->{'udppacketsize'} and DNS OK bit set\n"
1065    		if $self->{'debug'};
1066
1067    	my $optrr = Net::DNS::RR->new(
1068						Type         => 'OPT',
1069						Name         => '',
1070						Class        => $self->{'udppacketsize'},  # Decimal UDPpayload
1071						ednsflags    => 0x8000, # first bit set see RFC 3225
1072				   );
1073
1074
1075	    $packet->push('additional', $optrr) unless defined  $packet->{'optadded'} ;
1076	    $packet->{'optadded'}=1;
1077	} elsif ($self->{'udppacketsize'} > Net::DNS::PACKETSZ()) {
1078	    print ";; Adding EDNS extention with UDP packetsize  $self->{'udppacketsize'}.\n" if $self->{'debug'};
1079	    # RFC 3225
1080	    my $optrr = Net::DNS::RR->new(
1081						Type         => 'OPT',
1082						Name         => '',
1083						Class        => $self->{'udppacketsize'},  # Decimal UDPpayload
1084						TTL          => 0x0000 # RCODE 32bit Hex
1085				    );
1086
1087	    $packet->push('additional', $optrr) unless defined  $packet->{'optadded'} ;
1088	    $packet->{'optadded'}=1;
1089	}
1090
1091
1092	if ($self->{'tsig_rr'}) {
1093		if (!grep { $_->type eq 'TSIG' } $packet->additional) {
1094			$packet->push('additional', $self->{'tsig_rr'});
1095		}
1096	}
1097
1098	return $packet;
1099}
1100
1101sub axfr {
1102	my $self = shift;
1103	my @zone;
1104
1105	if ($self->axfr_start(@_)) {
1106		my ($rr, $err);
1107		while (($rr, $err) = $self->axfr_next, $rr && !$err) {
1108			push @zone, $rr;
1109		}
1110		@zone = () if $err;
1111	}
1112
1113	return @zone;
1114}
1115
1116sub axfr_old {
1117	croak "Use of Net::DNS::Resolver::axfr_old() is deprecated, use axfr() or axfr_start().";
1118}
1119
1120
1121sub axfr_start {
1122	my $self = shift;
1123	my ($dname, $class) = @_;
1124	$dname ||= $self->{'searchlist'}->[0];
1125	$class ||= 'IN';
1126	my $timeout = $self->{'tcp_timeout'};
1127
1128	unless ($dname) {
1129		print ";; ERROR: axfr: no zone specified\n" if $self->{'debug'};
1130		$self->errorstring('no zone');
1131		return;
1132	}
1133
1134
1135	print ";; axfr_start($dname, $class)\n" if $self->{'debug'};
1136
1137	unless ($self->nameservers()) {
1138		$self->errorstring('no nameservers');
1139		print ";; ERROR: no nameservers\n" if $self->{'debug'};
1140		return;
1141	}
1142
1143	my $packet = $self->make_query_packet($dname, 'AXFR', $class);
1144	my $packet_data = $packet->data;
1145
1146	my $ns = ($self->nameservers())[0];
1147
1148
1149	my $srcport = $self->{'srcport'};
1150	my $srcaddr = $self->{'srcaddr'};
1151	my $dstport = $self->{'port'};
1152
1153	print ";; axfr_start nameserver = $ns\n" if $self->{'debug'};
1154	print ";; axfr_start srcport: $srcport, srcaddr: $srcaddr, dstport: $dstport\n" if $self->{'debug'};
1155
1156
1157	my $sock;
1158	my $sock_key = "$ns:$self->{'port'}";
1159
1160
1161	if ($self->persistent_tcp && $self->{'axfr_sockets'}[AF_UNSPEC]{$sock_key}) {
1162		$sock = $self->{'axfr_sockets'}[AF_UNSPEC]{$sock_key};
1163		print ";; using persistent socket\n"
1164		    if $self->{'debug'};
1165	} else {
1166		$sock=$self->_create_tcp_socket($ns);
1167
1168		return unless ($sock);  # all error messages
1169		                        # are set by _create_tcp_socket
1170
1171
1172		$self->{'axfr_sockets'}[AF_UNSPEC]{$sock_key} = $sock if
1173		    $self->persistent_tcp;
1174	}
1175
1176	my $lenmsg = pack('n', length($packet_data));
1177
1178	unless ($sock->send($lenmsg)) {
1179		$self->errorstring($!);
1180		return;
1181	}
1182
1183	unless ($sock->send($packet_data)) {
1184		$self->errorstring($!);
1185		return;
1186	}
1187
1188	my $sel = IO::Select->new($sock);
1189
1190	$self->{'axfr_sel'}       = $sel;
1191	$self->{'axfr_rr'}        = [];
1192	$self->{'axfr_soa_count'} = 0;
1193
1194	return $sock;
1195}
1196
1197
1198sub axfr_next {
1199	my $self = shift;
1200	my $err  = '';
1201
1202	unless (@{$self->{'axfr_rr'}}) {
1203		unless ($self->{'axfr_sel'}) {
1204			my $err = 'no zone transfer in progress';
1205
1206			print ";; $err\n" if $self->{'debug'};
1207			$self->errorstring($err);
1208
1209			return wantarray ? (undef, $err) : undef;
1210		}
1211
1212		my $sel = $self->{'axfr_sel'};
1213		my $timeout = $self->{'tcp_timeout'};
1214
1215		#--------------------------------------------------------------
1216		# Read the length of the response packet.
1217		#--------------------------------------------------------------
1218
1219		my @ready = $sel->can_read($timeout);
1220		unless (@ready) {
1221			$err = 'timeout';
1222			$self->errorstring($err);
1223			return wantarray ? (undef, $err) : undef;
1224		}
1225
1226		my $buf = read_tcp($ready[0], Net::DNS::INT16SZ(), $self->{'debug'});
1227		unless (length $buf) {
1228			$err = 'truncated zone transfer';
1229			$self->errorstring($err);
1230			return wantarray ? (undef, $err) : undef;
1231		}
1232
1233		my ($len) = unpack('n', $buf);
1234		unless ($len) {
1235			$err = 'truncated zone transfer';
1236			$self->errorstring($err);
1237			return wantarray ? (undef, $err) : undef;
1238		}
1239
1240		#--------------------------------------------------------------
1241		# Read the response packet.
1242		#--------------------------------------------------------------
1243
1244		@ready = $sel->can_read($timeout);
1245		unless (@ready) {
1246			$err = 'timeout';
1247			$self->errorstring($err);
1248			return wantarray ? (undef, $err) : undef;
1249		}
1250
1251		$buf = read_tcp($ready[0], $len, $self->{'debug'});
1252
1253		print ';; received ', length($buf), " bytes\n"
1254			if $self->{'debug'};
1255
1256		unless (length($buf) == $len) {
1257			$err = "expected $len bytes, received " . length($buf);
1258			$self->errorstring($err);
1259			print ";; $err\n" if $self->{'debug'};
1260			return wantarray ? (undef, $err) : undef;
1261		}
1262
1263		my $ans;
1264		($ans, $err) = Net::DNS::Packet->new(\$buf, $self->{'debug'});
1265
1266		if ($ans) {
1267			if ($ans->header->rcode ne 'NOERROR') {
1268				$self->errorstring('Response code from server: ' . $ans->header->rcode);
1269				print ';; Response code from server: ' . $ans->header->rcode . "\n" if $self->{'debug'};
1270				return wantarray ? (undef, $err) : undef;
1271			}
1272			if ($ans->header->ancount < 1) {
1273				$err = 'truncated zone transfer';
1274				$self->errorstring($err);
1275				print ";; $err\n" if $self->{'debug'};
1276				return wantarray ? (undef, $err) : undef;
1277			}
1278		}
1279		else {
1280			$err ||= 'unknown error during packet parsing';
1281			$self->errorstring($err);
1282			print ";; $err\n" if $self->{'debug'};
1283			return wantarray ? (undef, $err) : undef;
1284		}
1285
1286		foreach my $rr ($ans->answer) {
1287			if ($rr->type eq 'SOA') {
1288				if (++$self->{'axfr_soa_count'} < 2) {
1289					push @{$self->{'axfr_rr'}}, $rr;
1290				}
1291			}
1292			else {
1293				push @{$self->{'axfr_rr'}}, $rr;
1294			}
1295		}
1296
1297		if ($self->{'axfr_soa_count'} >= 2) {
1298			$self->{'axfr_sel'} = undef;
1299			# we need to mark the transfer as over if the responce was in
1300			# many answers.  Otherwise, the user will call axfr_next again
1301			# and that will cause a 'no transfer in progress' error.
1302			push(@{$self->{'axfr_rr'}}, undef);
1303		}
1304	}
1305
1306	my $rr = shift @{$self->{'axfr_rr'}};
1307
1308	return wantarray ? ($rr, undef) : $rr;
1309}
1310
1311
1312
1313
1314sub dnssec {
1315    my ($self, $new_val) = @_;
1316    if (defined $new_val) {
1317	$self->{"dnssec"} = $new_val;
1318	# Setting the udppacket size to some higher default
1319	$self->udppacketsize(2048) if $new_val;
1320    }
1321
1322    Carp::carp ("You called the Net::DNS::Resolver::dnssec() method but do not have Net::DNS::SEC installed") if $self->{"dnssec"} && ! $Net::DNS::DNSSEC;
1323    return $self->{"dnssec"};
1324};
1325
1326
1327
1328sub tsig {
1329	my $self = shift;
1330
1331	if (@_ == 1) {
1332		if ($_[0] && ref($_[0])) {
1333			$self->{'tsig_rr'} = $_[0];
1334		}
1335		else {
1336			$self->{'tsig_rr'} = undef;
1337		}
1338	}
1339	elsif (@_ == 2) {
1340		my ($key_name, $key) = @_;
1341		$self->{'tsig_rr'} = Net::DNS::RR->new("$key_name TSIG $key");
1342	}
1343
1344	return $self->{'tsig_rr'};
1345}
1346
1347#
1348# Usage:  $data = read_tcp($socket, $nbytes, $debug);
1349#
1350sub read_tcp {
1351	my ($sock, $nbytes, $debug) = @_;
1352	my $buf = '';
1353
1354	while (length($buf) < $nbytes) {
1355		my $nread = $nbytes - length($buf);
1356		my $read_buf = '';
1357
1358		print ";; read_tcp: expecting $nread bytes\n" if $debug;
1359
1360		# During some of my tests recv() returned undef even
1361		# though there wasn't an error.  Checking for the amount
1362		# of data read appears to work around that problem.
1363
1364		unless ($sock->recv($read_buf, $nread)) {
1365			if (length($read_buf) < 1) {
1366				my $errstr = $!;
1367
1368				print ";; ERROR: read_tcp: recv failed: $!\n"
1369					if $debug;
1370
1371				if ($errstr eq 'Resource temporarily unavailable') {
1372					warn "ERROR: read_tcp: recv failed: $errstr\n";
1373					warn "ERROR: try setting \$res->timeout(undef)\n";
1374				}
1375
1376				last;
1377			}
1378		}
1379
1380		print ';; read_tcp: received ', length($read_buf), " bytes\n"
1381			if $debug;
1382
1383		last unless length($read_buf);
1384		$buf .= $read_buf;
1385	}
1386
1387	return $buf;
1388}
1389
1390
1391
1392sub _create_tcp_socket {
1393	my $self=shift;
1394	my $ns=shift;
1395	my $sock;
1396
1397	my $srcport = $self->{'srcport'};
1398	my $srcaddr = $self->{'srcaddr'};
1399	my $dstport = $self->{'port'};
1400
1401	my $timeout = $self->{'tcp_timeout'};
1402	# IO::Socket carps on errors if Perl's -w flag is
1403	# turned on.  Uncomment the next two lines and the
1404	# line following the "new" call to turn off these
1405	# messages.
1406
1407	#my $old_wflag = $^W;
1408	#$^W = 0;
1409
1410	if ($has_inet6 && ! $self->force_v4() && _ip_is_ipv6($ns) ){
1411		# XXX IO::Socket::INET6 fails in a cryptic way upon send()
1412		# on AIX5L if "0" is passed in as LocalAddr
1413		# $srcaddr="0" if $srcaddr eq "0.0.0.0";  # Otherwise the INET6 socket will just fail
1414
1415		my $srcaddr6 = $srcaddr eq '0.0.0.0' ? '::' : $srcaddr;
1416
1417		$sock =
1418		    IO::Socket::INET6->new(
1419					   PeerPort =>    $dstport,
1420					   PeerAddr =>    $ns,
1421					   LocalAddr => $srcaddr6,
1422					   LocalPort => ($srcport || undef),
1423					   Proto     => 'tcp',
1424					   Timeout   => $timeout,
1425					   );
1426
1427		unless($sock){
1428			$self->errorstring('connection failed(IPv6 socket failure)');
1429			print ";; ERROR: send_tcp: IPv6 connection to $ns".
1430			    "failed: $!\n" if $self->{'debug'};
1431			return();
1432		}
1433	}
1434
1435	# At this point we have sucessfully obtained an
1436	# INET6 socket to an IPv6 nameserver, or we are
1437	# running forced v4, or we do not have v6 at all.
1438	# Try v4.
1439
1440	unless($sock){
1441		if (_ip_is_ipv6($ns)){
1442			$self->errorstring(
1443					   'connection failed (trying IPv6 nameserver without having IPv6)');
1444			print
1445			    ';; ERROR: send_tcp: You are trying to connect to '.
1446			    $ns . " but you do not have IPv6 available\n"
1447			    if $self->{'debug'};
1448			return();
1449		}
1450
1451
1452		$sock = IO::Socket::INET->new(
1453					      PeerAddr  => $ns,
1454					      PeerPort  => $dstport,
1455					      LocalAddr => $srcaddr,
1456					      LocalPort => ($srcport || undef),
1457					      Proto     => 'tcp',
1458					      Timeout   => $timeout
1459					      )
1460	    }
1461
1462	#$^W = $old_wflag;
1463
1464	unless ($sock) {
1465		$self->errorstring('connection failed');
1466		print ';; ERROR: send_tcp: connection ',
1467		"failed: $!\n" if $self->{'debug'};
1468		return();
1469	}
1470
1471	return $sock;
1472}
1473
1474
1475# Lightweight versions of subroutines from Net::IP module, recoded to fix rt#28198
1476
1477sub _ip_is_ipv4 {
1478	my @field = split /\./, shift;
1479
1480	return 0 if @field > 4;				# too many fields
1481	return 0 if @field == 0;			# no fields at all
1482
1483	foreach ( @field ) {
1484		return 0 unless /./;			# reject if empty
1485		return 0 if /[^0-9]/;			# reject non-digit
1486		return 0 if $_ > 255;			# reject bad value
1487	}
1488
1489
1490	return 1;
1491}
1492
1493
1494sub _ip_is_ipv6 {
1495
1496	for ( shift ) {
1497		my @field = split /:/;			# split into fields
1498		return 0 if (@field < 3) or (@field > 8);
1499
1500		return 0 if /::.*::/;			# reject multiple ::
1501
1502		if ( /\./ ) {				# IPv6:IPv4
1503			return 0 unless _ip_is_ipv4(pop @field);
1504		}
1505
1506		foreach ( @field ) {
1507			next unless /./;		# skip ::
1508			return 0 if /[^0-9a-f]/i;	# reject non-hexdigit
1509			return 0 if length $_ > 4;	# reject bad value
1510		}
1511	}
1512	return 1;
1513}
1514
1515
1516
1517sub AUTOLOAD {
1518	my ($self) = @_;
1519
1520	my $name = $AUTOLOAD;
1521	$name =~ s/.*://;
1522
1523	Carp::croak "$name: no such method" unless exists $self->{$name};
1524
1525	no strict q/refs/;
1526
1527
1528	*{$AUTOLOAD} = sub {
1529		my ($self, $new_val) = @_;
1530
1531		if (defined $new_val) {
1532			$self->{"$name"} = $new_val;
1533		}
1534
1535		return $self->{"$name"};
1536	};
1537
1538
1539	goto &{$AUTOLOAD};
1540}
1541
15421;
1543
1544__END__
1545
1546=head1 NAME
1547
1548Net::DNS::Resolver::Base - Common Resolver Class
1549
1550=head1 SYNOPSIS
1551
1552 use base qw/Net::DNS::Resolver::Base/;
1553
1554=head1 DESCRIPTION
1555
1556This class is the common base class for the different platform
1557sub-classes of L<Net::DNS::Resolver|Net::DNS::Resolver>.
1558
1559No user serviceable parts inside, see L<Net::DNS::Resolver|Net::DNS::Resolver>
1560for all your resolving needs.
1561
1562=head1 COPYRIGHT
1563
1564Copyright (c) 1997-2002 Michael Fuhr.
1565
1566Portions Copyright (c) 2002-2004 Chris Reinhardt.
1567Portions Copyright (c) 2005 Olaf Kolkman  <olaf@net-dns.org>
1568Portions Copyright (c) 2006 Dick Franks.
1569
1570All rights reserved.  This program is free software; you may redistribute
1571it and/or modify it under the same terms as Perl itself.
1572
1573=head1 SEE ALSO
1574
1575L<perl(1)>, L<Net::DNS>, L<Net::DNS::Resolver>
1576
1577=cut
1578
1579
1580