1 /* 2 * Copyright (c) 1998, 2020, 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 85 return JNI_VERSION_1_2; 86 } 87 88 static int initialized = 0; 89 90 JNIEXPORT void JNICALL initInetAddressIDs(JNIEnv *env) { 91 if (!initialized) { 92 Java_java_net_InetAddress_init(env, 0); 93 JNU_CHECK_EXCEPTION(env); 94 Java_java_net_Inet4Address_init(env, 0); 95 JNU_CHECK_EXCEPTION(env); 96 Java_java_net_Inet6Address_init(env, 0); 97 JNU_CHECK_EXCEPTION(env); 98 initialized = 1; 99 } 100 } 101 102 /* The address, and family fields used to be in InetAddress 103 * but are now in an implementation object. So, there is an extra 104 * level of indirection to access them now. 105 */ 106 107 extern jclass iac_class; 108 extern jfieldID ia_holderID; 109 extern jfieldID iac_addressID; 110 extern jfieldID iac_familyID; 111 112 /** 113 * set_ methods return JNI_TRUE on success JNI_FALSE on error 114 * get_ methods that return +ve int return -1 on error 115 * get_ methods that return objects return NULL on error. 116 */ 117 jboolean setInet6Address_scopeifname(JNIEnv *env, jobject iaObj, jobject scopeifname) { 118 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 119 CHECK_NULL_RETURN(holder, JNI_FALSE); 120 (*env)->SetObjectField(env, holder, ia6_scopeifnameID, scopeifname); 121 return JNI_TRUE; 122 } 123 124 unsigned int getInet6Address_scopeid(JNIEnv *env, jobject iaObj) { 125 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 126 CHECK_NULL_RETURN(holder, 0); 127 return (unsigned int)(*env)->GetIntField(env, holder, ia6_scopeidID); 128 } 129 130 jboolean setInet6Address_scopeid(JNIEnv *env, jobject iaObj, int scopeid) { 131 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 132 CHECK_NULL_RETURN(holder, JNI_FALSE); 133 (*env)->SetIntField(env, holder, ia6_scopeidID, scopeid); 134 if (scopeid > 0) { 135 (*env)->SetBooleanField(env, holder, ia6_scopeidsetID, JNI_TRUE); 136 } 137 return JNI_TRUE; 138 } 139 140 jboolean getInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *dest) { 141 jobject holder, addr; 142 143 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 144 CHECK_NULL_RETURN(holder, JNI_FALSE); 145 addr = (*env)->GetObjectField(env, holder, ia6_ipaddressID); 146 CHECK_NULL_RETURN(addr, JNI_FALSE); 147 (*env)->GetByteArrayRegion(env, addr, 0, 16, (jbyte *)dest); 148 return JNI_TRUE; 149 } 150 151 jboolean setInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *address) { 152 jobject holder; 153 jbyteArray addr; 154 155 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID); 156 CHECK_NULL_RETURN(holder, JNI_FALSE); 157 addr = (jbyteArray)(*env)->GetObjectField(env, holder, ia6_ipaddressID); 158 if (addr == NULL) { 159 addr = (*env)->NewByteArray(env, 16); 160 CHECK_NULL_RETURN(addr, JNI_FALSE); 161 (*env)->SetObjectField(env, holder, ia6_ipaddressID, addr); 162 } 163 (*env)->SetByteArrayRegion(env, addr, 0, 16, (jbyte *)address); 164 return JNI_TRUE; 165 } 166 167 void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) { 168 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 169 CHECK_NULL_THROW_NPE(env, holder, "InetAddress holder is null"); 170 (*env)->SetIntField(env, holder, iac_addressID, address); 171 } 172 173 void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) { 174 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 175 CHECK_NULL_THROW_NPE(env, holder, "InetAddress holder is null"); 176 (*env)->SetIntField(env, holder, iac_familyID, family); 177 } 178 179 void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) { 180 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 181 CHECK_NULL_THROW_NPE(env, holder, "InetAddress holder is null"); 182 (*env)->SetObjectField(env, holder, iac_hostNameID, host); 183 (*env)->SetObjectField(env, holder, iac_origHostNameID, host); 184 } 185 186 int getInetAddress_addr(JNIEnv *env, jobject iaObj) { 187 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 188 CHECK_NULL_THROW_NPE_RETURN(env, holder, "InetAddress holder is null", -1); 189 return (*env)->GetIntField(env, holder, iac_addressID); 190 } 191 192 int getInetAddress_family(JNIEnv *env, jobject iaObj) { 193 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID); 194 CHECK_NULL_THROW_NPE_RETURN(env, holder, "InetAddress holder is null", -1); 195 return (*env)->GetIntField(env, holder, iac_familyID); 196 } 197 198 JNIEXPORT jobject JNICALL 199 NET_SockaddrToInetAddress(JNIEnv *env, SOCKETADDRESS *sa, int *port) { 200 jobject iaObj; 201 if (sa->sa.sa_family == AF_INET6) { 202 jbyte *caddr = (jbyte *)&sa->sa6.sin6_addr; 203 if (NET_IsIPv4Mapped(caddr)) { 204 int address; 205 iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); 206 CHECK_NULL_RETURN(iaObj, NULL); 207 address = NET_IPv4MappedToIPv4(caddr); 208 setInetAddress_addr(env, iaObj, address); 209 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 210 setInetAddress_family(env, iaObj, java_net_InetAddress_IPv4); 211 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 212 } else { 213 jboolean ret; 214 iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID); 215 CHECK_NULL_RETURN(iaObj, NULL); 216 ret = setInet6Address_ipaddress(env, iaObj, (char *)&sa->sa6.sin6_addr); 217 if (ret == JNI_FALSE) 218 return NULL; 219 setInetAddress_family(env, iaObj, java_net_InetAddress_IPv6); 220 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 221 setInet6Address_scopeid(env, iaObj, sa->sa6.sin6_scope_id); 222 } 223 *port = ntohs(sa->sa6.sin6_port); 224 } else { 225 iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID); 226 CHECK_NULL_RETURN(iaObj, NULL); 227 setInetAddress_family(env, iaObj, java_net_InetAddress_IPv4); 228 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 229 setInetAddress_addr(env, iaObj, ntohl(sa->sa4.sin_addr.s_addr)); 230 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 231 *port = ntohs(sa->sa4.sin_port); 232 } 233 return iaObj; 234 } 235 236 JNIEXPORT jboolean JNICALL 237 NET_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 JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); 242 if (sa->sa.sa_family == AF_INET6) { 243 jbyte *caddrNew = (jbyte *)&sa->sa6.sin6_addr; 244 if (NET_IsIPv4Mapped(caddrNew)) { 245 int addrNew, addrCur; 246 if (family == AF_INET6) { 247 return JNI_FALSE; 248 } 249 addrNew = NET_IPv4MappedToIPv4(caddrNew); 250 addrCur = getInetAddress_addr(env, iaObj); 251 JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); 252 if (addrNew == addrCur) { 253 return JNI_TRUE; 254 } else { 255 return JNI_FALSE; 256 } 257 } else { 258 jbyte caddrCur[16]; 259 if (family == AF_INET) { 260 return JNI_FALSE; 261 } 262 getInet6Address_ipaddress(env, iaObj, (char *)caddrCur); 263 if (NET_IsEqual(caddrNew, caddrCur) && 264 sa->sa6.sin6_scope_id == getInet6Address_scopeid(env, iaObj)) 265 { 266 return JNI_TRUE; 267 } else { 268 return JNI_FALSE; 269 } 270 } 271 } else { 272 int addrNew, addrCur; 273 if (family != AF_INET) { 274 return JNI_FALSE; 275 } 276 addrNew = ntohl(sa->sa4.sin_addr.s_addr); 277 addrCur = getInetAddress_addr(env, iaObj); 278 JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); 279 if (addrNew == addrCur) { 280 return JNI_TRUE; 281 } else { 282 return JNI_FALSE; 283 } 284 } 285 } 286 287 JNIEXPORT jint JNICALL 288 NET_GetPortFromSockaddr(SOCKETADDRESS *sa) { 289 if (sa->sa.sa_family == AF_INET6) { 290 return ntohs(sa->sa6.sin6_port); 291 } else { 292 return ntohs(sa->sa4.sin_port); 293 } 294 } 295 296 unsigned short 297 in_cksum(unsigned short *addr, int len) { 298 int nleft = len; 299 int sum = 0; 300 unsigned short *w = addr; 301 unsigned short answer = 0; 302 while(nleft > 1) { 303 sum += *w++; 304 nleft -= 2; 305 } 306 307 if (nleft == 1) { 308 *(unsigned char *) (&answer) = *(unsigned char *)w; 309 sum += answer; 310 } 311 312 sum = (sum >> 16) + (sum & 0xffff); 313 sum += (sum >> 16); 314 answer = ~sum; 315 return (answer); 316 }