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 }