-
Bug
-
Resolution: Fixed
-
P4
-
8u181, 11, 12
-
b20
-
x86
-
linux
-
Verified
ADDITIONAL SYSTEM INFORMATION :
$ java -version
openjdk version "1.8.0_181"
OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-2~0-b13)
OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
A DESCRIPTION OF THE PROBLEM :
If a java program tries to bind a datagram/UDP socket to a link- or node-local multicast
address and also sets the needed interface index, the bind operation on the socket
fails with "java.net.SocketException: Invalid argument".
The need to bind the socket to the IPv6 multicast address is to avoid receiving traffic
from all multicast groups, that are joined on the system. Since a join joins the system
(not the socket) to the group, all sockets bound to a port, which receive multicast
traffic will receive all of that traffic, no matter the destination address. The bind
prevents that. IP_MULTICAST_ALL sadly only works for IPv4, and IPV6_MULTICAST_ALL
has a bug in the Linux kernel, see https://marc.info/?l=linux-netdev&m=153656806202701&w=2
This is because the JDK networking native code only transfers the interface index to
the scope_id field in the struct sockaddr_in6, if the address to bind to is a link-local
address (IN6_IS_ADDR_LINKLOCAL()).
A bind to a multicast address of link- or node-local scope needs the scope_id field as well.
(There might be an additional problem here, when binding to a higher scoped multicast address and trying to use
the non-default-route interface)
The patch below fixes/adds this in the JDK networking native code. It is applicable
with few changes to all java versions I have looked at.
This is a copy/forward of the Debian bug #907541 (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=907541). I am reporting this here in the hope of getting a fix into upstream quicker.
This bugs affects ALL currently available Java versions (at least 7,8,10 and 11)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test-code. It throws an exception, which it should not.
The hard-coded network Interface name in the test code might have to be adapted in order for the test to work.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The bind should succeed.
ACTUAL -
Exception is thrown
---------- BEGIN SOURCE ----------
class mcast_test {
private static final byte[] ADDR = new byte[]{
(byte) 0xff, (byte) 0x12, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x47, (byte) 0x49,
(byte) 0x47, (byte) 0x50
};
public static void main(String[] args) throws Exception {
Inet6Address addr = Inet6Address.getByAddress("", ADDR, NetworkInterface.getByName("enp6s0"));
System.out.println(addr);
DatagramSocket s = new DatagramSocket(new InetSocketAddress( addr, 29550));
}
};
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
This is a patch against java 8, as it is distributed by debian in its unstable distribution. After applying this patch, the VM behaves as expected.
diff -Naur jdk/src/solaris/native/java/net/net_util_md.c jdk.new/src/solaris/native/java/net/net_util_md.c
--- a/jdk/src/solaris/native/java/net/net_util_md.c 2018-05-17 22:24:20.000000000 +0200
+++ b/jdk/src/solaris/native/java/net/net_util_md.c 2018-08-28 10:54:00.022607297 +0200
@@ -838,7 +838,9 @@
* cases the used value is cached for further use.
*/
#ifdef __linux__
- if (IN6_IS_ADDR_LINKLOCAL(&(him6->sin6_addr))) {
+ if (IN6_IS_ADDR_LINKLOCAL(&(him6->sin6_addr))
+ || IN6_IS_ADDR_MC_NODELOCAL(&(him6->sin6_addr))
+ || IN6_IS_ADDR_MC_LINKLOCAL(&(him6->sin6_addr))) {
int cached_scope_id = 0, scope_id = 0;
if (ia6_cachedscopeidID) {
FREQUENCY : always
$ java -version
openjdk version "1.8.0_181"
OpenJDK Runtime Environment (build 1.8.0_181-8u181-b13-2~0-b13)
OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)
A DESCRIPTION OF THE PROBLEM :
If a java program tries to bind a datagram/UDP socket to a link- or node-local multicast
address and also sets the needed interface index, the bind operation on the socket
fails with "java.net.SocketException: Invalid argument".
The need to bind the socket to the IPv6 multicast address is to avoid receiving traffic
from all multicast groups, that are joined on the system. Since a join joins the system
(not the socket) to the group, all sockets bound to a port, which receive multicast
traffic will receive all of that traffic, no matter the destination address. The bind
prevents that. IP_MULTICAST_ALL sadly only works for IPv4, and IPV6_MULTICAST_ALL
has a bug in the Linux kernel, see https://marc.info/?l=linux-netdev&m=153656806202701&w=2
This is because the JDK networking native code only transfers the interface index to
the scope_id field in the struct sockaddr_in6, if the address to bind to is a link-local
address (IN6_IS_ADDR_LINKLOCAL()).
A bind to a multicast address of link- or node-local scope needs the scope_id field as well.
(There might be an additional problem here, when binding to a higher scoped multicast address and trying to use
the non-default-route interface)
The patch below fixes/adds this in the JDK networking native code. It is applicable
with few changes to all java versions I have looked at.
This is a copy/forward of the Debian bug #907541 (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=907541). I am reporting this here in the hope of getting a fix into upstream quicker.
This bugs affects ALL currently available Java versions (at least 7,8,10 and 11)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test-code. It throws an exception, which it should not.
The hard-coded network Interface name in the test code might have to be adapted in order for the test to work.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The bind should succeed.
ACTUAL -
Exception is thrown
---------- BEGIN SOURCE ----------
class mcast_test {
private static final byte[] ADDR = new byte[]{
(byte) 0xff, (byte) 0x12, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x47, (byte) 0x49,
(byte) 0x47, (byte) 0x50
};
public static void main(String[] args) throws Exception {
Inet6Address addr = Inet6Address.getByAddress("", ADDR, NetworkInterface.getByName("enp6s0"));
System.out.println(addr);
DatagramSocket s = new DatagramSocket(new InetSocketAddress( addr, 29550));
}
};
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
This is a patch against java 8, as it is distributed by debian in its unstable distribution. After applying this patch, the VM behaves as expected.
diff -Naur jdk/src/solaris/native/java/net/net_util_md.c jdk.new/src/solaris/native/java/net/net_util_md.c
--- a/jdk/src/solaris/native/java/net/net_util_md.c 2018-05-17 22:24:20.000000000 +0200
+++ b/jdk/src/solaris/native/java/net/net_util_md.c 2018-08-28 10:54:00.022607297 +0200
@@ -838,7 +838,9 @@
* cases the used value is cached for further use.
*/
#ifdef __linux__
- if (IN6_IS_ADDR_LINKLOCAL(&(him6->sin6_addr))) {
+ if (IN6_IS_ADDR_LINKLOCAL(&(him6->sin6_addr))
+ || IN6_IS_ADDR_MC_NODELOCAL(&(him6->sin6_addr))
+ || IN6_IS_ADDR_MC_LINKLOCAL(&(him6->sin6_addr))) {
int cached_scope_id = 0, scope_id = 0;
if (ia6_cachedscopeidID) {
FREQUENCY : always
- relates to
-
JDK-8214247 java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java fails at Linux: Expected message not received
-
- Closed
-
-
JDK-8215294 Provide a better fix for binding to node- and link- local ipv6 multicast addresses
-
- Closed
-
-
JDK-8213490 Networking area typos and inconsistencies cleanup
-
- Closed
-
-
JDK-8215292 Back out changes for node- and link- local ipv6 multicast address
-
- Closed
-