1 /*
2  * Copyright (c) 2000, 2018, 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
Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv * env,jobject this)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
Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv * env,jobject this,jstring host)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)->GetStaticBooleanField(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, inet6Index;
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) {
207             inetIndex = inet6Count;
208             inet6Index = 0;
209         } else {
210             inetIndex = 0;
211             inet6Index = inetCount;
212         }
213 
214         while (iterator != NULL) {
215             if (iterator->ai_family == AF_INET) {
216               jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
217               if (IS_NULL(iaObj)) {
218                 ret = NULL;
219                 goto cleanupAndReturn;
220               }
221               setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
222               if ((*env)->ExceptionCheck(env))
223                   goto cleanupAndReturn;
224               setInetAddress_hostName(env, iaObj, host);
225               if ((*env)->ExceptionCheck(env))
226                   goto cleanupAndReturn;
227               (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj);
228                 inetIndex ++;
229             } else if (iterator->ai_family == AF_INET6) {
230               jint scope = 0, ret1;
231               jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
232               if (IS_NULL(iaObj)) {
233                 ret = NULL;
234                 goto cleanupAndReturn;
235               }
236               ret1 = setInet6Address_ipaddress(env, iaObj, (jbyte *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
237 
238               if (ret1 == JNI_FALSE) {
239                 ret = NULL;
240                 goto cleanupAndReturn;
241               }
242               scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
243               if (scope != 0) { /* zero is default value, no need to set */
244                 setInet6Address_scopeid(env, iaObj, scope);
245               }
246               setInetAddress_hostName(env, iaObj, host);
247               if ((*env)->ExceptionCheck(env))
248                   goto cleanupAndReturn;
249               (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj);
250               inet6Index ++;
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
Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv * env,jobject this,jbyteArray addrArray)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
tcp_ping6(JNIEnv * env,jint timeout,jint ttl,struct sockaddr_in6 him6,struct sockaddr_in6 * netif,int len)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
ping6(JNIEnv * env,struct sockaddr_in6 * src,struct sockaddr_in6 * dest,jint timeout,HANDLE hIcmpFile)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, -1, "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
Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv * env,jobject this,jbyteArray addrArray,jint scope,jint timeout,jbyteArray ifArray,jint ttl,jint if_scope)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 }
579