Ruby has problems with getaddrinfo(3)

Today I was trying to deploy some rails code to a host with both an RFC1918 and IPv6 address. The RFC1918 address is only valid within my CREDIL office, while the IPv6 is globally unique. When I’m in the office, IPv4 or IPv6 is fine, when I’m not, then it has to be IPv6.

With other applications when I do this, I sometimes get a delay as it tries the RFC1918 address, fails and tries IPv6 instead. SSH works great like this.

Ruby 1.8 (at least) fails: the RFC1918 address does not connect, and then ruby gives up. This makes Capistrano fail.

Capistrano uses Net::SSH, which calls TCPSocket.open. This is implemented in C code in the ruby interpreter. My reading of ruby-1.9.2-p0/ext/socket/ipsocket.c suggests that it might be okay in ruby 1.9, but I didn’t look at the 1.8 code yet, and I haven’t tried ruby 1.9.p

The following code exercises the problem, but you need to have an address which is both IPv6 and IPv4. It also does not seem to be consistent: it seems to depend on the network activity a bit. In theory, /etc/gai.conf can change the order that is returned, but I suspect that ruby is not using the system getaddrinfo(3).

% cat socktest.rb require 'socket' require 'timeout'

factory = TCPSocket n = factory.open(“sakura.gatineau.credil.org”, 22)

puts n.readlines n.close </code>