Imported Upstream version 2.66.6
[platform/upstream/glib.git] / gio / gsocks5proxy.c
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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   data->offset += read;
721   
722   if (data->offset == data->length)
723     {
724       GError *error = NULL;
725       gboolean must_auth = FALSE;
726       gboolean has_auth = data->username || data->password;
727
728       if (!parse_nego_reply (data->buffer, has_auth, &must_auth, &error))
729         {
730           g_task_return_error (task, error);
731           g_object_unref (task);
732           return;
733         }
734
735       if (must_auth)
736         {
737           g_free (data->buffer);
738
739           data->buffer = g_malloc0 (SOCKS5_AUTH_MSG_LEN);
740           data->length = set_auth_msg (data->buffer,
741                                        data->username,
742                                        data->password,
743                                        &error);
744           data->offset = 0;
745
746           if (data->length < 0)
747             {
748               g_task_return_error (task, error);
749               g_object_unref (task);
750               return;
751             }
752           
753           do_write (auth_msg_write_cb, task, data);
754         }
755       else
756         {
757           send_connect_msg (task);
758         }
759     }
760   else
761     {
762       do_read (nego_reply_read_cb, task, data);
763     }
764 }
765
766 static void
767 auth_msg_write_cb (GObject      *source,
768                    GAsyncResult *result,
769                    gpointer      user_data)
770 {
771   GTask *task = user_data;
772   ConnectAsyncData *data = g_task_get_task_data (task);
773   GError *error = NULL;
774   gssize written;
775
776   written = g_output_stream_write_finish (G_OUTPUT_STREAM (source),
777                                           result, &error);
778   
779   if (written < 0)
780     {
781       g_task_return_error (task, error);
782       g_object_unref (task);
783       return;
784     }
785
786   data->offset += written;
787
788   if (data->offset == data->length)
789     {
790       g_free (data->buffer);
791
792       data->buffer = g_malloc0 (SOCKS5_NEGO_REP_LEN);
793       data->length = SOCKS5_NEGO_REP_LEN;
794       data->offset = 0;
795
796       do_read (auth_reply_read_cb, task, data);
797     }
798   else
799     {
800       do_write (auth_msg_write_cb, task, data);
801     }
802 }
803
804 static void
805 auth_reply_read_cb (GObject      *source,
806                     GAsyncResult *result,
807                     gpointer      user_data)
808 {
809   GTask *task = user_data;
810   ConnectAsyncData *data = g_task_get_task_data (task);
811   GError *error = NULL;
812   gssize read;
813
814   read = g_input_stream_read_finish (G_INPUT_STREAM (source),
815                                      result, &error);
816
817   if (read < 0)
818     {
819       g_task_return_error (task, error);
820       g_object_unref (task);
821       return;
822     }
823
824   data->offset += read;
825
826   if (data->offset == data->length)
827     {
828       if (!check_auth_status (data->buffer, &error))
829         {
830           g_task_return_error (task, error);
831           g_object_unref (task);
832           return;
833         }
834         
835       send_connect_msg (task);
836     }
837   else
838     {
839       do_read (auth_reply_read_cb, task, data);
840     }
841 }
842
843 static void
844 send_connect_msg (GTask *task)
845 {
846   ConnectAsyncData *data = g_task_get_task_data (task);
847   GError *error = NULL;
848
849   g_free (data->buffer);
850
851   data->buffer = g_malloc0 (SOCKS5_CONN_MSG_LEN);
852   data->length = set_connect_msg (data->buffer,
853                                   data->hostname,
854                                   data->port,
855                                   &error);
856   data->offset = 0;
857   
858   if (data->length < 0)
859     {
860       g_task_return_error (task, error);
861       g_object_unref (task);
862       return;
863     }
864
865   do_write (connect_msg_write_cb, task, data);
866 }
867
868 static void
869 connect_msg_write_cb (GObject      *source,
870                       GAsyncResult *result,
871                       gpointer      user_data)
872 {
873   GTask *task = user_data;
874   ConnectAsyncData *data = g_task_get_task_data (task);
875   GError *error = NULL;
876   gssize written;
877
878   written = g_output_stream_write_finish (G_OUTPUT_STREAM (source),
879                                           result, &error);
880   
881   if (written < 0)
882     {
883       g_task_return_error (task, error);
884       g_object_unref (task);
885       return;
886     }
887
888   data->offset += written;
889
890   if (data->offset == data->length)
891     {
892       g_free (data->buffer);
893
894       data->buffer = g_malloc0 (SOCKS5_CONN_REP_LEN);
895       data->length = 4;
896       data->offset = 0;
897
898       do_read (connect_reply_read_cb, task, data);
899     }
900   else
901     {
902       do_write (connect_msg_write_cb, task, data);
903     }
904 }
905
906 static void
907 connect_reply_read_cb (GObject       *source,
908                        GAsyncResult  *result,
909                        gpointer       user_data)
910 {
911   GTask *task = user_data;
912   ConnectAsyncData *data = g_task_get_task_data (task);
913   GError *error = NULL;
914   gssize read;
915
916   read = g_input_stream_read_finish (G_INPUT_STREAM (source),
917                                      result, &error);
918
919   if (read < 0)
920     {
921       g_task_return_error (task, error);
922       g_object_unref (task);
923       return;
924     }
925
926   data->offset += read;
927
928   if (data->offset == data->length)
929     {
930       gint atype;
931
932       if (!parse_connect_reply (data->buffer, &atype, &error))
933         {
934           g_task_return_error (task, error);
935           g_object_unref (task);
936           return;
937         }
938
939       switch (atype)
940         {
941           case SOCKS5_ATYP_IPV4:
942             data->length = 6;
943             data->offset = 0;
944             do_read (connect_addr_read_cb, task, data);
945             break;
946
947           case SOCKS5_ATYP_IPV6:
948             data->length = 18;
949             data->offset = 0;
950             do_read (connect_addr_read_cb, task, data);
951             break;
952
953           case SOCKS5_ATYP_DOMAINNAME:
954             data->length = 1;
955             data->offset = 0;
956             do_read (connect_addr_len_read_cb, task, data);
957             break;
958         }
959     }
960   else
961     {
962       do_read (connect_reply_read_cb, task, data);
963     }
964 }
965
966 static void
967 connect_addr_len_read_cb (GObject      *source,
968                           GAsyncResult *result,
969                           gpointer      user_data)
970 {
971   GTask *task = user_data;
972   ConnectAsyncData *data = g_task_get_task_data (task);
973   GError *error = NULL;
974   gssize read;
975
976   read = g_input_stream_read_finish (G_INPUT_STREAM (source),
977                                      result, &error);
978
979   if (read < 0)
980     {
981       g_task_return_error (task, error);
982       g_object_unref (task);
983       return;
984     }
985
986   data->length = data->buffer[0] + 2;
987   data->offset = 0;
988
989   do_read (connect_addr_read_cb, task, data);
990 }
991
992 static void
993 connect_addr_read_cb (GObject      *source,
994                       GAsyncResult *result,
995                       gpointer      user_data)
996 {
997   GTask *task = user_data;
998   ConnectAsyncData *data = g_task_get_task_data (task);
999   GError *error = NULL;
1000   gssize read;
1001
1002   read = g_input_stream_read_finish (G_INPUT_STREAM (source),
1003                                      result, &error);
1004
1005   if (read < 0)
1006     {
1007       g_task_return_error (task, error);
1008       g_object_unref (task);
1009       return;
1010     }
1011
1012   data->offset += read;
1013
1014   if (data->offset == data->length)
1015     {
1016       g_task_return_pointer (task, g_object_ref (data->io_stream), g_object_unref);
1017       g_object_unref (task);
1018       return;
1019     }
1020   else
1021     {
1022       do_read (connect_reply_read_cb, task, data);
1023     }
1024 }
1025
1026 static GIOStream *
1027 g_socks5_proxy_connect_finish (GProxy       *proxy,
1028                                GAsyncResult *result,
1029                                GError      **error)
1030 {
1031   return g_task_propagate_pointer (G_TASK (result), error);
1032 }
1033
1034 static gboolean
1035 g_socks5_proxy_supports_hostname (GProxy *proxy)
1036 {
1037   return TRUE;
1038 }
1039
1040 static void
1041 g_socks5_proxy_class_init (GSocks5ProxyClass *class)
1042 {
1043   GObjectClass *object_class;
1044
1045   object_class = (GObjectClass *) class;
1046   object_class->finalize = g_socks5_proxy_finalize;
1047 }
1048
1049 static void
1050 g_socks5_proxy_iface_init (GProxyInterface *proxy_iface)
1051 {
1052   proxy_iface->connect  = g_socks5_proxy_connect;
1053   proxy_iface->connect_async = g_socks5_proxy_connect_async;
1054   proxy_iface->connect_finish = g_socks5_proxy_connect_finish;
1055   proxy_iface->supports_hostname = g_socks5_proxy_supports_hostname;
1056 }