1 /*
2  * Copyright (c) 2000, 2011, 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 #ifdef _ALLBSD_SOURCE
40 #include <unistd.h>
41 #include <sys/param.h>
42 #endif
43 
44 #include "jvm.h"
45 #include "jni_util.h"
46 #include "net_util.h"
47 
48 #include "JNIHelp.h"
49 
50 #define NATIVE_METHOD(className, functionName, signature) \
51 { #functionName, signature, (void*)(className ## _ ## functionName) }
52 
53 //#if defined(__GLIBC__) || (defined(__FreeBSD__) && (__FreeBSD_version >= 601104))
54 #define HAS_GLIBC_GETHOSTBY_R   1
55 //#endif
56 
57 #define SET_NONBLOCKING(fd) {           \
58         int flags = fcntl(fd, F_GETFL); \
59         flags |= O_NONBLOCK;            \
60         fcntl(fd, F_SETFL, flags);      \
61 }
62 
63 /**
64  * ping implementation.
65  * Send a ICMP_ECHO_REQUEST packet every second until either the timeout
66  * expires or a answer is received.
67  * Returns true is an ECHO_REPLY is received, otherwise, false.
68  */
69 static jboolean
ping4(JNIEnv * env,jint fd,struct sockaddr_in * him,jint timeout,struct sockaddr_in * netif,jint ttl)70 ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout,
71       struct sockaddr_in* netif, jint ttl) {
72     jint size;
73     jint n, hlen1, icmplen;
74     socklen_t len;
75     char sendbuf[1500];
76     char recvbuf[1500];
77     struct icmp *icmp;
78     struct ip *ip;
79     struct sockaddr_in sa_recv;
80     jchar pid;
81     jint tmout2, seq = 1;
82     struct timeval tv;
83     size_t plen;
84 
85     /* icmp_id is a 16 bit data type, therefore down cast the pid */
86     pid = (jchar)getpid();
87     size = 60*1024;
88     setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
89     /*
90      * sets the ttl (max number of hops)
91      */
92     if (ttl > 0) {
93       setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
94     }
95     /*
96      * a specific interface was specified, so let's bind the socket
97      * to that interface to ensure the requests are sent only through it.
98      */
99     if (netif != NULL) {
100       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
101         NET_ThrowNew(env, errno, "Can't bind socket");
102         untagSocket(env, fd);
103         close(fd);
104         return JNI_FALSE;
105       }
106     }
107     /*
108      * Make the socket non blocking so we can use select
109      */
110     SET_NONBLOCKING(fd);
111     do {
112       /*
113        * create the ICMP request
114        */
115       icmp = (struct icmp *) sendbuf;
116       icmp->icmp_type = ICMP_ECHO;
117       icmp->icmp_code = 0;
118       icmp->icmp_id = htons(pid);
119       icmp->icmp_seq = htons(seq);
120       seq++;
121       gettimeofday(&tv, NULL);
122       memcpy(icmp->icmp_data, &tv, sizeof(tv));
123       plen = ICMP_ADVLENMIN + sizeof(tv);
124       icmp->icmp_cksum = 0;
125       icmp->icmp_cksum = in_cksum((u_short *)icmp, plen);
126       /*
127        * send it
128        */
129       n = sendto(fd, sendbuf, plen, 0, (struct sockaddr *)him,
130                  sizeof(struct sockaddr));
131       if (n < 0 && errno != EINPROGRESS ) {
132 #ifdef __linux__
133         if (errno != EINVAL && errno != EHOSTUNREACH)
134           /*
135            * On some Linuxes, when bound to the loopback interface, sendto
136            * will fail and errno will be set to EINVAL or EHOSTUNREACH.
137            * When that happens, don't throw an exception, just return false.
138            */
139 #endif /*__linux__ */
140           NET_ThrowNew(env, errno, "Can't send ICMP packet");
141         untagSocket(env, fd);
142         close(fd);
143         return JNI_FALSE;
144       }
145 
146       tmout2 = timeout > 1000 ? 1000 : timeout;
147       do {
148         tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
149         if (tmout2 >= 0) {
150           len = sizeof(sa_recv);
151           n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&sa_recv, &len);
152           ip = (struct ip*) recvbuf;
153           hlen1 = (ip->ip_hl) << 2;
154           icmp = (struct icmp *) (recvbuf + hlen1);
155           icmplen = n - hlen1;
156           /*
157            * We did receive something, but is it what we were expecting?
158            * I.E.: A ICMP_ECHOREPLY packet with the proper PID.
159            */
160           if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY
161                && (ntohs(icmp->icmp_id) == pid)) {
162             if ((him->sin_addr.s_addr == sa_recv.sin_addr.s_addr)) {
163               untagSocket(env, fd);
164               close(fd);
165               return JNI_TRUE;
166             }
167 
168             if (him->sin_addr.s_addr == 0) {
169               untagSocket(env, fd);
170               close(fd);
171               return JNI_TRUE;
172             }
173          }
174 
175         }
176       } while (tmout2 > 0);
177       timeout -= 1000;
178     } while (timeout >0);
179     untagSocket(env, fd);
180     close(fd);
181     return JNI_FALSE;
182 }
183 
184 /*
185  * Class:     java_net_Inet4AddressImpl
186  * Method:    isReachable0
187  * Signature: ([bI[bI)Z
188  */
189 JNIEXPORT jboolean JNICALL
Inet4AddressImpl_isReachable0(JNIEnv * env,jobject this,jbyteArray addrArray,jint timeout,jbyteArray ifArray,jint ttl)190 Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this,
191                                            jbyteArray addrArray,
192                                            jint timeout,
193                                            jbyteArray ifArray,
194                                            jint ttl) {
195     jint addr;
196     jbyte caddr[4];
197     jint fd;
198     struct sockaddr_in him;
199     struct sockaddr_in* netif = NULL;
200     struct sockaddr_in inf;
201     int len = 0;
202     int connect_rv = -1;
203     int sz;
204 
205     memset((char *) caddr, 0, sizeof(caddr));
206     memset((char *) &him, 0, sizeof(him));
207     memset((char *) &inf, 0, sizeof(inf));
208     sz = (*env)->GetArrayLength(env, addrArray);
209     if (sz != 4) {
210       return JNI_FALSE;
211     }
212     (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
213     addr = ((caddr[0]<<24) & 0xff000000);
214     addr |= ((caddr[1] <<16) & 0xff0000);
215     addr |= ((caddr[2] <<8) & 0xff00);
216     addr |= (caddr[3] & 0xff);
217     addr = htonl(addr);
218     him.sin_addr.s_addr = addr;
219     him.sin_family = AF_INET;
220     len = sizeof(him);
221     /*
222      * If a network interface was specified, let's create the address
223      * for it.
224      */
225     if (!(IS_NULL(ifArray))) {
226       memset((char *) caddr, 0, sizeof(caddr));
227       (*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr);
228       addr = ((caddr[0]<<24) & 0xff000000);
229       addr |= ((caddr[1] <<16) & 0xff0000);
230       addr |= ((caddr[2] <<8) & 0xff00);
231       addr |= (caddr[3] & 0xff);
232       addr = htonl(addr);
233       inf.sin_addr.s_addr = addr;
234       inf.sin_family = AF_INET;
235       inf.sin_port = 0;
236       netif = &inf;
237     }
238 
239     /*
240      * Let's try to create a RAW socket to send ICMP packets
241      * This usually requires "root" privileges, so it's likely to fail.
242      */
243     fd = JVM_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
244     if (fd != -1) {
245       /*
246        * It didn't fail, so we can use ICMP_ECHO requests.
247        */
248       tagSocket(env, fd);
249       return ping4(env, fd, &him, timeout, netif, ttl);
250     }
251 
252     /*
253      * Can't create a raw socket, so let's try a TCP socket
254      */
255     fd = JVM_Socket(AF_INET, SOCK_STREAM, 0);
256     if (fd == JVM_IO_ERR) {
257         /* note: if you run out of fds, you may not be able to load
258          * the exception class, and get a NoClassDefFoundError
259          * instead.
260          */
261         NET_ThrowNew(env, errno, "Can't create socket");
262         return JNI_FALSE;
263     }
264     tagSocket(env, fd);
265 
266     if (ttl > 0) {
267       setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
268     }
269 
270     /*
271      * A network interface was specified, so let's bind to it.
272      */
273     if (netif != NULL) {
274       if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
275         NET_ThrowNew(env, errno, "Can't bind socket");
276         untagSocket(env, fd);
277         close(fd);
278         return JNI_FALSE;
279       }
280     }
281 
282     /*
283      * Make the socket non blocking so we can use select/poll.
284      */
285     SET_NONBLOCKING(fd);
286 
287     /* no need to use NET_Connect as non-blocking */
288     him.sin_port = htons(7);    /* Echo */
289     connect_rv = JVM_Connect(fd, (struct sockaddr *)&him, len);
290 
291     /**
292      * connection established or refused immediately, either way it means
293      * we were able to reach the host!
294      */
295     if (connect_rv == 0 || errno == ECONNREFUSED) {
296         untagSocket(env, fd);
297         close(fd);
298         return JNI_TRUE;
299     } else {
300         int optlen;
301 
302         switch (errno) {
303         case ENETUNREACH: /* Network Unreachable */
304         case EAFNOSUPPORT: /* Address Family not supported */
305         case EADDRNOTAVAIL: /* address is not available on  the  remote machine */
306 #ifdef __linux__
307         case EINVAL:
308         case EHOSTUNREACH:
309           /*
310            * On some Linuxes, when bound to the loopback interface, connect
311            * will fail and errno will be set to EINVAL or EHOSTUNREACH.
312            * When that happens, don't throw an exception, just return false.
313            */
314 #endif /* __linux__ */
315           untagSocket(env, fd);
316           close(fd);
317           return JNI_FALSE;
318         }
319 
320         if (errno != EINPROGRESS) {
321           NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
322                                        "connect failed");
323           untagSocket(env, fd);
324           close(fd);
325           return JNI_FALSE;
326         }
327 
328         timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
329         if (timeout >= 0) {
330           /* has connection been established? */
331           optlen = sizeof(connect_rv);
332           if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
333                              &optlen) <0) {
334             connect_rv = errno;
335           }
336           if (connect_rv == 0 || connect_rv == ECONNREFUSED) {
337             untagSocket(env, fd);
338             close(fd);
339             return JNI_TRUE;
340           }
341         }
342         untagSocket(env, fd);
343         close(fd);
344         return JNI_FALSE;
345     }
346 }
347