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       ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);

 146       ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");

 147       ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);

 148       ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");

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