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