1/* 2 * Copyright (c) 2000, 2012, 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 <unistd.h> /* gethostname */ 38#endif 39 40#include "jvm.h" 41#include "jni_util.h" 42#include "net_util.h" 43#ifndef IPV6_DEFS_H 44#include <netinet/icmp6.h> 45#endif 46 47#include "java_net_Inet4AddressImpl.h" 48#include "JNIHelp.h" 49 50#define NATIVE_METHOD(className, functionName, signature) \ 51{ #functionName, signature, (void*)(className ## _ ## functionName) } 52 53/* the initial size of our hostent buffers */ 54#ifndef NI_MAXHOST 55#define NI_MAXHOST 1025 56#endif 57 58 59/************************************************************************ 60 * Inet6AddressImpl 61 */ 62 63static jclass ni_iacls; 64static jclass ni_ia4cls; 65static jclass ni_ia6cls; 66static jmethodID ni_ia4ctrID; 67static jmethodID ni_ia6ctrID; 68static jfieldID ni_ia6ipaddressID; 69static int initialized = 0; 70 71/* 72 * Class: java_net_Inet6AddressImpl 73 * Method: getHostByAddr 74 * Signature: (I)Ljava/lang/String; 75 */ 76JNIEXPORT jstring JNICALL 77Inet6AddressImpl_getHostByAddr0(JNIEnv *env, jobject this, 78 jbyteArray addrArray) { 79 80 jstring ret = NULL; 81 82#ifdef AF_INET6 83 char host[NI_MAXHOST+1]; 84 int error = 0; 85 int len = 0; 86 jbyte caddr[16]; 87 88 if (NET_addrtransAvailable()) { 89 struct sockaddr_in him4; 90 struct sockaddr_in6 him6; 91 struct sockaddr *sa; 92 93 /* 94 * For IPv4 addresses construct a sockaddr_in structure. 95 */ 96 if ((*env)->GetArrayLength(env, addrArray) == 4) { 97 jint addr; 98 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); 99 addr = ((caddr[0]<<24) & 0xff000000); 100 addr |= ((caddr[1] <<16) & 0xff0000); 101 addr |= ((caddr[2] <<8) & 0xff00); 102 addr |= (caddr[3] & 0xff); 103 memset((void *) &him4, 0, sizeof(him4)); 104 him4.sin_addr.s_addr = (uint32_t) htonl(addr); 105 him4.sin_family = AF_INET; 106 sa = (struct sockaddr *) &him4; 107 len = sizeof(him4); 108 } else { 109 /* 110 * For IPv6 address construct a sockaddr_in6 structure. 111 */ 112 (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr); 113 memset((void *) &him6, 0, sizeof(him6)); 114 memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) ); 115 him6.sin6_family = AF_INET6; 116 sa = (struct sockaddr *) &him6 ; 117 len = sizeof(him6) ; 118 } 119 120 error = (*getnameinfo_ptr)(sa, len, host, NI_MAXHOST, NULL, 0, 121 NI_NAMEREQD); 122 123 if (!error) { 124 ret = (*env)->NewStringUTF(env, host); 125 } 126 } 127#endif /* AF_INET6 */ 128 129 if (ret == NULL) { 130 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL); 131 } 132 133 return ret; 134} 135 136#define SET_NONBLOCKING(fd) { \ 137 int flags = fcntl(fd, F_GETFL); \ 138 flags |= O_NONBLOCK; \ 139 fcntl(fd, F_SETFL, flags); \ 140} 141 142#ifdef AF_INET6 143static jboolean 144ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout, 145 struct sockaddr_in6* netif, jint ttl) { 146 jint size; 147 jint n; 148 socklen_t len; 149 char sendbuf[1500]; 150 unsigned char recvbuf[1500]; 151 struct icmp6_hdr *icmp6; 152 struct sockaddr_in6 sa_recv; 153 jbyte *caddr, *recv_caddr; 154 jchar pid; 155 jint tmout2, seq = 1; 156 struct timeval tv; 157 size_t plen; 158 159#ifdef __linux__ 160 { 161 int csum_offset; 162 /** 163 * For some strange reason, the linux kernel won't calculate the 164 * checksum of ICMPv6 packets unless you set this socket option 165 */ 166 csum_offset = 2; 167 setsockopt(fd, SOL_RAW, IPV6_CHECKSUM, &csum_offset, sizeof(int)); 168 } 169#endif 170 171 caddr = (jbyte *)&(him->sin6_addr); 172 173 /* icmp_id is a 16 bit data type, therefore down cast the pid */ 174 pid = (jchar)getpid(); 175 size = 60*1024; 176 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); 177 if (ttl > 0) { 178 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); 179 } 180 if (netif != NULL) { 181 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) { 182 NET_ThrowNew(env, errno, "Can't bind socket"); 183 untagSocket(env, fd); 184 close(fd); 185 return JNI_FALSE; 186 } 187 } 188 SET_NONBLOCKING(fd); 189 190 do { 191 icmp6 = (struct icmp6_hdr *) sendbuf; 192 icmp6->icmp6_type = ICMP6_ECHO_REQUEST; 193 icmp6->icmp6_code = 0; 194 /* let's tag the ECHO packet with our pid so we can identify it */ 195 icmp6->icmp6_id = htons(pid); 196 icmp6->icmp6_seq = htons(seq); 197 seq++; 198 icmp6->icmp6_cksum = 0; 199 gettimeofday(&tv, NULL); 200 memcpy(sendbuf + sizeof(struct icmp6_hdr), &tv, sizeof(tv)); 201 plen = sizeof(struct icmp6_hdr) + sizeof(tv); 202 n = sendto(fd, sendbuf, plen, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6)); 203 if (n < 0 && errno != EINPROGRESS) { 204#ifdef __linux__ 205 if (errno != EINVAL && errno != EHOSTUNREACH) 206 /* 207 * On some Linuxes, when bound to the loopback interface, sendto 208 * will fail and errno will be set to EINVAL or EHOSTUNREACH. 209 * When that happens, don't throw an exception, just return false. 210 */ 211#endif /*__linux__ */ 212 NET_ThrowNew(env, errno, "Can't send ICMP packet"); 213 untagSocket(env, fd); 214 close(fd); 215 return JNI_FALSE; 216 } 217 218 tmout2 = timeout > 1000 ? 1000 : timeout; 219 do { 220 tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2); 221 222 if (tmout2 >= 0) { 223 len = sizeof(sa_recv); 224 n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*) &sa_recv, &len); 225 icmp6 = (struct icmp6_hdr *) (recvbuf); 226 recv_caddr = (jbyte *)&(sa_recv.sin6_addr); 227 /* 228 * We did receive something, but is it what we were expecting? 229 * I.E.: An ICMP6_ECHO_REPLY packet with the proper PID and 230 * from the host that we are trying to determine is reachable. 231 */ 232 if (n >= 8 && icmp6->icmp6_type == ICMP6_ECHO_REPLY && 233 (ntohs(icmp6->icmp6_id) == pid)) { 234 if (NET_IsEqual(caddr, recv_caddr)) { 235 untagSocket(env, fd); 236 close(fd); 237 return JNI_TRUE; 238 } 239 if (NET_IsZeroAddr(caddr)) { 240 untagSocket(env, fd); 241 close(fd); 242 return JNI_TRUE; 243 } 244 } 245 } 246 } while (tmout2 > 0); 247 timeout -= 1000; 248 } while (timeout > 0); 249 untagSocket(env, fd); 250 close(fd); 251 return JNI_FALSE; 252} 253#endif /* AF_INET6 */ 254 255/* 256 * Class: java_net_Inet6AddressImpl 257 * Method: isReachable0 258 * Signature: ([bII[bI)Z 259 */ 260JNIEXPORT jboolean JNICALL 261Inet6AddressImpl_isReachable0(JNIEnv *env, jobject this, 262 jbyteArray addrArray, 263 jint scope, 264 jint timeout, 265 jbyteArray ifArray, 266 jint ttl, jint if_scope) { 267#ifdef AF_INET6 268 jbyte caddr[16]; 269 jint fd, sz; 270 struct sockaddr_in6 him6; 271 struct sockaddr_in6 inf6; 272 struct sockaddr_in6* netif = NULL; 273 int len = 0; 274 int connect_rv = -1; 275 276 /* 277 * If IPv6 is not enable, then we can't reach an IPv6 address, can we? 278 */ 279 if (!ipv6_available()) { 280 return JNI_FALSE; 281 } 282 /* 283 * If it's an IPv4 address, ICMP won't work with IPv4 mapped address, 284 * therefore, let's delegate to the Inet4Address method. 285 */ 286 sz = (*env)->GetArrayLength(env, addrArray); 287 if (sz == 4) { 288 return Inet4AddressImpl_isReachable0(env, this, 289 addrArray, 290 timeout, 291 ifArray, ttl); 292 } 293 294 memset((void *) caddr, 0, 16); 295 memset((void *) &him6, 0, sizeof(him6)); 296 (*env)->GetByteArrayRegion(env, addrArray, 0, 16, caddr); 297 memcpy((void *)&(him6.sin6_addr), caddr, sizeof(struct in6_addr) ); 298 him6.sin6_family = AF_INET6; 299 300 // Android-change: Don't try and figure out a default scope ID if one isn't 301 // set. It's only useful for link local addresses anyway, and callers are 302 // expected to call isReachable with a specific NetworkInterface if they 303 // want to query the reachability of an address that's local to that IF. 304 if (scope > 0) 305 him6.sin6_scope_id = scope; 306 len = sizeof(struct sockaddr_in6); 307 /* 308 * If a network interface was specified, let's create the address 309 * for it. 310 */ 311 if (!(IS_NULL(ifArray))) { 312 memset((void *) caddr, 0, 16); 313 memset((void *) &inf6, 0, sizeof(inf6)); 314 (*env)->GetByteArrayRegion(env, ifArray, 0, 16, caddr); 315 memcpy((void *)&(inf6.sin6_addr), caddr, sizeof(struct in6_addr) ); 316 inf6.sin6_family = AF_INET6; 317 inf6.sin6_scope_id = if_scope; 318 netif = &inf6; 319 } 320 /* 321 * If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST 322 * otherwise we'll try a tcp socket to the Echo port (7). 323 * Note that this is empiric, and not connecting could mean it's blocked 324 * or the echo servioe has been disabled. 325 */ 326 327 fd = JVM_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 328 329 if (fd != -1) { /* Good to go, let's do a ping */ 330 tagSocket(env, fd); 331 return ping6(env, fd, &him6, timeout, netif, ttl); 332 } 333 334 /* No good, let's fall back on TCP */ 335 fd = JVM_Socket(AF_INET6, SOCK_STREAM, 0); 336 if (fd == JVM_IO_ERR) { 337 /* note: if you run out of fds, you may not be able to load 338 * the exception class, and get a NoClassDefFoundError 339 * instead. 340 */ 341 NET_ThrowNew(env, errno, "Can't create socket"); 342 return JNI_FALSE; 343 } 344 tagSocket(env, fd); 345 346 if (ttl > 0) { 347 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); 348 } 349 350 /* 351 * A network interface was specified, so let's bind to it. 352 */ 353 if (netif != NULL) { 354 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) <0) { 355 NET_ThrowNew(env, errno, "Can't bind socket"); 356 untagSocket(env, fd); 357 close(fd); 358 return JNI_FALSE; 359 } 360 } 361 SET_NONBLOCKING(fd); 362 363 /* no need to use NET_Connect as non-blocking */ 364 him6.sin6_port = htons((short) 7); /* Echo port */ 365 connect_rv = JVM_Connect(fd, (struct sockaddr *)&him6, len); 366 367 /** 368 * connection established or refused immediately, either way it means 369 * we were able to reach the host! 370 */ 371 if (connect_rv == 0 || errno == ECONNREFUSED) { 372 untagSocket(env, fd); 373 close(fd); 374 return JNI_TRUE; 375 } else { 376 int optlen; 377 378 switch (errno) { 379 case ENETUNREACH: /* Network Unreachable */ 380 case EAFNOSUPPORT: /* Address Family not supported */ 381 case EADDRNOTAVAIL: /* address is not available on the remote machine */ 382#ifdef __linux__ 383 case EINVAL: 384 case EHOSTUNREACH: 385 /* 386 * On some Linuxes, when bound to the loopback interface, connect 387 * will fail and errno will be set to EINVAL or EHOSTUNREACH. 388 * When that happens, don't throw an exception, just return false. 389 */ 390#endif /* __linux__ */ 391 untagSocket(env, fd); 392 close(fd); 393 return JNI_FALSE; 394 } 395 396 if (errno != EINPROGRESS) { 397 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException", 398 "connect failed"); 399 untagSocket(env, fd); 400 close(fd); 401 return JNI_FALSE; 402 } 403 404 timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout); 405 406 if (timeout >= 0) { 407 /* has connection been established */ 408 optlen = sizeof(connect_rv); 409 if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv, 410 &optlen) <0) { 411 connect_rv = errno; 412 } 413 if (connect_rv == 0 || ECONNREFUSED) { 414 untagSocket(env, fd); 415 close(fd); 416 return JNI_TRUE; 417 } 418 } 419 untagSocket(env, fd); 420 close(fd); 421 return JNI_FALSE; 422 } 423#else /* AF_INET6 */ 424 return JNI_FALSE; 425#endif /* AF_INET6 */ 426} 427 428static JNINativeMethod gMethods[] = { 429 NATIVE_METHOD(Inet6AddressImpl, isReachable0, "([BII[BII)Z"), 430 NATIVE_METHOD(Inet6AddressImpl, getHostByAddr0, "([B)Ljava/lang/String;"), 431}; 432 433void register_java_net_Inet6AddressImpl(JNIEnv* env) { 434 jniRegisterNativeMethods(env, "java/net/Inet6AddressImpl", gMethods, NELEM(gMethods)); 435} 436