Bug 3794 - Dns.pm: Can't call method "qname" on an undefined value
Summary: Dns.pm: Can't call method "qname" on an undefined value
Status: RESOLVED FIXED
Alias: None
Product: Spamassassin
Classification: Unclassified
Component: Libraries (show other bugs)
Version: SVN Trunk (Latest Devel Version)
Hardware: All FreeBSD
: P3 normal
Target Milestone: 3.1.0
Assignee: SpamAssassin Developer Mailing List
URL: http://www.ijs.si/people/mark/trouble...
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-09-20 10:22 UTC by Mark Martinec
Modified: 2004-10-04 23:52 UTC (History)
0 users



Attachment Type Modified Status Actions Submitter/CLA Status
proposed patch patch None Daniel Quinlan [HasCLA]
proposed patch patch None Daniel Quinlan [HasCLA]

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Martinec 2004-09-20 10:22:08 UTC
Using 3.0.0-rc5, I came across a broken mail that causes SA 
to create an invalid DNS request, and on analyzing the DNS reply 
the Dns::do_rbl_lookup fails with: 
 
  Can't call method "qname" on an undefined value 
  at /usr/local/lib/perl5/site_perl/5.8.5/Mail/SpamAssassin/Dns.pm 
  line 194 
 
which blocks further mail processing (SA is being called from within 
amavisd-new, although I believe the problem is more general). 
 
Dumping the Net::DNS::Packet->string before and after the query 
(at bgsend and then at bgread) reveals the DNS format error: 
 
debug: rbl: launching DNS A query for 
guest.arnes.simaqcawaaagaaaaaaaaaaaaaaaaaaaaqahbaaa2aaaaaaaaaaaaaaaaaaaaaaaaqahbaaa.rhsbl.ahbl.org. 
in background 
 
before bgsend 
  (creating packet object by Net::DNS::Packet->new($host,$type) ): 
;; HEADER SECTION 
;; id = 51114 
;; qr = 0    opcode = QUERY    aa = 0    tc = 0    rd = 1 
;; ra = 0    ad = 0    cd = 0    rcode  = NOERROR 
;; qdcount = 1  ancount = 0  nscount = 0  arcount = 0 
;; QUESTION SECTION (1 record) 
;; 
guest.arnes.simaqcawaaagaaaaaaaaaaaaaaaaaaaaqahbaaa2aaaaaaaaaaaaaaaaaaaaaaaaqahbaaa.rhsbl.ahbl.org.  
IN      A 
;; ANSWER SECTION (0 records) 
;; AUTHORITY SECTION (0 records) 
;; ADDITIONAL SECTION (0 records) 
 
 
after bgread: 
;; HEADER SECTION 
;; id = 51114 
;; qr = 1    opcode = QUERY    aa = 0    tc = 0    rd = 1 
;; ra = 0    ad = 0    cd = 0    rcode  = FORMERR 
;; qdcount = 0  ancount = 0  nscount = 0  arcount = 0 
;; QUESTION SECTION (0 records) 
;; ANSWER SECTION (0 records) 
;; AUTHORITY SECTION (0 records) 
;; ADDITIONAL SECTION (0 records) 
 
Note the "rcode=FORMERR", and an empty (cleared) question section 
after the query. 
 
The bad data (sender address) comes directly from the "From:" 
header field of the broken mail message causing the problem. 
 
Regards 
   Mark
Comment 1 Justin Mason 2004-09-20 10:38:47 UTC
that's not too hot.  it kills further scanning of *other* messages, or just that
one message?

if the former, it should be in an eval { } block anyway.

aiming at 3.0.0
Comment 2 Mark Martinec 2004-09-20 11:31:12 UTC
> it kills further scanning of *other* messages, or just that 
> one message? 
 
In case of amavisd-new, it kills just that one message, which stays in the MTA 
queue (after a 4xx temporary failure) and delivery is re-attempted every so 
often for a couple of days, leaving a pile of intentionally preserved temporary 
files behind. 
 
> it should be in an eval { } block anyway. 
 
Perhaps, although I think a cleaner solution would be two-part: 
 
- don't assemble illegal DNS queries in the first place 
  (in this particular example one 'node label' in DNS parlance 
  exceeded 63 characters, and the complete query should 
  not be too long - rfc1034 mentions 255) 
 
- when analyzing the Net::DNS::Packet in process_dnsbl_result, 
  allow for its fields to be empty (the $packet->question in this case), 
  i.e. ignore the result, if does not appear valid. 
 
I think an eval {} could be used an additional safety net, 
but the known/expected cases should be handled explicitly. 
 
  Mark 
 
Comment 3 Theo Van Dinter 2004-09-20 11:39:18 UTC
Subject: Re:  Dns.pm: Can't call method "qname" on an undefined value

On Mon, Sep 20, 2004 at 11:31:13AM -0700, bugzilla-daemon@bugzilla.spamassassin.org wrote:
> I think an eval {} could be used an additional safety net, 
> but the known/expected cases should be handled explicitly. 

FYI: We really can't do much about this issue without having a message
attached (not cut/paste) to the ticket for debugging purposes.

I agree we should simply do the right thing instead of kluging around the
issue though (I think we use eval{} too much already).

Comment 4 Mark Martinec 2004-09-20 11:47:41 UTC
> We really can't do much about this issue without having a message 
> attached (not cut/paste) to the ticket for debugging purposes. 
 
Sure, attached, also: http://www.ijs.si/people/mark/trouble-sa-2.txt 
 
The message is a capture (postcat) directly from the MTA queue, untouched. 
Warning: may contain a virus. 
Comment 5 Michael Parker 2004-09-20 11:59:14 UTC
Subject: Re:  Dns.pm: Can't call method "qname" on an undefined value

What version of Net::DNS are you running?

I'm not able to recreate by checking that message with spamassassin on
the command line.

Michael

Comment 6 Mark Martinec 2004-09-20 13:02:48 UTC
Subject: Re:  Dns.pm: Can't call method "qname" on an undefined value

| I'm not able to recreate by checking that message with spamassassin on
| the command line.

Neither can I, for unknown reason.
(but I didn't investigate, as the broken DNS query
is clearly there if I debug the Dns.pm code).

perl -le 'use Net::DNS; print Net::DNS->version'
0.48

  Mark

Comment 7 Theo Van Dinter 2004-09-20 15:14:03 UTC
I also can't reproduce the issue.  Recommend pushing to 3.0.1 queue for further debugging.
Comment 8 Daniel Quinlan 2004-09-20 16:24:25 UTC
Created attachment 2354 [details]
proposed patch

add a bunch of defined() tests to catch some possible undefined values
Comment 9 Justin Mason 2004-09-20 16:38:10 UTC
As I was saying in IRC: IMO, we need to use eval { } with Net::DNS.

1. Net::DNS contains several explicit calls to die()

/usr/lib/perl5/Net/DNS/Nameserver.pm:   $sock->send($reply_data) or die "send: $!";
/usr/lib/perl5/Net/DNS/Nameserver.pm: ) || die "couldn't create nameserver
object\n";
/usr/lib/perl5/Net/DNS/Packet.pm:       #       die "dn_expand: loop:
offset=$offset (seen = ",
/usr/lib/perl5/Net/DNS/RR.pm:                 die $@;
/usr/lib/perl5/Net/DNS/RR.pm:           die "$rdata is inconsistent; length does
not match content"
/usr/lib/perl5/Net/DNS/RR.pm:           die 'Expected RFC3597 representation of
RDATA'
/usr/lib/perl5/Net/DNS/RR.pm:           die "$rdata is inconsistent; length does
not match content"

etc.

2. we don't currently have an eval{ } trap in the harvest_dnsbl_results() call
path from user code, so any die()s are propagated into the user code

3. Net::DNS' design is such that new objects are created, returned to us, and we
then are expected to call methods on those to get results.  This means that
(similar to this bug) there are many situations where we might try to call a
method that doesn't exist by that name on the object we've been given; this
results in a die() from perl itself.  The doco doesn't mention this case, but
then, according to the N:D documentation, this current bug should not exist
either, but yet it does. ;)

As far as I can see by a cursory examination, the Net::DNS object model
shouldn't screw up too much aside from this case, but I don't know for sure --
and that's subject to change in future N:D releases. for defensive-programming's
sake, we have to expect that we can receive die() exceptions from Net::DNS in
future.
Comment 10 Justin Mason 2004-09-20 16:43:55 UTC
+1

patch looks good for fixing for 3.0.0.   to reiterate: for 3.0.1, we need to add
use of eval { } at the harvest_dnsbl_results() level, to catch all possible
other Net::DNS screwups as well.
Comment 11 Michael Parker 2004-09-20 17:00:56 UTC
+1
Comment 12 Theo Van Dinter 2004-09-20 17:37:57 UTC
the patch is a bit larger than I expected, but I think it's ok

+1
Comment 13 Mark Martinec 2004-09-20 17:53:30 UTC
Subject: Re:  Dns.pm: Can't call method "qname" on an undefined value

Just to clarify why the supplied sample mail does not cause
'spamassassin -t' to die. Prepend a 'Return-Path: <test@example.com>'
to it, and the spamassassin will die just as well.

The difference is in the process_dnsbl_result where an empty
$self->{sender_host}, (i.e. envelope sender address) causes
further checks on DNS query result (on From address) to be skipped
(is this expected behaviour?).

In statement:
  my $question = ($packet->question)[0];

the ($packet->question) is an empty list, which is not against
Net::DNS::Packet specifications. There may be 0, 1, or any other
number of items in the list, at least theoretically.

  Mark

Comment 14 Daniel Quinlan 2004-09-20 20:15:27 UTC
Okay, checked in the fix with one minor change and I removed some of the
more complicated parts of the patch which I don't think are as necessary
and frankly make me nervous.

The minor change was adding a defined() check for $packet->header which is
used later.  I also removed the sections of the patch that check defined
values for non-objects, I don't think those are quite as critical so I wanted
to keep this as simple as possible.
Comment 15 Daniel Quinlan 2004-09-20 20:21:49 UTC
Created attachment 2355 [details]
proposed patch

patch for branch, please approve
Comment 16 Theo Van Dinter 2004-09-20 20:32:11 UTC
2355: +1
Comment 17 Justin Mason 2004-09-20 22:29:49 UTC
+1
Comment 18 Daniel Quinlan 2004-09-20 22:57:13 UTC
committed, moving to 3.1 for further changes
Comment 19 Justin Mason 2004-10-03 15:08:23 UTC
ok -- r51854 is a checkin of an eval { } block around the "hot spot" loop in
harvest_dnsbl_results() for 3.1.0.  that should catch any further wierd stuff
thrown by Net::DNS in this case.

if it looks good enough, feel free to close this bug...
Comment 20 Mark Martinec 2004-10-05 07:52:51 UTC
> if it looks good enough, feel free to close this bug... 
 
As far as I am concerned, this can be closed. Thanks!