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.1 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
)
291 if (g_hostname_is_non_ascii (host
))
292 host
= ascii_host
= g_hostname_to_ascii (host
);
294 length
= strlen (host
);
296 for (i
= 0; length
> 0 && priv
->ignore_domains
[i
].length
; i
++)
298 GSimpleProxyResolverDomain
*domain
= &priv
->ignore_domains
[i
];
300 offset
= length
- domain
->length
;
301 if ((domain
->port
== 0 || domain
->port
== port
) &&
302 (offset
== 0 || (offset
> 0 && host
[offset
- 1] == '.')) &&
303 (g_ascii_strcasecmp (domain
->name
, host
+ offset
) == 0))
317 g_simple_proxy_resolver_lookup (GProxyResolver
*proxy_resolver
,
319 GCancellable
*cancellable
,
322 GSimpleProxyResolver
*resolver
= G_SIMPLE_PROXY_RESOLVER (proxy_resolver
);
323 GSimpleProxyResolverPrivate
*priv
= resolver
->priv
;
324 const gchar
*proxy
= NULL
;
327 if (priv
->ignore_ips
|| priv
->ignore_domains
)
332 if (_g_uri_parse_authority (uri
, &host
, &port
, NULL
, NULL
) &&
333 ignore_host (resolver
, host
, port
))
339 if (!proxy
&& g_hash_table_size (priv
->uri_proxies
))
341 gchar
*scheme
= g_ascii_strdown (uri
, strcspn (uri
, ":"));
343 proxy
= g_hash_table_lookup (priv
->uri_proxies
, scheme
);
348 proxy
= priv
->default_proxy
;
352 if (!strncmp (proxy
, "socks://", 8))
354 proxies
= g_new0 (gchar
*, 4);
355 proxies
[0] = g_strdup_printf ("socks5://%s", proxy
+ 8);
356 proxies
[1] = g_strdup_printf ("socks4a://%s", proxy
+ 8);
357 proxies
[2] = g_strdup_printf ("socks4://%s", proxy
+ 8);
362 proxies
= g_new0 (gchar
*, 2);
363 proxies
[0] = g_strdup (proxy
);
370 g_simple_proxy_resolver_lookup_async (GProxyResolver
*proxy_resolver
,
372 GCancellable
*cancellable
,
373 GAsyncReadyCallback callback
,
376 GSimpleProxyResolver
*resolver
= G_SIMPLE_PROXY_RESOLVER (proxy_resolver
);
378 GError
*error
= NULL
;
381 task
= g_task_new (resolver
, cancellable
, callback
, user_data
);
382 g_task_set_source_tag (task
, g_simple_proxy_resolver_lookup_async
);
384 proxies
= g_simple_proxy_resolver_lookup (proxy_resolver
, uri
,
385 cancellable
, &error
);
387 g_task_return_pointer (task
, proxies
, (GDestroyNotify
)g_strfreev
);
389 g_task_return_error (task
, error
);
390 g_object_unref (task
);
394 g_simple_proxy_resolver_lookup_finish (GProxyResolver
*resolver
,
395 GAsyncResult
*result
,
398 g_return_val_if_fail (g_task_is_valid (result
, resolver
), NULL
);
400 return g_task_propagate_pointer (G_TASK (result
), error
);
404 g_simple_proxy_resolver_class_init (GSimpleProxyResolverClass
*resolver_class
)
406 GObjectClass
*object_class
= G_OBJECT_CLASS (resolver_class
);
408 object_class
->get_property
= g_simple_proxy_resolver_get_property
;
409 object_class
->set_property
= g_simple_proxy_resolver_set_property
;
410 object_class
->finalize
= g_simple_proxy_resolver_finalize
;
413 * GSimpleProxyResolver:default-proxy:
415 * The default proxy URI that will be used for any URI that doesn't
416 * match #GSimpleProxyResolver:ignore-hosts, and doesn't match any
417 * of the schemes set with g_simple_proxy_resolver_set_uri_proxy().
419 * Note that as a special case, if this URI starts with
420 * "socks://", #GSimpleProxyResolver will treat it as referring
421 * to all three of the socks5, socks4a, and socks4 proxy types.
423 g_object_class_install_property (object_class
, PROP_DEFAULT_PROXY
,
424 g_param_spec_string ("default-proxy",
426 P_("The default proxy URI"),
429 G_PARAM_STATIC_STRINGS
));
432 * GSimpleProxyResolver:ignore-hosts:
434 * A list of hostnames and IP addresses that the resolver should
435 * allow direct connections to.
437 * Entries can be in one of 4 formats:
439 * - A hostname, such as "example.com", ".example.com", or
440 * "*.example.com", any of which match "example.com" or
441 * any subdomain of it.
443 * - An IPv4 or IPv6 address, such as "192.168.1.1",
444 * which matches only that address.
446 * - A hostname or IP address followed by a port, such as
447 * "example.com:80", which matches whatever the hostname or IP
448 * address would match, but only for URLs with the (explicitly)
449 * indicated port. In the case of an IPv6 address, the address
450 * part must appear in brackets: "[::1]:443"
452 * - An IP address range, given by a base address and prefix length,
453 * such as "fe80::/10", which matches any address in that range.
455 * Note that when dealing with Unicode hostnames, the matching is
456 * done against the ASCII form of the name.
458 * Also note that hostname exclusions apply only to connections made
459 * to hosts identified by name, and IP address exclusions apply only
460 * to connections made to hosts identified by address. That is, if
461 * example.com has an address of 192.168.1.1, and the :ignore-hosts list
462 * contains only "192.168.1.1", then a connection to "example.com"
463 * (eg, via a #GNetworkAddress) will use the proxy, and a connection to
464 * "192.168.1.1" (eg, via a #GInetSocketAddress) will not.
466 * These rules match the "ignore-hosts"/"noproxy" rules most
467 * commonly used by other applications.
469 g_object_class_install_property (object_class
, PROP_IGNORE_HOSTS
,
470 g_param_spec_boxed ("ignore-hosts",
472 P_("Hosts that will not use the proxy"),
475 G_PARAM_STATIC_STRINGS
));
480 g_simple_proxy_resolver_iface_init (GProxyResolverInterface
*iface
)
482 iface
->lookup
= g_simple_proxy_resolver_lookup
;
483 iface
->lookup_async
= g_simple_proxy_resolver_lookup_async
;
484 iface
->lookup_finish
= g_simple_proxy_resolver_lookup_finish
;
488 * g_simple_proxy_resolver_new:
489 * @default_proxy: (nullable): the default proxy to use, eg
490 * "socks://192.168.1.1"
491 * @ignore_hosts: (nullable): an optional list of hosts/IP addresses
492 * to not use a proxy for.
494 * Creates a new #GSimpleProxyResolver. See
495 * #GSimpleProxyResolver:default-proxy and
496 * #GSimpleProxyResolver:ignore-hosts for more details on how the
497 * arguments are interpreted.
499 * Returns: (transfer full) a new #GSimpleProxyResolver
504 g_simple_proxy_resolver_new (const gchar
*default_proxy
,
505 gchar
**ignore_hosts
)
507 return g_object_new (G_TYPE_SIMPLE_PROXY_RESOLVER
,
508 "default-proxy", default_proxy
,
509 "ignore-hosts", ignore_hosts
,
514 * g_simple_proxy_resolver_set_default_proxy:
515 * @resolver: a #GSimpleProxyResolver
516 * @default_proxy: the default proxy to use
518 * Sets the default proxy on @resolver, to be used for any URIs that
519 * don't match #GSimpleProxyResolver:ignore-hosts or a proxy set
520 * via g_simple_proxy_resolver_set_uri_proxy().
522 * If @default_proxy starts with "socks://",
523 * #GSimpleProxyResolver will treat it as referring to all three of
524 * the socks5, socks4a, and socks4 proxy types.
529 g_simple_proxy_resolver_set_default_proxy (GSimpleProxyResolver
*resolver
,
530 const gchar
*default_proxy
)
532 g_return_if_fail (G_IS_SIMPLE_PROXY_RESOLVER (resolver
));
534 g_free (resolver
->priv
->default_proxy
);
535 resolver
->priv
->default_proxy
= g_strdup (default_proxy
);
536 g_object_notify (G_OBJECT (resolver
), "default-proxy");
540 * g_simple_proxy_resolver_set_ignore_hosts:
541 * @resolver: a #GSimpleProxyResolver
542 * @ignore_hosts: %NULL-terminated list of hosts/IP addresses
543 * to not use a proxy for
545 * Sets the list of ignored hosts.
547 * See #GSimpleProxyResolver:ignore-hosts for more details on how the
548 * @ignore_hosts argument is interpreted.
553 g_simple_proxy_resolver_set_ignore_hosts (GSimpleProxyResolver
*resolver
,
554 gchar
**ignore_hosts
)
556 g_return_if_fail (G_IS_SIMPLE_PROXY_RESOLVER (resolver
));
558 g_strfreev (resolver
->priv
->ignore_hosts
);
559 resolver
->priv
->ignore_hosts
= g_strdupv (ignore_hosts
);
560 reparse_ignore_hosts (resolver
);
561 g_object_notify (G_OBJECT (resolver
), "ignore-hosts");
565 * g_simple_proxy_resolver_set_uri_proxy:
566 * @resolver: a #GSimpleProxyResolver
567 * @uri_scheme: the URI scheme to add a proxy for
568 * @proxy: the proxy to use for @uri_scheme
570 * Adds a URI-scheme-specific proxy to @resolver; URIs whose scheme
571 * matches @uri_scheme (and which don't match
572 * #GSimpleProxyResolver:ignore-hosts) will be proxied via @proxy.
574 * As with #GSimpleProxyResolver:default-proxy, if @proxy starts with
575 * "socks://", #GSimpleProxyResolver will treat it
576 * as referring to all three of the socks5, socks4a, and socks4 proxy
582 g_simple_proxy_resolver_set_uri_proxy (GSimpleProxyResolver
*resolver
,
583 const gchar
*uri_scheme
,
586 g_return_if_fail (G_IS_SIMPLE_PROXY_RESOLVER (resolver
));
588 g_hash_table_replace (resolver
->priv
->uri_proxies
,
589 g_ascii_strdown (uri_scheme
, -1),