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