6458027: Disabling IPv6 on a specific network interface causes problems
Added a check to test if an interface is configured for IPv6 to native code TwoStacklainDatagramSocketImpl: getMulticastInterface, setMulticastInterface Reviewed-by: chegar, michaelm
This commit is contained in:
parent
763eb8d2e3
commit
4d540aa581
@ -900,7 +900,7 @@ JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0
|
||||
MIB_IFROW *ifRowP;
|
||||
ifRowP = getIF(index);
|
||||
if (ifRowP != NULL) {
|
||||
ret = ifRowP->dwAdminStatus == 1 &&
|
||||
ret = ifRowP->dwAdminStatus == MIB_IF_ADMIN_STATUS_UP &&
|
||||
(ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL ||
|
||||
ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED);
|
||||
free(ifRowP);
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "java_net_SocketOptions.h"
|
||||
#include "java_net_NetworkInterface.h"
|
||||
|
||||
#include "NetworkInterface.h"
|
||||
#include "jvm.h"
|
||||
#include "jni_util.h"
|
||||
#include "net_util.h"
|
||||
@ -1644,6 +1645,33 @@ static int getIndexFromIf (JNIEnv *env, jobject nif) {
|
||||
return (*env)->GetIntField(env, nif, ni_indexID);
|
||||
}
|
||||
|
||||
static int isAdapterIpv6Enabled(JNIEnv *env, int index) {
|
||||
netif *ifList, *curr;
|
||||
int ipv6Enabled = 0;
|
||||
if (getAllInterfacesAndAddresses (env, &ifList) < 0) {
|
||||
return ipv6Enabled;
|
||||
}
|
||||
|
||||
/* search by index */
|
||||
curr = ifList;
|
||||
while (curr != NULL) {
|
||||
if (index == curr->index) {
|
||||
break;
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
/* if found ipv6Index != 0 then interface is configured with IPV6 */
|
||||
if ((curr != NULL) && (curr->ipv6Index !=0)) {
|
||||
ipv6Enabled = 1;
|
||||
}
|
||||
|
||||
/* release the interface list */
|
||||
free_netif(ifList);
|
||||
|
||||
return ipv6Enabled;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the multicast interface.
|
||||
*
|
||||
@ -1703,7 +1731,6 @@ static void setMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1,
|
||||
struct in_addr in;
|
||||
|
||||
in.s_addr = htonl(getInetAddress_addr(env, value));
|
||||
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
|
||||
(const char*)&in, sizeof(in)) < 0) {
|
||||
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
|
||||
@ -1734,19 +1761,20 @@ static void setMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1,
|
||||
}
|
||||
index = (*env)->GetIntField(env, value, ni_indexID);
|
||||
|
||||
if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
|
||||
if ( isAdapterIpv6Enabled(env, index) != 0 ) {
|
||||
if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
|
||||
(const char*)&index, sizeof(index)) < 0) {
|
||||
if (errno == EINVAL && index > 0) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"IPV6_MULTICAST_IF failed (interface has IPv4 "
|
||||
"address only?)");
|
||||
} else {
|
||||
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
|
||||
if (errno == EINVAL && index > 0) {
|
||||
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
|
||||
"IPV6_MULTICAST_IF failed (interface has IPv4 "
|
||||
"address only?)");
|
||||
} else {
|
||||
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
|
||||
"Error setting socket option");
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there are any IPv4 addresses on this interface then
|
||||
* repeat the operation on the IPv4 fd */
|
||||
|
||||
@ -1797,7 +1825,6 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption(JNIEnv *env
|
||||
char c;
|
||||
} optval;
|
||||
int ipv6_supported = ipv6_available();
|
||||
|
||||
fd = getFD(env, this);
|
||||
|
||||
if (ipv6_supported) {
|
||||
@ -1898,42 +1925,21 @@ Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption(JNIEnv *env
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the multicast interface:
|
||||
*
|
||||
* SocketOptions.IP_MULTICAST_IF
|
||||
* IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
|
||||
* Create InetAddress
|
||||
* IP_MULTICAST_IF returns struct ip_mreqn on 2.2
|
||||
* kernel but struct in_addr on 2.4 kernel
|
||||
* IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
|
||||
* obtain from impl is Linux 2.2 kernel
|
||||
* If index == 0 return InetAddress representing
|
||||
* anyLocalAddress.
|
||||
* If index > 0 query NetworkInterface by index
|
||||
* and returns addrs[0]
|
||||
* called by getMulticastInterface to retrieve a NetworkInterface
|
||||
* configured for IPv4.
|
||||
* The ipv4Mode parameter, is a closet boolean, which allows for a NULL return,
|
||||
* or forces the creation of a NetworkInterface object with null data.
|
||||
* It relates to its calling context in getMulticastInterface.
|
||||
* ipv4Mode == 1, the context is IPV4 processing only.
|
||||
* ipv4Mode == 0, the context is IPV6 processing
|
||||
*
|
||||
* SocketOptions.IP_MULTICAST_IF2
|
||||
* IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
|
||||
* Query NetworkInterface by IP address and
|
||||
* return the NetworkInterface that the address
|
||||
* is bound too.
|
||||
* IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
|
||||
* (except Linux .2 kernel)
|
||||
* Query NetworkInterface by index and
|
||||
* return NetworkInterface.
|
||||
*/
|
||||
jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
|
||||
jboolean isIPV4 = !ipv6_available() || fd1 == -1;
|
||||
|
||||
/*
|
||||
* IPv4 implementation
|
||||
*/
|
||||
if (isIPV4) {
|
||||
static jobject getIPv4NetworkInterface (JNIEnv *env, jobject this, int fd, jint opt, int ipv4Mode) {
|
||||
static jclass inet4_class;
|
||||
static jmethodID inet4_ctrID;
|
||||
|
||||
static jclass ni_class;
|
||||
static jmethodID ni_ctrID;
|
||||
static jclass ni_class; static jmethodID ni_ctrID;
|
||||
static jfieldID ni_indexID;
|
||||
static jfieldID ni_addrsID;
|
||||
|
||||
@ -1944,7 +1950,6 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint o
|
||||
struct in_addr in;
|
||||
struct in_addr *inP = ∈
|
||||
int len = sizeof(struct in_addr);
|
||||
|
||||
if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
|
||||
(char *)inP, &len) < 0) {
|
||||
NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
|
||||
@ -1996,23 +2001,57 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint o
|
||||
if (ni) {
|
||||
return ni;
|
||||
}
|
||||
if (ipv4Mode) {
|
||||
ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
|
||||
CHECK_NULL_RETURN(ni, NULL);
|
||||
|
||||
/*
|
||||
* The address doesn't appear to be bound at any known
|
||||
* NetworkInterface. Therefore we construct a NetworkInterface
|
||||
* with this address.
|
||||
*/
|
||||
ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
|
||||
CHECK_NULL_RETURN(ni, NULL);
|
||||
|
||||
(*env)->SetIntField(env, ni, ni_indexID, -1);
|
||||
addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
|
||||
CHECK_NULL_RETURN(addrArray, NULL);
|
||||
(*env)->SetObjectArrayElement(env, addrArray, 0, addr);
|
||||
(*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
|
||||
(*env)->SetIntField(env, ni, ni_indexID, -1);
|
||||
addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
|
||||
CHECK_NULL_RETURN(addrArray, NULL);
|
||||
(*env)->SetObjectArrayElement(env, addrArray, 0, addr);
|
||||
(*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
|
||||
} else {
|
||||
ni = NULL;
|
||||
}
|
||||
return ni;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the multicast interface:
|
||||
*
|
||||
* SocketOptions.IP_MULTICAST_IF
|
||||
* IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
|
||||
* Create InetAddress
|
||||
* IP_MULTICAST_IF returns struct ip_mreqn on 2.2
|
||||
* kernel but struct in_addr on 2.4 kernel
|
||||
* IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
|
||||
* obtain from impl is Linux 2.2 kernel
|
||||
* If index == 0 return InetAddress representing
|
||||
* anyLocalAddress.
|
||||
* If index > 0 query NetworkInterface by index
|
||||
* and returns addrs[0]
|
||||
*
|
||||
* SocketOptions.IP_MULTICAST_IF2
|
||||
* IPv4: Query IPPROTO_IP/IP_MULTICAST_IF
|
||||
* Query NetworkInterface by IP address and
|
||||
* return the NetworkInterface that the address
|
||||
* is bound too.
|
||||
* IPv6: Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
|
||||
* (except Linux .2 kernel)
|
||||
* Query NetworkInterface by index and
|
||||
* return NetworkInterface.
|
||||
*/
|
||||
jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
|
||||
jboolean isIPV4 = !ipv6_available() || fd1 == -1;
|
||||
|
||||
/*
|
||||
* IPv4 implementation
|
||||
*/
|
||||
if (isIPV4) {
|
||||
jobject netObject = NULL; // return is either an addr or a netif
|
||||
netObject = getIPv4NetworkInterface(env, this, fd, opt, 1);
|
||||
return netObject;
|
||||
}
|
||||
|
||||
/*
|
||||
* IPv6 implementation
|
||||
@ -2103,6 +2142,13 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint o
|
||||
|
||||
addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
|
||||
return addr;
|
||||
} else if (index == 0) { // index == 0 typically means IPv6 not configured on the interfaces
|
||||
// falling back to treat interface as configured for IPv4
|
||||
jobject netObject = NULL;
|
||||
netObject = getIPv4NetworkInterface(env, this, fd, opt, 0);
|
||||
if (netObject != NULL) {
|
||||
return netObject;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2127,6 +2173,8 @@ jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint o
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns relevant info as a jint.
|
||||
*
|
||||
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6458027
|
||||
* @summary Disabling IPv6 on a specific network interface causes problems.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.MulticastSocket;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
|
||||
|
||||
public class SetGetNetworkInterfaceTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
boolean passed = true;
|
||||
try {
|
||||
MulticastSocket ms = new MulticastSocket();
|
||||
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface
|
||||
.getNetworkInterfaces();
|
||||
while (networkInterfaces.hasMoreElements()) {
|
||||
NetworkInterface netIf = networkInterfaces.nextElement();
|
||||
if (isNetworkInterfaceTestable(netIf)) {
|
||||
printNetIfDetails(netIf);
|
||||
ms.setNetworkInterface(netIf);
|
||||
NetworkInterface msNetIf = ms.getNetworkInterface();
|
||||
if (netIf.equals(msNetIf)) {
|
||||
System.out.println(" OK");
|
||||
} else {
|
||||
System.out.println("FAILED!!!");
|
||||
printNetIfDetails(msNetIf);
|
||||
passed = false;
|
||||
}
|
||||
System.out.println("------------------");
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
passed = false;
|
||||
}
|
||||
if (!passed) {
|
||||
throw new RuntimeException("Test Fail");
|
||||
}
|
||||
System.out.println("Test passed ");
|
||||
}
|
||||
|
||||
private static boolean isNetworkInterfaceTestable(NetworkInterface netIf) throws Exception {
|
||||
System.out.println("checking netif == " + netIf.getName());
|
||||
return (netIf.isUp() && netIf.supportsMulticast() && isIpAddrAvailable(netIf));
|
||||
}
|
||||
|
||||
private static boolean isIpAddrAvailable (NetworkInterface netIf) {
|
||||
boolean ipAddrAvailable = false;
|
||||
byte[] nullIpAddr = {'0', '0', '0', '0'};
|
||||
byte[] testIpAddr = null;
|
||||
|
||||
Enumeration<InetAddress> ipAddresses = netIf.getInetAddresses();
|
||||
while (ipAddresses.hasMoreElements()) {
|
||||
InetAddress testAddr = ipAddresses.nextElement();
|
||||
testIpAddr = testAddr.getAddress();
|
||||
if ((testIpAddr != null) && (!Arrays.equals(testIpAddr, nullIpAddr))) {
|
||||
ipAddrAvailable = true;
|
||||
break;
|
||||
} else {
|
||||
System.out.println("ignore netif " + netIf.getName());
|
||||
}
|
||||
}
|
||||
return ipAddrAvailable;
|
||||
}
|
||||
|
||||
private static void printNetIfDetails(NetworkInterface ni)
|
||||
throws SocketException {
|
||||
System.out.println("Name " + ni.getName() + " index " + ni.getIndex());
|
||||
Enumeration<InetAddress> en = ni.getInetAddresses();
|
||||
while (en.hasMoreElements()) {
|
||||
System.out.println(" InetAdress: " + en.nextElement());
|
||||
}
|
||||
System.out.println("HardwareAddress: " + createMacAddrString(ni));
|
||||
System.out.println("loopback: " + ni.isLoopback() + "; pointToPoint: "
|
||||
+ ni.isPointToPoint() + "; virtual: " + ni.isVirtual()
|
||||
+ "; MTU: " + ni.getMTU());
|
||||
}
|
||||
|
||||
private static String createMacAddrString(NetworkInterface netIf)
|
||||
throws SocketException {
|
||||
byte[] macAddr = netIf.getHardwareAddress();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (macAddr != null) {
|
||||
for (int i = 0; i < macAddr.length; i++) {
|
||||
sb.append(String.format("%02X%s", macAddr[i],
|
||||
(i < macAddr.length - 1) ? "-" : ""));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user