1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2008, 2010 Collabora, Ltd.
4 * Copyright (C) 2008 Nokia Corporation. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Youness Alaoui <youness.alaoui@collabora.co.uk
20 *
21 * Contributors:
22 * Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
23 */
24
25 #include "config.h"
26
27 #include "gsocks5proxy.h"
28
29 #include <string.h>
30
31 #include "giomodule.h"
32 #include "giomodule-priv.h"
33 #include "giostream.h"
34 #include "ginetaddress.h"
35 #include "ginputstream.h"
36 #include "glibintl.h"
37 #include "goutputstream.h"
38 #include "gproxy.h"
39 #include "gproxyaddress.h"
40 #include "gtask.h"
41
42 #define SOCKS5_VERSION 0x05
43
44 #define SOCKS5_CMD_CONNECT 0x01
45 #define SOCKS5_CMD_BIND 0x02
46 #define SOCKS5_CMD_UDP_ASSOCIATE 0x03
47
48 #define SOCKS5_ATYP_IPV4 0x01
49 #define SOCKS5_ATYP_DOMAINNAME 0x03
50 #define SOCKS5_ATYP_IPV6 0x04
51
52 #define SOCKS5_AUTH_VERSION 0x01
53
54 #define SOCKS5_AUTH_NONE 0x00
55 #define SOCKS5_AUTH_GSSAPI 0x01
56 #define SOCKS5_AUTH_USR_PASS 0x02
57 #define SOCKS5_AUTH_NO_ACCEPT 0xff
58
59 #define SOCKS5_MAX_LEN 255
60 #define SOCKS5_RESERVED 0x00
61
62 #define SOCKS5_REP_SUCCEEDED 0x00
63 #define SOCKS5_REP_SRV_FAILURE 0x01
64 #define SOCKS5_REP_NOT_ALLOWED 0x02
65 #define SOCKS5_REP_NET_UNREACH 0x03
66 #define SOCKS5_REP_HOST_UNREACH 0x04
67 #define SOCKS5_REP_REFUSED 0x05
68 #define SOCKS5_REP_TTL_EXPIRED 0x06
69 #define SOCKS5_REP_CMD_NOT_SUP 0x07
70 #define SOCKS5_REP_ATYPE_NOT_SUP 0x08
71
72
73 struct _GSocks5Proxy
74 {
75 GObject parent;
76 };
77
78 struct _GSocks5ProxyClass
79 {
80 GObjectClass parent_class;
81 };
82
83 static void g_socks5_proxy_iface_init (GProxyInterface *proxy_iface);
84
85 #define g_socks5_proxy_get_type _g_socks5_proxy_get_type
86 G_DEFINE_TYPE_WITH_CODE (GSocks5Proxy, g_socks5_proxy, G_TYPE_OBJECT,
87 G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
88 g_socks5_proxy_iface_init)
89 _g_io_modules_ensure_extension_points_registered ();
90 g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
91 g_define_type_id,
92 "socks5",
93 0))
94
95 static void
g_socks5_proxy_finalize(GObject * object)96 g_socks5_proxy_finalize (GObject *object)
97 {
98 /* must chain up */
99 G_OBJECT_CLASS (g_socks5_proxy_parent_class)->finalize (object);
100 }
101
102 static void
g_socks5_proxy_init(GSocks5Proxy * proxy)103 g_socks5_proxy_init (GSocks5Proxy *proxy)
104 {
105 }
106
107 /*
108 * +----+----------+----------+
109 * |VER | NMETHODS | METHODS |
110 * +----+----------+----------+
111 * | 1 | 1 | 1 to 255 |
112 * +----+----------+----------+
113 */
114 #define SOCKS5_NEGO_MSG_LEN 4
115 static gint
set_nego_msg(guint8 * msg,gboolean has_auth)116 set_nego_msg (guint8 *msg, gboolean has_auth)
117 {
118 gint len = 3;
119
120 msg[0] = SOCKS5_VERSION;
121 msg[1] = 0x01; /* number of methods supported */
122 msg[2] = SOCKS5_AUTH_NONE;
123
124 /* add support for authentication method */
125 if (has_auth)
126 {
127 msg[1] = 0x02; /* number of methods supported */
128 msg[3] = SOCKS5_AUTH_USR_PASS;
129 len++;
130 }
131
132 return len;
133 }
134
135
136 /*
137 * +----+--------+
138 * |VER | METHOD |
139 * +----+--------+
140 * | 1 | 1 |
141 * +----+--------+
142 */
143 #define SOCKS5_NEGO_REP_LEN 2
144 static gboolean
parse_nego_reply(const guint8 * data,gboolean has_auth,gboolean * must_auth,GError ** error)145 parse_nego_reply (const guint8 *data,
146 gboolean has_auth,
147 gboolean *must_auth,
148 GError **error)
149 {
150 if (data[0] != SOCKS5_VERSION)
151 {
152 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
153 _("The server is not a SOCKSv5 proxy server."));
154 return FALSE;
155 }
156
157 switch (data[1])
158 {
159 case SOCKS5_AUTH_NONE:
160 *must_auth = FALSE;
161 break;
162
163 case SOCKS5_AUTH_USR_PASS:
164 if (!has_auth)
165 {
166 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_NEED_AUTH,
167 _("The SOCKSv5 proxy requires authentication."));
168 return FALSE;
169 }
170 *must_auth = TRUE;
171 break;
172
173 case SOCKS5_AUTH_NO_ACCEPT:
174 if (!has_auth)
175 {
176 /* The server has said it accepts none of our authentication methods,
177 * but given the slightly odd implementation of set_nego_msg(), we
178 * actually only gave it the choice of %SOCKS5_AUTH_NONE, since the
179 * caller specified no username or password.
180 * Return %G_IO_ERROR_PROXY_NEED_AUTH so the caller knows that if
181 * they specify a username and password and try again, authentication
182 * might succeed (since we’ll send %SOCKS5_AUTH_USR_PASS next time). */
183 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_NEED_AUTH,
184 _("The SOCKSv5 proxy requires authentication."));
185 return FALSE;
186 }
187 G_GNUC_FALLTHROUGH;
188 case SOCKS5_AUTH_GSSAPI:
189 default:
190 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_AUTH_FAILED,
191 _("The SOCKSv5 proxy requires an authentication "
192 "method that is not supported by GLib."));
193 return FALSE;
194 break;
195 }
196
197 return TRUE;
198 }
199
200 #define SOCKS5_AUTH_MSG_LEN 515
201 static gint
set_auth_msg(guint8 * msg,const gchar * username,const gchar * password,GError ** error)202 set_auth_msg (guint8 *msg,
203 const gchar *username,
204 const gchar *password,
205 GError **error)
206 {
207 gint len = 0;
208 gint ulen = 0; /* username length */
209 gint plen = 0; /* Password length */
210
211 if (username)
212 ulen = strlen (username);
213
214 if (password)
215 plen = strlen (password);
216
217 if (ulen > SOCKS5_MAX_LEN || plen > SOCKS5_MAX_LEN)
218 {
219 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
220 _("Username or password is too long for SOCKSv5 "
221 "protocol."));
222 return -1;
223 }
224
225 msg[len++] = SOCKS5_AUTH_VERSION;
226 msg[len++] = ulen;
227
228 if (ulen > 0)
229 memcpy (msg + len, username, ulen);
230
231 len += ulen;
232 msg[len++] = plen;
233
234 if (plen > 0)
235 memcpy (msg + len, password, plen);
236
237 len += plen;
238
239 return len;
240 }
241
242
243 static gboolean
check_auth_status(const guint8 * data,GError ** error)244 check_auth_status (const guint8 *data, GError **error)
245 {
246 if (data[0] != SOCKS5_AUTH_VERSION
247 || data[1] != SOCKS5_REP_SUCCEEDED)
248 {
249 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_AUTH_FAILED,
250 _("SOCKSv5 authentication failed due to wrong "
251 "username or password."));
252 return FALSE;
253 }
254 return TRUE;
255 }
256
257 /*
258 * +----+-----+-------+------+----------+----------+
259 * |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
260 * +----+-----+-------+------+----------+----------+
261 * | 1 | 1 | X'00' | 1 | Variable | 2 |
262 * +----+-----+-------+------+----------+----------+
263 * DST.ADDR is a string with first byte being the size. So DST.ADDR may not be
264 * longer then 256 bytes.
265 */
266 #define SOCKS5_CONN_MSG_LEN 262
267 static gint
set_connect_msg(guint8 * msg,const gchar * hostname,guint16 port,GError ** error)268 set_connect_msg (guint8 *msg,
269 const gchar *hostname,
270 guint16 port,
271 GError **error)
272 {
273 guint len = 0;
274
275 msg[len++] = SOCKS5_VERSION;
276 msg[len++] = SOCKS5_CMD_CONNECT;
277 msg[len++] = SOCKS5_RESERVED;
278
279 if (g_hostname_is_ip_address (hostname))
280 {
281 GInetAddress *addr = g_inet_address_new_from_string (hostname);
282 gsize addr_len = g_inet_address_get_native_size (addr);
283
284 /* We are cheating for simplicity, here's the logic:
285 * 1 = IPV4 = 4 bytes / 4
286 * 4 = IPV6 = 16 bytes / 4 */
287 msg[len++] = addr_len / 4;
288 memcpy (msg + len, g_inet_address_to_bytes (addr), addr_len);
289 len += addr_len;
290
291 g_object_unref (addr);
292 }
293 else
294 {
295 gsize host_len = strlen (hostname);
296
297 if (host_len > SOCKS5_MAX_LEN)
298 {
299 g_set_error (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
300 _("Hostname “%s” is too long for SOCKSv5 protocol"),
301 hostname);
302 return -1;
303 }
304
305 msg[len++] = SOCKS5_ATYP_DOMAINNAME;
306 msg[len++] = (guint8) host_len;
307 memcpy (msg + len, hostname, host_len);
308 len += host_len;
309 }
310
311 {
312 guint16 hp = g_htons (port);
313 memcpy (msg + len, &hp, 2);
314 len += 2;
315 }
316
317 return len;
318 }
319
320 /*
321 * +----+-----+-------+------+----------+----------+
322 * |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
323 * +----+-----+-------+------+----------+----------+
324 * | 1 | 1 | X'00' | 1 | Variable | 2 |
325 * +----+-----+-------+------+----------+----------+
326 * This reply need to be read by small part to determine size. Buffer
327 * size is determined in function of the biggest part to read.
328 *
329 * The parser only requires 4 bytes.
330 */
331 #define SOCKS5_CONN_REP_LEN 255
332 static gboolean
parse_connect_reply(const guint8 * data,gint * atype,GError ** error)333 parse_connect_reply (const guint8 *data, gint *atype, GError **error)
334 {
335 if (data[0] != SOCKS5_VERSION)
336 {
337 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
338 _("The server is not a SOCKSv5 proxy server."));
339 return FALSE;
340 }
341
342 switch (data[1])
343 {
344 case SOCKS5_REP_SUCCEEDED:
345 if (data[2] != SOCKS5_RESERVED)
346 {
347 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
348 _("The server is not a SOCKSv5 proxy server."));
349 return FALSE;
350 }
351
352 switch (data[3])
353 {
354 case SOCKS5_ATYP_IPV4:
355 case SOCKS5_ATYP_IPV6:
356 case SOCKS5_ATYP_DOMAINNAME:
357 *atype = data[3];
358 break;
359
360 default:
361 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
362 _("The SOCKSv5 proxy server uses unknown address type."));
363 return FALSE;
364 }
365 break;
366
367 case SOCKS5_REP_SRV_FAILURE:
368 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
369 _("Internal SOCKSv5 proxy server error."));
370 return FALSE;
371 break;
372
373 case SOCKS5_REP_NOT_ALLOWED:
374 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_NOT_ALLOWED,
375 _("SOCKSv5 connection not allowed by ruleset."));
376 return FALSE;
377 break;
378
379 case SOCKS5_REP_TTL_EXPIRED:
380 case SOCKS5_REP_HOST_UNREACH:
381 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE,
382 _("Host unreachable through SOCKSv5 server."));
383 return FALSE;
384 break;
385
386 case SOCKS5_REP_NET_UNREACH:
387 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
388 _("Network unreachable through SOCKSv5 proxy."));
389 return FALSE;
390 break;
391
392 case SOCKS5_REP_REFUSED:
393 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_REFUSED,
394 _("Connection refused through SOCKSv5 proxy."));
395 return FALSE;
396 break;
397
398 case SOCKS5_REP_CMD_NOT_SUP:
399 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
400 _("SOCKSv5 proxy does not support “connect” command."));
401 return FALSE;
402 break;
403
404 case SOCKS5_REP_ATYPE_NOT_SUP:
405 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
406 _("SOCKSv5 proxy does not support provided address type."));
407 return FALSE;
408 break;
409
410 default: /* Unknown error */
411 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
412 _("Unknown SOCKSv5 proxy error."));
413 return FALSE;
414 break;
415 }
416
417 return TRUE;
418 }
419
420 static GIOStream *
g_socks5_proxy_connect(GProxy * proxy,GIOStream * io_stream,GProxyAddress * proxy_address,GCancellable * cancellable,GError ** error)421 g_socks5_proxy_connect (GProxy *proxy,
422 GIOStream *io_stream,
423 GProxyAddress *proxy_address,
424 GCancellable *cancellable,
425 GError **error)
426 {
427 gboolean has_auth;
428 GInputStream *in;
429 GOutputStream *out;
430 const gchar *hostname;
431 guint16 port;
432 const gchar *username;
433 const gchar *password;
434
435 hostname = g_proxy_address_get_destination_hostname (proxy_address);
436 port = g_proxy_address_get_destination_port (proxy_address);
437 username = g_proxy_address_get_username (proxy_address);
438 password = g_proxy_address_get_password (proxy_address);
439
440 has_auth = username || password;
441
442 in = g_io_stream_get_input_stream (io_stream);
443 out = g_io_stream_get_output_stream (io_stream);
444
445 /* Send SOCKS5 handshake */
446 {
447 guint8 msg[SOCKS5_NEGO_MSG_LEN];
448 gint len;
449
450 len = set_nego_msg (msg, has_auth);
451
452 if (!g_output_stream_write_all (out, msg, len, NULL,
453 cancellable, error))
454 goto error;
455 }
456
457 /* Receive SOCKS5 response and reply with authentication if required */
458 {
459 guint8 data[SOCKS5_NEGO_REP_LEN];
460 gboolean must_auth = FALSE;
461
462 if (!g_input_stream_read_all (in, data, sizeof (data), NULL,
463 cancellable, error))
464 goto error;
465
466 if (!parse_nego_reply (data, has_auth, &must_auth, error))
467 goto error;
468
469 if (must_auth)
470 {
471 guint8 msg[SOCKS5_AUTH_MSG_LEN];
472 gint len;
473
474 len = set_auth_msg (msg, username, password, error);
475
476 if (len < 0)
477 goto error;
478
479 if (!g_output_stream_write_all (out, msg, len, NULL,
480 cancellable, error))
481 goto error;
482
483 if (!g_input_stream_read_all (in, data, sizeof (data), NULL,
484 cancellable, error))
485 goto error;
486
487 if (!check_auth_status (data, error))
488 goto error;
489 }
490 }
491
492 /* Send SOCKS5 connection request */
493 {
494 guint8 msg[SOCKS5_CONN_MSG_LEN];
495 gint len;
496
497 len = set_connect_msg (msg, hostname, port, error);
498
499 if (len < 0)
500 goto error;
501
502 if (!g_output_stream_write_all (out, msg, len, NULL,
503 cancellable, error))
504 goto error;
505 }
506
507 /* Read SOCKS5 response */
508 {
509 guint8 data[SOCKS5_CONN_REP_LEN];
510 gint atype;
511
512 if (!g_input_stream_read_all (in, data, 4, NULL,
513 cancellable, error))
514 goto error;
515
516 if (!parse_connect_reply (data, &atype, error))
517 goto error;
518
519 switch (atype)
520 {
521 case SOCKS5_ATYP_IPV4:
522 if (!g_input_stream_read_all (in, data, 6, NULL,
523 cancellable, error))
524 goto error;
525 break;
526
527 case SOCKS5_ATYP_IPV6:
528 if (!g_input_stream_read_all (in, data, 18, NULL,
529 cancellable, error))
530 goto error;
531 break;
532
533 case SOCKS5_ATYP_DOMAINNAME:
534 if (!g_input_stream_read_all (in, data, 1, NULL,
535 cancellable, error))
536 goto error;
537 if (!g_input_stream_read_all (in, data, data[0] + 2, NULL,
538 cancellable, error))
539 goto error;
540 break;
541 }
542 }
543
544 return g_object_ref (io_stream);
545
546 error:
547 return NULL;
548 }
549
550
551 typedef struct
552 {
553 GIOStream *io_stream;
554 gchar *hostname;
555 guint16 port;
556 gchar *username;
557 gchar *password;
558 guint8 *buffer;
559 gssize length;
560 gssize offset;
561 } ConnectAsyncData;
562
563 static void nego_msg_write_cb (GObject *source,
564 GAsyncResult *res,
565 gpointer user_data);
566 static void nego_reply_read_cb (GObject *source,
567 GAsyncResult *res,
568 gpointer user_data);
569 static void auth_msg_write_cb (GObject *source,
570 GAsyncResult *res,
571 gpointer user_data);
572 static void auth_reply_read_cb (GObject *source,
573 GAsyncResult *result,
574 gpointer user_data);
575 static void send_connect_msg (GTask *task);
576 static void connect_msg_write_cb (GObject *source,
577 GAsyncResult *result,
578 gpointer user_data);
579 static void connect_reply_read_cb (GObject *source,
580 GAsyncResult *result,
581 gpointer user_data);
582 static void connect_addr_len_read_cb (GObject *source,
583 GAsyncResult *result,
584 gpointer user_data);
585 static void connect_addr_read_cb (GObject *source,
586 GAsyncResult *result,
587 gpointer user_data);
588
589 static void
free_connect_data(ConnectAsyncData * data)590 free_connect_data (ConnectAsyncData *data)
591 {
592 g_object_unref (data->io_stream);
593
594 g_free (data->hostname);
595 g_free (data->username);
596 g_free (data->password);
597 g_free (data->buffer);
598
599 g_slice_free (ConnectAsyncData, data);
600 }
601
602 static void
do_read(GAsyncReadyCallback callback,GTask * task,ConnectAsyncData * data)603 do_read (GAsyncReadyCallback callback, GTask *task, ConnectAsyncData *data)
604 {
605 GInputStream *in;
606 in = g_io_stream_get_input_stream (data->io_stream);
607 g_input_stream_read_async (in,
608 data->buffer + data->offset,
609 data->length - data->offset,
610 g_task_get_priority (task),
611 g_task_get_cancellable (task),
612 callback, task);
613 }
614
615 static void
do_write(GAsyncReadyCallback callback,GTask * task,ConnectAsyncData * data)616 do_write (GAsyncReadyCallback callback, GTask *task, ConnectAsyncData *data)
617 {
618 GOutputStream *out;
619 out = g_io_stream_get_output_stream (data->io_stream);
620 g_output_stream_write_async (out,
621 data->buffer + data->offset,
622 data->length - data->offset,
623 g_task_get_priority (task),
624 g_task_get_cancellable (task),
625 callback, task);
626 }
627
628 static void
g_socks5_proxy_connect_async(GProxy * proxy,GIOStream * io_stream,GProxyAddress * proxy_address,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)629 g_socks5_proxy_connect_async (GProxy *proxy,
630 GIOStream *io_stream,
631 GProxyAddress *proxy_address,
632 GCancellable *cancellable,
633 GAsyncReadyCallback callback,
634 gpointer user_data)
635 {
636 GTask *task;
637 ConnectAsyncData *data;
638
639 data = g_slice_new0 (ConnectAsyncData);
640 data->io_stream = g_object_ref (io_stream);
641
642 task = g_task_new (proxy, cancellable, callback, user_data);
643 g_task_set_source_tag (task, g_socks5_proxy_connect_async);
644 g_task_set_task_data (task, data, (GDestroyNotify) free_connect_data);
645
646 g_object_get (G_OBJECT (proxy_address),
647 "destination-hostname", &data->hostname,
648 "destination-port", &data->port,
649 "username", &data->username,
650 "password", &data->password,
651 NULL);
652
653 data->buffer = g_malloc0 (SOCKS5_NEGO_MSG_LEN);
654 data->length = set_nego_msg (data->buffer,
655 data->username || data->password);
656 data->offset = 0;
657
658 do_write (nego_msg_write_cb, task, data);
659 }
660
661
662 static void
nego_msg_write_cb(GObject * source,GAsyncResult * res,gpointer user_data)663 nego_msg_write_cb (GObject *source,
664 GAsyncResult *res,
665 gpointer user_data)
666 {
667 GTask *task = user_data;
668 ConnectAsyncData *data = g_task_get_task_data (task);
669 GError *error = NULL;
670 gssize written;
671
672 written = g_output_stream_write_finish (G_OUTPUT_STREAM (source),
673 res, &error);
674
675 if (written < 0)
676 {
677 g_task_return_error (task, error);
678 g_object_unref (task);
679 return;
680 }
681
682 data->offset += written;
683
684 if (data->offset == data->length)
685 {
686 g_free (data->buffer);
687
688 data->buffer = g_malloc0 (SOCKS5_NEGO_REP_LEN);
689 data->length = SOCKS5_NEGO_REP_LEN;
690 data->offset = 0;
691
692 do_read (nego_reply_read_cb, task, data);
693 }
694 else
695 {
696 do_write (nego_msg_write_cb, task, data);
697 }
698 }
699
700 static void
nego_reply_read_cb(GObject * source,GAsyncResult * res,gpointer user_data)701 nego_reply_read_cb (GObject *source,
702 GAsyncResult *res,
703 gpointer user_data)
704 {
705 GTask *task = user_data;
706 ConnectAsyncData *data = g_task_get_task_data (task);
707 GError *error = NULL;
708 gssize read;
709
710 read = g_input_stream_read_finish (G_INPUT_STREAM (source),
711 res, &error);
712
713 if (read < 0)
714 {
715 g_task_return_error (task, error);
716 g_object_unref (task);
717 return;
718 }
719
720 if (read == 0)
721 {
722 g_task_return_new_error (task,
723 G_IO_ERROR,
724 G_IO_ERROR_CONNECTION_CLOSED,
725 "Connection to SOCKSv5 proxy server lost");
726 g_object_unref (task);
727 return;
728 }
729
730 data->offset += read;
731
732 if (data->offset == data->length)
733 {
734 GError *error = NULL;
735 gboolean must_auth = FALSE;
736 gboolean has_auth = data->username || data->password;
737
738 if (!parse_nego_reply (data->buffer, has_auth, &must_auth, &error))
739 {
740 g_task_return_error (task, error);
741 g_object_unref (task);
742 return;
743 }
744
745 if (must_auth)
746 {
747 g_free (data->buffer);
748
749 data->buffer = g_malloc0 (SOCKS5_AUTH_MSG_LEN);
750 data->length = set_auth_msg (data->buffer,
751 data->username,
752 data->password,
753 &error);
754 data->offset = 0;
755
756 if (data->length < 0)
757 {
758 g_task_return_error (task, error);
759 g_object_unref (task);
760 return;
761 }
762
763 do_write (auth_msg_write_cb, task, data);
764 }
765 else
766 {
767 send_connect_msg (task);
768 }
769 }
770 else
771 {
772 do_read (nego_reply_read_cb, task, data);
773 }
774 }
775
776 static void
auth_msg_write_cb(GObject * source,GAsyncResult * result,gpointer user_data)777 auth_msg_write_cb (GObject *source,
778 GAsyncResult *result,
779 gpointer user_data)
780 {
781 GTask *task = user_data;
782 ConnectAsyncData *data = g_task_get_task_data (task);
783 GError *error = NULL;
784 gssize written;
785
786 written = g_output_stream_write_finish (G_OUTPUT_STREAM (source),
787 result, &error);
788
789 if (written < 0)
790 {
791 g_task_return_error (task, error);
792 g_object_unref (task);
793 return;
794 }
795
796 data->offset += written;
797
798 if (data->offset == data->length)
799 {
800 g_free (data->buffer);
801
802 data->buffer = g_malloc0 (SOCKS5_NEGO_REP_LEN);
803 data->length = SOCKS5_NEGO_REP_LEN;
804 data->offset = 0;
805
806 do_read (auth_reply_read_cb, task, data);
807 }
808 else
809 {
810 do_write (auth_msg_write_cb, task, data);
811 }
812 }
813
814 static void
auth_reply_read_cb(GObject * source,GAsyncResult * result,gpointer user_data)815 auth_reply_read_cb (GObject *source,
816 GAsyncResult *result,
817 gpointer user_data)
818 {
819 GTask *task = user_data;
820 ConnectAsyncData *data = g_task_get_task_data (task);
821 GError *error = NULL;
822 gssize read;
823
824 read = g_input_stream_read_finish (G_INPUT_STREAM (source),
825 result, &error);
826
827 if (read < 0)
828 {
829 g_task_return_error (task, error);
830 g_object_unref (task);
831 return;
832 }
833
834 if (read == 0)
835 {
836 g_task_return_new_error (task,
837 G_IO_ERROR,
838 G_IO_ERROR_CONNECTION_CLOSED,
839 "Connection to SOCKSv5 proxy server lost");
840 g_object_unref (task);
841 return;
842 }
843
844 data->offset += read;
845
846 if (data->offset == data->length)
847 {
848 if (!check_auth_status (data->buffer, &error))
849 {
850 g_task_return_error (task, error);
851 g_object_unref (task);
852 return;
853 }
854
855 send_connect_msg (task);
856 }
857 else
858 {
859 do_read (auth_reply_read_cb, task, data);
860 }
861 }
862
863 static void
send_connect_msg(GTask * task)864 send_connect_msg (GTask *task)
865 {
866 ConnectAsyncData *data = g_task_get_task_data (task);
867 GError *error = NULL;
868
869 g_free (data->buffer);
870
871 data->buffer = g_malloc0 (SOCKS5_CONN_MSG_LEN);
872 data->length = set_connect_msg (data->buffer,
873 data->hostname,
874 data->port,
875 &error);
876 data->offset = 0;
877
878 if (data->length < 0)
879 {
880 g_task_return_error (task, error);
881 g_object_unref (task);
882 return;
883 }
884
885 do_write (connect_msg_write_cb, task, data);
886 }
887
888 static void
connect_msg_write_cb(GObject * source,GAsyncResult * result,gpointer user_data)889 connect_msg_write_cb (GObject *source,
890 GAsyncResult *result,
891 gpointer user_data)
892 {
893 GTask *task = user_data;
894 ConnectAsyncData *data = g_task_get_task_data (task);
895 GError *error = NULL;
896 gssize written;
897
898 written = g_output_stream_write_finish (G_OUTPUT_STREAM (source),
899 result, &error);
900
901 if (written < 0)
902 {
903 g_task_return_error (task, error);
904 g_object_unref (task);
905 return;
906 }
907
908 data->offset += written;
909
910 if (data->offset == data->length)
911 {
912 g_free (data->buffer);
913
914 data->buffer = g_malloc0 (SOCKS5_CONN_REP_LEN);
915 data->length = 4;
916 data->offset = 0;
917
918 do_read (connect_reply_read_cb, task, data);
919 }
920 else
921 {
922 do_write (connect_msg_write_cb, task, data);
923 }
924 }
925
926 static void
connect_reply_read_cb(GObject * source,GAsyncResult * result,gpointer user_data)927 connect_reply_read_cb (GObject *source,
928 GAsyncResult *result,
929 gpointer user_data)
930 {
931 GTask *task = user_data;
932 ConnectAsyncData *data = g_task_get_task_data (task);
933 GError *error = NULL;
934 gssize read;
935
936 read = g_input_stream_read_finish (G_INPUT_STREAM (source),
937 result, &error);
938
939 if (read < 0)
940 {
941 g_task_return_error (task, error);
942 g_object_unref (task);
943 return;
944 }
945
946 if (read == 0)
947 {
948 g_task_return_new_error (task,
949 G_IO_ERROR,
950 G_IO_ERROR_CONNECTION_CLOSED,
951 "Connection to SOCKSv5 proxy server lost");
952 g_object_unref (task);
953 return;
954 }
955
956 data->offset += read;
957
958 if (data->offset == data->length)
959 {
960 gint atype;
961
962 if (!parse_connect_reply (data->buffer, &atype, &error))
963 {
964 g_task_return_error (task, error);
965 g_object_unref (task);
966 return;
967 }
968
969 switch (atype)
970 {
971 case SOCKS5_ATYP_IPV4:
972 data->length = 6;
973 data->offset = 0;
974 do_read (connect_addr_read_cb, task, data);
975 break;
976
977 case SOCKS5_ATYP_IPV6:
978 data->length = 18;
979 data->offset = 0;
980 do_read (connect_addr_read_cb, task, data);
981 break;
982
983 case SOCKS5_ATYP_DOMAINNAME:
984 data->length = 1;
985 data->offset = 0;
986 do_read (connect_addr_len_read_cb, task, data);
987 break;
988 }
989 }
990 else
991 {
992 do_read (connect_reply_read_cb, task, data);
993 }
994 }
995
996 static void
connect_addr_len_read_cb(GObject * source,GAsyncResult * result,gpointer user_data)997 connect_addr_len_read_cb (GObject *source,
998 GAsyncResult *result,
999 gpointer user_data)
1000 {
1001 GTask *task = user_data;
1002 ConnectAsyncData *data = g_task_get_task_data (task);
1003 GError *error = NULL;
1004 gssize read;
1005
1006 read = g_input_stream_read_finish (G_INPUT_STREAM (source),
1007 result, &error);
1008
1009 if (read < 0)
1010 {
1011 g_task_return_error (task, error);
1012 g_object_unref (task);
1013 return;
1014 }
1015
1016 if (read == 0)
1017 {
1018 g_task_return_new_error (task,
1019 G_IO_ERROR,
1020 G_IO_ERROR_CONNECTION_CLOSED,
1021 "Connection to SOCKSv5 proxy server lost");
1022 g_object_unref (task);
1023 return;
1024 }
1025
1026 data->length = data->buffer[0] + 2;
1027 data->offset = 0;
1028
1029 do_read (connect_addr_read_cb, task, data);
1030 }
1031
1032 static void
connect_addr_read_cb(GObject * source,GAsyncResult * result,gpointer user_data)1033 connect_addr_read_cb (GObject *source,
1034 GAsyncResult *result,
1035 gpointer user_data)
1036 {
1037 GTask *task = user_data;
1038 ConnectAsyncData *data = g_task_get_task_data (task);
1039 GError *error = NULL;
1040 gssize read;
1041
1042 read = g_input_stream_read_finish (G_INPUT_STREAM (source),
1043 result, &error);
1044
1045 if (read < 0)
1046 {
1047 g_task_return_error (task, error);
1048 g_object_unref (task);
1049 return;
1050 }
1051
1052 if (read == 0)
1053 {
1054 g_task_return_new_error (task,
1055 G_IO_ERROR,
1056 G_IO_ERROR_CONNECTION_CLOSED,
1057 "Connection to SOCKSv5 proxy server lost");
1058 g_object_unref (task);
1059 return;
1060 }
1061
1062 data->offset += read;
1063
1064 if (data->offset == data->length)
1065 {
1066 g_task_return_pointer (task, g_object_ref (data->io_stream), g_object_unref);
1067 g_object_unref (task);
1068 return;
1069 }
1070 else
1071 {
1072 do_read (connect_reply_read_cb, task, data);
1073 }
1074 }
1075
1076 static GIOStream *
g_socks5_proxy_connect_finish(GProxy * proxy,GAsyncResult * result,GError ** error)1077 g_socks5_proxy_connect_finish (GProxy *proxy,
1078 GAsyncResult *result,
1079 GError **error)
1080 {
1081 return g_task_propagate_pointer (G_TASK (result), error);
1082 }
1083
1084 static gboolean
g_socks5_proxy_supports_hostname(GProxy * proxy)1085 g_socks5_proxy_supports_hostname (GProxy *proxy)
1086 {
1087 return TRUE;
1088 }
1089
1090 static void
g_socks5_proxy_class_init(GSocks5ProxyClass * class)1091 g_socks5_proxy_class_init (GSocks5ProxyClass *class)
1092 {
1093 GObjectClass *object_class;
1094
1095 object_class = (GObjectClass *) class;
1096 object_class->finalize = g_socks5_proxy_finalize;
1097 }
1098
1099 static void
g_socks5_proxy_iface_init(GProxyInterface * proxy_iface)1100 g_socks5_proxy_iface_init (GProxyInterface *proxy_iface)
1101 {
1102 proxy_iface->connect = g_socks5_proxy_connect;
1103 proxy_iface->connect_async = g_socks5_proxy_connect_async;
1104 proxy_iface->connect_finish = g_socks5_proxy_connect_finish;
1105 proxy_iface->supports_hostname = g_socks5_proxy_supports_hostname;
1106 }
1107