1 /*
  2  * Copyright (c) 2000, 2021, 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 #include "java_net_spi_InetAddressResolver_LookupPolicy.h"
 33 
 34 /*
 35  * Inet6AddressImpl
 36  */
 37 
 38 /*
 39  * Class:     java_net_Inet6AddressImpl
 40  * Method:    getLocalHostName
 41  * Signature: ()Ljava/lang/String;
 42  */
 43 JNIEXPORT jstring JNICALL
 44 Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
 45     char hostname[256];
 46 
 47     if (gethostname(hostname, sizeof(hostname)) == -1) {
 48         strcpy(hostname, "localhost");
 49     }
 50     return JNU_NewStringPlatform(env, hostname);
 51 }
 52 
 53 /*
 54  * Class:     java_net_Inet6AddressImpl
 55  * Method:    lookupAllHostAddr
 56  * Signature: (Ljava/lang/String;)[[B
 57  */
 58 JNIEXPORT jobjectArray JNICALL
 59 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
 60                                                  jstring host, jint characteristics) {
 61     jobjectArray ret = NULL;
 62     const char *hostname;
 63     int error = 0;
 64     struct addrinfo hints, *res = NULL, *resNew = NULL, *last = NULL,
 65         *iterator;
 66 
 67     initInetAddressIDs(env);
 68     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
 69 
 70     if (IS_NULL(host)) {
 71         JNU_ThrowNullPointerException(env, "host argument is null");
 72         return NULL;
 73     }
 74     hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
 75     CHECK_NULL_RETURN(hostname, NULL);
 76 
 77     // try once, with our static buffer
 78     memset(&hints, 0, sizeof(hints));
 79     hints.ai_flags = AI_CANONNAME;
 80     hints.ai_family = lookupCharacteristicsToAddressFamily(characteristics);
 81 
 82     error = getaddrinfo(hostname, NULL, &hints, &res);
 83 
 84     if (error) {
 85         // report error
 86         NET_ThrowByNameWithLastError(env, "java/net/UnknownHostException",
 87                                      hostname);
 88         goto cleanupAndReturn;
 89     } else {
 90         int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0,
 91             inet6Index = 0, originalIndex = 0;


 92         iterator = res;
 93         while (iterator != NULL) {
 94             // skip duplicates
 95             int skip = 0;
 96             struct addrinfo *iteratorNew = resNew;
 97             while (iteratorNew != NULL) {
 98                 if (iterator->ai_family == iteratorNew->ai_family &&
 99                     iterator->ai_addrlen == iteratorNew->ai_addrlen) {
100                     if (iteratorNew->ai_family == AF_INET) { /* AF_INET */
101                         struct sockaddr_in *addr1, *addr2;
102                         addr1 = (struct sockaddr_in *)iterator->ai_addr;
103                         addr2 = (struct sockaddr_in *)iteratorNew->ai_addr;
104                         if (addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) {
105                             skip = 1;
106                             break;
107                         }
108                     } else {
109                         int t;
110                         struct sockaddr_in6 *addr1, *addr2;
111                         addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
112                         addr2 = (struct sockaddr_in6 *)iteratorNew->ai_addr;
113 
114                         for (t = 0; t < 16; t++) {
115                             if (addr1->sin6_addr.s6_addr[t] !=
116                                 addr2->sin6_addr.s6_addr[t]) {
117                                 break;
118                             }
119                         }
120                         if (t < 16) {
121                             iteratorNew = iteratorNew->ai_next;
122                             continue;
123                         } else {
124                             skip = 1;
125                             break;
126                         }
127                     }
128                 } else if (iterator->ai_family != AF_INET &&
129                            iterator->ai_family != AF_INET6) {
130                     // we can't handle other family types
131                     skip = 1;
132                     break;
133                 }
134                 iteratorNew = iteratorNew->ai_next;
135             }
136 
137             if (!skip) {
138                 struct addrinfo *next
139                     = (struct addrinfo *)malloc(sizeof(struct addrinfo));
140                 if (!next) {
141                     JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
142                     ret = NULL;
143                     goto cleanupAndReturn;
144                 }
145                 memcpy(next, iterator, sizeof(struct addrinfo));
146                 next->ai_next = NULL;
147                 if (resNew == NULL) {
148                     resNew = next;
149                 } else {
150                     last->ai_next = next;
151                 }
152                 last = next;
153                 i++;
154                 if (iterator->ai_family == AF_INET) {
155                     inetCount++;
156                 } else if (iterator->ai_family == AF_INET6) {
157                     inet6Count++;
158                 }
159             }
160             iterator = iterator->ai_next;
161         }
162 
163         // allocate array - at this point i contains the number of addresses
164         ret = (*env)->NewObjectArray(env, i, ia_class, NULL);
165         if (IS_NULL(ret)) {
166             /* we may have memory to free at the end of this */
167             goto cleanupAndReturn;
168         }
169 
170         if ((characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV6_FIRST) != 0) {
171             inetIndex = inet6Count;
172             inet6Index = 0;
173         } else if ((characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV4_FIRST) != 0) {
174             inetIndex = 0;
175             inet6Index = inetCount;
176         } else {
177             inetIndex = inet6Index = originalIndex = 0;
178         }
179 
180         iterator = resNew;
181         while (iterator != NULL) {
182             if (iterator->ai_family == AF_INET) {
183                 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
184                 if (IS_NULL(iaObj)) {
185                     ret = NULL;
186                     goto cleanupAndReturn;
187                 }
188                 setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
189                 if ((*env)->ExceptionCheck(env))
190                     goto cleanupAndReturn;
191                 setInetAddress_hostName(env, iaObj, host);
192                 if ((*env)->ExceptionCheck(env))
193                     goto cleanupAndReturn;
194                 (*env)->SetObjectArrayElement(env, ret, (inetIndex | originalIndex), iaObj);
195                 inetIndex++;
196             } else if (iterator->ai_family == AF_INET6) {
197                 jint scope = 0;
198                 jboolean ret1;
199                 jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
200                 if (IS_NULL(iaObj)) {
201                     ret = NULL;
202                     goto cleanupAndReturn;
203                 }
204                 ret1 = setInet6Address_ipaddress(env, iaObj, (char *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
205                 if (ret1 == JNI_FALSE) {
206                     ret = NULL;
207                     goto cleanupAndReturn;
208                 }
209                 scope = ((struct sockaddr_in6 *)iterator->ai_addr)->sin6_scope_id;
210                 if (scope != 0) { // zero is default value, no need to set
211                     setInet6Address_scopeid(env, iaObj, scope);
212                 }
213                 setInetAddress_hostName(env, iaObj, host);
214                 if ((*env)->ExceptionCheck(env))
215                     goto cleanupAndReturn;
216                 (*env)->SetObjectArrayElement(env, ret, (inet6Index | originalIndex), iaObj);
217                 inet6Index++;
218             }
219             // Check if addresses are requested to be returned in SYSTEM order
220             if (addressesInSystemOrder(characteristics)) {
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: ([B)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
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
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
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[BII)Z
439  */
440 JNIEXPORT jboolean JNICALL
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 }
--- EOF ---