• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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