1 /*
2 * Copyright (c) 2004, 2019, 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 <dlfcn.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "jni.h"
32 #include "jni_util.h"
33 #include "jvm.h"
34 #include "jvm_md.h"
35
36 #include "proxy_util.h"
37
38 #include "sun_net_spi_DefaultProxySelector.h"
39
40
41 /**
42 * These functions are used by the sun.net.spi.DefaultProxySelector class
43 * to access some platform specific settings.
44 * This is the Solaris/Linux Gnome 2.x code using the GConf-2 library.
45 * Everything is loaded dynamically so no hard link with any library exists.
46 * The GConf-2 settings used are:
47 * - /system/http_proxy/use_http_proxy boolean
48 * - /system/http_proxy/use_authentcation boolean
49 * - /system/http_proxy/use_same_proxy boolean
50 * - /system/http_proxy/host string
51 * - /system/http_proxy/authentication_user string
52 * - /system/http_proxy/authentication_password string
53 * - /system/http_proxy/port int
54 * - /system/proxy/socks_host string
55 * - /system/proxy/mode string
56 * - /system/proxy/ftp_host string
57 * - /system/proxy/secure_host string
58 * - /system/proxy/socks_port int
59 * - /system/proxy/ftp_port int
60 * - /system/proxy/secure_port int
61 * - /system/proxy/no_proxy_for list
62 *
63 * The following keys are not used in the new gnome 3
64 * - /system/http_proxy/use_http_proxy
65 * - /system/http_proxy/use_same_proxy
66 */
67 typedef void* gconf_client_get_default_func();
68 typedef char* gconf_client_get_string_func(void *, char *, void**);
69 typedef int gconf_client_get_int_func(void*, char *, void**);
70 typedef int gconf_client_get_bool_func(void*, char *, void**);
71 typedef int gconf_init_func(int, char**, void**);
72 typedef void g_type_init_func ();
73 gconf_client_get_default_func* my_get_default_func = NULL;
74 gconf_client_get_string_func* my_get_string_func = NULL;
75 gconf_client_get_int_func* my_get_int_func = NULL;
76 gconf_client_get_bool_func* my_get_bool_func = NULL;
77 g_type_init_func* my_g_type_init_func = NULL;
78
79
80 /*
81 * GProxyResolver provides synchronous and asynchronous network
82 * proxy resolution. It is based on GSettings, which is the standard
83 * of Gnome 3, to get system settings.
84 *
85 * In the current implementation, GProxyResolver has a higher priority
86 * than the old GConf. And we only resolve the proxy synchronously. In
87 * the future, we can also do the asynchronous network proxy resolution
88 * if necessary.
89 *
90 */
91 typedef struct _GProxyResolver GProxyResolver;
92 typedef struct _GSocketConnectable GSocketConnectable;
93 typedef struct GError GError;
94 typedef GProxyResolver* g_proxy_resolver_get_default_func();
95 typedef char** g_proxy_resolver_lookup_func();
96 typedef GSocketConnectable* g_network_address_parse_uri_func();
97 typedef const char* g_network_address_get_hostname_func();
98 typedef unsigned short g_network_address_get_port_func();
99 typedef void g_strfreev_func();
100
101 static g_proxy_resolver_get_default_func* g_proxy_resolver_get_default = NULL;
102 static g_proxy_resolver_lookup_func* g_proxy_resolver_lookup = NULL;
103 static g_network_address_parse_uri_func* g_network_address_parse_uri = NULL;
104 static g_network_address_get_hostname_func* g_network_address_get_hostname = NULL;
105 static g_network_address_get_port_func* g_network_address_get_port = NULL;
106 static g_strfreev_func* g_strfreev = NULL;
107
108 static void* gconf_client = NULL;
109 static int use_gproxyResolver = 0;
110 static int use_gconf = 0;
111
112
initGConf()113 static int initGConf() {
114 /**
115 * Let's try to load GConf-2 library
116 */
117 if (dlopen(JNI_LIB_NAME("gconf-2"), RTLD_GLOBAL | RTLD_LAZY) != NULL ||
118 dlopen(VERSIONED_JNI_LIB_NAME("gconf-2", "4"),
119 RTLD_GLOBAL | RTLD_LAZY) != NULL)
120 {
121 /*
122 * Now let's get pointer to the functions we need.
123 */
124 my_g_type_init_func =
125 (g_type_init_func*)dlsym(RTLD_DEFAULT, "g_type_init");
126 my_get_default_func =
127 (gconf_client_get_default_func*)dlsym(RTLD_DEFAULT,
128 "gconf_client_get_default");
129
130 if (my_g_type_init_func != NULL && my_get_default_func != NULL) {
131 /**
132 * Try to connect to GConf.
133 */
134 (*my_g_type_init_func)();
135 gconf_client = (*my_get_default_func)();
136 if (gconf_client != NULL) {
137 my_get_string_func =
138 (gconf_client_get_string_func*)dlsym(RTLD_DEFAULT,
139 "gconf_client_get_string");
140 my_get_int_func =
141 (gconf_client_get_int_func*)dlsym(RTLD_DEFAULT,
142 "gconf_client_get_int");
143 my_get_bool_func =
144 (gconf_client_get_bool_func*)dlsym(RTLD_DEFAULT,
145 "gconf_client_get_bool");
146 if (my_get_int_func != NULL && my_get_string_func != NULL &&
147 my_get_bool_func != NULL)
148 {
149 /**
150 * We did get all we need. Let's enable the System Proxy Settings.
151 */
152 return 1;
153 }
154 }
155 }
156 }
157 return 0;
158 }
159
getProxyByGConf(JNIEnv * env,const char * cproto,const char * chost)160 static jobjectArray getProxyByGConf(JNIEnv *env, const char* cproto,
161 const char* chost)
162 {
163 char *phost = NULL;
164 char *mode = NULL;
165 int pport = 0;
166 int use_proxy = 0;
167 int use_same_proxy = 0;
168 jobjectArray proxy_array = NULL;
169 jfieldID ptype_ID = ptype_httpID;
170
171 /* We only check manual proxy configurations */
172 mode = (*my_get_string_func)(gconf_client, "/system/proxy/mode", NULL);
173 if (mode && !strcasecmp(mode, "manual")) {
174 /*
175 * Even though /system/http_proxy/use_same_proxy is no longer used,
176 * its value is set to false in gnome 3. So it is not harmful to check
177 * it first in case jdk is used with an old gnome.
178 */
179 use_same_proxy = (*my_get_bool_func)(gconf_client, "/system/http_proxy/use_same_proxy", NULL);
180 if (use_same_proxy) {
181 phost = (*my_get_string_func)(gconf_client, "/system/http_proxy/host", NULL);
182 pport = (*my_get_int_func)(gconf_client, "/system/http_proxy/port", NULL);
183 use_proxy = (phost != NULL && pport != 0);
184 }
185
186 if (!use_proxy) {
187 /**
188 * HTTP:
189 * /system/http_proxy/use_http_proxy (boolean) - it's no longer used
190 * /system/http_proxy/host (string)
191 * /system/http_proxy/port (integer)
192 */
193 if (strcasecmp(cproto, "http") == 0) {
194 phost = (*my_get_string_func)(gconf_client, "/system/http_proxy/host", NULL);
195 pport = (*my_get_int_func)(gconf_client, "/system/http_proxy/port", NULL);
196 use_proxy = (phost != NULL && pport != 0);
197 }
198
199 /**
200 * HTTPS:
201 * /system/proxy/mode (string) [ "manual" means use proxy settings ]
202 * /system/proxy/secure_host (string)
203 * /system/proxy/secure_port (integer)
204 */
205 if (strcasecmp(cproto, "https") == 0) {
206 phost = (*my_get_string_func)(gconf_client, "/system/proxy/secure_host", NULL);
207 pport = (*my_get_int_func)(gconf_client, "/system/proxy/secure_port", NULL);
208 use_proxy = (phost != NULL && pport != 0);
209 }
210
211 /**
212 * FTP:
213 * /system/proxy/mode (string) [ "manual" means use proxy settings ]
214 * /system/proxy/ftp_host (string)
215 * /system/proxy/ftp_port (integer)
216 */
217 if (strcasecmp(cproto, "ftp") == 0) {
218 phost = (*my_get_string_func)(gconf_client, "/system/proxy/ftp_host", NULL);
219 pport = (*my_get_int_func)(gconf_client, "/system/proxy/ftp_port", NULL);
220 use_proxy = (phost != NULL && pport != 0);
221 }
222
223 /**
224 * SOCKS:
225 * /system/proxy/mode (string) [ "manual" means use proxy settings ]
226 * /system/proxy/socks_host (string)
227 * /system/proxy/socks_port (integer)
228 */
229 if (strcasecmp(cproto, "socks") == 0) {
230 phost = (*my_get_string_func)(gconf_client, "/system/proxy/socks_host", NULL);
231 pport = (*my_get_int_func)(gconf_client, "/system/proxy/socks_port", NULL);
232 use_proxy = (phost != NULL && pport != 0);
233 if (use_proxy)
234 ptype_ID = ptype_socksID;
235 }
236 }
237 }
238
239 if (use_proxy) {
240 jstring jhost;
241 char *noproxyfor;
242 char *s;
243
244 /**
245 * Check for the exclude list (aka "No Proxy For" list).
246 * It's a list of comma separated suffixes (e.g. domain name).
247 */
248 noproxyfor = (*my_get_string_func)(gconf_client, "/system/proxy/no_proxy_for", NULL);
249 if (noproxyfor != NULL) {
250 char *tmpbuf[512];
251 s = strtok_r(noproxyfor, ", ", tmpbuf);
252
253 while (s != NULL && strlen(s) <= strlen(chost)) {
254 if (strcasecmp(chost+(strlen(chost) - strlen(s)), s) == 0) {
255 /**
256 * the URL host name matches with one of the sufixes,
257 * therefore we have to use a direct connection.
258 */
259 use_proxy = 0;
260 break;
261 }
262 s = strtok_r(NULL, ", ", tmpbuf);
263 }
264 }
265 if (use_proxy) {
266 jobject proxy = NULL;
267 /* create a proxy array with one element. */
268 proxy_array = (*env)->NewObjectArray(env, 1, proxy_class, NULL);
269 if (proxy_array == NULL || (*env)->ExceptionCheck(env)) {
270 return NULL;
271 }
272 proxy = createProxy(env, ptype_ID, phost, pport);
273 if (proxy == NULL || (*env)->ExceptionCheck(env)) {
274 return NULL;
275 }
276 (*env)->SetObjectArrayElement(env, proxy_array, 0, proxy);
277 if ((*env)->ExceptionCheck(env)) {
278 return NULL;
279 }
280 }
281 }
282
283 return proxy_array;
284 }
285
initGProxyResolver()286 static int initGProxyResolver() {
287 void *gio_handle;
288
289 gio_handle = dlopen("libgio-2.0.so", RTLD_LAZY);
290 if (!gio_handle) {
291 gio_handle = dlopen("libgio-2.0.so.0", RTLD_LAZY);
292 if (!gio_handle) {
293 return 0;
294 }
295 }
296
297 my_g_type_init_func = (g_type_init_func*)dlsym(gio_handle, "g_type_init");
298
299 g_proxy_resolver_get_default =
300 (g_proxy_resolver_get_default_func*)dlsym(gio_handle,
301 "g_proxy_resolver_get_default");
302
303 g_proxy_resolver_lookup =
304 (g_proxy_resolver_lookup_func*)dlsym(gio_handle,
305 "g_proxy_resolver_lookup");
306
307 g_network_address_parse_uri =
308 (g_network_address_parse_uri_func*)dlsym(gio_handle,
309 "g_network_address_parse_uri");
310
311 g_network_address_get_hostname =
312 (g_network_address_get_hostname_func*)dlsym(gio_handle,
313 "g_network_address_get_hostname");
314
315 g_network_address_get_port =
316 (g_network_address_get_port_func*)dlsym(gio_handle,
317 "g_network_address_get_port");
318
319 g_strfreev = (g_strfreev_func*)dlsym(gio_handle, "g_strfreev");
320
321 if (!my_g_type_init_func ||
322 !g_proxy_resolver_get_default ||
323 !g_proxy_resolver_lookup ||
324 !g_network_address_parse_uri ||
325 !g_network_address_get_hostname ||
326 !g_network_address_get_port ||
327 !g_strfreev)
328 {
329 dlclose(gio_handle);
330 return 0;
331 }
332
333 (*my_g_type_init_func)();
334 return 1;
335 }
336
getProxyByGProxyResolver(JNIEnv * env,const char * cproto,const char * chost)337 static jobjectArray getProxyByGProxyResolver(JNIEnv *env, const char *cproto,
338 const char *chost)
339 {
340 GProxyResolver* resolver = NULL;
341 char** proxies = NULL;
342 GError *error = NULL;
343
344 size_t protoLen = 0;
345 size_t hostLen = 0;
346 char* uri = NULL;
347
348 jobjectArray proxy_array = NULL;
349
350 resolver = (*g_proxy_resolver_get_default)();
351 if (resolver == NULL) {
352 return NULL;
353 }
354
355 /* Construct the uri, cproto + "://" + chost */
356 protoLen = strlen(cproto);
357 hostLen = strlen(chost);
358 uri = malloc(protoLen + hostLen + 4);
359 if (!uri) {
360 /* Out of memory */
361 return NULL;
362 }
363 memcpy(uri, cproto, protoLen);
364 memcpy(uri + protoLen, "://", 3);
365 memcpy(uri + protoLen + 3, chost, hostLen + 1);
366
367 /*
368 * Looks into the system proxy configuration to determine what proxy,
369 * if any, to use to connect to uri. The returned proxy URIs are of
370 * the form <protocol>://[user[:password]@]host:port or direct://,
371 * where <protocol> could be http, rtsp, socks or other proxying protocol.
372 * direct:// is used when no proxy is needed.
373 */
374 proxies = (*g_proxy_resolver_lookup)(resolver, uri, NULL, &error);
375 free(uri);
376
377 if (proxies) {
378 if (!error) {
379 int i;
380 int nr_proxies = 0;
381 char** p = proxies;
382 /* count the elements in the null terminated string vector. */
383 while (*p) {
384 nr_proxies++;
385 p++;
386 }
387 /* create a proxy array that has to be filled. */
388 proxy_array = (*env)->NewObjectArray(env, nr_proxies, proxy_class, NULL);
389 if (proxy_array != NULL && !(*env)->ExceptionCheck(env)) {
390 for (i = 0; proxies[i]; i++) {
391 if (strncmp(proxies[i], "direct://", 9)) {
392 GSocketConnectable* conn =
393 (*g_network_address_parse_uri)(proxies[i], 0,
394 &error);
395 if (conn && !error) {
396 const char *phost = NULL;
397 unsigned short pport = 0;
398 phost = (*g_network_address_get_hostname)(conn);
399 pport = (*g_network_address_get_port)(conn);
400 if (phost && pport > 0) {
401 jobject proxy = NULL;
402 jfieldID ptype_ID = ptype_httpID;
403 if (!strncmp(proxies[i], "socks", 5))
404 ptype_ID = ptype_socksID;
405
406 proxy = createProxy(env, ptype_ID, phost, pport);
407 if (proxy == NULL || (*env)->ExceptionCheck(env)) {
408 proxy_array = NULL;
409 break;
410 }
411 (*env)->SetObjectArrayElement(env, proxy_array, i, proxy);
412 if ((*env)->ExceptionCheck(env)) {
413 proxy_array = NULL;
414 break;
415 }
416 }
417 }
418 } else {
419 /* direct connection - no proxy */
420 jobject proxy = (*env)->GetStaticObjectField(env, proxy_class,
421 pr_no_proxyID);
422 if (proxy == NULL || (*env)->ExceptionCheck(env)) {
423 proxy_array = NULL;
424 break;
425 }
426 (*env)->SetObjectArrayElement(env, proxy_array, i, proxy);
427 if ((*env)->ExceptionCheck(env)) {
428 proxy_array = NULL;
429 break;
430 }
431 }
432 }
433 }
434 }
435 (*g_strfreev)(proxies);
436 }
437
438 return proxy_array;
439 }
440
441 /*
442 * Class: sun_net_spi_DefaultProxySelector
443 * Method: init
444 * Signature: ()Z
445 */
446 JNIEXPORT jboolean JNICALL
Java_sun_net_spi_DefaultProxySelector_init(JNIEnv * env,jclass clazz)447 Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {
448 use_gproxyResolver = initGProxyResolver();
449 if (!use_gproxyResolver)
450 use_gconf = initGConf();
451
452 if (use_gproxyResolver || use_gconf) {
453 if (initJavaClass(env))
454 return JNI_TRUE;
455 }
456 return JNI_FALSE;
457 }
458
459 /*
460 * Class: sun_net_spi_DefaultProxySelector
461 * Method: getSystemProxies
462 * Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;
463 */
464 JNIEXPORT jobjectArray JNICALL
Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv * env,jobject this,jstring proto,jstring host)465 Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,
466 jobject this,
467 jstring proto,
468 jstring host)
469 {
470 const char* cproto;
471 const char* chost;
472
473 jboolean isProtoCopy;
474 jboolean isHostCopy;
475
476 jobjectArray proxyArray = NULL;
477
478 cproto = (*env)->GetStringUTFChars(env, proto, &isProtoCopy);
479
480 if (cproto != NULL && (use_gproxyResolver || use_gconf)) {
481 chost = (*env)->GetStringUTFChars(env, host, &isHostCopy);
482 if (chost != NULL) {
483 if (use_gproxyResolver)
484 proxyArray = getProxyByGProxyResolver(env, cproto, chost);
485 else if (use_gconf)
486 proxyArray = getProxyByGConf(env, cproto, chost);
487 if (isHostCopy == JNI_TRUE)
488 (*env)->ReleaseStringUTFChars(env, host, chost);
489 }
490 if (isProtoCopy == JNI_TRUE)
491 (*env)->ReleaseStringUTFChars(env, proto, cproto);
492 }
493 return proxyArray;
494 }
495
496