1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright 2010, 2013 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see
17 * <http://www.gnu.org/licenses/>.
25 #include "gsimpleproxyresolver.h"
26 #include "ginetaddress.h"
27 #include "ginetaddressmask.h"
28 #include "gnetworkingprivate.h"
34 * SECTION:gsimpleproxyresolver
35 * @short_description: Simple proxy resolver implementation
37 * @see_also: g_socket_client_set_proxy_resolver()
39 * #GSimpleProxyResolver is a simple #GProxyResolver implementation
40 * that handles a single default proxy, multiple URI-scheme-specific
41 * proxies, and a list of hosts that proxies should not be used for.
43 * #GSimpleProxyResolver is never the default proxy resolver, but it
44 * can be used as the base class for another proxy resolver
45 * implementation, or it can be created and used manually, such as
46 * with g_socket_client_set_proxy_resolver().
55 } GSimpleProxyResolverDomain
;
57 struct _GSimpleProxyResolverPrivate
{
58 gchar
*default_proxy
, **ignore_hosts
;
59 GHashTable
*uri_proxies
;
61 GPtrArray
*ignore_ips
;
62 GSimpleProxyResolverDomain
*ignore_domains
;
65 static void g_simple_proxy_resolver_iface_init (GProxyResolverInterface
*iface
);
67 G_DEFINE_TYPE_WITH_CODE (GSimpleProxyResolver
, g_simple_proxy_resolver
, G_TYPE_OBJECT
,
68 G_ADD_PRIVATE (GSimpleProxyResolver
)
69 G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER
,
70 g_simple_proxy_resolver_iface_init
))
79 static void reparse_ignore_hosts (GSimpleProxyResolver
*resolver
);
82 g_simple_proxy_resolver_finalize (GObject
*object
)
84 GSimpleProxyResolver
*resolver
= G_SIMPLE_PROXY_RESOLVER (object
);
85 GSimpleProxyResolverPrivate
*priv
= resolver
->priv
;
87 g_free (priv
->default_proxy
);
88 g_hash_table_destroy (priv
->uri_proxies
);
90 g_clear_pointer (&priv
->ignore_hosts
, g_strfreev
);
91 /* This will free ignore_ips and ignore_domains */
92 reparse_ignore_hosts (resolver
);
94 G_OBJECT_CLASS (g_simple_proxy_resolver_parent_class
)->finalize (object
);
98 g_simple_proxy_resolver_init (GSimpleProxyResolver
*resolver
)
100 resolver
->priv
= g_simple_proxy_resolver_get_instance_private (resolver
);
101 resolver
->priv
->uri_proxies
= g_hash_table_new_full (g_str_hash
, g_str_equal
,
106 g_simple_proxy_resolver_set_property (GObject
*object
,
111 GSimpleProxyResolver
*resolver
= G_SIMPLE_PROXY_RESOLVER (object
);
115 case PROP_DEFAULT_PROXY
:
116 g_simple_proxy_resolver_set_default_proxy (resolver
, g_value_get_string (value
));
119 case PROP_IGNORE_HOSTS
:
120 g_simple_proxy_resolver_set_ignore_hosts (resolver
, g_value_get_boxed (value
));
124 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
129 g_simple_proxy_resolver_get_property (GObject
*object
,
134 GSimpleProxyResolver
*resolver
= G_SIMPLE_PROXY_RESOLVER (object
);
138 case PROP_DEFAULT_PROXY
:
139 g_value_set_string (value
, resolver
->priv
->default_proxy
);
142 case PROP_IGNORE_HOSTS
:
143 g_value_set_boxed (value
, resolver
->priv
->ignore_hosts
);
147 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
152 reparse_ignore_hosts (GSimpleProxyResolver
*resolver
)
154 GSimpleProxyResolverPrivate
*priv
= resolver
->priv
;
155 GPtrArray
*ignore_ips
;
156 GArray
*ignore_domains
;
157 gchar
*host
, *tmp
, *colon
, *bracket
;
159 GInetAddressMask
*mask
;
160 GSimpleProxyResolverDomain domain
;
164 if (priv
->ignore_ips
)
165 g_ptr_array_free (priv
->ignore_ips
, TRUE
);
166 if (priv
->ignore_domains
)
168 for (i
= 0; priv
->ignore_domains
[i
].name
; i
++)
169 g_free (priv
->ignore_domains
[i
].name
);
170 g_free (priv
->ignore_domains
);
172 priv
->ignore_ips
= NULL
;
173 priv
->ignore_domains
= NULL
;
175 if (!priv
->ignore_hosts
|| !priv
->ignore_hosts
[0])
178 ignore_ips
= g_ptr_array_new_with_free_func (g_object_unref
);
179 ignore_domains
= g_array_new (TRUE
, FALSE
, sizeof (GSimpleProxyResolverDomain
));
181 for (i
= 0; priv
->ignore_hosts
[i
]; i
++)
183 host
= g_strchomp (priv
->ignore_hosts
[i
]);
185 /* See if it's an IP address or IP/length mask */
186 mask
= g_inet_address_mask_new_from_string (host
, NULL
);
189 g_ptr_array_add (ignore_ips
, mask
);
199 bracket
= strchr (host
, ']');
200 if (!bracket
|| !bracket
[1] || bracket
[1] != ':')
203 port
= strtoul (bracket
+ 2, &tmp
, 10);
211 colon
= strchr (host
, ':');
212 if (colon
&& !strchr (colon
+ 1, ':'))
214 /* hostname:port or IPv4:port */
215 port
= strtoul (colon
+ 1, &tmp
, 10);
222 iaddr
= g_inet_address_new_from_string (host
);
224 g_object_unref (iaddr
);
227 if (g_str_has_prefix (host
, "*."))
229 else if (*host
== '.')
233 memset (&domain
, 0, sizeof (domain
));
234 domain
.name
= g_strdup (host
);
235 domain
.length
= strlen (domain
.name
);
237 g_array_append_val (ignore_domains
, domain
);
241 g_warning ("Ignoring invalid ignore_hosts value '%s'", host
);
245 priv
->ignore_ips
= ignore_ips
;
247 g_ptr_array_free (ignore_ips
, TRUE
);
249 if (ignore_domains
->len
)
250 priv
->ignore_domains
= (GSimpleProxyResolverDomain
*)ignore_domains
->data
;
251 g_array_free (ignore_domains
, ignore_domains
->len
== 0);
255 ignore_host (GSimpleProxyResolver
*resolver
,
259 GSimpleProxyResolverPrivate
*priv
= resolver
->priv
;
260 gchar
*ascii_host
= NULL
;
261 gboolean ignore
= FALSE
;
262 gint i
, length
, offset
;
264 if (priv
->ignore_ips
)
268 iaddr
= g_inet_address_new_from_string (host
);
271 for (i
= 0; i
< priv
->ignore_ips
->len
; i
++)
273 GInetAddressMask
*mask
= priv
->ignore_ips
->pdata
[i
];
275 if (g_inet_address_mask_matches (mask
, iaddr
))
282 g_object_unref (iaddr
);
288 if (priv
->ignore_domains
)
290 if (g_hostname_is_non_ascii (host
))
291 host
= ascii_host
= g_hostname_to_ascii (host
);
292 length
= strlen (host
);
294 for (i
= 0; priv
->ignore_domains
[i
].length
; i
++)
296 GSimpleProxyResolverDomain
*domain
= &priv
->ignore_domains
[i
];
298 offset
= length
- domain
->length
;
299 if ((domain
->port
== 0 || domain
->port
== port
) &&
300 (offset
== 0 || (offset
> 0 && host
[offset
- 1] == '.')) &&
301 (g_ascii_strcasecmp (domain
->name
, host
+ offset
) == 0))
315 g_simple_proxy_resolver_lookup (GProxyResolver
*proxy_resolver
,
317 GCancellable
*cancellable
,
320 GSimpleProxyResolver
*resolver
= G_SIMPLE_PROXY_RESOLVER (proxy_resolver
);
321 GSimpleProxyResolverPrivate
*priv
= resolver
->priv
;
322 const gchar
*proxy
= NULL
;
325 if (priv
->ignore_ips
|| priv
->ignore_domains
)
330 if (_g_uri_parse_authority (uri
, &host
, &port
, NULL
) &&
331 ignore_host (resolver
, host
, port
))
337 if (!proxy
&& g_hash_table_size (priv
->uri_proxies
))
339 gchar
*scheme
= g_ascii_strdown (uri
, strcspn (uri
, ":"));
341 proxy
= g_hash_table_lookup (priv
->uri_proxies
, scheme
);
346 proxy
= priv
->default_proxy
;
350 if (!strncmp (proxy
, "socks://", 8))
352 proxies
= g_new0 (gchar
*, 4);
353 proxies
[0] = g_strdup_printf ("socks5://%s", proxy
+ 8);
354 proxies
[1] = g_strdup_printf ("socks4a://%s", proxy
+ 8);
355 proxies
[2] = g_strdup_printf ("socks4://%s", proxy
+ 8);
360 proxies
= g_new0 (gchar
*, 2);
361 proxies
[0] = g_strdup (proxy
);
368 g_simple_proxy_resolver_lookup_async (GProxyResolver
*proxy_resolver
,
370 GCancellable
*cancellable
,
371 GAsyncReadyCallback callback
,
374 GSimpleProxyResolver
*resolver
= G_SIMPLE_PROXY_RESOLVER (proxy_resolver
);
376 GError
*error
= NULL
;
379 task
= g_task_new (resolver
, cancellable
, callback
, user_data
);
380 g_task_set_source_tag (task
, g_simple_proxy_resolver_lookup_async
);
382 proxies
= g_simple_proxy_resolver_lookup (proxy_resolver
, uri
,
383 cancellable
, &error
);
385 g_task_return_pointer (task
, proxies
, (GDestroyNotify
)g_strfreev
);
387 g_task_return_error (task
, error
);
388 g_object_unref (task
);
392 g_simple_proxy_resolver_lookup_finish (GProxyResolver
*resolver
,
393 GAsyncResult
*result
,
396 g_return_val_if_fail (g_task_is_valid (result
, resolver
), NULL
);
398 return g_task_propagate_pointer (G_TASK (result
), error
);
402 g_simple_proxy_resolver_class_init (GSimpleProxyResolverClass
*resolver_class
)
404 GObjectClass
*object_class
= G_OBJECT_CLASS (resolver_class
);
406 object_class
->get_property
= g_simple_proxy_resolver_get_property
;
407 object_class
->set_property
= g_simple_proxy_resolver_set_property
;
408 object_class
->finalize
= g_simple_proxy_resolver_finalize
;
411 * GSimpleProxyResolver:default-proxy:
413 * The default proxy URI that will be used for any URI that doesn't
414 * match #GSimpleProxyResolver:ignore-hosts, and doesn't match any
415 * of the schemes set with g_simple_proxy_resolver_set_uri_proxy().
417 * Note that as a special case, if this URI starts with
418 * "socks://", #GSimpleProxyResolver will treat it as referring
419 * to all three of the socks5, socks4a, and socks4 proxy types.
421 g_object_class_install_property (object_class
, PROP_DEFAULT_PROXY
,
422 g_param_spec_string ("default-proxy",
424 P_("The default proxy URI"),
427 G_PARAM_STATIC_STRINGS
));
430 * GSimpleProxyResolver:ignore-hosts:
432 * A list of hostnames and IP addresses that the resolver should
433 * allow direct connections to.
435 * Entries can be in one of 4 formats:
437 * - A hostname, such as "example.com", ".example.com", or
438 * "*.example.com", any of which match "example.com" or
439 * any subdomain of it.
441 * - An IPv4 or IPv6 address, such as "192.168.1.1",
442 * which matches only that address.
444 * - A hostname or IP address followed by a port, such as
445 * "example.com:80", which matches whatever the hostname or IP
446 * address would match, but only for URLs with the (explicitly)
447 * indicated port. In the case of an IPv6 address, the address
448 * part must appear in brackets: "[::1]:443"
450 * - An IP address range, given by a base address and prefix length,
451 * such as "fe80::/10", which matches any address in that range.
453 * Note that when dealing with Unicode hostnames, the matching is
454 * done against the ASCII form of the name.
456 * Also note that hostname exclusions apply only to connections made
457 * to hosts identified by name, and IP address exclusions apply only
458 * to connections made to hosts identified by address. That is, if
459 * example.com has an address of 192.168.1.1, and the :ignore-hosts list
460 * contains only "192.168.1.1", then a connection to "example.com"
461 * (eg, via a #GNetworkAddress) will use the proxy, and a connection to
462 * "192.168.1.1" (eg, via a #GInetSocketAddress) will not.
464 * These rules match the "ignore-hosts"/"noproxy" rules most
465 * commonly used by other applications.
467 g_object_class_install_property (object_class
, PROP_IGNORE_HOSTS
,
468 g_param_spec_boxed ("ignore-hosts",
470 P_("Hosts that will not use the proxy"),
473 G_PARAM_STATIC_STRINGS
));
478 g_simple_proxy_resolver_iface_init (GProxyResolverInterface
*iface
)
480 iface
->lookup
= g_simple_proxy_resolver_lookup
;
481 iface
->lookup_async
= g_simple_proxy_resolver_lookup_async
;
482 iface
->lookup_finish
= g_simple_proxy_resolver_lookup_finish
;
486 * g_simple_proxy_resolver_new:
487 * @default_proxy: (nullable): the default proxy to use, eg
488 * "socks://192.168.1.1"
489 * @ignore_hosts: (nullable): an optional list of hosts/IP addresses
490 * to not use a proxy for.
492 * Creates a new #GSimpleProxyResolver. See
493 * #GSimpleProxyResolver:default-proxy and
494 * #GSimpleProxyResolver:ignore-hosts for more details on how the
495 * arguments are interpreted.
497 * Returns: (transfer full) a new #GSimpleProxyResolver
502 g_simple_proxy_resolver_new (const gchar
*default_proxy
,
503 gchar
**ignore_hosts
)
505 return g_object_new (G_TYPE_SIMPLE_PROXY_RESOLVER
,
506 "default-proxy", default_proxy
,
507 "ignore-hosts", ignore_hosts
,
512 * g_simple_proxy_resolver_set_default_proxy:
513 * @resolver: a #GSimpleProxyResolver
514 * @default_proxy: the default proxy to use
516 * Sets the default proxy on @resolver, to be used for any URIs that
517 * don't match #GSimpleProxyResolver:ignore-hosts or a proxy set
518 * via g_simple_proxy_resolver_set_uri_proxy().
520 * If @default_proxy starts with "socks://",
521 * #GSimpleProxyResolver will treat it as referring to all three of
522 * the socks5, socks4a, and socks4 proxy types.
527 g_simple_proxy_resolver_set_default_proxy (GSimpleProxyResolver
*resolver
,
528 const gchar
*default_proxy
)
530 g_return_if_fail (G_IS_SIMPLE_PROXY_RESOLVER (resolver
));
532 g_free (resolver
->priv
->default_proxy
);
533 resolver
->priv
->default_proxy
= g_strdup (default_proxy
);
534 g_object_notify (G_OBJECT (resolver
), "default-proxy");
538 * g_simple_proxy_resolver_set_ignore_hosts:
539 * @resolver: a #GSimpleProxyResolver
540 * @ignore_hosts: %NULL-terminated list of hosts/IP addresses
541 * to not use a proxy for
543 * Sets the list of ignored hosts.
545 * See #GSimpleProxyResolver:ignore-hosts for more details on how the
546 * @ignore_hosts argument is interpreted.
551 g_simple_proxy_resolver_set_ignore_hosts (GSimpleProxyResolver
*resolver
,
552 gchar
**ignore_hosts
)
554 g_return_if_fail (G_IS_SIMPLE_PROXY_RESOLVER (resolver
));
556 g_strfreev (resolver
->priv
->ignore_hosts
);
557 resolver
->priv
->ignore_hosts
= g_strdupv (ignore_hosts
);
558 reparse_ignore_hosts (resolver
);
559 g_object_notify (G_OBJECT (resolver
), "ignore-hosts");
563 * g_simple_proxy_resolver_set_uri_proxy:
564 * @resolver: a #GSimpleProxyResolver
565 * @uri_scheme: the URI scheme to add a proxy for
566 * @proxy: the proxy to use for @uri_scheme
568 * Adds a URI-scheme-specific proxy to @resolver; URIs whose scheme
569 * matches @uri_scheme (and which don't match
570 * #GSimpleProxyResolver:ignore-hosts) will be proxied via @proxy.
572 * As with #GSimpleProxyResolver:default-proxy, if @proxy starts with
573 * "socks://", #GSimpleProxyResolver will treat it
574 * as referring to all three of the socks5, socks4a, and socks4 proxy
580 g_simple_proxy_resolver_set_uri_proxy (GSimpleProxyResolver
*resolver
,
581 const gchar
*uri_scheme
,
584 g_return_if_fail (G_IS_SIMPLE_PROXY_RESOLVER (resolver
));
586 g_hash_table_replace (resolver
->priv
->uri_proxies
,
587 g_ascii_strdown (uri_scheme
, -1),