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