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