I've looked into this more. The underlying cause is that Resolv expects nameservers to be specified as IP addresses, not as domain names. When using multiple nameservers, Resolv tries to match the IP address of the nameserver responding to one of the nameservers given as input, and if you give a domain name as input, there will be no match.
It makes sense for Resolv to only handle IP addresses as nameservers, as if you are providing a domain name to use as a nameserver, where would you look up the IP address of that nameserver to know where to connect? You can't use the resolver you are setting up to resolve that. This is the same reason that no operating system allows you to use a domain name as a DNS server.
I was able to come up with a workaround that uses the system resolver:
diff --git a/lib/resolv.rb b/lib/resolv.rb
index e7b45e785a..d529550bdb 100644
--- a/lib/resolv.rb
+++ b/lib/resolv.rb
@@ -1027,12 +1027,33 @@ def lazy_initialize
if config_hash.include? :nameserver_port
@nameserver_port = config_hash[:nameserver_port].map {|ns, port| [ns, (port || Port)] }
end
+
@search = config_hash[:search] if config_hash.include? :search
@ndots = config_hash[:ndots] if config_hash.include? :ndots
- if @nameserver_port.empty?
+ case @nameserver_port.length
+ when 0
@nameserver_port << ['0.0.0.0', Port]
+ when 1
+ # nothing
+ else
+ @nameserver_port = @nameserver_port.map do |host, port|
+ dns_name = true
+ case host
+ when /\A[0-9.]+\z/
+ dns_name = false
+ when /\A[a-fA-F0-9:]+\z/
+ dns_name = host.index(':')
+ end
+
+ if dns_name
+ host = Addrinfo.getaddrinfo(host, nil)[0]&.ip_address
+ end
+
+ [host, port]
+ end
end
+
if @search
@search = @search.map {|arg| Label.split(arg) }
else
However, I'm fairly sure this is a misuse of the resolv library, and therefore I'm going to close this. The fact that things appear to work with a single domain name is just an implementation detail, not by design (single nameserver uses Requester::ConnectedUDP instead of Requester::UnconnectedUDP).