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