NetworkInterface.c 63.4 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
D
duke 已提交
3 4 5 6
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
7
 * published by the Free Software Foundation.  Oracle designates this
D
duke 已提交
8
 * particular file as subject to the "Classpath" exception as provided
9
 * by Oracle in the LICENSE file that accompanied this code.
D
duke 已提交
10 11 12 13 14 15 16 17 18 19 20
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
21 22 23
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
24 25 26 27 28 29 30 31 32 33 34 35
 */

#include <errno.h>
#include <strings.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_arp.h>
36

37
#if defined(__solaris__)
D
duke 已提交
38 39 40
#include <sys/dlpi.h>
#include <fcntl.h>
#include <stropts.h>
41
#include <sys/sockio.h>
D
duke 已提交
42
#endif
43

44
#if defined(__linux__)
D
duke 已提交
45 46 47 48 49
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <stdio.h>
#endif

50 51 52 53 54 55 56
#if defined(_AIX)
#include <sys/ioctl.h>
#include <netinet/in6_var.h>
#include <sys/ndd_var.h>
#include <sys/kinfo.h>
#endif

57 58 59 60 61 62 63 64 65 66 67 68 69
#if defined(_ALLBSD_SOURCE)
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/sockio.h>
#if defined(__APPLE__)
#include <net/ethernet.h>
#include <net/if_var.h>
#include <net/if_dl.h>
#include <netinet/in_var.h>
#include <ifaddrs.h>
#endif
#endif

D
duke 已提交
70 71 72 73
#include "jvm.h"
#include "jni_util.h"
#include "net_util.h"

74
#if defined(__linux__)
75 76 77 78 79 80
    #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
#elif defined(__solaris__)
    #ifndef SIOCGLIFHWADDR
        #define SIOCGLIFHWADDR _IOWR('i', 192, struct lifreq)
    #endif
    #define DEV_PREFIX "/dev/"
81 82
#endif

83 84 85 86 87 88
#ifdef LIFNAMSIZ
    #define IFNAMESIZE LIFNAMSIZ
#else
    #define IFNAMESIZE IFNAMSIZ
#endif

89 90 91 92 93 94 95 96 97
#define CHECKED_MALLOC3(_pointer, _type, _size) \
    do { \
        _pointer = (_type)malloc(_size); \
        if (_pointer == NULL) { \
            JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \
            return ifs; /* return untouched list */ \
        } \
    } while(0)

D
duke 已提交
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
typedef struct _netaddr  {
    struct sockaddr *addr;
    struct sockaddr *brdcast;
    short mask;
    int family; /* to make searches simple */
    struct _netaddr *next;
} netaddr;

typedef struct _netif {
    char *name;
    int index;
    char virtual;
    netaddr *addr;
    struct _netif *childs;
    struct _netif *next;
} netif;

/************************************************************************
 * NetworkInterface
 */

#include "java_net_NetworkInterface.h"

/************************************************************************
 * NetworkInterface
 */
jclass ni_class;
jfieldID ni_nameID;
jfieldID ni_indexID;
jfieldID ni_descID;
jfieldID ni_addrsID;
jfieldID ni_bindsID;
jfieldID ni_virutalID;
jfieldID ni_childsID;
jfieldID ni_parentID;
133
jfieldID ni_defaultIndexID;
D
duke 已提交
134 135 136 137 138 139 140 141
jmethodID ni_ctrID;

static jclass ni_ibcls;
static jmethodID ni_ibctrID;
static jfieldID ni_ibaddressID;
static jfieldID ni_ib4broadcastID;
static jfieldID ni_ib4maskID;

142
/** Private methods declarations **/
D
duke 已提交
143
static jobject createNetworkInterface(JNIEnv *env, netif *ifs);
144 145 146 147
static int     getFlags0(JNIEnv *env, jstring  ifname);

static netif  *enumInterfaces(JNIEnv *env);
static netif  *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs);
D
duke 已提交
148

149
#if defined(AF_INET6)
150 151 152
static netif  *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs);
#endif

153
static netif  *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,
154 155 156
                     struct sockaddr *ifr_addrP,
                     struct sockaddr *ifr_broadaddrP,
                     int family, short prefix);
157 158 159 160 161
static void    freeif(netif *ifs);

static int     openSocket(JNIEnv *env, int proto);
static int     openSocketWithFallback(JNIEnv *env, const char *ifname);

162 163
static short   translateIPv4AddressToPrefix(struct sockaddr_in *addr);
static short   translateIPv6AddressToPrefix(struct sockaddr_in6 *addr);
164

165
static int     getIndex(int sock, const char *ifname);
166
static int     getFlags(int sock, const char *ifname, int *flags);
167
static int     getMacAddress(JNIEnv *env, const char *ifname,
168
                             const struct in_addr *addr, unsigned char *buf);
169 170
static int     getMTU(JNIEnv *env, int sock, const char *ifname);

171 172 173
#if defined(__solaris__)
static int     getMacFromDevice(JNIEnv *env, const char *ifname,
                                unsigned char *retbuf);
174
#endif
175 176

/******************* Java entry points *****************************/
D
duke 已提交
177 178 179 180 181 182

/*
 * Class:     java_net_NetworkInterface
 * Method:    init
 * Signature: ()V
 */
183 184 185 186
JNIEXPORT void JNICALL Java_java_net_NetworkInterface_init
  (JNIEnv *env, jclass cls)
{
    ni_class = (*env)->FindClass(env, "java/net/NetworkInterface");
187
    CHECK_NULL(ni_class);
D
duke 已提交
188
    ni_class = (*env)->NewGlobalRef(env, ni_class);
189
    CHECK_NULL(ni_class);
190
    ni_nameID = (*env)->GetFieldID(env, ni_class, "name", "Ljava/lang/String;");
191
    CHECK_NULL(ni_nameID);
D
duke 已提交
192
    ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
193
    CHECK_NULL(ni_indexID);
194 195
    ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs",
                                    "[Ljava/net/InetAddress;");
196
    CHECK_NULL(ni_addrsID);
197 198
    ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings",
                                    "[Ljava/net/InterfaceAddress;");
199
    CHECK_NULL(ni_bindsID);
200 201
    ni_descID = (*env)->GetFieldID(env, ni_class, "displayName",
                                   "Ljava/lang/String;");
202
    CHECK_NULL(ni_descID);
D
duke 已提交
203
    ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z");
204
    CHECK_NULL(ni_virutalID);
205 206
    ni_childsID = (*env)->GetFieldID(env, ni_class, "childs",
                                     "[Ljava/net/NetworkInterface;");
207
    CHECK_NULL(ni_childsID);
208 209
    ni_parentID = (*env)->GetFieldID(env, ni_class, "parent",
                                     "Ljava/net/NetworkInterface;");
210
    CHECK_NULL(ni_parentID);
D
duke 已提交
211
    ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
212
    CHECK_NULL(ni_ctrID);
D
duke 已提交
213
    ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
214
    CHECK_NULL(ni_ibcls);
D
duke 已提交
215
    ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
216
    CHECK_NULL(ni_ibcls);
D
duke 已提交
217
    ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
218
    CHECK_NULL(ni_ibctrID);
219 220
    ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address",
                                        "Ljava/net/InetAddress;");
221
    CHECK_NULL(ni_ibaddressID);
222 223
    ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast",
                                           "Ljava/net/Inet4Address;");
224
    CHECK_NULL(ni_ib4broadcastID);
D
duke 已提交
225
    ni_ib4maskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
226
    CHECK_NULL(ni_ib4maskID);
227 228
    ni_defaultIndexID = (*env)->GetStaticFieldID(env, ni_class, "defaultIndex",
                                                 "I");
229 230 231
    CHECK_NULL(ni_defaultIndexID);

    initInetAddressIDs(env);
D
duke 已提交
232 233 234 235 236 237 238 239
}

/*
 * Class:     java_net_NetworkInterface
 * Method:    getByName0
 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
 */
JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0
240 241
  (JNIEnv *env, jclass cls, jstring name)
{
D
duke 已提交
242 243
    netif *ifs, *curr;
    jboolean isCopy;
244
    const char* name_utf;
D
duke 已提交
245 246
    jobject obj = NULL;

247 248 249 250
    if (name != NULL) {
        name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
    } else {
        JNU_ThrowNullPointerException(env, "network interface name is NULL");
D
duke 已提交
251 252 253
        return NULL;
    }

254
    if (name_utf == NULL) {
255 256 257 258 259 260 261 262
        if (!(*env)->ExceptionCheck(env))
            JNU_ThrowOutOfMemoryError(env, NULL);
        return NULL;
    }

    ifs = enumInterfaces(env);
    if (ifs == NULL) {
        return NULL;
263
    }
264

265
    // search the list of interfaces based on name
D
duke 已提交
266 267 268 269 270 271 272 273
    curr = ifs;
    while (curr != NULL) {
        if (strcmp(name_utf, curr->name) == 0) {
            break;
        }
        curr = curr->next;
    }

274
    // if found create a NetworkInterface
275
    if (curr != NULL) {
D
duke 已提交
276 277 278
        obj = createNetworkInterface(env, curr);
    }

279
    // release the UTF string and interface list
D
duke 已提交
280 281 282 283 284 285 286 287
    (*env)->ReleaseStringUTFChars(env, name, name_utf);
    freeif(ifs);

    return obj;
}

/*
 * Class:     java_net_NetworkInterface
288
 * Method:    getByIndex0
D
duke 已提交
289 290
 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
 */
291
JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0
292 293
  (JNIEnv *env, jclass cls, jint index)
{
D
duke 已提交
294 295 296 297 298 299 300 301 302 303 304 305
    netif *ifs, *curr;
    jobject obj = NULL;

    if (index <= 0) {
        return NULL;
    }

    ifs = enumInterfaces(env);
    if (ifs == NULL) {
        return NULL;
    }

306
    // search the list of interfaces based on index
D
duke 已提交
307 308 309 310 311 312 313 314
    curr = ifs;
    while (curr != NULL) {
        if (index == curr->index) {
            break;
        }
        curr = curr->next;
    }

315
    // if found create a NetworkInterface
316
    if (curr != NULL) {
D
duke 已提交
317 318 319
        obj = createNetworkInterface(env, curr);
    }

320
    // release the interface list
D
duke 已提交
321
    freeif(ifs);
322

D
duke 已提交
323 324 325 326 327 328 329 330 331
    return obj;
}

/*
 * Class:     java_net_NetworkInterface
 * Method:    getByInetAddress0
 * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
 */
JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
332 333
  (JNIEnv *env, jclass cls, jobject iaObj)
{
D
duke 已提交
334
    netif *ifs, *curr;
335 336
    jobject obj = NULL;
    jboolean match = JNI_FALSE;
337
#if defined(AF_INET6)
338
    int family = (getInetAddress_family(env, iaObj) == IPv4) ? AF_INET : AF_INET6;
339
    JNU_CHECK_EXCEPTION_RETURN(env, NULL);
C
chegar 已提交
340
#else
341
    int family =  AF_INET;
C
chegar 已提交
342
#endif
D
duke 已提交
343 344 345 346 347 348 349 350 351
    ifs = enumInterfaces(env);
    if (ifs == NULL) {
        return NULL;
    }

    curr = ifs;
    while (curr != NULL) {
        netaddr *addrP = curr->addr;

352
        // iterate through each address on the interface
D
duke 已提交
353 354 355 356
        while (addrP != NULL) {

            if (family == addrP->family) {
                if (family == AF_INET) {
357
                    int address1 = htonl(
358
                        ((struct sockaddr_in *)addrP->addr)->sin_addr.s_addr);
359
                    int address2 = getInetAddress_addr(env, iaObj);
360
                    JNU_CHECK_EXCEPTION_RETURN(env, NULL);
D
duke 已提交
361 362 363 364 365
                    if (address1 == address2) {
                        match = JNI_TRUE;
                        break;
                    }
                }
366
#if defined(AF_INET6)
D
duke 已提交
367
                if (family == AF_INET6) {
368 369
                    jbyte *bytes = (jbyte *)&(
                        ((struct sockaddr_in6*)addrP->addr)->sin6_addr);
D
duke 已提交
370 371
                    jbyte caddr[16];
                    int i;
M
michaelm 已提交
372
                    getInet6Address_ipaddress(env, iaObj, (char *)caddr);
D
duke 已提交
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
                    i = 0;
                    while (i < 16) {
                        if (caddr[i] != bytes[i]) {
                            break;
                        }
                        i++;
                    }
                    if (i >= 16) {
                        match = JNI_TRUE;
                        break;
                    }
                }
#endif
            }

            if (match) {
                break;
            }
            addrP = addrP->next;
        }

        if (match) {
            break;
        }
        curr = curr->next;
    }

400
    // if found create a NetworkInterface
401
    if (match) {
D
duke 已提交
402 403 404
        obj = createNetworkInterface(env, curr);
    }

405
    // release the interface list
D
duke 已提交
406
    freeif(ifs);
407

D
duke 已提交
408 409 410 411 412 413 414 415 416
    return obj;
}

/*
 * Class:     java_net_NetworkInterface
 * Method:    getAll
 * Signature: ()[Ljava/net/NetworkInterface;
 */
JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll
417 418
  (JNIEnv *env, jclass cls)
{
D
duke 已提交
419 420 421 422 423 424 425 426 427
    netif *ifs, *curr;
    jobjectArray netIFArr;
    jint arr_index, ifCount;

    ifs = enumInterfaces(env);
    if (ifs == NULL) {
        return NULL;
    }

428
    // count the interfaces
D
duke 已提交
429 430 431 432 433 434 435
    ifCount = 0;
    curr = ifs;
    while (curr != NULL) {
        ifCount++;
        curr = curr->next;
    }

436
    // allocate a NetworkInterface array
D
duke 已提交
437 438 439 440 441 442
    netIFArr = (*env)->NewObjectArray(env, ifCount, cls, NULL);
    if (netIFArr == NULL) {
        freeif(ifs);
        return NULL;
    }

443 444
    // iterate through the interfaces, create a NetworkInterface instance
    // for each array element and populate the object
D
duke 已提交
445 446 447 448 449 450 451 452 453 454 455
    curr = ifs;
    arr_index = 0;
    while (curr != NULL) {
        jobject netifObj;

        netifObj = createNetworkInterface(env, curr);
        if (netifObj == NULL) {
            freeif(ifs);
            return NULL;
        }

456
        // put the NetworkInterface into the array
D
duke 已提交
457 458 459 460 461
        (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);

        curr = curr->next;
    }

462
    // release the interface list
D
duke 已提交
463
    freeif(ifs);
464

D
duke 已提交
465 466 467
    return netIFArr;
}

468 469 470 471 472
/*
 * Class:     java_net_NetworkInterface
 * Method:    isUp0
 * Signature: (Ljava/lang/String;I)Z
 */
473 474 475
JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0
  (JNIEnv *env, jclass cls, jstring name, jint index)
{
476 477 478 479 480 481 482 483 484
    int ret = getFlags0(env, name);
    return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE :  JNI_FALSE;
}

/*
 * Class:     java_net_NetworkInterface
 * Method:    isP2P0
 * Signature: (Ljava/lang/String;I)Z
 */
485 486 487
JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0
  (JNIEnv *env, jclass cls, jstring name, jint index)
{
488 489 490 491 492 493 494 495 496
    int ret = getFlags0(env, name);
    return (ret & IFF_POINTOPOINT) ? JNI_TRUE :  JNI_FALSE;
}

/*
 * Class:     java_net_NetworkInterface
 * Method:    isLoopback0
 * Signature: (Ljava/lang/String;I)Z
 */
497 498 499
JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0
  (JNIEnv *env, jclass cls, jstring name, jint index)
{
500 501 502 503 504 505 506 507 508
    int ret = getFlags0(env, name);
    return (ret & IFF_LOOPBACK) ? JNI_TRUE :  JNI_FALSE;
}

/*
 * Class:     java_net_NetworkInterface
 * Method:    supportsMulticast0
 * Signature: (Ljava/lang/String;I)Z
 */
509 510 511
JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0
  (JNIEnv *env, jclass cls, jstring name, jint index)
{
512 513 514 515 516 517 518 519 520
    int ret = getFlags0(env, name);
    return (ret & IFF_MULTICAST) ? JNI_TRUE :  JNI_FALSE;
}

/*
 * Class:     java_net_NetworkInterface
 * Method:    getMacAddr0
 * Signature: ([bLjava/lang/String;I)[b
 */
521 522 523
JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0
  (JNIEnv *env, jclass cls, jbyteArray addrArray, jstring name, jint index)
{
524 525 526 527 528 529 530
    jint addr;
    jbyte caddr[4];
    struct in_addr iaddr;
    jbyteArray ret = NULL;
    unsigned char mac[16];
    int len;
    jboolean isCopy;
531
    const char *name_utf;
532

533 534 535 536 537
    if (name != NULL) {
        name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
    } else {
        JNU_ThrowNullPointerException(env, "network interface name is NULL");
        return NULL;
538
    }
539 540 541 542 543

    if (name_utf == NULL) {
        if (!(*env)->ExceptionCheck(env))
            JNU_ThrowOutOfMemoryError(env, NULL);
        return NULL;
544 545 546
    }

    if (!IS_NULL(addrArray)) {
547 548 549 550 551 552 553
        (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
        addr = ((caddr[0]<<24) & 0xff000000);
        addr |= ((caddr[1] <<16) & 0xff0000);
        addr |= ((caddr[2] <<8) & 0xff00);
        addr |= (caddr[3] & 0xff);
        iaddr.s_addr = htonl(addr);
        len = getMacAddress(env, name_utf, &iaddr, mac);
554
    } else {
555
        len = getMacAddress(env, name_utf, NULL, mac);
556
    }
557

558
    if (len > 0) {
559 560 561 562
        ret = (*env)->NewByteArray(env, len);
        if (!IS_NULL(ret)) {
            (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *)(mac));
        }
563 564
    }

565 566 567 568
    // release the UTF string and interface list
    (*env)->ReleaseStringUTFChars(env, name, name_utf);

    return ret;
569 570 571 572 573 574 575
}

/*
 * Class:       java_net_NetworkInterface
 * Method:      getMTU0
 * Signature:   ([bLjava/lang/String;I)I
 */
576 577 578
JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0
  (JNIEnv *env, jclass cls, jstring name, jint index)
{
579
    jboolean isCopy;
580
    int sock, ret = -1;
581
    const char* name_utf = NULL;
582

583 584 585 586 587 588
    if (name != NULL) {
        name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
    } else {
        JNU_ThrowNullPointerException(env, "network interface name is NULL");
        return ret;
    }
589

590
    if (name_utf == NULL) {
591 592 593
        if (!(*env)->ExceptionCheck(env))
            JNU_ThrowOutOfMemoryError(env, NULL);
        return ret;
594
    }
595

596
    if ((sock = openSocketWithFallback(env, name_utf)) < 0) {
597 598
        (*env)->ReleaseStringUTFChars(env, name, name_utf);
        return JNI_FALSE;
599 600 601 602 603 604 605 606 607 608 609 610 611 612
    }

    ret = getMTU(env, sock, name_utf);

    (*env)->ReleaseStringUTFChars(env, name, name_utf);

    close(sock);
    return ret;
}

/*** Private methods definitions ****/

static int getFlags0(JNIEnv *env, jstring name) {
    jboolean isCopy;
613 614
    int ret, sock, flags = 0;
    const char *name_utf;
615

616 617 618 619 620 621
    if (name != NULL) {
        name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
    } else {
        JNU_ThrowNullPointerException(env, "network interface name is NULL");
        return -1;
    }
622

623
    if (name_utf == NULL) {
624 625 626
        if (!(*env)->ExceptionCheck(env))
            JNU_ThrowOutOfMemoryError(env, NULL);
        return -1;
627
    }
628 629
    if ((sock = openSocketWithFallback(env, name_utf)) < 0) {
        (*env)->ReleaseStringUTFChars(env, name, name_utf);
630
        return -1;
631 632
    }

633
    ret = getFlags(sock, name_utf, &flags);
634 635 636 637 638

    close(sock);
    (*env)->ReleaseStringUTFChars(env, name, name_utf);

    if (ret < 0) {
639 640
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "getFlags() failed");
641 642 643
        return -1;
    }

644
    return flags;
645 646
}

D
duke 已提交
647
/*
648 649
 * Creates a NetworkInterface object, populates the name, the index, and
 * populates the InetAddress array based on the IP addresses for this
D
duke 已提交
650 651
 * interface.
 */
652
static jobject createNetworkInterface(JNIEnv *env, netif *ifs) {
D
duke 已提交
653 654 655 656 657
    jobject netifObj;
    jobject name;
    jobjectArray addrArr;
    jobjectArray bindArr;
    jobjectArray childArr;
658
    netaddr *addrs;
D
duke 已提交
659 660 661 662 663 664
    jint addr_index, addr_count, bind_index;
    jint child_count, child_index;
    netaddr *addrP;
    netif *childP;
    jobject tmp;

665
    // create a NetworkInterface object and populate it
D
duke 已提交
666
    netifObj = (*env)->NewObject(env, ni_class, ni_ctrID);
667
    CHECK_NULL_RETURN(netifObj, NULL);
D
duke 已提交
668
    name = (*env)->NewStringUTF(env, ifs->name);
669
    CHECK_NULL_RETURN(name, NULL);
D
duke 已提交
670 671 672
    (*env)->SetObjectField(env, netifObj, ni_nameID, name);
    (*env)->SetObjectField(env, netifObj, ni_descID, name);
    (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
673 674
    (*env)->SetBooleanField(env, netifObj, ni_virutalID,
                            ifs->virtual ? JNI_TRUE : JNI_FALSE);
D
duke 已提交
675

676
    // count the number of addresses on this interface
D
duke 已提交
677 678 679 680 681 682 683
    addr_count = 0;
    addrP = ifs->addr;
    while (addrP != NULL) {
        addr_count++;
        addrP = addrP->next;
    }

684
    // create the array of InetAddresses
685
    addrArr = (*env)->NewObjectArray(env, addr_count,  ia_class, NULL);
D
duke 已提交
686 687 688 689 690 691
    if (addrArr == NULL) {
        return NULL;
    }

    bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL);
    if (bindArr == NULL) {
692
       return NULL;
D
duke 已提交
693 694 695 696 697 698 699 700 701
    }
    addrP = ifs->addr;
    addr_index = 0;
    bind_index = 0;
    while (addrP != NULL) {
        jobject iaObj = NULL;
        jobject ibObj = NULL;

        if (addrP->family == AF_INET) {
702
            iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
D
duke 已提交
703
            if (iaObj) {
704 705
                setInetAddress_addr(env, iaObj, htonl(
                    ((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr));
706
                JNU_CHECK_EXCEPTION_RETURN(env, NULL);
707 708
            } else {
                return NULL;
D
duke 已提交
709 710 711
            }
            ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
            if (ibObj) {
712 713
                (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
                if (addrP->brdcast) {
714
                    jobject ia2Obj = NULL;
715
                    ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
716
                    if (ia2Obj) {
717 718
                        setInetAddress_addr(env, ia2Obj, htonl(
                            ((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr));
719
                        JNU_CHECK_EXCEPTION_RETURN(env, NULL);
720
                        (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj);
721 722
                    } else {
                        return NULL;
723
                    }
724 725 726
                }
                (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
                (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
727 728
            } else {
                return NULL;
D
duke 已提交
729 730
            }
        }
731
#if defined(AF_INET6)
D
duke 已提交
732 733
        if (addrP->family == AF_INET6) {
            int scope=0;
734
            iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
D
duke 已提交
735
            if (iaObj) {
736 737
                jboolean ret = setInet6Address_ipaddress(env, iaObj,
                    (char *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr));
M
michaelm 已提交
738
                if (ret == JNI_FALSE) {
D
duke 已提交
739 740
                    return NULL;
                }
741

D
duke 已提交
742
                scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;
743

D
duke 已提交
744
                if (scope != 0) { /* zero is default value, no need to set */
M
michaelm 已提交
745 746
                    setInet6Address_scopeid(env, iaObj, scope);
                    setInet6Address_scopeifname(env, iaObj, netifObj);
D
duke 已提交
747
                }
748 749
            } else {
                return NULL;
D
duke 已提交
750 751 752
            }
            ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
            if (ibObj) {
753 754 755
                (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
                (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
                (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
756 757
            } else {
                return NULL;
D
duke 已提交
758 759 760 761 762 763 764 765
            }
        }
#endif

        (*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj);
        addrP = addrP->next;
    }

766
    // see if there is any virtual interface attached to this one.
D
duke 已提交
767 768 769
    child_count = 0;
    childP = ifs->childs;
    while (childP) {
770 771
        child_count++;
        childP = childP->next;
D
duke 已提交
772 773 774 775
    }

    childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL);
    if (childArr == NULL) {
776
        return NULL;
D
duke 已提交
777 778
    }

779
    // create the NetworkInterface instances for the sub-interfaces as well
D
duke 已提交
780 781 782
    child_index = 0;
    childP = ifs->childs;
    while(childP) {
783 784 785 786 787 788 789
        tmp = createNetworkInterface(env, childP);
        if (tmp == NULL) {
            return NULL;
        }
        (*env)->SetObjectField(env, tmp, ni_parentID, netifObj);
        (*env)->SetObjectArrayElement(env, childArr, child_index++, tmp);
        childP = childP->next;
D
duke 已提交
790 791 792 793 794
    }
    (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
    (*env)->SetObjectField(env, netifObj, ni_bindsID, bindArr);
    (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);

795
    // return the NetworkInterface
D
duke 已提交
796 797 798 799 800 801 802
    return netifObj;
}

/*
 * Enumerates all interfaces
 */
static netif *enumInterfaces(JNIEnv *env) {
803
    netif *ifs = NULL;
804
    int sock;
D
duke 已提交
805

806 807 808 809 810
    sock = openSocket(env, AF_INET);
    if (sock < 0 && (*env)->ExceptionOccurred(env)) {
        return NULL;
    }

811
    // enumerate IPv4 addresses
812 813 814
    ifs = enumIPv4Interfaces(env, sock, NULL);
    close(sock);

815
    // return partial list if an exception occurs in the middle of process ???
816 817
    if (ifs == NULL && (*env)->ExceptionOccurred(env)) {
        return NULL;
D
duke 已提交
818 819
    }

820
    // If IPv6 is available then enumerate IPv6 addresses.
821
#if defined(AF_INET6)
822 823
        // User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,
        // so we have to call ipv6_available()
824
        if (ipv6_available()) {
825 826 827 828 829
            sock = openSocket(env, AF_INET6);
            if (sock < 0 && (*env)->ExceptionOccurred(env)) {
                freeif(ifs);
                return NULL;
            }
D
duke 已提交
830

831 832
            ifs = enumIPv6Interfaces(env, sock, ifs);
            close(sock);
833

834 835 836 837 838
            if ((*env)->ExceptionOccurred(env)) {
                freeif(ifs);
                return NULL;
            }
        }
D
duke 已提交
839 840 841 842 843 844
#endif

    return ifs;
}

/*
845
 * Frees an interface list (including any attached addresses).
D
duke 已提交
846
 */
847
static void freeif(netif *ifs) {
848 849
    netif *currif = ifs;
    netif *child = NULL;
D
duke 已提交
850

851 852 853 854 855 856
    while (currif != NULL) {
        netaddr *addrP = currif->addr;
        while (addrP != NULL) {
            netaddr *next = addrP->next;
            free(addrP);
            addrP = next;
857
        }
D
duke 已提交
858

859
        // don't forget to free the sub-interfaces
860 861 862
        if (currif->childs != NULL) {
            freeif(currif->childs);
        }
D
duke 已提交
863

864 865 866
        ifs = currif->next;
        free(currif);
        currif = ifs;
D
duke 已提交
867
    }
868
}
D
duke 已提交
869

870 871 872 873
static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,
                    struct sockaddr *ifr_addrP,
                    struct sockaddr *ifr_broadaddrP,
                    int family, short prefix)
874
{
875 876
    netif *currif = ifs, *parent;
    netaddr *addrP;
877
    char name[IFNAMESIZE], vname[IFNAMESIZE];
878
    char *name_colonP;
879 880
    int isVirtual = 0;
    int addr_size;
D
duke 已提交
881

882 883 884 885
    // If the interface name is a logical interface then we remove the unit
    // number so that we have the physical interface (eg: hme0:1 -> hme0).
    // NetworkInterface currently doesn't have any concept of physical vs.
    // logical interfaces.
886 887
    strncpy(name, if_name, IFNAMESIZE);
    name[IFNAMESIZE - 1] = '\0';
888
    *vname = 0;
D
duke 已提交
889

890 891
    // Create and populate the netaddr node. If allocation fails
    // return an un-updated list.
892

893
    // Allocate for addr and brdcast at once
D
duke 已提交
894

895
#if defined(AF_INET6)
896 897
    addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in)
                                    : sizeof(struct sockaddr_in6);
898 899 900
#else
    addr_size = sizeof(struct sockaddr_in);
#endif
D
duke 已提交
901

902 903
    CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr) + 2 * addr_size);
    addrP->addr = (struct sockaddr *)((char *)addrP + sizeof(netaddr));
904
    memcpy(addrP->addr, ifr_addrP, addr_size);
D
duke 已提交
905

906 907 908
    addrP->family = family;
    addrP->mask = prefix;
    addrP->next = 0;
909

910 911 912 913 914 915 916 917
    // for IPv4 add broadcast address
    if (family == AF_INET && ifr_broadaddrP != NULL) {
        addrP->brdcast = (struct sockaddr *)
                             ((char *)addrP + sizeof(netaddr) + addr_size);
        memcpy(addrP->brdcast, ifr_broadaddrP, addr_size);
    } else {
        addrP->brdcast = NULL;
    }
918

919
    // Deal with virtual interface with colon notation e.g. eth0:1
920 921
    name_colonP = strchr(name, ':');
    if (name_colonP != NULL) {
922
        int flags = 0;
923 924 925
        // This is a virtual interface. If we are able to access the parent
        // we need to create a new entry if it doesn't exist yet *and* update
        // the 'parent' interface with the new records.
926
        *name_colonP = 0;
927
        if (getFlags(sock, name, &flags) < 0 || flags < 0) {
928 929 930 931
            // failed to access parent interface do not create parent.
            // We are a virtual interface with no parent.
            isVirtual = 1;
            *name_colonP = ':';
932
        } else {
933 934 935 936
            // Got access to parent, so create it if necessary.
            // Save original name to vname and truncate name by ':'
            memcpy(vname, name, sizeof(vname));
            vname[name_colonP - name] = ':';
937 938
        }
    }
D
duke 已提交
939

940 941
    // Check if this is a "new" interface. Use the interface name for
    // matching because index isn't supported on Solaris 2.6 & 7.
942 943 944 945 946
    while (currif != NULL) {
        if (strcmp(name, currif->name) == 0) {
            break;
        }
        currif = currif->next;
D
duke 已提交
947
    }
948

949
    // If "new" then create a netif structure and insert it into the list.
950
    if (currif == NULL) {
951
         CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE);
952
         currif->name = (char *)currif + sizeof(netif);
953 954
         strncpy(currif->name, name, IFNAMESIZE);
         currif->name[IFNAMESIZE - 1] = '\0';
955
         currif->index = getIndex(sock, name);
956 957 958 959 960
         currif->addr = NULL;
         currif->childs = NULL;
         currif->virtual = isVirtual;
         currif->next = ifs;
         ifs = currif;
D
duke 已提交
961 962
    }

963
    // Finally insert the address on the interface
964 965
    addrP->next = currif->addr;
    currif->addr = addrP;
D
duke 已提交
966

967 968
    parent = currif;

969
    // Deal with the virtual interface now.
970 971 972 973 974 975 976 977 978 979
    if (vname[0]) {
        netaddr *tmpaddr;

        currif = parent->childs;

        while (currif != NULL) {
            if (strcmp(vname, currif->name) == 0) {
                break;
            }
            currif = currif->next;
D
duke 已提交
980 981
        }

982
        if (currif == NULL) {
983
            CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE);
984
            currif->name = (char *)currif + sizeof(netif);
985 986
            strncpy(currif->name, vname, IFNAMESIZE);
            currif->name[IFNAMESIZE - 1] = '\0';
987
            currif->index = getIndex(sock, vname);
988
            currif->addr = NULL; // Need to duplicate the addr entry?
989 990 991 992 993 994
            currif->virtual = 1;
            currif->childs = NULL;
            currif->next = parent->childs;
            parent->childs = currif;
        }

995
        CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr) + 2 * addr_size);
996 997
        memcpy(tmpaddr, addrP, sizeof(netaddr));
        if (addrP->addr != NULL) {
998 999
            tmpaddr->addr = (struct sockaddr *)
                ((char*)tmpaddr + sizeof(netaddr));
1000 1001 1002 1003
            memcpy(tmpaddr->addr, addrP->addr, addr_size);
        }

        if (addrP->brdcast != NULL) {
1004 1005
            tmpaddr->brdcast = (struct sockaddr *)
                ((char *)tmpaddr + sizeof(netaddr) + addr_size);
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
            memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size);
        }

        tmpaddr->next = currif->addr;
        currif->addr = tmpaddr;
    }

    return ifs;
}

1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
/*
 * Determines the prefix value for an AF_INET subnet address.
 */
static short translateIPv4AddressToPrefix(struct sockaddr_in *addr) {
    short prefix = 0;
    unsigned int mask = ntohl(addr->sin_addr.s_addr);
    while (mask) {
        mask <<= 1;
        prefix++;
    }
    return prefix;
}

/*
 * Determines the prefix value for an AF_INET6 subnet address.
 */
static short translateIPv6AddressToPrefix(struct sockaddr_in6 *addr) {
    short prefix = 0;
    u_char *addrBytes = (u_char *)&(addr->sin6_addr);
    unsigned int byte, bit;

    for (byte = 0; byte < sizeof(struct in6_addr); byte++, prefix += 8) {
        if (addrBytes[byte] != 0xff) {
            break;
        }
    }
    if (byte != sizeof(struct in6_addr)) {
        for (bit = 7; bit != 0; bit--, prefix++) {
            if (!(addrBytes[byte] & (1 << bit))) {
                break;
            }
        }
        for (; bit != 0; bit--) {
            if (addrBytes[byte] & (1 << bit)) {
                prefix = 0;
                break;
            }
        }
        if (prefix > 0) {
            byte++;
            for (; byte < sizeof(struct in6_addr); byte++) {
                if (addrBytes[byte]) {
                    prefix = 0;
                }
            }
        }
    }

    return prefix;
}

1067 1068
/*
 * Opens a socket for further ioct calls. proto is one of AF_INET or AF_INET6.
1069
 */
1070
static int openSocket(JNIEnv *env, int proto) {
1071 1072 1073
    int sock;

    if ((sock = JVM_Socket(proto, SOCK_DGRAM, 0)) < 0) {
1074 1075
        // If EPROTONOSUPPORT is returned it means we don't have
        // support for this proto so don't throw an exception.
1076
        if (errno != EPROTONOSUPPORT) {
1077 1078
            NET_ThrowByNameWithLastError
                (env, JNU_JAVANETPKG "SocketException", "Socket creation failed");
D
duke 已提交
1079
        }
1080 1081
        return -1;
    }
D
duke 已提交
1082

1083 1084 1085
    return sock;
}

1086 1087
/** Linux **/
#if defined(__linux__)
1088

1089
#if defined(AF_INET6)
1090
/*
1091 1092
 * Opens a socket for further ioctl calls. Tries AF_INET socket first and
 * if it fails return AF_INET6 socket.
1093 1094
 */
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
1095 1096
    int sock;

1097 1098 1099
    if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        if (errno == EPROTONOSUPPORT) {
            if ((sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1100 1101
                NET_ThrowByNameWithLastError
                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1102 1103 1104
                return -1;
            }
        } else { // errno is not NOSUPPORT
1105 1106
            NET_ThrowByNameWithLastError
                (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1107 1108 1109
            return -1;
        }
    }
1110

1111 1112 1113
    // Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or
    // IPv6 socket regardless of type of address of an interface.
    return sock;
1114 1115
}
#else
1116
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
1117
    return openSocket(env, AF_INET);
1118 1119 1120
}
#endif

1121 1122 1123
/*
 * Enumerates and returns all IPv4 interfaces on Linux.
 */
1124 1125 1126
static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
    struct ifconf ifc;
    struct ifreq *ifreqP;
1127
    char *buf = NULL;
1128 1129
    unsigned i;

1130
    // do a dummy SIOCGIFCONF to determine the buffer size
1131
    // SIOCGIFCOUNT doesn't work
1132 1133
    ifc.ifc_buf = NULL;
    if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1134 1135
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");
1136 1137
        return ifs;
    }
1138

1139
    // call SIOCGIFCONF to enumerate the interfaces
1140
    CHECKED_MALLOC3(buf, char *, ifc.ifc_len);
1141
    ifc.ifc_buf = buf;
1142 1143 1144
    if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");
1145
        free(buf);
1146 1147
        return ifs;
    }
D
duke 已提交
1148

1149
    // iterate through each interface
1150
    ifreqP = ifc.ifc_req;
1151
    for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {
1152 1153 1154
        struct sockaddr addr, broadaddr, *broadaddrP = NULL;
        short prefix = 0;

1155
        // ignore non IPv4 addresses
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
        if (ifreqP->ifr_addr.sa_family != AF_INET) {
            continue;
        }

        // save socket address
        memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));

        // determine broadcast address, if applicable
        if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&
            ifreqP->ifr_flags & IFF_BROADCAST) {

            // restore socket address to ifreqP
            memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));

            if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {
                memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),
                       sizeof(struct sockaddr));
                broadaddrP = &broadaddr;
            }
        }

        // restore socket address to ifreqP
        memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));

        // determine netmask
        if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {
            prefix = translateIPv4AddressToPrefix(
                         (struct sockaddr_in *)&(ifreqP->ifr_netmask));
        }

        // add interface to the list
1187
        ifs = addif(env, sock, ifreqP->ifr_name, ifs,
1188
                    &addr, broadaddrP, AF_INET, prefix);
1189

1190
        // in case of exception, free interface list and buffer and return NULL
D
duke 已提交
1191 1192
        if ((*env)->ExceptionOccurred(env)) {
            free(buf);
1193 1194
            freeif(ifs);
            return NULL;
D
duke 已提交
1195 1196 1197
        }
    }

1198
    // free buffer
D
duke 已提交
1199 1200 1201 1202
    free(buf);
    return ifs;
}

1203
#if defined(AF_INET6)
1204

D
duke 已提交
1205
/*
1206
 * Enumerates and returns all IPv6 interfaces on Linux.
D
duke 已提交
1207
 */
1208
static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
D
duke 已提交
1209
    FILE *f;
1210
    char devname[21], addr6p[8][5];
1211
    int prefix, scope, dad_status, if_idx;
D
duke 已提交
1212 1213

    if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1214
        while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
1215 1216 1217
                      addr6p[0], addr6p[1], addr6p[2], addr6p[3],
                      addr6p[4], addr6p[5], addr6p[6], addr6p[7],
                      &if_idx, &prefix, &scope, &dad_status, devname) != EOF) {
1218

1219
            char addr6[40];
D
duke 已提交
1220 1221 1222
            struct sockaddr_in6 addr;

            sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1223 1224
                    addr6p[0], addr6p[1], addr6p[2], addr6p[3],
                    addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
D
duke 已提交
1225 1226

            memset(&addr, 0, sizeof(struct sockaddr_in6));
1227
            inet_pton(AF_INET6, addr6, (void*)addr.sin6_addr.s6_addr);
1228

1229
            // set scope ID to interface index
D
duke 已提交
1230 1231
            addr.sin6_scope_id = if_idx;

1232
            // add interface to the list
1233
            ifs = addif(env, sock, devname, ifs, (struct sockaddr *)&addr,
1234
                        NULL, AF_INET6, (short)prefix);
1235

1236
            // if an exception occurred then return the list as is
D
duke 已提交
1237
            if ((*env)->ExceptionOccurred(env)) {
1238
                break;
D
duke 已提交
1239
            }
1240 1241
       }
       fclose(f);
D
duke 已提交
1242 1243 1244 1245
    }
    return ifs;
}

1246
#endif /* AF_INET6 */
D
duke 已提交
1247

1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
/*
 * Try to get the interface index.
 */
static int getIndex(int sock, const char *name) {
    struct ifreq if2;
    memset((char *)&if2, 0, sizeof(if2));
    strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);

    if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
        return -1;
    }

    return if2.ifr_ifindex;
}
1262

1263
/*
1264 1265 1266
 * Gets the Hardware address (usually MAC address) for the named interface.
 * On return puts the data in buf, and returns the length, in byte, of the
 * MAC address. Returns -1 if there is no hardware address on that interface.
1267
 */
1268
static int getMacAddress
1269
  (JNIEnv *env, const char *ifname, const struct in_addr *addr,
1270 1271
   unsigned char *buf)
{
1272
    struct ifreq ifr;
1273 1274 1275 1276 1277 1278
    int i, sock;

    if ((sock = openSocketWithFallback(env, ifname)) < 0) {
        return -1;
    }

1279 1280 1281 1282 1283
    memset((char *)&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
    if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFHWADDR) failed");
1284
        close(sock);
1285 1286 1287
        return -1;
    }

1288
    close(sock);
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
    memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);

    // all bytes to 0 means no hardware address
    for (i = 0; i < IFHWADDRLEN; i++) {
        if (buf[i] != 0)
            return IFHWADDRLEN;
    }

    return -1;
}

static int getMTU(JNIEnv *env, int sock, const char *ifname) {
    struct ifreq if2;
    memset((char *)&if2, 0, sizeof(if2));
    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);

    if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");
        return -1;
    }

    return if2.ifr_mtu;
}

static int getFlags(int sock, const char *ifname, int *flags) {
    struct ifreq if2;
    memset((char *)&if2, 0, sizeof(if2));
    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);

    if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
        return -1;
    }

    if (sizeof(if2.ifr_flags) == sizeof(short)) {
        *flags = (if2.ifr_flags & 0xffff);
    } else {
        *flags = if2.ifr_flags;
    }
    return 0;
}

#endif /* __linux__ */

/** AIX **/
#if defined(_AIX)

#if defined(AF_INET6)
/*
 * Opens a socket for further ioctl calls. Tries AF_INET socket first and
 * if it fails return AF_INET6 socket.
 */
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
    int sock;

1344
    if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1345
        if (errno == EPROTONOSUPPORT) {
1346
            if ((sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369
                NET_ThrowByNameWithLastError
                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                return -1;
            }
        } else { // errno is not NOSUPPORT
            NET_ThrowByNameWithLastError
                (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
            return -1;
        }
    }

    return sock;
}
#else
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
    return openSocket(env, AF_INET);
}
#endif

/*
 * Enumerates and returns all IPv4 interfaces on AIX.
 */
static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
1370 1371
    struct ifconf ifc;
    struct ifreq *ifreqP;
1372
    char *buf = NULL;
1373 1374
    unsigned i;

1375
    // call SIOCGSIZIFCONF to get the size of SIOCGIFCONF buffer
1376
    if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {
1377 1378
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");
1379 1380 1381
        return ifs;
    }

1382 1383 1384 1385
    // call CSIOCGIFCONF instead of SIOCGIFCONF where interface
    // records will always have sizeof(struct ifreq) length.
    // Be aware that only IPv4 data is complete this way.
    CHECKED_MALLOC3(buf, char *, ifc.ifc_len);
1386
    ifc.ifc_buf = buf;
1387 1388 1389
    if (ioctl(sock, CSIOCGIFCONF, (char *)&ifc) < 0) {
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(CSIOCGIFCONF) failed");
1390 1391 1392 1393
        free(buf);
        return ifs;
    }

1394
    // iterate through each interface
1395
    ifreqP = ifc.ifc_req;
1396 1397 1398
    for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {
        struct sockaddr addr, broadaddr, *broadaddrP = NULL;
        short prefix = 0;
1399

1400
        // ignore non IPv4 addresses
1401 1402 1403 1404 1405 1406
        if (ifreqP->ifr_addr.sa_family != AF_INET) {
            continue;
        }

        // save socket address
        memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));
1407

1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418
        // determine broadcast address, if applicable
        if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&
            ifreqP->ifr_flags & IFF_BROADCAST) {

            // restore socket address to ifreqP
            memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));

            if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {
                memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),
                       sizeof(struct sockaddr));
                broadaddrP = &broadaddr;
1419 1420 1421
            }
        }

1422 1423
        // restore socket address to ifreqP
        memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
1424

1425 1426 1427 1428
        // determine netmask
        if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {
            prefix = translateIPv4AddressToPrefix(
                         (struct sockaddr_in *)&(ifreqP->ifr_addr));
1429 1430
        }

1431
        // add interface to the list
1432
        ifs = addif(env, sock, ifreqP->ifr_name, ifs,
1433
                    &addr, broadaddrP, AF_INET, prefix);
1434

1435
        // in case of exception, free interface list and buffer and return NULL
1436 1437 1438 1439 1440 1441 1442
        if ((*env)->ExceptionOccurred(env)) {
            free(buf);
            freeif(ifs);
            return NULL;
        }
    }

1443
    // free buffer
1444 1445 1446 1447
    free(buf);
    return ifs;
}

1448
#if defined(AF_INET6)
1449

1450 1451 1452 1453 1454 1455
/*
 * Enumerates and returns all IPv6 interfaces on AIX.
 */
static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
    struct ifconf ifc;
    struct ifreq *ifreqP;
1456
    char *buf, *cp, *cplimit;
1457

1458 1459 1460 1461 1462
    // call SIOCGSIZIFCONF to get size for SIOCGIFCONF buffer
    if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");
        return ifs;
1463 1464
    }

1465 1466 1467 1468 1469 1470 1471 1472 1473
    // call SIOCGIFCONF to enumerate the interfaces
    CHECKED_MALLOC3(buf, char *, ifc.ifc_len);
    ifc.ifc_buf = buf;
    if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");
        free(buf);
        return ifs;
    }
1474

1475
    // iterate through each interface
1476 1477 1478
    ifreqP = ifc.ifc_req;
    cp = (char *)ifc.ifc_req;
    cplimit = cp + ifc.ifc_len;
D
duke 已提交
1479

1480 1481 1482 1483 1484 1485
    for (; cp < cplimit;
         cp += (sizeof(ifreqP->ifr_name) +
                MAX((ifreqP->ifr_addr).sa_len, sizeof(ifreqP->ifr_addr))))
    {
        ifreqP = (struct ifreq *)cp;
        short prefix = 0;
D
duke 已提交
1486

1487
        // ignore non IPv6 addresses
1488 1489
        if (ifreqP->ifr_addr.sa_family != AF_INET6) {
            continue;
1490
        }
D
duke 已提交
1491

1492 1493 1494 1495 1496 1497 1498 1499 1500
        // determine netmask
        struct in6_ifreq if6;
        memset((char *)&if6, 0, sizeof(if6));
        strncpy(if6.ifr_name, ifreqP->ifr_name, sizeof(if6.ifr_name) - 1);
        memcpy(&(if6.ifr_Addr), &(ifreqP->ifr_addr),
               sizeof(struct sockaddr_in6));
        if (ioctl(sock, SIOCGIFNETMASK6, (char *)&if6) >= 0) {
            prefix = translateIPv6AddressToPrefix(&(if6.ifr_Addr));
        }
1501

1502 1503 1504
        // set scope ID to interface index
        ((struct sockaddr_in6 *)&(ifreqP->ifr_addr))->sin6_scope_id =
            getIndex(sock, ifreqP->ifr_name);
D
duke 已提交
1505

1506 1507 1508 1509
        // add interface to the list
        ifs = addif(env, sock, ifreqP->ifr_name, ifs,
                    (struct sockaddr *)&(ifreqP->ifr_addr),
                    NULL, AF_INET6, prefix);
D
duke 已提交
1510

1511 1512 1513 1514 1515 1516
        // if an exception occurred then free the list
        if ((*env)->ExceptionOccurred(env)) {
            free(buf);
            freeif(ifs);
            return NULL;
        }
D
duke 已提交
1517
    }
1518

1519 1520 1521 1522
    // free buffer
    free(buf);
    return ifs;
}
D
duke 已提交
1523

1524 1525 1526 1527 1528 1529 1530 1531
#endif /* AF_INET6 */

/*
 * Try to get the interface index.
 */
static int getIndex(int sock, const char *name) {
    int index = if_nametoindex(name);
    return (index == 0) ? -1 : index;
1532 1533
}

1534 1535 1536
/*
 * Gets the Hardware address (usually MAC address) for the named interface.
 * On return puts the data in buf, and returns the length, in byte, of the
1537 1538
 * MAC address. Returns -1 if there is no hardware address on that interface.
 */
1539
static int getMacAddress
1540
  (JNIEnv *env, const char *ifname, const struct in_addr *addr,
1541 1542
   unsigned char *buf)
{
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
    int size;
    struct kinfo_ndd *nddp;
    void *end;

    size = getkerninfo(KINFO_NDD, 0, 0, 0);
    if (size == 0) {
        return -1;
    }

    if (size < 0) {
        perror("getkerninfo 1");
        return -1;
    }

    nddp = (struct kinfo_ndd *)malloc(size);

    if (!nddp) {
1560 1561
        JNU_ThrowOutOfMemoryError(env,
            "Network interface getMacAddress native buffer allocation failed");
1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581
        return -1;
    }

    if (getkerninfo(KINFO_NDD, nddp, &size, 0) < 0) {
        perror("getkerninfo 2");
        return -1;
    }

    end = (void *)nddp + size;
    while ((void *)nddp < end) {
        if (!strcmp(nddp->ndd_alias, ifname) ||
                !strcmp(nddp->ndd_name, ifname)) {
            bcopy(nddp->ndd_addr, buf, 6);
            return 6;
        } else {
            nddp++;
        }
    }

    return -1;
1582 1583
}

1584
static int getMTU(JNIEnv *env, int sock, const char *ifname) {
1585
    struct ifreq if2;
1586
    memset((char *)&if2, 0, sizeof(if2));
1587
    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
1588 1589

    if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
1590 1591
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");
1592 1593 1594
        return -1;
    }

1595
    return if2.ifr_mtu;
1596
}
D
duke 已提交
1597

1598
static int getFlags(int sock, const char *ifname, int *flags) {
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
    struct ifreq if2;
    memset((char *)&if2, 0, sizeof(if2));
    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);

    if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
        return -1;
    }

    if (sizeof(if2.ifr_flags) == sizeof(short)) {
        *flags = (if2.ifr_flags & 0xffff);
    } else {
        *flags = if2.ifr_flags;
    }
    return 0;
1613 1614
}

1615
#endif /* _AIX */
1616 1617

/** Solaris **/
1618
#if defined(__solaris__)
1619

1620
#if defined(AF_INET6)
1621
/*
1622 1623
 * Opens a socket for further ioctl calls. Tries AF_INET socket first and
 * if it fails return AF_INET6 socket.
1624 1625
 */
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
1626 1627 1628
    int sock, alreadyV6 = 0;
    struct lifreq if2;

1629 1630 1631
    if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        if (errno == EPROTONOSUPPORT) {
            if ((sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1632 1633
                NET_ThrowByNameWithLastError
                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1634 1635
                return -1;
            }
1636
            alreadyV6 = 1;
1637
        } else { // errno is not NOSUPPORT
1638 1639
            NET_ThrowByNameWithLastError
                (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1640 1641 1642
            return -1;
        }
    }
1643

1644 1645 1646 1647 1648 1649 1650 1651 1652
    // Solaris requires that we have an IPv6 socket to query an  interface
    // without an IPv4 address - check it here. POSIX 1 require the kernel to
    // return ENOTTY if the call is inappropriate for a device e.g. the NETMASK
    // for a device having IPv6 only address but not all devices follow the
    // standard so fall back on any error. It's not an ecologically friendly
    // gesture but more reliable.
    if (!alreadyV6) {
        memset((char *)&if2, 0, sizeof(if2));
        strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
1653
        if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
1654 1655
            close(sock);
            if ((sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1656 1657
                NET_ThrowByNameWithLastError
                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1658 1659
                return -1;
            }
1660 1661
        }
    }
D
duke 已提交
1662

1663 1664
    return sock;
}
1665
#else
1666
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
1667
    return openSocket(env, AF_INET);
1668 1669 1670 1671
}
#endif

/*
1672
 * Enumerates and returns all IPv4 interfaces on Solaris.
1673 1674 1675
 */
static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
    struct lifconf ifc;
1676
    struct lifreq *ifreqP;
1677
    struct lifnum numifs;
1678 1679
    char *buf = NULL;
    unsigned i;
D
duke 已提交
1680

1681
    // call SIOCGLIFNUM to get the interface count
1682
    numifs.lifn_family = AF_INET;
1683 1684
    numifs.lifn_flags = 0;
    if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {
1685 1686
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFNUM) failed");
1687
        return ifs;
D
duke 已提交
1688 1689
    }

1690 1691 1692
    // call SIOCGLIFCONF to enumerate the interfaces
    ifc.lifc_len = numifs.lifn_count * sizeof(struct lifreq);
    CHECKED_MALLOC3(buf, char *, ifc.lifc_len);
1693
    ifc.lifc_buf = buf;
1694 1695
    ifc.lifc_family = AF_INET;
    ifc.lifc_flags = 0;
1696
    if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {
1697 1698
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFCONF) failed");
1699 1700
        free(buf);
        return ifs;
D
duke 已提交
1701 1702
    }

1703 1704 1705 1706
    // iterate through each interface
    ifreqP = ifc.lifc_req;
    for (i = 0; i < numifs.lifn_count; i++, ifreqP++) {
        struct sockaddr addr, *broadaddrP = NULL;
D
duke 已提交
1707

1708
        // ignore non IPv4 addresses
1709
        if (ifreqP->lifr_addr.ss_family != AF_INET) {
1710 1711
            continue;
        }
D
duke 已提交
1712

1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726
        // save socket address
        memcpy(&addr, &(ifreqP->lifr_addr), sizeof(struct sockaddr));

        // determine broadcast address, if applicable
        if ((ioctl(sock, SIOCGLIFFLAGS, ifreqP) == 0) &&
            ifreqP->lifr_flags & IFF_BROADCAST) {

            // restore socket address to ifreqP
            memcpy(&(ifreqP->lifr_addr), &addr, sizeof(struct sockaddr));

            // query broadcast address and set pointer to it
            if (ioctl(sock, SIOCGLIFBRDADDR, ifreqP) == 0) {
                broadaddrP = (struct sockaddr *)&(ifreqP->lifr_broadaddr);
            }
1727 1728
        }

1729
        // add to the list
1730 1731
        ifs = addif(env, sock, ifreqP->lifr_name, ifs,
                    &addr, broadaddrP, AF_INET, (short)ifreqP->lifr_addrlen);
D
duke 已提交
1732

1733
        // if an exception occurred we return immediately
1734 1735 1736
        if ((*env)->ExceptionOccurred(env)) {
            free(buf);
            return ifs;
D
duke 已提交
1737
        }
1738
   }
D
duke 已提交
1739

1740
    // free buffer
1741
    free(buf);
D
duke 已提交
1742 1743 1744
    return ifs;
}

1745
#if defined(AF_INET6)
D
duke 已提交
1746

1747
/*
1748
 * Enumerates and returns all IPv6 interfaces on Solaris.
D
duke 已提交
1749
 */
1750 1751 1752 1753 1754 1755
static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
    struct lifconf ifc;
    struct lifreq *ifreqP;
    struct lifnum numifs;
    char *buf = NULL;
    unsigned i;
D
duke 已提交
1756

1757
    // call SIOCGLIFNUM to get the interface count
1758 1759 1760 1761 1762 1763
    numifs.lifn_family = AF_INET6;
    numifs.lifn_flags = 0;
    if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFNUM) failed");
        return ifs;
D
duke 已提交
1764
    }
1765

1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782
    // call SIOCGLIFCONF to enumerate the interfaces
    ifc.lifc_len = numifs.lifn_count * sizeof(struct lifreq);
    CHECKED_MALLOC3(buf, char *, ifc.lifc_len);
    ifc.lifc_buf = buf;
    ifc.lifc_family = AF_INET6;
    ifc.lifc_flags = 0;
    if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFCONF) failed");
        free(buf);
        return ifs;
    }

    // iterate through each interface
    ifreqP = ifc.lifc_req;
    for (i = 0; i < numifs.lifn_count; i++, ifreqP++) {

1783
        // ignore non IPv6 addresses
1784 1785
        if (ifreqP->lifr_addr.ss_family != AF_INET6) {
            continue;
1786 1787
        }

1788 1789 1790
        // set scope ID to interface index
        ((struct sockaddr_in6 *)&(ifreqP->lifr_addr))->sin6_scope_id =
            getIndex(sock, ifreqP->lifr_name);
1791

1792 1793 1794 1795 1796 1797 1798 1799 1800 1801
        // add to the list
        ifs = addif(env, sock, ifreqP->lifr_name, ifs,
                    (struct sockaddr *)&(ifreqP->lifr_addr),
                    NULL, AF_INET6, (short)ifreqP->lifr_addrlen);

        // if an exception occurred we return immediately
        if ((*env)->ExceptionOccurred(env)) {
            free(buf);
            return ifs;
        }
1802
    }
1803 1804 1805 1806

    // free buffer
    free(buf);
    return ifs;
D
duke 已提交
1807 1808
}

1809 1810
#endif /* AF_INET6 */

1811
/*
1812 1813
 * Try to get the interface index.
 * (Not supported on Solaris 2.6 or 7)
D
duke 已提交
1814
 */
1815
static int getIndex(int sock, const char *name) {
1816
    struct lifreq if2;
1817
    memset((char *)&if2, 0, sizeof(if2));
1818
    strncpy(if2.lifr_name, name, sizeof(if2.lifr_name) - 1);
D
duke 已提交
1819

1820
    if (ioctl(sock, SIOCGLIFINDEX, (char *)&if2) < 0) {
1821 1822 1823
        return -1;
    }

1824
    return if2.lifr_index;
D
duke 已提交
1825 1826
}

1827
/*
D
duke 已提交
1828 1829 1830 1831
 * Solaris specific DLPI code to get hardware address from a device.
 * Unfortunately, at least up to Solaris X, you have to have special
 * privileges (i.e. be root).
 */
1832
static int getMacFromDevice
1833
  (JNIEnv *env, const char *ifname, unsigned char *retbuf)
1834
{
1835 1836 1837 1838 1839 1840 1841 1842
    char style1dev[MAXPATHLEN];
    int fd;
    dl_phys_addr_req_t dlpareq;
    dl_phys_addr_ack_t *dlpaack;
    struct strbuf msg;
    char buf[128];
    int flags = 0;

1843
    // Device is in /dev.  e.g.: /dev/bge0
1844 1845 1846
    strcpy(style1dev, DEV_PREFIX);
    strcat(style1dev, ifname);
    if ((fd = open(style1dev, O_RDWR)) < 0) {
1847 1848 1849
        // Can't open it. We probably are missing the privilege.
        // We'll have to try something else
        return 0;
1850 1851 1852 1853 1854 1855 1856 1857 1858
    }

    dlpareq.dl_primitive = DL_PHYS_ADDR_REQ;
    dlpareq.dl_addr_type = DL_CURR_PHYS_ADDR;

    msg.buf = (char *)&dlpareq;
    msg.len = DL_PHYS_ADDR_REQ_SIZE;

    if (putmsg(fd, &msg, NULL, 0) < 0) {
1859 1860
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "putmsg() failed");
1861 1862 1863 1864 1865 1866 1867 1868 1869
        return -1;
    }

    dlpaack = (dl_phys_addr_ack_t *)buf;

    msg.buf = (char *)buf;
    msg.len = 0;
    msg.maxlen = sizeof (buf);
    if (getmsg(fd, &msg, NULL, &flags) < 0) {
1870 1871
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "getmsg() failed");
1872 1873 1874 1875
        return -1;
    }

    if (msg.len < DL_PHYS_ADDR_ACK_SIZE || dlpaack->dl_primitive != DL_PHYS_ADDR_ACK) {
1876 1877
        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
                        "Couldn't obtain phys addr\n");
1878 1879
        return -1;
    }
D
duke 已提交
1880

1881 1882
    memcpy(retbuf, &buf[dlpaack->dl_addr_offset], dlpaack->dl_addr_length);
    return dlpaack->dl_addr_length;
D
duke 已提交
1883 1884
}

1885 1886 1887
/*
 * Gets the Hardware address (usually MAC address) for the named interface.
 * On return puts the data in buf, and returns the length, in byte, of the
D
duke 已提交
1888 1889
 * MAC address. Returns -1 if there is no hardware address on that interface.
 */
1890
static int getMacAddress
1891
  (JNIEnv *env, const char *ifname, const struct in_addr *addr,
1892 1893
   unsigned char *buf)
{
1894
    struct lifreq if2;
1895 1896 1897 1898 1899
    int len, i, sock;

    if ((sock = openSocketWithFallback(env, ifname)) < 0) {
        return -1;
    }
1900

1901 1902
    // First, try the new (S11) SIOCGLIFHWADDR ioctl(). If that fails
    // try the old way.
1903 1904
    memset((char *)&if2, 0, sizeof(if2));
    strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
1905

1906
    if (ioctl(sock, SIOCGLIFHWADDR, &if2) != -1) {
1907
        struct sockaddr_dl *sp;
1908
        sp = (struct sockaddr_dl *)&if2.lifr_addr;
1909
        memcpy(buf, &sp->sdl_data[0], sp->sdl_alen);
1910
        close(sock);
1911 1912
        return sp->sdl_alen;
    }
1913

1914 1915 1916
    // On Solaris we have to use DLPI, but it will only work if we have
    // privileged access (i.e. root). If that fails, we try a lookup
    // in the ARP table, which requires an IPv4 address.
1917
    if (((len = getMacFromDevice(env, ifname, buf)) == 0) && (addr != NULL)) {
1918 1919 1920 1921
        struct arpreq arpreq;
        struct sockaddr_in *sin;
        struct sockaddr_in ipAddr;

1922
        len = 6; //???
D
duke 已提交
1923

1924 1925 1926 1927 1928 1929 1930
        sin = (struct sockaddr_in *)&arpreq.arp_pa;
        memset((char *)&arpreq, 0, sizeof(struct arpreq));
        ipAddr.sin_port = 0;
        ipAddr.sin_family = AF_INET;
        memcpy(&ipAddr.sin_addr, addr, sizeof(struct in_addr));
        memcpy(&arpreq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
        arpreq.arp_flags= ATF_PUBL;
D
duke 已提交
1931

1932 1933 1934 1935
        if (ioctl(sock, SIOCGARP, &arpreq) < 0) {
            close(sock);
            return -1;
        }
1936

1937
        memcpy(buf, &arpreq.arp_ha.sa_data[0], len);
1938
    }
1939
    close(sock);
D
duke 已提交
1940

1941
    // all bytes to 0 means no hardware address
1942
    for (i = 0; i < len; i++) {
1943 1944
        if (buf[i] != 0)
            return len;
1945
    }
D
duke 已提交
1946

1947
    return -1;
D
duke 已提交
1948 1949
}

1950
static int getMTU(JNIEnv *env, int sock, const char *ifname) {
1951
    struct lifreq if2;
1952 1953
    memset((char *)&if2, 0, sizeof(if2));
    strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
D
duke 已提交
1954

1955
    if (ioctl(sock, SIOCGLIFMTU, (char *)&if2) < 0) {
1956 1957
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFMTU) failed");
1958 1959
        return -1;
    }
D
duke 已提交
1960

1961
    return if2.lifr_mtu;
D
duke 已提交
1962 1963
}

1964
static int getFlags(int sock, const char *ifname, int *flags) {
1965 1966 1967
    struct lifreq if2;
    memset((char *)&if2, 0, sizeof(if2));
    strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
D
duke 已提交
1968

1969 1970 1971
    if (ioctl(sock, SIOCGLIFFLAGS, (char *)&if2) < 0) {
        return -1;
    }
D
duke 已提交
1972

1973 1974
    *flags = if2.lifr_flags;
    return 0;
1975
}
D
duke 已提交
1976

1977
#endif /* __solaris__ */
1978

1979
/** BSD **/
1980
#if defined(_ALLBSD_SOURCE)
1981

1982
#if defined(AF_INET6)
1983
/*
1984 1985
 * Opens a socket for further ioctl calls. Tries AF_INET socket first and
 * if it fails return AF_INET6 socket.
1986 1987
 */
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
1988 1989
    int sock;

1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002
    if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        if (errno == EPROTONOSUPPORT) {
            if ((sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
                NET_ThrowByNameWithLastError
                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
                return -1;
            }
        } else { // errno is not NOSUPPORT
            NET_ThrowByNameWithLastError
                (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
            return -1;
        }
    }
2003

2004
    return sock;
2005 2006
}
#else
2007
static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
2008
    return openSocket(env, AF_INET);
2009 2010 2011 2012
}
#endif

/*
2013
 * Enumerates and returns all IPv4 interfaces on BSD.
2014 2015 2016 2017 2018
 */
static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
    struct ifaddrs *ifa, *origifa;

    if (getifaddrs(&origifa) != 0) {
2019 2020
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "getifaddrs() failed");
2021 2022 2023 2024
        return ifs;
    }

    for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
2025
        struct sockaddr *broadaddrP = NULL;
2026

2027
        // ignore non IPv4 addresses
2028 2029 2030
        if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)
            continue;

2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
        // set ifa_broadaddr, if there is one
        if ((ifa->ifa_flags & IFF_POINTOPOINT) == 0 &&
            ifa->ifa_flags & IFF_BROADCAST) {
            broadaddrP = ifa->ifa_dstaddr;
        }

        // add interface to the list
        ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr,
                    broadaddrP, AF_INET,
                    translateIPv4AddressToPrefix((struct sockaddr_in *)
                                                 ifa->ifa_netmask));
2042

2043
        // if an exception occurred then free the list
2044 2045 2046 2047 2048 2049 2050
        if ((*env)->ExceptionOccurred(env)) {
            freeifaddrs(origifa);
            freeif(ifs);
            return NULL;
        }
    }

2051
    // free ifaddrs buffer
2052 2053 2054 2055
    freeifaddrs(origifa);
    return ifs;
}

2056
#if defined(AF_INET6)
2057 2058

/*
2059
 * Enumerates and returns all IPv6 interfaces on BSD.
2060 2061 2062 2063 2064
 */
static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
    struct ifaddrs *ifa, *origifa;

    if (getifaddrs(&origifa) != 0) {
2065 2066
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "getifaddrs() failed");
2067 2068 2069 2070
        return ifs;
    }

    for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
2071
        // ignore non IPv6 addresses
2072 2073 2074
        if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET6)
            continue;

2075 2076 2077
        // set scope ID to interface index
        ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id =
            getIndex(sock, ifa->ifa_name);
2078

2079 2080 2081 2082 2083
        // add interface to the list
        ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, NULL,
                    AF_INET6,
                    translateIPv6AddressToPrefix((struct sockaddr_in6 *)
                                                 ifa->ifa_netmask));
2084

2085
        // if an exception occurred then free the list
2086 2087 2088 2089 2090 2091 2092
        if ((*env)->ExceptionOccurred(env)) {
            freeifaddrs(origifa);
            freeif(ifs);
            return NULL;
        }
    }

2093
    // free ifaddrs buffer
2094 2095 2096 2097
    freeifaddrs(origifa);
    return ifs;
}

2098 2099 2100 2101 2102
#endif /* AF_INET6 */

/*
 * Try to get the interface index.
 */
2103
static int getIndex(int sock, const char *name) {
2104 2105 2106 2107
#if !defined(__FreeBSD__)
    int index = if_nametoindex(name);
    return (index == 0) ? -1 : index;
#else
2108
    struct ifreq if2;
2109 2110
    memset((char *)&if2, 0, sizeof(if2));
    strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);
2111 2112 2113 2114 2115 2116 2117 2118 2119

    if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
        return -1;
    }

    return if2.ifr_index;
#endif
}

2120 2121
/*
 * Gets the Hardware address (usually MAC address) for the named interface.
2122
 * On return puts the data in buf, and returns the length, in byte, of the
2123 2124
 * MAC address. Returns -1 if there is no hardware address on that interface.
 */
2125
static int getMacAddress
2126
  (JNIEnv *env, const char *ifname, const struct in_addr *addr,
2127 2128
   unsigned char *buf)
{
2129 2130 2131 2132
    struct ifaddrs *ifa0, *ifa;
    struct sockaddr *saddr;
    int i;

2133
    // grab the interface list
2134
    if (!getifaddrs(&ifa0)) {
2135
        // cycle through the interfaces
2136 2137
        for (i = 0, ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next, i++) {
            saddr = ifa->ifa_addr;
2138
            // link layer contains the MAC address
2139 2140
            if (saddr->sa_family == AF_LINK && !strcmp(ifname, ifa->ifa_name)) {
                struct sockaddr_dl *sadl = (struct sockaddr_dl *) saddr;
2141
                // check the address has the correct length
2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154
                if (sadl->sdl_alen == ETHER_ADDR_LEN) {
                    memcpy(buf, (sadl->sdl_data + sadl->sdl_nlen), ETHER_ADDR_LEN);
                    freeifaddrs(ifa0);
                    return ETHER_ADDR_LEN;
                }
            }
        }
        freeifaddrs(ifa0);
    }

    return -1;
}

2155
static int getMTU(JNIEnv *env, int sock, const char *ifname) {
2156
    struct ifreq if2;
2157 2158
    memset((char *)&if2, 0, sizeof(if2));
    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
2159 2160

    if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
2161 2162
        NET_ThrowByNameWithLastError
            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");
2163 2164 2165
        return -1;
    }

2166
    return if2.ifr_mtu;
2167 2168
}

2169
static int getFlags(int sock, const char *ifname, int *flags) {
2170 2171 2172
    struct ifreq if2;
    memset((char *)&if2, 0, sizeof(if2));
    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
2173

2174 2175 2176
    if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
        return -1;
    }
2177

2178 2179 2180 2181 2182 2183
    if (sizeof(if2.ifr_flags) == sizeof(short)) {
        *flags = (if2.ifr_flags & 0xffff);
    } else {
        *flags = if2.ifr_flags;
    }
    return 0;
2184
}
2185
#endif /* _ALLBSD_SOURCE */