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