d15fc2958063a9c115e7f74958eae5a89d6942c3
[platform/upstream/libnice.git] / socket / socks5.c
1 /*
2  * This file is part of the Nice GLib ICE library.
3  *
4  * (C) 2008 Collabora Ltd.
5  *  Contact: Youness Alaoui
6  * (C) 2008 Nokia Corporation. All rights reserved.
7  *
8  * The contents of this file are subject to the Mozilla Public License Version
9  * 1.1 (the "License"); you may not use this file except in compliance with
10  * the License. You may obtain a copy of the License at
11  * http://www.mozilla.org/MPL/
12  *
13  * Software distributed under the License is distributed on an "AS IS" basis,
14  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15  * for the specific language governing rights and limitations under the
16  * License.
17  *
18  * The Original Code is the Nice GLib ICE library.
19  *
20  * The Initial Developers of the Original Code are Collabora Ltd and Nokia
21  * Corporation. All Rights Reserved.
22  *
23  * Contributors:
24  *   Youness Alaoui, Collabora Ltd.
25  *
26  * Alternatively, the contents of this file may be used under the terms of the
27  * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
28  * case the provisions of LGPL are applicable instead of those above. If you
29  * wish to allow use of your version of this file only under the terms of the
30  * LGPL and not to allow others to use your version of this file under the
31  * MPL, indicate your decision by deleting the provisions above and replace
32  * them with the notice and other provisions required by the LGPL. If you do
33  * not delete the provisions above, a recipient may use your version of this
34  * file under either the MPL or the LGPL.
35  */
36
37 /*
38  * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See
39  * http://en.wikipedia.org/wiki/Berkeley_sockets.)
40  */
41 #ifdef HAVE_CONFIG_H
42 # include "config.h"
43 #endif
44
45 #include "socks5.h"
46 #include "agent-priv.h"
47 #include "socket-priv.h"
48
49 #include <string.h>
50
51 #ifndef G_OS_WIN32
52 #include <unistd.h>
53 #endif
54
55 typedef enum {
56   SOCKS_STATE_INIT,
57   SOCKS_STATE_AUTH,
58   SOCKS_STATE_CONNECT,
59   SOCKS_STATE_CONNECTED,
60   SOCKS_STATE_ERROR
61 } SocksState;
62
63 typedef struct {
64   SocksState state;
65   NiceSocket *base_socket;
66   NiceAddress addr;
67   gchar *username;
68   gchar *password;
69   GQueue send_queue;
70 } Socks5Priv;
71
72
73 static void socket_close (NiceSocket *sock);
74 static gint socket_recv_messages (NiceSocket *sock,
75     NiceInputMessage *recv_messages, guint n_recv_messages);
76 static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to,
77     const NiceOutputMessage *messages, guint n_messages);
78 static gint socket_send_messages_reliable (NiceSocket *sock,
79     const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages);
80 static gboolean socket_is_reliable (NiceSocket *sock);
81 static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr);
82 static void socket_set_writable_callback (NiceSocket *sock,
83     NiceSocketWritableCb callback, gpointer user_data);
84 static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other);
85
86
87 NiceSocket *
88 nice_socks5_socket_new (NiceSocket *base_socket,
89     NiceAddress *addr, gchar *username, gchar *password)
90 {
91   Socks5Priv *priv;
92   NiceSocket *sock = NULL;
93
94   if (addr) {
95     sock = g_slice_new0 (NiceSocket);
96     sock->priv = priv = g_slice_new0 (Socks5Priv);
97
98     priv->base_socket = base_socket;
99     priv->addr = *addr;
100     priv->username = g_strdup (username);
101     priv->password = g_strdup (password);
102
103     sock->type = NICE_SOCKET_TYPE_SOCKS5;
104     sock->fileno = priv->base_socket->fileno;
105     sock->addr = priv->base_socket->addr;
106     sock->send_messages = socket_send_messages;
107     sock->send_messages_reliable = socket_send_messages_reliable;
108     sock->recv_messages = socket_recv_messages;
109     sock->is_reliable = socket_is_reliable;
110     sock->can_send = socket_can_send;
111     sock->set_writable_callback = socket_set_writable_callback;
112     sock->is_based_on = socket_is_based_on;
113     sock->close = socket_close;
114
115     /* Send SOCKS5 handshake */
116     {
117       gchar msg[4];
118       gint len = 3;
119
120       msg[0] = 0x05; /* SOCKS version */
121       msg[1] = 0x01; /* number of methods supported */
122       msg[2] = 0x00; /* no authentication method*/
123
124       g_debug ("user/pass : %s - %s", username, password);
125       /* add support for authentication method */
126       if (username || password) {
127         msg[1] = 0x02; /* number of methods supported */
128         msg[3] = 0x02; /* authentication method */
129         len++;
130       }
131
132       /* We send 'to' NULL because it will always be to an already connected
133        * TCP base socket, which ignores the destination */
134       nice_socket_send_reliable (priv->base_socket, NULL, len, msg);
135       priv->state = SOCKS_STATE_INIT;
136     }
137   }
138
139   return sock;
140 }
141
142
143 static void
144 socket_close (NiceSocket *sock)
145 {
146   Socks5Priv *priv = sock->priv;
147
148   if (priv->base_socket)
149     nice_socket_free (priv->base_socket);
150
151   if (priv->username)
152     g_free (priv->username);
153
154   if (priv->password)
155     g_free (priv->password);
156
157   nice_socket_free_send_queue (&priv->send_queue);
158
159   g_slice_free(Socks5Priv, sock->priv);
160   sock->priv = NULL;
161 }
162
163
164 static gint
165 socket_recv_messages (NiceSocket *sock,
166     NiceInputMessage *recv_messages, guint n_recv_messages)
167 {
168   Socks5Priv *priv = sock->priv;
169   guint i;
170   gint ret = -1;
171
172   /* Make sure socket has not been freed: */
173   g_assert (sock->priv != NULL);
174
175   switch (priv->state) {
176     case SOCKS_STATE_CONNECTED:
177       /* Common case: fast pass-through to the base socket once we’re
178        * connected. */
179       if (priv->base_socket) {
180         ret = nice_socket_recv_messages (priv->base_socket,
181             recv_messages, n_recv_messages);
182       }
183
184       if (ret <= 0)
185         return ret;
186
187       /* After successfully receiving into at least one NiceInputMessage,
188        * update the from address in each valid NiceInputMessage. */
189       for (i = 0; i < (guint) ret; i++) {
190         if (recv_messages[i].from != NULL)
191           *recv_messages[i].from = priv->addr;
192       }
193
194       return ret;
195
196     case SOCKS_STATE_INIT:
197       {
198         guint8 data[2];
199         GInputVector local_recv_buf = { data, sizeof (data) };
200         NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
201
202         nice_debug ("Socks5 state Init");
203
204         if (priv->base_socket) {
205           ret = nice_socket_recv_messages (priv->base_socket,
206               &local_recv_message, 1);
207         }
208
209         if (ret <= 0) {
210           return ret;
211         } else if (ret == 1 && local_recv_buf.size == sizeof(data)) {
212           if (data[0] == 0x05) {
213             if (data[1] == 0x02) {
214               gchar msg[515];
215               gint len = 0;
216
217               if (priv->username || priv->password) {
218                 gint ulen = 0;
219                 gint plen = 0;
220
221                 if (priv->username)
222                   ulen = strlen (priv->username);
223                 if (ulen > 255) {
224                   nice_debug ("Socks5 username length > 255");
225                   goto error;
226                 }
227
228                 if (priv->password)
229                   plen  = strlen (priv->password);
230                 if (plen > 255) {
231                   nice_debug ("Socks5 password length > 255");
232                   goto error;
233                 }
234
235                 msg[len++] = 0x01; /* auth version */
236                 msg[len++] = ulen; /* username length */
237                 if (ulen > 0)
238                   memcpy (msg + len, priv->username, ulen); /* Username */
239                 len += ulen;
240                 msg[len++] = plen; /* Password length */
241                 if (plen > 0)
242                   memcpy (msg + len, priv->password, plen); /* Password */
243                 len += plen;
244
245                 nice_socket_send_reliable (priv->base_socket, NULL, len, msg);
246                 priv->state = SOCKS_STATE_AUTH;
247               } else {
248                 /* Authentication required but no auth info available */
249                 goto error;
250               }
251             } else if (data[1] == 0x00) {
252               goto send_connect;
253             } else {
254               /* method not supported by socks server */
255               goto error;
256             }
257           } else {
258             /* invalid SOCKS server version */
259             goto error;
260           }
261         } else {
262           /* read error */
263           goto error;
264         }
265       }
266       break;
267     case SOCKS_STATE_AUTH:
268       {
269         guint8 data[2];
270         GInputVector local_recv_buf = { data, sizeof (data) };
271         NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
272
273         nice_debug ("Socks5 state auth");
274         if (priv->base_socket) {
275           ret = nice_socket_recv_messages (priv->base_socket,
276               &local_recv_message, 1);
277         }
278
279         if (ret <= 0) {
280           return ret;
281         } else if (ret == 1 && local_recv_buf.size == sizeof(data)) {
282           if (data[0] == 0x01 && data[1] == 0x00) {
283             /* Authenticated */
284             goto send_connect;
285           } else {
286             /* Authentication failed */
287             goto error;
288           }
289         }
290       }
291       break;
292     case SOCKS_STATE_CONNECT:
293       {
294         guint8 data[22];
295         GInputVector local_recv_buf = { data, sizeof (data) };
296         NiceInputMessage local_recv_message = { &local_recv_buf, 1, NULL, 0 };
297
298         nice_debug ("Socks5 state connect");
299         if (priv->base_socket) {
300           local_recv_buf.size = 4;
301           ret = nice_socket_recv_messages (priv->base_socket,
302               &local_recv_message, 1);
303         }
304
305         if (ret <= 0) {
306           return ret;
307         } else if (ret == 1 && local_recv_buf.size == 4) {
308           if (data[0] == 0x05) {
309             switch (data[1]) {
310               case 0x00:
311                 if (data[2] == 0x00) {
312                   switch (data[3]) {
313                     case 0x01: /* IPV4 bound address */
314                       local_recv_buf.size = 6;
315                       ret = nice_socket_recv_messages (priv->base_socket,
316                           &local_recv_message, 1);
317                       if (ret != 1 || local_recv_buf.size != 6) {
318                         /* Could not read server bound address */
319                         goto error;
320                       }
321                       break;
322                     case 0x04: /* IPV6 bound address */
323                       local_recv_buf.size = 18;
324                       ret = nice_socket_recv_messages (priv->base_socket,
325                           &local_recv_message, 1);
326                       if (ret != 1 || local_recv_buf.size != 18) {
327                         /* Could not read server bound address */
328                         goto error;
329                       }
330                       break;
331                     default:
332                       /* Unsupported address type */
333                       goto error;
334                   }
335                   nice_socket_flush_send_queue (priv->base_socket,
336                       &priv->send_queue);
337                   priv->state = SOCKS_STATE_CONNECTED;
338                 } else {
339                   /* Wrong reserved value */
340                   goto error;
341                 }
342                 break;
343               case 0x01: /* general SOCKS server failure */
344               case 0x02: /* connection not allowed by ruleset */
345               case 0x03: /* Network unreachable */
346               case 0x04: /* Host unreachable */
347               case 0x05: /* Connection refused */
348               case 0x06: /* TTL expired */
349               case 0x07: /* Command not supported */
350               case 0x08: /* Address type not supported */
351               default: /* Unknown error */
352                 goto error;
353                 break;
354             }
355           } else {
356             /* Wrong server version */
357             goto error;
358           }
359         } else {
360           /* Invalid data received */
361           goto error;
362         }
363       }
364       break;
365     case SOCKS_STATE_ERROR:
366     default:
367       /* Unknown status */
368       goto error;
369   }
370
371   return 0;
372
373  send_connect:
374   {
375     gchar msg[22];
376     gint len = 0;
377     union {
378       struct sockaddr_storage storage;
379       struct sockaddr addr;
380       struct sockaddr_in in;
381       struct sockaddr_in6 in6;
382     } name;
383     nice_address_copy_to_sockaddr(&priv->addr, &name.addr);
384
385     msg[len++] = 0x05; /* SOCKS version */
386     msg[len++] = 0x01; /* connect command */
387     msg[len++] = 0x00; /* reserved */
388     if (name.storage.ss_family == AF_INET) {
389       msg[len++] = 0x01; /* IPV4 address type */
390       /* Address */
391       memcpy (msg + len, &(&name.in)->sin_addr, 4);
392       len += 4;
393       /* Port */
394       memcpy (msg + len, &(&name.in)->sin_port, 2);
395       len += 2;
396     } else if (name.storage.ss_family == AF_INET6) {
397       msg[len++] = 0x04; /* IPV6 address type */
398       /* Address */
399       memcpy (msg + len, &(&name.in6)->sin6_addr, 16);
400       len += 16;
401       /* Port */
402       memcpy (msg + len, &(&name.in6)->sin6_port, 2);
403       len += 2;
404     }
405
406     nice_socket_send_reliable (priv->base_socket, NULL, len, msg);
407     priv->state = SOCKS_STATE_CONNECT;
408
409     return 0;
410   }
411  error:
412   nice_debug ("Socks5 error");
413   if (priv->base_socket)
414     nice_socket_free (priv->base_socket);
415   priv->base_socket = NULL;
416   priv->state = SOCKS_STATE_ERROR;
417
418   return -1;
419 }
420
421 static gint
422 socket_send_messages (NiceSocket *sock, const NiceAddress *to,
423     const NiceOutputMessage *messages, guint n_messages)
424 {
425   Socks5Priv *priv = sock->priv;
426
427   /* Make sure socket has not been freed: */
428   g_assert (sock->priv != NULL);
429
430   if (priv->state == SOCKS_STATE_CONNECTED) {
431     /* Fast path: pass through to the base socket once connected. */
432     if (priv->base_socket == NULL)
433       return -1;
434
435     return nice_socket_send_messages (priv->base_socket, to, messages,
436         n_messages);
437   } else if (priv->state == SOCKS_STATE_ERROR) {
438     return -1;
439   } else {
440     return 0;
441   }
442 }
443
444
445 static gint
446 socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to,
447     const NiceOutputMessage *messages, guint n_messages)
448 {
449   Socks5Priv *priv = sock->priv;
450
451   if (priv->state == SOCKS_STATE_CONNECTED) {
452     /* Fast path: pass through to the base socket once connected. */
453     if (priv->base_socket == NULL)
454       return -1;
455
456     return nice_socket_send_messages_reliable (priv->base_socket, to, messages,
457         n_messages);
458   } else if (priv->state == SOCKS_STATE_ERROR) {
459     return -1;
460   } else {
461     nice_socket_queue_send (&priv->send_queue, to, messages, n_messages);
462   }
463   return n_messages;
464 }
465
466
467 static gboolean
468 socket_is_reliable (NiceSocket *sock)
469 {
470   Socks5Priv *priv = sock->priv;
471
472   return nice_socket_is_reliable (priv->base_socket);
473 }
474
475 static gboolean
476 socket_can_send (NiceSocket *sock, NiceAddress *addr)
477 {
478   Socks5Priv *priv = sock->priv;
479
480   return nice_socket_can_send (priv->base_socket, addr);
481 }
482
483 static void
484 socket_set_writable_callback (NiceSocket *sock,
485     NiceSocketWritableCb callback, gpointer user_data)
486 {
487   Socks5Priv *priv = sock->priv;
488
489   nice_socket_set_writable_callback (priv->base_socket, callback, user_data);
490 }
491
492 static gboolean
493 socket_is_based_on (NiceSocket *sock, NiceSocket *other)
494 {
495   Socks5Priv *priv = sock->priv;
496
497   return (sock == other) ||
498       (priv && nice_socket_is_based_on (priv->base_socket, other));
499 }