From: "datibbaw (Tjerk Meesters) via ruby-core" Date: 2026-11-13T08:03:10+00:00 Subject: [ruby-core:127460] [Ruby Bug#22538] require 'socket' raises NameError for builds with --disable-ipv6, and IPv6 addresses leak from the resolver Issue #22538 has been updated by datibbaw (Tjerk Meesters). nobu (Nobuyoshi Nakada) wrote in #note-1: > Applied in changeset commit:git|c99813a8d8484058987c968923cd814e99aa6dd3. > > ---------- > [Bug #22538] Fix failures when IPv6 is disabled Thanks for that, but that only fixes a small part of the issue; the rest involves the Happy Eyeballs implementation that causes hangs and otherwise undesirable behaviour ... in fact, the test suite doesn't pass with `--disable-ipv6` on a system that _does_ support it. I've drafted my proposed change here: https://github.com/ruby/ruby/compare/master...datibbaw:ruby:disable-ipv6-consistency ---------------------------------------- Bug #22538: require 'socket' raises NameError for builds with --disable-ipv6, and IPv6 addresses leak from the resolver https://bugs.ruby-lang.org/issues/22538#change-119921 * Author: datibbaw (Tjerk Meesters) * Status: Closed * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- On a Ruby built with `./configure --disable-ipv6`, `require 'socket'` fails: ``` $ ruby -rsocket -e0 .../socket.rb:622:in '': uninitialized constant Socket::AF_INET6 (NameError) from .../socket.rb:478:in '' ``` Reproduced with: * ruby 3.4.10 (2026-06-30 revision 2b0b7728dc) +PRISM [arm64-darwin25] * ruby 4.1.0dev (2026-11-12T01:39:13Z master 0738c9dfaa) +PRISM [arm64-darwin25] ## Cause With `--disable-ipv6`, `INET6` is not defined, so `mkconstants.rb` omits `AF_INET6`, `PF_INET6` and `IPV6_*`. Since Happy Eyeballs v2 was added to `Socket.tcp` (Ruby 3.4), `socket.rb` defines a class-level constant that references `Socket::AF_INET6` without a `defined?` check: ```ruby ADDRESS_FAMILIES = { ipv6: Socket::AF_INET6, ipv4: Socket::AF_INET }.freeze ``` ## Further problems once the require is fixed `--disable-ipv6` only removes the Ruby-level IPv6 constants. The system resolver still returns IPv6 addresses (with `AF_UNSPEC` hints), and `getifaddrs` still reports IPv6 interface addresses. Code that skips IPv6 handling with `defined?(Socket::AF_INET6)` then gets IPv6 sockets anyway: * `Socket.tcp_server_sockets(0)` never returns. `getaddrinfo(nil, 0, ..., AI_PASSIVE)` returns `::` and `0.0.0.0`; `ipv6only!` is a no-op because `Socket::IPV6_V6ONLY` is not defined, so the `[::]:P` socket is dual-stack, binding `0.0.0.0:P` fails with `EADDRINUSE`, and `ip_sockets_port0` retries forever. This also hangs `TestSocket#test_accept_loop_with_unix`. * `Socket.tcp(host, port, nil, 0)` (local port only) resolves `::1` and `127.0.0.1` locally; `ADDRESS_FAMILIES.key(AF_INET6)` is `nil`, so the resolver thread runs with a `nil` family. * `Addrinfo#connect_address` does not turn `[::]` into `[::1]` (that branch is guarded by `defined?(Socket::AF_INET6)`), and connecting to it fails with `ENOBUFS` on macOS. * `Socket.ip_address_list` and `Socket.udp_server_sockets` return IPv6 addresses. * `TCPSocket.new` (C Happy Eyeballs) starts an IPv6 resolver thread and then discards its results. ## Proposed fix Make `--disable-ipv6` consistently IPv4-only: * `socket.rb`: only add `:ipv6` to `ADDRESS_FAMILIES` when `Socket::AF_INET6` is defined. * `raddrinfo.c` (`rsock_getaddrinfo`, which every Ruby-level lookup goes through): when `INET6` is not defined, change `PF_UNSPEC` hints to `PF_INET` and reject `PF_INET6` with `EAI_FAMILY`. * `ipsocket.c`: resolve only IPv4 in the `TCPSocket.new` fast fallback path. * `socket.c`: skip `AF_INET6` in the getifaddrs and ioctl implementations of `Socket.ip_address_list`. The Windows implementation already does this. * Tests: skip tests that need IPv6 (`::1` servers, IPv6 addresses); make stubbed `Socket.tcp` and `TCPSocket.new` tests work when `Socket::AF_INET6` is undefined. User-visible change, only in `--disable-ipv6` builds: IPv6 literals such as `Addrinfo.ip("::1")` or `TCPSocket.new("::1", port)` raise `Socket::ResolutionError` instead of partly working. I will open a pull request. ## Note on backporting to 3.4 On 3.4, fixing `ADDRESS_FAMILIES` alone is not enough. With only one family to resolve, `Socket.tcp_with_fast_fallback` passes the Symbol `:ipv4` to `Addrinfo.getaddrinfo`, which raises `unknown socket domain: ipv4` (#21512). A 3.4 backport also needs both fixes for that issue: b896f80598 and its follow-up f33766720c. The first commit alone passes `ADDRESS_FAMILIES[:family_name]`, i.e. `nil`, so it silently resolves all families. -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/