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 <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 
  35 #include "java_net_InetAddress.h"
  36 #include "java_net_Inet4AddressImpl.h"
  37 #include "net_util.h"
  38 #include "icmp.h"
  39 
  40 
  41 /*
  42  * Returns true if hostname is in dotted IP address format. Note that this
  43  * function performs a syntax check only. For each octet it just checks that
  44  * the octet is at most 3 digits.
  45  */
  46 jboolean isDottedIPAddress(const char *hostname, unsigned int *addrp) {
  47     char *c = (char *)hostname;
  48     int octets = 0;
  49     unsigned int cur = 0;
  50     int digit_cnt = 0;
  51 
  52     while (*c) {
  53         if (*c == '.') {
  54             if (digit_cnt == 0) {
  55                 return JNI_FALSE;
  56             } else {
  57                 if (octets < 4) {
  58                     addrp[octets++] = cur;
  59                     cur = 0;
  60                     digit_cnt = 0;
  61                 } else {
  62                     return JNI_FALSE;
  63                 }
  64             }
  65             c++;
  66             continue;
  67         }
  68 
  69         if ((*c < '0') || (*c > '9')) {
  70             return JNI_FALSE;
  71         }
  72 
  73         digit_cnt++;
  74         if (digit_cnt > 3) {
  75             return JNI_FALSE;
  76         }
  77 
  78         /* don't check if current octet > 255 */
  79         cur = cur*10 + (*c - '0');
  80 
  81         /* Move onto next character and check for EOF */
  82         c++;
  83         if (*c == '\0') {
  84             if (octets < 4) {
  85                 addrp[octets++] = cur;
  86             } else {
  87                 return JNI_FALSE;
  88             }
  89         }
  90     }
  91 
  92     return (jboolean)(octets == 4);
  93 }
  94 
  95 /*
  96  * Inet4AddressImpl
  97  */
  98 
  99 /*
 100  * Class:     java_net_Inet4AddressImpl
 101  * Method:    getLocalHostName
 102  * Signature: ()Ljava/lang/String;
 103  */
 104 JNIEXPORT jstring JNICALL
 105 Java_java_net_Inet4AddressImpl_getLocalHostName (JNIEnv *env, jobject this) {
 106     char hostname[256];
 107 
 108     if (gethostname(hostname, sizeof hostname) == -1) {
 109         strcpy(hostname, "localhost");
 110     }
 111     return JNU_NewStringPlatform(env, hostname);
 112 }
 113 
 114 static jclass ni_iacls;
 115 static jclass ni_ia4cls;
 116 static jmethodID ni_ia4ctrID;
 117 static int initialized = 0;
 118 
 119 /*
 120  * Find an internet address for a given hostname.  Not this this
 121  * code only works for addresses of type INET. The translation
 122  * of %d.%d.%d.%d to an address (int) occurs in java now, so the
 123  * String "host" shouldn't be a %d.%d.%d.%d string. The only
 124  * exception should be when any of the %d are out of range and
 125  * we fallback to a lookup.
 126  *
 127  * Class:     java_net_Inet4AddressImpl
 128  * Method:    lookupAllHostAddr
 129  * Signature: (Ljava/lang/String;)[[B
 130  *
 131  * This is almost shared code
 132  */
 133 
 134 JNIEXPORT jobjectArray JNICALL
 135 Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
 136                                                 jstring host) {
 137     const char *hostname;
 138     struct hostent *hp;
 139     unsigned int addr[4];
 140 
 141     jobjectArray ret = NULL;
 142 
 143     if (!initialized) {
 144       ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
 145       CHECK_NULL_RETURN(ni_iacls, NULL);
 146       ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
 147       CHECK_NULL_RETURN(ni_iacls, NULL);
 148       ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
 149       CHECK_NULL_RETURN(ni_ia4cls, NULL);
 150       ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
 151       CHECK_NULL_RETURN(ni_ia4cls, NULL);
 152       ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
 153       CHECK_NULL_RETURN(ni_ia4ctrID, NULL);
 154       initialized = 1;
 155     }
 156 
 157     if (IS_NULL(host)) {
 158         JNU_ThrowNullPointerException(env, "host argument");
 159         return NULL;
 160     }
 161     hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
 162     CHECK_NULL_RETURN(hostname, NULL);
 163 
 164     /*
 165      * The NT/2000 resolver tolerates a space in front of localhost. This
 166      * is not consistent with other implementations of gethostbyname.
 167      * In addition we must do a white space check on Solaris to avoid a
 168      * bug whereby 0.0.0.0 is returned if any host name has a white space.
 169      */
 170     if (isspace(hostname[0])) {
 171         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", hostname);
 172         goto cleanupAndReturn;
 173     }
 174 
 175     /*
 176      * If the format is x.x.x.x then don't use gethostbyname as Windows
 177      * is unable to handle octets which are out of range.
 178      */
 179     if (isDottedIPAddress(hostname, &addr[0])) {
 180         unsigned int address;
 181         jobject iaObj;
 182 
 183         /*
 184          * Are any of the octets out of range?
 185          */
 186         if (addr[0] > 255 || addr[1] > 255 || addr[2] > 255 || addr[3] > 255) {
 187             JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", hostname);
 188             goto cleanupAndReturn;
 189         }
 190 
 191         /*
 192          * Return an byte array with the populated address.
 193          */
 194         address = (addr[3]<<24) & 0xff000000;
 195         address |= (addr[2]<<16) & 0xff0000;
 196         address |= (addr[1]<<8) & 0xff00;
 197         address |= addr[0];
 198 
 199         ret = (*env)->NewObjectArray(env, 1, ni_iacls, NULL);
 200 
 201         if (IS_NULL(ret)) {
 202             goto cleanupAndReturn;
 203         }
 204 
 205         iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
 206         if (IS_NULL(iaObj)) {
 207           ret = NULL;
 208           goto cleanupAndReturn;
 209         }
 210         setInetAddress_addr(env, iaObj, ntohl(address));
 211         (*env)->SetObjectArrayElement(env, ret, 0, iaObj);
 212         JNU_ReleaseStringPlatformChars(env, host, hostname);
 213         return ret;
 214     }
 215 
 216     /*
 217      * Perform the lookup
 218      */
 219     if ((hp = gethostbyname((char*)hostname)) != NULL) {
 220         struct in_addr **addrp = (struct in_addr **) hp->h_addr_list;
 221         int len = sizeof(struct in_addr);
 222         int i = 0;
 223 
 224         while (*addrp != (struct in_addr *) 0) {
 225             i++;
 226             addrp++;
 227         }
 228 
 229         ret = (*env)->NewObjectArray(env, i, ni_iacls, NULL);
 230 
 231         if (IS_NULL(ret)) {
 232             goto cleanupAndReturn;
 233         }
 234 
 235         addrp = (struct in_addr **) hp->h_addr_list;
 236         i = 0;
 237         while (*addrp != (struct in_addr *) 0) {
 238           jobject iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
 239           if (IS_NULL(iaObj)) {
 240             ret = NULL;
 241             goto cleanupAndReturn;
 242           }
 243           setInetAddress_addr(env, iaObj, ntohl((*addrp)->s_addr));
 244           setInetAddress_hostName(env, iaObj, host);
 245           (*env)->SetObjectArrayElement(env, ret, i, iaObj);
 246           addrp++;
 247           i++;
 248         }
 249     } else if (WSAGetLastError() == WSATRY_AGAIN) {
 250         NET_ThrowByNameWithLastError(env,
 251                                      JNU_JAVANETPKG "UnknownHostException",
 252                                      hostname);
 253     } else {
 254         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", hostname);
 255     }
 256 
 257 cleanupAndReturn:
 258     JNU_ReleaseStringPlatformChars(env, host, hostname);
 259     return ret;
 260 }
 261 
 262 /*
 263  * Class:     java_net_Inet4AddressImpl
 264  * Method:    getHostByAddr
 265  * Signature: (I)Ljava/lang/String;
 266  */
 267 JNIEXPORT jstring JNICALL
 268 Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
 269                                             jbyteArray addrArray) {
 270     struct hostent *hp;
 271     jbyte caddr[4];
 272     jint addr;
 273     (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
 274     addr = ((caddr[0]<<24) & 0xff000000);
 275     addr |= ((caddr[1] <<16) & 0xff0000);
 276     addr |= ((caddr[2] <<8) & 0xff00);
 277     addr |= (caddr[3] & 0xff);
 278     addr = htonl(addr);
 279 
 280     hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
 281     if (hp == NULL) {
 282         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 0);
 283         return NULL;
 284     }
 285     if (hp->h_name == NULL) { /* Deal with bug in Windows XP */
 286         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 0);
 287         return NULL;
 288     }
 289     return JNU_NewStringPlatform(env, hp->h_name);
 290 }
 291 
 292 
 293 /**
 294  * ping implementation.
 295  * Send a ICMP_ECHO_REQUEST packet every second until either the timeout
 296  * expires or a answer is received.
 297  * Returns true is an ECHO_REPLY is received, otherwise, false.
 298  */
 299 static jboolean
 300 ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout,
 301       struct sockaddr_in* netif, jint ttl) {
 302     jint size;
 303     jint n, len, hlen1, icmplen;
 304     char sendbuf[1500];
 305     char recvbuf[1500];
 306     struct icmp *icmp;
 307     struct ip *ip;
 308     WSAEVENT hEvent;
 309     struct sockaddr sa_recv;
 310     jint tmout2;
 311     u_short pid, seq;
 312     int read_rv = 0;
 313 
 314     /* Initialize the sequence number to a suitable random number and
 315        shift right one place to allow sufficient room for increamenting. */
 316     seq = ((unsigned short)rand()) >> 1;
 317 
 318     /* icmp_id is a 16 bit data type, therefore down cast the pid */
 319     pid = (u_short) _getpid();
 320     size = 60*1024;
 321     setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *) &size, sizeof(size));
 322     /**
 323      * A TTL was specified, let's set the socket option.
 324      */
 325     if (ttl > 0) {
 326       setsockopt(fd, IPPROTO_IP, IP_TTL, (const char *) &ttl, sizeof(ttl));
 327     }
 328 
 329     /**
 330      * A network interface was specified, let's bind to it.
 331      */
 332     if (netif != NULL) {
 333       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
 334         NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket");
 335         closesocket(fd);
 336         return JNI_FALSE;
 337       }
 338     }
 339 
 340     /**
 341      * Let's make the socket non blocking
 342      */
 343     hEvent = WSACreateEvent();
 344     WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);
 345 
 346     /**
 347      * send 1 ICMP REQUEST every second until either we get a valid reply
 348      * or the timeout expired.
 349      */
 350     do {
 351       /**
 352        * construct the ICMP header
 353        */
 354       memset(sendbuf, 0, 1500);
 355       icmp = (struct icmp *) sendbuf;
 356       icmp->icmp_type = ICMP_ECHO;
 357       icmp->icmp_code = 0;
 358       icmp->icmp_id = htons(pid);
 359       icmp->icmp_seq = htons(seq);
 360       /**
 361        * checksum has to be set to zero before we can calculate the
 362        * real checksum!
 363        */
 364       icmp->icmp_cksum = 0;
 365       icmp->icmp_cksum = in_cksum((u_short *)icmp, 64);
 366       /**
 367        * Ping!
 368        */
 369       n = sendto(fd, sendbuf, 64, 0, (struct sockaddr *)him,
 370                  sizeof(struct sockaddr));
 371       if (n < 0 && WSAGetLastError() != WSAEWOULDBLOCK) {
 372         NET_ThrowNew(env, WSAGetLastError(), "Can't send ICMP packet");
 373         closesocket(fd);
 374         WSACloseEvent(hEvent);
 375         return JNI_FALSE;
 376       }
 377 
 378       /*
 379        * wait for 1 second at most
 380        */
 381       tmout2 = timeout > 1000 ? 1000 : timeout;
 382       do {
 383         tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
 384         if (tmout2 >= 0) {
 385           len = sizeof(sa_recv);
 386           n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, &sa_recv, &len);
 387           ip = (struct ip*) recvbuf;
 388           hlen1 = (ip->ip_hl) << 2;
 389           icmp = (struct icmp *) (recvbuf + hlen1);
 390           icmplen = n - hlen1;
 391           /**
 392            * Is that a proper ICMP reply?
 393            */
 394           if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY &&
 395               (ntohs(icmp->icmp_seq) == seq) && (ntohs(icmp->icmp_id) == pid)) {
 396             closesocket(fd);
 397             WSACloseEvent(hEvent);
 398             return JNI_TRUE;
 399           }
 400         }
 401       } while (tmout2 > 0);
 402       timeout -= 1000;
 403       seq++;
 404     } while (timeout > 0);
 405     closesocket(fd);
 406     WSACloseEvent(hEvent);
 407     return JNI_FALSE;
 408 }
 409 
 410 /*
 411  * Class:     java_net_Inet4AddressImpl
 412  * Method:    isReachable0
 413  * Signature: ([bI[bI)Z
 414  */
 415 JNIEXPORT jboolean JNICALL
 416 Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this,
 417                                            jbyteArray addrArray,
 418                                            jint timeout,
 419                                            jbyteArray ifArray,
 420                                            jint ttl) {
 421     jint addr;
 422     jbyte caddr[4];
 423     jint fd;
 424     struct sockaddr_in him;
 425     struct sockaddr_in* netif = NULL;
 426     struct sockaddr_in inf;
 427     int len = 0;
 428     WSAEVENT hEvent;
 429     int connect_rv = -1;
 430     int sz;
 431 
 432     /**
 433      * Convert IP address from byte array to integer
 434      */
 435     sz = (*env)->GetArrayLength(env, addrArray);
 436     if (sz != 4) {
 437       return JNI_FALSE;
 438     }
 439     memset((char *) &him, 0, sizeof(him));
 440     memset((char *) caddr, 0, sizeof(caddr));
 441     (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
 442     addr = ((caddr[0]<<24) & 0xff000000);
 443     addr |= ((caddr[1] <<16) & 0xff0000);
 444     addr |= ((caddr[2] <<8) & 0xff00);
 445     addr |= (caddr[3] & 0xff);
 446     addr = htonl(addr);
 447     /**
 448      * Socket address
 449      */
 450     him.sin_addr.s_addr = addr;
 451     him.sin_family = AF_INET;
 452     len = sizeof(him);
 453 
 454     /**
 455      * If a network interface was specified, let's convert its address
 456      * as well.
 457      */
 458     if (!(IS_NULL(ifArray))) {
 459       memset((char *) caddr, 0, sizeof(caddr));
 460       (*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr);
 461       addr = ((caddr[0]<<24) & 0xff000000);
 462       addr |= ((caddr[1] <<16) & 0xff0000);
 463       addr |= ((caddr[2] <<8) & 0xff00);
 464       addr |= (caddr[3] & 0xff);
 465       addr = htonl(addr);
 466       inf.sin_addr.s_addr = addr;
 467       inf.sin_family = AF_INET;
 468       inf.sin_port = 0;
 469       netif = &inf;
 470     }
 471 
 472 #if 0
 473     /*
 474      * Windows implementation of ICMP & RAW sockets is too unreliable for now.
 475      * Therefore it's best not to try it at all and rely only on TCP
 476      * We may revisit and enable this code in the future.
 477      */
 478 
 479     /*
 480      * Let's try to create a RAW socket to send ICMP packets
 481      * This usually requires "root" privileges, so it's likely to fail.
 482      */
 483     fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
 484     if (fd != -1) {
 485       /*
 486        * It didn't fail, so we can use ICMP_ECHO requests.
 487        */
 488         return ping4(env, fd, &him, timeout, netif, ttl);
 489     }
 490 #endif
 491 
 492     /*
 493      * Can't create a raw socket, so let's try a TCP socket
 494      */
 495     fd = NET_Socket(AF_INET, SOCK_STREAM, 0);
 496     if (fd == JVM_IO_ERR) {
 497         /* note: if you run out of fds, you may not be able to load
 498          * the exception class, and get a NoClassDefFoundError
 499          * instead.
 500          */
 501         NET_ThrowNew(env, WSAGetLastError(), "Can't create socket");
 502         return JNI_FALSE;
 503     }
 504     if (ttl > 0) {
 505       setsockopt(fd, IPPROTO_IP, IP_TTL, (const char *)&ttl, sizeof(ttl));
 506     }
 507     /*
 508      * A network interface was specified, so let's bind to it.
 509      */
 510     if (netif != NULL) {
 511       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
 512         NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket");
 513         closesocket(fd);
 514         return JNI_FALSE;
 515       }
 516     }
 517 
 518     /*
 519      * Make the socket non blocking so we can use select/poll.
 520      */
 521     hEvent = WSACreateEvent();
 522     WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);
 523 
 524     /* no need to use NET_Connect as non-blocking */
 525     him.sin_port = htons(7);    /* Echo */
 526     connect_rv = connect(fd, (struct sockaddr *)&him, len);
 527 
 528     /**
 529      * connection established or refused immediately, either way it means
 530      * we were able to reach the host!
 531      */
 532     if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) {
 533         WSACloseEvent(hEvent);
 534         closesocket(fd);
 535         return JNI_TRUE;
 536     } else {
 537         int optlen;
 538 
 539         switch (WSAGetLastError()) {
 540         case WSAEHOSTUNREACH:   /* Host Unreachable */
 541         case WSAENETUNREACH:    /* Network Unreachable */
 542         case WSAENETDOWN:       /* Network is down */
 543         case WSAEPFNOSUPPORT:   /* Protocol Family unsupported */
 544           WSACloseEvent(hEvent);
 545           closesocket(fd);
 546           return JNI_FALSE;
 547         }
 548 
 549         if (WSAGetLastError() != WSAEWOULDBLOCK) {
 550             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
 551                                          "connect failed");
 552             WSACloseEvent(hEvent);
 553             closesocket(fd);
 554             return JNI_FALSE;
 555         }
 556 
 557         timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
 558 
 559         /* has connection been established */
 560 
 561         if (timeout >= 0) {
 562           optlen = sizeof(connect_rv);
 563           if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
 564                          &optlen) <0) {
 565             connect_rv = WSAGetLastError();
 566           }
 567 
 568           if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) {
 569             WSACloseEvent(hEvent);
 570             closesocket(fd);
 571             return JNI_TRUE;
 572           }
 573         }
 574     }
 575     WSACloseEvent(hEvent);
 576     closesocket(fd);
 577     return JNI_FALSE;
 578 }
--- EOF ---