ADDITIONAL SYSTEM INFORMATION :
$ java -version
openjdk version "10.0.2" 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13-Ubuntu-1ubuntu0.18.04.2)
OpenJDK 64-Bit Server VM (build 10.0.2+13-Ubuntu-1ubuntu0.18.04.2, mixed mode)
A DESCRIPTION OF THE PROBLEM :
When a unix domain socket is bound to fd 0 of a JVM instance all IPv6 functionality is disabled. This for example occurs when the JVM is spawned by Node.js (see https://stackoverflow.com/questions/34108124/ip-addresses-of-network-interfaces-in-a-java-process-spawned-by-nodejs).
I am completely unexperienced when it comes to the JDK/JVM source code, but I think I might have found the issue. The IPv6_supported function in src/java.base/unix/native/libnet/net_util_md.c contains the following check, whether fd 0 is a socket. If so and this socket is not an IPv6 socket it returns false. However, the comment above the function states that this check should disable IPv6 when the socket is an IPv4 socket.
I came to the conclusion that this is a bug, because the comment and the implementation do not match, and IPv6 is also disabled if the socket type is AF_UNIX.
307 /*
308 * If fd 0 is a socket it means we've been launched from inetd or
309 * xinetd. If it's a socket then check the family - if it's an
310 * IPv4 socket then we need to disable IPv6.
311 */
312 if (getsockname(0, &sa.sa, &sa_len) == 0) {
313 if (sa.sa.sa_family != AF_INET6) {
314 close(fd);
315 return JNI_FALSE;
316 }
317 }
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Launch a JVM with a unix domain socket bound to fd 0 and bind a ServerSocket to an IPv6 address.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
A sucessfully bounded ServerSocket.
ACTUAL -
Exception in thread "main" java.net.SocketException: Protocol family unavailable
at java.net.PlainSocketImpl.socketBind(Native Method)
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:387)
at java.net.ServerSocket.bind(ServerSocket.java:375)
at java.net.ServerSocket.bind(ServerSocket.java:329)
at Test.main(Test.java:6)
---------- BEGIN SOURCE ----------
import java.net.*;
public class Test {
public static void main(String[] args) throws Exception {
ServerSocket s = new ServerSocket();
s.bind(new InetSocketAddress("::", 12345));
}
}
The following python code can be used to start the jvm with a unix domain socket bound to fd 0:
#!/usr/bin/env python
import socket
import subprocess
sock = socket.socket(socket.AF_UNIX)
sock.bind('/tmp/socket')
fd = sock.makefile()
proc = subprocess.Popen(['/usr/bin/java', 'Test'], stdin=fd)
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The only "workaround" I found is to not bind a unix domain socket to fd 0.
FREQUENCY : always
$ java -version
openjdk version "10.0.2" 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13-Ubuntu-1ubuntu0.18.04.2)
OpenJDK 64-Bit Server VM (build 10.0.2+13-Ubuntu-1ubuntu0.18.04.2, mixed mode)
A DESCRIPTION OF THE PROBLEM :
When a unix domain socket is bound to fd 0 of a JVM instance all IPv6 functionality is disabled. This for example occurs when the JVM is spawned by Node.js (see https://stackoverflow.com/questions/34108124/ip-addresses-of-network-interfaces-in-a-java-process-spawned-by-nodejs).
I am completely unexperienced when it comes to the JDK/JVM source code, but I think I might have found the issue. The IPv6_supported function in src/java.base/unix/native/libnet/net_util_md.c contains the following check, whether fd 0 is a socket. If so and this socket is not an IPv6 socket it returns false. However, the comment above the function states that this check should disable IPv6 when the socket is an IPv4 socket.
I came to the conclusion that this is a bug, because the comment and the implementation do not match, and IPv6 is also disabled if the socket type is AF_UNIX.
307 /*
308 * If fd 0 is a socket it means we've been launched from inetd or
309 * xinetd. If it's a socket then check the family - if it's an
310 * IPv4 socket then we need to disable IPv6.
311 */
312 if (getsockname(0, &sa.sa, &sa_len) == 0) {
313 if (sa.sa.sa_family != AF_INET6) {
314 close(fd);
315 return JNI_FALSE;
316 }
317 }
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Launch a JVM with a unix domain socket bound to fd 0 and bind a ServerSocket to an IPv6 address.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
A sucessfully bounded ServerSocket.
ACTUAL -
Exception in thread "main" java.net.SocketException: Protocol family unavailable
at java.net.PlainSocketImpl.socketBind(Native Method)
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:387)
at java.net.ServerSocket.bind(ServerSocket.java:375)
at java.net.ServerSocket.bind(ServerSocket.java:329)
at Test.main(Test.java:6)
---------- BEGIN SOURCE ----------
import java.net.*;
public class Test {
public static void main(String[] args) throws Exception {
ServerSocket s = new ServerSocket();
s.bind(new InetSocketAddress("::", 12345));
}
}
The following python code can be used to start the jvm with a unix domain socket bound to fd 0:
#!/usr/bin/env python
import socket
import subprocess
sock = socket.socket(socket.AF_UNIX)
sock.bind('/tmp/socket')
fd = sock.makefile()
proc = subprocess.Popen(['/usr/bin/java', 'Test'], stdin=fd)
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The only "workaround" I found is to not bind a unix domain socket to fd 0.
FREQUENCY : always
- relates to
-
JDK-6914801 IPv6 unavailable if stdin is a socket
-
- Closed
-