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 }