1 /*
   2  * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 #include <arpa/inet.h>
  26 #include <errno.h>
  27 #include <net/if.h>
  28 #include <net/if_arp.h>
  29 #include <stdlib.h>
  30 #include <string.h>
  31 #include <sys/ioctl.h>
  32 
  33 #if defined(_AIX)
  34 #include <netinet/in6_var.h>
  35 #include <sys/ndd_var.h>
  36 #include <sys/kinfo.h>
  37 #include <strings.h>
  38 #endif
  39 
  40 #if defined(_ALLBSD_SOURCE)
  41 #include <net/ethernet.h>
  42 #include <net/if_dl.h>
  43 #include <ifaddrs.h>
  44 #endif
  45 
  46 #include "net_util.h"
  47 
  48 #include "java_net_InetAddress.h"
  49 
  50 #if defined(__linux__)
  51     #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
  52 #endif
  53 
  54 #ifdef LIFNAMSIZ
  55     #define IFNAMESIZE LIFNAMSIZ
  56 #else
  57     #define IFNAMESIZE IFNAMSIZ
  58 #endif
  59 
  60 #define CHECKED_MALLOC3(_pointer, _type, _size) \
  61     do { \
  62         _pointer = (_type)malloc(_size); \
  63         if (_pointer == NULL) { \
  64             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \
  65             return ifs; /* return untouched list */ \
  66         } \
  67     } while(0)
  68 
  69 typedef struct _netaddr  {
  70     struct sockaddr *addr;
  71     struct sockaddr *brdcast;
  72     short mask;
  73     int family; /* to make searches simple */
  74     struct _netaddr *next;
  75 } netaddr;
  76 
  77 typedef struct _netif {
  78     char *name;
  79     int index;
  80     char virtual;
  81     netaddr *addr;
  82     struct _netif *childs;
  83     struct _netif *next;
  84 } netif;
  85 
  86 /************************************************************************
  87  * NetworkInterface
  88  */
  89 
  90 #include "java_net_NetworkInterface.h"
  91 
  92 /************************************************************************
  93  * NetworkInterface
  94  */
  95 jclass ni_class;
  96 jfieldID ni_nameID;
  97 jfieldID ni_indexID;
  98 jfieldID ni_descID;
  99 jfieldID ni_addrsID;
 100 jfieldID ni_bindsID;
 101 jfieldID ni_virutalID;
 102 jfieldID ni_childsID;
 103 jfieldID ni_parentID;
 104 jfieldID ni_defaultIndexID;
 105 jmethodID ni_ctrID;
 106 
 107 static jclass ni_ibcls;
 108 static jmethodID ni_ibctrID;
 109 static jfieldID ni_ibaddressID;
 110 static jfieldID ni_ib4broadcastID;
 111 static jfieldID ni_ib4maskID;
 112 
 113 /** Private methods declarations **/
 114 static jobject createNetworkInterface(JNIEnv *env, netif *ifs);
 115 static int     getFlags0(JNIEnv *env, jstring  ifname);
 116 
 117 static netif  *enumInterfaces(JNIEnv *env);
 118 static netif  *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs);
 119 static netif  *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs);
 120 
 121 static netif  *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,
 122                      struct sockaddr *ifr_addrP,
 123                      struct sockaddr *ifr_broadaddrP,
 124                      int family, short prefix);
 125 static void    freeif(netif *ifs);
 126 
 127 static int     openSocket(JNIEnv *env, int proto);
 128 static int     openSocketWithFallback(JNIEnv *env, const char *ifname);
 129 
 130 static short   translateIPv4AddressToPrefix(struct sockaddr_in *addr);
 131 static short   translateIPv6AddressToPrefix(struct sockaddr_in6 *addr);
 132 
 133 static int     getIndex(int sock, const char *ifname);
 134 static int     getFlags(int sock, const char *ifname, int *flags);
 135 static int     getMacAddress(JNIEnv *env, const char *ifname,
 136                              const struct in_addr *addr, unsigned char *buf);
 137 static int     getMTU(JNIEnv *env, int sock, const char *ifname);
 138 
 139 /******************* Java entry points *****************************/
 140 
 141 /*
 142  * Class:     java_net_NetworkInterface
 143  * Method:    init
 144  * Signature: ()V
 145  */
 146 JNIEXPORT void JNICALL Java_java_net_NetworkInterface_init
 147   (JNIEnv *env, jclass cls)
 148 {
 149     ni_class = (*env)->FindClass(env, "java/net/NetworkInterface");
 150     CHECK_NULL(ni_class);
 151     ni_class = (*env)->NewGlobalRef(env, ni_class);
 152     CHECK_NULL(ni_class);
 153     ni_nameID = (*env)->GetFieldID(env, ni_class, "name", "Ljava/lang/String;");
 154     CHECK_NULL(ni_nameID);
 155     ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
 156     CHECK_NULL(ni_indexID);
 157     ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs",
 158                                     "[Ljava/net/InetAddress;");
 159     CHECK_NULL(ni_addrsID);
 160     ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings",
 161                                     "[Ljava/net/InterfaceAddress;");
 162     CHECK_NULL(ni_bindsID);
 163     ni_descID = (*env)->GetFieldID(env, ni_class, "displayName",
 164                                    "Ljava/lang/String;");
 165     CHECK_NULL(ni_descID);
 166     ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z");
 167     CHECK_NULL(ni_virutalID);
 168     ni_childsID = (*env)->GetFieldID(env, ni_class, "childs",
 169                                      "[Ljava/net/NetworkInterface;");
 170     CHECK_NULL(ni_childsID);
 171     ni_parentID = (*env)->GetFieldID(env, ni_class, "parent",
 172                                      "Ljava/net/NetworkInterface;");
 173     CHECK_NULL(ni_parentID);
 174     ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
 175     CHECK_NULL(ni_ctrID);
 176     ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
 177     CHECK_NULL(ni_ibcls);
 178     ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
 179     CHECK_NULL(ni_ibcls);
 180     ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
 181     CHECK_NULL(ni_ibctrID);
 182     ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address",
 183                                         "Ljava/net/InetAddress;");
 184     CHECK_NULL(ni_ibaddressID);
 185     ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast",
 186                                            "Ljava/net/Inet4Address;");
 187     CHECK_NULL(ni_ib4broadcastID);
 188     ni_ib4maskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
 189     CHECK_NULL(ni_ib4maskID);
 190     ni_defaultIndexID = (*env)->GetStaticFieldID(env, ni_class, "defaultIndex",
 191                                                  "I");
 192     CHECK_NULL(ni_defaultIndexID);
 193     initInetAddressIDs(env);
 194 }
 195 
 196 /*
 197  * Class:     java_net_NetworkInterface
 198  * Method:    getByName0
 199  * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
 200  */
 201 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0
 202   (JNIEnv *env, jclass cls, jstring name)
 203 {
 204     netif *ifs, *curr;
 205     jboolean isCopy;
 206     const char* name_utf;
 207     char *colonP;
 208     char searchName[IFNAMESIZE];
 209     jobject obj = NULL;
 210 
 211     if (name != NULL) {
 212         name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
 213     } else {
 214         JNU_ThrowNullPointerException(env, "network interface name is NULL");
 215         return NULL;
 216     }
 217 
 218     if (name_utf == NULL) {
 219         if (!(*env)->ExceptionCheck(env))
 220             JNU_ThrowOutOfMemoryError(env, NULL);
 221         return NULL;
 222     }
 223 
 224     ifs = enumInterfaces(env);
 225     if (ifs == NULL) {
 226         (*env)->ReleaseStringUTFChars(env, name, name_utf);
 227         return NULL;
 228     }
 229 
 230     // search the list of interfaces based on name,
 231     // if it is virtual sub interface search with parent first.
 232     strncpy(searchName, name_utf, IFNAMESIZE);
 233     searchName[IFNAMESIZE - 1] = '\0';
 234     colonP = strchr(searchName, ':');
 235     if (colonP != NULL) {
 236         *colonP = '\0';
 237     }
 238     curr = ifs;
 239     while (curr != NULL) {
 240         if (strcmp(searchName, curr->name) == 0) {
 241             break;
 242         }
 243         curr = curr->next;
 244     }
 245 
 246     // search the child list
 247     if (colonP != NULL && curr != NULL) {
 248         curr = curr->childs;
 249         while (curr != NULL) {
 250             if (strcmp(name_utf, curr->name) == 0) {
 251                 break;
 252             }
 253             curr = curr->next;
 254         }
 255     }
 256 
 257     // if found create a NetworkInterface
 258     if (curr != NULL) {
 259         obj = createNetworkInterface(env, curr);
 260     }
 261 
 262     // release the UTF string and interface list
 263     (*env)->ReleaseStringUTFChars(env, name, name_utf);
 264     freeif(ifs);
 265 
 266     return obj;
 267 }
 268 
 269 /*
 270  * Class:     java_net_NetworkInterface
 271  * Method:    getByIndex0
 272  * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
 273  */
 274 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0
 275   (JNIEnv *env, jclass cls, jint index)
 276 {
 277     netif *ifs, *curr;
 278     jobject obj = NULL;
 279 
 280     if (index <= 0) {
 281         return NULL;
 282     }
 283 
 284     ifs = enumInterfaces(env);
 285     if (ifs == NULL) {
 286         return NULL;
 287     }
 288 
 289     // search the list of interfaces based on index
 290     curr = ifs;
 291     while (curr != NULL) {
 292         if (index == curr->index) {
 293             break;
 294         }
 295         curr = curr->next;
 296     }
 297 
 298     // if found create a NetworkInterface
 299     if (curr != NULL) {
 300         obj = createNetworkInterface(env, curr);
 301     }
 302 
 303     // release the interface list
 304     freeif(ifs);
 305 
 306     return obj;
 307 }
 308 
 309 // Return the interface in ifs that iaObj is bound to, if any - otherwise NULL
 310 static netif* find_bound_interface(JNIEnv *env, netif* ifs, jobject iaObj, int family) {
 311     netif* curr = ifs;
 312     while (curr != NULL) {
 313         netaddr *addrP = curr->addr;
 314 
 315         // iterate through each address on the interface
 316         while (addrP != NULL) {
 317 
 318             if (family == addrP->family) {
 319                 if (family == AF_INET) {
 320                     int address1 = htonl(
 321                         ((struct sockaddr_in *)addrP->addr)->sin_addr.s_addr);
 322                     int address2 = getInetAddress_addr(env, iaObj);
 323                     if ((*env)->ExceptionCheck(env)) {
 324                         return NULL;
 325                     }
 326                     if (address1 == address2) {
 327                         return curr;
 328                     }
 329                 } else if (family == AF_INET6) {
 330                     jbyte *bytes = (jbyte *)&(
 331                         ((struct sockaddr_in6*)addrP->addr)->sin6_addr);
 332                     jbyte caddr[16];
 333                     int i;
 334                     unsigned int scopeid;
 335                     getInet6Address_ipaddress(env, iaObj, (char *)caddr);
 336                     scopeid = (unsigned int)getInet6Address_scopeid(env, iaObj);
 337                     if (scopeid != 0 && scopeid != ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id)
 338                         break;
 339                     i = 0;
 340                     while (i < 16) {
 341                         if (caddr[i] != bytes[i]) {
 342                             break;
 343                         }
 344                         i++;
 345                     }
 346                     if (i >= 16) {
 347                         return curr;
 348                     }
 349                 }
 350             }
 351 
 352             addrP = addrP->next;
 353         }
 354         curr = curr->next;
 355     }
 356 
 357     return NULL;
 358 }
 359 
 360 /*
 361  * Class:     java_net_NetworkInterface
 362  * Method:    boundInetAddress0
 363  * Signature: (Ljava/net/InetAddress;)boundInetAddress;
 364  */
 365 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0
 366     (JNIEnv *env, jclass cls, jobject iaObj)
 367 {
 368     netif *ifs = NULL;
 369     jboolean bound = JNI_FALSE;
 370     int sock;
 371 
 372     int family = getInetAddress_family(env, iaObj);
 373     JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
 374 
 375     if (family == java_net_InetAddress_IPv4) {
 376         family = AF_INET;
 377     } else if (family == java_net_InetAddress_IPv6) {
 378         family = AF_INET6;
 379     } else {
 380         return JNI_FALSE; // Invalid family
 381     }
 382 
 383     if (family == AF_INET) {
 384         sock = openSocket(env, AF_INET);
 385         if (sock < 0 && (*env)->ExceptionOccurred(env)) {
 386             return JNI_FALSE;
 387         }
 388 
 389         // enumerate IPv4 addresses
 390         if (sock >= 0) {
 391             ifs = enumIPv4Interfaces(env, sock, ifs);
 392             close(sock);
 393 
 394             if ((*env)->ExceptionOccurred(env)) {
 395                 goto cleanup;
 396             }
 397         }
 398         if (find_bound_interface(env, ifs, iaObj, family) != NULL)
 399             bound = JNI_TRUE;
 400     } else if (ipv6_available()) {
 401         // If IPv6 is available then enumerate IPv6 addresses.
 402         // User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,
 403         // so we have to call ipv6_available()
 404         sock = openSocket(env, AF_INET6);
 405         if (sock < 0) {
 406             return JNI_FALSE;
 407         }
 408 
 409         ifs = enumIPv6Interfaces(env, sock, ifs);
 410         close(sock);
 411 
 412         if ((*env)->ExceptionOccurred(env)) {
 413             goto cleanup;
 414         }
 415 
 416         if (find_bound_interface(env, ifs, iaObj, family) != NULL)
 417             bound = JNI_TRUE;
 418     }
 419 
 420 cleanup:
 421     freeif(ifs);
 422 
 423     return bound;
 424 }
 425 
 426 /*
 427  * Class:     java_net_NetworkInterface
 428  * Method:    getByInetAddress0
 429  * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
 430  */
 431 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
 432   (JNIEnv *env, jclass cls, jobject iaObj)
 433 {
 434     netif *ifs, *curr;
 435     jobject obj = NULL;
 436     int family = getInetAddress_family(env, iaObj);
 437     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
 438 
 439     if (family == java_net_InetAddress_IPv4) {
 440         family = AF_INET;
 441     } else if (family == java_net_InetAddress_IPv6) {
 442         family = AF_INET6;
 443     } else {
 444         return NULL; // Invalid family
 445     }
 446     ifs = enumInterfaces(env);
 447     if (ifs == NULL) {
 448         return NULL;
 449     }
 450 
 451     curr = find_bound_interface(env, ifs, iaObj, family);
 452 
 453     // if found create a NetworkInterface
 454     if (curr != NULL) {
 455         obj = createNetworkInterface(env, curr);
 456     }
 457 
 458     // release the interface list
 459     freeif(ifs);
 460 
 461     return obj;
 462 }
 463 
 464 /*
 465  * Class:     java_net_NetworkInterface
 466  * Method:    getAll
 467  * Signature: ()[Ljava/net/NetworkInterface;
 468  */
 469 JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll
 470   (JNIEnv *env, jclass cls)
 471 {
 472     netif *ifs, *curr;
 473     jobjectArray netIFArr;
 474     jint arr_index, ifCount;
 475 
 476     ifs = enumInterfaces(env);
 477     if (ifs == NULL) {
 478         return NULL;
 479     }
 480 
 481     // count the interfaces
 482     ifCount = 0;
 483     curr = ifs;
 484     while (curr != NULL) {
 485         ifCount++;
 486         curr = curr->next;
 487     }
 488 
 489     // allocate a NetworkInterface array
 490     netIFArr = (*env)->NewObjectArray(env, ifCount, cls, NULL);
 491     if (netIFArr == NULL) {
 492         freeif(ifs);
 493         return NULL;
 494     }
 495 
 496     // iterate through the interfaces, create a NetworkInterface instance
 497     // for each array element and populate the object
 498     curr = ifs;
 499     arr_index = 0;
 500     while (curr != NULL) {
 501         jobject netifObj;
 502 
 503         netifObj = createNetworkInterface(env, curr);
 504         if (netifObj == NULL) {
 505             freeif(ifs);
 506             return NULL;
 507         }
 508 
 509         // put the NetworkInterface into the array
 510         (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
 511 
 512         curr = curr->next;
 513     }
 514 
 515     // release the interface list
 516     freeif(ifs);
 517 
 518     return netIFArr;
 519 }
 520 
 521 /*
 522  * Class:     java_net_NetworkInterface
 523  * Method:    isUp0
 524  * Signature: (Ljava/lang/String;I)Z
 525  */
 526 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0
 527   (JNIEnv *env, jclass cls, jstring name, jint index)
 528 {
 529     int ret = getFlags0(env, name);
 530     return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE :  JNI_FALSE;
 531 }
 532 
 533 /*
 534  * Class:     java_net_NetworkInterface
 535  * Method:    isP2P0
 536  * Signature: (Ljava/lang/String;I)Z
 537  */
 538 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0
 539   (JNIEnv *env, jclass cls, jstring name, jint index)
 540 {
 541     int ret = getFlags0(env, name);
 542     return (ret & IFF_POINTOPOINT) ? JNI_TRUE :  JNI_FALSE;
 543 }
 544 
 545 /*
 546  * Class:     java_net_NetworkInterface
 547  * Method:    isLoopback0
 548  * Signature: (Ljava/lang/String;I)Z
 549  */
 550 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0
 551   (JNIEnv *env, jclass cls, jstring name, jint index)
 552 {
 553     int ret = getFlags0(env, name);
 554     return (ret & IFF_LOOPBACK) ? JNI_TRUE :  JNI_FALSE;
 555 }
 556 
 557 /*
 558  * Class:     java_net_NetworkInterface
 559  * Method:    supportsMulticast0
 560  * Signature: (Ljava/lang/String;I)Z
 561  */
 562 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0
 563   (JNIEnv *env, jclass cls, jstring name, jint index)
 564 {
 565     int ret = getFlags0(env, name);
 566     return (ret & IFF_MULTICAST) ? JNI_TRUE :  JNI_FALSE;
 567 }
 568 
 569 /*
 570  * Class:     java_net_NetworkInterface
 571  * Method:    getMacAddr0
 572  * Signature: ([bLjava/lang/String;I)[b
 573  */
 574 JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0
 575   (JNIEnv *env, jclass cls, jbyteArray addrArray, jstring name, jint index)
 576 {
 577     jint addr;
 578     jbyte caddr[4];
 579     struct in_addr iaddr;
 580     jbyteArray ret = NULL;
 581     unsigned char mac[16];
 582     int len;
 583     jboolean isCopy;
 584     const char *name_utf;
 585 
 586     if (name != NULL) {
 587         name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
 588     } else {
 589         JNU_ThrowNullPointerException(env, "network interface name is NULL");
 590         return NULL;
 591     }
 592 
 593     if (name_utf == NULL) {
 594         if (!(*env)->ExceptionCheck(env))
 595             JNU_ThrowOutOfMemoryError(env, NULL);
 596         return NULL;
 597     }
 598 
 599     if (!IS_NULL(addrArray)) {
 600         (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
 601         addr = ((caddr[0]<<24) & 0xff000000);
 602         addr |= ((caddr[1] <<16) & 0xff0000);
 603         addr |= ((caddr[2] <<8) & 0xff00);
 604         addr |= (caddr[3] & 0xff);
 605         iaddr.s_addr = htonl(addr);
 606         len = getMacAddress(env, name_utf, &iaddr, mac);
 607     } else {
 608         len = getMacAddress(env, name_utf, NULL, mac);
 609     }
 610 
 611     if (len > 0) {
 612         ret = (*env)->NewByteArray(env, len);
 613         if (!IS_NULL(ret)) {
 614             (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *)(mac));
 615         }
 616     }
 617 
 618     // release the UTF string and interface list
 619     (*env)->ReleaseStringUTFChars(env, name, name_utf);
 620 
 621     return ret;
 622 }
 623 
 624 /*
 625  * Class:       java_net_NetworkInterface
 626  * Method:      getMTU0
 627  * Signature:   ([bLjava/lang/String;I)I
 628  */
 629 JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0
 630   (JNIEnv *env, jclass cls, jstring name, jint index)
 631 {
 632     jboolean isCopy;
 633     int sock, ret = -1;
 634     const char* name_utf = NULL;
 635 
 636     if (name != NULL) {
 637         name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
 638     } else {
 639         JNU_ThrowNullPointerException(env, "network interface name is NULL");
 640         return ret;
 641     }
 642 
 643     if (name_utf == NULL) {
 644         if (!(*env)->ExceptionCheck(env))
 645             JNU_ThrowOutOfMemoryError(env, NULL);
 646         return ret;
 647     }
 648 
 649     if ((sock = openSocketWithFallback(env, name_utf)) < 0) {
 650         (*env)->ReleaseStringUTFChars(env, name, name_utf);
 651         return JNI_FALSE;
 652     }
 653 
 654     ret = getMTU(env, sock, name_utf);
 655 
 656     (*env)->ReleaseStringUTFChars(env, name, name_utf);
 657 
 658     close(sock);
 659     return ret;
 660 }
 661 
 662 /*** Private methods definitions ****/
 663 
 664 static int getFlags0(JNIEnv *env, jstring name) {
 665     jboolean isCopy;
 666     int ret, sock, flags = 0;
 667     const char *name_utf;
 668 
 669     if (name != NULL) {
 670         name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
 671     } else {
 672         JNU_ThrowNullPointerException(env, "network interface name is NULL");
 673         return -1;
 674     }
 675 
 676     if (name_utf == NULL) {
 677         if (!(*env)->ExceptionCheck(env))
 678             JNU_ThrowOutOfMemoryError(env, NULL);
 679         return -1;
 680     }
 681     if ((sock = openSocketWithFallback(env, name_utf)) < 0) {
 682         (*env)->ReleaseStringUTFChars(env, name, name_utf);
 683         return -1;
 684     }
 685 
 686     ret = getFlags(sock, name_utf, &flags);
 687 
 688     close(sock);
 689     (*env)->ReleaseStringUTFChars(env, name, name_utf);
 690 
 691     if (ret < 0) {
 692         JNU_ThrowByNameWithMessageAndLastError
 693             (env, JNU_JAVANETPKG "SocketException", "getFlags() failed");
 694         return -1;
 695     }
 696 
 697     return flags;
 698 }
 699 
 700 /*
 701  * Creates a NetworkInterface object, populates the name, the index, and
 702  * populates the InetAddress array based on the IP addresses for this
 703  * interface.
 704  */
 705 static jobject createNetworkInterface(JNIEnv *env, netif *ifs) {
 706     jobject netifObj;
 707     jobject name;
 708     jobjectArray addrArr;
 709     jobjectArray bindArr;
 710     jobjectArray childArr;
 711     netaddr *addrs;
 712     jint addr_index, addr_count, bind_index;
 713     jint child_count, child_index;
 714     netaddr *addrP;
 715     netif *childP;
 716     jobject tmp;
 717 
 718     // create a NetworkInterface object and populate it
 719     netifObj = (*env)->NewObject(env, ni_class, ni_ctrID);
 720     CHECK_NULL_RETURN(netifObj, NULL);
 721     name = (*env)->NewStringUTF(env, ifs->name);
 722     CHECK_NULL_RETURN(name, NULL);
 723     (*env)->SetObjectField(env, netifObj, ni_nameID, name);
 724     (*env)->SetObjectField(env, netifObj, ni_descID, name);
 725     (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
 726     (*env)->SetBooleanField(env, netifObj, ni_virutalID,
 727                             ifs->virtual ? JNI_TRUE : JNI_FALSE);
 728 
 729     // count the number of addresses on this interface
 730     addr_count = 0;
 731     addrP = ifs->addr;
 732     while (addrP != NULL) {
 733         addr_count++;
 734         addrP = addrP->next;
 735     }
 736 
 737     // create the array of InetAddresses
 738     addrArr = (*env)->NewObjectArray(env, addr_count, ia_class, NULL);
 739     if (addrArr == NULL) {
 740         return NULL;
 741     }
 742 
 743     bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL);
 744     if (bindArr == NULL) {
 745        return NULL;
 746     }
 747     addrP = ifs->addr;
 748     addr_index = 0;
 749     bind_index = 0;
 750     while (addrP != NULL) {
 751         jobject iaObj = NULL;
 752         jobject ibObj = NULL;
 753 
 754         if (addrP->family == AF_INET) {
 755             iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 756             if (iaObj) {
 757                 setInetAddress_addr(env, iaObj, htonl(
 758                     ((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr));
 759                 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
 760             } else {
 761                 return NULL;
 762             }
 763             ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
 764             if (ibObj) {
 765                 (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
 766                 if (addrP->brdcast) {
 767                     jobject ia2Obj = NULL;
 768                     ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 769                     if (ia2Obj) {
 770                         setInetAddress_addr(env, ia2Obj, htonl(
 771                             ((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr));
 772                         JNU_CHECK_EXCEPTION_RETURN(env, NULL);
 773                         (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj);
 774                     } else {
 775                         return NULL;
 776                     }
 777                 }
 778                 (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
 779                 (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
 780             } else {
 781                 return NULL;
 782             }
 783         }
 784         if (addrP->family == AF_INET6) {
 785             int scope=0;
 786             iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
 787             if (iaObj) {
 788                 jboolean ret = setInet6Address_ipaddress(env, iaObj,
 789                     (char *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr));
 790                 if (ret == JNI_FALSE) {
 791                     return NULL;
 792                 }
 793 
 794                 scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;
 795 
 796                 if (scope != 0) { /* zero is default value, no need to set */
 797                     setInet6Address_scopeid(env, iaObj, scope);
 798                     setInet6Address_scopeifname(env, iaObj, netifObj);
 799                 }
 800             } else {
 801                 return NULL;
 802             }
 803             ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
 804             if (ibObj) {
 805                 (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
 806                 (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
 807                 (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
 808             } else {
 809                 return NULL;
 810             }
 811         }
 812 
 813         (*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj);
 814         addrP = addrP->next;
 815     }
 816 
 817     // see if there is any virtual interface attached to this one.
 818     child_count = 0;
 819     childP = ifs->childs;
 820     while (childP) {
 821         child_count++;
 822         childP = childP->next;
 823     }
 824 
 825     childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL);
 826     if (childArr == NULL) {
 827         return NULL;
 828     }
 829 
 830     // create the NetworkInterface instances for the sub-interfaces as well
 831     child_index = 0;
 832     childP = ifs->childs;
 833     while(childP) {
 834         tmp = createNetworkInterface(env, childP);
 835         if (tmp == NULL) {
 836             return NULL;
 837         }
 838         (*env)->SetObjectField(env, tmp, ni_parentID, netifObj);
 839         (*env)->SetObjectArrayElement(env, childArr, child_index++, tmp);
 840         childP = childP->next;
 841     }
 842     (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
 843     (*env)->SetObjectField(env, netifObj, ni_bindsID, bindArr);
 844     (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
 845 
 846     // return the NetworkInterface
 847     return netifObj;
 848 }
 849 
 850 /*
 851  * Enumerates all interfaces
 852  */
 853 static netif *enumInterfaces(JNIEnv *env) {
 854     netif *ifs = NULL;
 855     int sock;
 856 
 857     sock = openSocket(env, AF_INET);
 858     if (sock < 0 && (*env)->ExceptionOccurred(env)) {
 859         return NULL;
 860     }
 861 
 862     // enumerate IPv4 addresses
 863     if (sock >= 0) {
 864         ifs = enumIPv4Interfaces(env, sock, ifs);
 865         close(sock);
 866 
 867         if ((*env)->ExceptionOccurred(env)) {
 868             freeif(ifs);
 869             return NULL;
 870         }
 871     }
 872 
 873     // If IPv6 is available then enumerate IPv6 addresses.
 874     // User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,
 875     // so we have to call ipv6_available()
 876     if (ipv6_available()) {
 877         sock = openSocket(env, AF_INET6);
 878         if (sock < 0) {
 879             freeif(ifs);
 880             return NULL;
 881         }
 882 
 883         ifs = enumIPv6Interfaces(env, sock, ifs);
 884         close(sock);
 885 
 886         if ((*env)->ExceptionOccurred(env)) {
 887             freeif(ifs);
 888             return NULL;
 889         }
 890     }
 891 
 892     return ifs;
 893 }
 894 
 895 /*
 896  * Frees an interface list (including any attached addresses).
 897  */
 898 static void freeif(netif *ifs) {
 899     netif *currif = ifs;
 900     netif *child = NULL;
 901 
 902     while (currif != NULL) {
 903         netaddr *addrP = currif->addr;
 904         while (addrP != NULL) {
 905             netaddr *next = addrP->next;
 906             free(addrP);
 907             addrP = next;
 908         }
 909 
 910         // don't forget to free the sub-interfaces
 911         if (currif->childs != NULL) {
 912             freeif(currif->childs);
 913         }
 914 
 915         ifs = currif->next;
 916         free(currif);
 917         currif = ifs;
 918     }
 919 }
 920 
 921 static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,
 922                     struct sockaddr *ifr_addrP,
 923                     struct sockaddr *ifr_broadaddrP,
 924                     int family, short prefix)
 925 {
 926     netif *currif = ifs, *parent;
 927     netaddr *addrP;
 928     char name[IFNAMESIZE], vname[IFNAMESIZE];
 929     char *name_colonP;
 930     int isVirtual = 0;
 931     int addr_size;
 932 
 933     // If the interface name is a logical interface then we remove the unit
 934     // number so that we have the physical interface (eg: hme0:1 -> hme0).
 935     // NetworkInterface currently doesn't have any concept of physical vs.
 936     // logical interfaces.
 937     strncpy(name, if_name, IFNAMESIZE);
 938     name[IFNAMESIZE - 1] = '\0';
 939     *vname = 0;
 940 
 941     // Create and populate the netaddr node. If allocation fails
 942     // return an un-updated list.
 943 
 944     // Allocate for addr and brdcast at once
 945 
 946     addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in)
 947                                     : sizeof(struct sockaddr_in6);
 948 
 949     CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr) + 2 * addr_size);
 950     addrP->addr = (struct sockaddr *)((char *)addrP + sizeof(netaddr));
 951     memcpy(addrP->addr, ifr_addrP, addr_size);
 952 
 953     addrP->family = family;
 954     addrP->mask = prefix;
 955     addrP->next = 0;
 956 
 957     // for IPv4 add broadcast address
 958     if (family == AF_INET && ifr_broadaddrP != NULL) {
 959         addrP->brdcast = (struct sockaddr *)
 960                              ((char *)addrP + sizeof(netaddr) + addr_size);
 961         memcpy(addrP->brdcast, ifr_broadaddrP, addr_size);
 962     } else {
 963         addrP->brdcast = NULL;
 964     }
 965 
 966     // Deal with virtual interface with colon notation e.g. eth0:1
 967     name_colonP = strchr(name, ':');
 968     if (name_colonP != NULL) {
 969         int flags = 0;
 970         // This is a virtual interface. If we are able to access the parent
 971         // we need to create a new entry if it doesn't exist yet *and* update
 972         // the 'parent' interface with the new records.
 973         *name_colonP = 0;
 974         if (getFlags(sock, name, &flags) < 0 || flags < 0) {
 975             // failed to access parent interface do not create parent.
 976             // We are a virtual interface with no parent.
 977             isVirtual = 1;
 978             *name_colonP = ':';
 979         } else {
 980             // Got access to parent, so create it if necessary.
 981             // Save original name to vname and truncate name by ':'
 982             memcpy(vname, name, sizeof(vname));
 983             vname[name_colonP - name] = ':';
 984         }
 985     }
 986 
 987     // Check if this is a "new" interface. Use the interface name for
 988     // matching because index isn't supported on Solaris 2.6 & 7.
 989     while (currif != NULL) {
 990         if (strcmp(name, currif->name) == 0) {
 991             break;
 992         }
 993         currif = currif->next;
 994     }
 995 
 996     // If "new" then create a netif structure and insert it into the list.
 997     if (currif == NULL) {
 998          CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE);
 999          currif->name = (char *)currif + sizeof(netif);
1000          strncpy(currif->name, name, IFNAMESIZE);
1001          currif->name[IFNAMESIZE - 1] = '\0';
1002          currif->index = getIndex(sock, name);
1003          currif->addr = NULL;
1004          currif->childs = NULL;
1005          currif->virtual = isVirtual;
1006          currif->next = ifs;
1007          ifs = currif;
1008     }
1009 
1010     // Finally insert the address on the interface
1011     addrP->next = currif->addr;
1012     currif->addr = addrP;
1013 
1014     parent = currif;
1015 
1016     // Deal with the virtual interface now.
1017     if (vname[0]) {
1018         netaddr *tmpaddr;
1019 
1020         currif = parent->childs;
1021 
1022         while (currif != NULL) {
1023             if (strcmp(vname, currif->name) == 0) {
1024                 break;
1025             }
1026             currif = currif->next;
1027         }
1028 
1029         if (currif == NULL) {
1030             CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE);
1031             currif->name = (char *)currif + sizeof(netif);
1032             strncpy(currif->name, vname, IFNAMESIZE);
1033             currif->name[IFNAMESIZE - 1] = '\0';
1034             currif->index = getIndex(sock, vname);
1035             currif->addr = NULL; // Need to duplicate the addr entry?
1036             currif->virtual = 1;
1037             currif->childs = NULL;
1038             currif->next = parent->childs;
1039             parent->childs = currif;
1040         }
1041 
1042         CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr) + 2 * addr_size);
1043         memcpy(tmpaddr, addrP, sizeof(netaddr));
1044         if (addrP->addr != NULL) {
1045             tmpaddr->addr = (struct sockaddr *)
1046                 ((char*)tmpaddr + sizeof(netaddr));
1047             memcpy(tmpaddr->addr, addrP->addr, addr_size);
1048         }
1049 
1050         if (addrP->brdcast != NULL) {
1051             tmpaddr->brdcast = (struct sockaddr *)
1052                 ((char *)tmpaddr + sizeof(netaddr) + addr_size);
1053             memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size);
1054         }
1055 
1056         tmpaddr->next = currif->addr;
1057         currif->addr = tmpaddr;
1058     }
1059 
1060     return ifs;
1061 }
1062 
1063 /*
1064  * Determines the prefix value for an AF_INET subnet address.
1065  */
1066 static short translateIPv4AddressToPrefix(struct sockaddr_in *addr) {
1067     short prefix = 0;
1068     unsigned int mask;
1069     if (addr == NULL) {
1070         return 0;
1071     }
1072     mask = ntohl(addr->sin_addr.s_addr);
1073     while (mask) {
1074         mask <<= 1;
1075         prefix++;
1076     }
1077     return prefix;
1078 }
1079 
1080 /*
1081  * Determines the prefix value for an AF_INET6 subnet address.
1082  */
1083 static short translateIPv6AddressToPrefix(struct sockaddr_in6 *addr) {
1084     short prefix = 0;
1085     u_char *addrBytes;
1086     if (addr == NULL) {
1087         return 0;
1088     }
1089     addrBytes = (u_char *)&(addr->sin6_addr);
1090     unsigned int byte, bit;
1091 
1092     for (byte = 0; byte < sizeof(struct in6_addr); byte++, prefix += 8) {
1093         if (addrBytes[byte] != 0xff) {
1094             break;
1095         }
1096     }
1097     if (byte != sizeof(struct in6_addr)) {
1098         for (bit = 7; bit != 0; bit--, prefix++) {
1099             if (!(addrBytes[byte] & (1 << bit))) {
1100                 break;
1101             }
1102         }
1103         for (; bit != 0; bit--) {
1104             if (addrBytes[byte] & (1 << bit)) {
1105                 prefix = 0;
1106                 break;
1107             }
1108         }
1109         if (prefix > 0) {
1110             byte++;
1111             for (; byte < sizeof(struct in6_addr); byte++) {
1112                 if (addrBytes[byte]) {
1113                     prefix = 0;
1114                 }
1115             }
1116         }
1117     }
1118 
1119     return prefix;
1120 }
1121 
1122 /*
1123  * Opens a socket for further ioct calls. proto is one of AF_INET or AF_INET6.
1124  */
1125 static int openSocket(JNIEnv *env, int proto) {
1126     int sock;
1127 
1128     if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) {
1129         // If we lack support for this address family or protocol,
1130         // don't throw an exception.
1131         if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT) {
1132             JNU_ThrowByNameWithMessageAndLastError
1133                 (env, JNU_JAVANETPKG "SocketException", "Socket creation failed");
1134         }
1135         return -1;
1136     }
1137 
1138     return sock;
1139 }
1140 
1141 /** Linux **/
1142 #if defined(__linux__)
1143 
1144 /*
1145  * Opens a socket for further ioctl calls. Tries AF_INET socket first and
1146  * if it fails return AF_INET6 socket.
1147  */
1148 static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
1149     int sock;
1150 
1151     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1152         if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {
1153             if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1154                 JNU_ThrowByNameWithMessageAndLastError
1155                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1156                 return -1;
1157             }
1158         } else { // errno is not NOSUPPORT
1159             JNU_ThrowByNameWithMessageAndLastError
1160                 (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1161             return -1;
1162         }
1163     }
1164 
1165     // Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or
1166     // IPv6 socket regardless of type of address of an interface.
1167     return sock;
1168 }
1169 
1170 /*
1171  * Enumerates and returns all IPv4 interfaces on Linux.
1172  */
1173 static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
1174     struct ifconf ifc;
1175     struct ifreq *ifreqP;
1176     char *buf = NULL;
1177     unsigned i;
1178 
1179     // do a dummy SIOCGIFCONF to determine the buffer size
1180     // SIOCGIFCOUNT doesn't work
1181     ifc.ifc_buf = NULL;
1182     if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1183         JNU_ThrowByNameWithMessageAndLastError
1184             (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");
1185         return ifs;
1186     }
1187 
1188     // call SIOCGIFCONF to enumerate the interfaces
1189     CHECKED_MALLOC3(buf, char *, ifc.ifc_len);
1190     ifc.ifc_buf = buf;
1191     if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1192         JNU_ThrowByNameWithMessageAndLastError
1193             (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");
1194         free(buf);
1195         return ifs;
1196     }
1197 
1198     // iterate through each interface
1199     ifreqP = ifc.ifc_req;
1200     for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {
1201         struct sockaddr addr, broadaddr, *broadaddrP = NULL;
1202         short prefix = 0;
1203 
1204         // ignore non IPv4 addresses
1205         if (ifreqP->ifr_addr.sa_family != AF_INET) {
1206             continue;
1207         }
1208 
1209         // save socket address
1210         memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));
1211 
1212         // determine broadcast address, if applicable
1213         if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&
1214             ifreqP->ifr_flags & IFF_BROADCAST) {
1215 
1216             // restore socket address to ifreqP
1217             memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
1218 
1219             if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {
1220                 memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),
1221                        sizeof(struct sockaddr));
1222                 broadaddrP = &broadaddr;
1223             }
1224         }
1225 
1226         // restore socket address to ifreqP
1227         memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
1228 
1229         // determine netmask
1230         if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {
1231             prefix = translateIPv4AddressToPrefix(
1232                          (struct sockaddr_in *)&(ifreqP->ifr_netmask));
1233         }
1234 
1235         // add interface to the list
1236         ifs = addif(env, sock, ifreqP->ifr_name, ifs,
1237                     &addr, broadaddrP, AF_INET, prefix);
1238 
1239         // in case of exception, free interface list and buffer and return NULL
1240         if ((*env)->ExceptionOccurred(env)) {
1241             free(buf);
1242             freeif(ifs);
1243             return NULL;
1244         }
1245     }
1246 
1247     // free buffer
1248     free(buf);
1249     return ifs;
1250 }
1251 
1252 /*
1253  * Enumerates and returns all IPv6 interfaces on Linux.
1254  */
1255 static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
1256     FILE *f;
1257     char devname[21], addr6p[8][5];
1258     int prefix, scope, dad_status, if_idx;
1259 
1260     if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1261         while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
1262                       addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1263                       addr6p[4], addr6p[5], addr6p[6], addr6p[7],
1264                       &if_idx, &prefix, &scope, &dad_status, devname) != EOF) {
1265 
1266             char addr6[40];
1267             struct sockaddr_in6 addr;
1268 
1269             sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1270                     addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1271                     addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1272 
1273             memset(&addr, 0, sizeof(struct sockaddr_in6));
1274             inet_pton(AF_INET6, addr6, (void*)addr.sin6_addr.s6_addr);
1275 
1276             // set scope ID to interface index
1277             addr.sin6_scope_id = if_idx;
1278 
1279             // add interface to the list
1280             ifs = addif(env, sock, devname, ifs, (struct sockaddr *)&addr,
1281                         NULL, AF_INET6, (short)prefix);
1282 
1283             // if an exception occurred then return the list as is
1284             if ((*env)->ExceptionOccurred(env)) {
1285                 break;
1286             }
1287        }
1288        fclose(f);
1289     }
1290     return ifs;
1291 }
1292 
1293 /*
1294  * Try to get the interface index.
1295  */
1296 static int getIndex(int sock, const char *name) {
1297     struct ifreq if2;
1298     memset((char *)&if2, 0, sizeof(if2));
1299     strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);
1300 
1301     if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
1302         return -1;
1303     }
1304 
1305     return if2.ifr_ifindex;
1306 }
1307 
1308 /*
1309  * Gets the Hardware address (usually MAC address) for the named interface.
1310  * On return puts the data in buf, and returns the length, in byte, of the
1311  * MAC address. Returns -1 if there is no hardware address on that interface.
1312  */
1313 static int getMacAddress
1314   (JNIEnv *env, const char *ifname, const struct in_addr *addr,
1315    unsigned char *buf)
1316 {
1317     struct ifreq ifr;
1318     int i, sock;
1319 
1320     if ((sock = openSocketWithFallback(env, ifname)) < 0) {
1321         return -1;
1322     }
1323 
1324     memset((char *)&ifr, 0, sizeof(ifr));
1325     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
1326     if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
1327         JNU_ThrowByNameWithMessageAndLastError
1328             (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFHWADDR) failed");
1329         close(sock);
1330         return -1;
1331     }
1332 
1333     close(sock);
1334     memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
1335 
1336     // all bytes to 0 means no hardware address
1337     for (i = 0; i < IFHWADDRLEN; i++) {
1338         if (buf[i] != 0)
1339             return IFHWADDRLEN;
1340     }
1341 
1342     return -1;
1343 }
1344 
1345 static int getMTU(JNIEnv *env, int sock, const char *ifname) {
1346     struct ifreq if2;
1347     memset((char *)&if2, 0, sizeof(if2));
1348     strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
1349 
1350     if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
1351         JNU_ThrowByNameWithMessageAndLastError
1352             (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");
1353         return -1;
1354     }
1355 
1356     return if2.ifr_mtu;
1357 }
1358 
1359 static int getFlags(int sock, const char *ifname, int *flags) {
1360     struct ifreq if2;
1361     memset((char *)&if2, 0, sizeof(if2));
1362     strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
1363 
1364     if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
1365         return -1;
1366     }
1367 
1368     if (sizeof(if2.ifr_flags) == sizeof(short)) {
1369         *flags = (if2.ifr_flags & 0xffff);
1370     } else {
1371         *flags = if2.ifr_flags;
1372     }
1373     return 0;
1374 }
1375 
1376 #endif /* __linux__ */
1377 
1378 /** AIX **/
1379 #if defined(_AIX)
1380 
1381 /* seems getkerninfo is guarded by _KERNEL in the system headers */
1382 /* see net/proto_uipc.h */
1383 int getkerninfo(int, char *, int *, int32long64_t);
1384 
1385 /*
1386  * Opens a socket for further ioctl calls. Tries AF_INET socket first and
1387  * if it fails return AF_INET6 socket.
1388  */
1389 static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
1390     int sock;
1391 
1392     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1393         if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {
1394             if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1395                 JNU_ThrowByNameWithMessageAndLastError
1396                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1397                 return -1;
1398             }
1399         } else { // errno is not NOSUPPORT
1400             JNU_ThrowByNameWithMessageAndLastError
1401                 (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1402             return -1;
1403         }
1404     }
1405 
1406     return sock;
1407 }
1408 
1409 /*
1410  * Enumerates and returns all IPv4 interfaces on AIX.
1411  */
1412 static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
1413     struct ifconf ifc;
1414     struct ifreq *ifreqP;
1415     char *buf = NULL;
1416     unsigned i;
1417 
1418     // call SIOCGSIZIFCONF to get the size of SIOCGIFCONF buffer
1419     if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {
1420         JNU_ThrowByNameWithMessageAndLastError
1421             (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");
1422         return ifs;
1423     }
1424 
1425     // call CSIOCGIFCONF instead of SIOCGIFCONF where interface
1426     // records will always have sizeof(struct ifreq) length.
1427     // Be aware that only IPv4 data is complete this way.
1428     CHECKED_MALLOC3(buf, char *, ifc.ifc_len);
1429     ifc.ifc_buf = buf;
1430     if (ioctl(sock, CSIOCGIFCONF, (char *)&ifc) < 0) {
1431         JNU_ThrowByNameWithMessageAndLastError
1432             (env, JNU_JAVANETPKG "SocketException", "ioctl(CSIOCGIFCONF) failed");
1433         free(buf);
1434         return ifs;
1435     }
1436 
1437     // iterate through each interface
1438     ifreqP = ifc.ifc_req;
1439     for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {
1440         struct sockaddr addr, broadaddr, *broadaddrP = NULL;
1441         short prefix = 0;
1442 
1443         // ignore non IPv4 addresses
1444         if (ifreqP->ifr_addr.sa_family != AF_INET) {
1445             continue;
1446         }
1447 
1448         // save socket address
1449         memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));
1450 
1451         // determine broadcast address, if applicable
1452         if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&
1453             ifreqP->ifr_flags & IFF_BROADCAST) {
1454 
1455             // restore socket address to ifreqP
1456             memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
1457 
1458             if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {
1459                 memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),
1460                        sizeof(struct sockaddr));
1461                 broadaddrP = &broadaddr;
1462             }
1463         }
1464 
1465         // restore socket address to ifreqP
1466         memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
1467 
1468         // determine netmask
1469         if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {
1470             prefix = translateIPv4AddressToPrefix(
1471                          (struct sockaddr_in *)&(ifreqP->ifr_addr));
1472         }
1473 
1474         // add interface to the list
1475         ifs = addif(env, sock, ifreqP->ifr_name, ifs,
1476                     &addr, broadaddrP, AF_INET, prefix);
1477 
1478         // in case of exception, free interface list and buffer and return NULL
1479         if ((*env)->ExceptionOccurred(env)) {
1480             free(buf);
1481             freeif(ifs);
1482             return NULL;
1483         }
1484     }
1485 
1486     // free buffer
1487     free(buf);
1488     return ifs;
1489 }
1490 
1491 /*
1492  * Enumerates and returns all IPv6 interfaces on AIX.
1493  */
1494 static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
1495     struct ifconf ifc;
1496     struct ifreq *ifreqP;
1497     char *buf, *cp, *cplimit;
1498 
1499     // call SIOCGSIZIFCONF to get size for SIOCGIFCONF buffer
1500     if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {
1501         JNU_ThrowByNameWithMessageAndLastError
1502             (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");
1503         return ifs;
1504     }
1505 
1506     // call SIOCGIFCONF to enumerate the interfaces
1507     CHECKED_MALLOC3(buf, char *, ifc.ifc_len);
1508     ifc.ifc_buf = buf;
1509     if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1510         JNU_ThrowByNameWithMessageAndLastError
1511             (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");
1512         free(buf);
1513         return ifs;
1514     }
1515 
1516     // iterate through each interface
1517     ifreqP = ifc.ifc_req;
1518     cp = (char *)ifc.ifc_req;
1519     cplimit = cp + ifc.ifc_len;
1520 
1521     for (; cp < cplimit;
1522          cp += (sizeof(ifreqP->ifr_name) +
1523                 MAX((ifreqP->ifr_addr).sa_len, sizeof(ifreqP->ifr_addr))))
1524     {
1525         ifreqP = (struct ifreq *)cp;
1526         short prefix = 0;
1527 
1528         // ignore non IPv6 addresses
1529         if (ifreqP->ifr_addr.sa_family != AF_INET6) {
1530             continue;
1531         }
1532 
1533         // determine netmask
1534         struct in6_ifreq if6;
1535         memset((char *)&if6, 0, sizeof(if6));
1536         strncpy(if6.ifr_name, ifreqP->ifr_name, sizeof(if6.ifr_name) - 1);
1537         memcpy(&(if6.ifr_Addr), &(ifreqP->ifr_addr),
1538                sizeof(struct sockaddr_in6));
1539         if (ioctl(sock, SIOCGIFNETMASK6, (char *)&if6) >= 0) {
1540             prefix = translateIPv6AddressToPrefix(&(if6.ifr_Addr));
1541         }
1542 
1543         // set scope ID to interface index
1544         ((struct sockaddr_in6 *)&(ifreqP->ifr_addr))->sin6_scope_id =
1545             getIndex(sock, ifreqP->ifr_name);
1546 
1547         // add interface to the list
1548         ifs = addif(env, sock, ifreqP->ifr_name, ifs,
1549                     (struct sockaddr *)&(ifreqP->ifr_addr),
1550                     NULL, AF_INET6, prefix);
1551 
1552         // if an exception occurred then free the list
1553         if ((*env)->ExceptionOccurred(env)) {
1554             free(buf);
1555             freeif(ifs);
1556             return NULL;
1557         }
1558     }
1559 
1560     // free buffer
1561     free(buf);
1562     return ifs;
1563 }
1564 
1565 /*
1566  * Try to get the interface index.
1567  */
1568 static int getIndex(int sock, const char *name) {
1569     int index = if_nametoindex(name);
1570     return (index == 0) ? -1 : index;
1571 }
1572 
1573 /*
1574  * Gets the Hardware address (usually MAC address) for the named interface.
1575  * On return puts the data in buf, and returns the length, in byte, of the
1576  * MAC address. Returns -1 if there is no hardware address on that interface.
1577  */
1578 static int getMacAddress
1579   (JNIEnv *env, const char *ifname, const struct in_addr *addr,
1580    unsigned char *buf)
1581 {
1582     int size;
1583     struct kinfo_ndd *nddp;
1584     void *end;
1585 
1586     size = getkerninfo(KINFO_NDD, 0, 0, 0);
1587     if (size == 0) {
1588         return -1;
1589     }
1590 
1591     if (size < 0) {
1592         perror("getkerninfo 1");
1593         return -1;
1594     }
1595 
1596     nddp = (struct kinfo_ndd *)malloc(size);
1597 
1598     if (!nddp) {
1599         JNU_ThrowOutOfMemoryError(env,
1600             "Network interface getMacAddress native buffer allocation failed");
1601         return -1;
1602     }
1603 
1604     if (getkerninfo(KINFO_NDD, (char*) nddp, &size, 0) < 0) {
1605         perror("getkerninfo 2");
1606         free(nddp);
1607         return -1;
1608     }
1609 
1610     end = (void *)nddp + size;
1611     while ((void *)nddp < end) {
1612         if (!strcmp(nddp->ndd_alias, ifname) ||
1613                  !strcmp(nddp->ndd_name, ifname)) {
1614             bcopy(nddp->ndd_addr, buf, 6);
1615             free(nddp);
1616             return 6;
1617         } else {
1618             nddp++;
1619         }
1620     }
1621 
1622     free(nddp);
1623     return -1;
1624 }
1625 
1626 static int getMTU(JNIEnv *env, int sock, const char *ifname) {
1627     struct ifreq if2;
1628     memset((char *)&if2, 0, sizeof(if2));
1629     strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
1630 
1631     if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
1632         JNU_ThrowByNameWithMessageAndLastError
1633             (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");
1634         return -1;
1635     }
1636 
1637     return if2.ifr_mtu;
1638 }
1639 
1640 static int getFlags(int sock, const char *ifname, int *flags) {
1641     struct ifreq if2;
1642     memset((char *)&if2, 0, sizeof(if2));
1643     strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
1644 
1645     if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
1646         return -1;
1647     }
1648 
1649     if (sizeof(if2.ifr_flags) == sizeof(short)) {
1650         *flags = (if2.ifr_flags & 0xffff);
1651     } else {
1652         *flags = if2.ifr_flags;
1653     }
1654     return 0;
1655 }
1656 
1657 #endif /* _AIX */
1658 
1659 /** BSD **/
1660 #if defined(_ALLBSD_SOURCE)
1661 
1662 /*
1663  * Opens a socket for further ioctl calls. Tries AF_INET socket first and
1664  * if it fails return AF_INET6 socket.
1665  */
1666 static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
1667     int sock;
1668 
1669     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1670         if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {
1671             if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1672                 JNU_ThrowByNameWithMessageAndLastError
1673                     (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1674                 return -1;
1675             }
1676         } else { // errno is not NOSUPPORT
1677             JNU_ThrowByNameWithMessageAndLastError
1678                 (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1679             return -1;
1680         }
1681     }
1682 
1683     return sock;
1684 }
1685 
1686 /*
1687  * Enumerates and returns all IPv4 interfaces on BSD.
1688  */
1689 static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
1690     struct ifaddrs *ifa, *origifa;
1691 
1692     if (getifaddrs(&origifa) != 0) {
1693         JNU_ThrowByNameWithMessageAndLastError
1694             (env, JNU_JAVANETPKG "SocketException", "getifaddrs() failed");
1695         return ifs;
1696     }
1697 
1698     for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
1699         struct sockaddr *broadaddrP = NULL;
1700 
1701         // ignore non IPv4 addresses
1702         if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)
1703             continue;
1704 
1705         // set ifa_broadaddr, if there is one
1706         if ((ifa->ifa_flags & IFF_POINTOPOINT) == 0 &&
1707             ifa->ifa_flags & IFF_BROADCAST) {
1708             broadaddrP = ifa->ifa_dstaddr;
1709         }
1710 
1711         // add interface to the list
1712         ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr,
1713                     broadaddrP, AF_INET,
1714                     translateIPv4AddressToPrefix((struct sockaddr_in *)
1715                                                  ifa->ifa_netmask));
1716 
1717         // if an exception occurred then free the list
1718         if ((*env)->ExceptionOccurred(env)) {
1719             freeifaddrs(origifa);
1720             freeif(ifs);
1721             return NULL;
1722         }
1723     }
1724 
1725     // free ifaddrs buffer
1726     freeifaddrs(origifa);
1727     return ifs;
1728 }
1729 
1730 /*
1731  * Enumerates and returns all IPv6 interfaces on BSD.
1732  */
1733 static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
1734     struct ifaddrs *ifa, *origifa;
1735 
1736     if (getifaddrs(&origifa) != 0) {
1737         JNU_ThrowByNameWithMessageAndLastError
1738             (env, JNU_JAVANETPKG "SocketException", "getifaddrs() failed");
1739         return ifs;
1740     }
1741 
1742     for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
1743         // ignore non IPv6 addresses
1744         if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET6)
1745             continue;
1746 
1747         // set scope ID to interface index
1748         ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id =
1749             getIndex(sock, ifa->ifa_name);
1750 
1751         // add interface to the list
1752         ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, NULL,
1753                     AF_INET6,
1754                     translateIPv6AddressToPrefix((struct sockaddr_in6 *)
1755                                                  ifa->ifa_netmask));
1756 
1757         // if an exception occurred then free the list
1758         if ((*env)->ExceptionOccurred(env)) {
1759             freeifaddrs(origifa);
1760             freeif(ifs);
1761             return NULL;
1762         }
1763     }
1764 
1765     // free ifaddrs buffer
1766     freeifaddrs(origifa);
1767     return ifs;
1768 }
1769 
1770 /*
1771  * Try to get the interface index.
1772  */
1773 static int getIndex(int sock, const char *name) {
1774 #if !defined(__FreeBSD__)
1775     int index = if_nametoindex(name);
1776     return (index == 0) ? -1 : index;
1777 #else
1778     struct ifreq if2;
1779     memset((char *)&if2, 0, sizeof(if2));
1780     strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);
1781 
1782     if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
1783         return -1;
1784     }
1785 
1786     return if2.ifr_index;
1787 #endif
1788 }
1789 
1790 /*
1791  * Gets the Hardware address (usually MAC address) for the named interface.
1792  * On return puts the data in buf, and returns the length, in byte, of the
1793  * MAC address. Returns -1 if there is no hardware address on that interface.
1794  */
1795 static int getMacAddress
1796   (JNIEnv *env, const char *ifname, const struct in_addr *addr,
1797    unsigned char *buf)
1798 {
1799     struct ifaddrs *ifa0, *ifa;
1800     struct sockaddr *saddr;
1801     int i;
1802 
1803     // grab the interface list
1804     if (!getifaddrs(&ifa0)) {
1805         // cycle through the interfaces
1806         for (i = 0, ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next, i++) {
1807             saddr = ifa->ifa_addr;
1808             if (saddr != NULL) {
1809                 // link layer contains the MAC address
1810                 if (saddr->sa_family == AF_LINK && !strcmp(ifname, ifa->ifa_name)) {
1811                     struct sockaddr_dl *sadl = (struct sockaddr_dl *) saddr;
1812                     // check the address has the correct length
1813                     if (sadl->sdl_alen == ETHER_ADDR_LEN) {
1814                         memcpy(buf, (sadl->sdl_data + sadl->sdl_nlen), ETHER_ADDR_LEN);
1815                         freeifaddrs(ifa0);
1816                         return ETHER_ADDR_LEN;
1817                     }
1818                 }
1819             }
1820         }
1821         freeifaddrs(ifa0);
1822     }
1823 
1824     return -1;
1825 }
1826 
1827 static int getMTU(JNIEnv *env, int sock, const char *ifname) {
1828     struct ifreq if2;
1829     memset((char *)&if2, 0, sizeof(if2));
1830     strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
1831 
1832     if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
1833         JNU_ThrowByNameWithMessageAndLastError
1834             (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");
1835         return -1;
1836     }
1837 
1838     return if2.ifr_mtu;
1839 }
1840 
1841 static int getFlags(int sock, const char *ifname, int *flags) {
1842     struct ifreq if2;
1843     memset((char *)&if2, 0, sizeof(if2));
1844     strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
1845 
1846     if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
1847         return -1;
1848     }
1849 
1850     if (sizeof(if2.ifr_flags) == sizeof(short)) {
1851         *flags = (if2.ifr_flags & 0xffff);
1852     } else {
1853         *flags = if2.ifr_flags;
1854     }
1855     return 0;
1856 }
1857 #endif /* _ALLBSD_SOURCE */