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