SA Bugzilla – Bug 4154
is_dns_available fails to loop as designed
Last modified: 2005-02-24 10:15:04 UTC
Dns.pm's is_dns_available checks a randomly picked well-known site to see if DNS is working. My caching-only nameserver times out when looking up NS records for a site that's not in the cache. Not entirely surprising, with a 3-second timeout in SA. And my site is infinitely small (just me), so it's going to be fairly common that one of the well-known sites is not in cache. is_dns_available realizes this, and tries to loop, but the loop is coded wrong, because either a success or a failure breaks out of the loop! A timeout in lookup_ns will result in $result defined, but containing no records, and that triggers the "failed horribly" clause, setting $IS_DNS_AVAILABLE to zero. This, of course, results in many missed spams that are listedin DNSBLs. I *think* the bug fix is just to remove that whole else clause from is_dns_available, but as a Perl novice I'd certainly like someone to double-check that. And, you know, now that I look at it, it seems like is_dns_available uses lookup_ns to test general DNS availability, but lookup_ns has its own caching that would seem to defeat the point of the test if a site is ever hit twice! I believe this also explains bugs 3626 and 3925, and quite possibly any number of "why did this get through" complaints.
Subject: Re: New: is_dns_available fails to loop as designed upon timeouts On Thu, Feb 24, 2005 at 09:26:31AM -0800, bugzilla-daemon@bugzilla.spamassassin.org wrote: > is_dns_available realizes this, and tries to loop, but the loop is coded wrong, > because either a success or a failure breaks out of the loop! A timeout in > lookup_ns will result in $result defined, but containing no records, and that > triggers the "failed horribly" clause, setting $IS_DNS_AVAILABLE to zero. This, > of course, results in many missed spams that are listedin DNSBLs. Oh, I see what you're saying. Basically, the loop in question: for(my $retry = 3; $retry > 0 and $#domains>-1; $retry--) { my $domain = splice(@domains, rand(@domains), 1); dbg ("trying ($retry) $domain...", "dnsavailable", -2); [...] tries to pick a random domain and try it. but the section in question: if(defined $result && scalar @$result > 0) { [...] $IS_DNS_AVAILABLE = 1; last; [...] } else { dbg ("NS lookup of $domain failed horribly => Perhaps your resolv.conf isn't pointing at a valid server?", "dnsavailable", -1); $IS_DNS_AVAILABLE = 0; # should already be 0, but let's be sure. last; } So "last" is called either way and we don't actually try 3 times, only once. > And, you know, now that I look at it, it seems like is_dns_available uses > lookup_ns to test general DNS availability, but lookup_ns has its own caching > that would seem to defeat the point of the test if a site is ever hit twice! Judging by the code, the cache only exists for the lifetime of 1 message check. When rbl_finish() is called post-check, the cache is destroyed.
moving to 3.1 queue
ok, patch committed. r155223 basically, lookup_ns will always return defined unless Net::DNS dies. in that case, the result is an empty array.
This patch has made me very happy. Thanks! One suggestion: You might want to include $self->{res}->errorstring in the dbg message for the NS failure.
*** Bug 3925 has been marked as a duplicate of this bug. ***