1 /*
   2  * Copyright (c) 2000, 2016, 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 #include <iphlpapi.h>
  35 #include <icmpapi.h>
  36 
  37 #include "java_net_InetAddress.h"
  38 #include "java_net_Inet4AddressImpl.h"
  39 #include "java_net_Inet6AddressImpl.h"
  40 #include "net_util.h"
  41 #include "icmp.h"
  42 
  43 #ifdef WIN32
  44 #ifndef _WIN64
  45 
  46 /* Retain this code a little longer to support building in
  47  * old environments.  _MSC_VER is defined as:
  48  *     1200 for MSVC++ 6.0
  49  *     1310 for Vc7
  50  */
  51 #if defined(_MSC_VER) && _MSC_VER < 1310
  52 #define sockaddr_in6 SOCKADDR_IN6
  53 #endif
  54 #endif
  55 #define uint32_t UINT32
  56 #endif
  57 
  58 /*
  59  * Inet6AddressImpl
  60  */
  61 
  62 /*
  63  * Class:     java_net_Inet6AddressImpl
  64  * Method:    getLocalHostName
  65  * Signature: ()Ljava/lang/String;
  66  */
  67 JNIEXPORT jstring JNICALL
  68 Java_java_net_Inet6AddressImpl_getLocalHostName (JNIEnv *env, jobject this) {
  69     char hostname [256];
  70 
  71     if (gethostname (hostname, sizeof (hostname)) == -1) {
  72         strcpy (hostname, "localhost");
  73     }
  74     return JNU_NewStringPlatform (env, hostname);
  75 }
  76 
  77 JNIEXPORT jobjectArray JNICALL
  78 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
  79                                                 jstring host) {
  80     const char *hostname;
  81     jobjectArray ret = 0;
  82     int retLen = 0;
  83     jboolean preferIPv6Address;
  84 
  85     int error=0;
  86     struct addrinfo hints, *res, *resNew = NULL;
  87 
  88     initInetAddressIDs(env);
  89     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
  90 
  91     if (IS_NULL(host)) {
  92         JNU_ThrowNullPointerException(env, "host is null");
  93         return 0;
  94     }
  95     hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
  96     CHECK_NULL_RETURN(hostname, NULL);
  97 
  98     /* get the address preference */
  99     preferIPv6Address
 100         = (*env)->GetStaticIntField(env, ia_class, ia_preferIPv6AddressID);
 101 
 102     /* Try once, with our static buffer. */
 103     memset(&hints, 0, sizeof(hints));
 104     hints.ai_flags = AI_CANONNAME;
 105     hints.ai_family = AF_UNSPEC;
 106 
 107     error = getaddrinfo(hostname, NULL, &hints, &res);
 108 
 109     if (error) {
 110         if (WSAGetLastError() == WSATRY_AGAIN) {
 111             NET_ThrowByNameWithLastError(env,
 112                                          JNU_JAVANETPKG "UnknownHostException",
 113                                          hostname);
 114             JNU_ReleaseStringPlatformChars(env, host, hostname);
 115             return NULL;
 116         } else {
 117             /* report error */
 118             JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
 119                             (char *)hostname);
 120             JNU_ReleaseStringPlatformChars(env, host, hostname);
 121             return NULL;
 122         }
 123     } else {
 124         int i = 0;
 125         int inetCount = 0, inet6Count = 0, inetIndex = 0, inet6Index = 0, originalIndex = 0;
 126         struct addrinfo *itr, *last, *iterator = res;
 127         while (iterator != NULL) {
 128             int skip = 0;
 129             itr = resNew;
 130             while (itr != NULL) {
 131                 if (iterator->ai_family == itr->ai_family &&
 132                     iterator->ai_addrlen == itr->ai_addrlen) {
 133                     if (itr->ai_family == AF_INET) { /* AF_INET */
 134                         struct sockaddr_in *addr1, *addr2;
 135                         addr1 = (struct sockaddr_in *)iterator->ai_addr;
 136                         addr2 = (struct sockaddr_in *)itr->ai_addr;
 137                         if (addr1->sin_addr.s_addr ==
 138                             addr2->sin_addr.s_addr) {
 139                             skip = 1;
 140                             break;
 141                         }
 142                     } else {
 143                         int t;
 144                         struct sockaddr_in6 *addr1, *addr2;
 145                         addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
 146                         addr2 = (struct sockaddr_in6 *)itr->ai_addr;
 147 
 148                         for (t = 0; t < 16; t++) {
 149                             if (addr1->sin6_addr.s6_addr[t] !=
 150                                 addr2->sin6_addr.s6_addr[t]) {
 151                                 break;
 152                             }
 153                         }
 154                         if (t < 16) {
 155                             itr = itr->ai_next;
 156                             continue;
 157                         } else {
 158                             skip = 1;
 159                             break;
 160                         }
 161                     }
 162                 } else if (iterator->ai_family != AF_INET &&
 163                            iterator->ai_family != AF_INET6) {
 164                     /* we can't handle other family types */
 165                     skip = 1;
 166                     break;
 167                 }
 168                 itr = itr->ai_next;
 169             }
 170 
 171             if (!skip) {
 172                 struct addrinfo *next
 173                     = (struct addrinfo*) malloc(sizeof(struct addrinfo));
 174                 if (!next) {
 175                     JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
 176                     ret = NULL;
 177                     goto cleanupAndReturn;
 178                 }
 179                 memcpy(next, iterator, sizeof(struct addrinfo));
 180                 next->ai_next = NULL;
 181                 if (resNew == NULL) {
 182                     resNew = next;
 183                 } else {
 184                     last->ai_next = next;
 185                 }
 186                 last = next;
 187                 i++;
 188                 if (iterator->ai_family == AF_INET) {
 189                     inetCount ++;
 190                 } else if (iterator->ai_family == AF_INET6) {
 191                     inet6Count ++;
 192                 }
 193             }
 194             iterator = iterator->ai_next;
 195         }
 196         retLen = i;
 197         iterator = resNew;
 198         i = 0;
 199         ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
 200 
 201         if (IS_NULL(ret)) {
 202             /* we may have memory to free at the end of this */
 203             goto cleanupAndReturn;
 204         }
 205 
 206         if (preferIPv6Address == java_net_InetAddress_PREFER_IPV6_VALUE) {
 207             inetIndex = inet6Count;
 208             inet6Index = 0;
 209         } else if (preferIPv6Address == java_net_InetAddress_PREFER_IPV4_VALUE) {
 210             inetIndex = 0;
 211             inet6Index = inetCount;
 212         } else if (preferIPv6Address == java_net_InetAddress_PREFER_SYSTEM_VALUE) {
 213             inetIndex = inet6Index = originalIndex = 0;
 214         }
 215 
 216         while (iterator != NULL) {
 217             if (iterator->ai_family == AF_INET) {
 218               jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 219               if (IS_NULL(iaObj)) {
 220                 ret = NULL;
 221                 goto cleanupAndReturn;
 222               }
 223               setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
 224               setInetAddress_hostName(env, iaObj, host);
 225               (*env)->SetObjectArrayElement(env, ret, (inetIndex | originalIndex), iaObj);
 226                 inetIndex ++;
 227             } else if (iterator->ai_family == AF_INET6) {
 228               jint scope = 0;
 229               jboolean ret1;
 230               jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
 231               if (IS_NULL(iaObj)) {
 232                 ret = NULL;
 233                 goto cleanupAndReturn;
 234               }
 235               ret1 = setInet6Address_ipaddress(env, iaObj, (jbyte *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
 236               if (ret1 == JNI_FALSE) {
 237                 ret = NULL;
 238                 goto cleanupAndReturn;
 239               }
 240               scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
 241               if (scope != 0) { /* zero is default value, no need to set */
 242                 setInet6Address_scopeid(env, iaObj, scope);
 243               }
 244               setInetAddress_hostName(env, iaObj, host);
 245               (*env)->SetObjectArrayElement(env, ret, (inet6Index | originalIndex), iaObj);
 246               inet6Index ++;
 247             }
 248             if (preferIPv6Address == java_net_InetAddress_PREFER_SYSTEM_VALUE) {
 249                 originalIndex++;
 250                 inetIndex = inet6Index = 0;
 251             }
 252             iterator = iterator->ai_next;
 253         }
 254     }
 255 
 256 cleanupAndReturn:
 257     {
 258         struct addrinfo *iterator, *tmp;
 259         iterator = resNew;
 260         while (iterator != NULL) {
 261             tmp = iterator;
 262             iterator = iterator->ai_next;
 263             free(tmp);
 264         }
 265         JNU_ReleaseStringPlatformChars(env, host, hostname);
 266     }
 267 
 268     freeaddrinfo(res);
 269 
 270     return ret;
 271 }
 272 
 273 /*
 274  * Class:     java_net_Inet6AddressImpl
 275  * Method:    getHostByAddr
 276  * Signature: (I)Ljava/lang/String;
 277  */
 278 JNIEXPORT jstring JNICALL
 279 Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
 280                                             jbyteArray addrArray) {
 281     jstring ret = NULL;
 282 
 283     char host[NI_MAXHOST+1];
 284     int error = 0;
 285     int len = 0;
 286     jbyte caddr[16];
 287 
 288     struct sockaddr_in him4;
 289     struct sockaddr_in6 him6;
 290     struct sockaddr *sa;
 291 
 292     /*
 293      * For IPv4 addresses construct a sockaddr_in structure.
 294      */
 295     if ((*env)->GetArrayLength(env, addrArray) == 4) {
 296         jint addr;
 297         (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
 298         addr = ((caddr[0]<<24) & 0xff000000);
 299         addr |= ((caddr[1] <<16) & 0xff0000);
 300         addr |= ((caddr[2] <<8) & 0xff00);
 301         addr |= (caddr[3] & 0xff);
 302         memset((char *) &him4, 0, sizeof(him4));
 303         him4.sin_addr.s_addr = (uint32_t) htonl(addr);
 304         him4.sin_family = AF_INET;
 305         sa = (struct sockaddr *) &him4;
 306         len = sizeof(him4);
 307     } else {
 308         /*
 309          * For IPv6 address construct a sockaddr_in6 structure.
 310          */
 311         (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
 312         memset((char *) &him6, 0, sizeof(him6));
 313         memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
 314         him6.sin6_family = AF_INET6;
 315         sa = (struct sockaddr *) &him6 ;
 316         len = sizeof(him6) ;
 317     }
 318 
 319     error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
 320 
 321     if (!error) {
 322         ret = (*env)->NewStringUTF(env, host);
 323         CHECK_NULL_RETURN(ret, NULL);
 324     }
 325 
 326     if (ret == NULL) {
 327         JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
 328     }
 329 
 330     return ret;
 331 }
 332 
 333 #ifdef AF_INET6
 334 
 335 /**
 336  * ping implementation using tcp port 7 (echo)
 337  */
 338 static jboolean
 339 tcp_ping6(JNIEnv *env,
 340           jint timeout,
 341           jint ttl,
 342           struct sockaddr_in6 him6,
 343           struct sockaddr_in6* netif,
 344           int len)
 345 {
 346     jint fd;
 347     WSAEVENT hEvent;
 348     int connect_rv = -1;
 349 
 350     fd = NET_Socket(AF_INET6, SOCK_STREAM, 0);
 351     if (fd == SOCKET_ERROR) {
 352         /* note: if you run out of fds, you may not be able to load
 353          * the exception class, and get a NoClassDefFoundError
 354          * instead.
 355          */
 356         NET_ThrowNew(env, errno, "Can't create socket");
 357         return JNI_FALSE;
 358     }
 359 
 360     /**
 361      * A TTL was specified, let's set the socket option.
 362      */
 363     if (ttl > 0) {
 364       setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *)&ttl, sizeof(ttl));
 365     }
 366 
 367     /**
 368      * A network interface was specified, let's bind to it.
 369      */
 370     if (netif != NULL) {
 371       if (NET_Bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) < 0) {
 372         NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket to interface");
 373         closesocket(fd);
 374         return JNI_FALSE;
 375       }
 376     }
 377 
 378     /**
 379      * Make the socket non blocking.
 380      */
 381     hEvent = WSACreateEvent();
 382     WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);
 383 
 384     /* no need to use NET_Connect as non-blocking */
 385     him6.sin6_port = htons((short) 7); /* Echo port */
 386     connect_rv = connect(fd, (struct sockaddr *)&him6, len);
 387 
 388     /**
 389      * connection established or refused immediately, either way it means
 390      * we were able to reach the host!
 391      */
 392     if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) {
 393         WSACloseEvent(hEvent);
 394         closesocket(fd);
 395         return JNI_TRUE;
 396     } else {
 397         int optlen;
 398 
 399         switch (WSAGetLastError()) {
 400         case WSAEHOSTUNREACH:   /* Host Unreachable */
 401         case WSAENETUNREACH:    /* Network Unreachable */
 402         case WSAENETDOWN:       /* Network is down */
 403         case WSAEPFNOSUPPORT:   /* Protocol Family unsupported */
 404           WSACloseEvent(hEvent);
 405           closesocket(fd);
 406           return JNI_FALSE;
 407         }
 408 
 409         if (WSAGetLastError() != WSAEWOULDBLOCK) {
 410             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
 411                                          "connect failed");
 412             WSACloseEvent(hEvent);
 413             closesocket(fd);
 414             return JNI_FALSE;
 415         }
 416 
 417         timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
 418 
 419         if (timeout >= 0) {
 420           /* has connection been established? */
 421           optlen = sizeof(connect_rv);
 422           if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
 423                          &optlen) <0) {
 424             connect_rv = WSAGetLastError();
 425           }
 426 
 427           if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) {
 428             WSACloseEvent(hEvent);
 429             closesocket(fd);
 430             return JNI_TRUE;
 431           }
 432         }
 433     }
 434     WSACloseEvent(hEvent);
 435     closesocket(fd);
 436     return JNI_FALSE;
 437 }
 438 
 439 /**
 440  * ping implementation.
 441  * Send a ICMP_ECHO_REQUEST packet every second until either the timeout
 442  * expires or a answer is received.
 443  * Returns true is an ECHO_REPLY is received, otherwise, false.
 444  */
 445 static jboolean
 446 ping6(JNIEnv *env,
 447       struct sockaddr_in6* src,
 448       struct sockaddr_in6* dest,
 449       jint timeout,
 450       HANDLE hIcmpFile)
 451 {
 452     DWORD dwRetVal = 0;
 453     char SendData[32] = {0};
 454     LPVOID ReplyBuffer = NULL;
 455     DWORD ReplySize = 0;
 456     IP_OPTION_INFORMATION ipInfo = {255, 0, 0, 0, NULL};
 457     struct sockaddr_in6 sa6Source;
 458 
 459     ReplySize = sizeof(ICMPV6_ECHO_REPLY) + sizeof(SendData);
 460     ReplyBuffer = (VOID*) malloc(ReplySize);
 461     if (ReplyBuffer == NULL) {
 462         IcmpCloseHandle(hIcmpFile);
 463         NET_ThrowNew(env, WSAGetLastError(), "Unable to allocate memory");
 464         return JNI_FALSE;
 465     }
 466 
 467     //define local source information
 468     sa6Source.sin6_addr = in6addr_any;
 469     sa6Source.sin6_family = AF_INET6;
 470     sa6Source.sin6_flowinfo = 0;
 471     sa6Source.sin6_port = 0;
 472 
 473     dwRetVal = Icmp6SendEcho2(hIcmpFile,    // HANDLE IcmpHandle,
 474                               NULL,         // HANDLE Event,
 475                               NULL,         // PIO_APC_ROUTINE ApcRoutine,
 476                               NULL,         // PVOID ApcContext,
 477                               &sa6Source,   // struct sockaddr_in6 *SourceAddress,
 478                               dest,         // struct sockaddr_in6 *DestinationAddress,
 479                               SendData,     // LPVOID RequestData,
 480                               sizeof(SendData), // WORD RequestSize,
 481                               &ipInfo,      // PIP_OPTION_INFORMATION RequestOptions,
 482                               ReplyBuffer,  // LPVOID ReplyBuffer,
 483                               ReplySize,    // DWORD ReplySize,
 484                               timeout);     // DWORD Timeout
 485 
 486     free(ReplyBuffer);
 487     IcmpCloseHandle(hIcmpFile);
 488 
 489 
 490     if (dwRetVal != 0) {
 491         return JNI_TRUE;
 492     } else {
 493         return JNI_FALSE;
 494     }
 495 }
 496 #endif /* AF_INET6 */
 497 
 498 /*
 499  * Class:     java_net_Inet6AddressImpl
 500  * Method:    isReachable0
 501  * Signature: ([bII[bI)Z
 502  */
 503 JNIEXPORT jboolean JNICALL
 504 Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
 505                                            jbyteArray addrArray,
 506                                            jint scope,
 507                                            jint timeout,
 508                                            jbyteArray ifArray,
 509                                            jint ttl, jint if_scope) {
 510 #ifdef AF_INET6
 511     jbyte caddr[16];
 512     jint sz;
 513     struct sockaddr_in6 him6;
 514     struct sockaddr_in6* netif = NULL;
 515     struct sockaddr_in6 inf6;
 516     int len = 0;
 517     HANDLE hIcmpFile;
 518 
 519     /*
 520      * If IPv6 is not enable, then we can't reach an IPv6 address, can we?
 521      * Actually, we probably shouldn't even get here.
 522      */
 523     if (!ipv6_available()) {
 524       return JNI_FALSE;
 525     }
 526     /*
 527      * If it's an IPv4 address, ICMP won't work with IPv4 mapped address,
 528      * therefore, let's delegate to the Inet4Address method.
 529      */
 530     sz = (*env)->GetArrayLength(env, addrArray);
 531     if (sz == 4) {
 532       return Java_java_net_Inet4AddressImpl_isReachable0(env, this,
 533                                                          addrArray,
 534                                                          timeout,
 535                                                          ifArray, ttl);
 536     }
 537 
 538     memset((char *) caddr, 0, 16);
 539     memset((char *) &him6, 0, sizeof(him6));
 540     (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
 541     memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
 542     him6.sin6_family = AF_INET6;
 543     if (scope > 0) {
 544       him6.sin6_scope_id = scope;
 545     }
 546     len = sizeof(struct sockaddr_in6);
 547 
 548     /**
 549      * A network interface was specified, let's convert the address
 550      */
 551     if (!(IS_NULL(ifArray))) {
 552       memset((char *) caddr, 0, 16);
 553       memset((char *) &inf6, 0, sizeof(inf6));
 554       (*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
 555       memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) );
 556       inf6.sin6_family = AF_INET6;
 557       inf6.sin6_port = 0;
 558       inf6.sin6_scope_id = if_scope;
 559       netif = &inf6;
 560     }
 561 
 562     hIcmpFile = Icmp6CreateFile();
 563     if (hIcmpFile == INVALID_HANDLE_VALUE) {
 564         int err = WSAGetLastError();
 565         if (err == ERROR_ACCESS_DENIED) {
 566             // fall back to TCP echo if access is denied to ICMP
 567             return tcp_ping6(env, timeout, ttl, him6, netif, len);
 568         } else {
 569             NET_ThrowNew(env, err, "Unable to create ICMP file handle");
 570             return JNI_FALSE;
 571         }
 572     } else {
 573         return ping6(env, netif, &him6, timeout, hIcmpFile);
 574     }
 575 
 576 #endif /* AF_INET6 */
 577     return JNI_FALSE;
 578 }