Issue #19144 has been updated by akr (Akira Tanaka).
kjtsanaktsidis (KJ Tsanaktsidis) wrote in #note-5:
@akr could you take a look at my PR when you get a
chance? I think I addressed your feedback, please let me know if I have misunderstood!
It seems fine.
I agree that we remove the test because it is too complicated.
----------------------------------------
Bug #19144: Ruby should set AI_V4MAPPED | AI_ADDRCONFIG getaddrinfo flags by default
https://bugs.ruby-lang.org/issues/19144#change-105512
* Author: kjtsanaktsidis (KJ Tsanaktsidis)
* Status: Open
* Priority: Normal
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
Currently, DNS lookups made with `getaddrinfo` from Ruby (i.e. not from the `Resolv`
module) cause both A and AAAA DNS requests to be made, even on systems that don’t actually
have an IPv6 address that could possibly make the AAAA response useful. I wouldn’t
_really_ care about this, normally, but glibc has a bug
(
https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1961697) which can cause a 5-second
delay in DNS lookups when both A and AAAA records are queried in parallel. This bug is
fixed in glibc upstream but still present in some LTS linux distros (Ubuntu 18.04 and
20.04 at least), so I think it’s worthwhile to try and work around it in circumstances
where the AAAA request is pointless anyway.
The dual A/AAAA lookup happens because whenever Ruby calls getaddrinfo to perform DNS
lookups, it always sets `hints`, and sets `hints->ai_flags` to zero by default unless
flags are specified by the caller (e.g. `AI_PASSIVE` is set when binding a TCP server
socket in `TCPServer.new`).
This matches the default value of `ai_flags` specified by POSIX, which is zero. However,
glibc behaves differently. When glibc’s `getaddrinfo` function is called with `NULL` for
the `hints` parameter, it defaults the `ai_flags` value to `(AI_V4MAPPED |
AI_ADDRCONFIG)`. The manpage (from the Linux man-pages project -
https://man7.org/linux/man-pages/man3/getaddrinfo.3.html) claims “this is an improvement
on the standard” (although I couldn’t find this mentioned in the glibc manual itself).
Of course, we’re not _actually_ ever calling `getaddrinfo` with NULL `hints`; so, we never
actually use these flags on glibc systems (unless they’re explicitly specified by the
caller).
My proposal is that we should change Ruby to set these two flags by default, when they’re
available, in the following circumstances:
* In all calls made internally to `rsock_getaddrinfo` as a result of socket functions like
`TCPSocket.new`, `UDPSocket.new`, etc.
* EXCEPT when `AI_PASSIVE` is also set (i.e. when we’re trying to get an address to bind
for listener socket - see below)
* In calls made to `rsock_getaddrinfo` as a direct result of calling
`Addrinfo.getaddrinfo` from Ruby with nil flags
* EXCEPT calls to `Addrinfo.getaddrinfo` where explicit flags are provided
Both of these seem like something you would almost always want to be doing in any outgoing
connection scenario:
* `AI_V4MAPPED` ensures that, if AF_INET6 is explicitly specified as the desired protocol,
and there is no AAAA record in DNS, that any A record that _is_ present gets converted to
an IPv4-mapped IPv6 address so it can be used e.g. with NAT64.
* `AI_ADDRCONFIG` ensures that, if a machine has no IPv6 address, it doesn’t bother making
an AAAA lookup that will return IPv6 addresses that can’t actually be used for anything
(and vice versa for IPv4).
The reason why we wouldn’t want to set `AI_ADDRCONFIG` in circumstances where Ruby
currently sets `AI_PASSIVE` is that loopback addresses are not considered in deciding if a
system has an IPv4/IPv6 address. Conceivably, you might want to bind to a `::1` loopback
address, and allow other processes on the same machine to connect to that.
Does changing this default sound reasonable? If so I can prepare a patch. Another option I
considered is doing this _only_ when Ruby is built against glibc (so that other system
behaviour is most closely matched).
--
https://bugs.ruby-lang.org/