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