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