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 <malloc.h> 26 27 #include "net_util.h" 28 29 #include "java_net_InetAddress.h" 30 #include "java_net_Inet4AddressImpl.h" 31 #include "java_net_Inet6AddressImpl.h" 32 #include "java_net_spi_InetAddressResolver_LookupPolicy.h" 33 34 /* 35 * Inet6AddressImpl 36 */ 37 38 /* 39 * Class: java_net_Inet6AddressImpl 40 * Method: getLocalHostName 41 * Signature: ()Ljava/lang/String; 42 */ 43 JNIEXPORT jstring JNICALL 44 Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) { 45 char hostname[256]; 46 47 if (gethostname(hostname, sizeof(hostname)) == -1) { 48 strcpy(hostname, "localhost"); 49 } 50 return JNU_NewStringPlatform(env, hostname); 51 } 52 53 /* 54 * Class: java_net_Inet6AddressImpl 55 * Method: lookupAllHostAddr 56 * Signature: (Ljava/lang/String;)[[B 57 */ 58 JNIEXPORT jobjectArray JNICALL 59 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, 60 jstring host, jint characteristics) { 61 jobjectArray ret = NULL; 62 const char *hostname; 63 int error = 0; 64 struct addrinfo hints, *res = NULL, *resNew = NULL, *last = NULL, 65 *iterator; 66 67 initInetAddressIDs(env); 68 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 69 70 if (IS_NULL(host)) { 71 JNU_ThrowNullPointerException(env, "host argument is null"); 72 return NULL; 73 } 74 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); 75 CHECK_NULL_RETURN(hostname, NULL); 76 77 // try once, with our static buffer 78 memset(&hints, 0, sizeof(hints)); 79 hints.ai_flags = AI_CANONNAME; 80 hints.ai_family = lookupCharacteristicsToAddressFamily(characteristics); 81 82 error = getaddrinfo(hostname, NULL, &hints, &res); 83 84 if (error) { 85 // report error 86 NET_ThrowByNameWithLastError(env, "java/net/UnknownHostException", 87 hostname); 88 goto cleanupAndReturn; 89 } else { 90 int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0, 91 inet6Index = 0, originalIndex = 0; 92 iterator = res; 93 while (iterator != NULL) { 94 // skip duplicates 95 int skip = 0; 96 struct addrinfo *iteratorNew = resNew; 97 while (iteratorNew != NULL) { 98 if (iterator->ai_family == iteratorNew->ai_family && 99 iterator->ai_addrlen == iteratorNew->ai_addrlen) { 100 if (iteratorNew->ai_family == AF_INET) { /* AF_INET */ 101 struct sockaddr_in *addr1, *addr2; 102 addr1 = (struct sockaddr_in *)iterator->ai_addr; 103 addr2 = (struct sockaddr_in *)iteratorNew->ai_addr; 104 if (addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) { 105 skip = 1; 106 break; 107 } 108 } else { 109 int t; 110 struct sockaddr_in6 *addr1, *addr2; 111 addr1 = (struct sockaddr_in6 *)iterator->ai_addr; 112 addr2 = (struct sockaddr_in6 *)iteratorNew->ai_addr; 113 114 for (t = 0; t < 16; t++) { 115 if (addr1->sin6_addr.s6_addr[t] != 116 addr2->sin6_addr.s6_addr[t]) { 117 break; 118 } 119 } 120 if (t < 16) { 121 iteratorNew = iteratorNew->ai_next; 122 continue; 123 } else { 124 skip = 1; 125 break; 126 } 127 } 128 } else if (iterator->ai_family != AF_INET && 129 iterator->ai_family != AF_INET6) { 130 // we can't handle other family types 131 skip = 1; 132 break; 133 } 134 iteratorNew = iteratorNew->ai_next; 135 } 136 137 if (!skip) { 138 struct addrinfo *next 139 = (struct addrinfo *)malloc(sizeof(struct addrinfo)); 140 if (!next) { 141 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); 142 ret = NULL; 143 goto cleanupAndReturn; 144 } 145 memcpy(next, iterator, sizeof(struct addrinfo)); 146 next->ai_next = NULL; 147 if (resNew == NULL) { 148 resNew = next; 149 } else { 150 last->ai_next = next; 151 } 152 last = next; 153 i++; 154 if (iterator->ai_family == AF_INET) { 155 inetCount++; 156 } else if (iterator->ai_family == AF_INET6) { 157 inet6Count++; 158 } 159 } 160 iterator = iterator->ai_next; 161 } 162 163 // allocate array - at this point i contains the number of addresses 164 ret = (*env)->NewObjectArray(env, i, ia_class, NULL); 165 if (IS_NULL(ret)) { 166 /* we may have memory to free at the end of this */ 167 goto cleanupAndReturn; 168 } 169 170 if ((characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV6_FIRST) != 0) { 171 inetIndex = inet6Count; 172 inet6Index = 0; 173 } else if ((characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV4_FIRST) != 0) { 174 inetIndex = 0; 175 inet6Index = inetCount; 176 } else { 177 inetIndex = inet6Index = originalIndex = 0; 178 } 179 180 iterator = resNew; 181 while (iterator != NULL) { 182 if (iterator->ai_family == AF_INET) { 183 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); 184 if (IS_NULL(iaObj)) { 185 ret = NULL; 186 goto cleanupAndReturn; 187 } 188 setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); 189 if ((*env)->ExceptionCheck(env)) 190 goto cleanupAndReturn; 191 setInetAddress_hostName(env, iaObj, host); 192 if ((*env)->ExceptionCheck(env)) 193 goto cleanupAndReturn; 194 (*env)->SetObjectArrayElement(env, ret, (inetIndex | originalIndex), iaObj); 195 inetIndex++; 196 } else if (iterator->ai_family == AF_INET6) { 197 jint scope = 0; 198 jboolean ret1; 199 jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID); 200 if (IS_NULL(iaObj)) { 201 ret = NULL; 202 goto cleanupAndReturn; 203 } 204 ret1 = setInet6Address_ipaddress(env, iaObj, (char *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr)); 205 if (ret1 == JNI_FALSE) { 206 ret = NULL; 207 goto cleanupAndReturn; 208 } 209 scope = ((struct sockaddr_in6 *)iterator->ai_addr)->sin6_scope_id; 210 if (scope != 0) { // zero is default value, no need to set 211 setInet6Address_scopeid(env, iaObj, scope); 212 } 213 setInetAddress_hostName(env, iaObj, host); 214 if ((*env)->ExceptionCheck(env)) 215 goto cleanupAndReturn; 216 (*env)->SetObjectArrayElement(env, ret, (inet6Index | originalIndex), iaObj); 217 inet6Index++; 218 } 219 // Check if addresses are requested to be returned in SYSTEM order 220 if (addressesInSystemOrder(characteristics)) { 221 originalIndex++; 222 inetIndex = inet6Index = 0; 223 } 224 iterator = iterator->ai_next; 225 } 226 } 227 cleanupAndReturn: 228 JNU_ReleaseStringPlatformChars(env, host, hostname); 229 while (resNew != NULL) { 230 last = resNew; 231 resNew = resNew->ai_next; 232 free(last); 233 } 234 if (res != NULL) { 235 freeaddrinfo(res); 236 } 237 return ret; 238 } 239 240 /* 241 * Class: java_net_Inet6AddressImpl 242 * Method: getHostByAddr 243 * Signature: ([B)Ljava/lang/String; 244 * 245 * Theoretically the UnknownHostException could be enriched with gai error 246 * information. But as it is silently ignored anyway, there's no need for this. 247 * It's only important that either a valid hostname is returned or an 248 * UnknownHostException is thrown. 249 */ 250 JNIEXPORT jstring JNICALL 251 Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this, 252 jbyteArray addrArray) { 253 jstring ret = NULL; 254 char host[NI_MAXHOST + 1]; 255 int len = 0; 256 jbyte caddr[16]; 257 SOCKETADDRESS sa; 258 259 memset((void *)&sa, 0, sizeof(SOCKETADDRESS)); 260 261 // construct a sockaddr_in structure (AF_INET or AF_INET6) 262 if ((*env)->GetArrayLength(env, addrArray) == 4) { 263 jint addr; 264 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); 265 addr = ((caddr[0] << 24) & 0xff000000); 266 addr |= ((caddr[1] << 16) & 0xff0000); 267 addr |= ((caddr[2] << 8) & 0xff00); 268 addr |= (caddr[3] & 0xff); 269 sa.sa4.sin_addr.s_addr = htonl(addr); 270 sa.sa4.sin_family = AF_INET; 271 len = sizeof(struct sockaddr_in); 272 } else { 273 (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr); 274 memcpy((void *)&sa.sa6.sin6_addr, caddr, sizeof(struct in6_addr)); 275 sa.sa6.sin6_family = AF_INET6; 276 len = sizeof(struct sockaddr_in6); 277 } 278 279 if (getnameinfo(&sa.sa, len, host, NI_MAXHOST, NULL, 0, NI_NAMEREQD)) { 280 JNU_ThrowByName(env, "java/net/UnknownHostException", NULL); 281 } else { 282 ret = (*env)->NewStringUTF(env, host); 283 if (ret == NULL) { 284 JNU_ThrowByName(env, "java/net/UnknownHostException", NULL); 285 } 286 } 287 288 return ret; 289 } 290 291 /** 292 * ping implementation using tcp port 7 (echo) 293 */ 294 static jboolean 295 tcp_ping6(JNIEnv *env, SOCKETADDRESS *sa, SOCKETADDRESS *netif, jint timeout, 296 jint ttl) 297 { 298 jint fd; 299 int connect_rv = -1; 300 WSAEVENT hEvent; 301 302 // open a TCP socket 303 fd = NET_Socket(AF_INET6, SOCK_STREAM, 0); 304 if (fd == SOCKET_ERROR) { 305 // note: if you run out of fds, you may not be able to load 306 // the exception class, and get a NoClassDefFoundError instead. 307 NET_ThrowNew(env, WSAGetLastError(), "Can't create socket"); 308 return JNI_FALSE; 309 } 310 311 // set TTL 312 if (ttl > 0) { 313 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *)&ttl, sizeof(ttl)); 314 } 315 316 // A network interface was specified, so let's bind to it. 317 if (netif != NULL) { 318 if (bind(fd, &netif->sa, sizeof(struct sockaddr_in6)) < 0) { 319 NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket to interface"); 320 closesocket(fd); 321 return JNI_FALSE; 322 } 323 } 324 325 // Make the socket non blocking so we can use select/poll. 326 hEvent = WSACreateEvent(); 327 WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE); 328 329 sa->sa6.sin6_port = htons(7); // echo port 330 connect_rv = connect(fd, &sa->sa, sizeof(struct sockaddr_in6)); 331 332 // connection established or refused immediately, either way it means 333 // we were able to reach the host! 334 if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) { 335 WSACloseEvent(hEvent); 336 closesocket(fd); 337 return JNI_TRUE; 338 } 339 340 switch (WSAGetLastError()) { 341 case WSAEHOSTUNREACH: // Host Unreachable 342 case WSAENETUNREACH: // Network Unreachable 343 case WSAENETDOWN: // Network is down 344 case WSAEPFNOSUPPORT: // Protocol Family unsupported 345 WSACloseEvent(hEvent); 346 closesocket(fd); 347 return JNI_FALSE; 348 case WSAEWOULDBLOCK: // this is expected as we'll probably have to wait 349 break; 350 default: 351 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", 352 "connect failed"); 353 WSACloseEvent(hEvent); 354 closesocket(fd); 355 return JNI_FALSE; 356 } 357 358 timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout); 359 if (timeout >= 0) { 360 // connection has been established, check for error condition 361 int optlen = sizeof(connect_rv); 362 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&connect_rv, 363 &optlen) < 0) 364 { 365 connect_rv = WSAGetLastError(); 366 } 367 if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) { 368 WSACloseEvent(hEvent); 369 closesocket(fd); 370 return JNI_TRUE; 371 } 372 } 373 WSACloseEvent(hEvent); 374 closesocket(fd); 375 return JNI_FALSE; 376 } 377 378 /** 379 * ping implementation. 380 * Send a ICMP_ECHO_REQUEST packet every second until either the timeout 381 * expires or a answer is received. 382 * Returns true is an ECHO_REPLY is received, otherwise, false. 383 */ 384 static jboolean 385 ping6(JNIEnv *env, HANDLE hIcmpFile, SOCKETADDRESS *sa, 386 SOCKETADDRESS *netif, jint timeout) 387 { 388 DWORD dwRetVal = 0; 389 char SendData[32] = {0}; 390 LPVOID ReplyBuffer = NULL; 391 DWORD ReplySize = 0; 392 IP_OPTION_INFORMATION ipInfo = {255, 0, 0, 0, NULL}; 393 SOCKETADDRESS dftNetif; 394 395 ReplySize = sizeof(ICMPV6_ECHO_REPLY) + sizeof(SendData); 396 ReplyBuffer = (VOID *)malloc(ReplySize); 397 if (ReplyBuffer == NULL) { 398 IcmpCloseHandle(hIcmpFile); 399 NET_ThrowNew(env, -1, "Unable to allocate memory"); 400 return JNI_FALSE; 401 } 402 403 //define local source information 404 if (netif == NULL) { 405 dftNetif.sa6.sin6_addr = in6addr_any; 406 dftNetif.sa6.sin6_family = AF_INET6; 407 dftNetif.sa6.sin6_flowinfo = 0; 408 dftNetif.sa6.sin6_port = 0; 409 netif = &dftNetif; 410 } 411 412 dwRetVal = Icmp6SendEcho2(hIcmpFile, // HANDLE IcmpHandle, 413 NULL, // HANDLE Event, 414 NULL, // PIO_APC_ROUTINE ApcRoutine, 415 NULL, // PVOID ApcContext, 416 &netif->sa6, // struct sockaddr_in6 *SourceAddress, 417 &sa->sa6, // struct sockaddr_in6 *DestinationAddress, 418 SendData, // LPVOID RequestData, 419 sizeof(SendData), // WORD RequestSize, 420 &ipInfo, // PIP_OPTION_INFORMATION RequestOptions, 421 ReplyBuffer, // LPVOID ReplyBuffer, 422 ReplySize, // DWORD ReplySize, 423 timeout); // DWORD Timeout 424 425 free(ReplyBuffer); 426 IcmpCloseHandle(hIcmpFile); 427 428 if (dwRetVal == 0) { // if the call failed 429 return JNI_FALSE; 430 } else { 431 return JNI_TRUE; 432 } 433 } 434 435 /* 436 * Class: java_net_Inet6AddressImpl 437 * Method: isReachable0 438 * Signature: ([BII[BII)Z 439 */ 440 JNIEXPORT jboolean JNICALL 441 Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this, 442 jbyteArray addrArray, jint scope, 443 jint timeout, jbyteArray ifArray, 444 jint ttl, jint if_scope) 445 { 446 jbyte caddr[16]; 447 jint sz; 448 SOCKETADDRESS sa, inf, *netif = NULL; 449 HANDLE hIcmpFile; 450 451 // If IPv6 is not enabled, then we can't reach an IPv6 address, can we? 452 // Actually, we probably shouldn't even get here. 453 if (!ipv6_available()) { 454 return JNI_FALSE; 455 } 456 457 // If it's an IPv4 address, ICMP won't work with IPv4 mapped address, 458 // therefore, let's delegate to the Inet4Address method. 459 sz = (*env)->GetArrayLength(env, addrArray); 460 if (sz == 4) { 461 return Java_java_net_Inet4AddressImpl_isReachable0(env, this, 462 addrArray, timeout, 463 ifArray, ttl); 464 } 465 466 // load address to SOCKETADDRESS 467 memset((char *)caddr, 0, 16); 468 (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr); 469 memset((char *)&sa, 0, sizeof(SOCKETADDRESS)); 470 memcpy((void *)&sa.sa6.sin6_addr, caddr, sizeof(struct in6_addr)); 471 sa.sa6.sin6_family = AF_INET6; 472 if (scope > 0) { 473 sa.sa6.sin6_scope_id = scope; 474 } 475 476 // load network interface address to SOCKETADDRESS, if specified 477 if (!(IS_NULL(ifArray))) { 478 memset((char *)caddr, 0, 16); 479 (*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr); 480 memset((char *)&inf, 0, sizeof(SOCKETADDRESS)); 481 memcpy((void *)&inf.sa6.sin6_addr, caddr, sizeof(struct in6_addr)); 482 inf.sa6.sin6_family = AF_INET6; 483 inf.sa6.sin6_scope_id = if_scope; 484 netif = &inf; 485 } 486 487 // Let's try to create an ICMP handle. 488 hIcmpFile = Icmp6CreateFile(); 489 if (hIcmpFile == INVALID_HANDLE_VALUE) { 490 int err = WSAGetLastError(); 491 if (err == ERROR_ACCESS_DENIED) { 492 // fall back to TCP echo if access is denied to ICMP 493 return tcp_ping6(env, &sa, netif, timeout, ttl); 494 } else { 495 NET_ThrowNew(env, err, "Unable to create ICMP file handle"); 496 return JNI_FALSE; 497 } 498 } else { 499 // It didn't fail, so we can use ICMP. 500 return ping6(env, hIcmpFile, &sa, netif, timeout); 501 } 502 } --- EOF ---