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