From: Sam Roberts Date: 2005-01-20T00:03:35+09:00 Subject: bug -- resolv.rb dies after Resolv::DNS is unsuccessful 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