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