1 /*
2 * Copyright (c) 2000, 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
24 */
25 #include <ctype.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/time.h>
30 #include <sys/types.h>
31 #include <netinet/in.h>
32 #include <netinet/icmp6.h>
33
34 #if defined(_ALLBSD_SOURCE)
35 #include <ifaddrs.h>
36 #include <net/if.h>
37 #endif
38
39 #include "net_util.h"
40
41 #include "java_net_InetAddress.h"
42 #include "java_net_Inet4AddressImpl.h"
43 #include "java_net_Inet6AddressImpl.h"
44
45 #define SET_NONBLOCKING(fd) { \
46 int flags = fcntl(fd, F_GETFL); \
47 flags |= O_NONBLOCK; \
48 fcntl(fd, F_SETFL, flags); \
49 }
50
51 /*
52 * Inet6AddressImpl
53 */
54
55 /*
56 * Class: java_net_Inet6AddressImpl
57 * Method: getLocalHostName
58 * Signature: ()Ljava/lang/String;
59 */
60 JNIEXPORT jstring JNICALL
61 Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
62 char hostname[NI_MAXHOST + 1];
63
64 hostname[0] = '\0';
65 if (gethostname(hostname, sizeof(hostname)) != 0) {
66 strcpy(hostname, "localhost");
67 } else {
68 // make sure string is null-terminated
69 hostname[NI_MAXHOST] = '\0';
70 }
71 return (*env)->NewStringUTF(env, hostname);
72 }
73
74 #if defined(MACOSX)
75 /* also called from Inet4AddressImpl.c */
76 __private_extern__ jobjectArray
77 lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6)
78 {
79 jobjectArray result = NULL;
80 char myhostname[NI_MAXHOST + 1];
81 struct ifaddrs *ifa = NULL;
82 int familyOrder = 0;
83 int count = 0, i, j;
84 int addrs4 = 0, addrs6 = 0, numV4Loopbacks = 0, numV6Loopbacks = 0;
85 jboolean includeLoopback = JNI_FALSE;
86 jobject name;
87
88 initInetAddressIDs(env);
89 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
90
91 /* If the requested name matches this host's hostname, return IP addresses
92 * from all attached interfaces. (#2844683 et al) This prevents undesired
93 * PPP dialup, but may return addresses that don't actually correspond to
94 * the name (if the name actually matches something in DNS etc.
95 */
96 myhostname[0] = '\0';
97 if (gethostname(myhostname, sizeof(myhostname)) == -1) {
134 addrs6++;
135 if (isLoopback) numV6Loopbacks++;
136 } // else we don't care, e.g. AF_LINK
137 }
138 }
139 iter = iter->ifa_next;
140 }
141
142 if (addrs4 == numV4Loopbacks && addrs6 == numV6Loopbacks) {
143 // We don't have a real IP address, just loopback. We need to include
144 // loopback in our results.
145 includeLoopback = JNI_TRUE;
146 }
147
148 /* Create and fill the Java array. */
149 int arraySize = addrs4 + addrs6 -
150 (includeLoopback ? 0 : (numV4Loopbacks + numV6Loopbacks));
151 result = (*env)->NewObjectArray(env, arraySize, ia_class, NULL);
152 if (!result) goto done;
153
154 if ((*env)->GetStaticBooleanField(env, ia_class, ia_preferIPv6AddressID)) {
155 i = includeLoopback ? addrs6 : (addrs6 - numV6Loopbacks);
156 j = 0;
157 } else {
158 i = 0;
159 j = includeLoopback ? addrs4 : (addrs4 - numV4Loopbacks);
160 }
161
162 // Now loop around the ifaddrs
163 iter = ifa;
164 while (iter != NULL) {
165 if (iter->ifa_addr != NULL) {
166 jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
167 int family = iter->ifa_addr->sa_family;
168
169 if (iter->ifa_name[0] != '\0' &&
170 (family == AF_INET || (family == AF_INET6 && includeV6)) &&
171 (!isLoopback || includeLoopback))
172 {
173 int port;
174 int index = (family == AF_INET) ? i++ : j++;
187 (*env)->DeleteLocalRef(env, o);
188 }
189 }
190 iter = iter->ifa_next;
191 }
192
193 done:
194 freeifaddrs(ifa);
195
196 return result;
197 }
198 #endif
199
200 /*
201 * Class: java_net_Inet6AddressImpl
202 * Method: lookupAllHostAddr
203 * Signature: (Ljava/lang/String;)[[B
204 */
205 JNIEXPORT jobjectArray JNICALL
206 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
207 jstring host) {
208 jobjectArray ret = NULL;
209 const char *hostname;
210 int error = 0;
211 struct addrinfo hints, *res = NULL, *resNew = NULL, *last = NULL,
212 *iterator;
213
214 initInetAddressIDs(env);
215 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
216
217 if (IS_NULL(host)) {
218 JNU_ThrowNullPointerException(env, "host argument is null");
219 return NULL;
220 }
221 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
222 CHECK_NULL_RETURN(hostname, NULL);
223
224 // try once, with our static buffer
225 memset(&hints, 0, sizeof(hints));
226 hints.ai_flags = AI_CANONNAME;
227 hints.ai_family = AF_UNSPEC;
228
229 error = getaddrinfo(hostname, NULL, &hints, &res);
230
231 if (error) {
232 #if defined(MACOSX)
233 // if getaddrinfo fails try getifaddrs
234 ret = lookupIfLocalhost(env, hostname, JNI_TRUE);
235 if (ret != NULL || (*env)->ExceptionCheck(env)) {
236 goto cleanupAndReturn;
237 }
238 #endif
239 // report error
240 NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
241 goto cleanupAndReturn;
242 } else {
243 int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0,
244 inet6Index = 0, originalIndex = 0;
245 int addressPreference =
246 (*env)->GetStaticIntField(env, ia_class, ia_preferIPv6AddressID);;
247 iterator = res;
248 while (iterator != NULL) {
249 // skip duplicates
250 int skip = 0;
251 struct addrinfo *iteratorNew = resNew;
252 while (iteratorNew != NULL) {
253 if (iterator->ai_family == iteratorNew->ai_family &&
254 iterator->ai_addrlen == iteratorNew->ai_addrlen) {
255 if (iteratorNew->ai_family == AF_INET) { /* AF_INET */
256 struct sockaddr_in *addr1, *addr2;
257 addr1 = (struct sockaddr_in *)iterator->ai_addr;
258 addr2 = (struct sockaddr_in *)iteratorNew->ai_addr;
259 if (addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) {
260 skip = 1;
261 break;
262 }
263 } else {
264 int t;
265 struct sockaddr_in6 *addr1, *addr2;
266 addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
305 last->ai_next = next;
306 }
307 last = next;
308 i++;
309 if (iterator->ai_family == AF_INET) {
310 inetCount++;
311 } else if (iterator->ai_family == AF_INET6) {
312 inet6Count++;
313 }
314 }
315 iterator = iterator->ai_next;
316 }
317
318 // allocate array - at this point i contains the number of addresses
319 ret = (*env)->NewObjectArray(env, i, ia_class, NULL);
320 if (IS_NULL(ret)) {
321 /* we may have memory to free at the end of this */
322 goto cleanupAndReturn;
323 }
324
325 if (addressPreference == java_net_InetAddress_PREFER_IPV6_VALUE) {
326 inetIndex = inet6Count;
327 inet6Index = 0;
328 } else if (addressPreference == java_net_InetAddress_PREFER_IPV4_VALUE) {
329 inetIndex = 0;
330 inet6Index = inetCount;
331 } else if (addressPreference == java_net_InetAddress_PREFER_SYSTEM_VALUE) {
332 inetIndex = inet6Index = originalIndex = 0;
333 }
334
335 iterator = resNew;
336 while (iterator != NULL) {
337 if (iterator->ai_family == AF_INET) {
338 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
339 if (IS_NULL(iaObj)) {
340 ret = NULL;
341 goto cleanupAndReturn;
342 }
343 setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
344 if ((*env)->ExceptionCheck(env))
345 goto cleanupAndReturn;
346 setInetAddress_hostName(env, iaObj, host);
347 if ((*env)->ExceptionCheck(env))
348 goto cleanupAndReturn;
349 (*env)->SetObjectArrayElement(env, ret, (inetIndex | originalIndex), iaObj);
350 inetIndex++;
351 } else if (iterator->ai_family == AF_INET6) {
354 jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
355 if (IS_NULL(iaObj)) {
356 ret = NULL;
357 goto cleanupAndReturn;
358 }
359 ret1 = setInet6Address_ipaddress(env, iaObj, (char *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
360 if (ret1 == JNI_FALSE) {
361 ret = NULL;
362 goto cleanupAndReturn;
363 }
364 scope = ((struct sockaddr_in6 *)iterator->ai_addr)->sin6_scope_id;
365 if (scope != 0) { // zero is default value, no need to set
366 setInet6Address_scopeid(env, iaObj, scope);
367 }
368 setInetAddress_hostName(env, iaObj, host);
369 if ((*env)->ExceptionCheck(env))
370 goto cleanupAndReturn;
371 (*env)->SetObjectArrayElement(env, ret, (inet6Index | originalIndex), iaObj);
372 inet6Index++;
373 }
374 if (addressPreference == java_net_InetAddress_PREFER_SYSTEM_VALUE) {
375 originalIndex++;
376 inetIndex = inet6Index = 0;
377 }
378 iterator = iterator->ai_next;
379 }
380 }
381 cleanupAndReturn:
382 JNU_ReleaseStringPlatformChars(env, host, hostname);
383 while (resNew != NULL) {
384 last = resNew;
385 resNew = resNew->ai_next;
386 free(last);
387 }
388 if (res != NULL) {
389 freeaddrinfo(res);
390 }
391 return ret;
392 }
393
394 /*
|
1 /*
2 * Copyright (c) 2000, 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
24 */
25 #include <ctype.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/time.h>
30 #include <sys/types.h>
31 #include <netinet/in.h>
32 #include <netinet/icmp6.h>
33
34 #if defined(_ALLBSD_SOURCE)
35 #include <ifaddrs.h>
36 #include <net/if.h>
37 #endif
38
39 #include "net_util.h"
40
41 #include "java_net_InetAddress.h"
42 #include "java_net_Inet4AddressImpl.h"
43 #include "java_net_Inet6AddressImpl.h"
44 #include "java_net_spi_InetAddressResolver_LookupPolicy.h"
45
46
47 #define SET_NONBLOCKING(fd) { \
48 int flags = fcntl(fd, F_GETFL); \
49 flags |= O_NONBLOCK; \
50 fcntl(fd, F_SETFL, flags); \
51 }
52
53 /*
54 * Inet6AddressImpl
55 */
56
57 /*
58 * Class: java_net_Inet6AddressImpl
59 * Method: getLocalHostName
60 * Signature: ()Ljava/lang/String;
61 */
62 JNIEXPORT jstring JNICALL
63 Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
64 char hostname[NI_MAXHOST + 1];
65
66 hostname[0] = '\0';
67 if (gethostname(hostname, sizeof(hostname)) != 0) {
68 strcpy(hostname, "localhost");
69 } else {
70 // make sure string is null-terminated
71 hostname[NI_MAXHOST] = '\0';
72 }
73 return (*env)->NewStringUTF(env, hostname);
74 }
75
76 #if defined(MACOSX)
77 /* also called from Inet4AddressImpl.c */
78 __private_extern__ jobjectArray
79 lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6, int characteristics)
80 {
81 jobjectArray result = NULL;
82 char myhostname[NI_MAXHOST + 1];
83 struct ifaddrs *ifa = NULL;
84 int familyOrder = 0;
85 int count = 0, i, j;
86 int addrs4 = 0, addrs6 = 0, numV4Loopbacks = 0, numV6Loopbacks = 0;
87 jboolean includeLoopback = JNI_FALSE;
88 jobject name;
89
90 initInetAddressIDs(env);
91 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
92
93 /* If the requested name matches this host's hostname, return IP addresses
94 * from all attached interfaces. (#2844683 et al) This prevents undesired
95 * PPP dialup, but may return addresses that don't actually correspond to
96 * the name (if the name actually matches something in DNS etc.
97 */
98 myhostname[0] = '\0';
99 if (gethostname(myhostname, sizeof(myhostname)) == -1) {
136 addrs6++;
137 if (isLoopback) numV6Loopbacks++;
138 } // else we don't care, e.g. AF_LINK
139 }
140 }
141 iter = iter->ifa_next;
142 }
143
144 if (addrs4 == numV4Loopbacks && addrs6 == numV6Loopbacks) {
145 // We don't have a real IP address, just loopback. We need to include
146 // loopback in our results.
147 includeLoopback = JNI_TRUE;
148 }
149
150 /* Create and fill the Java array. */
151 int arraySize = addrs4 + addrs6 -
152 (includeLoopback ? 0 : (numV4Loopbacks + numV6Loopbacks));
153 result = (*env)->NewObjectArray(env, arraySize, ia_class, NULL);
154 if (!result) goto done;
155
156 if ((characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV6_FIRST) != 0) {
157 i = includeLoopback ? addrs6 : (addrs6 - numV6Loopbacks);
158 j = 0;
159 } else {
160 i = 0;
161 j = includeLoopback ? addrs4 : (addrs4 - numV4Loopbacks);
162 }
163
164 // Now loop around the ifaddrs
165 iter = ifa;
166 while (iter != NULL) {
167 if (iter->ifa_addr != NULL) {
168 jboolean isLoopback = iter->ifa_flags & IFF_LOOPBACK;
169 int family = iter->ifa_addr->sa_family;
170
171 if (iter->ifa_name[0] != '\0' &&
172 (family == AF_INET || (family == AF_INET6 && includeV6)) &&
173 (!isLoopback || includeLoopback))
174 {
175 int port;
176 int index = (family == AF_INET) ? i++ : j++;
189 (*env)->DeleteLocalRef(env, o);
190 }
191 }
192 iter = iter->ifa_next;
193 }
194
195 done:
196 freeifaddrs(ifa);
197
198 return result;
199 }
200 #endif
201
202 /*
203 * Class: java_net_Inet6AddressImpl
204 * Method: lookupAllHostAddr
205 * Signature: (Ljava/lang/String;)[[B
206 */
207 JNIEXPORT jobjectArray JNICALL
208 Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
209 jstring host, jint characteristics) {
210 jobjectArray ret = NULL;
211 const char *hostname;
212 int error = 0;
213 struct addrinfo hints, *res = NULL, *resNew = NULL, *last = NULL,
214 *iterator;
215
216 initInetAddressIDs(env);
217 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
218
219 if (IS_NULL(host)) {
220 JNU_ThrowNullPointerException(env, "host argument is null");
221 return NULL;
222 }
223 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
224 CHECK_NULL_RETURN(hostname, NULL);
225
226 // try once, with our static buffer
227 memset(&hints, 0, sizeof(hints));
228 hints.ai_flags = AI_CANONNAME;
229 hints.ai_family = lookupCharacteristicsToAddressFamily(characteristics);
230
231 error = getaddrinfo(hostname, NULL, &hints, &res);
232
233 if (error) {
234 #if defined(MACOSX)
235 // if getaddrinfo fails try getifaddrs
236 ret = lookupIfLocalhost(env, hostname, JNI_TRUE, characteristics);
237 if (ret != NULL || (*env)->ExceptionCheck(env)) {
238 goto cleanupAndReturn;
239 }
240 #endif
241 // report error
242 NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
243 goto cleanupAndReturn;
244 } else {
245 int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0,
246 inet6Index = 0, originalIndex = 0;
247 iterator = res;
248 while (iterator != NULL) {
249 // skip duplicates
250 int skip = 0;
251 struct addrinfo *iteratorNew = resNew;
252 while (iteratorNew != NULL) {
253 if (iterator->ai_family == iteratorNew->ai_family &&
254 iterator->ai_addrlen == iteratorNew->ai_addrlen) {
255 if (iteratorNew->ai_family == AF_INET) { /* AF_INET */
256 struct sockaddr_in *addr1, *addr2;
257 addr1 = (struct sockaddr_in *)iterator->ai_addr;
258 addr2 = (struct sockaddr_in *)iteratorNew->ai_addr;
259 if (addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) {
260 skip = 1;
261 break;
262 }
263 } else {
264 int t;
265 struct sockaddr_in6 *addr1, *addr2;
266 addr1 = (struct sockaddr_in6 *)iterator->ai_addr;
305 last->ai_next = next;
306 }
307 last = next;
308 i++;
309 if (iterator->ai_family == AF_INET) {
310 inetCount++;
311 } else if (iterator->ai_family == AF_INET6) {
312 inet6Count++;
313 }
314 }
315 iterator = iterator->ai_next;
316 }
317
318 // allocate array - at this point i contains the number of addresses
319 ret = (*env)->NewObjectArray(env, i, ia_class, NULL);
320 if (IS_NULL(ret)) {
321 /* we may have memory to free at the end of this */
322 goto cleanupAndReturn;
323 }
324
325 if ((characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV6_FIRST) != 0) {
326 inetIndex = inet6Count;
327 inet6Index = 0;
328 } else if ((characteristics & java_net_spi_InetAddressResolver_LookupPolicy_IPV4_FIRST) != 0) {
329 inetIndex = 0;
330 inet6Index = inetCount;
331 } else {
332 inetIndex = inet6Index = originalIndex = 0;
333 }
334
335 iterator = resNew;
336 while (iterator != NULL) {
337 if (iterator->ai_family == AF_INET) {
338 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
339 if (IS_NULL(iaObj)) {
340 ret = NULL;
341 goto cleanupAndReturn;
342 }
343 setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)iterator->ai_addr)->sin_addr.s_addr));
344 if ((*env)->ExceptionCheck(env))
345 goto cleanupAndReturn;
346 setInetAddress_hostName(env, iaObj, host);
347 if ((*env)->ExceptionCheck(env))
348 goto cleanupAndReturn;
349 (*env)->SetObjectArrayElement(env, ret, (inetIndex | originalIndex), iaObj);
350 inetIndex++;
351 } else if (iterator->ai_family == AF_INET6) {
354 jobject iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
355 if (IS_NULL(iaObj)) {
356 ret = NULL;
357 goto cleanupAndReturn;
358 }
359 ret1 = setInet6Address_ipaddress(env, iaObj, (char *)&(((struct sockaddr_in6*)iterator->ai_addr)->sin6_addr));
360 if (ret1 == JNI_FALSE) {
361 ret = NULL;
362 goto cleanupAndReturn;
363 }
364 scope = ((struct sockaddr_in6 *)iterator->ai_addr)->sin6_scope_id;
365 if (scope != 0) { // zero is default value, no need to set
366 setInet6Address_scopeid(env, iaObj, scope);
367 }
368 setInetAddress_hostName(env, iaObj, host);
369 if ((*env)->ExceptionCheck(env))
370 goto cleanupAndReturn;
371 (*env)->SetObjectArrayElement(env, ret, (inet6Index | originalIndex), iaObj);
372 inet6Index++;
373 }
374 // Check if addresses are requested to be returned in SYSTEM order
375 if (addressesInSystemOrder(characteristics)) {
376 originalIndex++;
377 inetIndex = inet6Index = 0;
378 }
379 iterator = iterator->ai_next;
380 }
381 }
382 cleanupAndReturn:
383 JNU_ReleaseStringPlatformChars(env, host, hostname);
384 while (resNew != NULL) {
385 last = resNew;
386 resNew = resNew->ai_next;
387 free(last);
388 }
389 if (res != NULL) {
390 freeaddrinfo(res);
391 }
392 return ret;
393 }
394
395 /*
|