Path: blob/master/src/java.base/unix/native/libnet/NetworkInterface.c
41119 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#ifndef TARGET_IOS28#include <net/if_arp.h>29#endif30#include <stdlib.h>31#include <string.h>32#include <sys/ioctl.h>3334#if defined(_AIX)35#include <netinet/in6_var.h>36#include <sys/ndd_var.h>37#include <sys/kinfo.h>38#include <strings.h>39#endif4041#if defined(_ALLBSD_SOURCE)42#include <net/ethernet.h>43#include <net/if_dl.h>44#include <ifaddrs.h>45#endif4647#include "net_util.h"4849#include "java_net_InetAddress.h"5051#if defined(__linux__)52#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"53#endif5455#ifdef LIFNAMSIZ56#define IFNAMESIZE LIFNAMSIZ57#else58#define IFNAMESIZE IFNAMSIZ59#endif6061#define CHECKED_MALLOC3(_pointer, _type, _size) \62do { \63_pointer = (_type)malloc(_size); \64if (_pointer == NULL) { \65JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \66return ifs; /* return untouched list */ \67} \68} while(0)6970typedef struct _netaddr {71struct sockaddr *addr;72struct sockaddr *brdcast;73short mask;74int family; /* to make searches simple */75struct _netaddr *next;76} netaddr;7778typedef struct _netif {79char *name;80int index;81char virtual;82netaddr *addr;83struct _netif *childs;84struct _netif *next;85} netif;8687/************************************************************************88* NetworkInterface89*/9091#include "java_net_NetworkInterface.h"9293/************************************************************************94* NetworkInterface95*/96jclass ni_class;97jfieldID ni_nameID;98jfieldID ni_indexID;99jfieldID ni_descID;100jfieldID ni_addrsID;101jfieldID ni_bindsID;102jfieldID ni_virutalID;103jfieldID ni_childsID;104jfieldID ni_parentID;105jfieldID ni_defaultIndexID;106jmethodID ni_ctrID;107108static jclass ni_ibcls;109static jmethodID ni_ibctrID;110static jfieldID ni_ibaddressID;111static jfieldID ni_ib4broadcastID;112static jfieldID ni_ib4maskID;113114/** Private methods declarations **/115static jobject createNetworkInterface(JNIEnv *env, netif *ifs);116static int getFlags0(JNIEnv *env, jstring ifname);117118static netif *enumInterfaces(JNIEnv *env);119static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs);120static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs);121122static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,123struct sockaddr *ifr_addrP,124struct sockaddr *ifr_broadaddrP,125int family, short prefix);126static void freeif(netif *ifs);127128static int openSocket(JNIEnv *env, int proto);129static int openSocketWithFallback(JNIEnv *env, const char *ifname);130131static short translateIPv4AddressToPrefix(struct sockaddr_in *addr);132static short translateIPv6AddressToPrefix(struct sockaddr_in6 *addr);133134static int getIndex(int sock, const char *ifname);135static int getFlags(int sock, const char *ifname, int *flags);136static int getMacAddress(JNIEnv *env, const char *ifname,137const struct in_addr *addr, unsigned char *buf);138static int getMTU(JNIEnv *env, int sock, const char *ifname);139140/******************* Java entry points *****************************/141142/*143* Class: java_net_NetworkInterface144* Method: init145* Signature: ()V146*/147JNIEXPORT void JNICALL Java_java_net_NetworkInterface_init148(JNIEnv *env, jclass cls)149{150ni_class = (*env)->FindClass(env, "java/net/NetworkInterface");151CHECK_NULL(ni_class);152ni_class = (*env)->NewGlobalRef(env, ni_class);153CHECK_NULL(ni_class);154ni_nameID = (*env)->GetFieldID(env, ni_class, "name", "Ljava/lang/String;");155CHECK_NULL(ni_nameID);156ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");157CHECK_NULL(ni_indexID);158ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs",159"[Ljava/net/InetAddress;");160CHECK_NULL(ni_addrsID);161ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings",162"[Ljava/net/InterfaceAddress;");163CHECK_NULL(ni_bindsID);164ni_descID = (*env)->GetFieldID(env, ni_class, "displayName",165"Ljava/lang/String;");166CHECK_NULL(ni_descID);167ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z");168CHECK_NULL(ni_virutalID);169ni_childsID = (*env)->GetFieldID(env, ni_class, "childs",170"[Ljava/net/NetworkInterface;");171CHECK_NULL(ni_childsID);172ni_parentID = (*env)->GetFieldID(env, ni_class, "parent",173"Ljava/net/NetworkInterface;");174CHECK_NULL(ni_parentID);175ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");176CHECK_NULL(ni_ctrID);177ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");178CHECK_NULL(ni_ibcls);179ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);180CHECK_NULL(ni_ibcls);181ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");182CHECK_NULL(ni_ibctrID);183ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address",184"Ljava/net/InetAddress;");185CHECK_NULL(ni_ibaddressID);186ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast",187"Ljava/net/Inet4Address;");188CHECK_NULL(ni_ib4broadcastID);189ni_ib4maskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");190CHECK_NULL(ni_ib4maskID);191ni_defaultIndexID = (*env)->GetStaticFieldID(env, ni_class, "defaultIndex",192"I");193CHECK_NULL(ni_defaultIndexID);194initInetAddressIDs(env);195}196197/*198* Class: java_net_NetworkInterface199* Method: getByName0200* Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;201*/202JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0203(JNIEnv *env, jclass cls, jstring name)204{205netif *ifs, *curr;206jboolean isCopy;207const char* name_utf;208char *colonP;209jobject obj = NULL;210211if (name != NULL) {212name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);213} else {214JNU_ThrowNullPointerException(env, "network interface name is NULL");215return NULL;216}217218if (name_utf == NULL) {219if (!(*env)->ExceptionCheck(env))220JNU_ThrowOutOfMemoryError(env, NULL);221return NULL;222}223224ifs = enumInterfaces(env);225if (ifs == NULL) {226(*env)->ReleaseStringUTFChars(env, name, name_utf);227return NULL;228}229230// search the list of interfaces based on name,231// if it is virtual sub interface search with parent first.232colonP = strchr(name_utf, ':');233size_t limit = colonP != NULL ? (size_t)(colonP - name_utf) : strlen(name_utf);234curr = ifs;235while (curr != NULL) {236if (strlen(curr->name) == limit && memcmp(name_utf, curr->name, limit) == 0) {237break;238}239curr = curr->next;240}241242// search the child list243if (colonP != NULL && curr != NULL) {244curr = curr->childs;245while (curr != NULL) {246if (strcmp(name_utf, curr->name) == 0) {247break;248}249curr = curr->next;250}251}252253// if found create a NetworkInterface254if (curr != NULL) {255obj = createNetworkInterface(env, curr);256}257258// release the UTF string and interface list259(*env)->ReleaseStringUTFChars(env, name, name_utf);260freeif(ifs);261262return obj;263}264265/*266* Class: java_net_NetworkInterface267* Method: getByIndex0268* Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;269*/270JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0271(JNIEnv *env, jclass cls, jint index)272{273netif *ifs, *curr;274jobject obj = NULL;275276if (index <= 0) {277return NULL;278}279280ifs = enumInterfaces(env);281if (ifs == NULL) {282return NULL;283}284285// search the list of interfaces based on index286curr = ifs;287while (curr != NULL) {288if (index == curr->index) {289break;290}291curr = curr->next;292}293294// if found create a NetworkInterface295if (curr != NULL) {296obj = createNetworkInterface(env, curr);297}298299// release the interface list300freeif(ifs);301302return obj;303}304305// Return the interface in ifs that iaObj is bound to, if any - otherwise NULL306static netif* find_bound_interface(JNIEnv *env, netif* ifs, jobject iaObj, int family) {307netif* curr = ifs;308while (curr != NULL) {309netaddr *addrP = curr->addr;310311// iterate through each address on the interface312while (addrP != NULL) {313314if (family == addrP->family) {315if (family == AF_INET) {316int address1 = htonl(317((struct sockaddr_in *)addrP->addr)->sin_addr.s_addr);318int address2 = getInetAddress_addr(env, iaObj);319if ((*env)->ExceptionCheck(env)) {320return NULL;321}322if (address1 == address2) {323return curr;324}325} else if (family == AF_INET6) {326jbyte *bytes = (jbyte *)&(327((struct sockaddr_in6*)addrP->addr)->sin6_addr);328jbyte caddr[16];329int i;330unsigned int scopeid;331getInet6Address_ipaddress(env, iaObj, (char *)caddr);332scopeid = (unsigned int)getInet6Address_scopeid(env, iaObj);333if (scopeid != 0 && scopeid != ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id)334break;335i = 0;336while (i < 16) {337if (caddr[i] != bytes[i]) {338break;339}340i++;341}342if (i >= 16) {343return curr;344}345}346}347348addrP = addrP->next;349}350curr = curr->next;351}352353return NULL;354}355356/*357* Class: java_net_NetworkInterface358* Method: boundInetAddress0359* Signature: (Ljava/net/InetAddress;)boundInetAddress;360*/361JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0362(JNIEnv *env, jclass cls, jobject iaObj)363{364netif *ifs = NULL;365jboolean bound = JNI_FALSE;366int sock;367368int family = getInetAddress_family(env, iaObj);369JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);370371if (family == java_net_InetAddress_IPv4) {372family = AF_INET;373} else if (family == java_net_InetAddress_IPv6) {374family = AF_INET6;375} else {376return JNI_FALSE; // Invalid family377}378379if (family == AF_INET) {380sock = openSocket(env, AF_INET);381if (sock < 0 && (*env)->ExceptionOccurred(env)) {382return JNI_FALSE;383}384385// enumerate IPv4 addresses386if (sock >= 0) {387ifs = enumIPv4Interfaces(env, sock, ifs);388close(sock);389390if ((*env)->ExceptionOccurred(env)) {391goto cleanup;392}393}394if (find_bound_interface(env, ifs, iaObj, family) != NULL)395bound = JNI_TRUE;396} else if (ipv6_available()) {397// If IPv6 is available then enumerate IPv6 addresses.398// User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,399// so we have to call ipv6_available()400sock = openSocket(env, AF_INET6);401if (sock < 0) {402return JNI_FALSE;403}404405ifs = enumIPv6Interfaces(env, sock, ifs);406close(sock);407408if ((*env)->ExceptionOccurred(env)) {409goto cleanup;410}411412if (find_bound_interface(env, ifs, iaObj, family) != NULL)413bound = JNI_TRUE;414}415416cleanup:417freeif(ifs);418419return bound;420}421422/*423* Class: java_net_NetworkInterface424* Method: getByInetAddress0425* Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;426*/427JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0428(JNIEnv *env, jclass cls, jobject iaObj)429{430netif *ifs, *curr;431jobject obj = NULL;432int family = getInetAddress_family(env, iaObj);433JNU_CHECK_EXCEPTION_RETURN(env, NULL);434435if (family == java_net_InetAddress_IPv4) {436family = AF_INET;437} else if (family == java_net_InetAddress_IPv6) {438family = AF_INET6;439} else {440return NULL; // Invalid family441}442ifs = enumInterfaces(env);443if (ifs == NULL) {444return NULL;445}446447curr = find_bound_interface(env, ifs, iaObj, family);448449// if found create a NetworkInterface450if (curr != NULL) {451obj = createNetworkInterface(env, curr);452}453454// release the interface list455freeif(ifs);456457return obj;458}459460/*461* Class: java_net_NetworkInterface462* Method: getAll463* Signature: ()[Ljava/net/NetworkInterface;464*/465JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll466(JNIEnv *env, jclass cls)467{468netif *ifs, *curr;469jobjectArray netIFArr;470jint arr_index, ifCount;471472ifs = enumInterfaces(env);473if (ifs == NULL) {474return NULL;475}476477// count the interfaces478ifCount = 0;479curr = ifs;480while (curr != NULL) {481ifCount++;482curr = curr->next;483}484485// allocate a NetworkInterface array486netIFArr = (*env)->NewObjectArray(env, ifCount, cls, NULL);487if (netIFArr == NULL) {488freeif(ifs);489return NULL;490}491492// iterate through the interfaces, create a NetworkInterface instance493// for each array element and populate the object494curr = ifs;495arr_index = 0;496while (curr != NULL) {497jobject netifObj;498499netifObj = createNetworkInterface(env, curr);500if (netifObj == NULL) {501freeif(ifs);502return NULL;503}504505// put the NetworkInterface into the array506(*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);507(*env)->DeleteLocalRef(env, netifObj);508509curr = curr->next;510}511512// release the interface list513freeif(ifs);514515return netIFArr;516}517518/*519* Class: java_net_NetworkInterface520* Method: isUp0521* Signature: (Ljava/lang/String;I)Z522*/523JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0524(JNIEnv *env, jclass cls, jstring name, jint index)525{526int ret = getFlags0(env, name);527return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE : JNI_FALSE;528}529530/*531* Class: java_net_NetworkInterface532* Method: isP2P0533* Signature: (Ljava/lang/String;I)Z534*/535JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0536(JNIEnv *env, jclass cls, jstring name, jint index)537{538int ret = getFlags0(env, name);539return (ret & IFF_POINTOPOINT) ? JNI_TRUE : JNI_FALSE;540}541542/*543* Class: java_net_NetworkInterface544* Method: isLoopback0545* Signature: (Ljava/lang/String;I)Z546*/547JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0548(JNIEnv *env, jclass cls, jstring name, jint index)549{550int ret = getFlags0(env, name);551return (ret & IFF_LOOPBACK) ? JNI_TRUE : JNI_FALSE;552}553554/*555* Class: java_net_NetworkInterface556* Method: supportsMulticast0557* Signature: (Ljava/lang/String;I)Z558*/559JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0560(JNIEnv *env, jclass cls, jstring name, jint index)561{562int ret = getFlags0(env, name);563return (ret & IFF_MULTICAST) ? JNI_TRUE : JNI_FALSE;564}565566/*567* Class: java_net_NetworkInterface568* Method: getMacAddr0569* Signature: ([bLjava/lang/String;I)[b570*/571JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0572(JNIEnv *env, jclass cls, jbyteArray addrArray, jstring name, jint index)573{574jint addr;575jbyte caddr[4];576struct in_addr iaddr;577jbyteArray ret = NULL;578unsigned char mac[16];579int len;580jboolean isCopy;581const char *name_utf;582583if (name != NULL) {584name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);585} else {586JNU_ThrowNullPointerException(env, "network interface name is NULL");587return NULL;588}589590if (name_utf == NULL) {591if (!(*env)->ExceptionCheck(env))592JNU_ThrowOutOfMemoryError(env, NULL);593return NULL;594}595596if (!IS_NULL(addrArray)) {597(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);598addr = ((caddr[0]<<24) & 0xff000000);599addr |= ((caddr[1] <<16) & 0xff0000);600addr |= ((caddr[2] <<8) & 0xff00);601addr |= (caddr[3] & 0xff);602iaddr.s_addr = htonl(addr);603len = getMacAddress(env, name_utf, &iaddr, mac);604} else {605len = getMacAddress(env, name_utf, NULL, mac);606}607608if (len > 0) {609ret = (*env)->NewByteArray(env, len);610if (!IS_NULL(ret)) {611(*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *)(mac));612}613}614615// release the UTF string and interface list616(*env)->ReleaseStringUTFChars(env, name, name_utf);617618return ret;619}620621/*622* Class: java_net_NetworkInterface623* Method: getMTU0624* Signature: ([bLjava/lang/String;I)I625*/626JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0627(JNIEnv *env, jclass cls, jstring name, jint index)628{629jboolean isCopy;630int sock, ret = -1;631const char* name_utf = NULL;632633if (name != NULL) {634name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);635} else {636JNU_ThrowNullPointerException(env, "network interface name is NULL");637return ret;638}639640if (name_utf == NULL) {641if (!(*env)->ExceptionCheck(env))642JNU_ThrowOutOfMemoryError(env, NULL);643return ret;644}645646if ((sock = openSocketWithFallback(env, name_utf)) < 0) {647(*env)->ReleaseStringUTFChars(env, name, name_utf);648return JNI_FALSE;649}650651ret = getMTU(env, sock, name_utf);652653(*env)->ReleaseStringUTFChars(env, name, name_utf);654655close(sock);656return ret;657}658659/*** Private methods definitions ****/660661static int getFlags0(JNIEnv *env, jstring name) {662jboolean isCopy;663int ret, sock, flags = 0;664const char *name_utf;665666if (name != NULL) {667name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);668} else {669JNU_ThrowNullPointerException(env, "network interface name is NULL");670return -1;671}672673if (name_utf == NULL) {674if (!(*env)->ExceptionCheck(env))675JNU_ThrowOutOfMemoryError(env, NULL);676return -1;677}678if ((sock = openSocketWithFallback(env, name_utf)) < 0) {679(*env)->ReleaseStringUTFChars(env, name, name_utf);680return -1;681}682683ret = getFlags(sock, name_utf, &flags);684685close(sock);686(*env)->ReleaseStringUTFChars(env, name, name_utf);687688if (ret < 0) {689JNU_ThrowByNameWithMessageAndLastError690(env, JNU_JAVANETPKG "SocketException", "getFlags() failed");691return -1;692}693694return flags;695}696697/*698* Creates a NetworkInterface object, populates the name, the index, and699* populates the InetAddress array based on the IP addresses for this700* interface.701*/702static jobject createNetworkInterface(JNIEnv *env, netif *ifs) {703jobject netifObj;704jobject name;705jobjectArray addrArr;706jobjectArray bindArr;707jobjectArray childArr;708netaddr *addrs;709jint addr_index, addr_count, bind_index;710jint child_count, child_index;711netaddr *addrP;712netif *childP;713jobject tmp;714715// create a NetworkInterface object and populate it716netifObj = (*env)->NewObject(env, ni_class, ni_ctrID);717CHECK_NULL_RETURN(netifObj, NULL);718name = (*env)->NewStringUTF(env, ifs->name);719CHECK_NULL_RETURN(name, NULL);720(*env)->SetObjectField(env, netifObj, ni_nameID, name);721(*env)->SetObjectField(env, netifObj, ni_descID, name);722(*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);723(*env)->SetBooleanField(env, netifObj, ni_virutalID,724ifs->virtual ? JNI_TRUE : JNI_FALSE);725726// count the number of addresses on this interface727addr_count = 0;728addrP = ifs->addr;729while (addrP != NULL) {730addr_count++;731addrP = addrP->next;732}733734// create the array of InetAddresses735addrArr = (*env)->NewObjectArray(env, addr_count, ia_class, NULL);736if (addrArr == NULL) {737return NULL;738}739740bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL);741if (bindArr == NULL) {742return NULL;743}744addrP = ifs->addr;745addr_index = 0;746bind_index = 0;747while (addrP != NULL) {748jobject iaObj = NULL;749jobject ibObj = NULL;750751if (addrP->family == AF_INET) {752iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);753if (iaObj) {754setInetAddress_addr(env, iaObj, htonl(755((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr));756JNU_CHECK_EXCEPTION_RETURN(env, NULL);757} else {758return NULL;759}760ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);761if (ibObj) {762(*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);763if (addrP->brdcast) {764jobject ia2Obj = NULL;765ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID);766if (ia2Obj) {767setInetAddress_addr(env, ia2Obj, htonl(768((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr));769JNU_CHECK_EXCEPTION_RETURN(env, NULL);770(*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj);771(*env)->DeleteLocalRef(env, ia2Obj);772} else {773return NULL;774}775}776(*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);777(*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);778(*env)->DeleteLocalRef(env, ibObj);779} else {780return NULL;781}782}783if (addrP->family == AF_INET6) {784int scope=0;785iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);786if (iaObj) {787jboolean ret = setInet6Address_ipaddress(env, iaObj,788(char *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr));789if (ret == JNI_FALSE) {790return NULL;791}792793scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;794795if (scope != 0) { /* zero is default value, no need to set */796setInet6Address_scopeid(env, iaObj, scope);797setInet6Address_scopeifname(env, iaObj, netifObj);798}799} else {800return NULL;801}802ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);803if (ibObj) {804(*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);805(*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);806(*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);807(*env)->DeleteLocalRef(env, ibObj);808} else {809return NULL;810}811}812813(*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj);814(*env)->DeleteLocalRef(env, iaObj);815addrP = addrP->next;816}817818// see if there is any virtual interface attached to this one.819child_count = 0;820childP = ifs->childs;821while (childP) {822child_count++;823childP = childP->next;824}825826childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL);827if (childArr == NULL) {828return NULL;829}830831// create the NetworkInterface instances for the sub-interfaces as well832child_index = 0;833childP = ifs->childs;834while(childP) {835tmp = createNetworkInterface(env, childP);836if (tmp == NULL) {837return NULL;838}839(*env)->SetObjectField(env, tmp, ni_parentID, netifObj);840(*env)->SetObjectArrayElement(env, childArr, child_index++, tmp);841childP = childP->next;842}843(*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);844(*env)->SetObjectField(env, netifObj, ni_bindsID, bindArr);845(*env)->SetObjectField(env, netifObj, ni_childsID, childArr);846847(*env)->DeleteLocalRef(env, name);848(*env)->DeleteLocalRef(env, addrArr);849(*env)->DeleteLocalRef(env, bindArr);850(*env)->DeleteLocalRef(env, childArr);851852// return the NetworkInterface853return netifObj;854}855856/*857* Enumerates all interfaces858*/859static netif *enumInterfaces(JNIEnv *env) {860netif *ifs = NULL;861int sock;862863sock = openSocket(env, AF_INET);864if (sock < 0 && (*env)->ExceptionOccurred(env)) {865return NULL;866}867868// enumerate IPv4 addresses869if (sock >= 0) {870ifs = enumIPv4Interfaces(env, sock, ifs);871close(sock);872873if ((*env)->ExceptionOccurred(env)) {874freeif(ifs);875return NULL;876}877}878879// If IPv6 is available then enumerate IPv6 addresses.880// User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,881// so we have to call ipv6_available()882if (ipv6_available()) {883sock = openSocket(env, AF_INET6);884if (sock < 0) {885freeif(ifs);886return NULL;887}888889ifs = enumIPv6Interfaces(env, sock, ifs);890close(sock);891892if ((*env)->ExceptionOccurred(env)) {893freeif(ifs);894return NULL;895}896}897898return ifs;899}900901/*902* Frees an interface list (including any attached addresses).903*/904static void freeif(netif *ifs) {905netif *currif = ifs;906netif *child = NULL;907908while (currif != NULL) {909netaddr *addrP = currif->addr;910while (addrP != NULL) {911netaddr *next = addrP->next;912free(addrP);913addrP = next;914}915916// don't forget to free the sub-interfaces917if (currif->childs != NULL) {918freeif(currif->childs);919}920921ifs = currif->next;922free(currif);923currif = ifs;924}925}926927static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,928struct sockaddr *ifr_addrP,929struct sockaddr *ifr_broadaddrP,930int family, short prefix)931{932netif *currif = ifs, *parent;933netaddr *addrP;934char name[IFNAMESIZE], vname[IFNAMESIZE];935char *name_colonP;936int isVirtual = 0;937int addr_size;938939// If the interface name is a logical interface then we remove the unit940// number so that we have the physical interface (eg: hme0:1 -> hme0).941// NetworkInterface currently doesn't have any concept of physical vs.942// logical interfaces.943strncpy(name, if_name, IFNAMESIZE);944name[IFNAMESIZE - 1] = '\0';945*vname = 0;946947// Create and populate the netaddr node. If allocation fails948// return an un-updated list.949950// Allocate for addr and brdcast at once951952addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in)953: sizeof(struct sockaddr_in6);954955CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr) + 2 * addr_size);956addrP->addr = (struct sockaddr *)((char *)addrP + sizeof(netaddr));957memcpy(addrP->addr, ifr_addrP, addr_size);958959addrP->family = family;960addrP->mask = prefix;961addrP->next = 0;962963// for IPv4 add broadcast address964if (family == AF_INET && ifr_broadaddrP != NULL) {965addrP->brdcast = (struct sockaddr *)966((char *)addrP + sizeof(netaddr) + addr_size);967memcpy(addrP->brdcast, ifr_broadaddrP, addr_size);968} else {969addrP->brdcast = NULL;970}971972// Deal with virtual interface with colon notation e.g. eth0:1973name_colonP = strchr(name, ':');974if (name_colonP != NULL) {975int flags = 0;976// This is a virtual interface. If we are able to access the parent977// we need to create a new entry if it doesn't exist yet *and* update978// the 'parent' interface with the new records.979*name_colonP = 0;980if (getFlags(sock, name, &flags) < 0 || flags < 0) {981// failed to access parent interface do not create parent.982// We are a virtual interface with no parent.983isVirtual = 1;984*name_colonP = ':';985} else {986// Got access to parent, so create it if necessary.987// Save original name to vname and truncate name by ':'988memcpy(vname, name, sizeof(vname));989vname[name_colonP - name] = ':';990}991}992993// Check if this is a "new" interface. Use the interface name for994// matching because index isn't supported on Solaris 2.6 & 7.995while (currif != NULL) {996if (strcmp(name, currif->name) == 0) {997break;998}999currif = currif->next;1000}10011002// If "new" then create a netif structure and insert it into the list.1003if (currif == NULL) {1004CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE);1005currif->name = (char *)currif + sizeof(netif);1006strncpy(currif->name, name, IFNAMESIZE);1007currif->name[IFNAMESIZE - 1] = '\0';1008currif->index = getIndex(sock, name);1009currif->addr = NULL;1010currif->childs = NULL;1011currif->virtual = isVirtual;1012currif->next = ifs;1013ifs = currif;1014}10151016// Finally insert the address on the interface1017addrP->next = currif->addr;1018currif->addr = addrP;10191020parent = currif;10211022// Deal with the virtual interface now.1023if (vname[0]) {1024netaddr *tmpaddr;10251026currif = parent->childs;10271028while (currif != NULL) {1029if (strcmp(vname, currif->name) == 0) {1030break;1031}1032currif = currif->next;1033}10341035if (currif == NULL) {1036CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE);1037currif->name = (char *)currif + sizeof(netif);1038strncpy(currif->name, vname, IFNAMESIZE);1039currif->name[IFNAMESIZE - 1] = '\0';1040currif->index = getIndex(sock, vname);1041currif->addr = NULL; // Need to duplicate the addr entry?1042currif->virtual = 1;1043currif->childs = NULL;1044currif->next = parent->childs;1045parent->childs = currif;1046}10471048CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr) + 2 * addr_size);1049memcpy(tmpaddr, addrP, sizeof(netaddr));1050if (addrP->addr != NULL) {1051tmpaddr->addr = (struct sockaddr *)1052((char*)tmpaddr + sizeof(netaddr));1053memcpy(tmpaddr->addr, addrP->addr, addr_size);1054}10551056if (addrP->brdcast != NULL) {1057tmpaddr->brdcast = (struct sockaddr *)1058((char *)tmpaddr + sizeof(netaddr) + addr_size);1059memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size);1060}10611062tmpaddr->next = currif->addr;1063currif->addr = tmpaddr;1064}10651066return ifs;1067}10681069/*1070* Determines the prefix value for an AF_INET subnet address.1071*/1072static short translateIPv4AddressToPrefix(struct sockaddr_in *addr) {1073short prefix = 0;1074unsigned int mask;1075if (addr == NULL) {1076return 0;1077}1078mask = ntohl(addr->sin_addr.s_addr);1079while (mask) {1080mask <<= 1;1081prefix++;1082}1083return prefix;1084}10851086/*1087* Determines the prefix value for an AF_INET6 subnet address.1088*/1089static short translateIPv6AddressToPrefix(struct sockaddr_in6 *addr) {1090short prefix = 0;1091u_char *addrBytes;1092if (addr == NULL) {1093return 0;1094}1095addrBytes = (u_char *)&(addr->sin6_addr);1096unsigned int byte, bit;10971098for (byte = 0; byte < sizeof(struct in6_addr); byte++, prefix += 8) {1099if (addrBytes[byte] != 0xff) {1100break;1101}1102}1103if (byte != sizeof(struct in6_addr)) {1104for (bit = 7; bit != 0; bit--, prefix++) {1105if (!(addrBytes[byte] & (1 << bit))) {1106break;1107}1108}1109for (; bit != 0; bit--) {1110if (addrBytes[byte] & (1 << bit)) {1111prefix = 0;1112break;1113}1114}1115if (prefix > 0) {1116byte++;1117for (; byte < sizeof(struct in6_addr); byte++) {1118if (addrBytes[byte]) {1119prefix = 0;1120}1121}1122}1123}11241125return prefix;1126}11271128/*1129* Opens a socket for further ioct calls. proto is one of AF_INET or AF_INET6.1130*/1131static int openSocket(JNIEnv *env, int proto) {1132int sock;11331134if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) {1135// If we lack support for this address family or protocol,1136// don't throw an exception.1137if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT) {1138JNU_ThrowByNameWithMessageAndLastError1139(env, JNU_JAVANETPKG "SocketException", "Socket creation failed");1140}1141return -1;1142}11431144return sock;1145}11461147/** Linux **/1148#if defined(__linux__)11491150/*1151* Opens a socket for further ioctl calls. Tries AF_INET socket first and1152* if it fails return AF_INET6 socket.1153*/1154static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1155int sock;11561157if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {1158if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {1159if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {1160JNU_ThrowByNameWithMessageAndLastError1161(env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");1162return -1;1163}1164} else { // errno is not NOSUPPORT1165JNU_ThrowByNameWithMessageAndLastError1166(env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");1167return -1;1168}1169}11701171// Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or1172// IPv6 socket regardless of type of address of an interface.1173return sock;1174}11751176/*1177* Enumerates and returns all IPv4 interfaces on Linux.1178*/1179static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {1180struct ifconf ifc;1181struct ifreq *ifreqP;1182char *buf = NULL;1183unsigned i;11841185// do a dummy SIOCGIFCONF to determine the buffer size1186// SIOCGIFCOUNT doesn't work1187ifc.ifc_buf = NULL;1188if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {1189JNU_ThrowByNameWithMessageAndLastError1190(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");1191return ifs;1192}11931194// call SIOCGIFCONF to enumerate the interfaces1195CHECKED_MALLOC3(buf, char *, ifc.ifc_len);1196ifc.ifc_buf = buf;1197if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {1198JNU_ThrowByNameWithMessageAndLastError1199(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");1200free(buf);1201return ifs;1202}12031204// iterate through each interface1205ifreqP = ifc.ifc_req;1206for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {1207struct sockaddr addr, broadaddr, *broadaddrP = NULL;1208short prefix = 0;12091210// ignore non IPv4 addresses1211if (ifreqP->ifr_addr.sa_family != AF_INET) {1212continue;1213}12141215// save socket address1216memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));12171218// determine broadcast address, if applicable1219if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&1220ifreqP->ifr_flags & IFF_BROADCAST) {12211222// restore socket address to ifreqP1223memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));12241225if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {1226memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),1227sizeof(struct sockaddr));1228broadaddrP = &broadaddr;1229}1230}12311232// restore socket address to ifreqP1233memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));12341235// determine netmask1236if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {1237prefix = translateIPv4AddressToPrefix(1238(struct sockaddr_in *)&(ifreqP->ifr_netmask));1239}12401241// add interface to the list1242ifs = addif(env, sock, ifreqP->ifr_name, ifs,1243&addr, broadaddrP, AF_INET, prefix);12441245// in case of exception, free interface list and buffer and return NULL1246if ((*env)->ExceptionOccurred(env)) {1247free(buf);1248freeif(ifs);1249return NULL;1250}1251}12521253// free buffer1254free(buf);1255return ifs;1256}12571258/*1259* Enumerates and returns all IPv6 interfaces on Linux.1260*/1261static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {1262FILE *f;1263char devname[21], addr6p[8][5];1264int prefix, scope, dad_status, if_idx;12651266if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {1267while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",1268addr6p[0], addr6p[1], addr6p[2], addr6p[3],1269addr6p[4], addr6p[5], addr6p[6], addr6p[7],1270&if_idx, &prefix, &scope, &dad_status, devname) != EOF) {12711272char addr6[40];1273struct sockaddr_in6 addr;12741275sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",1276addr6p[0], addr6p[1], addr6p[2], addr6p[3],1277addr6p[4], addr6p[5], addr6p[6], addr6p[7]);12781279memset(&addr, 0, sizeof(struct sockaddr_in6));1280inet_pton(AF_INET6, addr6, (void*)addr.sin6_addr.s6_addr);12811282// set scope ID to interface index1283addr.sin6_scope_id = if_idx;12841285// add interface to the list1286ifs = addif(env, sock, devname, ifs, (struct sockaddr *)&addr,1287NULL, AF_INET6, (short)prefix);12881289// if an exception occurred then return the list as is1290if ((*env)->ExceptionOccurred(env)) {1291break;1292}1293}1294fclose(f);1295}1296return ifs;1297}12981299/*1300* Try to get the interface index.1301*/1302static int getIndex(int sock, const char *name) {1303struct ifreq if2;1304memset((char *)&if2, 0, sizeof(if2));1305strncpy(if2.ifr_name, name, sizeof(if2.ifr_name));1306if2.ifr_name[sizeof(if2.ifr_name) - 1] = 0;13071308if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {1309return -1;1310}13111312return if2.ifr_ifindex;1313}13141315/*1316* Gets the Hardware address (usually MAC address) for the named interface.1317* On return puts the data in buf, and returns the length, in byte, of the1318* MAC address. Returns -1 if there is no hardware address on that interface.1319*/1320static int getMacAddress1321(JNIEnv *env, const char *ifname, const struct in_addr *addr,1322unsigned char *buf)1323{1324struct ifreq ifr;1325int i, sock;13261327if ((sock = openSocketWithFallback(env, ifname)) < 0) {1328return -1;1329}13301331memset((char *)&ifr, 0, sizeof(ifr));1332strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);1333if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {1334JNU_ThrowByNameWithMessageAndLastError1335(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFHWADDR) failed");1336close(sock);1337return -1;1338}13391340close(sock);1341memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);13421343// all bytes to 0 means no hardware address1344for (i = 0; i < IFHWADDRLEN; i++) {1345if (buf[i] != 0)1346return IFHWADDRLEN;1347}13481349return -1;1350}13511352static int getMTU(JNIEnv *env, int sock, const char *ifname) {1353struct ifreq if2;1354memset((char *)&if2, 0, sizeof(if2));1355strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);13561357if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {1358JNU_ThrowByNameWithMessageAndLastError1359(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");1360return -1;1361}13621363return if2.ifr_mtu;1364}13651366static int getFlags(int sock, const char *ifname, int *flags) {1367struct ifreq if2;1368memset((char *)&if2, 0, sizeof(if2));1369strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name));1370if2.ifr_name[sizeof(if2.ifr_name) - 1] = 0;13711372if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {1373return -1;1374}13751376if (sizeof(if2.ifr_flags) == sizeof(short)) {1377*flags = (if2.ifr_flags & 0xffff);1378} else {1379*flags = if2.ifr_flags;1380}1381return 0;1382}13831384#endif /* __linux__ */13851386/** AIX **/1387#if defined(_AIX)13881389/* seems getkerninfo is guarded by _KERNEL in the system headers */1390/* see net/proto_uipc.h */1391int getkerninfo(int, char *, int *, int32long64_t);13921393/*1394* Opens a socket for further ioctl calls. Tries AF_INET socket first and1395* if it fails return AF_INET6 socket.1396*/1397static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1398int sock;13991400if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {1401if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {1402if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {1403JNU_ThrowByNameWithMessageAndLastError1404(env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");1405return -1;1406}1407} else { // errno is not NOSUPPORT1408JNU_ThrowByNameWithMessageAndLastError1409(env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");1410return -1;1411}1412}14131414return sock;1415}14161417/*1418* Enumerates and returns all IPv4 interfaces on AIX.1419*/1420static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {1421struct ifconf ifc;1422struct ifreq *ifreqP;1423char *buf = NULL;1424unsigned i;14251426// call SIOCGSIZIFCONF to get the size of SIOCGIFCONF buffer1427if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {1428JNU_ThrowByNameWithMessageAndLastError1429(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");1430return ifs;1431}14321433// call CSIOCGIFCONF instead of SIOCGIFCONF where interface1434// records will always have sizeof(struct ifreq) length.1435// Be aware that only IPv4 data is complete this way.1436CHECKED_MALLOC3(buf, char *, ifc.ifc_len);1437ifc.ifc_buf = buf;1438if (ioctl(sock, CSIOCGIFCONF, (char *)&ifc) < 0) {1439JNU_ThrowByNameWithMessageAndLastError1440(env, JNU_JAVANETPKG "SocketException", "ioctl(CSIOCGIFCONF) failed");1441free(buf);1442return ifs;1443}14441445// iterate through each interface1446ifreqP = ifc.ifc_req;1447for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {1448struct sockaddr addr, broadaddr, *broadaddrP = NULL;1449short prefix = 0;14501451// ignore non IPv4 addresses1452if (ifreqP->ifr_addr.sa_family != AF_INET) {1453continue;1454}14551456// save socket address1457memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));14581459// determine broadcast address, if applicable1460if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&1461ifreqP->ifr_flags & IFF_BROADCAST) {14621463// restore socket address to ifreqP1464memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));14651466if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {1467memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),1468sizeof(struct sockaddr));1469broadaddrP = &broadaddr;1470}1471}14721473// restore socket address to ifreqP1474memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));14751476// determine netmask1477if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {1478prefix = translateIPv4AddressToPrefix(1479(struct sockaddr_in *)&(ifreqP->ifr_addr));1480}14811482// add interface to the list1483ifs = addif(env, sock, ifreqP->ifr_name, ifs,1484&addr, broadaddrP, AF_INET, prefix);14851486// in case of exception, free interface list and buffer and return NULL1487if ((*env)->ExceptionOccurred(env)) {1488free(buf);1489freeif(ifs);1490return NULL;1491}1492}14931494// free buffer1495free(buf);1496return ifs;1497}14981499/*1500* Enumerates and returns all IPv6 interfaces on AIX.1501*/1502static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {1503struct ifconf ifc;1504struct ifreq *ifreqP;1505char *buf, *cp, *cplimit;15061507// call SIOCGSIZIFCONF to get size for SIOCGIFCONF buffer1508if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {1509JNU_ThrowByNameWithMessageAndLastError1510(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");1511return ifs;1512}15131514// call SIOCGIFCONF to enumerate the interfaces1515CHECKED_MALLOC3(buf, char *, ifc.ifc_len);1516ifc.ifc_buf = buf;1517if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {1518JNU_ThrowByNameWithMessageAndLastError1519(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");1520free(buf);1521return ifs;1522}15231524// iterate through each interface1525ifreqP = ifc.ifc_req;1526cp = (char *)ifc.ifc_req;1527cplimit = cp + ifc.ifc_len;15281529for (; cp < cplimit;1530cp += (sizeof(ifreqP->ifr_name) +1531MAX((ifreqP->ifr_addr).sa_len, sizeof(ifreqP->ifr_addr))))1532{1533ifreqP = (struct ifreq *)cp;1534short prefix = 0;15351536// ignore non IPv6 addresses1537if (ifreqP->ifr_addr.sa_family != AF_INET6) {1538continue;1539}15401541// determine netmask1542struct in6_ifreq if6;1543memset((char *)&if6, 0, sizeof(if6));1544strncpy(if6.ifr_name, ifreqP->ifr_name, sizeof(if6.ifr_name) - 1);1545memcpy(&(if6.ifr_Addr), &(ifreqP->ifr_addr),1546sizeof(struct sockaddr_in6));1547if (ioctl(sock, SIOCGIFNETMASK6, (char *)&if6) >= 0) {1548prefix = translateIPv6AddressToPrefix(&(if6.ifr_Addr));1549}15501551// set scope ID to interface index1552((struct sockaddr_in6 *)&(ifreqP->ifr_addr))->sin6_scope_id =1553getIndex(sock, ifreqP->ifr_name);15541555// add interface to the list1556ifs = addif(env, sock, ifreqP->ifr_name, ifs,1557(struct sockaddr *)&(ifreqP->ifr_addr),1558NULL, AF_INET6, prefix);15591560// if an exception occurred then free the list1561if ((*env)->ExceptionOccurred(env)) {1562free(buf);1563freeif(ifs);1564return NULL;1565}1566}15671568// free buffer1569free(buf);1570return ifs;1571}15721573/*1574* Try to get the interface index.1575*/1576static int getIndex(int sock, const char *name) {1577int index = if_nametoindex(name);1578return (index == 0) ? -1 : index;1579}15801581/*1582* Gets the Hardware address (usually MAC address) for the named interface.1583* On return puts the data in buf, and returns the length, in byte, of the1584* MAC address. Returns -1 if there is no hardware address on that interface.1585*/1586static int getMacAddress1587(JNIEnv *env, const char *ifname, const struct in_addr *addr,1588unsigned char *buf)1589{1590int size;1591struct kinfo_ndd *nddp;1592void *end;15931594size = getkerninfo(KINFO_NDD, 0, 0, 0);1595if (size == 0) {1596return -1;1597}15981599if (size < 0) {1600perror("getkerninfo 1");1601return -1;1602}16031604nddp = (struct kinfo_ndd *)malloc(size);16051606if (!nddp) {1607JNU_ThrowOutOfMemoryError(env,1608"Network interface getMacAddress native buffer allocation failed");1609return -1;1610}16111612if (getkerninfo(KINFO_NDD, (char*) nddp, &size, 0) < 0) {1613perror("getkerninfo 2");1614free(nddp);1615return -1;1616}16171618end = (void *)nddp + size;1619while ((void *)nddp < end) {1620if (!strcmp(nddp->ndd_alias, ifname) ||1621!strcmp(nddp->ndd_name, ifname)) {1622bcopy(nddp->ndd_addr, buf, 6);1623free(nddp);1624return 6;1625} else {1626nddp++;1627}1628}16291630free(nddp);1631return -1;1632}16331634static int getMTU(JNIEnv *env, int sock, const char *ifname) {1635struct ifreq if2;1636memset((char *)&if2, 0, sizeof(if2));1637strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);16381639if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {1640JNU_ThrowByNameWithMessageAndLastError1641(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");1642return -1;1643}16441645return if2.ifr_mtu;1646}16471648static int getFlags(int sock, const char *ifname, int *flags) {1649struct ifreq if2;1650memset((char *)&if2, 0, sizeof(if2));1651strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);16521653if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {1654return -1;1655}16561657if (sizeof(if2.ifr_flags) == sizeof(short)) {1658*flags = (if2.ifr_flags & 0xffff);1659} else {1660*flags = if2.ifr_flags;1661}1662return 0;1663}16641665#endif /* _AIX */16661667/** BSD **/1668#if defined(_ALLBSD_SOURCE)16691670/*1671* Opens a socket for further ioctl calls. Tries AF_INET socket first and1672* if it fails return AF_INET6 socket.1673*/1674static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1675int sock;16761677if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {1678if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {1679if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {1680JNU_ThrowByNameWithMessageAndLastError1681(env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");1682return -1;1683}1684} else { // errno is not NOSUPPORT1685JNU_ThrowByNameWithMessageAndLastError1686(env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");1687return -1;1688}1689}16901691return sock;1692}16931694/*1695* Enumerates and returns all IPv4 interfaces on BSD.1696*/1697static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {1698struct ifaddrs *ifa, *origifa;16991700if (getifaddrs(&origifa) != 0) {1701JNU_ThrowByNameWithMessageAndLastError1702(env, JNU_JAVANETPKG "SocketException", "getifaddrs() failed");1703return ifs;1704}17051706for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {1707struct sockaddr *broadaddrP = NULL;17081709// ignore non IPv4 addresses1710if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)1711continue;17121713// set ifa_broadaddr, if there is one1714if ((ifa->ifa_flags & IFF_POINTOPOINT) == 0 &&1715ifa->ifa_flags & IFF_BROADCAST) {1716broadaddrP = ifa->ifa_dstaddr;1717}17181719// add interface to the list1720ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr,1721broadaddrP, AF_INET,1722translateIPv4AddressToPrefix((struct sockaddr_in *)1723ifa->ifa_netmask));17241725// if an exception occurred then free the list1726if ((*env)->ExceptionOccurred(env)) {1727freeifaddrs(origifa);1728freeif(ifs);1729return NULL;1730}1731}17321733// free ifaddrs buffer1734freeifaddrs(origifa);1735return ifs;1736}17371738/*1739* Enumerates and returns all IPv6 interfaces on BSD.1740*/1741static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {1742struct ifaddrs *ifa, *origifa;17431744if (getifaddrs(&origifa) != 0) {1745JNU_ThrowByNameWithMessageAndLastError1746(env, JNU_JAVANETPKG "SocketException", "getifaddrs() failed");1747return ifs;1748}17491750for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {1751// ignore non IPv6 addresses1752if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET6)1753continue;17541755// set scope ID to interface index1756((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id =1757getIndex(sock, ifa->ifa_name);17581759// add interface to the list1760ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, NULL,1761AF_INET6,1762translateIPv6AddressToPrefix((struct sockaddr_in6 *)1763ifa->ifa_netmask));17641765// if an exception occurred then free the list1766if ((*env)->ExceptionOccurred(env)) {1767freeifaddrs(origifa);1768freeif(ifs);1769return NULL;1770}1771}17721773// free ifaddrs buffer1774freeifaddrs(origifa);1775return ifs;1776}17771778/*1779* Try to get the interface index.1780*/1781static int getIndex(int sock, const char *name) {1782#if !defined(__FreeBSD__)1783int index = if_nametoindex(name);1784return (index == 0) ? -1 : index;1785#else1786struct ifreq if2;1787memset((char *)&if2, 0, sizeof(if2));1788strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);17891790if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {1791return -1;1792}17931794return if2.ifr_index;1795#endif1796}17971798/*1799* Gets the Hardware address (usually MAC address) for the named interface.1800* On return puts the data in buf, and returns the length, in byte, of the1801* MAC address. Returns -1 if there is no hardware address on that interface.1802*/1803static int getMacAddress1804(JNIEnv *env, const char *ifname, const struct in_addr *addr,1805unsigned char *buf)1806{1807struct ifaddrs *ifa0, *ifa;1808struct sockaddr *saddr;1809int i;18101811// grab the interface list1812if (!getifaddrs(&ifa0)) {1813// cycle through the interfaces1814for (i = 0, ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next, i++) {1815saddr = ifa->ifa_addr;1816if (saddr != NULL) {1817// link layer contains the MAC address1818if (saddr->sa_family == AF_LINK && !strcmp(ifname, ifa->ifa_name)) {1819struct sockaddr_dl *sadl = (struct sockaddr_dl *) saddr;1820// check the address has the correct length1821if (sadl->sdl_alen == ETHER_ADDR_LEN) {1822memcpy(buf, (sadl->sdl_data + sadl->sdl_nlen), ETHER_ADDR_LEN);1823freeifaddrs(ifa0);1824return ETHER_ADDR_LEN;1825}1826}1827}1828}1829freeifaddrs(ifa0);1830}18311832return -1;1833}18341835static int getMTU(JNIEnv *env, int sock, const char *ifname) {1836struct ifreq if2;1837memset((char *)&if2, 0, sizeof(if2));1838strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);18391840if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {1841JNU_ThrowByNameWithMessageAndLastError1842(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");1843return -1;1844}18451846return if2.ifr_mtu;1847}18481849static int getFlags(int sock, const char *ifname, int *flags) {1850struct ifreq if2;1851memset((char *)&if2, 0, sizeof(if2));1852strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);18531854if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {1855return -1;1856}18571858if (sizeof(if2.ifr_flags) == sizeof(short)) {1859*flags = (if2.ifr_flags & 0xffff);1860} else {1861*flags = if2.ifr_flags;1862}1863return 0;1864}1865#endif /* _ALLBSD_SOURCE */186618671868