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