[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

bug -- resolv.rb dies when "domain" in resolv.conf has no arg

Sam Roberts

1/17/2005 12:22:00 AM

Example input:

-- domain.rb --
domain
nameserver 1.2.3.4
--

What happens with an unpatched resolv.rb is:

[ensemble] ~/p/ruby/zeroconf $ ruby18 -rresolv -rpp -e '(r=Resolv::DNS::Config.new("./domain.conf")).lazy_initialize; pp r'
/usr/local/lib/ruby/1.8/resolv.rb:921:in `split': private method `scan' called for nil:NilClass (NoMethodError)
from /usr/local/lib/ruby/1.8/resolv.rb:788:in `lazy_initialize'
from /usr/local/lib/ruby/1.8/resolv.rb:788:in `map'
from /usr/local/lib/ruby/1.8/resolv.rb:788:in `lazy_initialize'
from /usr/local/lib/ruby/1.8/resolv.rb:761:in `synchronize'
from /usr/local/lib/ruby/1.8/resolv.rb:761:in `lazy_initialize'
from -e:1

Please don't tell me the resolv.conf synatx is invalid - these files are
automatically created by OS X's network system. Also, resolv.rb accepts
an empty nameserver and an empty search command without problems.

-- search.rb --
search
nameserver 1.2.3.4
--

Patch to fix this:

Index: 1.8-resolv.rb
===================================================================
--- 1.8-resolv.rb (revision 5)
+++ 1.8-resolv.rb (working copy)
@@ -734,7 +734,7 @@
when 'nameserver'
nameserver += args
when 'domain'
- search = [args[0]]
+ search = args[0, 1]
when 'search'
search = args
end
===================================================================

Without this patch, @search becomes [nil] when domain had no arguments,
causing death later.

This can be tested with:

ruby18 -r1.8-resolv -rpp -e '(r=Resolv::DNS::Config.new("./search.conf")).lazy_initialize; pp r'
ruby18 -r1.8-resolv -rpp -e '(r=Resolv::DNS::Config.new("./domain.conf")).lazy_initialize; pp r'

You can see the behaviour before/after the patch.

Note that search (before) and domain (now, instead of dieing) with no
arguments both surpress the automagical choice of a search path based on
Socket.hostname. I believe this to be the correct behaviour, because it
seems reasonable to want to surpress the lookup (as a config option),
and because this is how the OS X C library resolver behaves.

Thanks,
Sam




4 Answers

Tanaka Akira

1/18/2005 4:30:00 PM

0

In article <20050117002220.GA1001@ensemble.local>,
Sam Roberts <sroberts@uniserve.com> writes:

> [ensemble] ~/p/ruby/zeroconf $ ruby18 -rresolv -rpp -e '(r=Resolv::DNS::Config.new("./domain.conf")).lazy_initialize; pp r'
> /usr/local/lib/ruby/1.8/resolv.rb:921:in `split': private method `scan' called for nil:NilClass (NoMethodError)
> from /usr/local/lib/ruby/1.8/resolv.rb:788:in `lazy_initialize'
> from /usr/local/lib/ruby/1.8/resolv.rb:788:in `map'
> from /usr/local/lib/ruby/1.8/resolv.rb:788:in `lazy_initialize'
> from /usr/local/lib/ruby/1.8/resolv.rb:761:in `synchronize'
> from /usr/local/lib/ruby/1.8/resolv.rb:761:in `lazy_initialize'
> from -e:1

Thank you for the report.

> Note that search (before) and domain (now, instead of dieing) with no
> arguments both surpress the automagical choice of a search path based on
> Socket.hostname. I believe this to be the correct behaviour, because it
> seems reasonable to want to surpress the lookup (as a config option),
> and because this is how the OS X C library resolver behaves.

bind-9.3.0/lib/bind/resolv/res_init.c seems to ignore domain and
search directive with no arguments. So I modified resolv.rb to ignore
them. This may be incompatible with OS X C library resolver, though.
--
Tanaka Akira


Sam Roberts

1/19/2005 4:39:00 AM

0

Quoteing akr@m17n.org, on Wed, Jan 19, 2005 at 01:29:57AM +0900:
> In article <20050117002220.GA1001@ensemble.local>,
> Sam Roberts <sroberts@uniserve.com> writes:
>
> > [ensemble] ~/p/ruby/zeroconf $ ruby18 -rresolv -rpp -e '(r=Resolv::DNS::Config.new("./domain.conf")).lazy_initialize; pp r'
> > /usr/local/lib/ruby/1.8/resolv.rb:921:in `split': private method `scan' called for nil:NilClass (NoMethodError)
> > from /usr/local/lib/ruby/1.8/resolv.rb:788:in `lazy_initialize'
> > from /usr/local/lib/ruby/1.8/resolv.rb:788:in `map'
> > from /usr/local/lib/ruby/1.8/resolv.rb:788:in `lazy_initialize'
> > from /usr/local/lib/ruby/1.8/resolv.rb:761:in `synchronize'
> > from /usr/local/lib/ruby/1.8/resolv.rb:761:in `lazy_initialize'
> > from -e:1
>
> Thank you for the report.

Thank you for the fix!

> > Note that search (before) and domain (now, instead of dieing) with no
> > arguments both surpress the automagical choice of a search path based on
> > Socket.hostname. I believe this to be the correct behaviour, because it
> > seems reasonable to want to surpress the lookup (as a config option),
> > and because this is how the OS X C library resolver behaves.
>
> bind-9.3.0/lib/bind/resolv/res_init.c seems to ignore domain and
> search directive with no arguments. So I modified resolv.rb to ignore
> them. This may be incompatible with OS X C library resolver, though.

That's OK, it can't be compatible with everybody's resolver libraries,
so being compatible with bind9 seems very reasonable.

Sam



Sam Roberts

1/19/2005 3:04:00 PM

0


resolv.rb:877 does

raise ResolvError.new("DNS resolv error: #{name}")

This means that when Resolv::DNS fails to find at least one record for
a query, it raises an error, preventing the next resolver in @resolvers
from being checked (see Resolv#each_address()).

Symptoms:

- you can't do a DNS lookup, then fallback to a Hosts lookup:

resolv = Resolv.new([Resolv::DNS.new, Resolv::Hosts.new])

resolv.getaddress("localhost")

# This will fail (unless your DNS server has an entry for "localhost",
# some do). Doing the opposite (the default) does work, i.e. doing
# the hosts lookup, then the DNS lookup.


- resolv.rb:228 (and probably 256) are no-ops

Instead of getting ResolvError.new("no address for #{name}') raised as
it appears was intended, you will always get the lower level "DNS
resolv error".

- if you have two DNS resolvers registered the second will never be
reached

You might do this if the first uses resolv.conf for its configuration,
and you add a second with a default config specified with a Hash:

resolv = Resolv.new([Resolv::DNS.new, Resolv::DNS.new( ... my config ...) ])


- If you write you own resolver module, then the failure of the DNS
module prevents the next resolver from being used to attempt the
lookup.


Cheers,
Sam


Example patch:

===================================================================
--- 1.8-resolv.rb (revision 11)
+++ 1.8-resolv.rb (working copy)
@@ -226,6 +226,8 @@
def getaddress(name)
each_address(name) {|address| return address}
raise ResolvError.new("no address for #{name}")
+# - this line is a no-op, it isn't reached because an internal DNS error is
+# raised instead.
end

def getaddresses(name)
@@ -872,7 +874,8 @@
rescue OtherResolvError
raise ResolvError.new("DNS error: #{$!.message}")
end
- raise ResolvError.new("DNS resolv error: #{name}")
+# raise ResolvError.new("DNS resolv error: #{name}")
+# - this shouldn't be fatal, the next resolver might be able to resolve this name!
end

class NXDomain < ResolvError


Test code:

#!/usr/bin/ruby

require 'pp'
require 'socket'
require 'resolv'

puts "(C library resolver) localhost -->"
addr = IPSocket.getaddress("localhost")
pp addr

# This is the default, args = [Resolv::Hosts.new, Resolv::DNS.new]
resolv = Resolv.new

puts "(Hosts, DNS) localhost -->"
addr = resolv.getaddress("localhost")
pp addr
puts "OK - address resolves!"

begin
puts "(Hosts, DNS) asergh.net -->"
addr = resolv.getaddress("asergh.net")
pp addr
rescue
pp $!
unless($!.to_s =~ /^no address for/)
puts "BUG - this should have hit resolv.rb:228, instead it is returning a DNS-specific error!"
end
end

# This is trying DNS lookup before host lookup
resolv = Resolv.new([Resolv::DNS.new, Resolv::Hosts.new])

begin
puts "(resolv) localhost -->"
addr = resolv.getaddress("localhost")
pp addr
rescue
pp $!
puts "BUG - this failed to find localhost when the resolvers were reordered!"
end




Tanaka Akira

1/21/2005 11:13:00 AM

0

In article <20050119150325.GA1113@ensemble.local>,
Sam Roberts <sroberts@uniserve.com> writes:


> resolv.rb:877 does
>
> raise ResolvError.new("DNS resolv error: #{name}")
>
> This means that when Resolv::DNS fails to find at least one record for
> a query, it raises an error, preventing the next resolver in @resolvers
> from being checked (see Resolv#each_address()).

Thank you for the report.

Resolv::DNS#each_address shouldn't raise ResolvError.
--
Tanaka Akira