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
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.
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.)
57 SOCKS_STATE_CONNECTED
,
63 NiceSocket
*base_socket
;
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
);
91 nice_socks5_socket_new (NiceSocket
*base_socket
,
92 NiceAddress
*addr
, gchar
*username
, gchar
*password
)
95 NiceSocket
*sock
= NULL
;
98 sock
= g_slice_new0 (NiceSocket
);
99 sock
->priv
= priv
= g_slice_new0 (Socks5Priv
);
101 priv
->base_socket
= base_socket
;
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 */
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 */
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
;
142 socket_close (NiceSocket
*sock
)
144 Socks5Priv
*priv
= sock
->priv
;
146 if (priv
->base_socket
)
147 nice_socket_free (priv
->base_socket
);
150 g_free (priv
->username
);
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
);
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
);
172 case SOCKS_STATE_INIT
:
177 nice_debug ("Socks5 state Init");
179 if (priv
->base_socket
)
180 ret
= nice_socket_recv (priv
->base_socket
, from
, sizeof(data
), data
);
184 } else if(ret
== sizeof(data
)) {
185 if (data
[0] == 0x05) {
186 if (data
[1] == 0x02) {
190 if (priv
->username
|| priv
->password
) {
195 ulen
= strlen (priv
->username
);
197 nice_debug ("Socks5 username length > 255");
202 plen
= strlen (priv
->password
);
204 nice_debug ("Socks5 password length > 255");
208 msg
[len
++] = 0x01; /* auth version */
209 msg
[len
++] = ulen
; /* username length */
211 memcpy (msg
+ len
, priv
->username
, ulen
); /* Username */
213 msg
[len
++] = plen
; /* Password length */
215 memcpy (msg
+ len
, priv
->password
, plen
); /* Password */
218 nice_socket_send (priv
->base_socket
, NULL
, len
, msg
);
219 priv
->state
= SOCKS_STATE_AUTH
;
221 /* Authentication required but no auth info available */
224 } else if (data
[1] == 0x00) {
227 /* method not supported by socks server */
231 /* invalid SOCKS server version */
240 case SOCKS_STATE_AUTH
:
245 nice_debug ("Socks5 state auth");
246 if (priv
->base_socket
)
247 ret
= nice_socket_recv (priv
->base_socket
, from
, sizeof(data
), data
);
251 } else if(ret
== sizeof(data
)) {
252 if (data
[0] == 0x01 && data
[1] == 0x00) {
256 /* Authentication failed */
262 case SOCKS_STATE_CONNECT
:
267 nice_debug ("Socks5 state connect");
268 if (priv
->base_socket
)
269 ret
= nice_socket_recv (priv
->base_socket
, from
, 4, data
);
273 } else if(ret
== 4) {
274 if (data
[0] == 0x05) {
277 if (data
[2] == 0x00) {
278 struct to_be_sent
*tbs
= NULL
;
280 case 0x01: /* IPV4 bound address */
281 ret
= nice_socket_recv (priv
->base_socket
, from
, 6, data
);
283 /* Could not read server bound address */
287 case 0x04: /* IPV6 bound address */
288 ret
= nice_socket_recv (priv
->base_socket
, from
, 18, data
);
290 /* Could not read server bound address */
295 /* Unsupported address type */
298 while ((tbs
= g_queue_pop_head (&priv
->send_queue
))) {
299 nice_socket_send (priv
->base_socket
, &tbs
->to
,
300 tbs
->length
, tbs
->buf
);
302 g_slice_free (struct to_be_sent
, tbs
);
304 priv
->state
= SOCKS_STATE_CONNECTED
;
306 /* Wrong reserved value */
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 */
323 /* Wrong server version */
327 /* Invalid data received */
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 */
352 memcpy (msg
+ len
, &((struct sockaddr_in
*) &name
)->sin_addr
, 4);
355 memcpy (msg
+ len
, &((struct sockaddr_in
*) &name
)->sin_port
, 2);
357 } else if (name
.ss_family
== AF_INET6
) {
358 msg
[len
++] = 0x04; /* IPV6 address type */
360 memcpy (msg
+ len
, &((struct sockaddr_in6
*) &name
)->sin6_addr
, 16);
363 memcpy (msg
+ len
, &((struct sockaddr_in6
*) &name
)->sin6_port
, 2);
367 nice_socket_send (priv
->base_socket
, NULL
, len
, msg
);
368 priv
->state
= SOCKS_STATE_CONNECT
;
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
;
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
);
393 } else if (priv
->state
== SOCKS_STATE_ERROR
) {
396 add_to_be_sent (sock
, to
, buf
, len
);
403 socket_is_reliable (NiceSocket
*sock
)
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
;
419 tbs
= g_slice_new0 (struct to_be_sent
);
420 tbs
->buf
= g_memdup (buf
, len
);
424 g_queue_push_tail (&priv
->send_queue
, tbs
);
430 free_to_be_sent (struct to_be_sent
*tbs
)
433 g_slice_free (struct to_be_sent
, tbs
);