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