JDK-6914801 : IPv6 unavailable if stdin is a socket
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 6u17
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: linux_redhat_5.0
  • CPU: x86
  • Submitted: 2010-01-07
  • Updated: 2023-07-21
  • Resolved: 2023-01-09
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 21
21 b05Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_17"
Java(TM) SE Runtime Environment (build 1.6.0_17-b04)
Java HotSpot(TM) Server VM (build 14.3-b01, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux xxxxxx.yyyy.com 2.6.18-128.1.14.el5 #1 SMP Mon Jun 1 15:52:58 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux
Red Hat Enterprise Linux Client release 5.3 (Tikanga)
(seems to affect all redhat-based linuxes, 32- and 64-bit.  debian-based linuxes seem immune)

EXTRA RELEVANT SYSTEM CONFIGURATION :
/etc/hosts:
127.0.0.1	localhost.localdomain	localhost	xxxxxx
::1	localhost.localdomain	localhost	xxxxxx

/sbin/ifconfig summary:
eth0      Link encap:Ethernet  HWaddr 00:10:18:34:xx:xx
          inet addr:10.0.x.x  Bcast:10.0.255.255  Mask:255.255.0.0
          inet6 addr: fe80::210:18ff:fe34:xxxx/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
vmnet1    Link encap:Ethernet  HWaddr 00:50:56:C0:00:01
          inet addr:192.168.223.1  Bcast:192.168.223.255  Mask:255.255.255.0
          inet6 addr: fe80::250:56ff:fec0:1/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
vmnet8    Link encap:Ethernet  HWaddr 00:50:56:C0:00:08
          inet addr:172.16.244.1  Bcast:172.16.244.255  Mask:255.255.255.0
          inet6 addr: fe80::250:56ff:fec0:8/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

A DESCRIPTION OF THE PROBLEM :
When stdin is connected to a socket (in particular, a FILE socket), IPv6 is completely unavailable in Java.

We noticed that when we invoked java as an immediate command from ssh, as in
   ssh host 'java ClassName'
it would not talk to certain server software that, due to an obscure DNS configuration, was only listening on the IPv6 loopback (rather than both the IPv4 and IPv6 loopbacks).

For some reason, this seems to affect all the Redhat-based linuxes I have tested (64-bit, 32-bit, and 32-bit vm on 64-bit kernel) and does not seem to affect the Debian-based linuxes I have tested.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The easiest way to reproduce the condition of stdin being connected to a FILE socket is to run Java as an immediate command through ssh, like
$ ssh localhost 'java IPv6Test'
java.net.preferIPv4Stack=null
IPv6 is not working! Protocol family unavailable

If I use my bash shell to redirect stdin from a file or pipe on the other end, there is no problem:
$ ssh localhost 'java IPv6Test < /dev/null'
java.net.preferIPv4Stack=null
IPv6 seems to be working
$ ssh localhost 'echo | java IPv6Test'
java.net.preferIPv4Stack=null
IPv6 seems to be working

Or I can use ssh to connect stdin to a pseudo-tty, (mimicking what happens if you log in with ssh):
$ ssh -t localhost 'java IPv6Test'
java.net.preferIPv4Stack=null
IPv6 seems to be working
Connection to localhost closed.

The test class is simple in that it uses a failed connection to determine whether IPv6 is available, but this problem certainly prevents making connections.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Availability of IPv6 should not depend on what kind of io/file stdin is connected to.
ACTUAL -
Availability of IPv6 depends on what kind of io/file stdin is connected to, even when stdin is never read.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
You can actually see in the strace where it is detecting whether stdin (fd=0) is connected to a socket (or not):
getsockname(0, {sa_family=AF_FILE, path=""}, [17150529334688088066]) = 0
vs.
getsockname(0, 0xf7f28240, [17148559009851113500]) = -1 ENOTSOCK (Socket operation on non-socket)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.net.*;

public class IPv6Test {
    public static void main(String[] args) throws Exception {
        System.out.println("java.net.preferIPv4Stack=" + System.getProperty("java.net.preferIPv4Stack"));
        try {
            new Socket("::1", 29876).close();  // IPv6 loopback, on port unlikely to be listening
            // someone was listening and we connected and closed
            System.out.println("IPv6 seems to be working");
        } catch (ConnectException e) {
            // tried to connect, but no one was listening--what we expect
            System.out.println("IPv6 seems to be working");
        } catch (SocketException e) {
            // some other problem connecting
            System.out.println("IPv6 is not working! " + e.getMessage());
        } catch (UnknownHostException e) {
            // doesn't understand IPv6 loopback "::1"
            System.out.println("IPv6 is not available");
        }
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
With an ssh immediate command, using the -t parameter is a suitable work-around, because it will connect stdin to a pseudo-tty rather than a socket.

Comments
Changeset: 8d17d1ee Author: Daniel JeliƄski <djelinski@openjdk.org> Date: 2023-01-09 07:39:12 +0000 URL: https://git.openjdk.org/jdk/commit/8d17d1ee6f08ee90771d469182aaaaa7c23971fd
09-01-2023

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/11638 Date: 2022-12-12 20:30:05 +0000
12-12-2022

EVALUATION The JDK requires all sockets be IPv4 or all sockets be IPv6. It doesn't support the scenario where some Sockets are IPv4 and others are IPv6 (the only exception is java.nio.channels.DatagramChannel for the purposes of IPv4 multicasting when IPv6 is enabled). The issue we have is that the VM can be launched by inet/xinetd and the peer socket made available to the application via the System.inheritedChannel method. In the ssh case, as stdin is connected to an IPv4 socket, it forces all sockets to be IPv4 (as we can't support a SocketChannel connected to an IPv4 socket and all other Socket/SocketChannels be connected to an IPv6 socket). One idea is to remove the check during start and allow IPv6 is used. The only implication is likely to be that rmid and others launching java via inetd/xinetd will need to set the preferIPv4Stack property to true as otherwise System.inheritedChannel will return null (due to the protocol family mismatch).
07-01-2010