Skip Menu |

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

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

People
Owner: Nobody in particular
Requestors: john.mceleney [...] netservers.co.uk
Cc:
AdminCc:

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



Subject: Runaway rapid memory growth when handling Net::DNS::Packet
Date: Sat, 11 Oct 2014 10:54:42 +0100
To: bug-Net-DNS [...] rt.cpan.org
From: John McEleney <john.mceleney [...] netservers.co.uk>
I originally reported this bug over at Redhat's bugzilla because I was using Fedora. However, I've since determined that this bug also occurs on Ubuntu Trusty when version 0.80 of Net::DNS is used. Under Ubuntu I built Net::DNS 0.80 on the host from CPAN, so this is not a bug introduced downstream. Original report: https://bugzilla.redhat.com/show_bug.cgi?id=1151572 Description of problem: When I query the NS records for a certain domain using Net::DNS::Resolver::Recurse, the perl process gets stuck in a infinite loop, rapidly expanding in size until it is killed by the OOM killer. How reproducible: Can be reproduced every time you query certain domain(s). I've now reproduced it on Ubuntu Trusty, and four different Fedora 20 systems, one of which was a virgin system booted from the Fedora Live DVD. The problem does _not_ occur on CentOS/RHEL 6.5 or CentOS/RHEL 7 which ship with Net::DNS versions lower that 0.80. Steps to Reproduce: 1. Create a perl script that queries NS records for domain villamontanavista.co.uk 2. Run the script 3. Watch top and see the script grow in size until the OOM killer steps in. Actual results: Perl script devours all available memory until it is killed by OOM Killer Expected results: DNS records should be handled by the script and it should exit almost instantly Additional info: This perl script will always trigger the bug: ========================= #!/usr/bin/perl use strict; use Net::DNS; use Net::DNS::Resolver::Recurse; use Data::Dumper; select STDERR; $| = 1; select STDOUT; $| = 1; my $res = Net::DNS::Resolver::Recurse->new; $res->hints(); $res->recursion_callback(sub { my $packet = shift; print "==============\n".Dumper($packet)."\n--------------------\n"; for ($packet->additional){ print $_->string."\n"; } }); $res->tcp_timeout(10); $res->udp_timeout(10); print "Starting recursion\n"; my $packet=$res->query_dorecursion("villamontanavista.co.uk","NS"); print "Finished recursion\n"; ========================= Some strace output (goes on like this until killed): brk(0) = 0x18a1000 brk(0x18c2000) = 0x18c2000 brk(0) = 0x18c2000 brk(0x18e3000) = 0x18e3000 brk(0) = 0x18e3000 brk(0x1904000) = 0x1904000 brk(0) = 0x1904000 brk(0x1925000) = 0x1925000 brk(0) = 0x1925000 brk(0x1946000) = 0x1946000 brk(0) = 0x1946000 brk(0x1967000) = 0x1967000 brk(0) = 0x1967000 brk(0x1988000) = 0x1988000 brk(0) = 0x1988000 -- ----------------------------- John McEleney Netservers Ltd. 21 Signet Court Cambridge CB5 8LA http://www.netservers.co.uk ----------------------------- Tel. 01223 446000 Fax. 0870 4861970 ----------------------------- Registered in England Number: 04028770 -----------------------------
Thanks John, Acknowledged! We're working on a fix now. Regards, -- Willem
Hi John, hi Dick, Here is a patch that needs some more work, but at least works around the issue you found for now. Dick, could you review/improve? Thanks, -- Willem
Subject: Recurse.pm.patch
Index: Recurse.pm =================================================================== --- Recurse.pm (revision 1272) +++ Recurse.pm (working copy) @@ -136,7 +136,15 @@ my @answer = $packet->answer; # return authoritative answer return $packet if $packet->header->aa && grep $_->name eq $original->qname, @answer; - my @auth = grep $_->type eq 'NS', $packet->answer, $packet->authority; + + my @nsses = grep $_->type eq 'NS', $packet->answer, $packet->authority; + my @auth = grep (($domain ? lc $domain : '.') eq lc $_->name), @nsses; + if (!scalar(@auth) && scalar(@nsses)) { + # TODO: Filter on allowed owner names + $domain = @nsses[0]->name; + $nslist = $res->{cache}->{$domain} ||= []; + @auth = grep lc $domain eq lc $_->name, @nsses; + } print ";; cache nameservers for $domain.\n" if $res->{debug} && scalar(@auth); my %auth = map { lc $_->nsdname => 1 } @auth; my @glue = grep $auth{lc $_->name}, $packet->additional;
An improved fix is in the svn repository and will be in the next release. Thanks!