Path: blob/master/src/java.base/unix/native/libnet/NetworkInterface.c
67766 views
/*1* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24#include <arpa/inet.h>25#include <errno.h>26#include <net/if.h>27#include <net/if_arp.h>28#include <stdlib.h>29#include <string.h>30#include <sys/ioctl.h>3132#if defined(_AIX)33#include <netinet/in6_var.h>34#include <sys/ndd_var.h>35#include <sys/kinfo.h>36#include <strings.h>37#endif3839#if defined(_ALLBSD_SOURCE)40#include <net/ethernet.h>41#include <net/if_dl.h>42#include <ifaddrs.h>43#endif4445#include "net_util.h"4647#include "java_net_InetAddress.h"4849#if defined(__linux__)50#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"51#endif5253#ifdef LIFNAMSIZ54#define IFNAMESIZE LIFNAMSIZ55#else56#define IFNAMESIZE IFNAMSIZ57#endif5859#define CHECKED_MALLOC3(_pointer, _type, _size) \60do { \61_pointer = (_type)malloc(_size); \62if (_pointer == NULL) { \63JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \64return ifs; /* return untouched list */ \65} \66} while(0)6768typedef struct _netaddr {69struct sockaddr *addr;70struct sockaddr *brdcast;71short mask;72int family; /* to make searches simple */73struct _netaddr *next;74} netaddr;7576typedef struct _netif {77char *name;78int index;79char virtual;80netaddr *addr;81struct _netif *childs;82struct _netif *next;83} netif;8485/************************************************************************86* NetworkInterface87*/8889#include "java_net_NetworkInterface.h"9091/************************************************************************92* NetworkInterface93*/94jclass ni_class;95jfieldID ni_nameID;96jfieldID ni_indexID;97jfieldID ni_descID;98jfieldID ni_addrsID;99jfieldID ni_bindsID;100jfieldID ni_virutalID;101jfieldID ni_childsID;102jfieldID ni_parentID;103jfieldID ni_defaultIndexID;104jmethodID ni_ctrID;105106static jclass ni_ibcls;107static jmethodID ni_ibctrID;108static jfieldID ni_ibaddressID;109static jfieldID ni_ib4broadcastID;110static jfieldID ni_ib4maskID;111112/** Private methods declarations **/113static jobject createNetworkInterface(JNIEnv *env, netif *ifs);114static int getFlags0(JNIEnv *env, jstring ifname);115116static netif *enumInterfaces(JNIEnv *env);117static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs);118static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs);119120static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,121struct sockaddr *ifr_addrP,122struct sockaddr *ifr_broadaddrP,123int family, short prefix);124static void freeif(netif *ifs);125126static int openSocket(JNIEnv *env, int proto);127static int openSocketWithFallback(JNIEnv *env, const char *ifname);128129static short translateIPv4AddressToPrefix(struct sockaddr_in *addr);130static short translateIPv6AddressToPrefix(struct sockaddr_in6 *addr);131132static int getIndex(int sock, const char *ifname);133static int getFlags(int sock, const char *ifname, int *flags);134static int getMacAddress(JNIEnv *env, const char *ifname,135const struct in_addr *addr, unsigned char *buf);136static int getMTU(JNIEnv *env, int sock, const char *ifname);137138/******************* Java entry points *****************************/139140/*141* Class: java_net_NetworkInterface142* Method: init143* Signature: ()V144*/145JNIEXPORT void JNICALL Java_java_net_NetworkInterface_init146(JNIEnv *env, jclass cls)147{148ni_class = (*env)->FindClass(env, "java/net/NetworkInterface");149CHECK_NULL(ni_class);150ni_class = (*env)->NewGlobalRef(env, ni_class);151CHECK_NULL(ni_class);152ni_nameID = (*env)->GetFieldID(env, ni_class, "name", "Ljava/lang/String;");153CHECK_NULL(ni_nameID);154ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");155CHECK_NULL(ni_indexID);156ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs",157"[Ljava/net/InetAddress;");158CHECK_NULL(ni_addrsID);159ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings",160"[Ljava/net/InterfaceAddress;");161CHECK_NULL(ni_bindsID);162ni_descID = (*env)->GetFieldID(env, ni_class, "displayName",163"Ljava/lang/String;");164CHECK_NULL(ni_descID);165ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z");166CHECK_NULL(ni_virutalID);167ni_childsID = (*env)->GetFieldID(env, ni_class, "childs",168"[Ljava/net/NetworkInterface;");169CHECK_NULL(ni_childsID);170ni_parentID = (*env)->GetFieldID(env, ni_class, "parent",171"Ljava/net/NetworkInterface;");172CHECK_NULL(ni_parentID);173ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");174CHECK_NULL(ni_ctrID);175ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");176CHECK_NULL(ni_ibcls);177ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);178CHECK_NULL(ni_ibcls);179ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");180CHECK_NULL(ni_ibctrID);181ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address",182"Ljava/net/InetAddress;");183CHECK_NULL(ni_ibaddressID);184ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast",185"Ljava/net/Inet4Address;");186CHECK_NULL(ni_ib4broadcastID);187ni_ib4maskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");188CHECK_NULL(ni_ib4maskID);189ni_defaultIndexID = (*env)->GetStaticFieldID(env, ni_class, "defaultIndex",190"I");191CHECK_NULL(ni_defaultIndexID);192initInetAddressIDs(env);193}194195/*196* Class: java_net_NetworkInterface197* Method: getByName0198* Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;199*/200JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0201(JNIEnv *env, jclass cls, jstring name)202{203netif *ifs, *curr;204jboolean isCopy;205const char* name_utf;206char *colonP;207jobject obj = NULL;208209if (name != NULL) {210name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);211} else {212JNU_ThrowNullPointerException(env, "network interface name is NULL");213return NULL;214}215216if (name_utf == NULL) {217if (!(*env)->ExceptionCheck(env))218JNU_ThrowOutOfMemoryError(env, NULL);219return NULL;220}221222ifs = enumInterfaces(env);223if (ifs == NULL) {224(*env)->ReleaseStringUTFChars(env, name, name_utf);225return NULL;226}227228// search the list of interfaces based on name,229// if it is virtual sub interface search with parent first.230colonP = strchr(name_utf, ':');231size_t limit = colonP != NULL ? (size_t)(colonP - name_utf) : strlen(name_utf);232curr = ifs;233while (curr != NULL) {234if (strlen(curr->name) == limit && memcmp(name_utf, curr->name, limit) == 0) {235break;236}237curr = curr->next;238}239240// search the child list241if (colonP != NULL && curr != NULL) {242curr = curr->childs;243while (curr != NULL) {244if (strcmp(name_utf, curr->name) == 0) {245break;246}247curr = curr->next;248}249}250251// if found create a NetworkInterface252if (curr != NULL) {253obj = createNetworkInterface(env, curr);254}255256// release the UTF string and interface list257(*env)->ReleaseStringUTFChars(env, name, name_utf);258freeif(ifs);259260return obj;261}262263/*264* Class: java_net_NetworkInterface265* Method: getByIndex0266* Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;267*/268JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0269(JNIEnv *env, jclass cls, jint index)270{271netif *ifs, *curr;272jobject obj = NULL;273274if (index <= 0) {275return NULL;276}277278ifs = enumInterfaces(env);279if (ifs == NULL) {280return NULL;281}282283// search the list of interfaces based on index284curr = ifs;285while (curr != NULL) {286if (index == curr->index) {287break;288}289curr = curr->next;290}291292// if found create a NetworkInterface293if (curr != NULL) {294obj = createNetworkInterface(env, curr);295}296297// release the interface list298freeif(ifs);299300return obj;301}302303// Return the interface in ifs that iaObj is bound to, if any - otherwise NULL304static netif* find_bound_interface(JNIEnv *env, netif* ifs, jobject iaObj, int family) {305netif* curr = ifs;306while (curr != NULL) {307netaddr *addrP = curr->addr;308309// iterate through each address on the interface310while (addrP != NULL) {311312if (family == addrP->family) {313if (family == AF_INET) {314int address1 = htonl(315((struct sockaddr_in *)addrP->addr)->sin_addr.s_addr);316int address2 = getInetAddress_addr(env, iaObj);317if ((*env)->ExceptionCheck(env)) {318return NULL;319}320if (address1 == address2) {321return curr;322}323} else if (family == AF_INET6) {324jbyte *bytes = (jbyte *)&(325((struct sockaddr_in6*)addrP->addr)->sin6_addr);326jbyte caddr[16];327int i;328unsigned int scopeid;329getInet6Address_ipaddress(env, iaObj, (char *)caddr);330scopeid = (unsigned int)getInet6Address_scopeid(env, iaObj);331if (scopeid != 0 && scopeid != ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id)332break;333i = 0;334while (i < 16) {335if (caddr[i] != bytes[i]) {336break;337}338i++;339}340if (i >= 16) {341return curr;342}343}344}345346addrP = addrP->next;347}348curr = curr->next;349}350351return NULL;352}353354/*355* Class: java_net_NetworkInterface356* Method: boundInetAddress0357* Signature: (Ljava/net/InetAddress;)boundInetAddress;358*/359JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0360(JNIEnv *env, jclass cls, jobject iaObj)361{362netif *ifs = NULL;363jboolean bound = JNI_FALSE;364int sock;365366int family = getInetAddress_family(env, iaObj);367JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);368369if (family == java_net_InetAddress_IPv4) {370family = AF_INET;371} else if (family == java_net_InetAddress_IPv6) {372family = AF_INET6;373} else {374return JNI_FALSE; // Invalid family375}376377if (family == AF_INET) {378sock = openSocket(env, AF_INET);379if (sock < 0 && (*env)->ExceptionOccurred(env)) {380return JNI_FALSE;381}382383// enumerate IPv4 addresses384if (sock >= 0) {385ifs = enumIPv4Interfaces(env, sock, ifs);386close(sock);387388if ((*env)->ExceptionOccurred(env)) {389goto cleanup;390}391}392if (find_bound_interface(env, ifs, iaObj, family) != NULL)393bound = JNI_TRUE;394} else if (ipv6_available()) {395// If IPv6 is available then enumerate IPv6 addresses.396// User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,397// so we have to call ipv6_available()398sock = openSocket(env, AF_INET6);399if (sock < 0) {400return JNI_FALSE;401}402403ifs = enumIPv6Interfaces(env, sock, ifs);404close(sock);405406if ((*env)->ExceptionOccurred(env)) {407goto cleanup;408}409410if (find_bound_interface(env, ifs, iaObj, family) != NULL)411bound = JNI_TRUE;412}413414cleanup:415freeif(ifs);416417return bound;418}419420/*421* Class: java_net_NetworkInterface422* Method: getByInetAddress0423* Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;424*/425JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0426(JNIEnv *env, jclass cls, jobject iaObj)427{428netif *ifs, *curr;429jobject obj = NULL;430int family = getInetAddress_family(env, iaObj);431JNU_CHECK_EXCEPTION_RETURN(env, NULL);432433if (family == java_net_InetAddress_IPv4) {434family = AF_INET;435} else if (family == java_net_InetAddress_IPv6) {436family = AF_INET6;437} else {438return NULL; // Invalid family439}440ifs = enumInterfaces(env);441if (ifs == NULL) {442return NULL;443}444445curr = find_bound_interface(env, ifs, iaObj, family);446447// if found create a NetworkInterface448if (curr != NULL) {449obj = createNetworkInterface(env, curr);450}451452// release the interface list453freeif(ifs);454455return obj;456}457458/*459* Class: java_net_NetworkInterface460* Method: getAll461* Signature: ()[Ljava/net/NetworkInterface;462*/463JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll464(JNIEnv *env, jclass cls)465{466netif *ifs, *curr;467jobjectArray netIFArr;468jint arr_index, ifCount;469470ifs = enumInterfaces(env);471if (ifs == NULL) {472return NULL;473}474475// count the interfaces476ifCount = 0;477curr = ifs;478while (curr != NULL) {479ifCount++;480curr = curr->next;481}482483// allocate a NetworkInterface array484netIFArr = (*env)->NewObjectArray(env, ifCount, cls, NULL);485if (netIFArr == NULL) {486freeif(ifs);487return NULL;488}489490// iterate through the interfaces, create a NetworkInterface instance491// for each array element and populate the object492curr = ifs;493arr_index = 0;494while (curr != NULL) {495jobject netifObj;496497netifObj = createNetworkInterface(env, curr);498if (netifObj == NULL) {499freeif(ifs);500return NULL;501}502503// put the NetworkInterface into the array504(*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);505(*env)->DeleteLocalRef(env, netifObj);506507curr = curr->next;508}509510// release the interface list511freeif(ifs);512513return netIFArr;514}515516/*517* Class: java_net_NetworkInterface518* Method: isUp0519* Signature: (Ljava/lang/String;I)Z520*/521JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0522(JNIEnv *env, jclass cls, jstring name, jint index)523{524int ret = getFlags0(env, name);525return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE : JNI_FALSE;526}527528/*529* Class: java_net_NetworkInterface530* Method: isP2P0531* Signature: (Ljava/lang/String;I)Z532*/533JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0534(JNIEnv *env, jclass cls, jstring name, jint index)535{536int ret = getFlags0(env, name);537return (ret & IFF_POINTOPOINT) ? JNI_TRUE : JNI_FALSE;538}539540/*541* Class: java_net_NetworkInterface542* Method: isLoopback0543* Signature: (Ljava/lang/String;I)Z544*/545JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0546(JNIEnv *env, jclass cls, jstring name, jint index)547{548int ret = getFlags0(env, name);549return (ret & IFF_LOOPBACK) ? JNI_TRUE : JNI_FALSE;550}551552/*553* Class: java_net_NetworkInterface554* Method: supportsMulticast0555* Signature: (Ljava/lang/String;I)Z556*/557JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0558(JNIEnv *env, jclass cls, jstring name, jint index)559{560int ret = getFlags0(env, name);561return (ret & IFF_MULTICAST) ? JNI_TRUE : JNI_FALSE;562}563564/*565* Class: java_net_NetworkInterface566* Method: getMacAddr0567* Signature: ([bLjava/lang/String;I)[b568*/569JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0570(JNIEnv *env, jclass cls, jbyteArray addrArray, jstring name, jint index)571{572jint addr;573jbyte caddr[4];574struct in_addr iaddr;575jbyteArray ret = NULL;576unsigned char mac[16];577int len;578jboolean isCopy;579const char *name_utf;580581if (name != NULL) {582name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);583} else {584JNU_ThrowNullPointerException(env, "network interface name is NULL");585return NULL;586}587588if (name_utf == NULL) {589if (!(*env)->ExceptionCheck(env))590JNU_ThrowOutOfMemoryError(env, NULL);591return NULL;592}593594if (!IS_NULL(addrArray)) {595(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);596addr = ((caddr[0]<<24) & 0xff000000);597addr |= ((caddr[1] <<16) & 0xff0000);598addr |= ((caddr[2] <<8) & 0xff00);599addr |= (caddr[3] & 0xff);600iaddr.s_addr = htonl(addr);601len = getMacAddress(env, name_utf, &iaddr, mac);602} else {603len = getMacAddress(env, name_utf, NULL, mac);604}605606if (len > 0) {607ret = (*env)->NewByteArray(env, len);608if (!IS_NULL(ret)) {609(*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *)(mac));610}611}612613// release the UTF string and interface list614(*env)->ReleaseStringUTFChars(env, name, name_utf);615616return ret;617}618619/*620* Class: java_net_NetworkInterface621* Method: getMTU0622* Signature: ([bLjava/lang/String;I)I623*/624JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0625(JNIEnv *env, jclass cls, jstring name, jint index)626{627jboolean isCopy;628int sock, ret = -1;629const char* name_utf = NULL;630631if (name != NULL) {632name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);633} else {634JNU_ThrowNullPointerException(env, "network interface name is NULL");635return ret;636}637638if (name_utf == NULL) {639if (!(*env)->ExceptionCheck(env))640JNU_ThrowOutOfMemoryError(env, NULL);641return ret;642}643644if ((sock = openSocketWithFallback(env, name_utf)) < 0) {645(*env)->ReleaseStringUTFChars(env, name, name_utf);646return JNI_FALSE;647}648649ret = getMTU(env, sock, name_utf);650651(*env)->ReleaseStringUTFChars(env, name, name_utf);652653close(sock);654return ret;655}656657/*** Private methods definitions ****/658659static int getFlags0(JNIEnv *env, jstring name) {660jboolean isCopy;661int ret, sock, flags = 0;662const char *name_utf;663664if (name != NULL) {665name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);666} else {667JNU_ThrowNullPointerException(env, "network interface name is NULL");668return -1;669}670671if (name_utf == NULL) {672if (!(*env)->ExceptionCheck(env))673JNU_ThrowOutOfMemoryError(env, NULL);674return -1;675}676if ((sock = openSocketWithFallback(env, name_utf)) < 0) {677(*env)->ReleaseStringUTFChars(env, name, name_utf);678return -1;679}680681ret = getFlags(sock, name_utf, &flags);682683close(sock);684(*env)->ReleaseStringUTFChars(env, name, name_utf);685686if (ret < 0) {687JNU_ThrowByNameWithMessageAndLastError688(env, JNU_JAVANETPKG "SocketException", "getFlags() failed");689return -1;690}691692return flags;693}694695/*696* Creates a NetworkInterface object, populates the name, the index, and697* populates the InetAddress array based on the IP addresses for this698* interface.699*/700static jobject createNetworkInterface(JNIEnv *env, netif *ifs) {701jobject netifObj;702jobject name;703jobjectArray addrArr;704jobjectArray bindArr;705jobjectArray childArr;706netaddr *addrs;707jint addr_index, addr_count, bind_index;708jint child_count, child_index;709netaddr *addrP;710netif *childP;711jobject tmp;712713// create a NetworkInterface object and populate it714netifObj = (*env)->NewObject(env, ni_class, ni_ctrID);715CHECK_NULL_RETURN(netifObj, NULL);716name = (*env)->NewStringUTF(env, ifs->name);717CHECK_NULL_RETURN(name, NULL);718(*env)->SetObjectField(env, netifObj, ni_nameID, name);719(*env)->SetObjectField(env, netifObj, ni_descID, name);720(*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);721(*env)->SetBooleanField(env, netifObj, ni_virutalID,722ifs->virtual ? JNI_TRUE : JNI_FALSE);723724// count the number of addresses on this interface725addr_count = 0;726addrP = ifs->addr;727while (addrP != NULL) {728addr_count++;729addrP = addrP->next;730}731732// create the array of InetAddresses733addrArr = (*env)->NewObjectArray(env, addr_count, ia_class, NULL);734if (addrArr == NULL) {735return NULL;736}737738bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL);739if (bindArr == NULL) {740return NULL;741}742addrP = ifs->addr;743addr_index = 0;744bind_index = 0;745while (addrP != NULL) {746jobject iaObj = NULL;747jobject ibObj = NULL;748749if (addrP->family == AF_INET) {750iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);751if (iaObj) {752setInetAddress_addr(env, iaObj, htonl(753((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr));754JNU_CHECK_EXCEPTION_RETURN(env, NULL);755} else {756return NULL;757}758ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);759if (ibObj) {760(*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);761if (addrP->brdcast) {762jobject ia2Obj = NULL;763ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID);764if (ia2Obj) {765setInetAddress_addr(env, ia2Obj, htonl(766((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr));767JNU_CHECK_EXCEPTION_RETURN(env, NULL);768(*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj);769(*env)->DeleteLocalRef(env, ia2Obj);770} else {771return NULL;772}773}774(*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);775(*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);776(*env)->DeleteLocalRef(env, ibObj);777} else {778return NULL;779}780}781if (addrP->family == AF_INET6) {782int scope=0;783iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);784if (iaObj) {785jboolean ret = setInet6Address_ipaddress(env, iaObj,786(char *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr));787if (ret == JNI_FALSE) {788return NULL;789}790791scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;792793if (scope != 0) { /* zero is default value, no need to set */794setInet6Address_scopeid(env, iaObj, scope);795setInet6Address_scopeifname(env, iaObj, netifObj);796}797} else {798return NULL;799}800ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);801if (ibObj) {802(*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);803(*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);804(*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);805(*env)->DeleteLocalRef(env, ibObj);806} else {807return NULL;808}809}810811(*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj);812(*env)->DeleteLocalRef(env, iaObj);813addrP = addrP->next;814}815816// see if there is any virtual interface attached to this one.817child_count = 0;818childP = ifs->childs;819while (childP) {820child_count++;821childP = childP->next;822}823824childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL);825if (childArr == NULL) {826return NULL;827}828829// create the NetworkInterface instances for the sub-interfaces as well830child_index = 0;831childP = ifs->childs;832while(childP) {833tmp = createNetworkInterface(env, childP);834if (tmp == NULL) {835return NULL;836}837(*env)->SetObjectField(env, tmp, ni_parentID, netifObj);838(*env)->SetObjectArrayElement(env, childArr, child_index++, tmp);839childP = childP->next;840}841(*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);842(*env)->SetObjectField(env, netifObj, ni_bindsID, bindArr);843(*env)->SetObjectField(env, netifObj, ni_childsID, childArr);844845(*env)->DeleteLocalRef(env, name);846(*env)->DeleteLocalRef(env, addrArr);847(*env)->DeleteLocalRef(env, bindArr);848(*env)->DeleteLocalRef(env, childArr);849850// return the NetworkInterface851return netifObj;852}853854/*855* Enumerates all interfaces856*/857static netif *enumInterfaces(JNIEnv *env) {858netif *ifs = NULL;859int sock;860861sock = openSocket(env, AF_INET);862if (sock < 0 && (*env)->ExceptionOccurred(env)) {863return NULL;864}865866// enumerate IPv4 addresses867if (sock >= 0) {868ifs = enumIPv4Interfaces(env, sock, ifs);869close(sock);870871if ((*env)->ExceptionOccurred(env)) {872freeif(ifs);873return NULL;874}875}876877// If IPv6 is available then enumerate IPv6 addresses.878// User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,879// so we have to call ipv6_available()880if (ipv6_available()) {881sock = openSocket(env, AF_INET6);882if (sock < 0) {883freeif(ifs);884return NULL;885}886887ifs = enumIPv6Interfaces(env, sock, ifs);888close(sock);889890if ((*env)->ExceptionOccurred(env)) {891freeif(ifs);892return NULL;893}894}895896return ifs;897}898899/*900* Frees an interface list (including any attached addresses).901*/902static void freeif(netif *ifs) {903netif *currif = ifs;904netif *child = NULL;905906while (currif != NULL) {907netaddr *addrP = currif->addr;908while (addrP != NULL) {909netaddr *next = addrP->next;910free(addrP);911addrP = next;912}913914// don't forget to free the sub-interfaces915if (currif->childs != NULL) {916freeif(currif->childs);917}918919ifs = currif->next;920free(currif);921currif = ifs;922}923}924925static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,926struct sockaddr *ifr_addrP,927struct sockaddr *ifr_broadaddrP,928int family, short prefix)929{930netif *currif = ifs, *parent;931netaddr *addrP;932char name[IFNAMESIZE], vname[IFNAMESIZE];933char *name_colonP;934int isVirtual = 0;935int addr_size;936937// If the interface name is a logical interface then we remove the unit938// number so that we have the physical interface (eg: hme0:1 -> hme0).939// NetworkInterface currently doesn't have any concept of physical vs.940// logical interfaces.941strncpy(name, if_name, IFNAMESIZE);942name[IFNAMESIZE - 1] = '\0';943*vname = 0;944945// Create and populate the netaddr node. If allocation fails946// return an un-updated list.947948// Allocate for addr and brdcast at once949950addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in)951: sizeof(struct sockaddr_in6);952953CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr) + 2 * addr_size);954addrP->addr = (struct sockaddr *)((char *)addrP + sizeof(netaddr));955memcpy(addrP->addr, ifr_addrP, addr_size);956957addrP->family = family;958addrP->mask = prefix;959addrP->next = 0;960961// for IPv4 add broadcast address962if (family == AF_INET && ifr_broadaddrP != NULL) {963addrP->brdcast = (struct sockaddr *)964((char *)addrP + sizeof(netaddr) + addr_size);965memcpy(addrP->brdcast, ifr_broadaddrP, addr_size);966} else {967addrP->brdcast = NULL;968}969970// Deal with virtual interface with colon notation e.g. eth0:1971name_colonP = strchr(name, ':');972if (name_colonP != NULL) {973int flags = 0;974// This is a virtual interface. If we are able to access the parent975// we need to create a new entry if it doesn't exist yet *and* update976// the 'parent' interface with the new records.977*name_colonP = 0;978if (getFlags(sock, name, &flags) < 0 || flags < 0) {979// failed to access parent interface do not create parent.980// We are a virtual interface with no parent.981isVirtual = 1;982*name_colonP = ':';983} else {984// Got access to parent, so create it if necessary.985// Save original name to vname and truncate name by ':'986memcpy(vname, name, sizeof(vname));987vname[name_colonP - name] = ':';988}989}990991// Check if this is a "new" interface. Use the interface name for992// matching because index isn't supported on Solaris 2.6 & 7.993while (currif != NULL) {994if (strcmp(name, currif->name) == 0) {995break;996}997currif = currif->next;998}9991000// If "new" then create a netif structure and insert it into the list.1001if (currif == NULL) {1002CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE);1003currif->name = (char *)currif + sizeof(netif);1004strncpy(currif->name, name, IFNAMESIZE);1005currif->name[IFNAMESIZE - 1] = '\0';1006currif->index = getIndex(sock, name);1007currif->addr = NULL;1008currif->childs = NULL;1009currif->virtual = isVirtual;1010currif->next = ifs;1011ifs = currif;1012}10131014// Finally insert the address on the interface1015addrP->next = currif->addr;1016currif->addr = addrP;10171018parent = currif;10191020// Deal with the virtual interface now.1021if (vname[0]) {1022netaddr *tmpaddr;10231024currif = parent->childs;10251026while (currif != NULL) {1027if (strcmp(vname, currif->name) == 0) {1028break;1029}1030currif = currif->next;1031}10321033if (currif == NULL) {1034CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE);1035currif->name = (char *)currif + sizeof(netif);1036strncpy(currif->name, vname, IFNAMESIZE);1037currif->name[IFNAMESIZE - 1] = '\0';1038currif->index = getIndex(sock, vname);1039currif->addr = NULL; // Need to duplicate the addr entry?1040currif->virtual = 1;1041currif->childs = NULL;1042currif->next = parent->childs;1043parent->childs = currif;1044}10451046CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr) + 2 * addr_size);1047memcpy(tmpaddr, addrP, sizeof(netaddr));1048if (addrP->addr != NULL) {1049tmpaddr->addr = (struct sockaddr *)1050((char*)tmpaddr + sizeof(netaddr));1051memcpy(tmpaddr->addr, addrP->addr, addr_size);1052}10531054if (addrP->brdcast != NULL) {1055tmpaddr->brdcast = (struct sockaddr *)1056((char *)tmpaddr + sizeof(netaddr) + addr_size);1057memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size);1058}10591060tmpaddr->next = currif->addr;1061currif->addr = tmpaddr;1062}10631064return ifs;1065}10661067/*1068* Determines the prefix value for an AF_INET subnet address.1069*/1070static short translateIPv4AddressToPrefix(struct sockaddr_in *addr) {1071short prefix = 0;1072unsigned int mask;1073if (addr == NULL) {1074return 0;1075}1076mask = ntohl(addr->sin_addr.s_addr);1077while (mask) {1078mask <<= 1;1079prefix++;1080}1081return prefix;1082}10831084/*1085* Determines the prefix value for an AF_INET6 subnet address.1086*/1087static short translateIPv6AddressToPrefix(struct sockaddr_in6 *addr) {1088short prefix = 0;1089u_char *addrBytes;1090if (addr == NULL) {1091return 0;1092}1093addrBytes = (u_char *)&(addr->sin6_addr);1094unsigned int byte, bit;10951096for (byte = 0; byte < sizeof(struct in6_addr); byte++, prefix += 8) {1097if (addrBytes[byte] != 0xff) {1098break;1099}1100}1101if (byte != sizeof(struct in6_addr)) {1102for (bit = 7; bit != 0; bit--, prefix++) {1103if (!(addrBytes[byte] & (1 << bit))) {1104break;1105}1106}1107for (; bit != 0; bit--) {1108if (addrBytes[byte] & (1 << bit)) {1109prefix = 0;1110break;1111}1112}1113if (prefix > 0) {1114byte++;1115for (; byte < sizeof(struct in6_addr); byte++) {1116if (addrBytes[byte]) {1117prefix = 0;1118}1119}1120}1121}11221123return prefix;1124}11251126/*1127* Opens a socket for further ioct calls. proto is one of AF_INET or AF_INET6.1128*/1129static int openSocket(JNIEnv *env, int proto) {1130int sock;11311132if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) {1133// If we lack support for this address family or protocol,1134// don't throw an exception.1135if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT) {1136JNU_ThrowByNameWithMessageAndLastError1137(env, JNU_JAVANETPKG "SocketException", "Socket creation failed");1138}1139return -1;1140}11411142return sock;1143}11441145/** Linux **/1146#if defined(__linux__)11471148/*1149* Opens a socket for further ioctl calls. Tries AF_INET socket first and1150* if it fails return AF_INET6 socket.1151*/1152static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1153int sock;11541155if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {1156if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {1157if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {1158JNU_ThrowByNameWithMessageAndLastError1159(env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");1160return -1;1161}1162} else { // errno is not NOSUPPORT1163JNU_ThrowByNameWithMessageAndLastError1164(env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");1165return -1;1166}1167}11681169// Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or1170// IPv6 socket regardless of type of address of an interface.1171return sock;1172}11731174/*1175* Enumerates and returns all IPv4 interfaces on Linux.1176*/1177static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {1178struct ifconf ifc;1179struct ifreq *ifreqP;1180char *buf = NULL;1181unsigned i;11821183// do a dummy SIOCGIFCONF to determine the buffer size1184// SIOCGIFCOUNT doesn't work1185ifc.ifc_buf = NULL;1186if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {1187JNU_ThrowByNameWithMessageAndLastError1188(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");1189return ifs;1190}11911192// call SIOCGIFCONF to enumerate the interfaces1193CHECKED_MALLOC3(buf, char *, ifc.ifc_len);1194ifc.ifc_buf = buf;1195if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {1196JNU_ThrowByNameWithMessageAndLastError1197(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");1198free(buf);1199return ifs;1200}12011202// iterate through each interface1203ifreqP = ifc.ifc_req;1204for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {1205struct sockaddr addr, broadaddr, *broadaddrP = NULL;1206short prefix = 0;12071208// ignore non IPv4 addresses1209if (ifreqP->ifr_addr.sa_family != AF_INET) {1210continue;1211}12121213// save socket address1214memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));12151216// determine broadcast address, if applicable1217if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&1218ifreqP->ifr_flags & IFF_BROADCAST) {12191220// restore socket address to ifreqP1221memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));12221223if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {1224memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),1225sizeof(struct sockaddr));1226broadaddrP = &broadaddr;1227}1228}12291230// restore socket address to ifreqP1231memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));12321233// determine netmask1234if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {1235prefix = translateIPv4AddressToPrefix(1236(struct sockaddr_in *)&(ifreqP->ifr_netmask));1237}12381239// add interface to the list1240ifs = addif(env, sock, ifreqP->ifr_name, ifs,1241&addr, broadaddrP, AF_INET, prefix);12421243// in case of exception, free interface list and buffer and return NULL1244if ((*env)->ExceptionOccurred(env)) {1245free(buf);1246freeif(ifs);1247return NULL;1248}1249}12501251// free buffer1252free(buf);1253return ifs;1254}12551256/*1257* Enumerates and returns all IPv6 interfaces on Linux.1258*/1259static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {1260FILE *f;1261char devname[21], addr6p[8][5];1262int prefix, scope, dad_status, if_idx;12631264if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {1265while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",1266addr6p[0], addr6p[1], addr6p[2], addr6p[3],1267addr6p[4], addr6p[5], addr6p[6], addr6p[7],1268&if_idx, &prefix, &scope, &dad_status, devname) != EOF) {12691270char addr6[40];1271struct sockaddr_in6 addr;12721273sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",1274addr6p[0], addr6p[1], addr6p[2], addr6p[3],1275addr6p[4], addr6p[5], addr6p[6], addr6p[7]);12761277memset(&addr, 0, sizeof(struct sockaddr_in6));1278inet_pton(AF_INET6, addr6, (void*)addr.sin6_addr.s6_addr);12791280// set scope ID to interface index1281addr.sin6_scope_id = if_idx;12821283// add interface to the list1284ifs = addif(env, sock, devname, ifs, (struct sockaddr *)&addr,1285NULL, AF_INET6, (short)prefix);12861287// if an exception occurred then return the list as is1288if ((*env)->ExceptionOccurred(env)) {1289break;1290}1291}1292fclose(f);1293}1294return ifs;1295}12961297/*1298* Try to get the interface index.1299*/1300static int getIndex(int sock, const char *name) {1301struct ifreq if2;1302memset((char *)&if2, 0, sizeof(if2));1303strncpy(if2.ifr_name, name, sizeof(if2.ifr_name));1304if2.ifr_name[sizeof(if2.ifr_name) - 1] = 0;13051306if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {1307return -1;1308}13091310return if2.ifr_ifindex;1311}13121313/*1314* Gets the Hardware address (usually MAC address) for the named interface.1315* On return puts the data in buf, and returns the length, in byte, of the1316* MAC address. Returns -1 if there is no hardware address on that interface.1317*/1318static int getMacAddress1319(JNIEnv *env, const char *ifname, const struct in_addr *addr,1320unsigned char *buf)1321{1322struct ifreq ifr;1323int i, sock;13241325if ((sock = openSocketWithFallback(env, ifname)) < 0) {1326return -1;1327}13281329memset((char *)&ifr, 0, sizeof(ifr));1330strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);1331if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {1332JNU_ThrowByNameWithMessageAndLastError1333(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFHWADDR) failed");1334close(sock);1335return -1;1336}13371338close(sock);1339memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);13401341// all bytes to 0 means no hardware address1342for (i = 0; i < IFHWADDRLEN; i++) {1343if (buf[i] != 0)1344return IFHWADDRLEN;1345}13461347return -1;1348}13491350static int getMTU(JNIEnv *env, int sock, const char *ifname) {1351struct ifreq if2;1352memset((char *)&if2, 0, sizeof(if2));1353strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);13541355if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {1356JNU_ThrowByNameWithMessageAndLastError1357(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");1358return -1;1359}13601361return if2.ifr_mtu;1362}13631364static int getFlags(int sock, const char *ifname, int *flags) {1365struct ifreq if2;1366memset((char *)&if2, 0, sizeof(if2));1367strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name));1368if2.ifr_name[sizeof(if2.ifr_name) - 1] = 0;13691370if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {1371return -1;1372}13731374if (sizeof(if2.ifr_flags) == sizeof(short)) {1375*flags = (if2.ifr_flags & 0xffff);1376} else {1377*flags = if2.ifr_flags;1378}1379return 0;1380}13811382#endif /* __linux__ */13831384/** AIX **/1385#if defined(_AIX)13861387/* seems getkerninfo is guarded by _KERNEL in the system headers */1388/* see net/proto_uipc.h */1389int getkerninfo(int, char *, int *, int32long64_t);13901391/*1392* Opens a socket for further ioctl calls. Tries AF_INET socket first and1393* if it fails return AF_INET6 socket.1394*/1395static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1396int sock;13971398if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {1399if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {1400if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {1401JNU_ThrowByNameWithMessageAndLastError1402(env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");1403return -1;1404}1405} else { // errno is not NOSUPPORT1406JNU_ThrowByNameWithMessageAndLastError1407(env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");1408return -1;1409}1410}14111412return sock;1413}14141415/*1416* Enumerates and returns all IPv4 interfaces on AIX.1417*/1418static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {1419struct ifconf ifc;1420struct ifreq *ifreqP;1421char *buf = NULL;1422unsigned i;14231424// call SIOCGSIZIFCONF to get the size of SIOCGIFCONF buffer1425if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {1426JNU_ThrowByNameWithMessageAndLastError1427(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");1428return ifs;1429}14301431// call CSIOCGIFCONF instead of SIOCGIFCONF where interface1432// records will always have sizeof(struct ifreq) length.1433// Be aware that only IPv4 data is complete this way.1434CHECKED_MALLOC3(buf, char *, ifc.ifc_len);1435ifc.ifc_buf = buf;1436if (ioctl(sock, CSIOCGIFCONF, (char *)&ifc) < 0) {1437JNU_ThrowByNameWithMessageAndLastError1438(env, JNU_JAVANETPKG "SocketException", "ioctl(CSIOCGIFCONF) failed");1439free(buf);1440return ifs;1441}14421443// iterate through each interface1444ifreqP = ifc.ifc_req;1445for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {1446struct sockaddr addr, broadaddr, *broadaddrP = NULL;1447short prefix = 0;14481449// ignore non IPv4 addresses1450if (ifreqP->ifr_addr.sa_family != AF_INET) {1451continue;1452}14531454// save socket address1455memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));14561457// determine broadcast address, if applicable1458if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&1459ifreqP->ifr_flags & IFF_BROADCAST) {14601461// restore socket address to ifreqP1462memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));14631464if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {1465memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),1466sizeof(struct sockaddr));1467broadaddrP = &broadaddr;1468}1469}14701471// restore socket address to ifreqP1472memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));14731474// determine netmask1475if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {1476prefix = translateIPv4AddressToPrefix(1477(struct sockaddr_in *)&(ifreqP->ifr_addr));1478}14791480// add interface to the list1481ifs = addif(env, sock, ifreqP->ifr_name, ifs,1482&addr, broadaddrP, AF_INET, prefix);14831484// in case of exception, free interface list and buffer and return NULL1485if ((*env)->ExceptionOccurred(env)) {1486free(buf);1487freeif(ifs);1488return NULL;1489}1490}14911492// free buffer1493free(buf);1494return ifs;1495}14961497/*1498* Enumerates and returns all IPv6 interfaces on AIX.1499*/1500static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {1501struct ifconf ifc;1502struct ifreq *ifreqP;1503char *buf, *cp, *cplimit;15041505// call SIOCGSIZIFCONF to get size for SIOCGIFCONF buffer1506if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {1507JNU_ThrowByNameWithMessageAndLastError1508(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");1509return ifs;1510}15111512// call SIOCGIFCONF to enumerate the interfaces1513CHECKED_MALLOC3(buf, char *, ifc.ifc_len);1514ifc.ifc_buf = buf;1515if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {1516JNU_ThrowByNameWithMessageAndLastError1517(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");1518free(buf);1519return ifs;1520}15211522// iterate through each interface1523ifreqP = ifc.ifc_req;1524cp = (char *)ifc.ifc_req;1525cplimit = cp + ifc.ifc_len;15261527for (; cp < cplimit;1528cp += (sizeof(ifreqP->ifr_name) +1529MAX((ifreqP->ifr_addr).sa_len, sizeof(ifreqP->ifr_addr))))1530{1531ifreqP = (struct ifreq *)cp;1532short prefix = 0;15331534// ignore non IPv6 addresses1535if (ifreqP->ifr_addr.sa_family != AF_INET6) {1536continue;1537}15381539// determine netmask1540struct in6_ifreq if6;1541memset((char *)&if6, 0, sizeof(if6));1542strncpy(if6.ifr_name, ifreqP->ifr_name, sizeof(if6.ifr_name) - 1);1543memcpy(&(if6.ifr_Addr), &(ifreqP->ifr_addr),1544sizeof(struct sockaddr_in6));1545if (ioctl(sock, SIOCGIFNETMASK6, (char *)&if6) >= 0) {1546prefix = translateIPv6AddressToPrefix(&(if6.ifr_Addr));1547}15481549// set scope ID to interface index1550((struct sockaddr_in6 *)&(ifreqP->ifr_addr))->sin6_scope_id =1551getIndex(sock, ifreqP->ifr_name);15521553// add interface to the list1554ifs = addif(env, sock, ifreqP->ifr_name, ifs,1555(struct sockaddr *)&(ifreqP->ifr_addr),1556NULL, AF_INET6, prefix);15571558// if an exception occurred then free the list1559if ((*env)->ExceptionOccurred(env)) {1560free(buf);1561freeif(ifs);1562return NULL;1563}1564}15651566// free buffer1567free(buf);1568return ifs;1569}15701571/*1572* Try to get the interface index.1573*/1574static int getIndex(int sock, const char *name) {1575int index = if_nametoindex(name);1576return (index == 0) ? -1 : index;1577}15781579/*1580* Gets the Hardware address (usually MAC address) for the named interface.1581* On return puts the data in buf, and returns the length, in byte, of the1582* MAC address. Returns -1 if there is no hardware address on that interface.1583*/1584static int getMacAddress1585(JNIEnv *env, const char *ifname, const struct in_addr *addr,1586unsigned char *buf)1587{1588int size;1589struct kinfo_ndd *nddp;1590void *end;15911592size = getkerninfo(KINFO_NDD, 0, 0, 0);1593if (size == 0) {1594return -1;1595}15961597if (size < 0) {1598perror("getkerninfo 1");1599return -1;1600}16011602nddp = (struct kinfo_ndd *)malloc(size);16031604if (!nddp) {1605JNU_ThrowOutOfMemoryError(env,1606"Network interface getMacAddress native buffer allocation failed");1607return -1;1608}16091610if (getkerninfo(KINFO_NDD, (char*) nddp, &size, 0) < 0) {1611perror("getkerninfo 2");1612free(nddp);1613return -1;1614}16151616end = (void *)nddp + size;1617while ((void *)nddp < end) {1618if (!strcmp(nddp->ndd_alias, ifname) ||1619!strcmp(nddp->ndd_name, ifname)) {1620bcopy(nddp->ndd_addr, buf, 6);1621free(nddp);1622return 6;1623} else {1624nddp++;1625}1626}16271628free(nddp);1629return -1;1630}16311632static int getMTU(JNIEnv *env, int sock, const char *ifname) {1633struct ifreq if2;1634memset((char *)&if2, 0, sizeof(if2));1635strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);16361637if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {1638JNU_ThrowByNameWithMessageAndLastError1639(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");1640return -1;1641}16421643return if2.ifr_mtu;1644}16451646static int getFlags(int sock, const char *ifname, int *flags) {1647struct ifreq if2;1648memset((char *)&if2, 0, sizeof(if2));1649strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);16501651if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {1652return -1;1653}16541655if (sizeof(if2.ifr_flags) == sizeof(short)) {1656*flags = (if2.ifr_flags & 0xffff);1657} else {1658*flags = if2.ifr_flags;1659}1660return 0;1661}16621663#endif /* _AIX */16641665/** BSD **/1666#if defined(_ALLBSD_SOURCE)16671668/*1669* Opens a socket for further ioctl calls. Tries AF_INET socket first and1670* if it fails return AF_INET6 socket.1671*/1672static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1673int sock;16741675if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {1676if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {1677if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {1678JNU_ThrowByNameWithMessageAndLastError1679(env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");1680return -1;1681}1682} else { // errno is not NOSUPPORT1683JNU_ThrowByNameWithMessageAndLastError1684(env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");1685return -1;1686}1687}16881689return sock;1690}16911692/*1693* Enumerates and returns all IPv4 interfaces on BSD.1694*/1695static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {1696struct ifaddrs *ifa, *origifa;16971698if (getifaddrs(&origifa) != 0) {1699JNU_ThrowByNameWithMessageAndLastError1700(env, JNU_JAVANETPKG "SocketException", "getifaddrs() failed");1701return ifs;1702}17031704for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {1705struct sockaddr *broadaddrP = NULL;17061707// ignore non IPv4 addresses1708if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)1709continue;17101711// set ifa_broadaddr, if there is one1712if ((ifa->ifa_flags & IFF_POINTOPOINT) == 0 &&1713ifa->ifa_flags & IFF_BROADCAST) {1714broadaddrP = ifa->ifa_dstaddr;1715}17161717// add interface to the list1718ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr,1719broadaddrP, AF_INET,1720translateIPv4AddressToPrefix((struct sockaddr_in *)1721ifa->ifa_netmask));17221723// if an exception occurred then free the list1724if ((*env)->ExceptionOccurred(env)) {1725freeifaddrs(origifa);1726freeif(ifs);1727return NULL;1728}1729}17301731// free ifaddrs buffer1732freeifaddrs(origifa);1733return ifs;1734}17351736/*1737* Enumerates and returns all IPv6 interfaces on BSD.1738*/1739static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {1740struct ifaddrs *ifa, *origifa;17411742if (getifaddrs(&origifa) != 0) {1743JNU_ThrowByNameWithMessageAndLastError1744(env, JNU_JAVANETPKG "SocketException", "getifaddrs() failed");1745return ifs;1746}17471748for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {1749// ignore non IPv6 addresses1750if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET6)1751continue;17521753// set scope ID to interface index1754((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id =1755getIndex(sock, ifa->ifa_name);17561757// add interface to the list1758ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, NULL,1759AF_INET6,1760translateIPv6AddressToPrefix((struct sockaddr_in6 *)1761ifa->ifa_netmask));17621763// if an exception occurred then free the list1764if ((*env)->ExceptionOccurred(env)) {1765freeifaddrs(origifa);1766freeif(ifs);1767return NULL;1768}1769}17701771// free ifaddrs buffer1772freeifaddrs(origifa);1773return ifs;1774}17751776/*1777* Try to get the interface index.1778*/1779static int getIndex(int sock, const char *name) {1780#if !defined(__FreeBSD__)1781int index = if_nametoindex(name);1782return (index == 0) ? -1 : index;1783#else1784struct ifreq if2;1785memset((char *)&if2, 0, sizeof(if2));1786strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);17871788if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {1789return -1;1790}17911792return if2.ifr_index;1793#endif1794}17951796/*1797* Gets the Hardware address (usually MAC address) for the named interface.1798* On return puts the data in buf, and returns the length, in byte, of the1799* MAC address. Returns -1 if there is no hardware address on that interface.1800*/1801static int getMacAddress1802(JNIEnv *env, const char *ifname, const struct in_addr *addr,1803unsigned char *buf)1804{1805struct ifaddrs *ifa0, *ifa;1806struct sockaddr *saddr;1807int i;18081809// grab the interface list1810if (!getifaddrs(&ifa0)) {1811// cycle through the interfaces1812for (i = 0, ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next, i++) {1813saddr = ifa->ifa_addr;1814if (saddr != NULL) {1815// link layer contains the MAC address1816if (saddr->sa_family == AF_LINK && !strcmp(ifname, ifa->ifa_name)) {1817struct sockaddr_dl *sadl = (struct sockaddr_dl *) saddr;1818// check the address has the correct length1819if (sadl->sdl_alen == ETHER_ADDR_LEN) {1820memcpy(buf, (sadl->sdl_data + sadl->sdl_nlen), ETHER_ADDR_LEN);1821freeifaddrs(ifa0);1822return ETHER_ADDR_LEN;1823}1824}1825}1826}1827freeifaddrs(ifa0);1828}18291830return -1;1831}18321833static int getMTU(JNIEnv *env, int sock, const char *ifname) {1834struct ifreq if2;1835memset((char *)&if2, 0, sizeof(if2));1836strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);18371838if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {1839JNU_ThrowByNameWithMessageAndLastError1840(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");1841return -1;1842}18431844return if2.ifr_mtu;1845}18461847static int getFlags(int sock, const char *ifname, int *flags) {1848struct ifreq if2;1849memset((char *)&if2, 0, sizeof(if2));1850strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);18511852if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {1853return -1;1854}18551856if (sizeof(if2.ifr_flags) == sizeof(short)) {1857*flags = (if2.ifr_flags & 0xffff);1858} else {1859*flags = if2.ifr_flags;1860}1861return 0;1862}1863#endif /* _ALLBSD_SOURCE */186418651866