Skip Menu |

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

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

People
Owner: Nobody in particular
Requestors: CONOR [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in:
  • 0.65
  • 0.66
Fixed in: (no value)



Subject: Modifying nameservers in a new() object leaks to subsequent calls
Using the attached 'modify-nameservers.pl' script, if you call without a parameter, 2 of 2 tests run will succeed. If you call with 'bad', 3 tests will run, and all will pass, but the test 3 reuses test 2's nameservers. It looks like the value of $worker->{nameservers} is being cached somehow, and the only workaround I've come up with is to save off the {nameservers} value before modifying it and then restoring after the ->search() 10.0.0.1 is the DNS server in /etc/resolv.conf on my machine 4.2.2.1 is a Level3/Verizon DNS server I'm using Ubuntu 10.04 with Perl 5.10.1 here is the output: conor@box:~/scratch/2011-07-28 $ perl modify-nameservers.pl 1: 66.7.199.108/devio.us using 10.0.0.1 2: 66.7.199.108/devio.us using 10.0.0.1 ok 1 - test_dns(devio.us): 1 1: 76.13.6.175/del.icio.us using 10.0.0.1 2: 76.13.6.175/del.icio.us using 10.0.0.1 ok 2 - test_dns(del.icio.us): 1 1..2 conor@box:~/scratch/2011-07-28 $ perl modify-nameservers.pl bad 1: 66.7.199.108/devio.us using 10.0.0.1 2: 66.7.199.108/devio.us using 10.0.0.1 ok 1 - test_dns(devio.us): 1 1: 212.124.110.54/pinboard.in using 10.0.0.1 2: 212.124.110.54/pinboard.in using 4.2.2.1 ok 2 - test_dns(pinboard.in, 4.2.2.1): 1 1: 76.13.6.175/del.icio.us using 4.2.2.1 2: 76.13.6.175/del.icio.us using 4.2.2.1 ok 3 - test_dns(del.icio.us): 1 1..3
Subject: modify-nameservers.pl
#!/usr/bin/perl -w ## modify-nameservers.pl -- shows a bug in Net::DNS when resetting nameservers use strict; use warnings; use Net::DNS; use Test::More qw(no_plan); my $mode = shift @ARGV; $mode = 'good' unless defined $mode; ## make a call that will succeed my $results = test_dns('66.7.199.108', 'devio.us'); is ($results, 1, "test_dns(devio.us): $results"); ## if $mode != good, modify the nameservers unless ($mode =~ /good/i) { $results = test_dns('212.124.110.54', 'pinboard.in', '4.2.2.1'); is ($results, 1, "test_dns(pinboard.in, 4.2.2.1): $results"); } ## make a call that _should_ succeed, but won't if we've modified the nameservers above $results = test_dns('76.13.6.175', 'del.icio.us'); is ($results, 1, "test_dns(del.icio.us): $results"); exit; ## subs below sub test_dns { # test_dns($ip, $hostname, [$dns_server]) - attempts to resolve $hostname to $ip, then reverses that and returns 0|1 for failure|success my ($ip, $hostname, $dns_server) = @_; my $results = 0; my $worker = Net::DNS::Resolver->new; $worker->{udp_timeout} = 10; # don't want to wait forever... print "1: $ip/$hostname using ", join(",", @{$worker->{nameservers}}), "\n"; if (defined $dns_server) { # need to empty the list of nameservers from /etc/resolv.conf and use passed parameter @{$worker->{nameservers}} = ($dns_server) unless ref $dns_server; @{$worker->{nameservers}} = @{$dns_server} if ref $dns_server eq 'ARRAY'; @{$worker->{searchlist}} = (); # fair to assume you won't want this either } print "2: $ip/$hostname using ", join(",", @{$worker->{nameservers}}), "\n"; my $response = $worker->search($hostname); if ($response) { for my $r ($response->answer) { my $local_ip = (defined $r->address) ? $r->address : 'unknown'; my $local_hostname = (defined $r->name) ? $r->name : 'unknown'; if ($local_ip eq $ip) { $results = 1; last; } } } else { $results = 0; } return $results; }
Hi Conor, A fresh new resolver instance is initialized with certain default values. The attributes containing those values should be read and altered by using instance *methods* such as $worker->nameserver($new_nameserver);. You should never bypass those methods and use the ``internal'' blessed hash yourself or the Resolver instance will not behave as intended. In your case, a new Resolver instance is initialized with a set of default values. The nameservers attribute is initialized with an ARRAY reference. You altered the nameservers like this: @{$worker->{nameservers}} = ($dns_server); So you replaced the values to which the *default* reference pointed! If you had replaced the reference you would have been fine, $worker->{nameservers} = [$dns_server]; , but you should *really* only set those values with the designated methods. So, the only correct way to do it is: $worker->nameserver( $dns_server ); Likewise you should never use $worker->{searchlist}, and $work->{udp_timeout} directly, but in stead use the $worker->searchlist and $worker->udp_timeout methods. I admit that I don't see how a searchlist should be cleared this way :), but in your case that is not a problem because you could have initialized it on object construction: my $worker = Net::DNS::Resolver->new(searchlist => []); Best regards, -- Willem