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