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;
}