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