1 /*
2 * Copyright (c) 1998, 2021, 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
ipv4_available()38 JNIEXPORT jint JNICALL ipv4_available()
39 {
40 return IPv4_available;
41 }
42
ipv6_available()43 JNIEXPORT jint JNICALL ipv6_available()
44 {
45 return IPv6_available;
46 }
47
reuseport_available()48 JNIEXPORT jint JNICALL reuseport_available()
49 {
50 return REUSEPORT_available;
51 }
52
53 JNIEXPORT jint JNICALL
DEF_JNI_OnLoad(JavaVM * vm,void * reserved)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
initInetAddressIDs(JNIEnv * env)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 */
setInet6Address_scopeifname(JNIEnv * env,jobject iaObj,jobject scopeifname)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 (*env)->DeleteLocalRef(env, holder);
122 return JNI_TRUE;
123 }
124
getInet6Address_scopeid(JNIEnv * env,jobject iaObj)125 unsigned int getInet6Address_scopeid(JNIEnv *env, jobject iaObj) {
126 unsigned int id;
127 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
128 CHECK_NULL_RETURN(holder, 0);
129 id = (unsigned int)(*env)->GetIntField(env, holder, ia6_scopeidID);
130 (*env)->DeleteLocalRef(env, holder);
131 return id;
132 }
133
setInet6Address_scopeid(JNIEnv * env,jobject iaObj,int scopeid)134 jboolean setInet6Address_scopeid(JNIEnv *env, jobject iaObj, int scopeid) {
135 jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
136 CHECK_NULL_RETURN(holder, JNI_FALSE);
137 (*env)->SetIntField(env, holder, ia6_scopeidID, scopeid);
138 if (scopeid > 0) {
139 (*env)->SetBooleanField(env, holder, ia6_scopeidsetID, JNI_TRUE);
140 }
141 (*env)->DeleteLocalRef(env, holder);
142 return JNI_TRUE;
143 }
144
getInet6Address_ipaddress(JNIEnv * env,jobject iaObj,char * dest)145 jboolean getInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *dest) {
146 jobject holder, addr;
147
148 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
149 CHECK_NULL_RETURN(holder, JNI_FALSE);
150 addr = (*env)->GetObjectField(env, holder, ia6_ipaddressID);
151 CHECK_NULL_RETURN(addr, JNI_FALSE);
152 (*env)->GetByteArrayRegion(env, addr, 0, 16, (jbyte *)dest);
153 (*env)->DeleteLocalRef(env, addr);
154 (*env)->DeleteLocalRef(env, holder);
155 return JNI_TRUE;
156 }
157
setInet6Address_ipaddress(JNIEnv * env,jobject iaObj,char * address)158 jboolean setInet6Address_ipaddress(JNIEnv *env, jobject iaObj, char *address) {
159 jobject holder;
160 jbyteArray addr;
161
162 holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
163 CHECK_NULL_RETURN(holder, JNI_FALSE);
164 addr = (jbyteArray)(*env)->GetObjectField(env, holder, ia6_ipaddressID);
165 if (addr == NULL) {
166 addr = (*env)->NewByteArray(env, 16);
167 CHECK_NULL_RETURN(addr, JNI_FALSE);
168 (*env)->SetObjectField(env, holder, ia6_ipaddressID, addr);
169 }
170 (*env)->SetByteArrayRegion(env, addr, 0, 16, (jbyte *)address);
171 (*env)->DeleteLocalRef(env, addr);
172 (*env)->DeleteLocalRef(env, holder);
173 return JNI_TRUE;
174 }
175
setInetAddress_addr(JNIEnv * env,jobject iaObj,int address)176 void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) {
177 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
178 CHECK_NULL_THROW_NPE(env, holder, "InetAddress holder is null");
179 (*env)->SetIntField(env, holder, iac_addressID, address);
180 (*env)->DeleteLocalRef(env, holder);
181 }
182
setInetAddress_family(JNIEnv * env,jobject iaObj,int family)183 void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) {
184 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
185 CHECK_NULL_THROW_NPE(env, holder, "InetAddress holder is null");
186 (*env)->SetIntField(env, holder, iac_familyID, family);
187 (*env)->DeleteLocalRef(env, holder);
188 }
189
setInetAddress_hostName(JNIEnv * env,jobject iaObj,jobject host)190 void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) {
191 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
192 CHECK_NULL_THROW_NPE(env, holder, "InetAddress holder is null");
193 (*env)->SetObjectField(env, holder, iac_hostNameID, host);
194 (*env)->SetObjectField(env, holder, iac_origHostNameID, host);
195 (*env)->DeleteLocalRef(env, holder);
196 }
197
getInetAddress_addr(JNIEnv * env,jobject iaObj)198 int getInetAddress_addr(JNIEnv *env, jobject iaObj) {
199 int addr;
200 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
201 CHECK_NULL_THROW_NPE_RETURN(env, holder, "InetAddress holder is null", -1);
202 addr = (*env)->GetIntField(env, holder, iac_addressID);
203 (*env)->DeleteLocalRef(env, holder);
204 return addr;
205 }
206
getInetAddress_family(JNIEnv * env,jobject iaObj)207 int getInetAddress_family(JNIEnv *env, jobject iaObj) {
208 int family;
209 jobject holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
210 CHECK_NULL_THROW_NPE_RETURN(env, holder, "InetAddress holder is null", -1);
211 family = (*env)->GetIntField(env, holder, iac_familyID);
212 (*env)->DeleteLocalRef(env, holder);
213 return family;
214 }
215
216 JNIEXPORT jobject JNICALL
NET_SockaddrToInetAddress(JNIEnv * env,SOCKETADDRESS * sa,int * port)217 NET_SockaddrToInetAddress(JNIEnv *env, SOCKETADDRESS *sa, int *port) {
218 jobject iaObj;
219 if (sa->sa.sa_family == AF_INET6) {
220 jbyte *caddr = (jbyte *)&sa->sa6.sin6_addr;
221 if (NET_IsIPv4Mapped(caddr)) {
222 int address;
223 iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
224 CHECK_NULL_RETURN(iaObj, NULL);
225 address = NET_IPv4MappedToIPv4(caddr);
226 setInetAddress_addr(env, iaObj, address);
227 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
228 setInetAddress_family(env, iaObj, java_net_InetAddress_IPv4);
229 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
230 } else {
231 jboolean ret;
232 iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
233 CHECK_NULL_RETURN(iaObj, NULL);
234 ret = setInet6Address_ipaddress(env, iaObj, (char *)&sa->sa6.sin6_addr);
235 if (ret == JNI_FALSE)
236 return NULL;
237 setInetAddress_family(env, iaObj, java_net_InetAddress_IPv6);
238 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
239 setInet6Address_scopeid(env, iaObj, sa->sa6.sin6_scope_id);
240 }
241 *port = ntohs(sa->sa6.sin6_port);
242 } else {
243 iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
244 CHECK_NULL_RETURN(iaObj, NULL);
245 setInetAddress_family(env, iaObj, java_net_InetAddress_IPv4);
246 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
247 setInetAddress_addr(env, iaObj, ntohl(sa->sa4.sin_addr.s_addr));
248 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
249 *port = ntohs(sa->sa4.sin_port);
250 }
251 return iaObj;
252 }
253
254 JNIEXPORT jboolean JNICALL
NET_SockaddrEqualsInetAddress(JNIEnv * env,SOCKETADDRESS * sa,jobject iaObj)255 NET_SockaddrEqualsInetAddress(JNIEnv *env, SOCKETADDRESS *sa, jobject iaObj)
256 {
257 jint family = getInetAddress_family(env, iaObj) ==
258 java_net_InetAddress_IPv4 ? AF_INET : AF_INET6;
259 JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
260 if (sa->sa.sa_family == AF_INET6) {
261 jbyte *caddrNew = (jbyte *)&sa->sa6.sin6_addr;
262 if (NET_IsIPv4Mapped(caddrNew)) {
263 int addrNew, addrCur;
264 if (family == AF_INET6) {
265 return JNI_FALSE;
266 }
267 addrNew = NET_IPv4MappedToIPv4(caddrNew);
268 addrCur = getInetAddress_addr(env, iaObj);
269 JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
270 if (addrNew == addrCur) {
271 return JNI_TRUE;
272 } else {
273 return JNI_FALSE;
274 }
275 } else {
276 jbyte caddrCur[16];
277 if (family == AF_INET) {
278 return JNI_FALSE;
279 }
280 getInet6Address_ipaddress(env, iaObj, (char *)caddrCur);
281 if (NET_IsEqual(caddrNew, caddrCur) &&
282 sa->sa6.sin6_scope_id == getInet6Address_scopeid(env, iaObj))
283 {
284 return JNI_TRUE;
285 } else {
286 return JNI_FALSE;
287 }
288 }
289 } else {
290 int addrNew, addrCur;
291 if (family != AF_INET) {
292 return JNI_FALSE;
293 }
294 addrNew = ntohl(sa->sa4.sin_addr.s_addr);
295 addrCur = getInetAddress_addr(env, iaObj);
296 JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);
297 if (addrNew == addrCur) {
298 return JNI_TRUE;
299 } else {
300 return JNI_FALSE;
301 }
302 }
303 }
304
305 JNIEXPORT jint JNICALL
NET_GetPortFromSockaddr(SOCKETADDRESS * sa)306 NET_GetPortFromSockaddr(SOCKETADDRESS *sa) {
307 if (sa->sa.sa_family == AF_INET6) {
308 return ntohs(sa->sa6.sin6_port);
309 } else {
310 return ntohs(sa->sa4.sin_port);
311 }
312 }
313
314 unsigned short
in_cksum(unsigned short * addr,int len)315 in_cksum(unsigned short *addr, int len) {
316 int nleft = len;
317 int sum = 0;
318 unsigned short *w = addr;
319 unsigned short answer = 0;
320 while(nleft > 1) {
321 sum += *w++;
322 nleft -= 2;
323 }
324
325 if (nleft == 1) {
326 *(unsigned char *) (&answer) = *(unsigned char *)w;
327 sum += answer;
328 }
329
330 sum = (sum >> 16) + (sum & 0xffff);
331 sum += (sum >> 16);
332 answer = ~sum;
333 return (answer);
334 }
335