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