-
-
Notifications
You must be signed in to change notification settings - Fork 922
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolver failing on IPv6-only hosts #2279
Comments
Debugged this on an IPv6-only VM (thanks @lupine) and discovered the following:
The main difference between connected and unconnected UDP (ConnectedUDP versus UnconnectedUDP in resolv.rb) appears to be that unconnected uses send(...., @host, @PORT) where connected uses the form without host and port. @lupine earlier theorized that the request may not be coming back to the right place, and that seems to fit with this discovery. So it seems like there's a problem with UDP doing a send with host = "::" followed by a select. Binding to the wrong address, most likely? |
I've had a bit of a poke with strace in a few spare minutes. YARV seems to be defaulting to ConnectedUDP, rather than UnconnectedUDP - or at least, I see this sequence:
JRuby looks more like this:
That said, I do think recvfrom() is returning the data the kernel received from the DNS server. Quite what (J)Ruby is doing with it after that, I've not had a chance to look at - there are futex timeouts and things, and it's all a bit messy. I do wonder if a testcase that pokes UnconnectedUDP directly would fail on YARV? And why are they picking different resolution strategies on the same machine? I don't have time to look right now, but I'll keep digging as and when I can. |
I think I'll need access to that VM again to keep working on this, but your observation is interesting. resolv.rb chooses "connected" vs "unconnected" using code like this: def make_udp_requester # :nodoc:
nameserver_port = @config.nameserver_port
if nameserver_port.length == 1
Requester::ConnectedUDP.new(*nameserver_port[0])
else
Requester::UnconnectedUDP.new(*nameserver_port)
end
end The list of nameserver_port comes from a pipeline of config logic that appears to default to parsing resolv.conf on a unix-like system. If you can determine why we're not ending up with nameserver_port.length == 1 on JRuby, it would go a long way toward fixing this issue. |
The VMs are still sat around, same login details as before. Poke me on IRC if you need a hand getting back in / reminding of the contact details. I'll have some time to devote to this on Wednesday, I think, but I won't complain if you get there first ;) |
I'm a bit late, but I've got a test case that works on machines with IPv4 connectivity now. It works by poking Resolv::DNS::Requester::UnconnectedUDP directly: #!/usr/bin/env ruby
require 'resolv'
RESOLVER = ARGV[0]
NAME = ARGV[1]
puts ("JRuby " + JRUBY_VERSION ) if defined?(JRUBY_VERSION)
puts "Ruby " + RUBY_VERSION
puts "Resolver: " + RESOLVER
puts "Name: " + NAME
D = Resolv::DNS
name = D::Name.create( NAME )
msg = D::Message.new
msg.add_question( name, D::Resource::IN::A )
print "Connected: "
connected = D::Requester::ConnectedUDP.new( RESOLVER )
c_sender = connected.sender( msg, name, RESOLVER )
puts connected.request( c_sender, 5.0 ).size.to_s
print "Unconnected: "
unconnected = D::Requester::UnconnectedUDP.new( RESOLVER )
u_sender = unconnected.sender( msg, name, RESOLVER )
puts unconnected.request( u_sender, 5.0 ).size.to_s Quick results:
Other rubies: It works fine under MRI 1.9.3; fails under JRuby 9.0.0.0pre1. |
I've poked the logic in make_udp_requester a bit, and it seems that MRI and JRuby are both ending up with an UnconnectedUDP instance - eventually (on JRuby, you have to do a dns request before it's anything but nil):
The /etc/resolv.conf file looks like:
So this is actually fine, and the logic of using ConnectedUDP when there is one entry, but UnconnectedUDP when there is <>1 doesn't make any sense to me. Was the original intent to use UnconnectedUDP when no port was specified, perhaps? Going back to strace, MRI does this for UnconnectedUDP:
JRuby (9.0.0.0pre1) does this:
Which is to say... it receives the data, then spawns a child process, which subsequently segfaults, so losing it? |
And just for reference, if I have just a single nameserver entry in resolv.conf, then my ipv6-only host can resolve DNS just fine - presumably because it uses ConnectedUDP instead, which isn't all sorts of broken. |
Basic test case:
jruby -e 'require "resolv" ; Resolv::getaddresses("auth.bytemark.co.uk")'
On a machine with v4 networking turned off, and a valid /etc/resolv.conf containing only v6 resolvers, this hangs (no CPU usage, DNS queries going out and coming back) for a very long time before eventually raising
#<Resolv::ResolvError: no address for auth.bytemark.co.uk>
Here's a ctrl+\
The text was updated successfully, but these errors were encountered: