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