1package Net::DNS::Nameserver; 2# 3# $Id: Nameserver.pm 709 2008-02-06 22:40:42Z olaf $ 4# 5 6use Net::DNS; 7use IO::Socket; 8use IO::Socket::INET; 9use IO::Select; 10use Carp qw(cluck); 11 12use strict; 13use vars qw( $VERSION 14 $has_inet6 15 ); 16 17use constant FORCE_INET4 => 0; 18 19use constant DEFAULT_ADDR => 0; 20use constant DEFAULT_PORT => 53; 21 22use constant STATE_ACCEPTED => 1; 23use constant STATE_GOT_LENGTH => 2; 24use constant STATE_SENDING => 3; 25 26$VERSION = (qw$LastChangedRevision: 709 $)[1]; 27 28 29 30BEGIN { 31 if ( FORCE_INET4 ) { 32 $has_inet6 = 0; 33 } elsif ( eval {require Socket6;} && 34 # INET6 earlier than V2.01 will not work; sorry. 35 eval {require IO::Socket::INET6; IO::Socket::INET6->VERSION("2.01");} ) { 36 import Socket6; 37 $has_inet6 = 1; 38 } else { 39 $has_inet6=0; 40 } 41} 42 43 44#------------------------------------------------------------------------------ 45 46 47#------------------------------------------------------------------------------ 48# Constructor. 49#------------------------------------------------------------------------------ 50 51sub new { 52 my ($class, %self) = @_; 53 54 unless ( ref $self{ReplyHandler} ) { 55 cluck "No reply handler!"; 56 return; 57 } 58 59 # local server addresses must also be accepted by a resolver 60 my @LocalAddr = ref $self{LocalAddr} ? @{$self{LocalAddr}} : ($self{LocalAddr}); 61 my $resolver = Net::DNS::Resolver->new; 62 $resolver->force_v4(1) unless $has_inet6; 63 $resolver->nameservers(undef); 64 my @localaddresses = $resolver->nameservers(@LocalAddr); 65 66 my $port = $self{LocalPort} || DEFAULT_PORT; 67 68 my @sock_tcp; # All the TCP sockets we will listen to. 69 my @sock_udp; # All the UDP sockets we will listen to. 70 71 # while we are here, print incomplete lines as they come along. 72 local $| = 1 if $self{Verbose}; 73 74 foreach my $addr ( @localaddresses ? @localaddresses : DEFAULT_ADDR ){ 75 76 #-------------------------------------------------------------------------- 77 # Create the TCP socket. 78 #-------------------------------------------------------------------------- 79 80 print "\nCreating TCP socket $addr#$port - " if $self{Verbose}; 81 82 my $sock_tcp = inet_new( 83 LocalAddr => $addr, 84 LocalPort => $port, 85 Listen => 64, 86 Proto => "tcp", 87 Reuse => 1, 88 ); 89 if ( $sock_tcp ) { 90 push @sock_tcp, $sock_tcp; 91 print "done.\n" if $self{Verbose}; 92 } else { 93 cluck "Couldn't create TCP socket: $!"; 94 } 95 96 #-------------------------------------------------------------------------- 97 # Create the UDP Socket. 98 #-------------------------------------------------------------------------- 99 100 print "Creating UDP socket $addr#$port - " if $self{Verbose}; 101 102 my $sock_udp = inet_new( 103 LocalAddr => $addr, 104 LocalPort => $port, 105 Proto => "udp", 106 ); 107 108 if ( $sock_udp ) { 109 push @sock_udp, $sock_udp; 110 print "done.\n" if $self{Verbose}; 111 } else { 112 cluck "Couldn't create UDP socket: $!"; 113 } 114 115 } 116 117 #-------------------------------------------------------------------------- 118 # Create the Select object. 119 #-------------------------------------------------------------------------- 120 121 my $select = $self{select} = IO::Select->new; 122 123 $select->add(@sock_tcp); 124 $select->add(@sock_udp); 125 126 return undef unless $select->count; 127 128 #-------------------------------------------------------------------------- 129 # Return the object. 130 #-------------------------------------------------------------------------- 131 132 my $self = bless \%self, $class; 133 return $self; 134} 135 136#------------------------------------------------------------------------------ 137# inet_new - Calls the constructor in the correct module for making sockets. 138#------------------------------------------------------------------------------ 139 140sub inet_new { 141 if ($has_inet6) { 142 return IO::Socket::INET6->new(@_); 143 } else { 144 return IO::Socket::INET->new(@_); 145 } 146} 147 148#------------------------------------------------------------------------------ 149# make_reply - Make a reply packet. 150#------------------------------------------------------------------------------ 151 152sub make_reply { 153 my ($self, $query, $peerhost) = @_; 154 155 my $reply = Net::DNS::Packet->new(); # create empty reply packet 156 $reply->header->qr(1); 157 158 my $headermask; 159 160 unless ($query) { 161 print "ERROR: invalid packet\n" if $self->{"Verbose"}; 162 $reply->header->rcode("FORMERR"); 163 return $reply; 164 } 165 166 if ($query->header->qr()) { 167 print "ERROR: invalid packet (qr was set, dropping)\n" if $self->{"Verbose"}; 168 return; 169 } 170 171 172 # question section returned to caller 173 my @q = $query->question; 174 @q=( Net::DNS::Question->new('', 'ANY', 'ANY') ) unless @q; 175 176 $reply->push("question", @q); 177 178 if ($query->header->opcode eq "QUERY" || 179 $query->header->opcode eq "NS_NOTIFY_OP" #RFC1996 180 ) { 181 if ($query->header->qdcount == 1) { 182 my ($qr) = @q; 183 my $qname = $qr->qname; 184 my $qtype = $qr->qtype; 185 my $qclass = $qr->qclass; 186 187 print "query ", $query->header->id, 188 ": ($qname, $qclass, $qtype) - " if $self->{"Verbose"}; 189 190 my ($rcode, $ans, $auth, $add); 191 192 if ($query->header->opcode eq "QUERY"){ 193 ($rcode, $ans, $auth, $add, $headermask) = 194 &{$self->{"ReplyHandler"}}($qname, $qclass, $qtype, $peerhost, $query); 195 }else{ 196 $reply->header->rcode("SERVFAIL") unless 197 ( ref $self->{"NotifyHandler"} eq "CODE"); 198 ($rcode, $ans, $auth, $add, $headermask) = 199 &{$self->{"NotifyHandler"}}($qname, $qclass, $qtype, $peerhost, $query); 200 } 201 print "$rcode\n" if $self->{"Verbose"}; 202 203 $reply->header->rcode($rcode); 204 205 $reply->push("answer", @$ans) if $ans; 206 $reply->push("authority", @$auth) if $auth; 207 $reply->push("additional", @$add) if $add; 208 } else { 209 print "ERROR: qdcount ", $query->header->qdcount, 210 "unsupported\n" if $self->{"Verbose"}; 211 $reply->header->rcode("FORMERR"); 212 } 213 } else { 214 print "ERROR: opcode ", $query->header->opcode, " unsupported\n" 215 if $self->{"Verbose"}; 216 $reply->header->rcode("FORMERR"); 217 } 218 219 220 221 if (!defined ($headermask)) { 222 $reply->header->ra(1); 223 $reply->header->ad(0); 224 } else { 225 $reply->header->aa(1) if $headermask->{'aa'}; 226 $reply->header->ra(1) if $headermask->{'ra'}; 227 $reply->header->ad(1) if $headermask->{'ad'}; 228 } 229 230 231 $reply->header->cd($query->header->cd); 232 $reply->header->rd($query->header->rd); 233 $reply->header->id($query->header->id); 234 235 $reply->header->print if $self->{"Verbose"} && defined $headermask; 236 237 return $reply; 238} 239 240#------------------------------------------------------------------------------ 241# readfromtcp - read from a TCP client 242#------------------------------------------------------------------------------ 243 244sub readfromtcp { 245 my ($self, $sock) = @_; 246 return -1 unless defined $self->{"_tcp"}{$sock}; 247 my $peer = $self->{"_tcp"}{$sock}{"peer"}; 248 my $charsread = $sock->sysread( 249 $self->{"_tcp"}{$sock}{"inbuffer"}, 250 16384); 251 $self->{"_tcp"}{$sock}{"timeout"} = time()+120; # Reset idle timer 252 print "Received $charsread octets from $peer\n" if $self->{"Verbose"}; 253 if ($charsread == 0) { # 0 octets means socket has closed 254 print "Connection to $peer closed or lost.\n" if $self->{"Verbose"}; 255 $self->{"select"}->remove($sock); 256 $sock->close(); 257 delete $self->{"_tcp"}{$sock}; 258 return $charsread; 259 } 260 return $charsread; 261} 262 263#------------------------------------------------------------------------------ 264# tcp_connection - Handle a TCP connection. 265#------------------------------------------------------------------------------ 266 267sub tcp_connection { 268 my ($self, $sock) = @_; 269 270 if (not $self->{"_tcp"}{$sock}) { 271 # We go here if we are called with a listener socket. 272 my $client = $sock->accept; 273 if (not defined $client) { 274 print "TCP connection closed by peer before we could accept it.\n" if $self->{"Verbose"}; 275 return 0; 276 } 277 my $peerport= $client->peerport; 278 my $peerhost = $client->peerhost; 279 280 print "TCP connection from $peerhost:$peerport\n" if $self->{"Verbose"}; 281 $client->blocking(0); 282 $self->{"_tcp"}{$client}{"peer"} = "tcp:".$peerhost.":".$peerport; 283 $self->{"_tcp"}{$client}{"state"} = STATE_ACCEPTED; 284 $self->{"_tcp"}{$client}{"socket"} = $client; 285 $self->{"_tcp"}{$client}{"timeout"} = time()+120; 286 $self->{"select"}->add($client); 287 # After we accepted we will look at the socket again 288 # to see if there is any data there. ---Olaf 289 $self->loop_once(0); 290 } else { 291 # We go here if we are called with a client socket 292 my $peer = $self->{"_tcp"}{$sock}{"peer"}; 293 294 if ($self->{"_tcp"}{$sock}{"state"} == STATE_ACCEPTED) { 295 if (not $self->{"_tcp"}{$sock}{"inbuffer"} =~ s/^(..)//s) { 296 return; # Still not 2 octets ready 297 } 298 my $msglen = unpack("n", $1); 299 print "Removed 2 octets from the input buffer from $peer.\n". 300 "$peer said his query contains $msglen octets.\n" 301 if $self->{"Verbose"}; 302 $self->{"_tcp"}{$sock}{"state"} = STATE_GOT_LENGTH; 303 $self->{"_tcp"}{$sock}{"querylength"} = $msglen; 304 } 305 # Not elsif, because we might already have all the data 306 if ($self->{"_tcp"}{$sock}{"state"} == STATE_GOT_LENGTH) { 307 # return if not all data has been received yet. 308 return if $self->{"_tcp"}{$sock}{"querylength"} > length $self->{"_tcp"}{$sock}{"inbuffer"}; 309 310 my $qbuf = substr($self->{"_tcp"}{$sock}{"inbuffer"}, 0, $self->{"_tcp"}{$sock}{"querylength"}); 311 substr($self->{"_tcp"}{$sock}{"inbuffer"}, 0, $self->{"_tcp"}{$sock}{"querylength"}) = ""; 312 my $query = Net::DNS::Packet->new(\$qbuf); 313 my $reply = $self->make_reply($query, $sock->peerhost); 314 if (not defined $reply) { 315 print "I couldn't create a reply for $peer. Closing socket.\n" 316 if $self->{"Verbose"}; 317 $self->{"select"}->remove($sock); 318 $sock->close(); 319 delete $self->{"_tcp"}{$sock}; 320 return; 321 } 322 my $reply_data = $reply->data; 323 my $len = length $reply_data; 324 $self->{"_tcp"}{$sock}{"outbuffer"} = pack("n", $len) . $reply_data; 325 print "Queued ", 326 length $self->{"_tcp"}{$sock}{"outbuffer"}, 327 " octets to $peer\n" 328 if $self->{"Verbose"}; 329 # We are done. 330 $self->{"_tcp"}{$sock}{"state"} = STATE_SENDING; 331 } 332 } 333} 334 335#------------------------------------------------------------------------------ 336# udp_connection - Handle a UDP connection. 337#------------------------------------------------------------------------------ 338 339sub udp_connection { 340 my ($self, $sock) = @_; 341 342 my $buf = ""; 343 344 $sock->recv($buf, &Net::DNS::PACKETSZ); 345 my ($peerhost,$peerport) = ($sock->peerhost, $sock->peerport); 346 347 print "UDP connection from $peerhost:$peerport\n" if $self->{"Verbose"}; 348 349 my $query = Net::DNS::Packet->new(\$buf); 350 351 my $reply = $self->make_reply($query, $peerhost) || return; 352 my $reply_data = $reply->data; 353 354 local $| = 1 if $self->{"Verbose"}; 355 print "Writing response - " if $self->{"Verbose"}; 356 357 if ($sock->send($reply_data)) { # 358 print "done\n" if $self->{"Verbose"}; 359 } 360 else { 361 print "failed to send reply: $!\n" if $self->{"Verbose"}; 362 } 363 } 364 365 366sub get_open_tcp { 367 my $self=shift; 368 return keys %{$self->{"_tcp"}}; 369} 370 371 372#------------------------------------------------------------------------------ 373# loop_once - Just check "once" on sockets already set up 374#------------------------------------------------------------------------------ 375 376# This function might not actually return immediately. If an AXFR request is 377# coming in which will generate a huge reply, we will not relinquish control 378# until our outbuffers are empty. 379 380# 381# NB this method may be subject to change and is therefore left 'undocumented' 382# 383 384sub loop_once { 385 my ($self, $timeout) = @_; 386 $timeout=0 unless defined($timeout); 387 print ";loop_once called with $timeout \n" if $self->{"Verbose"} >4; 388 foreach my $sock (keys %{$self->{"_tcp"}}) { 389 $timeout = 0.1 if $self->{"_tcp"}{$sock}{"outbuffer"}; 390 } 391 my @ready = $self->{"select"}->can_read($timeout); 392 393 foreach my $sock (@ready) { 394 my $protonum = $sock->protocol; 395 # This is a weird and nasty hack. Although not incorrect, 396 # I just don't know why ->protocol won't tell me the protocol 397 # on a connected socket. --robert 398 $protonum = getprotobyname('tcp') if not defined $protonum and $self->{"_tcp"}{$sock}; 399 400 my $proto = getprotobynumber($protonum); 401 if (!$proto) { 402 print "ERROR: connection with unknown protocol\n" 403 if $self->{"Verbose"}; 404 } elsif (lc($proto) eq "tcp") { 405 406 $self->readfromtcp($sock) && 407 $self->tcp_connection($sock); 408 } elsif (lc($proto) eq "udp") { 409 $self->udp_connection($sock); 410 } else { 411 print "ERROR: connection with unsupported protocol $proto\n" 412 if $self->{"Verbose"}; 413 } 414 } 415 my $now = time(); 416 # Lets check if any of our TCP clients has pending actions. 417 # (outbuffer, timeout) 418 foreach my $s (keys %{$self->{"_tcp"}}) { 419 my $sock = $self->{"_tcp"}{$s}{"socket"}; 420 if ($self->{"_tcp"}{$s}{"outbuffer"}) { 421 # If we have buffered output, then send as much as the OS will accept 422 # and wait with the rest 423 my $len = length $self->{"_tcp"}{$s}{"outbuffer"}; 424 my $charssent = $sock->syswrite($self->{"_tcp"}{$s}{"outbuffer"}); 425 print "Sent $charssent of $len octets to ",$self->{"_tcp"}{$s}{"peer"},".\n" 426 if $self->{"Verbose"}; 427 substr($self->{"_tcp"}{$s}{"outbuffer"}, 0, $charssent) = ""; 428 if (length $self->{"_tcp"}{$s}{"outbuffer"} == 0) { 429 delete $self->{"_tcp"}{$s}{"outbuffer"}; 430 $self->{"_tcp"}{$s}{"state"} = STATE_ACCEPTED; 431 if (length $self->{"_tcp"}{$s}{"inbuffer"} >= 2) { 432 # See if the client has send us enough data to process the 433 # next query. 434 # We do this here, because we only want to process (and buffer!!) 435 # a single query at a time, per client. If we allowed a STATE_SENDING 436 # client to have new requests processed. We could be easilier 437 # victims of DoS (client sending lots of queries and never reading 438 # from it's socket). 439 # Note that this does not disable serialisation on part of the 440 # client. The split second it should take for us to lookip the 441 # next query, is likely faster than the time it takes to 442 # send the response... well, unless it's a lot of tiny queries, 443 # in which case we will be generating an entire TCP packet per 444 # reply. --robert 445 $self->tcp_connection($self->{"_tcp"}{"socket"}); 446 } 447 } 448 $self->{"_tcp"}{$s}{"timeout"} = time()+120; 449 } else { 450 # Get rid of idle clients. 451 my $timeout = $self->{"_tcp"}{$s}{"timeout"}; 452 if ($timeout - $now < 0) { 453 print $self->{"_tcp"}{$s}{"peer"}," has been idle for too long and will be disconnected.\n" 454 if $self->{"Verbose"}; 455 $self->{"select"}->remove($sock); 456 $sock->close(); 457 delete $self->{"_tcp"}{$s}; 458 } 459 } 460 } 461} 462 463#------------------------------------------------------------------------------ 464# main_loop - Main nameserver loop. 465#------------------------------------------------------------------------------ 466 467sub main_loop { 468 my $self = shift; 469 470 while (1) { 471 print "Waiting for connections...\n" if $self->{"Verbose"}; 472 # You really need an argument otherwise you'll be burning 473 # CPU. 474 $self->loop_once(10); 475 } 476} 477 4781; 479 480__END__ 481 482=head1 NAME 483 484Net::DNS::Nameserver - DNS server class 485 486=head1 SYNOPSIS 487 488C<use Net::DNS::Nameserver;> 489 490=head1 DESCRIPTION 491 492Instances of the C<Net::DNS::Nameserver> class represent DNS server 493objects. See L</EXAMPLE> for an example. 494 495=head1 METHODS 496 497=head2 new 498 499 my $ns = Net::DNS::Nameserver->new( 500 LocalAddr => "10.1.2.3", 501 LocalPort => "5353", 502 ReplyHandler => \&reply_handler, 503 Verbose => 1 504 ); 505 506 507 508 my $ns = Net::DNS::Nameserver->new( 509 LocalAddr => ['::1' , '127.0.0.1' ], 510 LocalPort => "5353", 511 ReplyHandler => \&reply_handler, 512 Verbose => 1 513 ); 514 515Creates a nameserver object. Attributes are: 516 517 LocalAddr IP address on which to listen. Defaults to INADDR_ANY. 518 LocalPort Port on which to listen. Defaults to 53. 519 ReplyHandler Reference to reply-handling 520 subroutine Required. 521 NotifyHandler Reference to reply-handling 522 subroutine for queries with 523 opdcode NS_NOTIFY (RFC1996) 524 Verbose Print info about received 525 queries. Defaults to 0 (off). 526 527 528The LocalAddr attribute may alternatively be specified as a list of IP 529addresses to listen to. 530 531If IO::Socket::INET6 and Socket6 are available on the system you can 532also list IPv6 addresses and the default is '0' (listen on all interfaces on 533IPv6 and IPv4); 534 535 536The ReplyHandler subroutine is passed the query name, query class, 537query type and optionally an argument containing the peerhost the 538incoming query. It must return the response code and references to the 539answer, authority, and additional sections of the response. Common 540response codes are: 541 542 NOERROR No error 543 FORMERR Format error 544 SERVFAIL Server failure 545 NXDOMAIN Non-existent domain (name doesn't exist) 546 NOTIMP Not implemented 547 REFUSED Query refused 548 549For advanced usage it may also contain a headermaks containing an 550hashref with the settings for the C<aa>, C<ra>, and C<ad> 551header bits. The argument is of the form 552C<< { ad => 1, aa => 0, ra => 1 } >>. 553 554 555See RFC 1035 and the IANA dns-parameters file for more information: 556 557 ftp://ftp.rfc-editor.org/in-notes/rfc1035.txt 558 http://www.isi.edu/in-notes/iana/assignments/dns-parameters 559 560The nameserver will listen for both UDP and TCP connections. On 561Unix-like systems, the program will probably have to run as root 562to listen on the default port, 53. A non-privileged user should 563be able to listen on ports 1024 and higher. 564 565Returns a Net::DNS::Nameserver object, or undef if the object 566couldn't be created. 567 568See L</EXAMPLE> for an example. 569 570=head2 main_loop 571 572 $ns->main_loop; 573 574Start accepting queries. Calling main_loop never returns. 575 576=cut 577 578##### 579# 580# The functionality might change. Left "undocumented" for now. 581# 582=head2 loop_once 583 584 $ns->loop_once( [TIMEOUT_IN_SECONDS] ); 585 586Start accepting queries, but returns. If called without a parameter, 587the call will not return until a request has been received (and 588replied to). If called with a number, that number specifies how many 589seconds (even fractional) to maximum wait before returning. If called 590with 0 it will return immediately unless there's something to do. 591 592Handling a request and replying obviously depends on the speed of 593ReplyHandler. Assuming ReplyHandler is super fast, loop_once should spend 594just a fraction of a second, if called with a timeout value of 0 seconds. 595One exception is when an AXFR has requested a huge amount of data that 596the OS is not ready to receive in full. In that case, it will keep 597running through a loop (while servicing new requests) until the reply 598has been sent. 599 600In case loop_once accepted a TCP connection it will immediatly check 601if there is data to be read from the socket. If not it will return and 602you will have to call loop_once() again to check if there is any data 603waiting on the socket to be processed. In most cases you will have to 604count on calling "loop_once" twice. 605 606A code fragment like: 607 $ns->loop_once(10); 608 while( $ns->get_open_tcp() ){ 609 $ns->loop_once(0); 610 } 611 612Would wait for 10 seconds for the initial connection and would then 613process all TCP sockets until none is left. 614 615=head2 get_open_tcp 616 617In scalar context returns the number of TCP connections for which state 618is maintained. In array context it returns IO::Socket objects, these could 619be useful for troubleshooting but be careful using them. 620 621=head1 EXAMPLE 622 623The following example will listen on port 5353 and respond to all queries 624for A records with the IP address 10.1.2.3. All other queries will be 625answered with NXDOMAIN. Authority and additional sections are left empty. 626The $peerhost variable catches the IP address of the peer host, so that 627additional filtering on its basis may be applied. 628 629 #!/usr/bin/perl 630 631 use Net::DNS::Nameserver; 632 use strict; 633 use warnings; 634 635 sub reply_handler { 636 my ($qname, $qclass, $qtype, $peerhost,$query) = @_; 637 my ($rcode, @ans, @auth, @add); 638 639 print "Received query from $peerhost\n"; 640 $query->print; 641 642 643 if ($qtype eq "A" && $qname eq "foo.example.com" ) { 644 my ($ttl, $rdata) = (3600, "10.1.2.3"); 645 push @ans, Net::DNS::RR->new("$qname $ttl $qclass $qtype $rdata"); 646 $rcode = "NOERROR"; 647 }elsif( $qname eq "foo.example.com" ) { 648 $rcode = "NOERROR"; 649 650 }else{ 651 $rcode = "NXDOMAIN"; 652 } 653 654 655 # mark the answer as authoritive (by setting the 'aa' flag 656 return ($rcode, \@ans, \@auth, \@add, { aa => 1 }); 657 } 658 659 my $ns = Net::DNS::Nameserver->new( 660 LocalPort => 5353, 661 ReplyHandler => \&reply_handler, 662 Verbose => 1, 663 ) || die "couldn't create nameserver object\n"; 664 665 $ns->main_loop; 666 667=head1 BUGS 668 669Limitations in perl 5.8.6 makes it impossible to guarantee that 670replies to UDP queries from Net::DNS::Nameserver are sent from the 671IP-address they were received on. This is a problem for machines with 672multiple IP-addresses and causes violation of RFC2181 section 4. 673Thus a UDP socket created listening to INADDR_ANY (all available 674IP-addresses) will reply not necessarily with the source address being 675the one to which the request was sent, but rather with the address that 676the operating system choses. This is also often called "the closest 677address". This should really only be a problem on a server which has 678more than one IP-address (besides localhost - any experience with IPv6 679complications here, would be nice). If this is a problem for you, a 680work-around would be to not listen to INADDR_ANY but to specify each 681address that you want this module to listen on. A seperate set of 682sockets will then be created for each IP-address. 683 684=head1 COPYRIGHT 685 686Copyright (c) 1997-2002 Michael Fuhr. 687 688Portions Copyright (c) 2002-2004 Chris Reinhardt. 689 690Portions Copyright (c) 2005-2007 O.M, Kolkman, RIPE NCC. 691 692Portions Copyright (c) 2005 Robert Martin-Legene. 693 694All rights reserved. This program is free software; you may redistribute 695it and/or modify it under the same terms as Perl itself. 696 697=head1 SEE ALSO 698 699L<perl(1)>, L<Net::DNS>, L<Net::DNS::Resolver>, L<Net::DNS::Packet>, 700L<Net::DNS::Update>, L<Net::DNS::Header>, L<Net::DNS::Question>, 701L<Net::DNS::RR>, RFC 1035 702 703=cut 704