On 09/02/2026 10:59, Robert Stupp wrote:
Hi Alan,
My question basically came up when I was investigating a network issue
against a dual-stack web site. In my case, there was a routing issue
(somewhere) that affected only IPv4 (packet-loss -> dup-ack), but IPv6
worked fine. So tools like curl/wget, which used the system settings,
just worked without any issue, but the "Java variant" always ran into
that issue. It took me a bit to figure out that IPv4 is by default
preferred in Java, despite the system settings (getinetaddr result).
Even worse for me: the tool I used effectively prevented setting the
system property 'java.net.preferIPv6Addresses=true'.
The crux of such network issues is that those are hard to narrow down,
especially when for example CDNs are in the mix, besides that
it requires networking knowledge.
The question that came up was, whether there's a way to prevent such
issues from bubbling up to users.
Modern web browsers and curl _appear_ to prefer IPv6 over IPv4 by
default. Those use "Happy Eyeballs" (RFC 8305/6555), which is likely a
sign that using IPv6 is (sadly, after ~30 years, sigh) still causing
issues for users [1]. Such HTTP applications probably also use other
mechanisms as well [2]. "Happy Eyeballs" is fine for browsers and
tools like 'curl', it sits on top of the lower level
InetAddress.get*()/getinetaddr, using their own hostname resolution
and leveraging recent "connection quality" (persisted history).
Changing the default from 'PV4 | IPV6 | IPV4_FIRST' to 'IPV4 | IPV6'
in 'java.net.InetAddress' is, no doubt, a change to the observed
behavior. There is certainly a risk that existing applications break
with this change, when suddenly connections are made via IPv6 instead
of IPv4. So a definitive "no go" for released Java versions.
OTOH there's the observed difference between the ordering of the
results of InetAddress.get*() and getinetaddr. I figured that
difference a bit surprising (I never cared about it in the
last years TBH, because everything just worked).
Most code, not just Java, probably just takes the first element
returned by InetAddress.get*()/getinetaddr, which is IMHO not a bad
approach, because there's no, say, "quality metadata" about the
individual entries.
I am by no means an expert on the "state of practical use and
usability of IPv6", so my observation is very subjective. Things are,
I am sure, different from ISP to ISP and within organizations'
networks and not to forget interactions with "all the other things".
Options I currently see are (no particular order here):
* "Just"(TM) change the default (tempting, but devils inside).
* Add new InetAddress.get*() functions that allows applications to
pass a lookup preference to use. That would have to work in all cases:
v4-only, v6-only, dual-stack).
* Introduction of a general, inet specific name resolution API (a la
Netty?) with more options.
* Have a "Happy Eyeballs" implementation, raising the questions of
where and how to add it. Naively thinking: something like
'SocketChannel.connect(List<InetSocketAddress> addresses)' and/or
'Socket.connect(List<InetSocketAddress> addresses)'
While it is certainly possible to have a "proper" solution by
implementing custom code or leveraging existing libraries, developers
need to be aware of the potential IPv4/v6 issues when writing code.
Having something in the core Java APIs and/or implementation could
help avoiding networking issues in the broader ecosystem.
JEP 418 added an SPI for host name resolution that has the finer grain
LookupPolicy that you are looking for. This opens up the potential to
add new lookup methods to Inet4Addresss and Inet6Address that could be
used by more advanced applications/clients that wish to use one or the
other.
SocketChannel would be way too low level for happy eyeballs or other
fallback but potentially interesting when using the HTTP or other client
APIs.
-Alan