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