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 <errno.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <netdb.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #ifdef _ALLBSD_SOURCE
37 #include <ifaddrs.h>
38 #include <net/if.h>
39 #include <unistd.h> /* gethostname */
40 #endif
41
42 #include "jvm.h"
43 #include "jni_util.h"
44 #include "net_util.h"
45 #ifndef IPV6_DEFS_H
46 #include <netinet/icmp6.h>
47 #endif
48
49 #include "java_net_Inet4AddressImpl.h"
50 #include "java_net_Inet6AddressImpl.h"
51
52 /* the initial size of our hostent buffers */
53 #ifndef NI_MAXHOST
54 #define NI_MAXHOST 1025
55 #endif
56
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[NI_MAXHOST + 1];
70
71 hostname[0] = '\0';
72 if (JVM_GetHostName(hostname, sizeof(hostname))) {
73 strcpy(hostname, "localhost");
74 #if defined(__solaris__) && defined(AF_INET6)
75 } else {
76 // try to resolve hostname via nameservice
77 // if it is known but getnameinfo fails, hostname will still be the
78 // value from gethostname
79 struct addrinfo hints, *res;
80
81 // make sure string is null-terminated
82 hostname[NI_MAXHOST] = '\0';
83 memset(&hints, 0, sizeof(hints));
84 hints.ai_flags = AI_CANONNAME;
85 hints.ai_family = AF_UNSPEC;
86
87 if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
88 getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST,
89 NULL, 0, NI_NAMEREQD);
90 freeaddrinfo(res);
91 }
92 }
93 #else
94 } else {
95 // make sure string is null-terminated
96 hostname[NI_MAXHOST] = '\0';
97 }
98 #endif
99 return (*env)->NewStringUTF(env, hostname);
100 }
101
102 #ifdef _ALLBSD_SOURCE
103 /* also called from Inet4AddressImpl.c */
104 jobjectArray
lookupIfLocalhost(JNIEnv * env,const char * hostname,jboolean includeV6)105 lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6)
106 {
107 jobjectArray result = NULL;
108 char myhostname[NI_MAXHOST+1];
109 struct ifaddrs *ifa = NULL;
110 int familyOrder = 0;
111 int count = 0, i, j;
112 int addrs4 = 0, addrs6 = 0, numV4Loopbacks = 0, numV6Loopbacks = 0;
113 jboolean includeLoopback = JNI_FALSE;
114 jobject name;
115
116 initInetAddressIDs(env);
117 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
118
119 /* If the requested name matches this host's hostname, return IP addresses
120 * from all attached interfaces. (#2844683 et al) This prevents undesired
121 * PPP dialup, but may return addresses that don't actually correspond to
122 * the name (if the name actually matches something in DNS etc.
123 */
124 myhostname[0] = '\0';
125 if (JVM_GetHostName(myhostname, NI_MAXHOST)) {
126 /* Something went wrong, maybe networking is not setup? */
127 return NULL;
128 }
129 myhostname[NI_MAXHOST] = '\0';
130
131 if (strcmp(myhostname, hostname) != 0) {
132 // Non-self lookup
133 return NULL;
134 }
135
136 if (getifaddrs(&ifa) != 0) {
137 NET_ThrowNew(env, errno, "Can't get local interface addresses");
138 return NULL;
139 }
140
141 name = (*env)->NewStringUTF(env, hostname);
142 if (name == NULL) {
143 freeifaddrs(ifa);
144 return NULL;
145 }
146
147 /* Iterate over the interfaces, and total up the number of IPv4 and IPv6
148 * addresses we have. Also keep a count of loopback addresses. We need to
149 * exclude them in the normal case, but return them if we don't get an IP
150 * address.
151 */
152 struct ifaddrs *iter = ifa;
153 while (iter) {
154 int family = iter->ifa_addr->sa_family;
155 if (iter->ifa_name[0] != '\0' && iter->ifa_addr)
156 {
157 jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
158 if (family == AF_INET) {
159 addrs4++;
160 if (isLoopback) numV4Loopbacks++;
161 } else if (family == AF_INET6 && includeV6) {
162 addrs6++;
163 if (isLoopback) numV6Loopbacks++;
164 } else {
165 /* We don't care e.g. AF_LINK */
166 }
167 }
168 iter = iter->ifa_next;
169 }
170
171 if (addrs4 == numV4Loopbacks && addrs6 == numV6Loopbacks) {
172 // We don't have a real IP address, just loopback. We need to include
173 // loopback in our results.
174 includeLoopback = JNI_TRUE;
175 }
176
177 /* Create and fill the Java array. */
178 int arraySize = addrs4 + addrs6 -
179 (includeLoopback ? 0 : (numV4Loopbacks + numV6Loopbacks));
180 result = (*env)->NewObjectArray(env, arraySize, ia_class, NULL);
181 if (!result) goto done;
182
183 if ((*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID)) {
184 i = includeLoopback ? addrs6 : (addrs6 - numV6Loopbacks);
185 j = 0;
186 } else {
187 i = 0;
188 j = includeLoopback ? addrs4 : (addrs4 - numV4Loopbacks);
189 }
190
191 // Now loop around the ifaddrs
192 iter = ifa;
193 while (iter != NULL) {
194 jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
195 int family = iter->ifa_addr->sa_family;
196
197 if (iter->ifa_name[0] != '\0' && iter->ifa_addr
198 && (family == AF_INET || (family == AF_INET6 && includeV6))
199 && (!isLoopback || includeLoopback))
200 {
201 int port;
202 int index = (family == AF_INET) ? i++ : j++;
203 jobject o = NET_SockaddrToInetAddress(env, iter->ifa_addr, &port);
204 if (!o) {
205 freeifaddrs(ifa);
206 if (!(*env)->ExceptionCheck(env))
207 JNU_ThrowOutOfMemoryError(env, "Object allocation failed");
208 return NULL;
209 }
210 setInetAddress_hostName(env, o, name);
211 if ((*env)->ExceptionCheck(env))
212 goto done;
213 (*env)->SetObjectArrayElement(env, result, index, o);
214 (*env)->DeleteLocalRef(env, o);
215 }
216 iter = iter->ifa_next;
217 }
218
219 done:
220 freeifaddrs(ifa);
221
222 return result;
223 }
224 #endif
225
226 /*
227 * Find an internet address for a given hostname. Note that this
228 * code only works for addresses of type INET. The translation
229 * of %d.%d.%d.%d to an address (int) occurs in java now, so the
230 * String "host" shouldn't *ever* be a %d.%d.%d.%d string
231 *
232 * Class: java_net_Inet6AddressImpl
233 * Method: lookupAllHostAddr
234 * Signature: (Ljava/lang/String;)[[B
235 */
236
237 JNIEXPORT jobjectArray JNICALL
Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv * env,jobject this,jstring host)238 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
239 jstring host) {
240 const char *hostname;
241 jobjectArray ret = 0;
242 int retLen = 0;
243
244 int getaddrinfo_error=0;
245 #ifdef AF_INET6
246 struct addrinfo hints, *res, *resNew = NULL;
247 #endif /* AF_INET6 */
248
249 initInetAddressIDs(env);
250 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
251
252 if (IS_NULL(host)) {
253 JNU_ThrowNullPointerException(env, "host is null");
254 return 0;
255 }
256 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
257 CHECK_NULL_RETURN(hostname, NULL);
258
259 #ifdef _ALLBSD_SOURCE
260 /*
261 * If we're looking up the local machine, attempt to get the address
262 * from getifaddrs. This ensures we get an IPv6 address for the local
263 * machine.
264 */
265 ret = lookupIfLocalhost(env, hostname, JNI_TRUE);
266 if (ret != NULL || (*env)->ExceptionCheck(env)) {
267 JNU_ReleaseStringPlatformChars(env, host, hostname);
268 return ret;
269 }
270 #endif
271
272 #ifdef AF_INET6
273 /* Try once, with our static buffer. */
274 memset(&hints, 0, sizeof(hints));
275 hints.ai_flags = AI_CANONNAME;
276 hints.ai_family = AF_UNSPEC;
277
278 #ifdef __solaris__
279 /*
280 * Workaround for Solaris bug 4160367 - if a hostname contains a
281 * white space then 0.0.0.0 is returned
282 */
283 if (isspace((unsigned char)hostname[0])) {
284 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
285 hostname);
286 JNU_ReleaseStringPlatformChars(env, host, hostname);
287 return NULL;
288 }
289 #endif
290
291 getaddrinfo_error = getaddrinfo(hostname, NULL, &hints, &res);
292
293 #ifdef MACOSX
294 if (getaddrinfo_error) {
295 /*
296 * If getaddrinfo fails looking up the local machine, attempt to get the
297 * address from getifaddrs. This ensures we get an IPv6 address for the
298 * local machine.
299 */
300 ret = lookupIfLocalhost(env, hostname, JNI_TRUE);
301 if (ret != NULL || (*env)->ExceptionCheck(env)) {
302 JNU_ReleaseStringPlatformChars(env, host, hostname);
303 return ret;
304 }
305 }
306 #endif
307
308 if (getaddrinfo_error) {
309 /* report error */
310 ThrowUnknownHostExceptionWithGaiError(
311 env, hostname, getaddrinfo_error);
312 JNU_ReleaseStringPlatformChars(env, host, hostname);
313 return NULL;
314 } else {
315 int i = 0;
316 int inetCount = 0, inet6Count = 0, inetIndex, inet6Index;
317 struct addrinfo *itr, *last = NULL, *iterator = res;
318 while (iterator != NULL) {
319 int skip = 0;
320 itr = resNew;
321 while (itr != NULL) {
322 if (iterator->ai_family == itr->ai_family &&
323 iterator->ai_addrlen == itr->ai_addrlen) {
324 if (itr->ai_family == AF_INET) { /* AF_INET */
325 struct sockaddr_in *addr1, *addr2;
326 addr1 = (struct sockaddr_in *)iterator->ai_addr;
327 addr2 = (struct sockaddr_in *)itr->ai_addr;
328 if (addr1->sin_addr.s_addr ==
329 addr2->sin_addr.s_addr) {
330 skip = 1;
331 break;
332 }
333 } else {
334 int t;
335 struct sockaddr_in6 *addr1, *addr2;
336 addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
337 addr2 = (struct sockaddr_in6 *)itr->ai_addr;
338
339 for (t = 0; t < 16; t++) {
340 if (addr1->sin6_addr.s6_addr[t] !=
341 addr2->sin6_addr.s6_addr[t]) {
342 break;
343 }
344 }
345 if (t < 16) {
346 itr = itr->ai_next;
347 continue;
348 } else {
349 skip = 1;
350 break;
351 }
352 }
353 } else if (iterator->ai_family != AF_INET &&
354 iterator->ai_family != AF_INET6) {
355 /* we can't handle other family types */
356 skip = 1;
357 break;
358 }
359 itr = itr->ai_next;
360 }
361
362 if (!skip) {
363 struct addrinfo *next
364 = (struct addrinfo*) malloc(sizeof(struct addrinfo));
365 if (!next) {
366 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
367 ret = NULL;
368 goto cleanupAndReturn;
369 }
370 memcpy(next, iterator, sizeof(struct addrinfo));
371 next->ai_next = NULL;
372 if (resNew == NULL) {
373 resNew = next;
374 } else {
375 last->ai_next = next;
376 }
377 last = next;
378 i++;
379 if (iterator->ai_family == AF_INET) {
380 inetCount ++;
381 } else if (iterator->ai_family == AF_INET6) {
382 inet6Count ++;
383 }
384 }
385 iterator = iterator->ai_next;
386 }
387 retLen = i;
388 iterator = resNew;
389
390 ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
391
392 if (IS_NULL(ret)) {
393 /* we may have memory to free at the end of this */
394 goto cleanupAndReturn;
395 }
396
397 if ((*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID)) {
398 /* AF_INET addresses will be offset by inet6Count */
399 inetIndex = inet6Count;
400 inet6Index = 0;
401 } else {
402 /* AF_INET6 addresses will be offset by inetCount */
403 inetIndex = 0;
404 inet6Index = inetCount;
405 }
406
407 while (iterator != NULL) {
408 int ret1;
409 if (iterator->ai_family == AF_INET) {
410 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
411 if (IS_NULL(iaObj)) {
412 ret = NULL;
413 goto cleanupAndReturn;
414 }
415 setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
416 if ((*env)->ExceptionCheck(env))
417 goto cleanupAndReturn;
418 setInetAddress_hostName(env, iaObj, host);
419 if ((*env)->ExceptionCheck(env))
420 goto cleanupAndReturn;
421 (*env)->SetObjectArrayElement(env, ret, inetIndex, iaObj);
422 inetIndex++;
423 } else if (iterator->ai_family == AF_INET6) {
424 jint scope = 0;
425
426 jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
427 if (IS_NULL(iaObj)) {
428 ret = NULL;
429 goto cleanupAndReturn;
430 }
431 ret1 = setInet6Address_ipaddress(env, iaObj, (char *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
432 if (!ret1) {
433 ret = NULL;
434 goto cleanupAndReturn;
435 }
436
437 scope = ((struct sockaddr_in6*)iterator->ai_addr)->sin6_scope_id;
438 if (scope != 0) { /* zero is default value, no need to set */
439 setInet6Address_scopeid(env, iaObj, scope);
440 }
441 setInetAddress_hostName(env, iaObj, host);
442 if ((*env)->ExceptionCheck(env))
443 goto cleanupAndReturn;
444 (*env)->SetObjectArrayElement(env, ret, inet6Index, iaObj);
445 inet6Index++;
446 }
447 iterator = iterator->ai_next;
448 }
449 }
450
451 cleanupAndReturn:
452 {
453 struct addrinfo *iterator, *tmp;
454 iterator = resNew;
455 while (iterator != NULL) {
456 tmp = iterator;
457 iterator = iterator->ai_next;
458 free(tmp);
459 }
460 JNU_ReleaseStringPlatformChars(env, host, hostname);
461 }
462
463 freeaddrinfo(res);
464 #endif /* AF_INET6 */
465
466 return ret;
467 }
468
469 /*
470 * Class: java_net_Inet6AddressImpl
471 * Method: getHostByAddr
472 * Signature: (I)Ljava/lang/String;
473 */
474 JNIEXPORT jstring JNICALL
Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv * env,jobject this,jbyteArray addrArray)475 Java_java_net_Inet6AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
476 jbyteArray addrArray) {
477
478 jstring ret = NULL;
479
480 #ifdef AF_INET6
481 char host[NI_MAXHOST+1];
482 int error = 0;
483 int len = 0;
484 jbyte caddr[16];
485
486 struct sockaddr_in him4;
487 struct sockaddr_in6 him6;
488 struct sockaddr *sa;
489
490 /*
491 * For IPv4 addresses construct a sockaddr_in structure.
492 */
493 if ((*env)->GetArrayLength(env, addrArray) == 4) {
494 jint addr;
495 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
496 addr = ((caddr[0]<<24) & 0xff000000);
497 addr |= ((caddr[1] <<16) & 0xff0000);
498 addr |= ((caddr[2] <<8) & 0xff00);
499 addr |= (caddr[3] & 0xff);
500 memset((void *) &him4, 0, sizeof(him4));
501 him4.sin_addr.s_addr = (uint32_t) htonl(addr);
502 him4.sin_family = AF_INET;
503 sa = (struct sockaddr *) &him4;
504 len = sizeof(him4);
505 } else {
506 /*
507 * For IPv6 address construct a sockaddr_in6 structure.
508 */
509 (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
510 memset((void *) &him6, 0, sizeof(him6));
511 memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
512 him6.sin6_family = AF_INET6;
513 sa = (struct sockaddr *) &him6 ;
514 len = sizeof(him6) ;
515 }
516
517 error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0,
518 NI_NAMEREQD);
519
520 if (!error) {
521 ret = (*env)->NewStringUTF(env, host);
522 CHECK_NULL_RETURN(ret, NULL);
523 }
524 #endif /* AF_INET6 */
525
526 if (ret == NULL) {
527 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
528 }
529
530 return ret;
531 }
532
533 #define SET_NONBLOCKING(fd) { \
534 int flags = fcntl(fd, F_GETFL); \
535 flags |= O_NONBLOCK; \
536 fcntl(fd, F_SETFL, flags); \
537 }
538
539 #ifdef AF_INET6
540 static jboolean
ping6(JNIEnv * env,jint fd,struct sockaddr_in6 * him,jint timeout,struct sockaddr_in6 * netif,jint ttl)541 ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout,
542 struct sockaddr_in6* netif, jint ttl) {
543 jint size;
544 jint n;
545 socklen_t len;
546 char sendbuf[1500];
547 unsigned char recvbuf[1500];
548 struct icmp6_hdr *icmp6;
549 struct sockaddr_in6 sa_recv;
550 jbyte *caddr, *recv_caddr;
551 jchar pid;
552 jint tmout2, seq = 1;
553 struct timeval tv;
554 size_t plen;
555
556 #ifdef __linux__
557 {
558 int csum_offset;
559 /**
560 * For some strange reason, the linux kernel won't calculate the
561 * checksum of ICMPv6 packets unless you set this socket option
562 */
563 csum_offset = 2;
564 setsockopt(fd, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sizeof(int));
565 }
566 #endif
567
568 caddr = (jbyte *)&(him->sin6_addr);
569
570 /* icmp_id is a 16 bit data type, therefore down cast the pid */
571 pid = (jchar)getpid();
572 size = 60*1024;
573 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
574 if (ttl > 0) {
575 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
576 }
577 if (netif != NULL) {
578 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
579 NET_ThrowNew(env, errno, "Can't bind socket");
580 close(fd);
581 return JNI_FALSE;
582 }
583 }
584 SET_NONBLOCKING(fd);
585
586 do {
587 icmp6 = (struct icmp6_hdr *) sendbuf;
588 icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
589 icmp6->icmp6_code = 0;
590 /* let's tag the ECHO packet with our pid so we can identify it */
591 icmp6->icmp6_id = htons(pid);
592 icmp6->icmp6_seq = htons(seq);
593 seq++;
594 icmp6->icmp6_cksum = 0;
595 gettimeofday(&tv, NULL);
596 memcpy(sendbuf + sizeof(struct icmp6_hdr), &tv, sizeof(tv));
597 plen = sizeof(struct icmp6_hdr) + sizeof(tv);
598 n = sendto(fd, sendbuf, plen, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6));
599 if (n < 0 && errno != EINPROGRESS) {
600 #ifdef __linux__
601 if (errno != EINVAL && errno != EHOSTUNREACH)
602 /*
603 * On some Linux versions, when a socket is bound to the
604 * loopback interface, sendto will fail and errno will be
605 * set to EINVAL or EHOSTUNREACH.
606 * When that happens, don't throw an exception, just return false.
607 */
608 #endif /*__linux__ */
609 NET_ThrowNew(env, errno, "Can't send ICMP packet");
610 close(fd);
611 return JNI_FALSE;
612 }
613
614 tmout2 = timeout > 1000 ? 1000 : timeout;
615 do {
616 tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
617
618 if (tmout2 >= 0) {
619 len = sizeof(sa_recv);
620 n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*) &sa_recv, &len);
621 icmp6 = (struct icmp6_hdr *) (recvbuf);
622 recv_caddr = (jbyte *)&(sa_recv.sin6_addr);
623 /*
624 * We did receive something, but is it what we were expecting?
625 * I.E.: An ICMP6_ECHO_REPLY packet with the proper PID and
626 * from the host that we are trying to determine is reachable.
627 */
628 if (n >= 8 && icmp6->icmp6_type == ICMP6_ECHO_REPLY &&
629 (ntohs(icmp6->icmp6_id) == pid)) {
630 if (NET_IsEqual(caddr, recv_caddr)) {
631 close(fd);
632 return JNI_TRUE;
633 }
634 if (NET_IsZeroAddr(caddr)) {
635 close(fd);
636 return JNI_TRUE;
637 }
638 }
639 }
640 } while (tmout2 > 0);
641 timeout -= 1000;
642 } while (timeout > 0);
643 close(fd);
644 return JNI_FALSE;
645 }
646 #endif /* AF_INET6 */
647
648 /*
649 * Class: java_net_Inet6AddressImpl
650 * Method: isReachable0
651 * Signature: ([bII[bI)Z
652 */
653 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)654 Java_java_net_Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this,
655 jbyteArray addrArray,
656 jint scope,
657 jint timeout,
658 jbyteArray ifArray,
659 jint ttl, jint if_scope) {
660 #ifdef AF_INET6
661 jbyte caddr[16];
662 jint fd, sz;
663 struct sockaddr_in6 him6;
664 struct sockaddr_in6 inf6;
665 struct sockaddr_in6* netif = NULL;
666 int len = 0;
667 int connect_rv = -1;
668
669 /*
670 * If IPv6 is not enable, then we can't reach an IPv6 address, can we?
671 */
672 if (!ipv6_available()) {
673 return JNI_FALSE;
674 }
675 /*
676 * If it's an IPv4 address, ICMP won't work with IPv4 mapped address,
677 * therefore, let's delegate to the Inet4Address method.
678 */
679 sz = (*env)->GetArrayLength(env, addrArray);
680 if (sz == 4) {
681 return Java_java_net_Inet4AddressImpl_isReachable0(env, this,
682 addrArray,
683 timeout,
684 ifArray, ttl);
685 }
686
687 memset((void *) caddr, 0, 16);
688 memset((void *) &him6, 0, sizeof(him6));
689 (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr);
690 memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) );
691 him6.sin6_family = AF_INET6;
692 #ifdef __linux__
693 if (scope > 0)
694 him6.sin6_scope_id = scope;
695 else
696 him6.sin6_scope_id = getDefaultIPv6Interface( &(him6.sin6_addr));
697 len = sizeof(struct sockaddr_in6);
698 #else
699 if (scope > 0)
700 him6.sin6_scope_id = scope;
701 len = sizeof(struct sockaddr_in6);
702 #endif
703 /*
704 * If a network interface was specified, let's create the address
705 * for it.
706 */
707 if (!(IS_NULL(ifArray))) {
708 memset((void *) caddr, 0, 16);
709 memset((void *) &inf6, 0, sizeof(inf6));
710 (*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr);
711 memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) );
712 inf6.sin6_family = AF_INET6;
713 inf6.sin6_scope_id = if_scope;
714 netif = &inf6;
715 }
716 /*
717 * If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST
718 * otherwise we'll try a tcp socket to the Echo port (7).
719 * Note that this is empiric, and not connecting could mean it's blocked
720 * or the echo service has been disabled.
721 */
722
723 fd = JVM_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
724
725 if (fd != -1) { /* Good to go, let's do a ping */
726 return ping6(env, fd, &him6, timeout, netif, ttl);
727 }
728
729 /* No good, let's fall back on TCP */
730 fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0);
731 if (fd == JVM_IO_ERR) {
732 /* note: if you run out of fds, you may not be able to load
733 * the exception class, and get a NoClassDefFoundError
734 * instead.
735 */
736 NET_ThrowNew(env, errno, "Can't create socket");
737 return JNI_FALSE;
738 }
739 if (ttl > 0) {
740 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
741 }
742
743 /*
744 * A network interface was specified, so let's bind to it.
745 */
746 if (netif != NULL) {
747 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) {
748 NET_ThrowNew(env, errno, "Can't bind socket");
749 close(fd);
750 return JNI_FALSE;
751 }
752 }
753 SET_NONBLOCKING(fd);
754
755 /* no need to use NET_Connect as non-blocking */
756 him6.sin6_port = htons((short) 7); /* Echo port */
757 connect_rv = JVM_Connect(fd, (struct sockaddr *)&him6, len);
758
759 /**
760 * connection established or refused immediately, either way it means
761 * we were able to reach the host!
762 */
763 if (connect_rv == 0 || errno == ECONNREFUSED) {
764 close(fd);
765 return JNI_TRUE;
766 } else {
767 int optlen;
768
769 switch (errno) {
770 case ENETUNREACH: /* Network Unreachable */
771 case EAFNOSUPPORT: /* Address Family not supported */
772 case EADDRNOTAVAIL: /* address is not available on the remote machine */
773 #ifdef __linux__
774 case EINVAL:
775 case EHOSTUNREACH:
776 /*
777 * On some Linux versions, when a socket is bound to the
778 * loopback interface, connect will fail and errno will
779 * be set to EINVAL or EHOSTUNREACH. When that happens,
780 * don't throw an exception, just return false.
781 */
782 #endif /* __linux__ */
783 close(fd);
784 return JNI_FALSE;
785 }
786
787 if (errno != EINPROGRESS) {
788 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
789 "connect failed");
790 close(fd);
791 return JNI_FALSE;
792 }
793
794 timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
795
796 if (timeout >= 0) {
797 /* has connection been established */
798 optlen = sizeof(connect_rv);
799 if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
800 &optlen) <0) {
801 connect_rv = errno;
802 }
803 if (connect_rv == 0 || ECONNREFUSED) {
804 close(fd);
805 return JNI_TRUE;
806 }
807 }
808 close(fd);
809 return JNI_FALSE;
810 }
811 #else /* AF_INET6 */
812 return JNI_FALSE;
813 #endif /* AF_INET6 */
814 }
815