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 }