NetworkInterface.c revision d5476be7c8108697ac20d19ffba3955d392a39fe
1/*
2 * Copyright (c) 2000, 2011, 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
26
27#include <errno.h>
28#include <strings.h>
29#if defined(_ALLBSD_SOURCE) && defined(__OpenBSD__)
30#include <sys/types.h>
31#endif
32#include <netinet/in.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <arpa/inet.h>
38#include <net/if.h>
39#include <net/if_arp.h>
40#include <linux/if_packet.h>
41
42#include <sys/ioctl.h>
43//#include <bits/ioctls.h>
44#include <sys/utsname.h>
45#include <stdio.h>
46#include <ifaddrs.h>
47
48#include "jvm.h"
49#include "jni_util.h"
50#include "net_util.h"
51#include "JNIHelp.h"
52
53#define NATIVE_METHOD(className, functionName, signature) \
54{ #functionName, signature, (void*)(className ## _ ## functionName) }
55
56typedef struct _netaddr  {
57    struct sockaddr *addr;
58    struct sockaddr *brdcast;
59    short mask;
60    int family; /* to make searches simple */
61    struct _netaddr *next;
62} netaddr;
63
64typedef struct _netif {
65    char *name;
66    int index;
67    char virtual;
68
69    uint8_t hwAddrLen;
70    uint8_t *hwAddr;
71    netaddr *addr;
72    struct _netif *childs;
73    struct _netif *next;
74} netif;
75
76/************************************************************************
77 * NetworkInterface
78 */
79
80
81/************************************************************************
82 * NetworkInterface
83 */
84jclass ni_class;
85jfieldID ni_nameID;
86jfieldID ni_indexID;
87jfieldID ni_descID;
88jfieldID ni_addrsID;
89jfieldID ni_bindsID;
90jfieldID ni_virutalID;
91jfieldID ni_childsID;
92jfieldID ni_parentID;
93jfieldID ni_defaultIndexID;
94jfieldID ni_hardwareAddrID;
95jmethodID ni_ctrID;
96
97static jclass ni_iacls;
98static jclass ni_ia4cls;
99static jclass ni_ia6cls;
100static jclass ni_ibcls;
101static jmethodID ni_ia4ctrID;
102static jmethodID ni_ia6ctrID;
103static jmethodID ni_ibctrID;
104static jfieldID ni_ia6ipaddressID;
105static jfieldID ni_ibaddressID;
106static jfieldID ni_ib4broadcastID;
107static jfieldID ni_ib4maskID;
108
109/** Private methods declarations **/
110static jobject createNetworkInterface(JNIEnv *env, netif *ifs);
111static int     getFlags0(JNIEnv *env, jstring  ifname);
112
113static netif  *enumInterfaces(JNIEnv *env);
114
115static netif  *addif(JNIEnv *env, int sock, struct ifaddrs *ifa, netif *ifs);
116static void    freeif(netif *ifs);
117
118static int     openSocket(JNIEnv *env, int proto);
119static int     openSocketWithFallback(JNIEnv *env, const char *ifname);
120
121static int     getIndex(int sock, const char *ifname);
122
123static int     getFlags(int sock, const char *ifname, int *flags);
124static int     getMTU(JNIEnv *env, int sock, const char *ifname);
125
126/******************* Java entry points *****************************/
127
128/*
129 * Class:     java_net_NetworkInterface
130 * Method:    init
131 * Signature: ()V
132 */
133JNIEXPORT void JNICALL
134NetworkInterface_init(JNIEnv *env, jclass cls) {
135    ni_class = (*env)->FindClass(env,"java/net/NetworkInterface");
136    ni_class = (*env)->NewGlobalRef(env, ni_class);
137    ni_nameID = (*env)->GetFieldID(env, ni_class,"name", "Ljava/lang/String;");
138    ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
139    ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;");
140    ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;");
141    ni_descID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;");
142    ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z");
143    ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;");
144    ni_parentID = (*env)->GetFieldID(env, ni_class, "parent", "Ljava/net/NetworkInterface;");
145    ni_hardwareAddrID = (*env)->GetFieldID(env, ni_class, "hardwareAddr", "[B");
146    ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
147
148    ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
149    ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
150    ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
151    ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
152    ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address");
153    ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls);
154    ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
155    ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
156    ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
157    ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V");
158    ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
159    ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B");
160    ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;");
161    ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;");
162    ni_ib4maskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
163    ni_defaultIndexID = (*env)->GetStaticFieldID(env, ni_class, "defaultIndex", "I");
164}
165
166
167/*
168 * Class:     java_net_NetworkInterface
169 * Method:    getByName0
170 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
171 */
172JNIEXPORT jobject JNICALL NetworkInterface_getByName0
173    (JNIEnv *env, jclass cls, jstring name) {
174
175    netif *ifs, *curr;
176    jboolean isCopy;
177    const char* name_utf;
178    jobject obj = NULL;
179
180    ifs = enumInterfaces(env);
181    if (ifs == NULL) {
182        return NULL;
183    }
184
185    name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
186
187    /*
188     * Search the list of interface based on name
189     */
190    curr = ifs;
191    while (curr != NULL) {
192        if (strcmp(name_utf, curr->name) == 0) {
193            break;
194        }
195        curr = curr->next;
196    }
197
198    /* if found create a NetworkInterface */
199    if (curr != NULL) {;
200        obj = createNetworkInterface(env, curr);
201    }
202
203    /* release the UTF string and interface list */
204    (*env)->ReleaseStringUTFChars(env, name, name_utf);
205    freeif(ifs);
206
207    return obj;
208}
209
210
211/*
212 * Class:     java_net_NetworkInterface
213 * Method:    getByIndex0
214 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
215 */
216JNIEXPORT jobject JNICALL NetworkInterface_getByIndex0
217    (JNIEnv *env, jclass cls, jint index) {
218
219    netif *ifs, *curr;
220    jobject obj = NULL;
221
222    if (index <= 0) {
223        return NULL;
224    }
225
226    ifs = enumInterfaces(env);
227    if (ifs == NULL) {
228        return NULL;
229    }
230
231    /*
232     * Search the list of interface based on index
233     */
234    curr = ifs;
235    while (curr != NULL) {
236        if (index == curr->index) {
237            break;
238        }
239        curr = curr->next;
240    }
241
242    /* if found create a NetworkInterface */
243    if (curr != NULL) {;
244        obj = createNetworkInterface(env, curr);
245    }
246
247    freeif(ifs);
248    return obj;
249}
250
251/*
252 * Class:     java_net_NetworkInterface
253 * Method:    getByInetAddress0
254 * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
255 */
256JNIEXPORT jobject JNICALL NetworkInterface_getByInetAddress0
257    (JNIEnv *env, jclass cls, jobject iaObj) {
258
259    netif *ifs, *curr;
260
261    int family = (getInetAddress_family(env, iaObj) == IPv4) ? AF_INET : AF_INET6;
262
263    jobject obj = NULL;
264    jboolean match = JNI_FALSE;
265
266    ifs = enumInterfaces(env);
267    if (ifs == NULL) {
268        return NULL;
269    }
270
271    curr = ifs;
272    while (curr != NULL) {
273        netaddr *addrP = curr->addr;
274
275        /*
276         * Iterate through each address on the interface
277         */
278        while (addrP != NULL) {
279
280            if (family == addrP->family) {
281                if (family == AF_INET) {
282                    int address1 = htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr);
283                    int address2 = getInetAddress_addr(env, iaObj);
284
285                    if (address1 == address2) {
286                        match = JNI_TRUE;
287                        break;
288                    }
289                }
290
291                if (family == AF_INET6) {
292                    jbyte *bytes = (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr);
293                    jbyteArray ipaddress = (*env)->GetObjectField(env, iaObj, ni_ia6ipaddressID);
294                    jbyte caddr[16];
295                    int i;
296
297                    (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddr);
298                    i = 0;
299                    while (i < 16) {
300                        if (caddr[i] != bytes[i]) {
301                            break;
302                        }
303                        i++;
304                    }
305                    if (i >= 16) {
306                        match = JNI_TRUE;
307                        break;
308                    }
309                }
310            }
311
312            if (match) {
313                break;
314            }
315            addrP = addrP->next;
316        }
317
318        if (match) {
319            break;
320        }
321        curr = curr->next;
322    }
323
324    /* if found create a NetworkInterface */
325    if (match) {;
326        obj = createNetworkInterface(env, curr);
327    }
328
329    freeif(ifs);
330    return obj;
331}
332
333
334/*
335 * Class:     java_net_NetworkInterface
336 * Method:    getAll
337 * Signature: ()[Ljava/net/NetworkInterface;
338 */
339JNIEXPORT jobjectArray JNICALL NetworkInterface_getAll
340    (JNIEnv *env, jclass cls) {
341
342    netif *ifs, *curr;
343    jobjectArray netIFArr;
344    jint arr_index, ifCount;
345
346    ifs = enumInterfaces(env);
347    if (ifs == NULL) {
348        return NULL;
349    }
350
351    /* count the interface */
352    ifCount = 0;
353    curr = ifs;
354    while (curr != NULL) {
355        ifCount++;
356        curr = curr->next;
357    }
358
359    /* allocate a NetworkInterface array */
360    netIFArr = (*env)->NewObjectArray(env, ifCount, cls, NULL);
361    if (netIFArr == NULL) {
362        freeif(ifs);
363        return NULL;
364    }
365
366    /*
367     * Iterate through the interfaces, create a NetworkInterface instance
368     * for each array element and populate the object.
369     */
370    curr = ifs;
371    arr_index = 0;
372    while (curr != NULL) {
373        jobject netifObj;
374
375        netifObj = createNetworkInterface(env, curr);
376        if (netifObj == NULL) {
377            freeif(ifs);
378            return NULL;
379        }
380
381        /* put the NetworkInterface into the array */
382        (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
383
384        curr = curr->next;
385    }
386
387    freeif(ifs);
388    return netIFArr;
389}
390
391
392/*
393 * Class:     java_net_NetworkInterface
394 * Method:    isUp0
395 * Signature: (Ljava/lang/String;I)Z
396 */
397JNIEXPORT jboolean JNICALL NetworkInterface_isUp0(JNIEnv *env, jclass cls, jstring name, jint index) {
398    int ret = getFlags0(env, name);
399    return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE :  JNI_FALSE;
400}
401
402/*
403 * Class:     java_net_NetworkInterface
404 * Method:    isP2P0
405 * Signature: (Ljava/lang/String;I)Z
406 */
407JNIEXPORT jboolean JNICALL NetworkInterface_isP2P0(JNIEnv *env, jclass cls, jstring name, jint index) {
408    int ret = getFlags0(env, name);
409    return (ret & IFF_POINTOPOINT) ? JNI_TRUE :  JNI_FALSE;
410}
411
412/*
413 * Class:     java_net_NetworkInterface
414 * Method:    isLoopback0
415 * Signature: (Ljava/lang/String;I)Z
416 */
417JNIEXPORT jboolean JNICALL NetworkInterface_isLoopback0(JNIEnv *env, jclass cls, jstring name, jint index) {
418  int ret = getFlags0(env, name);
419  return (ret & IFF_LOOPBACK) ? JNI_TRUE :  JNI_FALSE;
420}
421
422/*
423 * Class:     java_net_NetworkInterface
424 * Method:    supportsMulticast0
425 * Signature: (Ljava/lang/String;I)Z
426 */
427JNIEXPORT jboolean JNICALL NetworkInterface_supportsMulticast0(JNIEnv *env, jclass cls, jstring name, jint index) {
428  int ret = getFlags0(env, name);
429  return (ret & IFF_MULTICAST) ? JNI_TRUE :  JNI_FALSE;
430}
431
432/*
433 * Class:       java_net_NetworkInterface
434 * Method:      getMTU0
435 * Signature:   ([bLjava/lang/String;I)I
436 */
437
438JNIEXPORT jint JNICALL NetworkInterface_getMTU0(JNIEnv *env, jclass class, jstring name, jint index) {
439  jboolean isCopy;
440  int ret = -1;
441  int sock;
442  const char* name_utf;
443
444  name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
445
446  if ((sock =openSocketWithFallback(env, name_utf)) < 0) {
447    (*env)->ReleaseStringUTFChars(env, name, name_utf);
448    return JNI_FALSE;
449  }
450
451  ret = getMTU(env, sock, name_utf);
452
453  (*env)->ReleaseStringUTFChars(env, name, name_utf);
454
455  close(sock);
456  return ret;
457}
458
459/*** Private methods definitions ****/
460
461static int getFlags0(JNIEnv *env, jstring name) {
462  jboolean isCopy;
463  int ret, sock;
464  const char* name_utf;
465  int flags = 0;
466
467  name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
468
469  if ((sock = openSocketWithFallback(env, name_utf)) < 0) {
470    (*env)->ReleaseStringUTFChars(env, name, name_utf);
471    return -1;
472  }
473
474  name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
475
476  ret = getFlags(sock, name_utf, &flags);
477
478  close(sock);
479  (*env)->ReleaseStringUTFChars(env, name, name_utf);
480
481  if (ret < 0) {
482    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL  SIOCGLIFFLAGS failed");
483    return -1;
484  }
485
486  return flags;
487}
488
489
490
491
492/*
493 * Create a NetworkInterface object, populate the name and index, and
494 * populate the InetAddress array based on the IP addresses for this
495 * interface.
496 */
497jobject createNetworkInterface(JNIEnv *env, netif *ifs) {
498  jobject netifObj;
499  jobject name;
500  jobjectArray addrArr;
501  jobjectArray bindArr;
502  jobjectArray childArr;
503  netaddr *addrs;
504  jint addr_index, addr_count, bind_index;
505  jint child_count, child_index;
506  netaddr *addrP;
507  netif *childP;
508  jobject tmp;
509
510  /*
511   * Create a NetworkInterface object and populate it
512   */
513  netifObj = (*env)->NewObject(env, ni_class, ni_ctrID);
514  name = (*env)->NewStringUTF(env, ifs->name);
515  if (netifObj == NULL || name == NULL) {
516    return NULL;
517  }
518  (*env)->SetObjectField(env, netifObj, ni_nameID, name);
519  (*env)->SetObjectField(env, netifObj, ni_descID, name);
520  (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
521  (*env)->SetBooleanField(env, netifObj, ni_virutalID, ifs->virtual ? JNI_TRUE : JNI_FALSE);
522
523  /*
524   * Set the hardware address
525   */
526  if (ifs->hwAddrLen > 0 && ifs->hwAddr != NULL) {
527    jbyteArray hardwareAddr = (*env)->NewByteArray(env, ifs->hwAddrLen);
528    if (hardwareAddr == NULL) {
529      return NULL;
530    }
531    (*env)->SetByteArrayRegion(env, hardwareAddr, 0, ifs->hwAddrLen, (jbyte *)ifs->hwAddr);
532    (*env)->SetObjectField(env, netifObj, ni_hardwareAddrID, hardwareAddr);
533  }
534
535  /*
536   * Count the number of address on this interface
537   */
538  addr_count = 0;
539  addrP = ifs->addr;
540  while (addrP != NULL) {
541    addr_count++;
542    addrP = addrP->next;
543  }
544
545  /*
546   * Create the array of InetAddresses
547   */
548  addrArr = (*env)->NewObjectArray(env, addr_count,  ni_iacls, NULL);
549  if (addrArr == NULL) {
550    return NULL;
551  }
552
553  bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL);
554  if (bindArr == NULL) {
555    return NULL;
556  }
557  addrP = ifs->addr;
558  addr_index = 0;
559  bind_index = 0;
560  while (addrP != NULL) {
561    jobject iaObj = NULL;
562    jobject ibObj = NULL;
563
564    if (addrP->family == AF_INET) {
565      iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
566      if (iaObj) {
567        setInetAddress_addr(env, iaObj, htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr));
568      }
569      ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
570      if (ibObj) {
571        (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
572        if (addrP->brdcast) {
573          jobject ia2Obj = NULL;
574          ia2Obj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
575          if (ia2Obj) {
576            setInetAddress_addr(env, ia2Obj, htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr));
577            (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj);
578          }
579        }
580        (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
581        (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
582      }
583    }
584
585    if (addrP->family == AF_INET6) {
586      int scope=0;
587      iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
588      if (iaObj) {
589        jbyteArray ipaddress = (*env)->NewByteArray(env, 16);
590        if (ipaddress == NULL) {
591          return NULL;
592        }
593        (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
594                                   (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr));
595
596        scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;
597
598        if (scope != 0) { /* zero is default value, no need to set */
599          (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
600          (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
601          (*env)->SetObjectField(env, iaObj, ia6_scopeifnameID, netifObj);
602        }
603        (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress);
604      }
605      ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
606      if (ibObj) {
607        (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
608        (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
609        (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
610      }
611    }
612
613    if (iaObj == NULL) {
614      return NULL;
615    }
616
617    (*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj);
618    addrP = addrP->next;
619  }
620
621  /*
622   * See if there is any virtual interface attached to this one.
623   */
624  child_count = 0;
625  childP = ifs->childs;
626  while (childP) {
627    child_count++;
628    childP = childP->next;
629  }
630
631  childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL);
632  if (childArr == NULL) {
633    return NULL;
634  }
635
636  /*
637   * Create the NetworkInterface instances for the sub-interfaces as
638   * well.
639   */
640  child_index = 0;
641  childP = ifs->childs;
642  while(childP) {
643    tmp = createNetworkInterface(env, childP);
644    if (tmp == NULL) {
645      return NULL;
646    }
647    (*env)->SetObjectField(env, tmp, ni_parentID, netifObj);
648    (*env)->SetObjectArrayElement(env, childArr, child_index++, tmp);
649    childP = childP->next;
650  }
651  (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
652  (*env)->SetObjectField(env, netifObj, ni_bindsID, bindArr);
653  (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
654
655  /* return the NetworkInterface */
656  return netifObj;
657}
658
659/*
660 * Determines the mask length for IPV4/v6 addresses.
661 */
662static
663int mask_address_to_mask_length(uint8_t *val, int size) {
664  int byte, bit, plen = 0;
665
666  for (byte = 0; byte < size && val[byte] == 0xff; byte++) {
667    plen += 8;
668  }
669  if (byte < size) {
670    for (bit = 7; bit > 0; bit--) {
671      if (val[byte] & (1 << bit)) plen++;
672    }
673  }
674  return plen;
675}
676
677/*
678 * Enumerates all interfaces
679 */
680static netif *enumInterfaces(JNIEnv *env) {
681  netif *ifs = NULL;
682  struct ifaddrs *ifa, *origifa;
683
684  int sock = openSocket(env, AF_INET);
685  if (sock < 0 && (*env)->ExceptionOccurred(env)) {
686    return NULL;
687  }
688
689  if (getifaddrs(&origifa) != 0) {
690    NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException",
691                                 "getifaddrs() function failed");
692    return NULL;
693  }
694
695  for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
696    if (ifa->ifa_addr != NULL) {
697      switch (ifa->ifa_addr->sa_family) {
698        case AF_PACKET:
699        case AF_INET:
700        case AF_INET6:
701          ifs = addif(env, sock, ifa, ifs);
702          break;
703      }
704    }
705  }
706
707  freeifaddrs(origifa);
708  close(sock);
709
710  return ifs;
711}
712
713#define CHECKED_MALLOC3(_pointer,_type,_size) \
714    do{ \
715      _pointer = (_type)malloc( _size ); \
716      if (_pointer == NULL) { \
717        JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \
718        return ifs; /* return untouched list */ \
719      } \
720    } while(0)
721
722
723/*
724 * Free an interface list (including any attached addresses)
725 */
726void freeif(netif *ifs) {
727  netif *currif = ifs;
728  netif *child = NULL;
729
730  while (currif != NULL) {
731    netaddr *addrP = currif->addr;
732    while (addrP != NULL) {
733      netaddr *next = addrP->next;
734      free(addrP);
735      addrP = next;
736    }
737
738    /*
739     * Don't forget to free the sub-interfaces.
740     */
741    if (currif->childs != NULL) {
742      freeif(currif->childs);
743    }
744
745    /*
746     * Remove mac address
747     */
748    if (currif->hwAddr != NULL) {
749      free(currif->hwAddr);
750    }
751
752    ifs = currif->next;
753    free(currif);
754    currif = ifs;
755  }
756}
757
758netif *addif(JNIEnv *env, int sock, struct ifaddrs *ifa, netif *ifs)
759{
760  netif *currif = ifs, *parent;
761  netaddr *addrP = NULL;
762
763  char name[IFNAMSIZ], vname[IFNAMSIZ];
764
765  char  *name_colonP;
766  int mask;
767  int isVirtual = 0;
768  int addr_size;
769  int flags = 0;
770
771  /*
772   * If the interface name is a logical interface then we
773   * remove the unit number so that we have the physical
774   * interface (eg: hme0:1 -> hme0). NetworkInterface
775   * currently doesn't have any concept of physical vs.
776   * logical interfaces.
777   */
778  strncpy(name, ifa->ifa_name, sizeof(name));
779  name[sizeof(name) - 1] = '\0';
780  *vname = 0;
781
782  /*
783   * Create and populate the netaddr node. If allocation fails
784   * return an un-updated list.
785   */
786  switch(ifa->ifa_addr->sa_family) {
787    case AF_INET:
788      addr_size = sizeof(struct sockaddr_in);
789      break;
790    case AF_INET6:
791      addr_size = sizeof(struct sockaddr_in6);
792      break;
793    case AF_PACKET:
794      // Don't add an address entry, will extract data to netif struct
795      addr_size = 0;
796      break;
797    default:
798      return NULL;
799  }
800
801  if (addr_size > 0) {
802    /*Allocate for addr and brdcast at once*/
803    CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr)+2*addr_size);
804    addrP->addr = (struct sockaddr *)( (char *) addrP+sizeof(netaddr) );
805    memcpy(addrP->addr, ifa->ifa_addr, addr_size);
806
807    addrP->family = ifa->ifa_addr->sa_family;
808    addrP->next = 0;
809
810    if (ifa->ifa_broadaddr && (ifa->ifa_flags & IFF_BROADCAST)) {
811      struct sockaddr * brdcast_to = (struct sockaddr *) ((char *) addrP + sizeof(netaddr) + addr_size);
812      addrP->brdcast = brdcast_to;
813      memcpy(brdcast_to, ifa->ifa_broadaddr, sizeof(struct sockaddr));
814    } else {
815      addrP->brdcast = NULL;
816    }
817
818    if (ifa->ifa_netmask) {
819      if (ifa->ifa_netmask->sa_family == AF_INET) {
820        addrP->mask = mask_address_to_mask_length(
821            (uint8_t*)&(((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr),
822            sizeof(struct in_addr));
823      } else if (ifa->ifa_netmask->sa_family == AF_INET6) {
824        addrP->mask = mask_address_to_mask_length(
825            (uint8_t*)&((struct sockaddr_in6*)ifa->ifa_netmask)->sin6_addr,
826            sizeof(struct in6_addr));
827      }
828    } else {
829      addrP->mask = 0;
830    }
831  }
832
833  /**
834   * Deal with virtual interface with colon notaion e.g. eth0:1
835   */
836  name_colonP = strchr(name, ':');
837  if (name_colonP != NULL) {
838    /**
839     * This is a virtual interface. If we are able to access the parent
840     * we need to create a new entry if it doesn't exist yet *and* update
841     * the 'parent' interface with the new records.
842     */
843    *name_colonP = 0;
844    if (getFlags(sock, name, &flags) < 0 || flags < 0) {
845      // failed to access parent interface do not create parent.
846      // We are a virtual interface with no parent.
847      isVirtual = 1;
848      *name_colonP = ':';
849    }
850    else{
851      // Got access to parent, so create it if necessary.
852      // Save original name to vname and truncate name by ':'
853      memcpy(vname, name, sizeof(vname) );
854      vname[name_colonP - name] = ':';
855    }
856  }
857
858  /*
859   * Check if this is a "new" interface. Use the interface
860   * name for matching because index isn't supported on
861   * Solaris 2.6 & 7.
862   */
863  while (currif != NULL) {
864    if (strcmp(name, currif->name) == 0) {
865      break;
866    }
867    currif = currif->next;
868  }
869
870  /*
871   * If "new" then create an netif structure and
872   * insert it onto the list.
873   */
874  if (currif == NULL) {
875    CHECKED_MALLOC3(currif, netif *, sizeof(netif) + sizeof(name));
876    currif->name = (char *) currif+sizeof(netif);
877    strncpy(currif->name, name, sizeof(name));
878    currif->name[sizeof(name) - 1] = '\0';
879    currif->index = getIndex(sock, name);
880    currif->addr = NULL;
881    currif->childs = NULL;
882    currif->virtual = isVirtual;
883    currif->hwAddrLen = 0;
884    currif->hwAddr = NULL;
885    currif->next = ifs;
886    ifs = currif;
887  }
888
889  /*
890   * Insert the mac address on the interface
891   */
892  if (ifa->ifa_addr->sa_family == AF_PACKET) {
893    struct sockaddr_ll *s = (struct sockaddr_ll*)ifa->ifa_addr;
894
895    if (s->sll_halen > 0) {
896      /*
897       * All bytes to 0 means no hardware address.
898       */
899      int i;
900      for (i = 0;i < s->sll_halen; ++i) {
901        if (s->sll_addr[i] != 0) {
902          break;
903        }
904      }
905      if (i != s->sll_halen && currif->hwAddr == NULL) {
906        CHECKED_MALLOC3(currif->hwAddr, uint8_t *, s->sll_halen);
907        memcpy(currif->hwAddr, s->sll_addr, s->sll_halen);
908        currif->hwAddrLen = s->sll_halen;
909      }
910    }
911  }
912
913  /*
914   * Finally insert the address on the interface
915   */
916  if (addrP != NULL) {
917    addrP->next = currif->addr;
918    currif->addr = addrP;
919  }
920
921  parent = currif;
922
923  /**
924   * Let's deal with the virtual interface now.
925   */
926  if (vname[0]) {
927    netaddr *tmpaddr;
928
929    currif = parent->childs;
930
931    while (currif != NULL) {
932      if (strcmp(vname, currif->name) == 0) {
933        break;
934      }
935      currif = currif->next;
936    }
937
938    if (currif == NULL) {
939      CHECKED_MALLOC3(currif, netif *, sizeof(netif) + sizeof(name));
940      currif->name = (char *) currif + sizeof(netif);
941      strncpy(currif->name, vname, sizeof(name));
942      currif->name[sizeof(name) - 1] = '\0';
943      currif->index = getIndex(sock, vname);
944      currif->addr = NULL;
945      /* Need to duplicate the addr entry? */
946      currif->virtual = 1;
947      currif->childs = NULL;
948      currif->next = parent->childs;
949      parent->childs = currif;
950    }
951
952    CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr)+2*addr_size);
953    memcpy(tmpaddr, addrP, sizeof(netaddr));
954    if (addrP->addr != NULL) {
955      tmpaddr->addr = (struct sockaddr *) ( (char*)tmpaddr + sizeof(netaddr) ) ;
956      memcpy(tmpaddr->addr, addrP->addr, addr_size);
957    }
958
959    if (addrP->brdcast != NULL) {
960      tmpaddr->brdcast = (struct sockaddr *) ((char *) tmpaddr + sizeof(netaddr)+addr_size);
961      memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size);
962    }
963
964    tmpaddr->next = currif->addr;
965    currif->addr = tmpaddr;
966  }
967
968  return ifs;
969}
970
971/* Open socket for further ioct calls
972 * proto is AF_INET/AF_INET6
973 */
974static int  openSocket(JNIEnv *env, int proto){
975  int sock;
976
977  if ((sock = JVM_Socket(proto, SOCK_DGRAM, 0)) < 0) {
978    /*
979     * If EPROTONOSUPPORT is returned it means we don't have
980     * support  for this proto so don't throw an exception.
981     */
982    if (errno != EPROTONOSUPPORT) {
983      NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "Socket creation failed");
984    }
985    return -1;
986  }
987
988  return sock;
989}
990
991
992/** Linux **/
993
994/* Open socket for further ioct calls, try v4 socket first and
995 * if it falls return v6 socket
996 */
997
998static int openSocketWithFallback(JNIEnv *env, const char *ifname){
999  int sock;
1000  struct ifreq if2;
1001
1002  if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1003    if (errno == EPROTONOSUPPORT){
1004      if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
1005        NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1006        return -1;
1007      }
1008    }
1009    else{ // errno is not NOSUPPORT
1010      NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1011      return -1;
1012    }
1013  }
1014
1015  /* Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or IPv6 socket regardless of type
1016     of address of an interface */
1017
1018  return sock;
1019}
1020
1021static int getIndex(int sock, const char *name){
1022  /*
1023   * Try to get the interface index
1024   * (Not supported on Solaris 2.6 or 7)
1025   */
1026  struct ifreq if2;
1027  strcpy(if2.ifr_name, name);
1028
1029  if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
1030    return -1;
1031  }
1032
1033  return if2.ifr_ifindex;
1034}
1035
1036static int getMTU(JNIEnv *env, int sock,  const char *ifname) {
1037  struct ifreq if2;
1038
1039  memset((char *) &if2, 0, sizeof(if2));
1040  strcpy(if2.ifr_name, ifname);
1041
1042  if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
1043    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFMTU failed");
1044    return -1;
1045  }
1046
1047  return  if2.ifr_mtu;
1048}
1049
1050static int getFlags(int sock, const char *ifname, int *flags) {
1051  struct ifreq if2;
1052
1053  memset((char *) &if2, 0, sizeof(if2));
1054  strcpy(if2.ifr_name, ifname);
1055
1056  if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0){
1057    return -1;
1058  }
1059
1060  if (sizeof(if2.ifr_flags) == sizeof(short)) {
1061    *flags = (if2.ifr_flags & 0xffff);
1062  } else {
1063    *flags = if2.ifr_flags;
1064  }
1065  return 0;
1066}
1067
1068static JNINativeMethod gMethods[] = {
1069  NATIVE_METHOD(NetworkInterface, getMTU0, "(Ljava/lang/String;I)I"),
1070  NATIVE_METHOD(NetworkInterface, supportsMulticast0, "(Ljava/lang/String;I)Z"),
1071  NATIVE_METHOD(NetworkInterface, isLoopback0, "(Ljava/lang/String;I)Z"),
1072  NATIVE_METHOD(NetworkInterface, isP2P0, "(Ljava/lang/String;I)Z"),
1073  NATIVE_METHOD(NetworkInterface, isUp0, "(Ljava/lang/String;I)Z"),
1074  NATIVE_METHOD(NetworkInterface, getAll, "()[Ljava/net/NetworkInterface;"),
1075  NATIVE_METHOD(NetworkInterface, getByInetAddress0, "(Ljava/net/InetAddress;)Ljava/net/NetworkInterface;"),
1076  NATIVE_METHOD(NetworkInterface, getByIndex0, "(I)Ljava/net/NetworkInterface;"),
1077  NATIVE_METHOD(NetworkInterface, getByName0, "(Ljava/lang/String;)Ljava/net/NetworkInterface;"),
1078  NATIVE_METHOD(NetworkInterface, init, "()V"),
1079
1080};
1081
1082void register_java_net_NetworkInterface(JNIEnv* env) {
1083  jniRegisterNativeMethods(env, "java/net/NetworkInterface", gMethods, NELEM(gMethods));
1084}
1085