1/* 2 * Copyright (c) 1998, 2017, 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 "net_util.h" 27 28#include "java_net_InetAddress.h" 29 30int IPv6_supported(); 31int reuseport_supported(); 32 33static int IPv6_available; 34static int REUSEPORT_available; 35 36JNIEXPORT jint JNICALL ipv6_available() 37{ 38 return IPv6_available; 39} 40 41JNIEXPORT jint JNICALL reuseport_available() 42{ 43 return REUSEPORT_available; 44} 45 46JNIEXPORT jint JNICALL 47DEF_JNI_OnLoad(JavaVM *vm, void *reserved) 48{ 49 JNIEnv *env; 50 jclass iCls; 51 jmethodID mid; 52 jstring s; 53 jint preferIPv4Stack; 54 if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_2) != JNI_OK) { 55 return JNI_EVERSION; /* JNI version not supported */ 56 } 57 58 iCls = (*env)->FindClass(env, "java/lang/Boolean"); 59 CHECK_NULL_RETURN(iCls, JNI_VERSION_1_2); 60 mid = (*env)->GetStaticMethodID(env, iCls, "getBoolean", "(Ljava/lang/String;)Z"); 61 CHECK_NULL_RETURN(mid, JNI_VERSION_1_2); 62 s = (*env)->NewStringUTF(env, "java.net.preferIPv4Stack"); 63 CHECK_NULL_RETURN(s, JNI_VERSION_1_2); 64 preferIPv4Stack = (*env)->CallStaticBooleanMethod(env, iCls, mid, s); 65 66 /* 67 * Since we have initialized and loaded the socket library we will 68 * check now whether we have IPv6 on this platform and if the 69 * supporting socket APIs are available 70 */ 71 IPv6_available = IPv6_supported() & (!preferIPv4Stack); 72 73 /* check if SO_REUSEPORT is supported on this platform */ 74 REUSEPORT_available = reuseport_supported(); 75 platformInit(); 76 parseExclusiveBindProperty(env); 77 78 return JNI_VERSION_1_2; 79} 80 81static int initialized = 0; 82 83JNIEXPORT void JNICALL initInetAddressIDs(JNIEnv *env) { 84 if (!initialized) { 85 Java_java_net_InetAddress_init(env, 0); 86 JNU_CHECK_EXCEPTION(env); 87 Java_java_net_Inet4Address_init(env, 0); 88 JNU_CHECK_EXCEPTION(env); 89 Java_java_net_Inet6Address_init(env, 0); 90 JNU_CHECK_EXCEPTION(env); 91 initialized = 1; 92 } 93} 94 95/* The address, and family fields used to be in InetAddress 96 * but are now in an implementation object. So, there is an extra 97 * level of indirection to access them now. 98 */ 99 100extern jclass iac_class; 101extern jfieldID ia_holderID; 102extern jfieldID iac_addressID; 103extern jfieldID iac_familyID; 104 105/** 106 * set_ methods return JNI_TRUE on success JNI_FALSE on error 107 * get_ methods that return +ve int return -1 on error 108 * get_ methods that return objects return NULL on error. 109 */ 110jobject getInet6Address_scopeifname(JNIEnv *env, jobject iaObj) { 111 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 112 CHECK_NULL_RETURN(holder, NULL); 113 return (*env)->GetObjectField(env, holder, ia6_scopeifnameID); 114} 115 116jboolean setInet6Address_scopeifname(JNIEnv *env, jobject iaObj, jobject scopeifname) { 117 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 118 CHECK_NULL_RETURN(holder, JNI_FALSE); 119 (*env)->SetObjectField(env, holder, ia6_scopeifnameID, scopeifname); 120 return JNI_TRUE; 121} 122 123jboolean getInet6Address_scopeid_set(JNIEnv *env, jobject iaObj) { 124 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 125 CHECK_NULL_RETURN(holder, JNI_FALSE); 126 return (*env)->GetBooleanField(env, holder, ia6_scopeidsetID); 127} 128 129unsigned int getInet6Address_scopeid(JNIEnv *env, jobject iaObj) { 130 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 131 CHECK_NULL_RETURN(holder, 0); 132 return (unsigned int)(*env)->GetIntField(env, holder, ia6_scopeidID); 133} 134 135jboolean setInet6Address_scopeid(JNIEnv *env, jobject iaObj, int scopeid) { 136 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 137 CHECK_NULL_RETURN(holder, JNI_FALSE); 138 (*env)->SetIntField(env, holder, ia6_scopeidID, scopeid); 139 if (scopeid > 0) { 140 (*env)->SetBooleanField(env, holder, ia6_scopeidsetID, JNI_TRUE); 141 } 142 return JNI_TRUE; 143} 144 145jboolean getInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *dest) { 146 jobject holder, addr; 147 148 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 149 CHECK_NULL_RETURN(holder, JNI_FALSE); 150 addr = (*env)->GetObjectField(env, holder, ia6_ipaddressID); 151 CHECK_NULL_RETURN(addr, JNI_FALSE); 152 (*env)->GetByteArrayRegion(env, addr, 0, 16, (jbyte *)dest); 153 return JNI_TRUE; 154} 155 156jboolean setInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *address) { 157 jobject holder; 158 jbyteArray addr; 159 160 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 161 CHECK_NULL_RETURN(holder, JNI_FALSE); 162 addr = (jbyteArray)(*env)->GetObjectField(env, holder, ia6_ipaddressID); 163 if (addr == NULL) { 164 addr = (*env)->NewByteArray(env, 16); 165 CHECK_NULL_RETURN(addr, JNI_FALSE); 166 (*env)->SetObjectField(env, holder, ia6_ipaddressID, addr); 167 } 168 (*env)->SetByteArrayRegion(env, addr, 0, 16, (jbyte *)address); 169 return JNI_TRUE; 170} 171 172void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) { 173 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 174 (*env)->SetIntField(env, holder, iac_addressID, address); 175} 176 177void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) { 178 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 179 (*env)->SetIntField(env, holder, iac_familyID, family); 180} 181 182void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) { 183 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 184 (*env)->SetObjectField(env, holder, iac_hostNameID, host); 185 (*env)->SetObjectField(env, holder, iac_origHostNameID, host); 186} 187 188int getInetAddress_addr(JNIEnv *env, jobject iaObj) { 189 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 190 return (*env)->GetIntField(env, holder, iac_addressID); 191} 192 193int getInetAddress_family(JNIEnv *env, jobject iaObj) { 194 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 195 return (*env)->GetIntField(env, holder, iac_familyID); 196} 197 198jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) { 199 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 200 return (*env)->GetObjectField(env, holder, iac_hostNameID); 201} 202 203JNIEXPORT jobject JNICALL 204NET_SockaddrToInetAddress(JNIEnv *env, SOCKETADDRESS *sa, int *port) { 205 jobject iaObj; 206 if (sa->sa.sa_family == AF_INET6) { 207 jbyte *caddr = (jbyte *)&sa->sa6.sin6_addr; 208 if (NET_IsIPv4Mapped(caddr)) { 209 int address; 210 iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); 211 CHECK_NULL_RETURN(iaObj, NULL); 212 address = NET_IPv4MappedToIPv4(caddr); 213 setInetAddress_addr(env, iaObj, address); 214 setInetAddress_family(env, iaObj, java_net_InetAddress_IPv4); 215 } else { 216 jboolean ret; 217 iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID); 218 CHECK_NULL_RETURN(iaObj, NULL); 219 ret = setInet6Address_ipaddress(env, iaObj, (char *)&sa->sa6.sin6_addr); 220 if (ret == JNI_FALSE) 221 return NULL; 222 setInetAddress_family(env, iaObj, java_net_InetAddress_IPv6); 223 setInet6Address_scopeid(env, iaObj, sa->sa6.sin6_scope_id); 224 } 225 *port = ntohs(sa->sa6.sin6_port); 226 } else { 227 iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); 228 CHECK_NULL_RETURN(iaObj, NULL); 229 setInetAddress_family(env, iaObj, java_net_InetAddress_IPv4); 230 setInetAddress_addr(env, iaObj, ntohl(sa->sa4.sin_addr.s_addr)); 231 *port = ntohs(sa->sa4.sin_port); 232 } 233 return iaObj; 234} 235 236JNIEXPORT jboolean JNICALL 237NET_SockaddrEqualsInetAddress(JNIEnv *env, SOCKETADDRESS *sa, jobject iaObj) 238{ 239 jint family = getInetAddress_family(env, iaObj) == 240 java_net_InetAddress_IPv4 ? AF_INET : AF_INET6; 241 if (sa->sa.sa_family == AF_INET6) { 242 jbyte *caddrNew = (jbyte *)&sa->sa6.sin6_addr; 243 if (NET_IsIPv4Mapped(caddrNew)) { 244 int addrNew, addrCur; 245 if (family == AF_INET6) { 246 return JNI_FALSE; 247 } 248 addrNew = NET_IPv4MappedToIPv4(caddrNew); 249 addrCur = getInetAddress_addr(env, iaObj); 250 if (addrNew == addrCur) { 251 return JNI_TRUE; 252 } else { 253 return JNI_FALSE; 254 } 255 } else { 256 jbyte caddrCur[16]; 257 if (family == AF_INET) { 258 return JNI_FALSE; 259 } 260 getInet6Address_ipaddress(env, iaObj, (char *)caddrCur); 261 if (NET_IsEqual(caddrNew, caddrCur) && 262 sa->sa6.sin6_scope_id == getInet6Address_scopeid(env, iaObj)) 263 { 264 return JNI_TRUE; 265 } else { 266 return JNI_FALSE; 267 } 268 } 269 } else { 270 int addrNew, addrCur; 271 if (family != AF_INET) { 272 return JNI_FALSE; 273 } 274 addrNew = ntohl(sa->sa4.sin_addr.s_addr); 275 addrCur = getInetAddress_addr(env, iaObj); 276 if (addrNew == addrCur) { 277 return JNI_TRUE; 278 } else { 279 return JNI_FALSE; 280 } 281 } 282} 283 284JNIEXPORT jint JNICALL 285NET_GetPortFromSockaddr(SOCKETADDRESS *sa) { 286 if (sa->sa.sa_family == AF_INET6) { 287 return ntohs(sa->sa6.sin6_port); 288 } else { 289 return ntohs(sa->sa4.sin_port); 290 } 291} 292 293unsigned short 294in_cksum(unsigned short *addr, int len) { 295 int nleft = len; 296 int sum = 0; 297 unsigned short *w = addr; 298 unsigned short answer = 0; 299 while(nleft > 1) { 300 sum += *w++; 301 nleft -= 2; 302 } 303 304 if (nleft == 1) { 305 *(unsigned char *) (&answer) = *(unsigned char *)w; 306 sum += answer; 307 } 308 309 sum = (sum >> 16) + (sum & 0xffff); 310 sum += (sum >> 16); 311 answer = ~sum; 312 return (answer); 313} 314