Subject: | A failure or a signal during Net::DNS::Packet::decode results in missing sections in DNS packet object |
The 'decode' (or the 'new') method in Net::DNS::Packet uses an
eval in an attempt to capture possible failures (thrown signals)
while decoding a raw packet into a Net::DNS::Packet object.
In case of an error, the 'decode' (or the 'new') is supposed
to return undef and provide a failure reason in $@ .
Unfortunately the code in decode() returns a partially filled
packet object instead of undef when eval fails, so a caller
is unaware that decoding failed. A fix is trivial - attached.
Background story: A typical scenario (in SpamAssassin) is when
an application calls Net::DNS::Resolver::bgread() and receives
a reply packet object with a missing question section (or other
missing sections) - resulting in a reported warning.
This elusive bug occurs a couple times per day in case of mail
filtering with SpamAssassin, and has been observed for years,
resulting in the following (old) comment in code:
# odd. this should not happen, but clearly some DNS servers
# can return something that Net::DNS interprets as having no
# question section.
It took a couple of days of packet capturing, saving bytes as
read by recv() in bgread() and comparing them with captured
packets to prove that a packet with a missing question section
does not come from a faulty DNS server but is fabricated locally.
Instrumenting Net::DNS::Packet with debugging finally revealed
that on a rare occasion an alarm signal occurs sometime
during decoding of a packet and causes exit from eval (without
invalidating the partially decoded packet object), so all later
sections remain undecoded, i.e. resulting in an apparently valid
packet object but with a missing answer section, or a missing
question + answer (and later) sections.
I would appreciate if the attached patch would be accepted.
Subject: | Net-DNS-Packet.patch |
--- Net/DNS/Packet.pm.ori 2012-12-28 14:22:41.000000000 +0100
+++ Net/DNS/Packet.pm 2013-02-15 17:11:02.000000000 +0100
@@ -151,6 +151,9 @@
( $record, $offset ) = decode Net::DNS::RR( $data, $offset, $hash );
CORE::push( @{$self->{additional}}, $record );
}
+ 1;
+ } or do {
+ undef $self;
};
if ( $debug && $self ) {