From: craig65535@... Date: 2015-10-12T17:43:30+00:00 Subject: [ruby-core:71064] [Ruby trunk - Feature #9925] rsock_addrinfo uses DNS family AF_UNSPEC for lookup causing high IPv6 AAAA volume Issue #9925 has been updated by Craig Davison. I have a similar issue. While running strace, I noticed that a ruby script sending a UDP datagram to localhost would call sendto twice. The first sendto used an IPv6 address, and would fail, and the second sendto used an IPv4 address and would succeed. The issue seems to be that sockets are created with a domain of PF_INET by default, but hostname lookups (getaddrinfo) are done with no address family hint. I have attempted to fix this in https://github.com/ruby/ruby/pull/1052 by reading the socket's address family in rsock_addrinfo(), and passing it as a hint to getaddrinfo(). Here is a short script that illustrates the problem. ~~~ require 'socket' socket = UDPSocket.new socket.send("123", 0, "localhost", 5556) ~~~ Here is the strace output, before my patch: ~~~ $ strace ~/ruby-master/bin/ruby ~/udp.rb 2>&1 | grep INET | egrep '(send|socket)' socket(PF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP) = 7 socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 8 socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = 8 sendto(7, "123", 3, 0, {sa_family=AF_INET6, sin6_port=htons(5556), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EAFNOSUPPORT (Address family not supported by protocol) sendto(7, "123", 3, 0, {sa_family=AF_INET, sin_port=htons(5556), sin_addr=inet_addr("127.0.0.1")}, 16) = 3 ~~~ And after my patch: ~~~ $ strace ~/ruby-fix-getaddrinfo/bin/ruby ~/udp.rb 2>&1 | grep INET | egrep '(send|socket)' socket(PF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP) = 7 socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 8 sendto(7, "123", 3, 0, {sa_family=AF_INET, sin_port=htons(5556), sin_addr=inet_addr("127.0.0.1")}, 1 ~~~ ---------------------------------------- Feature #9925: rsock_addrinfo uses DNS family AF_UNSPEC for lookup causing high IPv6 AAAA volume https://bugs.ruby-lang.org/issues/9925#change-54432 * Author: Aaron Stone * Status: Open * Priority: Normal * Assignee: ---------------------------------------- In ext/socket/raddrinfo.c, the function `rsock_addrinfo()` always uses `AF_UNSPEC` for DNS queries. This is causing me a very high volume of IPv6 DNS lookups. `rsock_addrinfo()` is used by TCPSocket (and all other Socket base classes, e.g. Socket and UDPSocket), and TCPSocket is used by Net::HTTP. Remember that DNS does not do negative caching - if a hostname does not have a AAAA record, then DNS will _always_ try to look up that record again! I propose that the following code should have some way to force IPv4 or IPv6 lookups: http://rxr.whitequark.org/mri/source/ext/socket/raddrinfo.c ~~~c 378 struct addrinfo* 379 rsock_addrinfo(VALUE host, VALUE port, int socktype, int flags) 380 { 381 struct addrinfo hints; 382 383 MEMZERO(&hints, struct addrinfo, 1); 384 hints.ai_family = AF_UNSPEC; 385 hints.ai_socktype = socktype; 386 hints.ai_flags = flags; 387 return rsock_getaddrinfo(host, port, &hints, 1); 388 } ~~~ For example, an environment variable named something like `RUBY_GAI` could be set to "INET" or "INET6" to switch the `hints.ai_family` away from `AF_UNSPEC`. -- https://bugs.ruby-lang.org/