Version 0.1.0
[sipe-libnice.git] / socket / socks5.c
blobe325dd100461cdfa6922e1e450319faa28594298
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2008 Collabora Ltd.
5 * Contact: Youness Alaoui
6 * (C) 2008 Nokia Corporation. All rights reserved.
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/
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.
18 * The Original Code is the Nice GLib ICE library.
20 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
21 * Corporation. All Rights Reserved.
23 * Contributors:
24 * Youness Alaoui, Collabora Ltd.
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.
38 * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See
39 * http://en.wikipedia.org/wiki/Berkeley_sockets.)
41 #ifdef HAVE_CONFIG_H
42 # include "config.h"
43 #endif
45 #include "socks5.h"
47 #include <string.h>
49 #ifndef G_OS_WIN32
50 #include <unistd.h>
51 #endif
53 typedef enum {
54 SOCKS_STATE_INIT,
55 SOCKS_STATE_AUTH,
56 SOCKS_STATE_CONNECT,
57 SOCKS_STATE_CONNECTED,
58 SOCKS_STATE_ERROR
59 } SocksState;
61 typedef struct {
62 SocksState state;
63 NiceSocket *base_socket;
64 NiceAddress addr;
65 gchar *username;
66 gchar *password;
67 GQueue send_queue;
68 } Socks5Priv;
71 struct to_be_sent {
72 guint length;
73 gchar *buf;
74 NiceAddress to;
78 static void socket_close (NiceSocket *sock);
79 static gint socket_recv (NiceSocket *sock, NiceAddress *from,
80 guint len, gchar *buf);
81 static gboolean socket_send (NiceSocket *sock, const NiceAddress *to,
82 guint len, const gchar *buf);
83 static gboolean socket_is_reliable (NiceSocket *sock);
85 static void add_to_be_sent (NiceSocket *sock, const NiceAddress *to,
86 const gchar *buf, guint len);
87 static void free_to_be_sent (struct to_be_sent *tbs);
90 NiceSocket *
91 nice_socks5_socket_new (NiceSocket *base_socket,
92 NiceAddress *addr, gchar *username, gchar *password)
94 Socks5Priv *priv;
95 NiceSocket *sock = NULL;
97 if (addr) {
98 sock = g_slice_new0 (NiceSocket);
99 sock->priv = priv = g_slice_new0 (Socks5Priv);
101 priv->base_socket = base_socket;
102 priv->addr = *addr;
103 priv->username = g_strdup (username);
104 priv->password = g_strdup (password);
106 sock->fileno = priv->base_socket->fileno;
107 sock->addr = priv->base_socket->addr;
108 sock->send = socket_send;
109 sock->recv = socket_recv;
110 sock->is_reliable = socket_is_reliable;
111 sock->close = socket_close;
113 /* Send SOCKS5 handshake */
115 gchar msg[4];
116 gint len = 3;
118 msg[0] = 0x05; /* SOCKS version */
119 msg[1] = 0x01; /* number of methods supported */
120 msg[2] = 0x00; /* no authentication method*/
122 g_debug ("user/pass : %s - %s", username, password);
123 /* add support for authentication method */
124 if (username || password) {
125 msg[1] = 0x02; /* number of methods supported */
126 msg[3] = 0x02; /* authentication method */
127 len++;
130 /* We send 'to' NULL because it will always be to an already connected
131 * TCP base socket, which ignores the destination */
132 nice_socket_send (priv->base_socket, NULL, len, msg);
133 priv->state = SOCKS_STATE_INIT;
137 return sock;
141 static void
142 socket_close (NiceSocket *sock)
144 Socks5Priv *priv = sock->priv;
146 if (priv->base_socket)
147 nice_socket_free (priv->base_socket);
149 if (priv->username)
150 g_free (priv->username);
152 if (priv->password)
153 g_free (priv->password);
155 g_queue_foreach (&priv->send_queue, (GFunc) free_to_be_sent, NULL);
156 g_queue_clear (&priv->send_queue);
158 g_slice_free(Socks5Priv, sock->priv);
162 static gint
163 socket_recv (NiceSocket *sock, NiceAddress *from, guint len, gchar *buf)
165 Socks5Priv *priv = sock->priv;
167 switch (priv->state) {
168 case SOCKS_STATE_CONNECTED:
169 if (priv->base_socket)
170 return nice_socket_recv (priv->base_socket, from, len, buf);
171 break;
172 case SOCKS_STATE_INIT:
174 gchar data[2];
175 gint ret = -1;
177 nice_debug ("Socks5 state Init");
179 if (priv->base_socket)
180 ret = nice_socket_recv (priv->base_socket, from, sizeof(data), data);
182 if (ret <= 0) {
183 return ret;
184 } else if(ret == sizeof(data)) {
185 if (data[0] == 0x05) {
186 if (data[1] == 0x02) {
187 gchar msg[515];
188 gint len = 0;
190 if (priv->username || priv->password) {
191 gint ulen = 0;
192 gint plen = 0;
194 if (priv->username)
195 ulen = strlen (priv->username);
196 if (ulen > 255) {
197 nice_debug ("Socks5 username length > 255");
198 goto error;
201 if (priv->password)
202 plen = strlen (priv->password);
203 if (plen > 255) {
204 nice_debug ("Socks5 password length > 255");
205 goto error;
208 msg[len++] = 0x01; /* auth version */
209 msg[len++] = ulen; /* username length */
210 if (ulen > 0)
211 memcpy (msg + len, priv->username, ulen); /* Username */
212 len += ulen;
213 msg[len++] = plen; /* Password length */
214 if (plen > 0)
215 memcpy (msg + len, priv->password, plen); /* Password */
216 len += plen;
218 nice_socket_send (priv->base_socket, NULL, len, msg);
219 priv->state = SOCKS_STATE_AUTH;
220 } else {
221 /* Authentication required but no auth info available */
222 goto error;
224 } else if (data[1] == 0x00) {
225 goto send_connect;
226 } else {
227 /* method not supported by socks server */
228 goto error;
230 } else {
231 /* invalid SOCKS server version */
232 goto error;
234 } else {
235 /* read error */
236 goto error;
239 break;
240 case SOCKS_STATE_AUTH:
242 gchar data[2];
243 gint ret = -1;
245 nice_debug ("Socks5 state auth");
246 if (priv->base_socket)
247 ret = nice_socket_recv (priv->base_socket, from, sizeof(data), data);
249 if (ret <= 0) {
250 return ret;
251 } else if(ret == sizeof(data)) {
252 if (data[0] == 0x01 && data[1] == 0x00) {
253 /* Authenticated */
254 goto send_connect;
255 } else {
256 /* Authentication failed */
257 goto error;
261 break;
262 case SOCKS_STATE_CONNECT:
264 gchar data[22];
265 gint ret = -1;
267 nice_debug ("Socks5 state connect");
268 if (priv->base_socket)
269 ret = nice_socket_recv (priv->base_socket, from, 4, data);
271 if (ret <= 0) {
272 return ret;
273 } else if(ret == 4) {
274 if (data[0] == 0x05) {
275 switch (data[1]) {
276 case 0x00:
277 if (data[2] == 0x00) {
278 struct to_be_sent *tbs = NULL;
279 switch (data[3]) {
280 case 0x01: /* IPV4 bound address */
281 ret = nice_socket_recv (priv->base_socket, from, 6, data);
282 if (ret != 6) {
283 /* Could not read server bound address */
284 goto error;
286 break;
287 case 0x04: /* IPV6 bound address */
288 ret = nice_socket_recv (priv->base_socket, from, 18, data);
289 if (ret != 18) {
290 /* Could not read server bound address */
291 goto error;
293 break;
294 default:
295 /* Unsupported address type */
296 goto error;
298 while ((tbs = g_queue_pop_head (&priv->send_queue))) {
299 nice_socket_send (priv->base_socket, &tbs->to,
300 tbs->length, tbs->buf);
301 g_free (tbs->buf);
302 g_slice_free (struct to_be_sent, tbs);
304 priv->state = SOCKS_STATE_CONNECTED;
305 } else {
306 /* Wrong reserved value */
307 goto error;
309 break;
310 case 0x01: /* general SOCKS server failure */
311 case 0x02: /* connection not allowed by ruleset */
312 case 0x03: /* Network unreachable */
313 case 0x04: /* Host unreachable */
314 case 0x05: /* Connection refused */
315 case 0x06: /* TTL expired */
316 case 0x07: /* Command not supported */
317 case 0x08: /* Address type not supported */
318 default: /* Unknown error */
319 goto error;
320 break;
322 } else {
323 /* Wrong server version */
324 goto error;
326 } else {
327 /* Invalid data received */
328 goto error;
331 break;
332 default:
333 /* Unknown status */
334 goto error;
337 return 0;
339 send_connect:
341 gchar msg[22];
342 gint len = 0;
343 struct sockaddr_storage name;
344 nice_address_copy_to_sockaddr(&priv->addr, (struct sockaddr *)&name);
346 msg[len++] = 0x05; /* SOCKS version */
347 msg[len++] = 0x01; /* connect command */
348 msg[len++] = 0x00; /* reserved */
349 if (name.ss_family == AF_INET) {
350 msg[len++] = 0x01; /* IPV4 address type */
351 /* Address */
352 memcpy (msg + len, &((struct sockaddr_in *) &name)->sin_addr, 4);
353 len += 4;
354 /* Port */
355 memcpy (msg + len, &((struct sockaddr_in *) &name)->sin_port, 2);
356 len += 2;
357 } else if (name.ss_family == AF_INET6) {
358 msg[len++] = 0x04; /* IPV6 address type */
359 /* Address */
360 memcpy (msg + len, &((struct sockaddr_in6 *) &name)->sin6_addr, 16);
361 len += 16;
362 /* Port */
363 memcpy (msg + len, &((struct sockaddr_in6 *) &name)->sin6_port, 2);
364 len += 2;
367 nice_socket_send (priv->base_socket, NULL, len, msg);
368 priv->state = SOCKS_STATE_CONNECT;
370 return 0;
372 error:
373 nice_debug ("Socks5 error");
374 if (priv->base_socket)
375 nice_socket_free (priv->base_socket);
376 priv->base_socket = NULL;
377 priv->state = SOCKS_STATE_ERROR;
379 return -1;
382 static gboolean
383 socket_send (NiceSocket *sock, const NiceAddress *to,
384 guint len, const gchar *buf)
386 Socks5Priv *priv = sock->priv;
388 if (priv->state == SOCKS_STATE_CONNECTED) {
389 if (priv->base_socket)
390 return nice_socket_send (priv->base_socket, to, len, buf);
391 else
392 return FALSE;
393 } else if (priv->state == SOCKS_STATE_ERROR) {
394 return FALSE;
395 } else {
396 add_to_be_sent (sock, to, buf, len);
398 return TRUE;
402 static gboolean
403 socket_is_reliable (NiceSocket *sock)
405 return TRUE;
409 static void
410 add_to_be_sent (NiceSocket *sock, const NiceAddress *to,
411 const gchar *buf, guint len)
413 Socks5Priv *priv = sock->priv;
414 struct to_be_sent *tbs = NULL;
416 if (len <= 0)
417 return;
419 tbs = g_slice_new0 (struct to_be_sent);
420 tbs->buf = g_memdup (buf, len);
421 tbs->length = len;
422 if (to)
423 tbs->to = *to;
424 g_queue_push_tail (&priv->send_queue, tbs);
429 static void
430 free_to_be_sent (struct to_be_sent *tbs)
432 g_free (tbs->buf);
433 g_slice_free (struct to_be_sent, tbs);