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#include <ctype.h> 26#include <errno.h> 27#include <sys/types.h> 28#include <netinet/in.h> 29#include <netinet/in_systm.h> 30#include <netinet/ip.h> 31#include <netinet/ip_icmp.h> 32#include <stdlib.h> 33#include <string.h> 34#include <sys/time.h> 35 36#include "net_util.h" 37 38#include "java_net_Inet4AddressImpl.h" 39 40#if defined(MACOSX) 41extern jobjectArray lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6); 42#endif 43 44/* the initial size of our hostent buffers */ 45#ifndef NI_MAXHOST 46#define NI_MAXHOST 1025 47#endif 48 49/************************************************************************ 50 * Inet4AddressImpl 51 */ 52 53/* 54 * Class: java_net_Inet4AddressImpl 55 * Method: getLocalHostName 56 * Signature: ()Ljava/lang/String; 57 */ 58JNIEXPORT jstring JNICALL 59Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) { 60 char hostname[NI_MAXHOST+1]; 61 62 hostname[0] = '\0'; 63 if (gethostname(hostname, NI_MAXHOST)) { 64 /* Something went wrong, maybe networking is not setup? */ 65 strcpy(hostname, "localhost"); 66 } else { 67 struct addrinfo hints, *res; 68 int error; 69 70 hostname[NI_MAXHOST] = '\0'; 71 memset(&hints, 0, sizeof(hints)); 72 hints.ai_flags = AI_CANONNAME; 73 hints.ai_family = AF_INET; 74 75 error = getaddrinfo(hostname, NULL, &hints, &res); 76 77 if (error == 0) {/* host is known to name service */ 78 getnameinfo(res->ai_addr, 79 res->ai_addrlen, 80 hostname, 81 NI_MAXHOST, 82 NULL, 83 0, 84 NI_NAMEREQD); 85 86 /* if getnameinfo fails hostname is still the value 87 from gethostname */ 88 89 freeaddrinfo(res); 90 } 91 } 92 return (*env)->NewStringUTF(env, hostname); 93} 94 95/* 96 * Find an internet address for a given hostname. Note that this 97 * code only works for addresses of type INET. The translation 98 * of %d.%d.%d.%d to an address (int) occurs in java now, so the 99 * String "host" shouldn't *ever* be a %d.%d.%d.%d string 100 * 101 * Class: java_net_Inet4AddressImpl 102 * Method: lookupAllHostAddr 103 * Signature: (Ljava/lang/String;)[[B 104 */ 105 106JNIEXPORT jobjectArray JNICALL 107Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, 108 jstring host) { 109 const char *hostname; 110 jobjectArray ret = 0; 111 int retLen = 0; 112 int error = 0; 113 struct addrinfo hints, *res, *resNew = NULL; 114 115 initInetAddressIDs(env); 116 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 117 118 if (IS_NULL(host)) { 119 JNU_ThrowNullPointerException(env, "host is null"); 120 return 0; 121 } 122 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); 123 CHECK_NULL_RETURN(hostname, NULL); 124 125 /* Try once, with our static buffer. */ 126 memset(&hints, 0, sizeof(hints)); 127 hints.ai_flags = AI_CANONNAME; 128 hints.ai_family = AF_INET; 129 130#ifdef __solaris__ 131 /* 132 * Workaround for Solaris bug 4160367 - if a hostname contains a 133 * white space then 0.0.0.0 is returned 134 */ 135 if (isspace((unsigned char)hostname[0])) { 136 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 137 (char *)hostname); 138 JNU_ReleaseStringPlatformChars(env, host, hostname); 139 return NULL; 140 } 141#endif 142 143 error = getaddrinfo(hostname, NULL, &hints, &res); 144 145#ifdef MACOSX 146 if (error) { 147 // If getaddrinfo fails try getifaddrs, see bug 8170910. 148 ret = lookupIfLocalhost(env, hostname, JNI_FALSE); 149 if (ret != NULL || (*env)->ExceptionCheck(env)) { 150 JNU_ReleaseStringPlatformChars(env, host, hostname); 151 return ret; 152 } 153 } 154#endif 155 156 if (error) { 157 /* report error */ 158 NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error); 159 JNU_ReleaseStringPlatformChars(env, host, hostname); 160 return NULL; 161 } else { 162 int i = 0; 163 struct addrinfo *itr, *last = NULL, *iterator = res; 164 165 while (iterator != NULL) { 166 // remove the duplicate one 167 int skip = 0; 168 itr = resNew; 169 while (itr != NULL) { 170 struct sockaddr_in *addr1, *addr2; 171 addr1 = (struct sockaddr_in *)iterator->ai_addr; 172 addr2 = (struct sockaddr_in *)itr->ai_addr; 173 if (addr1->sin_addr.s_addr == 174 addr2->sin_addr.s_addr) { 175 skip = 1; 176 break; 177 } 178 itr = itr->ai_next; 179 } 180 181 if (!skip) { 182 struct addrinfo *next 183 = (struct addrinfo *)malloc(sizeof(struct addrinfo)); 184 if (!next) { 185 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); 186 ret = NULL; 187 goto cleanupAndReturn; 188 } 189 memcpy(next, iterator, sizeof(struct addrinfo)); 190 next->ai_next = NULL; 191 if (resNew == NULL) { 192 resNew = next; 193 } else { 194 last->ai_next = next; 195 } 196 last = next; 197 i++; 198 } 199 iterator = iterator->ai_next; 200 } 201 202 retLen = i; 203 iterator = resNew; 204 205 ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL); 206 207 if (IS_NULL(ret)) { 208 /* we may have memory to free at the end of this */ 209 goto cleanupAndReturn; 210 } 211 212 i = 0; 213 while (iterator != NULL) { 214 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); 215 if (IS_NULL(iaObj)) { 216 ret = NULL; 217 goto cleanupAndReturn; 218 } 219 setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr)); 220 setInetAddress_hostName(env, iaObj, host); 221 (*env)->SetObjectArrayElement(env, ret, i++, iaObj); 222 iterator = iterator->ai_next; 223 } 224 } 225 226cleanupAndReturn: 227 { 228 struct addrinfo *iterator, *tmp; 229 iterator = resNew; 230 while (iterator != NULL) { 231 tmp = iterator; 232 iterator = iterator->ai_next; 233 free(tmp); 234 } 235 JNU_ReleaseStringPlatformChars(env, host, hostname); 236 } 237 238 freeaddrinfo(res); 239 240 return ret; 241} 242 243/* 244 * Class: java_net_Inet4AddressImpl 245 * Method: getHostByAddr 246 * Signature: (I)Ljava/lang/String; 247 */ 248JNIEXPORT jstring JNICALL 249Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this, 250 jbyteArray addrArray) { 251 jstring ret = NULL; 252 253 char host[NI_MAXHOST+1]; 254 int error = 0; 255 int len = 0; 256 jbyte caddr[4]; 257 258 struct sockaddr_in him4; 259 struct sockaddr *sa; 260 261 jint addr; 262 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); 263 addr = ((caddr[0]<<24) & 0xff000000); 264 addr |= ((caddr[1] <<16) & 0xff0000); 265 addr |= ((caddr[2] <<8) & 0xff00); 266 addr |= (caddr[3] & 0xff); 267 memset((void *) &him4, 0, sizeof(him4)); 268 him4.sin_addr.s_addr = htonl(addr); 269 him4.sin_family = AF_INET; 270 sa = (struct sockaddr *) &him4; 271 len = sizeof(him4); 272 273 error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0, NI_NAMEREQD); 274 275 if (!error) { 276 ret = (*env)->NewStringUTF(env, host); 277 } 278 279 if (ret == NULL) { 280 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL); 281 } 282 283 return ret; 284} 285 286#define SET_NONBLOCKING(fd) { \ 287 int flags = fcntl(fd, F_GETFL); \ 288 flags |= O_NONBLOCK; \ 289 fcntl(fd, F_SETFL, flags); \ 290} 291 292/** 293 * ping implementation. 294 * Send a ICMP_ECHO_REQUEST packet every second until either the timeout 295 * expires or a answer is received. 296 * Returns true is an ECHO_REPLY is received, otherwise, false. 297 */ 298static jboolean 299ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout, 300 struct sockaddr_in* netif, jint ttl) { 301 jint size; 302 jint n, hlen1, icmplen; 303 socklen_t len; 304 char sendbuf[1500]; 305 char recvbuf[1500]; 306 struct icmp *icmp; 307 struct ip *ip; 308 struct sockaddr_in sa_recv; 309 jchar pid; 310 jint tmout2, seq = 1; 311 struct timeval tv; 312 size_t plen; 313 314 /* icmp_id is a 16 bit data type, therefore down cast the pid */ 315 pid = (jchar)getpid(); 316 size = 60*1024; 317 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 318 /* 319 * sets the ttl (max number of hops) 320 */ 321 if (ttl > 0) { 322 setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); 323 } 324 /* 325 * a specific interface was specified, so let's bind the socket 326 * to that interface to ensure the requests are sent only through it. 327 */ 328 if (netif != NULL) { 329 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) { 330 NET_ThrowNew(env, errno, "Can't bind socket"); 331 close(fd); 332 return JNI_FALSE; 333 } 334 } 335 /* 336 * Make the socket non blocking so we can use select 337 */ 338 SET_NONBLOCKING(fd); 339 do { 340 /* 341 * create the ICMP request 342 */ 343 icmp = (struct icmp *) sendbuf; 344 icmp->icmp_type = ICMP_ECHO; 345 icmp->icmp_code = 0; 346 icmp->icmp_id = htons(pid); 347 icmp->icmp_seq = htons(seq); 348 seq++; 349 gettimeofday(&tv, NULL); 350 memcpy(icmp->icmp_data, &tv, sizeof(tv)); 351 plen = ICMP_ADVLENMIN + sizeof(tv); 352 icmp->icmp_cksum = 0; 353 icmp->icmp_cksum = in_cksum((u_short *)icmp, plen); 354 /* 355 * send it 356 */ 357 n = sendto(fd, sendbuf, plen, 0, (struct sockaddr *)him, 358 sizeof(struct sockaddr)); 359 if (n < 0 && errno != EINPROGRESS ) { 360#ifdef __linux__ 361 if (errno != EINVAL && errno != EHOSTUNREACH) 362 /* 363 * On some Linux versions, when a socket is bound to the loopback 364 * interface, sendto will fail and errno will be set to 365 * EINVAL or EHOSTUNREACH. When that happens, don't throw an 366 * exception, just return false. 367 */ 368#endif /*__linux__ */ 369 NET_ThrowNew(env, errno, "Can't send ICMP packet"); 370 close(fd); 371 return JNI_FALSE; 372 } 373 374 tmout2 = timeout > 1000 ? 1000 : timeout; 375 do { 376 tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2); 377 if (tmout2 >= 0) { 378 len = sizeof(sa_recv); 379 n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&sa_recv, &len); 380 ip = (struct ip*) recvbuf; 381 hlen1 = (ip->ip_hl) << 2; 382 icmp = (struct icmp *) (recvbuf + hlen1); 383 icmplen = n - hlen1; 384 /* 385 * We did receive something, but is it what we were expecting? 386 * I.E.: A ICMP_ECHOREPLY packet with the proper PID. 387 */ 388 if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY 389 && (ntohs(icmp->icmp_id) == pid)) { 390 if ((him->sin_addr.s_addr == sa_recv.sin_addr.s_addr)) { 391 close(fd); 392 return JNI_TRUE; 393 } 394 395 if (him->sin_addr.s_addr == 0) { 396 close(fd); 397 return JNI_TRUE; 398 } 399 } 400 401 } 402 } while (tmout2 > 0); 403 timeout -= 1000; 404 } while (timeout >0); 405 close(fd); 406 return JNI_FALSE; 407} 408 409/* 410 * Class: java_net_Inet4AddressImpl 411 * Method: isReachable0 412 * Signature: ([bI[bI)Z 413 */ 414JNIEXPORT jboolean JNICALL 415Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this, 416 jbyteArray addrArray, 417 jint timeout, 418 jbyteArray ifArray, 419 jint ttl) { 420 jint addr; 421 jbyte caddr[4]; 422 jint fd; 423 struct sockaddr_in him; 424 struct sockaddr_in* netif = NULL; 425 struct sockaddr_in inf; 426 int len = 0; 427 int connect_rv = -1; 428 int sz; 429 430 memset((char *) caddr, 0, sizeof(caddr)); 431 memset((char *) &him, 0, sizeof(him)); 432 memset((char *) &inf, 0, sizeof(inf)); 433 sz = (*env)->GetArrayLength(env, addrArray); 434 if (sz != 4) { 435 return JNI_FALSE; 436 } 437 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); 438 addr = ((caddr[0]<<24) & 0xff000000); 439 addr |= ((caddr[1] <<16) & 0xff0000); 440 addr |= ((caddr[2] <<8) & 0xff00); 441 addr |= (caddr[3] & 0xff); 442 addr = htonl(addr); 443 him.sin_addr.s_addr = addr; 444 him.sin_family = AF_INET; 445 len = sizeof(him); 446 /* 447 * If a network interface was specified, let's create the address 448 * for it. 449 */ 450 if (!(IS_NULL(ifArray))) { 451 memset((char *) caddr, 0, sizeof(caddr)); 452 (*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr); 453 addr = ((caddr[0]<<24) & 0xff000000); 454 addr |= ((caddr[1] <<16) & 0xff0000); 455 addr |= ((caddr[2] <<8) & 0xff00); 456 addr |= (caddr[3] & 0xff); 457 addr = htonl(addr); 458 inf.sin_addr.s_addr = addr; 459 inf.sin_family = AF_INET; 460 inf.sin_port = 0; 461 netif = &inf; 462 } 463 464 /* 465 * Let's try to create a RAW socket to send ICMP packets 466 * This usually requires "root" privileges, so it's likely to fail. 467 */ 468 fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 469 if (fd != -1) { 470 /* 471 * It didn't fail, so we can use ICMP_ECHO requests. 472 */ 473 return ping4(env, fd, &him, timeout, netif, ttl); 474 } 475 476 /* 477 * Can't create a raw socket, so let's try a TCP socket 478 */ 479 fd = socket(AF_INET, SOCK_STREAM, 0); 480 if (fd == -1) { 481 /* note: if you run out of fds, you may not be able to load 482 * the exception class, and get a NoClassDefFoundError 483 * instead. 484 */ 485 NET_ThrowNew(env, errno, "Can't create socket"); 486 return JNI_FALSE; 487 } 488 if (ttl > 0) { 489 setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); 490 } 491 492 /* 493 * A network interface was specified, so let's bind to it. 494 */ 495 if (netif != NULL) { 496 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) { 497 NET_ThrowNew(env, errno, "Can't bind socket"); 498 close(fd); 499 return JNI_FALSE; 500 } 501 } 502 503 /* 504 * Make the socket non blocking so we can use select/poll. 505 */ 506 SET_NONBLOCKING(fd); 507 508 him.sin_port = htons(7); /* Echo */ 509 connect_rv = NET_Connect(fd, (struct sockaddr *)&him, len); 510 511 /** 512 * connection established or refused immediately, either way it means 513 * we were able to reach the host! 514 */ 515 if (connect_rv == 0 || errno == ECONNREFUSED) { 516 close(fd); 517 return JNI_TRUE; 518 } else { 519 socklen_t optlen = (socklen_t)sizeof(connect_rv); 520 521 switch (errno) { 522 case ENETUNREACH: /* Network Unreachable */ 523 case EAFNOSUPPORT: /* Address Family not supported */ 524 case EADDRNOTAVAIL: /* address is not available on the remote machine */ 525#if defined(__linux__) || defined(_AIX) 526 case EINVAL: 527 case EHOSTUNREACH: /* No route to host */ 528 /* 529 * On some Linux versions, when a socket is bound to the loopback 530 * interface, connect will fail and errno will be set to EINVAL 531 * or EHOSTUNREACH. When that happens, don't throw an exception, 532 * just return false. 533 */ 534#endif /* __linux__ */ 535 close(fd); 536 return JNI_FALSE; 537 } 538 539 if (errno != EINPROGRESS) { 540 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", 541 "connect failed"); 542 close(fd); 543 return JNI_FALSE; 544 } 545 546 timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout); 547 if (timeout >= 0) { 548 /* has connection been established? */ 549 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv, 550 &optlen) <0) { 551 connect_rv = errno; 552 } 553 if (connect_rv == 0 || connect_rv == ECONNREFUSED) { 554 close(fd); 555 return JNI_TRUE; 556 } 557 } 558 close(fd); 559 return JNI_FALSE; 560 } 561} 562