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