1 /*
2  * Copyright (c) 2000, 2018, 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 #include <errno.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <netdb.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #ifdef _ALLBSD_SOURCE
37 #include <ifaddrs.h>
38 #include <net/if.h>
39 #include <unistd.h> /* gethostname */
40 #endif
41 
42 #include "jvm.h"
43 #include "jni_util.h"
44 #include "net_util.h"
45 #ifndef IPV6_DEFS_H
46 #include <netinet/icmp6.h>
47 #endif
48 
49 #include "java_net_Inet4AddressImpl.h"
50 #include "java_net_Inet6AddressImpl.h"
51 
52 /* the initial size of our hostent buffers */
53 #ifndef NI_MAXHOST
54 #define NI_MAXHOST 1025
55 #endif
56 
57 
58 /************************************************************************
59  * Inet6AddressImpl
60  */
61 
62 /*
63  * Class:     java_net_Inet6AddressImpl
64  * Method:    getLocalHostName
65  * Signature: ()Ljava/lang/String;
66  */
67 JNIEXPORT jstring JNICALL
Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv * env,jobject this)68 Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
69     char hostname[NI_MAXHOST + 1];
70 
71     hostname[0] = '\0';
72     if (JVM_GetHostName(hostname, sizeof(hostname))) {
73         strcpy(hostname, "localhost");
74 #if defined(__solaris__) && defined(AF_INET6)
75     } else {
76         // try to resolve hostname via nameservice
77         // if it is known but getnameinfo fails, hostname will still be the
78         // value from gethostname
79         struct addrinfo hints, *res;
80 
81         // make sure string is null-terminated
82         hostname[NI_MAXHOST] = '\0';
83         memset(&hints, 0, sizeof(hints));
84         hints.ai_flags = AI_CANONNAME;
85         hints.ai_family = AF_UNSPEC;
86 
87         if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
88             getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST,
89                         NULL, 0, NI_NAMEREQD);
90             freeaddrinfo(res);
91         }
92     }
93 #else
94     } else {
95         // make sure string is null-terminated
96         hostname[NI_MAXHOST] = '\0';
97     }
98 #endif
99     return (*env)->NewStringUTF(env, hostname);
100 }
101 
102 #ifdef _ALLBSD_SOURCE
103 /* also called from Inet4AddressImpl.c */
104 jobjectArray
lookupIfLocalhost(JNIEnv * env,const char * hostname,jboolean includeV6)105 lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6)
106 {
107     jobjectArray result = NULL;
108     char myhostname[NI_MAXHOST+1];
109     struct ifaddrs *ifa = NULL;
110     int familyOrder = 0;
111     int count = 0, i, j;
112     int addrs4 = 0, addrs6 = 0, numV4Loopbacks = 0, numV6Loopbacks = 0;
113     jboolean includeLoopback = JNI_FALSE;
114     jobject name;
115 
116     initInetAddressIDs(env);
117     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
118 
119     /* If the requested name matches this host's hostname, return IP addresses
120      * from all attached interfaces. (#2844683 et al) This prevents undesired
121      * PPP dialup, but may return addresses that don't actually correspond to
122      * the name (if the name actually matches something in DNS etc.
123      */
124     myhostname[0] = '\0';
125     if (JVM_GetHostName(myhostname, NI_MAXHOST)) {
126         /* Something went wrong, maybe networking is not setup? */
127         return NULL;
128     }
129     myhostname[NI_MAXHOST] = '\0';
130 
131     if (strcmp(myhostname, hostname) != 0) {
132         // Non-self lookup
133         return NULL;
134     }
135 
136     if (getifaddrs(&ifa) != 0) {
137         NET_ThrowNew(env, errno, "Can't get local interface addresses");
138         return NULL;
139     }
140 
141     name = (*env)->NewStringUTF(env, hostname);
142     if (name == NULL) {
143         freeifaddrs(ifa);
144         return NULL;
145     }
146 
147     /* Iterate over the interfaces, and total up the number of IPv4 and IPv6
148      * addresses we have. Also keep a count of loopback addresses. We need to
149      * exclude them in the normal case, but return them if we don't get an IP
150      * address.
151      */
152     struct ifaddrs *iter = ifa;
153     while (iter) {
154         int family = iter->ifa_addr->sa_family;
155         if (iter->ifa_name[0] != '\0'  &&  iter->ifa_addr)
156         {
157             jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
158             if (family == AF_INET) {
159                 addrs4++;
160                 if (isLoopback) numV4Loopbacks++;
161             } else if (family == AF_INET6 && includeV6) {
162                 addrs6++;
163                 if (isLoopback) numV6Loopbacks++;
164             } else {
165                 /* We don't care e.g. AF_LINK */
166             }
167         }
168         iter = iter->ifa_next;
169     }
170 
171     if (addrs4 == numV4Loopbacks && addrs6 == numV6Loopbacks) {
172         // We don't have a real IP address, just loopback. We need to include
173         // loopback in our results.
174         includeLoopback = JNI_TRUE;
175     }
176 
177     /* Create and fill the Java array. */
178     int arraySize = addrs4 + addrs6 -
179         (includeLoopback ? 0 : (numV4Loopbacks + numV6Loopbacks));
180     result = (*env)->NewObjectArray(env, arraySize, ia_class, NULL);
181     if (!result) goto done;
182 
183     if ((*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID)) {
184         i = includeLoopback ? addrs6 : (addrs6 - numV6Loopbacks);
185         j = 0;
186     } else {
187         i = 0;
188         j = includeLoopback ? addrs4 : (addrs4 - numV4Loopbacks);
189     }
190 
191     // Now loop around the ifaddrs
192     iter = ifa;
193     while (iter != NULL) {
194         jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
195         int family = iter->ifa_addr->sa_family;
196 
197         if (iter->ifa_name[0] != '\0'  &&  iter->ifa_addr
198             && (family == AF_INET || (family == AF_INET6 && includeV6))
199             && (!isLoopback || includeLoopback))
200         {
201             int port;
202             int index = (family == AF_INET) ? i++ : j++;
203             jobject o = NET_SockaddrToInetAddress(env, iter->ifa_addr, &port);
204             if (!o) {
205                 freeifaddrs(ifa);
206                 if (!(*env)->ExceptionCheck(env))
207                     JNU_ThrowOutOfMemoryError(env, "Object allocation failed");
208                 return NULL;
209             }
210             setInetAddress_hostName(env, o, name);
211             if ((*env)->ExceptionCheck(env))
212                 goto done;
213             (*env)->SetObjectArrayElement(env, result, index, o);
214             (*env)->DeleteLocalRef(env, o);
215         }
216         iter = iter->ifa_next;
217     }
218 
219   done:
220     freeifaddrs(ifa);
221 
222     return result;
223 }
224 #endif
225 
226 /*
227  * Find an internet address for a given hostname.  Note that this
228  * code only works for addresses of type INET. The translation
229  * of %d.%d.%d.%d to an address (int) occurs in java now, so the
230  * String "host" shouldn't *ever* be a %d.%d.%d.%d string
231  *
232  * Class:     java_net_Inet6AddressImpl
233  * Method:    lookupAllHostAddr
234  * Signature: (Ljava/lang/String;)[[B
235  */
236 
237 JNIEXPORT jobjectArray JNICALL
Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv * env,jobject this,jstring host)238 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
239                                                 jstring host) {
240     const char *hostname;
241     jobjectArray ret = 0;
242     int retLen = 0;
243 
244     int getaddrinfo_error=0;
245 #ifdef AF_INET6
246     struct addrinfo hints, *res, *resNew = NULL;
247 #endif /* AF_INET6 */
248 
249     initInetAddressIDs(env);
250     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
251 
252     if (IS_NULL(host)) {
253         JNU_ThrowNullPointerException(env, "host is null");
254         return 0;
255     }
256     hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
257     CHECK_NULL_RETURN(hostname, NULL);
258 
259 #ifdef _ALLBSD_SOURCE
260     /*
261      * If we're looking up the local machine, attempt to get the address
262      * from getifaddrs. This ensures we get an IPv6 address for the local
263      * machine.
264      */
265     ret = lookupIfLocalhost(env, hostname, JNI_TRUE);
266     if (ret != NULL || (*env)->ExceptionCheck(env)) {
267         JNU_ReleaseStringPlatformChars(env, host, hostname);
268         return ret;
269     }
270 #endif
271 
272 #ifdef AF_INET6
273     /* Try once, with our static buffer. */
274     memset(&hints, 0, sizeof(hints));
275     hints.ai_flags = AI_CANONNAME;
276     hints.ai_family = AF_UNSPEC;
277 
278 #ifdef __solaris__
279     /*
280      * Workaround for Solaris bug 4160367 - if a hostname contains a
281      * white space then 0.0.0.0 is returned
282      */
283     if (isspace((unsigned char)hostname[0])) {
284         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
285                         hostname);
286         JNU_ReleaseStringPlatformChars(env, host, hostname);
287         return NULL;
288     }
289 #endif
290 
291     getaddrinfo_error = getaddrinfo(hostname, NULL, &hints, &res);
292 
293 #ifdef MACOSX
294     if (getaddrinfo_error) {
295         /*
296          * If getaddrinfo fails looking up the local machine, attempt to get the
297          * address from getifaddrs. This ensures we get an IPv6 address for the
298          * local machine.
299          */
300         ret = lookupIfLocalhost(env, hostname, JNI_TRUE);
301         if (ret != NULL || (*env)->ExceptionCheck(env)) {
302             JNU_ReleaseStringPlatformChars(env, host, hostname);
303             return ret;
304         }
305     }
306 #endif
307 
308     if (getaddrinfo_error) {
309         /* report error */
310         ThrowUnknownHostExceptionWithGaiError(
311             env, hostname, getaddrinfo_error);
312         JNU_ReleaseStringPlatformChars(env, host, hostname);
313         return NULL;
314     } else {
315         int i = 0;
316         int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
317         struct addrinfo *itr, *last = NULL, *iterator = res;
318         while (iterator != NULL) {
319             int skip = 0;
320             itr = resNew;
321             while (itr != NULL) {
322                 if (iterator->ai_family == itr->ai_family &&
323                     iterator->ai_addrlen == itr->ai_addrlen) {
324                     if (itr->ai_family == AF_INET) { /* AF_INET */
325                         struct sockaddr_in *addr1, *addr2;
326                         addr1 = (struct sockaddr_in *)iterator->ai_addr;
327                         addr2 = (struct sockaddr_in *)itr->ai_addr;
328                         if (addr1->sin_addr.s_addr ==
329                             addr2->sin_addr.s_addr) {
330                             skip = 1;
331                             break;
332                         }
333                     } else {
334                         int t;
335                         struct sockaddr_in6 *addr1, *addr2;
336                         addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
337                         addr2 = (struct sockaddr_in6 *)itr->ai_addr;
338 
339                         for (t = 0; t < 16; t++) {
340                             if (addr1->sin6_addr.s6_addr[t] !=
341                                 addr2->sin6_addr.s6_addr[t]) {
342                                 break;
343                             }
344                         }
345                         if (t < 16) {
346                             itr = itr->ai_next;
347                             continue;
348                         } else {
349                             skip = 1;
350                             break;
351                         }
352                     }
353                 } else if (iterator->ai_family != AF_INET &&
354                            iterator->ai_family != AF_INET6) {
355                     /* we can't handle other family types */
356                     skip = 1;
357                     break;
358                 }
359                 itr = itr->ai_next;
360             }
361 
362             if (!skip) {
363                 struct addrinfo *next
364                     = (struct addrinfo*) malloc(sizeof(struct addrinfo));
365                 if (!next) {
366                     JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
367                     ret = NULL;
368                     goto cleanupAndReturn;
369                 }
370                 memcpy(next, iterator, sizeof(struct addrinfo));
371                 next->ai_next = NULL;
372                 if (resNew == NULL) {
373                     resNew = next;
374                 } else {
375                     last->ai_next = next;
376                 }
377                 last = next;
378                 i++;
379                 if (iterator->ai_family == AF_INET) {
380                     inetCount ++;
381                 } else if (iterator->ai_family == AF_INET6) {
382                     inet6Count ++;
383                 }
384             }
385             iterator = iterator->ai_next;
386         }
387         retLen = i;
388         iterator = resNew;
389 
390         ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
391 
392         if (IS_NULL(ret)) {
393             /* we may have memory to free at the end of this */
394             goto cleanupAndReturn;
395         }
396 
397         if ((*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID)) {
398             /* AF_INET addresses will be offset by inet6Count */
399             inetIndex = inet6Count;
400             inet6Index = 0;
401         } else {
402             /* AF_INET6 addresses will be offset by inetCount */
403             inetIndex = 0;
404             inet6Index = inetCount;
405         }
406 
407         while (iterator != NULL) {
408             int ret1;
409             if (iterator->ai_family == AF_INET) {
410                 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
411                 if (IS_NULL(iaObj)) {
412                     ret = NULL;
413                     goto cleanupAndReturn;
414                 }
415                 setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
416                 if ((*env)->ExceptionCheck(env))
417                     goto cleanupAndReturn;
418                 setInetAddress_hostName(env, iaObj, host);
419                 if ((*env)->ExceptionCheck(env))
420                     goto cleanupAndReturn;
421                 (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj);
422                 inetIndex++;
423             } else if (iterator->ai_family == AF_INET6) {
424                 jint scope = 0;
425 
426                 jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
427                 if (IS_NULL(iaObj)) {
428                     ret = NULL;
429                     goto cleanupAndReturn;
430                 }
431                 ret1 = setInet6Address_ipaddress(env, iaObj, (char *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
432                 if (!ret1) {
433                     ret = NULL;
434                     goto cleanupAndReturn;
435                 }
436 
437                 scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
438                 if (scope != 0) { /* zero is default value, no need to set */
439                     setInet6Address_scopeid(env, iaObj, scope);
440                 }
441                 setInetAddress_hostName(env, iaObj, host);
442                 if ((*env)->ExceptionCheck(env))
443                     goto cleanupAndReturn;
444                 (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj);
445                 inet6Index++;
446             }
447             iterator = iterator->ai_next;
448         }
449     }
450 
451  cleanupAndReturn:
452     {
453       struct addrinfo *iterator, *tmp;
454         iterator = resNew;
455         while (iterator != NULL) {
456             tmp = iterator;
457             iterator = iterator->ai_next;
458             free(tmp);
459         }
460         JNU_ReleaseStringPlatformChars(env, host, hostname);
461     }
462 
463     freeaddrinfo(res);
464 #endif /* AF_INET6 */
465 
466     return ret;
467 }
468 
469 /*
470  * Class:     java_net_Inet6AddressImpl
471  * Method:    getHostByAddr
472  * Signature: (I)Ljava/lang/String;
473  */
474 JNIEXPORT jstring JNICALL
Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv * env,jobject this,jbyteArray addrArray)475 Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
476                                             jbyteArray addrArray) {
477 
478     jstring ret = NULL;
479 
480 #ifdef AF_INET6
481     char host[NI_MAXHOST+1];
482     int error = 0;
483     int len = 0;
484     jbyte caddr[16];
485 
486     struct sockaddr_in him4;
487     struct sockaddr_in6 him6;
488     struct sockaddr *sa;
489 
490     /*
491      * For IPv4 addresses construct a sockaddr_in structure.
492      */
493     if ((*env)->GetArrayLength(env, addrArray) == 4) {
494         jint addr;
495         (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
496         addr = ((caddr[0]<<24) & 0xff000000);
497         addr |= ((caddr[1] <<16) & 0xff0000);
498         addr |= ((caddr[2] <<8) & 0xff00);
499         addr |= (caddr[3] & 0xff);
500         memset((void *) &him4, 0, sizeof(him4));
501         him4.sin_addr.s_addr = (uint32_t) htonl(addr);
502         him4.sin_family = AF_INET;
503         sa = (struct sockaddr *) &him4;
504         len = sizeof(him4);
505     } else {
506         /*
507          * For IPv6 address construct a sockaddr_in6 structure.
508          */
509         (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
510         memset((void *) &him6, 0, sizeof(him6));
511         memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
512         him6.sin6_family = AF_INET6;
513         sa = (struct sockaddr *) &him6 ;
514         len = sizeof(him6) ;
515     }
516 
517     error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
518                         NI_NAMEREQD);
519 
520     if (!error) {
521         ret = (*env)->NewStringUTF(env, host);
522         CHECK_NULL_RETURN(ret, NULL);
523     }
524 #endif /* AF_INET6 */
525 
526     if (ret == NULL) {
527         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
528     }
529 
530     return ret;
531 }
532 
533 #define SET_NONBLOCKING(fd) {           \
534         int flags = fcntl(fd, F_GETFL); \
535         flags |= O_NONBLOCK;            \
536         fcntl(fd, F_SETFL, flags);      \
537 }
538 
539 #ifdef AF_INET6
540 static jboolean
ping6(JNIEnv * env,jint fd,struct sockaddr_in6 * him,jint timeout,struct sockaddr_in6 * netif,jint ttl)541 ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout,
542       struct sockaddr_in6* netif, jint ttl) {
543     jint size;
544     jint n;
545     socklen_t len;
546     char sendbuf[1500];
547     unsigned char recvbuf[1500];
548     struct icmp6_hdr *icmp6;
549     struct sockaddr_in6 sa_recv;
550     jbyte *caddr, *recv_caddr;
551     jchar pid;
552     jint tmout2, seq = 1;
553     struct timeval tv;
554     size_t plen;
555 
556 #ifdef __linux__
557     {
558     int csum_offset;
559     /**
560      * For some strange reason, the linux kernel won't calculate the
561      * checksum of ICMPv6 packets unless you set this socket option
562      */
563     csum_offset = 2;
564     setsockopt(fd, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sizeof(int));
565     }
566 #endif
567 
568     caddr = (jbyte *)&(him->sin6_addr);
569 
570     /* icmp_id is a 16 bit data type, therefore down cast the pid */
571     pid = (jchar)getpid();
572     size = 60*1024;
573     setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
574     if (ttl > 0) {
575       setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
576     }
577     if (netif != NULL) {
578       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
579         NET_ThrowNew(env, errno, "Can't bind socket");
580         close(fd);
581         return JNI_FALSE;
582       }
583     }
584     SET_NONBLOCKING(fd);
585 
586     do {
587       icmp6 = (struct icmp6_hdr *) sendbuf;
588       icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
589       icmp6->icmp6_code = 0;
590       /* let's tag the ECHO packet with our pid so we can identify it */
591       icmp6->icmp6_id = htons(pid);
592       icmp6->icmp6_seq = htons(seq);
593       seq++;
594       icmp6->icmp6_cksum = 0;
595       gettimeofday(&tv, NULL);
596       memcpy(sendbuf + sizeof(struct icmp6_hdr), &tv, sizeof(tv));
597       plen = sizeof(struct icmp6_hdr) + sizeof(tv);
598       n = sendto(fd, sendbuf, plen, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6));
599       if (n < 0 && errno != EINPROGRESS) {
600 #ifdef __linux__
601         if (errno != EINVAL && errno != EHOSTUNREACH)
602           /*
603            * On some Linux versions, when a socket is  bound to the
604            * loopback interface, sendto will fail and errno will be
605            * set to EINVAL or EHOSTUNREACH.
606            * When that happens, don't throw an exception, just return false.
607            */
608 #endif /*__linux__ */
609         NET_ThrowNew(env, errno, "Can't send ICMP packet");
610         close(fd);
611         return JNI_FALSE;
612       }
613 
614       tmout2 = timeout > 1000 ? 1000 : timeout;
615       do {
616         tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
617 
618         if (tmout2 >= 0) {
619           len = sizeof(sa_recv);
620           n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*) &sa_recv, &len);
621           icmp6 = (struct icmp6_hdr *) (recvbuf);
622           recv_caddr = (jbyte *)&(sa_recv.sin6_addr);
623           /*
624            * We did receive something, but is it what we were expecting?
625            * I.E.: An ICMP6_ECHO_REPLY packet with the proper PID and
626            *       from the host that we are trying to determine is reachable.
627            */
628           if (n >= 8 && icmp6->icmp6_type == ICMP6_ECHO_REPLY &&
629               (ntohs(icmp6->icmp6_id) == pid)) {
630             if (NET_IsEqual(caddr, recv_caddr)) {
631               close(fd);
632               return JNI_TRUE;
633             }
634             if (NET_IsZeroAddr(caddr)) {
635               close(fd);
636               return JNI_TRUE;
637             }
638           }
639         }
640       } while (tmout2 > 0);
641       timeout -= 1000;
642     } while (timeout > 0);
643     close(fd);
644     return JNI_FALSE;
645 }
646 #endif /* AF_INET6 */
647 
648 /*
649  * Class:     java_net_Inet6AddressImpl
650  * Method:    isReachable0
651  * Signature: ([bII[bI)Z
652  */
653 JNIEXPORT jboolean JNICALL
Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv * env,jobject this,jbyteArray addrArray,jint scope,jint timeout,jbyteArray ifArray,jint ttl,jint if_scope)654 Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
655                                            jbyteArray addrArray,
656                                            jint scope,
657                                            jint timeout,
658                                            jbyteArray ifArray,
659                                            jint ttl, jint if_scope) {
660 #ifdef AF_INET6
661     jbyte caddr[16];
662     jint fd, sz;
663     struct sockaddr_in6 him6;
664     struct sockaddr_in6 inf6;
665     struct sockaddr_in6* netif = NULL;
666     int len = 0;
667     int connect_rv = -1;
668 
669     /*
670      * If IPv6 is not enable, then we can't reach an IPv6 address, can we?
671      */
672     if (!ipv6_available()) {
673       return JNI_FALSE;
674     }
675     /*
676      * If it's an IPv4 address, ICMP won't work with IPv4 mapped address,
677      * therefore, let's delegate to the Inet4Address method.
678      */
679     sz = (*env)->GetArrayLength(env, addrArray);
680     if (sz == 4) {
681       return Java_java_net_Inet4AddressImpl_isReachable0(env, this,
682                                                          addrArray,
683                                                          timeout,
684                                                          ifArray, ttl);
685     }
686 
687     memset((void *) caddr, 0, 16);
688     memset((void *) &him6, 0, sizeof(him6));
689     (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
690     memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
691     him6.sin6_family = AF_INET6;
692 #ifdef __linux__
693     if (scope > 0)
694       him6.sin6_scope_id = scope;
695     else
696       him6.sin6_scope_id = getDefaultIPv6Interface( &(him6.sin6_addr));
697     len = sizeof(struct sockaddr_in6);
698 #else
699     if (scope > 0)
700       him6.sin6_scope_id = scope;
701     len = sizeof(struct sockaddr_in6);
702 #endif
703     /*
704      * If a network interface was specified, let's create the address
705      * for it.
706      */
707     if (!(IS_NULL(ifArray))) {
708       memset((void *) caddr, 0, 16);
709       memset((void *) &inf6, 0, sizeof(inf6));
710       (*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
711       memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) );
712       inf6.sin6_family = AF_INET6;
713       inf6.sin6_scope_id = if_scope;
714       netif = &inf6;
715     }
716     /*
717      * If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST
718      * otherwise we'll try a tcp socket to the Echo port (7).
719      * Note that this is empiric, and not connecting could mean it's blocked
720      * or the echo service has been disabled.
721      */
722 
723     fd = JVM_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
724 
725     if (fd != -1) { /* Good to go, let's do a ping */
726         return ping6(env, fd, &him6, timeout, netif, ttl);
727     }
728 
729     /* No good, let's fall back on TCP */
730     fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0);
731     if (fd == JVM_IO_ERR) {
732         /* note: if you run out of fds, you may not be able to load
733          * the exception class, and get a NoClassDefFoundError
734          * instead.
735          */
736         NET_ThrowNew(env, errno, "Can't create socket");
737         return JNI_FALSE;
738     }
739     if (ttl > 0) {
740       setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
741     }
742 
743     /*
744      * A network interface was specified, so let's bind to it.
745      */
746     if (netif != NULL) {
747       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
748         NET_ThrowNew(env, errno, "Can't bind socket");
749         close(fd);
750         return JNI_FALSE;
751       }
752     }
753     SET_NONBLOCKING(fd);
754 
755     /* no need to use NET_Connect as non-blocking */
756     him6.sin6_port = htons((short) 7); /* Echo port */
757     connect_rv = JVM_Connect(fd, (struct sockaddr *)&him6, len);
758 
759     /**
760      * connection established or refused immediately, either way it means
761      * we were able to reach the host!
762      */
763     if (connect_rv == 0 || errno == ECONNREFUSED) {
764         close(fd);
765         return JNI_TRUE;
766     } else {
767         int optlen;
768 
769         switch (errno) {
770         case ENETUNREACH: /* Network Unreachable */
771         case EAFNOSUPPORT: /* Address Family not supported */
772         case EADDRNOTAVAIL: /* address is not available on  the  remote machine */
773 #ifdef __linux__
774         case EINVAL:
775         case EHOSTUNREACH:
776           /*
777            * On some Linux versions, when  a socket is bound to the
778            * loopback interface, connect will fail and errno will
779            * be set to EINVAL or EHOSTUNREACH.  When that happens,
780            * don't throw an exception, just return false.
781            */
782 #endif /* __linux__ */
783           close(fd);
784           return JNI_FALSE;
785         }
786 
787         if (errno != EINPROGRESS) {
788             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
789                                          "connect failed");
790             close(fd);
791             return JNI_FALSE;
792         }
793 
794         timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
795 
796         if (timeout >= 0) {
797           /* has connection been established */
798           optlen = sizeof(connect_rv);
799           if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
800                              &optlen) <0) {
801             connect_rv = errno;
802           }
803           if (connect_rv == 0 || ECONNREFUSED) {
804             close(fd);
805             return JNI_TRUE;
806           }
807         }
808         close(fd);
809         return JNI_FALSE;
810     }
811 #else /* AF_INET6 */
812     return JNI_FALSE;
813 #endif /* AF_INET6 */
814 }
815