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