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 }