Skip Menu |

This queue is for tickets about the Net-DNS CPAN distribution.

Report information
The Basics
Id: 18580
Status: resolved
Priority: 0/
Queue: Net-DNS

People
Owner: Nobody in particular
Requestors: estair [...] ilm.com
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 0.57
Fixed in: (no value)



Subject: rcode not set if lookup fails and rcode=NXDOMAIN or rcode=SERVFAIL
v5.8.8 built for x86_64-linux-thread-multi perl-Net-DNS-0.57-1 x86-64 both on Fedora5 and RHEL4.2 Net::DNS does not appear to set the value of ->{header}->{rcode} (or incidentally ->{header}->{ancount}) unless the query is successful. Inline is the output of this script with the resolver set to debug output. You can compare the obviously set rcode values in the header vs the undefined/empty values in the output. Attached is a script I've just written with this you can use to verify. Cheers, /eli ######### successful query: ############ [estair@adroit bin]$ clear ; ./check_dns_host.pl -q FORWARD -H google.com -w 100 -c 200 -r 3 ;; search(google.com, A, IN) ;; query(google.com, A, IN) ;; setting up an AF_INET() family type UDP socket ;; send_udp(10.65.1.108:53) ;; answer from 10.65.1.108:53 : 76 bytes ;; HEADER SECTION ;; id = 15376 ;; qr = 1 opcode = QUERY aa = 0 tc = 0 rd = 0 ;; ra = 1 ad = 0 cd = 0 rcode = NOERROR ;; qdcount = 1 ancount = 3 nscount = 0 arcount = 0 ;; QUESTION SECTION (1 record) ;; google.com. IN A ;; ANSWER SECTION (3 records) google.com. 118 IN A 64.233.187.99 google.com. 118 IN A 64.233.167.99 google.com. 118 IN A 72.14.207.99 ;; AUTHORITY SECTION (0 records) ;; ADDITIONAL SECTION (0 records) $query_returncode: NOERROR $query->{header}->{ancount}: 3 $query->{header}->{rcode}: NOERROR $query_returncode: NOERROR DNS OK: ANSWERS=(3) QUERY_RETURNVAL=(64.233.187.99 64.233.167.99 72.14.207.99) ELAPSED=(5 ms) | DurationMS=5 ######### failed query: ############ [estair@adroit bin]$ clear ; ./check_dns_host.pl -q FORWARD -H blah.google.com -w 100 -c 200 -r 3 ;; search(blah.google.com, A, IN) ;; query(blah.google.com, A, IN) ;; setting up an AF_INET() family type UDP socket ;; send_udp(10.65.1.108:53) ;; answer from 10.65.1.108:53 : 179 bytes ;; HEADER SECTION ;; id = 4216 ;; qr = 1 opcode = QUERY aa = 0 tc = 0 rd = 0 ;; ra = 1 ad = 0 cd = 0 rcode = NOERROR ;; qdcount = 1 ancount = 0 nscount = 4 arcount = 4 ;; QUESTION SECTION (1 record) ;; blah.google.com. IN A ;; ANSWER SECTION (0 records) ;; AUTHORITY SECTION (4 records) google.com. 85856 IN NS ns3.google.com. google.com. 85856 IN NS ns4.google.com. google.com. 85856 IN NS ns1.google.com. google.com. 85856 IN NS ns2.google.com. ;; ADDITIONAL SECTION (4 records) ns3.google.com. 85856 IN A 216.239.36.10 ns4.google.com. 85856 IN A 216.239.38.10 ns1.google.com. 85856 IN A 216.239.32.10 ns2.google.com. 85856 IN A 216.239.34.10 ;; search(blah.google.com.lucasfilm.com, A, IN) ;; query(blah.google.com.lucasfilm.com, A, IN) ;; setting up an AF_INET() family type UDP socket ;; send_udp(10.65.1.108:53) ;; answer from 10.65.1.108:53 : 132 bytes ;; HEADER SECTION ;; id = 4217 ;; qr = 1 opcode = QUERY aa = 1 tc = 0 rd = 0 ;; ra = 1 ad = 0 cd = 0 rcode = NXDOMAIN ;; qdcount = 1 ancount = 0 nscount = 1 arcount = 0 ;; QUESTION SECTION (1 record) ;; blah.google.com.lucasfilm.com. IN A ;; ANSWER SECTION (0 records) ;; AUTHORITY SECTION (1 record) lucasfilm.com. 3600 IN SOA lucas-dc2.lucas.alllucas.com. hostmaster.lucas.alllucas.com. ( 2001401971 ; Serial 900 ; Refresh 600 ; Retry 86400 ; Expire 3600 ) ; Minimum TTL ;; ADDITIONAL SECTION (0 records) $query_returncode: $query->{header}->{ancount}: $query->{header}->{rcode}: $query_returncode: DNS : ANSWERS=() QUERY_RETURNVAL=() ELAPSED=(9 ms) | DurationMS=9
Subject: check_dns_host.pl
#!/usr/bin/perl #FILE: check_dns.pl #SYNOPSIS: check A/PTR records for a host. Added support for checking matching returnval vs. a string, and #of responses. #use strict; #use warnings; use Net::DNS; use Getopt::Long; use Pod::Usage; use Time::HiRes qw( usleep ualarm gettimeofday tv_interval ); ### Define ARGV options: my ($host,$match,$server,$timeout,$wlevel,$clevel,$retvalnum,$query_type); GetOptions( "H=s" => \$host, "m=s" => \$match, "s=s" => \$server, "q=s" => \$query_type, "t=i" => \$timeout, "r=i" => \$retvalnum, "w=i" => \$wlevel, "c=i" => \$clevel ); if(!$timeout){$timeout=10}; alarm($timeout); $SIG{ALRM} = sub {print "$0 timed out.\n"; exit 2;}; if(!$host || !$wlevel || !$clevel){ pod2usage("$0: fixme"); exit 3; } if($wlevel>=$clevel){ pod2usage("$0: fixme"); exit 3; # Nagios: unknown } ###################################################################################### ### START code: ###################################################################################### ### define program vars: my ($header,$exitstate,@retval,$checkfailed); # Initialize the DNS Resolver package and start timer: my $res = Net::DNS::Resolver->new( recurse => 0, debug => 1, ); my ($t0, $t1); $t0 = [gettimeofday]; ### define program flow: &query_run; &query_lint; &query_compile; &eval; ###################################################################################### ### Execute defined query: # Perform the lookup, and set status values: sub query_run { $query = $res->search("$host"); # Calculate time elapsed for lookup: $t1 = [gettimeofday]; $elapsed = int (1000 * tv_interval ( $t0, $t1)); $query_returncode = ($query->{header}->{rcode}); $query_count = ($query->{header}->{ancount}); } #/sub query_run sub query_compile { # Populate comparison array based on query type: if ($query_type eq "FORWARD") { # A queries: foreach my $rr ($query->answer) { next unless $rr->type eq "A"; my $ip = $rr->address; push (@retval, $ip); } } #/if ($query_type eq "FORWARD") if ($query_type eq "REVERSE") { # PTR queries: foreach my $rr ($query->answer) { next unless $rr->type eq "PTR"; my $hostname = $rr->ptrdname; push (@retval, $hostname); } } #/if ($query_type eq "REVERSE") } #/sub query_compile sub query_lint { print "\$query_returncode: $query_returncode \n"; unless ($query_returncode) { print "\$query->{header}->{ancount}: $query->{header}->{ancount} \n"; print "\$query->{header}->{rcode}: $query->{header}->{rcode} \n"; $querycheck = "FAILED"; &exit; } print "\$query->{header}->{ancount}: $query->{header}->{ancount} \n"; print "\$query->{header}->{rcode}: $query->{header}->{rcode} \n"; } ###################################################################################### ### FUNCTION: eval ### Check for failure conditions: sub eval { # Query failed: if ($query_returncode ne "NOERROR") { $exitstate = "CRITICAL"; &exit; } # warn timeout threshhold exceeded: if ($elapsed > $wlevel) { $exitstate = "WARNING"; &exit; } # crit timeout threshhold exceeded: if ($elapsed > $clevel) { $exitstate = "CRITICAL"; &exit; } # num query returns out of specified bounds: if ($retvalnum) { ($retvalnum != $query_count) && ($exitstate = "CRITICAL"); if ($exitstate) { $checkfailed = qq{"RETVAL:$retvalnum" != "QUERYCOUNT:$query_count"}; &exit; } } # query return does not match specified string: if ($match) { foreach my $value (@retval) { ($match eq $value) || ($exitstate = "CRITICAL"); } if ($exitstate) { $checkfailed = qq{"MATCH:$match" != "RETVAL:@retval"}; &exit; } } # Yay! all seems OK... $query_returncode eq "NOERROR" && ($exitstate = "OK"); &exit; } ###################################################################################### ### FUNCTION: exit sub exit { print "\$query_returncode: $query_returncode \n"; # Query failures: if ($queryfailed) { die "QUERY FAILED"; } # check failures: if ($checkfailed) { print "EXITING ERROR \n"; $output = "DNS $exitstate=($checkfailed) QUERYRETURNCODE=($query_returncode) ANSWERS=($query_count) QUERY_RETURNVAL=(@retval) ELAPSED=(${elapsed} ms) | DurationMS=$elapsed"; } else { # print "EXITING NOERROR \n"; $output = "DNS $exitstate: ANSWERS=($query_count) QUERY_RETURNVAL=(@retval) ELAPSED=(${elapsed} ms) | DurationMS=$elapsed"; $checkfailed = ""; } print "$output \n"; exit 2 if(!$query_returncode); # Nagios: Critical exit 2 if($elapsed>$clevel); # Nagios: Critical exit 2 if($query_count != $retvalnum); # Nagios: Critical exit 2 if(!$checkfailed eq ""); # Nagios: Critical exit 1 if($elapsed>$wlevel); # Nagios: Warning exit 0; # Nagios: OK } ### perldoc: =head1 NAME check_dns.pl - DNS-Query and Statistics =head1 SYNOPSIS check_dns.pl -H host -s server -w wlevel -c clevel [-t timeout] host: The host to be resolved server: The DNS-server to ask timeout: Timeout in seconds wlevel: Warning treshhold (milliseconds) clevel: Critical treshhold (milliseconds) =head1 DESCRIPTION This asks a server to resolve a host. It returns OK if the process was successfull and took less than wlevel milliseconds. It returns a warning if it took less than clevel milliseconds. Everything else returns critical. (Also, if it takes longer than timeout.) =head1 PROBLEMS This contains a hardcoded perl lib directory. Might wanna change this if running on a machine with only one perl distribution. Not too reliable timing functions, I suppose. =head1 AUTHOR Copyright (c) 2003 Hannes Schulz <mail@hannes-schulz.de> =cut #</perldoc>
Subject: Re: [rt.cpan.org #18580] rcode not set if lookup fails and rcode=NXDOMAIN or rcode=SERVFAIL
Date: Fri, 7 Apr 2006 09:16:05 +0200
To: bug-Net-DNS [...] rt.cpan.org
From: "Olaf M. Kolkman" <olaf [...] dacht.net>
The example you provided does not seem to have a bug. Both returned packets in the failed query example are protocol compliant (rfc1034 and rfc1035). The first question (blah.google.com, A) returns a referral message. That is not what I would expect from a correctly functioning recursive nameserver. But I am not quite sure what kind of server is at 10.65.1.108. The second question (blah.google.com.lucasfilm.com., A) just correctly answers that there is no such domain by setting an rcode=NXDOMAIN. Note that you use the search function which will try to append the default domain (lucasfilm.com in your case) to the name if a direct match failed. --Olaf ------------------------------------------------------ Ik dacht net... heel even maar.
Download PGP.sig
application/pgp-signature 227b

Message body not shown because it is not plain text.

Subject: Re: [rt.cpan.org #18580] rcode not set if lookup fails and rcode=NXDOMAIN or rcode=SERVFAIL
Date: Fri, 07 Apr 2006 13:45:03 -0700
To: bug-Net-DNS [...] rt.cpan.org
From: Eli Stair <estair [...] ilm.com>
My point was that the array "$query->{header}->{rcode}" is not being set to NXDOMAIN when the rcode on the actual query return IS set to "NXDOMAIN"... the only value I've been able to get rcode set with on a return is "NOERROR"... I know the return was false, that was the point, in a failed NXDOMAIN query the 'rcode' and 'ancount' do not get defined. As the query return header shows: ;; HEADER SECTION ;; id = 4217 ;; qr = 1 opcode = QUERY aa = 1 tc = 0 rd = 0 ;; ra = 1 ad = 0 cd = 0 rcode = NXDOMAIN ;; qdcount = 1 ancount = 0 nscount = 1 arcount = 0 And the output of the (unset) values: $query->{header}->{ancount}: $query->{header}->{rcode}: Versus the successful query: ;; ra = 1 ad = 0 cd = 0 rcode = NOERROR ;; qdcount = 1 ancount = 3 nscount = 0 arcount = 0 $query->{header}->{ancount}: 3 $query->{header}->{rcode}: NOERROR /eli On Fri, 2006-04-07 at 03:16 -0400, Olaf M. Kolkman via RT wrote: Show quoted text
> <URL: http://rt.cpan.org/Ticket/Display.html?id=18580 > > > > The example you provided does not seem to have a bug. > > Both returned packets in the failed query example are protocol > compliant (rfc1034 and rfc1035). > > The first question (blah.google.com, A) returns a referral message. > That is not what I would expect from a correctly functioning > recursive nameserver. But I am not quite sure what kind of server is > at 10.65.1.108. > > The second question (blah.google.com.lucasfilm.com., A) just > correctly answers that there is no such domain by setting an > rcode=NXDOMAIN. Note that you use the search function which will try > to append the default domain (lucasfilm.com in your case) to the name > if a direct match failed. > > --Olaf > > > ------------------------------------------------------ > Ik dacht net... heel even maar. > > > >
Subject: Re: [rt.cpan.org #18580] rcode not set if lookup fails and rcode=NXDOMAIN or rcode=SERVFAIL
Date: Sat, 8 Apr 2006 10:31:21 +0200
To: bug-Net-DNS [...] rt.cpan.org
From: "Olaf M. Kolkman" <olaf [...] dacht.net>
Show quoted text
> > My point was that the array "$query->{header}->{rcode}" is not > being set > to NXDOMAIN when the rcode on the actual query return IS set to > "NXDOMAIN"... the only value I've been able to get rcode set with on a > return is "NOERROR"... I know the return was false, that was the > point, > in a failed NXDOMAIN query the 'rcode' and 'ancount' do not get > defined. > > As the query return header shows: >
Aha... I misread that. The problem that you encounter is that query and search have been tailored towards 'positive' answers. That is an early design decision that I am hesitant to change. What happens is that the returned object is only defined when the answer count is larger than 0. This is documented in the Resolver perlpod: Show quoted text
> Returns a "Net::DNS::Packet" object, or "undef" if no > answers were > found. If you need to examine the response packet whether > it contains > any answers or not, use the send() method instead.
I'd suggest you rewrite your testprogram to use send. The benefit is that you have a little more control about the search lists and so on. (I reckon that you hardly ever want to use the searchlist for these kind of benchmark tests.) I hope this answers your question. --Olaf ------------------------------------------------------ Ik dacht net... heel even maar.
Download PGP.sig
application/pgp-signature 227b

Message body not shown because it is not plain text.

Subject: Re: [rt.cpan.org #18580] rcode not set if lookup fails and rcode=NXDOMAIN or rcode=SERVFAIL
Date: Sat, 8 Apr 2006 09:13:39 -0600
To: "Olaf M. Kolkman via RT" <bug-Net-DNS [...] rt.cpan.org>
From: Michael Fuhr <mike [...] fuhr.org>
On Sat, Apr 08, 2006 at 04:31:51AM -0400, Olaf M. Kolkman via RT wrote: Show quoted text
> The problem that you encounter is that query and search have been > tailored towards 'positive' answers. That is an early design decision > that I am hesitant to change. > > What happens is that the returned object is only defined when the > answer count is larger than 0.
The rationale behind that decision is that it mimics the behavior of the C resolver functions res_query() and res_search(), which return -1 if the response contained no answer records. Net::DNS has behaved that way since the beginning; changing it would break all the existing code that relies on that documented behavior. -- Michael Fuhr
Subject: RE: [rt.cpan.org #18580] rcode not set if lookup fails and rcode=NXDOMAIN or rcode=SERVFAIL
Date: Sat, 8 Apr 2006 11:26:29 -0700
To: <bug-Net-DNS [...] rt.cpan.org>
From: "Eli Stair" <estair [...] ilm.com>
Olaf, thanks for the clarification. My bad for not _reading_ the perldoc, and assuming the value would be set in all circumstances. I'll take that advice. Cheers, /eli Show quoted text
-----Original Message----- From: Olaf M. Kolkman via RT [mailto:bug-Net-DNS@rt.cpan.org] Sent: Sat 4/8/2006 1:31 AM To: Eli Stair Subject: Re: [rt.cpan.org #18580] rcode not set if lookup fails and rcode=NXDOMAIN or rcode=SERVFAIL <URL: http://rt.cpan.org/Ticket/Display.html?id=18580 >
> > My point was that the array "$query->{header}->{rcode}" is not > being set > to NXDOMAIN when the rcode on the actual query return IS set to > "NXDOMAIN"... the only value I've been able to get rcode set with on a > return is "NOERROR"... I know the return was false, that was the > point, > in a failed NXDOMAIN query the 'rcode' and 'ancount' do not get > defined. > > As the query return header shows: >
Aha... I misread that. The problem that you encounter is that query and search have been tailored towards 'positive' answers. That is an early design decision that I am hesitant to change. What happens is that the returned object is only defined when the answer count is larger than 0. This is documented in the Resolver perlpod:
> Returns a "Net::DNS::Packet" object, or "undef" if no > answers were > found. If you need to examine the response packet whether > it contains > any answers or not, use the send() method instead.
I'd suggest you rewrite your testprogram to use send. The benefit is that you have a little more control about the search lists and so on. (I reckon that you hardly ever want to use the searchlist for these kind of benchmark tests.) I hope this answers your question. --Olaf ------------------------------------------------------ Ik dacht net... heel even maar.
Download winmail.dat
application/ms-tnef 4k

Message body not shown because it is not plain text.

Subject: Re: [rt.cpan.org #18580] rcode not set if lookup fails and rcode=NXDOMAIN or rcode=SERVFAIL
Date: Sat, 8 Apr 2006 21:34:28 +0200
To: bug-Net-DNS [...] rt.cpan.org
From: "Olaf M. Kolkman" <olaf [...] dacht.net>
On Apr 8, 2006, at 5:14 PM, Michael Fuhr via RT wrote: Show quoted text
> > The rationale behind that decision is that it mimics the behavior > of the C resolver functions res_query() and res_search(), which > return -1 if the response contained no answer records. Net::DNS > has behaved that way since the beginning; changing it would break > all the existing code that relies on that documented behavior. >
Hi Michael, Good to see you're still keeping an eye on things <:-)> "I am hesitant to change" actually means .. "over my dead body" in this particular case. </:-) It would mean a major API change and that would be a bad idea indeed. --Olaf ------------------------------------------------------ Ik dacht net... heel even maar.
Download PGP.sig
application/pgp-signature 227b

Message body not shown because it is not plain text.