summaryrefslogtreecommitdiff
path: root/src/libproxy/proxy-dbus.c
blob: 6b594e37fd201350f3f8f19fcb839db201487de7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/* proxy-dbus.c
 *
 * Copyright 2022-2023 The Libproxy Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#include <gio/gio.h>

#include "proxy.h"

struct _pxProxyFactory {
  GDBusProxy *proxy;
  GCancellable *cancellable;
};

/**
 * SECTION:px-proxy
 * @short_description: A convient helper for using proxy servers
 */

pxProxyFactory *px_proxy_factory_copy (pxProxyFactory *self);

G_DEFINE_BOXED_TYPE (pxProxyFactory,
                     px_proxy_factory,
                     (GBoxedCopyFunc)px_proxy_factory_copy,
                     (GFreeFunc)px_proxy_factory_new);


pxProxyFactory *
px_proxy_factory_copy (pxProxyFactory *self)
{
  return g_memdup2 (self, sizeof (pxProxyFactory));
}

/**
 * px_proxy_factory_new:
 *
 * Creates a new `pxProxyFactory` instance.
 *
 * This instance should be kept around as long as possible as it contains
 * cached data to increase performance.  Memory usage should be minimal
 * (cache is small) and the cache lifespan is handled automatically.
 *
 * Returns: The newly created `pxProxyFactory`
 */
pxProxyFactory *
px_proxy_factory_new (void)
{
  g_autoptr (GError) error = NULL;
  pxProxyFactory *self = g_new0 (pxProxyFactory, 1);

  self->cancellable = g_cancellable_new ();
  self->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
                                               G_DBUS_PROXY_FLAGS_NONE,
                                               NULL, /* GDBusInterfaceInfo */
                                               "org.libproxy.proxy",
                                               "/org/libproxy/proxy",
                                               "org.libproxy.proxy",
                                               self->cancellable, /* GCancellable */
                                               &error);

  if (!self->proxy) {
    g_clear_error (&error);

    self->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
                                                 G_DBUS_PROXY_FLAGS_NONE,
                                                 NULL, /* GDBusInterfaceInfo */
                                                 "org.libproxy.proxy",
                                                 "/org/libproxy/proxy",
                                                 "org.libproxy.proxy",
                                                 self->cancellable, /* GCancellable */
                                                 &error);
  }

  if (!self->proxy)
    g_warning ("Could not create libproxy dbus proxy: %s", error->message);

  return self;
}

/**
 * px_proxy_factory_get_proxies:
 * @self: a #pxProxyFactory
 * @url: Get proxxies for specificed URL
 *
 * Get which proxies to use for the specified @URL.
 *
 * A %NULL-terminated array of proxy strings is returned.
 * If the first proxy fails, the second should be tried, etc...
 * Don't forget to free the strings/array when you are done.
 * If an unrecoverable error occurs, this function returns %NULL.
 *
 * Regarding performance: this method always blocks and may be called
 * in a separate thread (is thread-safe).  In most cases, the time
 * required to complete this function call is simply the time required
 * to read the configuration (i.e. from gconf, kconfig, etc).
 *
 * In the case of PAC, if no valid PAC is found in the cache (i.e.
 * configuration has changed, cache is invalid, etc), the PAC file is
 * downloaded and inserted into the cache. This is the most expensive
 * operation as the PAC is retrieved over the network. Once a PAC exists
 * in the cache, it is merely a javascript invocation to evaluate the PAC.
 * One should note that DNS can be called from within a PAC during
 * javascript invocation.
 *
 * In the case of WPAD, WPAD is used to automatically locate a PAC on the
 * network.  Currently, we only use DNS for this, but other methods may
 * be implemented in the future.  Once the PAC is located, normal PAC
 * performance (described above) applies.
 *
 * The format of the returned proxy strings are as follows:
 *
 *   - http://[username:password@]proxy:port
 *
 *   - socks://[username:password@]proxy:port
 *
 *   - socks5://[username:password@]proxy:port
 *
 *   - socks4://[username:password@]proxy:port
 *
 *   - <procotol>://[username:password@]proxy:port
 *
 *   - direct://
 *
 * Please note that the username and password in the above URLs are optional
 * and should be use to authenticate the connection if present.
 *
 * For SOCKS proxies, when the protocol version is specified (socks4:// or
 * socks5://), it is expected that only this version is used. When only
 * socks:// is set, the client MUST try SOCKS version 5 protocol and, on
 * connection failure, fallback to SOCKS version 4.
 *
 * Other proxying protocols may exist. It is expected that the returned
 * configuration scheme shall match the network service name of the
 * proxy protocol or the service name of the protocol being proxied if the
 * previous does not exist. As an example, on Mac OS X you can configure a
 * RTSP streaming proxy. The expected returned configuration would be:
 *
 *   - rtsp://[username:password@]proxy:port
 *
 * To free the returned value, call @px_proxy_factory_free_proxies.
 *
 * Returns: (transfer full): a list of proxies
 */
char **
px_proxy_factory_get_proxies (pxProxyFactory *self,
                              const char     *url)
{
  g_autoptr (GVariant) result = NULL;
  g_autoptr (GError) error = NULL;
  g_autoptr (GVariantIter) iter = NULL;
  g_autoptr (GList) list = NULL;
  GList *tmp;
  char *str;
  char **retval;
  gsize len;
  gsize idx;

  if (!self->proxy)
    return NULL;

  result = g_dbus_proxy_call_sync (self->proxy,
                                   "query",
                                   g_variant_new ("(s)", url),
                                   G_DBUS_CALL_FLAGS_NONE,
                                   -1,
                                   self->cancellable,
                                   &error);
  if (!result) {
    g_warning ("Could not query proxy dbus: %s", error->message);
    return NULL;
  }

  g_variant_get (result, "(as)", &iter);

  while (g_variant_iter_loop (iter, "&s", &str)) {
    list = g_list_prepend (list, str);
  }

  len = g_list_length (list);
  if (len == 0) {
    retval = g_malloc0 (sizeof (char *) * 2);
    retval[0] = g_strdup ("direct://");

    return retval;
  }

  retval = g_malloc0_n (len + 1, sizeof (char *));
  for (tmp = list, idx = 0; tmp && tmp->data; tmp = tmp->next, idx++) {
    char *value = tmp->data;
    retval[idx] = g_strdup (value);
  }

  return retval;
}

/**
 * px_proxy_factory_free_proxies
 * @proxies: (array zero-terminated=1): a %NULL-terminated array of proxies
 *
 * Frees the proxy array returned by @px_proxy_factory_get_proxies when no
 * longer used.
 *
 * @since 0.4.16
 */
void
px_proxy_factory_free_proxies (char **proxies)
{
  g_clear_pointer (&proxies, g_strfreev);
}

/**
 * px_proxy_factory_free:
 * @self: a #pxProxyFactory
 *
 * Frees the `pxProxyFactory`.
 */
void
px_proxy_factory_free (pxProxyFactory *self)
{
  g_cancellable_cancel (self->cancellable);
  g_clear_object (&self->cancellable);
  g_clear_object (&self->proxy);
  g_clear_pointer (&self, g_free);
}