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 <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 33 /* 34 * Inet6AddressImpl 35 */ 36 37 /* 38 * Class: java_net_Inet6AddressImpl 39 * Method: getLocalHostName 40 * Signature: ()Ljava/lang/String; 41 */ 42 JNIEXPORT jstring JNICALL 43 Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) { 44 char hostname[256]; 45 46 if (gethostname(hostname, sizeof(hostname)) == -1) { 47 strcpy(hostname, "localhost"); 48 } 49 return JNU_NewStringPlatform(env, hostname); 50 } 51 52 /* 53 * Class: java_net_Inet6AddressImpl 54 * Method: lookupAllHostAddr 55 * Signature: (Ljava/lang/String;)[[B 56 */ 57 JNIEXPORT jobjectArray JNICALL 58 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, 59 jstring host) { 60 jobjectArray ret = NULL; 61 const char *hostname; 62 int error = 0; 63 struct addrinfo hints, *res = NULL, *resNew = NULL, *last = NULL, 64 *iterator; 65 66 initInetAddressIDs(env); 67 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 68 69 if (IS_NULL(host)) { 70 JNU_ThrowNullPointerException(env, "host argument is null"); 71 return NULL; 72 } 73 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); 74 CHECK_NULL_RETURN(hostname, NULL); 75 76 // try once, with our static buffer 77 memset(&hints, 0, sizeof(hints)); 78 hints.ai_flags = AI_CANONNAME; 79 hints.ai_family = AF_UNSPEC; 80 81 error = getaddrinfo(hostname, NULL, &hints, &res); 82 83 if (error) { 84 // report error 85 NET_ThrowByNameWithLastError(env, "java/net/UnknownHostException", 86 hostname); 87 goto cleanupAndReturn; 88 } else { 89 int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0, 90 inet6Index = 0, originalIndex = 0; 91 int addressPreference = 92 (*env)->GetStaticIntField(env, ia_class, ia_preferIPv6AddressID); 93 iterator = res; 94 while (iterator != NULL) { 95 // skip duplicates 96 int skip = 0; 97 struct addrinfo *iteratorNew = resNew; 98 while (iteratorNew != NULL) { 99 if (iterator->ai_family == iteratorNew->ai_family && 100 iterator->ai_addrlen == iteratorNew->ai_addrlen) { 101 if (iteratorNew->ai_family == AF_INET) { /* AF_INET */ 102 struct sockaddr_in *addr1, *addr2; 103 addr1 = (struct sockaddr_in *)iterator->ai_addr; 104 addr2 = (struct sockaddr_in *)iteratorNew->ai_addr; 105 if (addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) { 106 skip = 1; 107 break; 108 } 109 } else { 110 int t; 111 struct sockaddr_in6 *addr1, *addr2; 112 addr1 = (struct sockaddr_in6 *)iterator->ai_addr; 113 addr2 = (struct sockaddr_in6 *)iteratorNew->ai_addr; 114 115 for (t = 0; t < 16; t++) { 116 if (addr1->sin6_addr.s6_addr[t] != 117 addr2->sin6_addr.s6_addr[t]) { 118 break; 119 } 120 } 121 if (t < 16) { 122 iteratorNew = iteratorNew->ai_next; 123 continue; 124 } else { 125 skip = 1; 126 break; 127 } 128 } 129 } else if (iterator->ai_family != AF_INET && 130 iterator->ai_family != AF_INET6) { 131 // we can't handle other family types 132 skip = 1; 133 break; 134 } 135 iteratorNew = iteratorNew->ai_next; 136 } 137 138 if (!skip) { 139 struct addrinfo *next 140 = (struct addrinfo *)malloc(sizeof(struct addrinfo)); 141 if (!next) { 142 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); 143 ret = NULL; 144 goto cleanupAndReturn; 145 } 146 memcpy(next, iterator, sizeof(struct addrinfo)); 147 next->ai_next = NULL; 148 if (resNew == NULL) { 149 resNew = next; 150 } else { 151 last->ai_next = next; 152 } 153 last = next; 154 i++; 155 if (iterator->ai_family == AF_INET) { 156 inetCount++; 157 } else if (iterator->ai_family == AF_INET6) { 158 inet6Count++; 159 } 160 } 161 iterator = iterator->ai_next; 162 } 163 164 // allocate array - at this point i contains the number of addresses 165 ret = (*env)->NewObjectArray(env, i, ia_class, NULL); 166 if (IS_NULL(ret)) { 167 /* we may have memory to free at the end of this */ 168 goto cleanupAndReturn; 169 } 170 171 if (addressPreference == java_net_InetAddress_PREFER_IPV6_VALUE) { 172 inetIndex = inet6Count; 173 inet6Index = 0; 174 } else if (addressPreference == java_net_InetAddress_PREFER_IPV4_VALUE) { 175 inetIndex = 0; 176 inet6Index = inetCount; 177 } else if (addressPreference == java_net_InetAddress_PREFER_SYSTEM_VALUE) { 178 inetIndex = inet6Index = originalIndex = 0; 179 } 180 181 iterator = resNew; 182 while (iterator != NULL) { 183 if (iterator->ai_family == AF_INET) { 184 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); 185 if (IS_NULL(iaObj)) { 186 ret = NULL; 187 goto cleanupAndReturn; 188 } 189 setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); 190 if ((*env)->ExceptionCheck(env)) 191 goto cleanupAndReturn; 192 setInetAddress_hostName(env, iaObj, host); 193 if ((*env)->ExceptionCheck(env)) 194 goto cleanupAndReturn; 195 (*env)->SetObjectArrayElement(env, ret, (inetIndex | originalIndex), iaObj); 196 inetIndex++; 197 } else if (iterator->ai_family == AF_INET6) { 198 jint scope = 0; 199 jboolean ret1; 200 jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID); 201 if (IS_NULL(iaObj)) { 202 ret = NULL; 203 goto cleanupAndReturn; 204 } 205 ret1 = setInet6Address_ipaddress(env, iaObj, (char *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr)); 206 if (ret1 == JNI_FALSE) { 207 ret = NULL; 208 goto cleanupAndReturn; 209 } 210 scope = ((struct sockaddr_in6 *)iterator->ai_addr)->sin6_scope_id; 211 if (scope != 0) { // zero is default value, no need to set 212 setInet6Address_scopeid(env, iaObj, scope); 213 } 214 setInetAddress_hostName(env, iaObj, host); 215 if ((*env)->ExceptionCheck(env)) 216 goto cleanupAndReturn; 217 (*env)->SetObjectArrayElement(env, ret, (inet6Index | originalIndex), iaObj); 218 inet6Index++; 219 } 220 if (addressPreference == java_net_InetAddress_PREFER_SYSTEM_VALUE) { 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 }