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 "net_util.h"
26 #include "NetworkInterface.h"
27 
28 #include "java_net_InetAddress.h"
29 #include "java_net_NetworkInterface.h"
30 
31 /*
32  * Windows implementation of the java.net.NetworkInterface native methods.
33  * This module provides the implementations of getAll, getByName, getByIndex,
34  * and getByAddress.
35  *
36  * Interfaces and addresses are enumerated using the IP helper routines
37  * GetIfTable, GetIfAddrTable resp. These routines are available on Windows
38  * 98, NT SP+4, 2000, and XP. They are also available on Windows 95 if
39  * IE is upgraded to 5.x.
40  *
41  * Windows does not have any standard for device names so we are forced
42  * to use our own convention which is based on the normal Unix naming
43  * convention ("lo" for the loopback, eth0, eth1, .. for ethernet devices,
44  * tr0, tr1, .. for token ring, and so on). This convention gives us
45  * consistency across multiple Windows editions and also consistency with
46  * Solaris/Linux device names. Note that we always enumerate in index
47  * order and this ensures consistent device number across invocations.
48  */
49 
50 /* various JNI ids */
51 
52 jclass ni_class;            /* NetworkInterface */
53 
54 jmethodID ni_ctor;          /* NetworkInterface() */
55 
56 jfieldID ni_indexID;        /* NetworkInterface.index */
57 jfieldID ni_addrsID;        /* NetworkInterface.addrs */
58 jfieldID ni_bindsID;        /* NetworkInterface.bindings */
59 jfieldID ni_nameID;         /* NetworkInterface.name */
60 jfieldID ni_displayNameID;  /* NetworkInterface.displayName */
61 jfieldID ni_childsID;       /* NetworkInterface.childs */
62 
63 jclass ni_ibcls;            /* InterfaceAddress */
64 jmethodID ni_ibctrID;       /* InterfaceAddress() */
65 jfieldID ni_ibaddressID;        /* InterfaceAddress.address */
66 jfieldID ni_ibbroadcastID;      /* InterfaceAddress.broadcast */
67 jfieldID ni_ibmaskID;           /* InterfaceAddress.maskLength */
68 
69 /*
70  * Support routines to free netif and netaddr lists
71  */
free_netif(netif * netifP)72 void free_netif(netif *netifP) {
73     netif *curr = netifP;
74     while (curr != NULL) {
75         if (curr->name != NULL)
76             free(curr->name);
77         if (curr->displayName != NULL)
78             free(curr->displayName);
79         if (curr->addrs != NULL)
80             free_netaddr (curr->addrs);
81         netifP = netifP->next;
82         free(curr);
83         curr = netifP;
84     }
85 }
86 
free_netaddr(netaddr * netaddrP)87 void free_netaddr(netaddr *netaddrP) {
88     netaddr *curr = netaddrP;
89     while (curr != NULL) {
90         netaddrP = netaddrP->next;
91         free(curr);
92         curr = netaddrP;
93     }
94 }
95 
96 /*
97  * Returns the interface structure from the table with the matching index.
98  */
getIF(jint index)99 MIB_IFROW *getIF(jint index) {
100     MIB_IFTABLE *tableP;
101     MIB_IFROW *ifrowP, *ret = NULL;
102     ULONG size;
103     DWORD i, count;
104     jint ifindex;
105 
106     /*
107      * Ask the IP Helper library to enumerate the adapters
108      */
109     size = sizeof(MIB_IFTABLE);
110     tableP = (MIB_IFTABLE *)malloc(size);
111     if(tableP == NULL)
112         return NULL;
113 
114     count = GetIfTable(tableP, &size, TRUE);
115     if (count == ERROR_INSUFFICIENT_BUFFER || count == ERROR_BUFFER_OVERFLOW) {
116         MIB_IFTABLE* newTableP =  (MIB_IFTABLE *)realloc(tableP, size);
117         if (newTableP == NULL) {
118             free(tableP);
119             return NULL;
120         }
121         tableP = newTableP;
122 
123         count = GetIfTable(tableP, &size, TRUE);
124     }
125 
126     if (count != NO_ERROR) {
127         free(tableP);
128         return NULL;
129     }
130 
131     {
132     ifrowP = tableP->table;
133     for (i=0; i<tableP->dwNumEntries; i++) {
134     /*
135      * Warning: the real index is obtained by GetFriendlyIfIndex()
136     */
137         ifindex = GetFriendlyIfIndex(ifrowP->dwIndex);
138         if (ifindex == index) {
139           /*
140            * Create a copy of the entry so that we can free the table.
141            */
142             ret = (MIB_IFROW *) malloc(sizeof(MIB_IFROW));
143             if (ret == NULL) {
144                 free(tableP);
145                 return NULL;
146             }
147             memcpy(ret, ifrowP, sizeof(MIB_IFROW));
148             break;
149         }
150 
151         /* onto the next interface */
152         ifrowP++;
153       }
154       free(tableP);
155     }
156     return ret;
157 }
158 
159 /*
160  * Enumerate network interfaces using IP Helper Library routine GetIfTable.
161  * We use GetIfTable rather than other IP helper routines because it's
162  * available on 98 & NT SP4+.
163  *
164  * Returns the number of interfaces found or -1 if error. If no error
165  * occurs then netifPP be returned as list of netif structures or NULL
166  * if no interfaces are found.
167  */
enumInterfaces(JNIEnv * env,netif ** netifPP)168 int enumInterfaces(JNIEnv *env, netif **netifPP)
169 {
170     MIB_IFTABLE *tableP;
171     MIB_IFROW *ifrowP;
172     ULONG size;
173     DWORD ret;
174     int count;
175     netif *netifP;
176     DWORD i;
177     int lo=0, eth=0, tr=0, fddi=0, ppp=0, sl=0, wlan=0, net=0, wlen=0;
178 
179     /*
180      * Ask the IP Helper library to enumerate the adapters
181      */
182     size = sizeof(MIB_IFTABLE);
183     tableP = (MIB_IFTABLE *)malloc(size);
184     if (tableP == NULL) {
185         JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
186         return -1;
187     }
188 
189     ret = GetIfTable(tableP, &size, TRUE);
190     if (ret == ERROR_INSUFFICIENT_BUFFER || ret == ERROR_BUFFER_OVERFLOW) {
191         MIB_IFTABLE * newTableP = (MIB_IFTABLE *)realloc(tableP, size);
192         if (newTableP == NULL) {
193             free(tableP);
194             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
195             return -1;
196         }
197         tableP = newTableP;
198         ret = GetIfTable(tableP, &size, TRUE);
199     }
200 
201     if (ret != NO_ERROR) {
202         free(tableP);
203 
204         JNU_ThrowByName(env, "java/lang/Error",
205                 "IP Helper Library GetIfTable function failed");
206         // this different error code is to handle the case when we call
207         // GetIpAddrTable in pure IPv6 environment
208         return -2;
209     }
210 
211     /*
212      * Iterate through the list of adapters
213      */
214     count = 0;
215     netifP = NULL;
216 
217     ifrowP = tableP->table;
218     for (i=0; i<tableP->dwNumEntries; i++) {
219         char dev_name[8];
220         netif *curr;
221 
222         /*
223          * Generate a name for the device as Windows doesn't have any
224          * real concept of a device name.
225          */
226         switch (ifrowP->dwType) {
227             case MIB_IF_TYPE_ETHERNET:
228                 _snprintf_s(dev_name, 8, _TRUNCATE, "eth%d", eth++);
229                 break;
230 
231             case MIB_IF_TYPE_TOKENRING:
232                 _snprintf_s(dev_name, 8, _TRUNCATE, "tr%d", tr++);
233                 break;
234 
235             case MIB_IF_TYPE_FDDI:
236                 _snprintf_s(dev_name, 8, _TRUNCATE, "fddi%d", fddi++);
237                 break;
238 
239             case MIB_IF_TYPE_LOOPBACK:
240                 /* There should only be only IPv4 loopback address */
241                 if (lo > 0) {
242                     continue;
243                 }
244                 strncpy_s(dev_name, 8, "lo", _TRUNCATE);
245                 lo++;
246                 break;
247 
248             case MIB_IF_TYPE_PPP:
249                 _snprintf_s(dev_name, 8, _TRUNCATE, "ppp%d", ppp++);
250                 break;
251 
252             case MIB_IF_TYPE_SLIP:
253                 _snprintf_s(dev_name, 8, _TRUNCATE, "sl%d", sl++);
254                 break;
255 
256             case IF_TYPE_IEEE80211:
257                 _snprintf_s(dev_name, 8, _TRUNCATE, "wlan%d", wlan++);
258                 break;
259 
260             default:
261                 _snprintf_s(dev_name, 8, _TRUNCATE, "net%d", net++);
262         }
263 
264         /*
265          * Allocate a netif structure and space for the name and
266          * display name (description in this case).
267          */
268         curr = (netif *)calloc(1, sizeof(netif));
269         if (curr != NULL) {
270             wlen = MultiByteToWideChar(CP_OEMCP, 0, ifrowP->bDescr,
271                        ifrowP->dwDescrLen, NULL, 0);
272             if(wlen == 0) {
273                 // MultiByteToWideChar should not fail
274                 // But in rare case it fails, we allow 'char' to be displayed
275                 curr->displayName = (char *)malloc(ifrowP->dwDescrLen + 1);
276             } else {
277                 curr->displayName = (wchar_t *)malloc((wlen+1)*sizeof(wchar_t));
278             }
279 
280             curr->name = (char *)malloc(strlen(dev_name) + 1);
281 
282             if (curr->name == NULL || curr->displayName == NULL) {
283                 if (curr->name) free(curr->name);
284                 if (curr->displayName) free(curr->displayName);
285                 free(curr);
286                 curr = NULL;
287             }
288         }
289         if (curr == NULL) {
290             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
291             free_netif(netifP);
292             free(tableP);
293             return -1;
294         }
295 
296         /*
297          * Populate the interface. Note that we need to convert the
298          * index into its "friendly" value as otherwise we will expose
299          * 32-bit numbers as index values.
300          */
301         strcpy(curr->name, dev_name);
302         if (wlen == 0) {
303             // display char type in case of MultiByteToWideChar failure
304             strncpy(curr->displayName, ifrowP->bDescr, ifrowP->dwDescrLen);
305             curr->displayName[ifrowP->dwDescrLen] = '\0';
306         } else {
307             // call MultiByteToWideChar again to fill curr->displayName
308             // it should not fail, because we have called it once before
309             if (MultiByteToWideChar(CP_OEMCP, 0, ifrowP->bDescr,
310                    ifrowP->dwDescrLen, curr->displayName, wlen) == 0) {
311                 JNU_ThrowByName(env, "java/lang/Error",
312                        "Cannot get multibyte char for interface display name");
313                 free_netif(netifP);
314                 free(tableP);
315                 free(curr->name);
316                 free(curr->displayName);
317                 free(curr);
318                 return -1;
319             } else {
320                 ((wchar_t *)curr->displayName)[wlen] = L'\0';
321                 curr->dNameIsUnicode = TRUE;
322             }
323         }
324 
325         curr->dwIndex = ifrowP->dwIndex;
326         curr->ifType = ifrowP->dwType;
327         curr->index = GetFriendlyIfIndex(ifrowP->dwIndex);
328 
329         /*
330          * Put the interface at tail of list as GetIfTable(,,TRUE) is
331          * returning the interfaces in index order.
332          */
333         count++;
334         if (netifP == NULL) {
335             netifP = curr;
336         } else {
337             netif *tail = netifP;
338             while (tail->next != NULL) {
339                 tail = tail->next;
340             }
341             tail->next = curr;
342         }
343 
344         /* onto the next interface */
345         ifrowP++;
346     }
347 
348     /*
349      * Free the interface table and return the interface list
350      */
351     if (tableP != NULL) {
352         free(tableP);
353     }
354     *netifPP = netifP;
355     return count;
356 }
357 
358 /*
359  * Enumerate all addresses using the IP helper library
360  */
lookupIPAddrTable(JNIEnv * env,MIB_IPADDRTABLE ** tablePP)361 int lookupIPAddrTable(JNIEnv *env, MIB_IPADDRTABLE **tablePP)
362 {
363     MIB_IPADDRTABLE *tableP;
364     ULONG size;
365     DWORD ret;
366     /*
367      * Use GetIpAddrTable to enumerate the IP Addresses
368      */
369     size = sizeof(MIB_IPADDRTABLE);
370     tableP = (MIB_IPADDRTABLE *)malloc(size);
371     if (tableP == NULL) {
372         JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
373         return -1;
374     }
375 
376     ret = GetIpAddrTable(tableP, &size, FALSE);
377     if (ret == ERROR_INSUFFICIENT_BUFFER || ret == ERROR_BUFFER_OVERFLOW) {
378         MIB_IPADDRTABLE * newTableP = (MIB_IPADDRTABLE *)realloc(tableP, size);
379         if (newTableP == NULL) {
380             free(tableP);
381             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
382             return -1;
383         }
384         tableP = newTableP;
385 
386         ret = GetIpAddrTable(tableP, &size, FALSE);
387     }
388     if (ret != NO_ERROR) {
389         if (tableP != NULL) {
390             free(tableP);
391         }
392         JNU_ThrowByName(env, "java/lang/Error",
393                 "IP Helper Library GetIpAddrTable function failed");
394         // this different error code is to handle the case when we call
395         // GetIpAddrTable in pure IPv6 environment
396         return -2;
397     }
398     *tablePP = tableP;
399     return 0;
400 }
401 
402 /*
403  * Enumerate the IP addresses on an interface, given an IP address table
404  * and matching based on index.
405  *
406  * Returns the count of addresses, or -1 if error. If no error occurs then
407  * netaddrPP will return a list of netaddr structures with the IP addresses.
408  */
enumAddresses_win_ipaddrtable(JNIEnv * env,netif * netifP,netaddr ** netaddrPP,MIB_IPADDRTABLE * tableP)409 int enumAddresses_win_ipaddrtable(JNIEnv *env, netif *netifP, netaddr **netaddrPP, MIB_IPADDRTABLE *tableP)
410 {
411     DWORD i;
412     netaddr *netaddrP;
413     int count = 0;
414     unsigned long mask;
415 
416     /*
417      * Iterate through the table to find the addresses with the
418      * matching dwIndex. Ignore 0.0.0.0 addresses.
419      */
420     if (tableP == NULL)
421         return 0;
422     count = 0;
423     netaddrP = NULL;
424 
425     i = 0;
426     while (i < tableP->dwNumEntries) {
427         if (tableP->table[i].dwIndex == netifP->dwIndex &&
428             tableP->table[i].dwAddr != 0) {
429 
430             netaddr *curr = (netaddr *)malloc(sizeof(netaddr));
431             if (curr == NULL) {
432                 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
433                 free_netaddr(netaddrP);
434                 free(tableP);
435                 return -1;
436             }
437 
438             curr->addr.sa4.sin_family = AF_INET;
439             curr->addr.sa4.sin_addr.s_addr = tableP->table[i].dwAddr;
440             /*
441              * Get netmask / broadcast address
442              */
443             switch (netifP->ifType) {
444             case MIB_IF_TYPE_ETHERNET:
445             case MIB_IF_TYPE_TOKENRING:
446             case MIB_IF_TYPE_FDDI:
447             case MIB_IF_TYPE_LOOPBACK:
448             case IF_TYPE_IEEE80211:
449                 /**
450                  * Contrary to what it seems to indicate, dwBCastAddr doesn't
451                  * contain the broadcast address but 0 or 1 depending on whether
452                  * the broadcast address should set the bits of the host part
453                  * to 0 or 1.
454                  * Yes, I know it's stupid, but what can I say, it's MSFTs API.
455                  */
456                 curr->brdcast.sa4.sin_family = AF_INET;
457                 if (tableP->table[i].dwBCastAddr == 1)
458                     curr->brdcast.sa4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask) | (0xffffffff ^ tableP->table[i].dwMask);
459                 else
460                     curr->brdcast.sa4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask);
461                 mask = ntohl(tableP->table[i].dwMask);
462                 curr->mask = 0;
463                 while (mask) {
464                     mask <<= 1;
465                     curr->mask++;
466                 }
467                 break;
468             case MIB_IF_TYPE_PPP:
469             case MIB_IF_TYPE_SLIP:
470             default:
471                 /**
472                  * these don't have broadcast/subnet
473                  */
474                 curr->mask = -1;
475                     break;
476             }
477 
478             curr->next = netaddrP;
479             netaddrP = curr;
480             count++;
481         }
482         i++;
483     }
484 
485     *netaddrPP = netaddrP;
486     return count;
487 }
488 
489 
490 /*
491  * Enumerate the IP addresses on an interface, using an IP address table
492  * retrieved using GetIPAddrTable and matching based on index.
493  *
494  * Returns the count of addresses, or -1 if error. If no error occurs then
495  * netaddrPP will return a list of netaddr structures with the IP addresses.
496  */
enumAddresses_win(JNIEnv * env,netif * netifP,netaddr ** netaddrPP)497 int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP) {
498     MIB_IPADDRTABLE *tableP;
499     int count;
500     int ret = lookupIPAddrTable(env, &tableP);
501     if (ret < 0) {
502       return NULL;
503     }
504     count = enumAddresses_win_ipaddrtable(env, netifP, netaddrPP, tableP);
505     free(tableP);
506     return count;
507 }
508 
509 
510 /*
511  * Class:     java_net_NetworkInterface
512  * Method:    init
513  * Signature: ()V
514  */
515 JNIEXPORT void JNICALL
Java_java_net_NetworkInterface_init(JNIEnv * env,jclass cls)516 Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls)
517 {
518     /*
519      * Get the various JNI ids that we require
520      */
521     ni_class = (*env)->NewGlobalRef(env, cls);
522     CHECK_NULL(ni_class);
523     ni_nameID = (*env)->GetFieldID(env, ni_class, "name", "Ljava/lang/String;");
524     CHECK_NULL(ni_nameID);
525     ni_displayNameID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;");
526     CHECK_NULL(ni_displayNameID);
527     ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
528     CHECK_NULL(ni_indexID);
529     ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;");
530     CHECK_NULL(ni_addrsID);
531     ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;");
532     CHECK_NULL(ni_bindsID);
533     ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;");
534     CHECK_NULL(ni_childsID);
535     ni_ctor = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
536     CHECK_NULL(ni_ctor);
537     ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
538     CHECK_NULL(ni_ibcls);
539     ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
540     CHECK_NULL(ni_ibcls);
541     ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
542     CHECK_NULL(ni_ibctrID);
543     ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;");
544     CHECK_NULL(ni_ibaddressID);
545     ni_ibbroadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;");
546     CHECK_NULL(ni_ibbroadcastID);
547     ni_ibmaskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
548     CHECK_NULL(ni_ibmaskID);
549 
550     initInetAddressIDs(env);
551 }
552 
553 /*
554  * Create a NetworkInterface object, populate the name and index, and
555  * populate the InetAddress array based on the IP addresses for this
556  * interface.
557  */
createNetworkInterface(JNIEnv * env,netif * ifs,int netaddrCount,netaddr * netaddrP)558 jobject createNetworkInterface
559     (JNIEnv *env, netif *ifs, int netaddrCount, netaddr *netaddrP)
560 {
561     jobject netifObj;
562     jobject name, displayName;
563     jobjectArray addrArr, bindsArr, childArr;
564     netaddr *addrs;
565     jint addr_index;
566     jint bind_index;
567 
568     /*
569      * Create a NetworkInterface object and populate it
570      */
571     netifObj = (*env)->NewObject(env, ni_class, ni_ctor);
572     CHECK_NULL_RETURN(netifObj, NULL);
573     name = (*env)->NewStringUTF(env, ifs->name);
574     CHECK_NULL_RETURN(name, NULL);
575     if (ifs->dNameIsUnicode) {
576         displayName = (*env)->NewString(env, (PWCHAR)ifs->displayName,
577                                        (jsize)wcslen ((PWCHAR)ifs->displayName));
578     } else {
579         displayName = (*env)->NewStringUTF(env, ifs->displayName);
580     }
581     CHECK_NULL_RETURN(displayName, NULL);
582     (*env)->SetObjectField(env, netifObj, ni_nameID, name);
583     (*env)->SetObjectField(env, netifObj, ni_displayNameID, displayName);
584     (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
585 
586     /*
587      * Get the IP addresses for this interface if necessary
588      * Note that 0 is a valid number of addresses.
589      */
590     if (netaddrCount < 0) {
591         netaddrCount = enumAddresses_win(env, ifs, &netaddrP);
592         if (netaddrCount < 0) {
593             return NULL;
594         }
595     }
596     addrArr = (*env)->NewObjectArray(env, netaddrCount, ia_class, NULL);
597     if (addrArr == NULL) {
598         free_netaddr(netaddrP);
599         return NULL;
600     }
601 
602     bindsArr = (*env)->NewObjectArray(env, netaddrCount, ni_ibcls, NULL);
603     if (bindsArr == NULL) {
604       free_netaddr(netaddrP);
605       return NULL;
606     }
607     addrs = netaddrP;
608     addr_index = 0;
609     bind_index = 0;
610     while (addrs != NULL) {
611         jobject iaObj, ia2Obj;
612         jobject ibObj = NULL;
613         if (addrs->addr.sa.sa_family == AF_INET) {
614             iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
615             if (iaObj == NULL) {
616                 free_netaddr(netaddrP);
617                 return NULL;
618             }
619             /* default ctor will set family to AF_INET */
620 
621             setInetAddress_addr(env, iaObj, ntohl(addrs->addr.sa4.sin_addr.s_addr));
622             if ((*env)->ExceptionCheck(env)) {
623                 free_netaddr(netaddrP);
624                 return NULL;
625             }
626             if (addrs->mask != -1) {
627               ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
628               if (ibObj == NULL) {
629                 free_netaddr(netaddrP);
630                 return NULL;
631               }
632               (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
633               ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
634               if (ia2Obj == NULL) {
635                 free_netaddr(netaddrP);
636                 return NULL;
637               }
638               setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.sa4.sin_addr.s_addr));
639               if ((*env)->ExceptionCheck(env)) {
640                   free_netaddr(netaddrP);
641                   return NULL;
642               }
643               (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj);
644               (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
645               (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
646             }
647         } else /* AF_INET6 */ {
648             int scope;
649             iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
650             if (iaObj) {
651                 jboolean ret = setInet6Address_ipaddress(env, iaObj,  (jbyte *)&(addrs->addr.sa6.sin6_addr.s6_addr));
652                 if (ret == JNI_FALSE) {
653                     free_netaddr(netaddrP);
654                     return NULL;
655                 }
656 
657                 scope = addrs->addr.sa6.sin6_scope_id;
658                 if (scope != 0) { /* zero is default value, no need to set */
659                     setInet6Address_scopeid(env, iaObj, scope);
660                     setInet6Address_scopeifname(env, iaObj, netifObj);
661                 }
662                 ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
663                 if (ibObj == NULL) {
664                   free_netaddr(netaddrP);
665                   return NULL;
666                 }
667                 (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
668                 (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
669                 (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
670             }
671         }
672         (*env)->SetObjectArrayElement(env, addrArr, addr_index, iaObj);
673         addrs = addrs->next;
674         addr_index++;
675     }
676     (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
677     (*env)->SetObjectField(env, netifObj, ni_bindsID, bindsArr);
678 
679     free_netaddr(netaddrP);
680 
681     /*
682      * Windows doesn't have virtual interfaces, so child array
683      * is always empty.
684      */
685     childArr = (*env)->NewObjectArray(env, 0, ni_class, NULL);
686     if (childArr == NULL) {
687       return NULL;
688     }
689     (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
690 
691     /* return the NetworkInterface */
692     return netifObj;
693 }
694 
695 /*
696  * Class:     java_net_NetworkInterface
697  * Method:    getByName0
698  * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
699  */
Java_java_net_NetworkInterface_getByName0(JNIEnv * env,jclass cls,jstring name)700 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0
701     (JNIEnv *env, jclass cls, jstring name)
702 {
703     netif *ifList, *curr;
704     jboolean isCopy;
705     const char *name_utf;
706     jobject netifObj = NULL;
707 
708     // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
709     if (ipv6_available()) {
710         return Java_java_net_NetworkInterface_getByName0_XP (env, cls, name);
711     }
712 
713     /* get the list of interfaces */
714     if (enumInterfaces(env, &ifList) < 0) {
715         return NULL;
716     }
717 
718     /* get the name as a C string */
719     name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
720     if (name_utf != NULL) {
721 
722         /* Search by name */
723         curr = ifList;
724         while (curr != NULL) {
725             if (strcmp(name_utf, curr->name) == 0) {
726                 break;
727             }
728             curr = curr->next;
729         }
730 
731         /* if found create a NetworkInterface */
732         if (curr != NULL) {;
733             netifObj = createNetworkInterface(env, curr, -1, NULL);
734         }
735 
736         /* release the UTF string */
737         (*env)->ReleaseStringUTFChars(env, name, name_utf);
738     } else {
739         if (!(*env)->ExceptionCheck(env))
740             JNU_ThrowOutOfMemoryError(env, NULL);
741     }
742 
743     /* release the interface list */
744     free_netif(ifList);
745 
746     return netifObj;
747 }
748 
749 /*
750  * Class:     NetworkInterface
751  * Method:    getByIndex0
752  * Signature: (I)LNetworkInterface;
753  */
Java_java_net_NetworkInterface_getByIndex0(JNIEnv * env,jclass cls,jint index)754 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0
755   (JNIEnv *env, jclass cls, jint index)
756 {
757     netif *ifList, *curr;
758     jobject netifObj = NULL;
759 
760     // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
761     if (ipv6_available()) {
762         return Java_java_net_NetworkInterface_getByIndex0_XP (env, cls, index);
763     }
764 
765     /* get the list of interfaces */
766     if (enumInterfaces(env, &ifList) < 0) {
767         return NULL;
768     }
769 
770     /* search by index */
771     curr = ifList;
772     while (curr != NULL) {
773         if (index == curr->index) {
774             break;
775         }
776         curr = curr->next;
777     }
778 
779     /* if found create a NetworkInterface */
780     if (curr != NULL) {
781         netifObj = createNetworkInterface(env, curr, -1, NULL);
782     }
783 
784     /* release the interface list */
785     free_netif(ifList);
786 
787     return netifObj;
788 }
789 
790 
791 /*
792  * Class:     java_net_NetworkInterface
793  * Method:    boundInetAddress0
794  * Signature: (Ljava/net/InetAddress;)Z
795  */
Java_java_net_NetworkInterface_boundInetAddress0(JNIEnv * env,jclass cls,jobject iaObj)796 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0
797     (JNIEnv *env, jclass cls, jobject iaObj)
798 {
799     jobject netifObj = NULL;
800     DWORD i;
801 
802     int family = getInetAddress_family(env, iaObj);
803     JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
804 
805     if (family == java_net_InetAddress_IPv6) {
806         if (!ipv6_available())
807             return JNI_FALSE;
808         return Java_java_net_NetworkInterface_getByInetAddress0_XP(env, cls, iaObj) != NULL;
809     } else if (family == java_net_InetAddress_IPv4) {
810         jint addr = getInetAddress_addr(env, iaObj);
811         JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
812 
813         jboolean found = JNI_FALSE;
814         MIB_IPADDRTABLE *tableP;
815         if (lookupIPAddrTable(env, &tableP) >= 0 && tableP != NULL) {
816             for (i = 0; i < tableP->dwNumEntries; i++) {
817                 if (tableP->table[i].dwAddr != 0 &&
818                     (unsigned long)addr == ntohl(tableP->table[i].dwAddr)) {
819                     found = JNI_TRUE;
820                     break;
821                 }
822             }
823         }
824         if (tableP != NULL) {
825           free(tableP);
826         }
827         return found;
828     } else {
829       // Unknown address family
830       return JNI_FALSE;
831     }
832 }
833 
834 /*
835  * Class:     java_net_NetworkInterface
836  * Method:    getByInetAddress0
837  * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
838  */
Java_java_net_NetworkInterface_getByInetAddress0(JNIEnv * env,jclass cls,jobject iaObj)839 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
840     (JNIEnv *env, jclass cls, jobject iaObj)
841 {
842     netif *ifList, *curr;
843     MIB_IPADDRTABLE *tableP;
844     jobject netifObj = NULL;
845     jint addr = getInetAddress_addr(env, iaObj);
846     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
847 
848     if (ipv6_available()) {
849         return Java_java_net_NetworkInterface_getByInetAddress0_XP (env, cls, iaObj);
850     }
851 
852     /* get the list of interfaces */
853     if (enumInterfaces(env, &ifList) < 0) {
854         return NULL;
855     }
856 
857     /*
858      * Enumerate the addresses on each interface until we find a
859      * matching address.
860      */
861     tableP = NULL;
862     if (lookupIPAddrTable(env, &tableP) >= 0) {
863         curr = ifList;
864         while (curr != NULL) {
865             int count;
866             netaddr *addrList;
867             netaddr *addrP;
868 
869             /* enumerate the addresses on this interface */
870             count = enumAddresses_win_ipaddrtable(env, curr, &addrList, tableP);
871             if (count < 0) {
872                 free_netif(ifList);
873                 free(tableP);
874                 return NULL;
875             }
876 
877             /* iterate through each address */
878             addrP = addrList;
879 
880             while (addrP != NULL) {
881                 if ((unsigned long)addr == ntohl(addrP->addr.sa4.sin_addr.s_addr)) {
882                     break;
883                 }
884                 addrP = addrP->next;
885             }
886 
887             /*
888              * Address matched so create NetworkInterface for this interface
889              * and address list.
890              */
891             if (addrP != NULL) {
892                 /* createNetworkInterface will free addrList */
893                 netifObj = createNetworkInterface(env, curr, count, addrList);
894                 break;
895             }
896 
897             /* on next interface */
898             curr = curr->next;
899         }
900     }
901 
902     /* release the IP address table */
903     if (tableP != NULL)
904         free(tableP);
905 
906     /* release the interface list */
907     free_netif(ifList);
908 
909     return netifObj;
910 }
911 
912 /*
913  * Class:     java_net_NetworkInterface
914  * Method:    getAll
915  * Signature: ()[Ljava/net/NetworkInterface;
916  */
Java_java_net_NetworkInterface_getAll(JNIEnv * env,jclass cls)917 JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll
918     (JNIEnv *env, jclass cls)
919 {
920     int count;
921     netif *ifList = NULL, *curr;
922     jobjectArray netIFArr;
923     jint arr_index;
924 
925     // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
926     if (ipv6_available()) {
927         return Java_java_net_NetworkInterface_getAll_XP (env, cls);
928     }
929 
930     /*
931      * Get list of interfaces
932      */
933     count = enumInterfaces(env, &ifList);
934     if (count < 0) {
935         return NULL;
936     }
937 
938     /* allocate a NetworkInterface array */
939     netIFArr = (*env)->NewObjectArray(env, count, cls, NULL);
940     if (netIFArr == NULL) {
941         free_netif(ifList);
942         return NULL;
943     }
944 
945     /*
946      * Iterate through the interfaces, create a NetworkInterface instance
947      * for each array element and populate the object.
948      */
949     curr = ifList;
950     arr_index = 0;
951     while (curr != NULL) {
952         jobject netifObj;
953 
954         netifObj = createNetworkInterface(env, curr, -1, NULL);
955         if (netifObj == NULL) {
956             free_netif(ifList);
957             return NULL;
958         }
959 
960         /* put the NetworkInterface into the array */
961         (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
962 
963         curr = curr->next;
964     }
965 
966     /* release the interface list */
967     free_netif(ifList);
968 
969     return netIFArr;
970 }
971 
972 /*
973  * Class:     java_net_NetworkInterface
974  * Method:    isUp0
975  * Signature: (Ljava/lang/String;)Z
976  */
Java_java_net_NetworkInterface_isUp0(JNIEnv * env,jclass cls,jstring name,jint index)977 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0
978     (JNIEnv *env, jclass cls, jstring name, jint index) {
979   jboolean ret = JNI_FALSE;
980 
981   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
982   if (ipv6_available()) {
983     return Java_java_net_NetworkInterface_isUp0_XP(env, cls, name, index);
984   } else {
985     MIB_IFROW *ifRowP;
986     ifRowP = getIF(index);
987     if (ifRowP != NULL) {
988       ret = ifRowP->dwAdminStatus == MIB_IF_ADMIN_STATUS_UP &&
989             (ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL ||
990              ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED);
991       free(ifRowP);
992     }
993   }
994     return ret;
995 }
996 
997 /*
998  * Class:     java_net_NetworkInterface
999  * Method:    isP2P0
1000  * Signature: (Ljava/lang/String;I)Z
1001  */
Java_java_net_NetworkInterface_isP2P0(JNIEnv * env,jclass cls,jstring name,jint index)1002 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0
1003     (JNIEnv *env, jclass cls, jstring name, jint index) {
1004   MIB_IFROW *ifRowP;
1005   jboolean ret = JNI_FALSE;
1006 
1007   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
1008   if (ipv6_available()) {
1009     return Java_java_net_NetworkInterface_isP2P0_XP(env, cls, name, index);
1010   } else {
1011     ifRowP = getIF(index);
1012     if (ifRowP != NULL) {
1013       switch(ifRowP->dwType) {
1014       case MIB_IF_TYPE_PPP:
1015       case MIB_IF_TYPE_SLIP:
1016         ret = JNI_TRUE;
1017         break;
1018       }
1019       free(ifRowP);
1020     }
1021   }
1022   return ret;
1023 }
1024 
1025 /*
1026  * Class:     java_net_NetworkInterface
1027  * Method:    isLoopback0
1028  * Signature: (Ljava/lang/String;I)Z
1029  */
Java_java_net_NetworkInterface_isLoopback0(JNIEnv * env,jclass cls,jstring name,jint index)1030 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0
1031     (JNIEnv *env, jclass cls, jstring name, jint index) {
1032   MIB_IFROW *ifRowP;
1033   jboolean ret = JNI_FALSE;
1034 
1035   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
1036   if (ipv6_available()) {
1037     return Java_java_net_NetworkInterface_isLoopback0_XP(env, cls, name, index);
1038   } else {
1039     ifRowP = getIF(index);
1040     if (ifRowP != NULL) {
1041       if (ifRowP->dwType == MIB_IF_TYPE_LOOPBACK)
1042         ret = JNI_TRUE;
1043       free(ifRowP);
1044     }
1045     return ret;
1046   }
1047 }
1048 
1049 /*
1050  * Class:     java_net_NetworkInterface
1051  * Method:    supportsMulticast0
1052  * Signature: (Ljava/lang/String;I)Z
1053  */
Java_java_net_NetworkInterface_supportsMulticast0(JNIEnv * env,jclass cls,jstring name,jint index)1054 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0
1055     (JNIEnv *env, jclass cls, jstring name, jint index) {
1056     return Java_java_net_NetworkInterface_supportsMulticast0_XP(env, cls,
1057                                                                name, index);
1058 }
1059 
1060 /*
1061  * Class:     java_net_NetworkInterface
1062  * Method:    getMacAddr0
1063  * Signature: ([bLjava/lang/String;I)[b
1064  */
Java_java_net_NetworkInterface_getMacAddr0(JNIEnv * env,jclass class,jbyteArray addrArray,jstring name,jint index)1065 JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0
1066     (JNIEnv *env, jclass class, jbyteArray addrArray, jstring name, jint index) {
1067   jbyteArray ret = NULL;
1068   int len;
1069   MIB_IFROW *ifRowP;
1070 
1071   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
1072   if (ipv6_available()) {
1073     return Java_java_net_NetworkInterface_getMacAddr0_XP(env, class, name, index);
1074   } else {
1075     ifRowP = getIF(index);
1076     if (ifRowP != NULL) {
1077       switch(ifRowP->dwType) {
1078       case MIB_IF_TYPE_ETHERNET:
1079       case MIB_IF_TYPE_TOKENRING:
1080       case MIB_IF_TYPE_FDDI:
1081       case IF_TYPE_IEEE80211:
1082         len = ifRowP->dwPhysAddrLen;
1083         if (len > 0) {
1084             ret = (*env)->NewByteArray(env, len);
1085             if (!IS_NULL(ret)) {
1086               (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr);
1087             }
1088         }
1089         break;
1090       }
1091       free(ifRowP);
1092     }
1093     return ret;
1094   }
1095 }
1096 
1097 /*
1098  * Class:       java_net_NetworkInterface
1099  * Method:      getMTU0
1100  * Signature:   ([bLjava/lang/String;I)I
1101  */
Java_java_net_NetworkInterface_getMTU0(JNIEnv * env,jclass class,jstring name,jint index)1102 JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0
1103     (JNIEnv *env, jclass class, jstring name, jint index) {
1104   jint ret = -1;
1105   MIB_IFROW *ifRowP;
1106 
1107   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
1108   if (ipv6_available()) {
1109     return Java_java_net_NetworkInterface_getMTU0_XP(env, class, name, index);
1110   } else {
1111     ifRowP = getIF(index);
1112     if (ifRowP != NULL) {
1113       ret = ifRowP->dwMtu;
1114       free(ifRowP);
1115     }
1116     return ret;
1117   }
1118 }
1119