The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Changes 2153
META.yml 11
README 3020
TODO 35
contrib/check_zone 44
lib/Net/DNS/Nameserver.pm 158321
lib/Net/DNS/RR/CNAME.pm 32
lib/Net/DNS/RR/SRV.pm 34
lib/Net/DNS/RR/TXT.pm 228
lib/Net/DNS/RR.pm 68
lib/Net/DNS/Resolver/Base.pm 2630
lib/Net/DNS/Resolver/Recurse.pm 610
lib/Net/DNS/Resolver/UNIX.pm 33
lib/Net/DNS/Resolver/Win32.pm 47
lib/Net/DNS/Resolver.pm 46
lib/Net/DNS/Update.pm 33
lib/Net/DNS.pm 54
t/01-resolver.t 117
t/05-rr.t 1095
t/07-misc.t 33
t/08-online.t 47
t/11-inet6.t 1859
22 files changed (This is a version diff) 299790
@@ -1,6 +1,157 @@
 Revision history for Net::DNS                                     -*-text-*-
 =============================
 
+
+**** 0.55 December 14, 2005
+
+Fix Inconsistency in test
+
+   There was an inconsistency in the t/05-rr.t that got triggered by
+   the release of Net::DNS::SEC version 0.13 (when installed). That
+   has been fixed.
+
+Feature Net::DNS::Nameserver loop_once()
+
+   Uncommented the documentation of the loop_once() function and introduced
+   get_open_tcp() that reports if there are any open TCP sockets (useful
+   when using loop_once().
+
+   loop_once() itself was introduced in version 0.53_02
+
+
+Fix rt.cpan.org 16392
+
+   TCP Sockets stayed open even if not requested. This may cause the kernel
+   to run out of TCP slots. 
+
+   This bug is the reason for releasing version 0.55 shortly after 0.54.
+
+   Spotted and patched by Robert Felber.
+
+
+*** 0.54 December 7, 2005
+
+
+Fix rt.cpan.org 15947
+
+  Failure to bind a nameserver when specifying an IPv6 address.
+
+Fix rt.cpan.org 11931
+
+  Using Net-DNS 0.53 on Win XP, it is unable to retrieve the
+  nameservers when the IP address of the interface is assigned by
+  DHCP.  This is due to the DHCP assigned IP address being stored in
+  DhcpIPAddress rather than IPAddress (which is then 0.0.0.0).  Adding
+  a check of DhcpIPAddress existance and not being 0.0.0.0 fixes the
+  problem.  Applied the patch submitted by "orjan". 
+
+Fix rt.cpan.org 15119
+
+  main_loop() consumed 100% of memory, because of a bug that
+  couced loop_once() to loop ad infinitum.
+
+Fix rt.cpan.org 15299
+
+  Defining multiple constants with 'use constant { BLA => 1, FOO =>2 };
+  is a backwards incompatible feature. Thanks to Ian White for spotting and
+  fixing this.
+
+*** 0.53_02 Oct 18, 2005
+
+
+
+Fix rt.cpan.org 14046
+
+  RRSIGs verify and create failed fror a number of RR types. The 
+  error message showed something like:
+      Can't call method "dn_comp" on an undefined value 
+  This was caused by an ommission in the _canonicalRdata() method
+  in Net::DNS::RR that was inherited by all failing RR types.
+
+  Code was added to t/05-rr.t that will test signature creation
+  if Net::DNS::SEC is available and can be loaded.
+
+
+Feature async nameserver behaviour.
+  
+   In rt.cpan.org 14622 Robert Stone suggested:
+
+      The fact that it needs to take over the main runnning thread
+      limits its audience.  Since many daemon programs are already
+      driven by a top level select loop, it seems useful to provide an
+      API for the user to integrate Net::DNS::Nameserver processing to
+      their own select loop.
+
+   He also supplied example code for which he is hereby acknowledged.
+   The patch was not used because simultaneously Robert Martin-Legene
+   supplied a patch to Nameservers.pm that allowed the same async
+   functionality through the use of loop_once method. Robert M-L's 
+   code also carefully manages the TCP sockets, so that they can 
+   deal with AXFRs.
+
+   Robert S. has been so kind to review Robert M-L's code and is hereby
+   kindly acknowledged.
+
+   NB. Since the code may be subject to change the documentation of the
+   loop_once method has been commented out.
+
+
+Fix bgsend srcaddr for IPv6 Achim Adam previously noticed that the
+  source address wildard "::" works provides better portability than
+  "0". We forgot to fix the bgsend() part earlier.
+
+
+
+Fix rt.cpan.org 14624 
+
+  Fixed documentation of Nameserver.pm Replyhandler and fixed a bug
+  that prevented the peerhost to be set.
+
+Fix rt.cpan.org 14700
+
+  mistyped _name2wire helper function name. Noticed and patched by Simon 
+  Josefsson.
+
+Fix rt.cpan.org 13944
+
+  Terminating dot not printed when printing SRV record. The SRV dname should
+  be printed as FQDN, that is, including the dot at the end.
+  Acknowledgements Jakob Schlyter. 
+
+  While adding the "dot" I noticed that in the fileformat parsing code
+  there might be theoretical corner cases where rdata elements are not
+  properly read. The code needs an audit for this.
+
+Fix srcport for socket creation in bgsend method
+
+   Lionel Cons noted and patched a small bug in bgsocket creation code for
+   lib/Net/DNS/Resolver/Base.pm
+
+
+*** 0.53_01 July 31, 2005
+
+Fix rt.cpan.org 13809
+
+   "Phar" noted that the peerhost is never passed to the make_reply function
+   in nameserver.pm and provided the trivial patch. 
+
+Fix rt.cpan.org 13922
+
+    Fixed a problem with persistent TCP sockets which was introdcuced
+    because of using the address family as an index to the array of
+    persistent sockets. 
+
+    Used AF_UNSPEC for the array index for the TCP socket; just to choose
+    a number. The key to the persistent sockets is the remote nameserver:port 
+    combination.
+
+    Acknowledgements to Mike Mitchell for reporting the bug and testing
+    the solution.
+
+Feat t/01-resolve will not try to do tests from private IP space; hopefully
+    that cuts down on the number of false positives.
+
+
 *** 0.53 July 22, 2005
 
 Fix rt.cpan.org 13669
@@ -15,7 +166,7 @@ Fix rt.cpan.org 13534
 
 Doc rt.cpan.org 13387
 
-    Documented the BUG caught by Robert Martin-Legène;
+    Documented the BUG caught by Robert Martin-Legène
     Net::DNS::Nameserver running with multiple IP interfaces might
     violate section 4 of RFC2181.
 
@@ -836,4 +987,4 @@ Olaf Kolkman <olaf@net-dns.org>
 Chris Reinhardt 
 Michael Fuhr 
 
-$Id: Changes 468 2005-07-22 12:12:55Z olaf $
+$Id: Changes 536 2005-12-14 10:06:12Z olaf $
@@ -1,7 +1,7 @@
 # http://module-build.sourceforge.net/META-spec.html
 #XXXXXXX This is a prototype!!!  It will change in the future!!! XXXXX#
 name:         Net-DNS
-version:      0.53
+version:      0.55
 version_from: lib/Net/DNS.pm
 installdirs:  site
 requires:
@@ -89,23 +89,6 @@ For IPv6 support you will need Socket6 and IO::Socket::INET6. The availability
 of these is tested at runtime.
 
 
-Net::DNS has been tested with the following:
-
-    Perl 5.8.2
-
-    Version of Socket distributed with Perl 5.8.2
-    Version of IO::Socket distributed with Perl 5.8.2
-    Version of IO::Select distributed with Perl 5.8.2
-    Version of FileHandle distributed with Perl 5.8.2
-
-	Perl 5.6.1
-	
-    Version of Socket distributed with Perl 5.6.1
-    Version of IO::Socket distributed with Perl 5.6.1
-    Version of IO::Select distributed with Perl 5.6.1
-    Version of FileHandle distributed with Perl 5.6.1
-
-
 You can obtain the latest version of Perl from:
 
     http://www.cpan.org/src/
@@ -183,12 +166,13 @@ for more information and examples, please see the Net::DNS::Update
 manual page.
 
 Please note that there are some bugs in the BIND 8.1-REL nameserver
-that can cause it to dump core when receiving certain dynamic
-updates, so if you have problems using Net::DNS that might be the
-cause.  If you're running BIND 9, you should be using the latest
-version available from the Internet Software Consortium (ISC,
-www.isc.org) or from your OS vendor.  As of this writing, the latest
-production version of BIND 9 available from the ISC is 9.2.3.
+that can cause it to dump core when receiving certain dynamic updates,
+so if you have problems using Net::DNS that might be the cause.  If
+you're running BIND 9, you should be using the latest version
+available from the Internet Software Consortium (ISC, www.isc.org) or
+from your OS vendor.  As of this writing, the latest production
+version of BIND 9 available from the ISC is 9.3.1. (with 9.3.2 at the
+horizon)
 
 Here's a summary of the update semantics for those interested (see
 RFC 2136 for details):
@@ -282,6 +266,8 @@ Portions Copyright (c) 2002-2004 Chris Reinhardt.
 
 Portions Copyright (c) 2005 Olaf Kolkman (RIPE NCC)
 
+Portions Copyright (c) 2005 Olaf Kolkman (NLnet Labs)
+
 All rights reserved.  This program is free software; you may redistribute
 it and/or modify it under the same terms as Perl itself.
 
@@ -289,8 +275,8 @@ it and/or modify it under the same terms as Perl itself.
 12. AUTHOR INFORMATION
 ----------------------
 
-Net::DNS is currently maintained by:
-        Olaf Kolkman
+Net::DNS is currently maintained at NLnet Labs (www.nlnetlabs.nl) by:
+        Olaf Kolkman and his team.
 	olaf at net-dns.org
 
 Between 2002 and 2004 Net::DNS was maintained by:
@@ -340,10 +326,11 @@ and not a conscious act of omission.
 
 Thanks to Larry Wall and all who have made Perl possible.
 
-Thanks to Paul Albitz and Cricket Liu for allowing me to write the
-Net::DNS section in the programming chapter of _DNS and BIND_, 3rd
-Edition.  This chapter in earlier editions was very helpful while
-I was developing Net::DNS, and I was proud to contribute to it.
+Thanks to Paul Albitz and Cricket Liu for allowing me [OK: that's
+Mike] to write the Net::DNS section in the programming chapter of _DNS
+and BIND_, 3rd Edition.  This chapter in earlier editions was very
+helpful while I was developing Net::DNS, and I was proud to contribute
+to it.
 
 Thanks to Paul Vixie and all who have worked on the BIND nameserver,
 which I've used exclusively while developing Net::DNS.
@@ -351,6 +338,9 @@ which I've used exclusively while developing Net::DNS.
 Thanks to Andreas Gustafsson for DNAME support, and for all the work
 he has done on BIND 9.
 
+Olaf acknowledges the RIPE NCC for allowing Net::DNS maintenance to
+take place as part of 'the job'.
+
 Thanks to the team that maintains ethereal, without its marvelous
 interface debuging of bugs in wireformat would be so much more
 difficult.
@@ -360,4 +350,4 @@ I've always developed Net::DNS using open-source systems and I'm
 proud to make Net::DNS freely available to the world 
 
 ----
-$Id: README 293 2005-05-24 07:34:28Z olaf $
+$Id: README 519 2005-12-07 12:30:16Z olaf $
@@ -1,7 +1,10 @@
 To Do list for Net::DNS
 =======================
 
-( While taking over Net::DNS maintenance I've also inhereted this TODO list.
+
+
+(
+  While taking over Net::DNS maintenance I've also inhereted this TODO list.
   I have not yet "updated" the TODO list to reflect my feeling of priority 
   with these items. 
 
@@ -98,9 +101,8 @@ To Do list for Net::DNS
 * Consider rewriting the packet-parsing code in C for increased speed,
   or possibly going back to using Dave Shield's resparse library.
 
-
 * And a number of things listed on the request tracker rt.cpan.org.
 
 
 ---
-$Id: TODO 468 2005-07-22 12:12:55Z olaf $
+$Id: TODO 519 2005-12-07 12:30:16Z olaf $
@@ -1,5 +1,5 @@
 #!/usr/local/bin/perl -w
-# $Id: check_zone 264 2005-04-06 09:16:15Z olaf $
+# $Id: check_zone 479 2005-07-31 14:19:41Z olaf $
 
 =head1 NAME
 
@@ -166,12 +166,12 @@ sub check_domain {
         $res->nameservers( $ns );
         
         my @local_zone = $res->axfr( $domain, $class );
-        unless( defined( @local_zone ) && @local_zone ) {
+        unless( @local_zone ) {
     
             warn "Zone transfer from '", $ns, "' failed: ", 
                     $res->errorstring, "\n";
         }
-        @zone = @local_zone if( ! defined( @zone ) && ! @zone );
+        @zone = @local_zone if( ! @zone );
     }
 
     # Query each name server for the zone
@@ -691,7 +691,7 @@ sub types4name {
     # return the RR types of ???
     #
     
-    push @rr_types, ( '???' ) if( ! defined( @rr_types ) || ! @rr_types );
+    push @rr_types, ( '???' ) if( ! @rr_types );
 
     return @rr_types;
 }
@@ -1,14 +1,8 @@
 package Net::DNS::Nameserver;
 #
-# $Id: Nameserver.pm 460 2005-07-15 19:18:22Z olaf $
+# $Id: Nameserver.pm 535 2005-12-13 12:08:13Z olaf $
 #
 
-
-BEGIN { 
-    eval { require bytes; }
-} 
-
-
 use Net::DNS;
 use IO::Socket;
 use IO::Socket::INET;
@@ -22,7 +16,12 @@ use vars qw($VERSION
  	    $DEFAULT_PORT
  	    );
 
-$VERSION = (qw$LastChangedRevision: 460 $)[1];
+use constant	STATE_ACCEPTED => 1;
+use constant	STATE_GOT_LENGTH => 2;
+use constant	STATE_SENDING => 3;
+use Net::IP qw(ip_is_ipv4 ip_is_ipv6 ip_normalize); 
+
+$VERSION = (qw$LastChangedRevision: 535 $)[1];
 
 #@DEFAULT_ADDR is set in the BEGIN block 
 $DEFAULT_PORT=53;
@@ -64,7 +63,6 @@ sub new {
 		return;
 	}
 
-
  	my $addr;
  	my $port;
  	
@@ -74,109 +72,71 @@ sub new {
   
  	my @localaddresses = @{$self{"LocalAddr"}};
  	
-  
-  
  	my @sock_tcp;   # All the TCP sockets we will listen to.
  	my @sock_udp;   # All the UDP sockets we will listen to.
-  
+
+	# while we are here, print incomplete lines as they come along.
+	local $| = 1 if $self{"Verbose"};
+
  	foreach my $localaddress (@localaddresses){
- 	    print "Dealing with $localaddress...\n" if $self{"Verbose"};
-  
- 	    my $sock_tcp ;
   
+ 	    $port = $self{"LocalPort"} || $DEFAULT_PORT;
+
  	    if ($has_inet6){
-  
  		$addr = $localaddress;
- 		$port = $self{"LocalPort"} || $DEFAULT_PORT;
-  
+	    }else{
+ 		$addr = $localaddress || inet_ntoa($DEFAULT_ADDR[0]);
+	    }
+
+	    # If not, it will do DNS lookups trying to resolve it as a hostname
+	    # We could also just set it to undef?
+
+	    $addr = inet_ntoa($addr) unless (ip_is_ipv4($addr) || ip_is_ipv6($addr));
+
+	    # Pretty IP-addresses, if they are otherwise binary.
+	    my $addrname = $addr;
+	    $addrname = inet_ntoa($addrname) unless $addrname =~ /^[\w\.:\-]+$/;
+
+ 	    print "Setting up listening sockets for $addrname...\n" if $self{"Verbose"};
+
+ 	    print "Creating TCP socket for $addrname - " if $self{"Verbose"};
   
- 		#--------------------------------------------------------------------------
- 		# Create the IPv4/IPv6 ONLY TCP socket.
- 		#--------------------------------------------------------------------------
+ 	    #--------------------------------------------------------------------------
+ 	    # Create the TCP socket.
+ 	    #--------------------------------------------------------------------------
  		
- 		print "creating TCP socket for $localaddress" if $self{"Verbose"};
- 
- 		$sock_tcp  = IO::Socket::INET6->new(
+	    my $sock_tcp = inet_new(
  						    LocalAddr => $addr,
  						    LocalPort => $port,
- 						    Listen	  => 5,
+ 						    Listen	  => 64,
  						    Proto	  => "tcp",
  						    Reuse	  => 1,
  						    );
- 
- 
- 
- 		if (! $sock_tcp) {
- 		    cluck "couldn't create TCP socket: $!";
- 		    return;
- 		}
- 		push @sock_tcp, $sock_tcp;
- 		print "done.\n" if $self{"Verbose"};
- 		
- 		
- 	    }else{
- 		$addr = $localaddress || inet_ntoa($DEFAULT_ADDR[0]);
- 		$port = $self{"LocalPort"} || $DEFAULT_PORT;
- 
- 		
- 		#--------------------------------------------------------------------------
- 		# Create the IPv4 ONLY TCP socket.
- 		#--------------------------------------------------------------------------
- 		
- 		print "creating TCP socket for $localaddress" if $self{"Verbose"};
- 
- 
- 		$sock_tcp  = IO::Socket::INET->new(
- 						   LocalAddr => $addr,
- 						   LocalPort => $port,
- 						   Listen	  => 5,
- 						   Proto	  => "tcp",
- 						   Reuse	  => 1,
- 						   );
- 		
- 		
- 		if (! $sock_tcp) {
- 		    cluck "couldn't create TCP socket: $!";
- 		    return;
- 		}
- 		push @sock_tcp, $sock_tcp;
- 		print "done.\n" if $self{"Verbose"};
- 		
-  
-  
+ 	    if (! $sock_tcp) {
+ 	        cluck "Couldn't create TCP socket: $!";
+ 	        return;
  	    }
- 	    
- 	    
+ 	    push @sock_tcp, $sock_tcp;
+ 	    print "done.\n" if $self{"Verbose"};
  	    
  	    #--------------------------------------------------------------------------
  	    # Create the UDP Socket.
  	    #--------------------------------------------------------------------------
  	    
- 	    print "creating UDP socket..." if $self{"Verbose"};
+ 	    print "Creating UDP socket for $addrname - " if $self{"Verbose"};
  	    
- 	    my $sock_udp;
- 	    if ($has_inet6){
- 		$sock_udp = IO::Socket::INET6->new(
+ 	    my $sock_udp = inet_new(
  						   LocalAddr => $addr,
  						   LocalPort => $port,
  						   Proto => "udp",
  						   );
  		
- 	    }else{
- 		$sock_udp = IO::Socket::INET->new(
- 						  LocalAddr => $addr,
- 						  LocalPort => $port,
- 						  Proto => "udp",
- 						  );
- 	    }
  	    if (!$sock_udp) {
- 		cluck "couldn't create UDP socket: $!";
+ 		cluck "Couldn't create UDP socket: $!";
  		return;
  	    }
- 	    
-
- 	    print "done.\n" if $self{"Verbose"};
  	    push @sock_udp, $sock_udp;
+ 	    print "done.\n" if $self{"Verbose"};
  	}
  	
   	#--------------------------------------------------------------------------
@@ -202,6 +162,18 @@ sub new {
 }
 
 #------------------------------------------------------------------------------
+# inet_new - Calls the constructor in the correct module for making sockets.
+#------------------------------------------------------------------------------
+
+sub inet_new {
+	if ($has_inet6) {
+	    return IO::Socket::INET6->new(@_);
+	} else {
+	    return IO::Socket::INET->new(@_);
+	}
+}
+  
+#------------------------------------------------------------------------------
 # make_reply - Make a reply packet.
 #------------------------------------------------------------------------------
 
@@ -236,7 +208,7 @@ sub make_reply {
 	if ($query->header->opcode eq "QUERY") {
 		if ($query->header->qdcount == 1) {
 			print "query ", $query->header->id,
-			": ($qname, $qclass, $qtype)..." if $self->{"Verbose"};
+			": ($qname, $qclass, $qtype) - " if $self->{"Verbose"};
 			
 			my ($rcode, $ans, $auth, $add);
 			
@@ -285,40 +257,98 @@ sub make_reply {
 }
 
 #------------------------------------------------------------------------------
+# readfromtcp - read from a TCP client
+#------------------------------------------------------------------------------
+
+sub readfromtcp {
+  	my ($self, $sock) = @_;
+	return -1 unless defined $self->{"_tcp"}{$sock};
+	my $peer = $self->{"_tcp"}{$sock}{"peer"};
+	my $charsread = $sock->sysread(
+	    $self->{"_tcp"}{$sock}{"inbuffer"}, 
+	    16384);
+	$self->{"_tcp"}{$sock}{"timeout"} = time()+120; # Reset idle timer
+	print "Received $charsread octets from $peer\n" if $self->{"Verbose"};
+	if ($charsread == 0) { # 0 octets means socket has closed
+	  print "Connection to $peer closed or lost.\n" if $self->{"Verbose"};
+	  $self->{"select"}->remove($sock);
+	  $sock->close();
+	  delete $self->{"_tcp"}{$sock};
+	  return $charsread;
+	}
+	return $charsread;
+}
+
+#------------------------------------------------------------------------------
 # tcp_connection - Handle a TCP connection.
 #------------------------------------------------------------------------------
 
 sub tcp_connection {
 	my ($self, $sock) = @_;
-	my $peerhost = $sock->peerhost;
-
-	print "TCP connection from ", $sock->peerhost, ":", $sock->peerport, "\n"
-	  if $self->{"Verbose"};
-		
-	while (1) {
-		my $buf;
-		print "reading message length..." if $self->{"Verbose"};
-		$sock->read($buf, 2) or last;
-		print "done\n" if $self->{"Verbose"};
-
-		my ($msglen) = unpack("n", $buf);
-		print "expecting $msglen bytes..." if $self->{"Verbose"};
-		$sock->read($buf, $msglen);
-		print "got ", length($buf), " bytes\n" if $self->{"Verbose"};
-
-		my $query = Net::DNS::Packet->new(\$buf);
-		
-		my $reply = $self->make_reply($query, $peerhost) || last;
-		my $reply_data = $reply->data;
-
-		print "writing response..." if $self->{"Verbose"};
-		$sock->write(pack("n", length($reply_data)) . $reply_data);
-		print "done\n" if $self->{"Verbose"};
+	
+	if (not $self->{"_tcp"}{$sock}) {
+		# We go here if we are called with a listener socket.
+		my $client = $sock->accept;
+		if (not defined $client) {
+	  		print "TCP connection closed by peer before we could accept it.\n" if $self->{"Verbose"};
+	  		return 0;
+		}
+		my $peerport= $client->peerport;
+		my $peerhost = $client->peerhost;
+
+		print "TCP connection from $peerhost:$peerport\n" if $self->{"Verbose"};
+		$client->blocking(0);
+		$self->{"_tcp"}{$client}{"peer"} = "tcp:".$peerhost.":".$peerport;
+		$self->{"_tcp"}{$client}{"state"} = STATE_ACCEPTED;
+		$self->{"_tcp"}{$client}{"socket"} = $client;
+		$self->{"_tcp"}{$client}{"timeout"} = time()+120;
+ 		$self->{"select"}->add($client);
+		# After we accepted we will look at the socket again 
+		# to see if there is any data there. ---Olaf
+		$self->loop_once(0);
+	} else {
+		# We go here if we are called with a client socket
+		my $peer = $self->{"_tcp"}{$sock}{"peer"};
+
+		if ($self->{"_tcp"}{$sock}{"state"} == STATE_ACCEPTED) {
+		  if (not $self->{"_tcp"}{$sock}{"inbuffer"} =~ s/^(..)//s) {
+		    return; # Still not 2 octets ready
+		  }
+		  my $msglen = unpack("n", $1);
+		  print "Removed 2 octets from the input buffer from $peer.\n".
+		  	"$peer said his query contains $msglen octets.\n"
+		  	if $self->{"Verbose"};
+		  $self->{"_tcp"}{$sock}{"state"} = STATE_GOT_LENGTH;
+		  $self->{"_tcp"}{$sock}{"querylength"} = $msglen;
+		}
+		# Not elsif, because we might already have all the data
+		if ($self->{"_tcp"}{$sock}{"state"} == STATE_GOT_LENGTH) {
+			# return if not all data has been received yet.
+		  	return if $self->{"_tcp"}{$sock}{"querylength"} > length $self->{"_tcp"}{$sock}{"inbuffer"};
+
+			my $qbuf = substr($self->{"_tcp"}{$sock}{"inbuffer"}, 0, $self->{"_tcp"}{$sock}{"querylength"});
+			substr($self->{"_tcp"}{$sock}{"inbuffer"}, 0, $self->{"_tcp"}{$sock}{"querylength"}) = "";
+		  	my $query = Net::DNS::Packet->new(\$qbuf);
+		  	my $reply = $self->make_reply($query, $sock->peerhost);
+		  	if (not defined $reply) {
+		    		print "I couldn't create a reply for $peer. Closing socket.\n"
+		    			if $self->{"Verbose"};
+				$self->{"select"}->remove($sock);
+				$sock->close();
+				delete $self->{"_tcp"}{$sock};
+				return;
+		  	}
+		  	my $reply_data = $reply->data;
+			my $len = length $reply_data;
+			$self->{"_tcp"}{$sock}{"outbuffer"} = pack("n", $len) . $reply_data;
+			print "Queued ",
+				length $self->{"_tcp"}{$sock}{"outbuffer"},
+				" octets to $peer\n"
+				if $self->{"Verbose"};
+			# We are done.
+		  	$self->{"_tcp"}{$sock}{"state"} = STATE_SENDING;
+		}
 	}
-
-	print "closing connection..." if $self->{"Verbose"};
-	$sock->close;
-	print "done\n" if $self->{"Verbose"};
 }
 
 #------------------------------------------------------------------------------
@@ -330,55 +360,134 @@ sub udp_connection {
 
 	my $buf = "";
 
- 	my ($peerhost,$peerport);
- 
  	$sock->recv($buf, &Net::DNS::PACKETSZ);
+ 	my ($peerhost,$peerport) = ($sock->peerhost, $sock->peerport);
  
- 	print "UDP connection from ", $sock->peerhost, ":", $sock->peerport, "\n"
- 	  if $self->{"Verbose"};
-
-	print "UDP connection from $peerhost:$peerport\n" if $self->{"Verbose"};
+ 	print "UDP connection from $peerhost:$peerport\n" if $self->{"Verbose"};
 
 	my $query = Net::DNS::Packet->new(\$buf);
 
 	my $reply = $self->make_reply($query, $peerhost) || return;
 	my $reply_data = $reply->data;
 
-	print "writing response..." if $self->{"Verbose"};
+	local $| = 1 if $self->{"Verbose"};
+	print "Writing response - " if $self->{"Verbose"};
+	# die() ?!??  I think we need something better. --robert
 	$sock->send($reply_data) or die "send: $!";
 	print "done\n" if $self->{"Verbose"};
 }
 
+
+sub get_open_tcp {
+    my $self=shift;
+    return keys %{$self->{"_tcp"}};
+}
+
+
 #------------------------------------------------------------------------------
-# main_loop - Main nameserver loop.
+# loop_once - Just check "once" on sockets already set up
 #------------------------------------------------------------------------------
 
-sub main_loop {
-	my $self = shift;
+# This function might not actually return immediately. If an AXFR request is
+# coming in which will generate a huge reply, we will not relinquish control
+# until our outbuffers are empty.
 
-	local $| = 1;
+#
+#  NB  this method may be subject to change and is therefore left 'undocumented'
+#
 
-	while (1) {
-		print "waiting for connections..." if $self->{"Verbose"};
-		my @ready = $self->{"select"}->can_read;
-	
-		foreach my $sock (@ready) {
-			my $proto = getprotobynumber($sock->protocol);
-	
-			if (!$proto) {
-				print "ERROR: connection with unknown protocol\n"
-					if $self->{"Verbose"};
-			} elsif (lc($proto) eq "tcp") {
-				my $client = $sock->accept;
-				$self->tcp_connection($client);
-			} elsif (lc($proto) eq "udp") {
-				$self->udp_connection($sock);
-			} else {
-				print "ERROR: connection with unsupported protocol $proto\n"
-					if $self->{"Verbose"};
-			}
-		}
-	}
+sub loop_once {
+  my ($self, $timeout) = @_;
+  $timeout=0 unless defined($timeout);
+  print ";loop_once called with $timeout \n" if $self->{"Verbose"} >4;
+  foreach my $sock (keys %{$self->{"_tcp"}}) {
+      $timeout = 0.1 if $self->{"_tcp"}{$sock}{"outbuffer"};
+  }
+  my @ready = $self->{"select"}->can_read($timeout);
+  
+  foreach my $sock (@ready) {
+      my $protonum = $sock->protocol;
+      # This is a weird and nasty hack. Although not incorrect,
+      # I just don't know why ->protocol won't tell me the protocol
+      # on a connected socket. --robert
+      $protonum = getprotobyname('tcp') if not defined $protonum and $self->{"_tcp"}{$sock};
+      
+      my $proto = getprotobynumber($protonum);
+      if (!$proto) {
+	  print "ERROR: connection with unknown protocol\n"
+	      if $self->{"Verbose"};
+      } elsif (lc($proto) eq "tcp") {
+	  
+	  $self->readfromtcp($sock) &&
+	      $self->tcp_connection($sock);
+      } elsif (lc($proto) eq "udp") {
+	  $self->udp_connection($sock);
+      } else {
+	  print "ERROR: connection with unsupported protocol $proto\n"
+	      if $self->{"Verbose"};
+      }
+  }
+  my $now = time();
+  # Lets check if any of our TCP clients has pending actions.
+  # (outbuffer, timeout)
+  foreach my $s (keys %{$self->{"_tcp"}}) {
+      my $sock = $self->{"_tcp"}{$s}{"socket"};
+      if ($self->{"_tcp"}{$s}{"outbuffer"}) {
+	  # If we have buffered output, then send as much as the OS will accept
+	  # and wait with the rest
+	  my $len = length $self->{"_tcp"}{$s}{"outbuffer"};
+	  my $charssent = $sock->syswrite($self->{"_tcp"}{$s}{"outbuffer"});
+	  print "Sent $charssent of $len octets to ",$self->{"_tcp"}{$s}{"peer"},".\n"
+	      if $self->{"Verbose"};
+	  substr($self->{"_tcp"}{$s}{"outbuffer"}, 0, $charssent) = "";
+	  if (length $self->{"_tcp"}{$s}{"outbuffer"} == 0) {
+	      delete $self->{"_tcp"}{$s}{"outbuffer"};
+	      $self->{"_tcp"}{$s}{"state"} = STATE_ACCEPTED;
+	      if (length $self->{"_tcp"}{$s}{"inbuffer"} >= 2) {
+		  # See if the client has send us enough data to process the
+		  # next query.
+		  # We do this here, because we only want to process (and buffer!!)
+		  # a single query at a time, per client. If we allowed a STATE_SENDING
+		  # client to have new requests processed. We could be easilier
+		  # victims of DoS (client sending lots of queries and never reading
+		  # from it's socket).
+		  # Note that this does not disable serialisation on part of the
+		  # client. The split second it should take for us to lookip the
+		  # next query, is likely faster than the time it takes to
+		  # send the response... well, unless it's a lot of tiny queries,
+		  # in which case we will be generating an entire TCP packet per
+		  # reply. --robert
+		  $self->tcp_connection($self->{"_tcp"}{"socket"});
+	      }
+	  }
+	  $self->{"_tcp"}{$s}{"timeout"} = time()+120;
+      } else {
+	  # Get rid of idle clients.
+	  my $timeout = $self->{"_tcp"}{$s}{"timeout"};
+	  if ($timeout - $now < 0) {
+	      print $self->{"_tcp"}{$s}{"peer"}," has been idle for too long and will be disconnected.\n"
+		  if $self->{"Verbose"};
+	      $self->{"select"}->remove($sock);
+	      $sock->close();
+	      delete $self->{"_tcp"}{$s};
+	  }
+      }
+  }
+}
+
+#------------------------------------------------------------------------------
+# main_loop - Main nameserver loop.
+#------------------------------------------------------------------------------
+
+sub main_loop {
+    my $self = shift;
+    
+    while (1) {
+	print "Waiting for connections...\n" if $self->{"Verbose"};
+	# You really need an argument otherwise you'll be burning
+	# CPU.
+	$self->loop_once(10);
+    }
 }
 
 1;
@@ -395,7 +504,7 @@ C<use Net::DNS::Nameserver;>
 
 =head1 DESCRIPTION
 
-Instances of the C<Net::DNS::Nameserver> class represent simple DNS server
+Instances of the C<Net::DNS::Nameserver> class represent DNS server
 objects.  See L</EXAMPLE> for an example.
 
 =head1 METHODS
@@ -429,7 +538,7 @@ Creates a nameserver object.  Attributes are:
 
 
 The LocalAddr attribute may alternatively be specified as a list of IP
-addresses to liten to. 
+addresses to listen to. 
 
 If IO::Socket::INET6 and Socket6 are available on the system you can
 also list IPv6 addresses and the default is '0' (listen on all interfaces on
@@ -474,7 +583,52 @@ See L</EXAMPLE> for an example.
 
 	$ns->main_loop;
 
-Start accepting queries.
+Start accepting queries. Calling main_loop never returns.
+
+=cut
+
+#####
+#
+#  The functionality might change. Left "undocumented" for now.
+#
+=head2 loop_once
+
+	$ns->loop_once( [TIMEOUT_IN_SECONDS] );
+
+Start accepting queries, but returns. If called without a parameter,
+the call will not return until a request has been received (and
+replied to). If called with a number, that number specifies how many
+seconds (even fractional) to maximum wait before returning. If called
+with 0 it will return immediately unless there's something to do.
+
+Handling a request and replying obviously depends on the speed of
+ReplyHandler. Assuming ReplyHandler is super fast, loop_once should spend
+just a fraction of a second, if called with a timeout value of 0 seconds.
+One exception is when an AXFR has requested a huge amount of data that
+the OS is not ready to receive in full. In that case, it will keep
+running through a loop (while servicing new requests) until the reply
+has been sent.
+
+In case loop_once accepted a TCP connection it will immediatly check
+if there is data to be read from the socket. If not it will return and
+you will have to call loop_once() again to check if there is any data
+waiting on the socket to be processed. In most cases you will have to
+count on calling "loop_once" twice.
+
+A code fragment like:
+	$ns->loop_once(10);
+        while( $ns->get_open_tcp() ){
+	      $ns->loop_once(0);
+	}
+
+Would wait for 10 seconds for the initial connection and would then
+process all TCP sockets until none is left. 
+
+=head2 get_open_tcp
+
+In scalar context returns the number of TCP connections for which state
+is maintained. In array context it returns IO::Socket objects, these could
+be useful for troubleshooting but be careful using them.
 
 =head1 EXAMPLE
 
@@ -486,7 +640,7 @@ additional filtering on its basis may be applied.
 
  #!/usr/bin/perl 
  
- use Net::DNS;
+ use Net::DNS::Nameserver;
  use strict;
  use warnings;
  
@@ -494,12 +648,15 @@ additional filtering on its basis may be applied.
 	 my ($qname, $qclass, $qtype, $peerhost) = @_;
 	 my ($rcode, @ans, @auth, @add);
 	 
-	 if ($qtype eq "A") {
+	 if ($qtype eq "A" && qname eq "foo.example.com" ) {
 		 my ($ttl, $rdata) = (3600, "10.1.2.3");
 		 push @ans, Net::DNS::RR->new("$qname $ttl $qclass $qtype $rdata");
 		 $rcode = "NOERROR";
-	 } else {
-         $rcode = "NXDOMAIN";
+	 }elsif( qname eq "foo.example.com" ) {
+		 $rcode = "NOERROR";
+
+	 }else{
+  	          $rcode = "NXDOMAIN";
 	 }
 	 
 	 # mark the answer as authoritive (by setting the 'aa' flag
@@ -511,18 +668,25 @@ additional filtering on its basis may be applied.
      ReplyHandler => \&reply_handler,
      Verbose      => 1,
  ) || die "couldn't create nameserver object\n";
- 
+
  $ns->main_loop;
- 
-=head1 BUGS
 
-Net::DNS::Nameserver objects can handle only one query at a time.
+=head1 BUGS
 
 Limitations in perl 5.8.6 makes it impossible to guarantee that
 replies to UDP queries from Net::DNS::Nameserver are sent from the
 IP-address they were received on. This is a problem for machines with
 multiple IP-addresses and causes violation of RFC2181 section 4.
-
+Thus a UDP socket created listening to INADDR_ANY (all available
+IP-addresses) will reply not necessarily with the source address being
+the one to which the request was sent, but rather with the address that
+the operating system choses. This is also often called "the closest
+address". This should really only be a problem on a server which has
+more than one IP-address (besides localhost - any experience with IPv6
+complications here, would be nice). If this is a problem for you, a
+work-around would be to not listen to INADDR_ANY but to specify each
+address that you want this module to listen on. A seperate set of
+sockets will then be created for each IP-address.
 
 =head1 COPYRIGHT
 
@@ -532,7 +696,7 @@ Portions Copyright (c) 2002-2004 Chris Reinhardt.
 
 Portions Copyright (c) 2005 O.M, Kolkman, RIPE NCC.
  
-
+Portions Copyright (c) 2005 Robert Martin-Legene.
 
 All rights reserved.  This program is free software; you may redistribute
 it and/or modify it under the same terms as Perl itself.
@@ -544,4 +708,3 @@ L<Net::DNS::Update>, L<Net::DNS::Header>, L<Net::DNS::Question>,
 L<Net::DNS::RR>, RFC 1035
 
 =cut
-
@@ -1,6 +1,6 @@
 package Net::DNS::RR::CNAME;
 #
-# $Id: CNAME.pm 388 2005-06-22 10:06:05Z olaf $
+# $Id: CNAME.pm 501 2005-10-18 13:50:11Z olaf $
 #
 use strict;
 BEGIN { 
@@ -10,7 +10,7 @@ BEGIN {
 use vars qw(@ISA $VERSION);
 
 @ISA     = qw(Net::DNS::RR);
-$VERSION = (qw$LastChangedRevision: 388 $)[1];
+$VERSION = (qw$LastChangedRevision: 501 $)[1];
 
 sub new {
 	my ($class, $self, $data, $offset) = @_;
@@ -53,7 +53,6 @@ sub rr_rdata {
 # rdata contains a compressed domainname... we should not have that.
 sub _canonicalRdata {	
 	my ($self) = @_;
-
 	return $self->_name2wire($self->{"cname"});
 }
 
@@ -1,6 +1,6 @@
 package Net::DNS::RR::SRV;
 #
-# $Id: SRV.pm 388 2005-06-22 10:06:05Z olaf $
+# $Id: SRV.pm 484 2005-09-22 19:05:12Z olaf $
 #
 use strict;
 BEGIN { 
@@ -9,7 +9,7 @@ BEGIN {
 use vars qw(@ISA $VERSION);
 
 @ISA     = qw(Net::DNS::RR);
-$VERSION = (qw$LastChangedRevision: 388 $)[1];
+$VERSION = (qw$LastChangedRevision: 484 $)[1];
 
 sub new {
 	my ($class, $self, $data, $offset) = @_;
@@ -42,6 +42,7 @@ sub rdatastr {
 
 	if (exists $self->{'priority'}) {
 		$rdatastr = join(' ', @{$self}{qw(priority weight port target)});
+		$rdatastr =~ s/(.*[^\.])$/$1./;
 	} else {
 		$rdatastr = '';
 	}
@@ -68,7 +69,7 @@ sub _canonicalRdata {
 	
 	if (exists $self->{'priority'}) {
 		$rdata .= pack('n3', @{$self}{qw(priority weight port)});
-		$rdata .= $self->name_2wire($self->{'target'});
+		$rdata .= $self->_name2wire($self->{'target'});
 	}
 
 	return $rdata;
@@ -1,6 +1,6 @@
 package Net::DNS::RR::TXT;
 #
-# $Id: TXT.pm 388 2005-06-22 10:06:05Z olaf $
+# $Id: TXT.pm 515 2005-11-16 15:28:39Z olaf $
 #
 use strict;
 BEGIN { 
@@ -11,7 +11,7 @@ use vars qw(@ISA $VERSION);
 use Text::ParseWords;
 
 @ISA     = qw(Net::DNS::RR);
-$VERSION = (qw$LastChangedRevision: 388 $)[1];
+$VERSION = (qw$LastChangedRevision: 515 $)[1];
 
 sub new {
 	my ($class, $self, $data, $offset) = @_;
@@ -125,6 +125,7 @@ be deprecated.
 
 Use C<< $txt->rdatastr() >> or C<< $txt->char_str_list() >> instead.
 
+
 =head2 char_str_list
 
  print "Individual <character-string> list: \n\t", 
@@ -133,11 +134,36 @@ Use C<< $txt->rdatastr() >> or C<< $txt->char_str_list() >> instead.
 Returns a list of the individual <character-string> elements, 
 as unquoted strings.  Used by TXT->rdatastr and TXT->rr_rdata.
 
+
+=head1 FEATURES
+
+The RR.pm module accepts semi-colons as a start of a comment. This is
+to allow the RR.pm to deal with RFC1035 specified zonefile format.
+
+For some applications of the TXT RR the semicolon is relevant, you
+will need to escape it on input.
+
+Also note that you should specify the several character strings
+separately. The easiest way to do so is to include the whole argument
+in single quotes and the several character strings in double
+quotes. Double quotes inside the character strings will need to be
+escaped.
+
+my $TXTrr=Net::DNS::RR->new('txt2.t.net-dns.org.	60	IN
+	TXT  "Test1 \" \; more stuff"  "Test2"');
+
+would result in 
+$TXTrr->char_str_list())[0] containing 'Test1 " ; more stuff'
+and
+$TXTrr->char_str_list())[1] containing 'Test2'
+
+
 =head1 COPYRIGHT
 
 Copyright (c) 1997-2002 Michael Fuhr. 
 
 Portions Copyright (c) 2002-2004 Chris Reinhardt.
+Portions Copyright (c) 2005 Olaf Kolkman (NLnet Labs)
 
 All rights reserved.  This program is free software; you may redistribute
 it and/or modify it under the same terms as Perl itself.
@@ -1,6 +1,6 @@
 package Net::DNS::RR;
 #
-# $Id: RR.pm 388 2005-06-22 10:06:05Z olaf $
+# $Id: RR.pm 517 2005-11-21 08:38:47Z olaf $
 #
 use strict;
 
@@ -15,7 +15,7 @@ use Net::DNS::RR::Unknown;
 
 
 
-$VERSION = (qw$LastChangedRevision: 388 $)[1];
+$VERSION = (qw$LastChangedRevision: 517 $)[1];
 
 =head1 NAME
 
@@ -186,7 +186,7 @@ sub build_regex {
  $a     = Net::DNS::RR->new("foo.example.com. 86400 A 10.1.2.3");
  $mx    = Net::DNS::RR->new("example.com. 7200 MX 10 mailhost.example.com.");
  $cname = Net::DNS::RR->new("www.example.com 300 IN CNAME www1.example.com");
- $txt   = Net::DNS::RR->new("baz.example.com 3600 HS TXT 'text record'");
+ $txt   = Net::DNS::RR->new('baz.example.com 3600 HS TXT "text record"');
 
 Returns a C<Net::DNS::RR> object of the appropriate type and
 initialized from the string passed by the user.  The format of the
@@ -663,7 +663,7 @@ sub _canonicaldata {
 	    my @dname=Net::DNS::name2labels($name);
 	    for (my $i=0;$i<@dname;$i++){
 		$data .= pack ('C',length $dname[$i] );
-		$data .= $dname[$i] ;
+		$data .= lc($dname[$i] );
 	    }
 	    $data .= pack ('C','0');
 	}
@@ -688,9 +688,11 @@ sub _canonicaldata {
 # have domain names in the RDATA and _name2wire is used to convert a
 # domain name to "wire format"
 
+
 sub _canonicalRdata {
-    my $self = shift;
-    my $rdata = $self->rr_rdata;
+    my $self=shift;
+    my $packet=Net::DNS::Packet->new();
+    my $rdata = $self->rr_rdata($packet,0);
     return $rdata;
 }
 
@@ -1,6 +1,6 @@
 package Net::DNS::Resolver::Base;
 #
-# $Id: Base.pm 459 2005-07-15 18:56:02Z olaf $
+# $Id: Base.pm 534 2005-12-09 18:03:45Z olaf $
 #
 
 use strict;
@@ -25,7 +25,7 @@ use Net::IP qw(ip_is_ipv4 ip_is_ipv6 ip_normalize);
 use Net::DNS;
 use Net::DNS::Packet;
 
-$VERSION = (qw$LastChangedRevision: 459 $)[1];
+$VERSION = (qw$LastChangedRevision: 534 $)[1];
 
 
 #
@@ -574,8 +574,8 @@ sub send_tcp {
 		my $sock;
 		my $sock_key = "$ns:$dstport";
 		my ($host,$port);
-		if ($self->persistent_tcp && $self->{'sockets'}{$sock_key}) {
-			$sock = $self->{'sockets'}{$sock_key};
+		if ($self->persistent_tcp && $self->{'sockets'}[AF_UNSPEC]{$sock_key}) {
+			$sock = $self->{'sockets'}[AF_UNSPEC]{$sock_key};
 			print ";; using persistent socket\n"
 				if $self->{'debug'};
 		} else {
@@ -586,7 +586,7 @@ sub send_tcp {
 		    
 		    #my $old_wflag = $^W;
 		    #$^W = 0;
-		    if ($has_inet6 && ! $self->force_v4()){
+		    if ($has_inet6 && ! $self->force_v4() && ip_is_ipv6($ns) ){
                         # XXX IO::Socket::INET6 fails in a cryptic way upon send()
                         # on AIX5L if "0" is passed in as LocalAddr
 			# $srcaddr="0" if $srcaddr eq "0.0.0.0";  # Otherwise the INET6 socket will just fail
@@ -595,7 +595,7 @@ sub send_tcp {
 
 			$sock = 
 			    IO::Socket::INET6->new(
-						   PeerPort =>    53,
+						   PeerPort =>    $dstport,
 						   PeerAddr =>    $ns,
 						   LocalAddr => $srcaddr6,
 						   LocalPort => ($srcport || undef),
@@ -622,8 +622,9 @@ sub send_tcp {
 			"failed: $!\n" if $self->{'debug'};
 			next;
 		    }
-
-			$self->{'sockets'}{$sock_key} = $sock;
+		    
+		    $self->{'sockets'}[AF_UNSPEC]{$sock_key} = $sock if 
+			$self->persistent_tcp;
 		}
 
 		my $lenmsg = pack('n', length($packet_data));
@@ -817,7 +818,7 @@ sub send_udp {
 	  # If getaddrinfo is available that is used for both INET4 and INET6
 	  # If getaddrinfo is not avialable (Socket6 failed to load) we revert
 	  # to the 'classic mechanism
-	  if ($has_inet6  && ! $self->force_v4()){ 
+	  if ($has_inet6  && ! $self->force_v4() ){ 
 	      # we can use getaddrinfo
 	      no strict 'subs';   # Because of the eval statement in the BEGIN
 	      # AI_NUMERICHOST is not available at compile time.
@@ -1072,15 +1073,16 @@ sub bgsend {
 							 Proto => 'udp',
 							 Type => SOCK_DGRAM,
 							 LocalAddr => $srcaddr,
-							 LocalPort => $srcport,
+							 LocalPort => ($srcport || undef),
 					    );
 	} elsif ($has_inet6 && $sockfamily == AF_INET6() ) {
-	    $srcaddr="0" if $srcaddr eq "0.0.0.0";  # Otherwise the INET6 socket will just fail
+	    # Otherwise the INET6 socket will just fail
+	    my $srcaddr6 = $srcaddr eq "0.0.0.0" ? '::' : $srcaddr;
 	    $socket[$sockfamily] = IO::Socket::INET6->new(
 							  Proto => 'udp',
 							  Type => SOCK_DGRAM,
-							  LocalAddr => $srcaddr,
-							  LocalPort => $srcport,
+							  LocalAddr => $srcaddr6,
+							  LocalPort => ($srcport || undef),
 					     );
 	} else {
 	    die ref($self)." bgsend:Unsoported Socket Family: $sockfamily";
@@ -1252,28 +1254,30 @@ sub axfr_start {
 
 	my $ns = ($self->nameservers())[0];
 
-	print ";; axfr_start nameserver = $ns\n" if $self->{'debug'};
 
 	my $srcport = $self->{'srcport'};
 	my $srcaddr = $self->{'srcaddr'};
 	my $dstport = $self->{'port'};
 
+	print ";; axfr_start nameserver = $ns\n" if $self->{'debug'};
+	print ";; axfr_start srcport: $srcport, srcaddr: $srcaddr, dstport: $dstport\n" if $self->{'debug'};
+
+
 	my $sock;
 	my $sock_key = "$ns:$self->{'port'}";
 
-	if ($self->{'persistent_tcp'} && $self->{'sockets'}->{$sock_key}) {
-	    $sock = $self->{'sockets'}->{$sock_key};
+	if ($self->{'persistent_tcp'} && $self->{'sockets'}[AF_UNSPEC]{$sock_key}) {
+	    $sock = $self->{'sockets'}[AF_UNSPEC]{$sock_key};
 	    print ";; using persistent socket\n" if $self->{'debug'};
 	    
 	} else {
-	    if ($has_inet6  && ! $self->force_v4()){
-		$srcaddr="0" if $srcaddr eq "0.0.0.0";  # Otherwise the INET6 socket will just fail
-		
-		$sock = 
-		    IO::Socket::INET6->new(
-					   PeerPort =>    53,
+	    if ($has_inet6  && ! $self->force_v4() && ip_is_ipv6($ns)){
+		# Otherwise the INET6 socket will just fail
+		my $srcaddr6 = $srcaddr eq "0.0.0.0" ? '::' : $srcaddr;
+		$sock = IO::Socket::INET6->new(
+					   PeerPort =>    $dstport,
 					   PeerAddr =>    $ns,
-					   LocalAddr => 0,
+					   LocalAddr => $srcaddr6,
 					   LocalPort => ($srcport || undef),
 					   Proto     => 'tcp',
 					   );
@@ -1294,10 +1298,11 @@ sub axfr_start {
 		$self->errorstring('connection failed');
 		print ';; ERROR: send_tcp: connection ',
 		"failed: $!\n" if $self->{'debug'};
-		next;
+		return;
 	    }
 	    
-	    $self->{'sockets'}{$sock_key} = $sock;
+	    $self->{'sockets'}[AF_UNSPEC]{$sock_key} = $sock 
+		if $self->persistent_tcp;
 	}
 
 
@@ -1448,7 +1453,6 @@ sub dnssec {
     }
     
     Carp::carp ("You called the Net::DNS::Resolver::dnssec() method but do not have Net::DNS::SEC installed") if $self->{"dnssec"} && ! $Net::DNS::DNSSEC;
-    
     return $self->{"dnssec"};
 };
 
@@ -1,13 +1,13 @@
 package Net::DNS::Resolver::Recurse;
 #
-# $Id: Recurse.pm 462 2005-07-15 20:55:32Z olaf $
+# $Id: Recurse.pm 515 2005-11-16 15:28:39Z olaf $
 #
 use strict;
 use Net::DNS::Resolver;
 
 use vars qw($VERSION @ISA);
 
-$VERSION = (qw$LastChangedRevision: 462 $)[1];
+$VERSION = (qw$LastChangedRevision: 515 $)[1];
 @ISA = qw(Net::DNS::Resolver);
 
 sub hints {
@@ -133,9 +133,13 @@ sub _dorecursion {
   my $depth = shift;
   my $cache = $self->{'authority_cache'};
 
-  print ";; _dorecursion() depth=[$depth] known_zone=[$known_zone]\n" if $self->{'debug'};
-  die "Recursion too deep, aborting..." if $depth > 255;
-
+  # die "Recursion too deep, aborting..." if $depth > 255;
+  if ( $depth > 255 ) {
+      print ";; _dorecursion() Recursion too deep, aborting...\n" if
+	  $self->{'debug'};
+      $self->errorstring="Recursion to deep, abborted";
+      return undef;
+  }
   
   $known_zone =~ s/\.*$/./;
 
@@ -397,7 +401,7 @@ Portions Copyright (c) 2005, Olaf M Kolkman.
 This module is free software; you can redistribute
 it and/or modify it under the same terms as Perl itself.
 
-$Id: Recurse.pm 462 2005-07-15 20:55:32Z olaf $
+$Id: Recurse.pm 515 2005-11-16 15:28:39Z olaf $
 
 =cut
 
@@ -1,6 +1,6 @@
 package Net::DNS::Resolver::UNIX;
 #
-# $Id: UNIX.pm 264 2005-04-06 09:16:15Z olaf $
+# $Id: UNIX.pm 482 2005-09-02 13:34:33Z olaf $
 #
 
 use strict;
@@ -9,7 +9,7 @@ use vars qw(@ISA $VERSION);
 use Net::DNS::Resolver::Base ();
 
 @ISA     = qw(Net::DNS::Resolver::Base);
-$VERSION = (qw$LastChangedRevision: 264 $)[1];
+$VERSION = (qw$LastChangedRevision: 482 $)[1];
 
 my $resolv_conf = '/etc/resolv.conf';
 my $dotfile     = '.resolv.conf';
@@ -71,4 +71,4 @@ it and/or modify it under the same terms as Perl itself.
 
 L<perl(1)>, L<Net::DNS>, L<Net::DNS::Resolver>
 
-=cut
\ No newline at end of file
+=cut
@@ -1,6 +1,6 @@
 package Net::DNS::Resolver::Win32;
 #
-# $Id: Win32.pm 295 2005-05-25 22:20:59Z olaf $
+# $Id: Win32.pm 514 2005-11-15 13:02:54Z olaf $
 #
 
 use strict;
@@ -9,7 +9,7 @@ use vars qw(@ISA $VERSION);
 use Net::DNS::Resolver::Base ();
 
 @ISA     = qw(Net::DNS::Resolver::Base);
-$VERSION = (qw$LastChangedRevision: 295 $)[1];
+$VERSION = (qw$LastChangedRevision: 514 $)[1];
 
 use Win32::Registry;
 
@@ -93,19 +93,22 @@ sub init {
 	    foreach my $iface (@ifacelist) {
 		my $regiface;
 		$interfaces->Open($iface, $regiface);
+		
 		if ($regiface) {
 		    my $ns;
 		    my $type;
 		    my $ip;
+		    my $ipdhcp;
 		    $regiface->QueryValueEx("IPAddress", $type, $ip);
-		    if ($ip && !($ip =~ /0\.0\.0\.0/)) {
+		    $regiface->QueryValueEx("DhcpIPAddress", $type, $ipdhcp);
+		    if (($ip && !($ip =~ /0\.0\.0\.0/)) || ($ipdhcp && !($ipdhcp =~ /0\.0
+\.0\.0/))) {
 			# NameServer overrides DhcpNameServer if both exist
 			$regiface->QueryValueEx("NameServer", $type, $ns);
 			$regiface->QueryValueEx("DhcpNameServer", $type, $ns) unless $ns;
 			$nameservers .= " $ns" if $ns;
 		    }
 		}
-		
 	    }
 	}
 	if (!$nameservers) {
@@ -1,12 +1,12 @@
 package Net::DNS::Resolver;
 #
-# $Id: Resolver.pm 290 2005-05-20 11:42:59Z olaf $
+# $Id: Resolver.pm 513 2005-11-09 23:49:38Z olaf $
 #
 
 use strict;
 use vars qw($VERSION @ISA);
 
-$VERSION = (qw$LastChangedRevision: 290 $)[1];
+$VERSION = (qw$LastChangedRevision: 513 $)[1];
 
 BEGIN {
 	if ($^O eq 'MSWin32') {
@@ -153,7 +153,7 @@ An array reference of domains.
 
 =item retry
 
-=item usecv
+=item usevc
 
 =item stayopen
 
@@ -729,12 +729,14 @@ Error reporting and handling needs to be improved.
 The current implementation supports TSIG only on outgoing packets.
 No validation of server replies is performed.
 
+bgsend does not honor the usevc flag and only uses UDP for transport.
+
 =head1 COPYRIGHT
 
 Copyright (c) 1997-2002 Michael Fuhr. 
 
 Portions Copyright (c) 2002-2004 Chris Reinhardt.
-Portions Copyright (c) 2005 Olaf M. Kolkman
+Portions Copyright (c) 2005 Olaf M. Kolkman, NLnet Labs.
 
 All rights reserved.  This program is free software; you may redistribute
 it and/or modify it under the same terms as Perl itself.
@@ -1,6 +1,6 @@
 package Net::DNS::Update;
 #
-# $Id: Update.pm 388 2005-06-22 10:06:05Z olaf $
+# $Id: Update.pm 517 2005-11-21 08:38:47Z olaf $
 #
 use strict;
 BEGIN { 
@@ -11,7 +11,7 @@ use vars qw($VERSION @ISA);
 use Net::DNS;
 
 @ISA     = qw(Net::DNS::Packet);
-$VERSION = (qw$LastChangedRevision: 388 $)[1];
+$VERSION = (qw$LastChangedRevision: 517 $)[1];
 
 =head1 NAME
 
@@ -128,7 +128,7 @@ show only the creation of the update packet.
 
     my $update = Net::DNS::Update->new('example.com');
     $update->push(pre    => nxdomain('info.example.com'));
-    $update->push(update => rr_add('info.example.com TXT 'yabba dabba doo''));
+    $update->push(update => rr_add('info.example.com TXT "yabba dabba doo"'));
 
 =head2 Delete all A records for a name
 
@@ -1,6 +1,6 @@
 package Net::DNS;
 #
-# $Id: DNS.pm 468 2005-07-22 12:12:55Z olaf $
+# $Id: DNS.pm 539 2005-12-14 10:16:14Z olaf $
 #
 use strict;
 
@@ -41,7 +41,7 @@ BEGIN {
     @ISA     = qw(Exporter DynaLoader);
 
     
-    $VERSION = '0.53';
+    $VERSION = '0.55';
     $HAVE_XS = eval { 
 	local $SIG{'__DIE__'} = 'DEFAULT';
 	__PACKAGE__->bootstrap(); 1 
@@ -833,17 +833,16 @@ the source distribution.
 =head1 COPYRIGHT
 
 Copyright (c) 1997-2002 Michael Fuhr. 
-
 Portions Copyright (c) 2002-2004 Chris Reinhardt.
-
 Portions Copyright (c) 2005 Olaf Kolkman (RIPE NCC)
+Portions Copyright (c) 2006 Olaf Kolkman (NLnet Labs)
 
 All rights reserved.  This program is free software; you may redistribute
 it and/or modify it under the same terms as Perl itself.
 
 =head1 AUTHOR INFORMATION
 
-Net::DNS is currently maintained by:
+Net::DNS is currently maintained at NLnet Labs (www.nlnetlabs.nl) by:
         Olaf Kolkman
 	olaf@net-dns.org
 
@@ -1,4 +1,4 @@
-# $Id: 01-resolver.t 302 2005-05-28 05:39:23Z olaf $  -*-perl-*-
+# $Id: 01-resolver.t 479 2005-07-31 14:19:41Z olaf $  -*-perl-*-
 
 use Test::More tests => 44;
 use strict;
@@ -70,10 +70,26 @@ my %bad_input = (
 	cdflag         => 'set',
 );	
 
+# Some people try to run these on private address space."
+
+use Net::IP;
+
+use IO::Socket::INET;
+my $sock = IO::Socket::INET->new(PeerAddr => '193.0.14.129', # k.root-servers.net.
+				 PeerPort => '25',
+				 Proto    => 'udp');
+
+
+my $ip=Net::IP->new(inet_ntoa($sock->sockaddr));
+	    
+
 SKIP: {
 	skip 'Online tests disabled.', 2
 		unless -e 't/online.enabled';
 
+	skip 'Tests may not run succesful from private IP('.$ip->ip() .')', 2
+	    if ($ip->iptype() ne "PUBLIC");
+
 	my $res = Net::DNS::Resolver->new;
 	
 	$res->nameservers('a.t.net-dns.org');
@@ -1,8 +1,64 @@
-# $Id: 05-rr.t 264 2005-04-06 09:16:15Z olaf $
+# $Id: 05-rr.t 536 2005-12-14 10:06:12Z olaf $   -*-perl-*-
 
-use Test::More tests => 219;
+use Test::More;
 use strict;
 
+use vars qw( $HAS_DNSSEC );
+
+my $keypathrsa="Kexample.com.+005+24866.private";
+my $rsakeyrr;
+
+BEGIN {
+    if(
+	eval {require Net::DNS::SEC;}
+	){
+	$HAS_DNSSEC=1;
+	plan tests => 245;
+
+    }else{
+	$HAS_DNSSEC=0;
+	plan tests => 219;
+    }
+};
+
+
+
+
+if ($HAS_DNSSEC){  # Create key material    
+    diag "The suite will run additonal DNSSEC tests";
+    my $privrsakey= << 'ENDRSA' ;
+Private-key-format: v1.2
+Algorithm: 5 (RSASHA1)
+Modulus: osG7zULAQoU3HxVnQl0dj8pLCcxA4ZQk9lgSzd+Q5GvhQYPS4vtnBRvwQDPTckfINqHYbxLQBZGYyl3n0ZQ0W5GDUlnDkeKk+2fe0UIbArY+xkODYGBmv6VGDk1K0kc7mH6cYHUciEtPMdyzYa9hIPfPDp2IE0+BRpr3hPkRnLE=
+PublicExponent: Aw==
+PrivateExponent: bIEn3iyALFjPag5E1ui+X9wyBogrQQ1t+ZAMiT+17Z1A1lfh7KeaA2f1gCKM9tqFecE69Lc1WQu7MZPv4Q14O/uDO/th5aF6oUL6kYYiSkbmxZ138w6g/PRh+Y/F135Hz8nVyTLrbmo+l5tjiaN5LOgUjvYYwSR3k1FFhgW3zks=
+Prime1: zF8a/5xhYpBZH7uVB0xxuo7FbepslQnCSudXRd+1KFmpJ6z4XSDEJVl/XngaVw4j4IvHL9FpjF8JkH1PUn2c7Q==
+Prime2: y99dYRRYDdywY6th8ZshkVXYaWUHNWuB68vAr8JZ4XY3qC66S5qehpfPFSX44x05uyRw/JGIDG7gEJHsngBKVQ==
+Exponent1: iD9nVRLrlwrmFSe4r4hL0bSDnpxIY1vW3Jo6LpUjcDvGGnNQPhXYGOZU6aVm5LQX6wfaH+DxCD9btajfjFO98w==
+Exponent2: h+o+QLg6s+h1l8eWoRIWYOPlm5ivePJWnTKAdSw766QlGsnRh7xprw/fY26l7L4mfML1/bZasvSVYGFIaVWG4w==
+Coefficient: BV4xfdcDiyLKBr6647EUocgAziN3qfVsfJc0DdJjYW3VnuECVvNo8Q2ehAYTAwdzNRjBhwB7ZV3Mi6+S8OXFTQ==
+ENDRSA
+
+
+open (RSA,">$keypathrsa") or die "Could not open $keypathrsa";
+    print RSA $privrsakey;
+    close(RSA);
+        
+ $rsakeyrr=new Net::DNS::RR ("example.com. IN DNSKEY 256 3 5 AQOiwbvNQsBChTcfFWdCXR2PyksJzEDhlCT2WBLN35Dka+FBg9Li+2cF G/BAM9NyR8g2odhvEtAFkZjKXefRlDRbkYNSWcOR4qT7Z97RQhsCtj7G Q4NgYGa/pUYOTUrSRzuYfpxgdRyIS08x3LNhr2Eg988OnYgTT4FGmveE +RGcsQ==
+
+");
+    
+    
+    
+
+    ok( $rsakeyrr, 'RSA public key created');     # test 5
+    
+    
+}
+
+
+
+
 
 BEGIN { use_ok('Net::DNS'); }
 
@@ -157,21 +213,37 @@ my @rrs = (
 	
 );
 
+
+
+
+
 #------------------------------------------------------------------------------
-# Create the packet.
+# Create the packet and signatures (if DNSSEC is available.)
 #------------------------------------------------------------------------------
 
+my @rrsigs;
 my $packet = Net::DNS::Packet->new($name);
 ok($packet,         'Packet created');
 
 foreach my $data (@rrs) {
-	$packet->push('answer', 
-		Net::DNS::RR->new(
-			name => $name,
-			ttl  => $ttl,
-			%{$data},
-		)
-	);
+    my $RR=Net::DNS::RR->new(
+	   name => $name,
+	   ttl  => $ttl,
+	   %{$data});
+       
+       if ($HAS_DNSSEC){
+	   my $sigrr= create Net::DNS::RR::RRSIG( [ $RR ],
+						  $keypathrsa,
+						  (
+						   ttl => 360, 
+						   sigval => 100,
+						  ));
+	   $sigrr->print;
+	   push  @rrsigs, $sigrr;
+       }
+       
+
+       $packet->push('answer', $RR );
 }
 
 
@@ -192,6 +264,9 @@ my @answer = $packet->answer;
 ok(@answer && @answer == @rrs, 'Packet returned correct answer section');
 
 
+
+
+
 while (@answer and @rrs) {
 	my $data = shift @rrs;
 	my $rr   = shift @answer;
@@ -209,6 +284,16 @@ while (@answer and @rrs) {
 	
 	my $rr2 = Net::DNS::RR->new($rr->string);
 	is($rr2->string, $rr->string,   "$type - Parsing from string works");
+	if ($HAS_DNSSEC){
+	    my $rrsig=shift @rrsigs;
+	    ok($rrsig->verify([ $rr ], $rsakeyrr), "RR of type ".$type." signature creation/validation cycle");
+	}
+	
 }
 
 
+
+
+
+
+unlink($keypathrsa);
@@ -1,4 +1,4 @@
-# $Id: 07-misc.t 264 2005-04-06 09:16:15Z olaf $ -*-perl-*-
+# $Id: 07-misc.t 488 2005-09-26 08:15:21Z olaf $ -*-perl-*-
 
 use Test::More tests => 22;
 use strict;
@@ -62,8 +62,8 @@ is($warning, 0, 'No evil warning');
 {
 	my $srv = Net::DNS::RR->new('srv.t.net-dns.org 60 IN SRV 0 2 3 target.net-dns.org');
 	
-	like($srv->string, '/0 2 3 target.net-dns.org/');
-	is($srv->rdatastr, '0 2 3 target.net-dns.org');
+	like($srv->string, '/0 2 3 target.net-dns.org\./');
+	is($srv->rdatastr, '0 2 3 target.net-dns.org.');
 }
 
 
@@ -1,4 +1,4 @@
-# $Id: 08-online.t 385 2005-06-20 15:44:00Z olaf $ -*-perl-*-
+# $Id: 08-online.t 490 2005-10-05 13:14:07Z olaf $ -*-perl-*-
 
 use Test::More;
 use strict;
@@ -152,10 +152,12 @@ $res = Net::DNS::Resolver->new(
 		isa_ok($a, 'Net::DNS::RR::A');
 		is($a->name, 'a.t.net-dns.org',"Correct name (with $method)");
 	}
-	
-	# $res->debug(1);
+#	$res->debug(1);
 	my $socket=$res->bgsend('a.t.net-dns.org','A');
 	ok(ref($socket)=~/^IO::Socket::INET(6?)$/,"Socket returned");
+	diag("Error condition: ".$res->errorstring ."Socket ref:".ref($socket)) unless ref($socket)=~/^IO::Socket::INET(6?)$/;
+
+
 	my $loop=0;
 	# burn a little CPU to get the socket ready.
 	# I could off course used microsleep or something.
@@ -163,12 +165,13 @@ $res = Net::DNS::Resolver->new(
 	    $loop++;
 	}
 	$loop=0;
-
 	while ($loop<6){
 	    last if $res->bgisready($socket);
 	    sleep(1); # If burning CPU above was not sufficient.
 	    $loop++;
 	}
+	$res->debug(0);
+
 	ok ($res->bgisready($socket),"Socket is ready");
       SKIP: {
 	  skip "No socket to read from",3 unless $res->bgisready($socket);
@@ -1,8 +1,8 @@
-# $Id: 11-inet6.t 319 2005-05-30 17:12:09Z olaf $ -*-perl-*-
+# $Id: 11-inet6.t 499 2005-10-11 10:15:46Z olaf $ -*-perl-*-
 
 
 my $has_inet6;
-use Test::More tests=>6;
+use Test::More tests=>10;
 use strict;
 
 
@@ -21,7 +21,7 @@ BEGIN { use_ok('Net::DNS');
 
 
 SKIP: { skip "Socket6 and or IO::Socket::INET6 not loaded\n".
-	    "You will need to install these modules for IPv6 transport support", 5 unless $has_inet6;
+	    "You will need to install these modules for IPv6 transport support", 9 unless $has_inet6;
 
 	diag "";
 	diag "The libraries needed for IPv6 support have been found\n";
@@ -53,6 +53,7 @@ exit unless $has_inet6; #This prevents nested SKIP blocks..
 
 my $answer;
 my $res;
+my $res2;
 
 SKIP: { skip "online tests are not enabled", 2 unless -e 't/online.enabled';
 
@@ -78,31 +79,30 @@ SKIP: { skip "online tests are not enabled", 2 unless -e 't/online.enabled';
 	    diag ("\n\t\t Trying to connect to  ". $ns->nsdname . " ($AAAA_address)");
 	    last;
 	}
-	    
 
 	$res->nameservers($AAAA_address);
-
-	$res->print;
+	# $res->print;
 	$answer=$res->send("ripe.net","SOA","IN");
-	if($res->errorstring =~ /Send error: /){	
-		diag "\n\t\t Connection failed: " . $res->errorstring ;
-		diag "\n\t\t It seems you do not have global IPv6 connectivity' \n" ;
-		diag "\t\t This is not an error in Net::DNS \n";
-
-		diag "\t\t You can confirm this by trying 'ping6 ".$AAAA_address."' \n\n";
-	}		
+	if($res->errorstring =~ /Send error: /){
+	    diag "\n\t\t Connection failed: " . $res->errorstring ;
+	    diag "\n\t\t It seems you do not have global IPv6 connectivity' \n" ;
+	    diag "\t\t This is not an error in Net::DNS \n";
+	    
+	    diag "\t\t You can confirm this by trying 'ping6 ".$AAAA_address."' \n\n";
+	}
 	
-    }
- SKIP: { skip "No answer available to analyse", 3 unless $answer;
+}
+
+ SKIP: { skip "No answer available to analyse (". $res->errorstring.")", 3 unless $answer;
 	 
-	 $answer->print;
+	 # $answer->print;
 	 is (($answer->answer)[0]->type, "SOA","Query over udp6 succeeded");
 	 $res->usevc(1);
 	 $answer=$res->send("ripe.net","NS","IN");
 	 is (($answer->answer)[0]->type, "NS","Query over tcp6  succeeded");
 	 $res->force_v4(1);
-	 $res->print;
-	 $res->debug(1);
+	 # $res->print;
+	 # $res->debug(1);
 	 $answer=$res->send("ripe.net","SOA","IN");
 	 is ($res->errorstring,"no nameservers","Correct errorstring when forcing v4");
 	 
@@ -112,3 +112,44 @@ SKIP: { skip "online tests are not enabled", 2 unless -e 't/online.enabled';
 
 
 
+
+#
+#
+#  Now test AXFR functionality.
+#
+#
+my $socket;
+SKIP: { skip "online tests are not enabled", 2 unless -e 't/online.enabled';
+
+	# First use the local resolver to query for the AAAA record of a 
+
+	$res2=Net::DNS::Resolver->new;
+	# $res2->debug(1);
+	my $nsanswer=$res2->send("net-dns.org","NS","IN");
+	is (($nsanswer->answer)[0]->type, "NS","Preparing  for v6 transport, got NS records for net-dns.org");
+	my $AAAA_address;
+	foreach my $ns ($nsanswer->answer){
+#	    next if $ns->nsdname !~ /ripe\.net/; # User rupe.net only
+	    my $aaaa_answer=$res2->send($ns->nsdname,"AAAA","IN");
+	    next if ($aaaa_answer->header->ancount == 0);
+	    is (($aaaa_answer->answer)[0]->type,"AAAA", "Preparing  for v6 transport, got AAAA records for ". $ns->nsdname);
+	    $AAAA_address=($aaaa_answer->answer)[0]->address;
+
+	    diag ("\n\t\t Trying to connect to  ". $ns->nsdname . " ($AAAA_address)");
+	    last;
+	}
+
+	$res2->nameservers($AAAA_address);
+	# $res2->print;
+	
+        $socket=$res2->axfr_start('example.com');
+}
+
+
+
+SKIP: { skip "axfr_start did not return a socket", 2 unless defined($socket);
+	is(ref($socket),"IO::Socket::INET6","axfr_start returns IPv6 Socket");
+	my ($rr,$err)=$res2->axfr_next;
+	is($res2->errorstring,'Response code from server: NOTAUTH',"Transfer is not authorized (but our connection worked)");
+
+}