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