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
);
198 plen
= strlen (priv
->password
);
200 msg
[len
++] = 0x01; /* auth version */
201 msg
[len
++] = ulen
; /* username length */
202 memcpy (msg
+ len
, priv
->username
, ulen
); /* Username */
204 msg
[len
++] = plen
; /* Password length */
205 memcpy (msg
+ len
, priv
->password
, plen
); /* Password */
208 nice_socket_send (priv
->base_socket
, NULL
, len
, msg
);
209 priv
->state
= SOCKS_STATE_AUTH
;
211 /* Authentication required but no auth info available */
214 } else if (data
[1] == 0x00) {
217 /* method not supported by socks server */
221 /* invalid SOCKS server version */
230 case SOCKS_STATE_AUTH
:
235 nice_debug ("Socks5 state auth");
236 if (priv
->base_socket
)
237 ret
= nice_socket_recv (priv
->base_socket
, from
, sizeof(data
), data
);
241 } else if(ret
== sizeof(data
)) {
242 if (data
[0] == 0x01 && data
[1] == 0x00) {
246 /* Authentication failed */
252 case SOCKS_STATE_CONNECT
:
257 nice_debug ("Socks5 state connect");
258 if (priv
->base_socket
)
259 ret
= nice_socket_recv (priv
->base_socket
, from
, 4, data
);
263 } else if(ret
== 4) {
264 if (data
[0] == 0x05) {
267 if (data
[2] == 0x00) {
268 struct to_be_sent
*tbs
= NULL
;
270 case 0x01: /* IPV4 bound address */
271 ret
= nice_socket_recv (priv
->base_socket
, from
, 6, data
);
273 /* Could not read server bound address */
277 case 0x04: /* IPV6 bound address */
278 ret
= nice_socket_recv (priv
->base_socket
, from
, 18, data
);
280 /* Could not read server bound address */
285 /* Unsupported address type */
288 while ((tbs
= g_queue_pop_head (&priv
->send_queue
))) {
289 nice_socket_send (priv
->base_socket
, &tbs
->to
,
290 tbs
->length
, tbs
->buf
);
292 g_slice_free (struct to_be_sent
, tbs
);
294 priv
->state
= SOCKS_STATE_CONNECTED
;
296 /* Wrong reserved value */
300 case 0x01: /* general SOCKS server failure */
301 case 0x02: /* connection not allowed by ruleset */
302 case 0x03: /* Network unreachable */
303 case 0x04: /* Host unreachable */
304 case 0x05: /* Connection refused */
305 case 0x06: /* TTL expired */
306 case 0x07: /* Command not supported */
307 case 0x08: /* Address type not supported */
308 default: /* Unknown error */
313 /* Wrong server version */
317 /* Invalid data received */
333 struct sockaddr_storage name
;
334 nice_address_copy_to_sockaddr(&priv
->addr
, (struct sockaddr
*)&name
);
336 msg
[len
++] = 0x05; /* SOCKS version */
337 msg
[len
++] = 0x01; /* connect command */
338 msg
[len
++] = 0x00; /* reserved */
339 if (name
.ss_family
== AF_INET
) {
340 msg
[len
++] = 0x01; /* IPV4 address type */
342 memcpy (msg
+ len
, &((struct sockaddr_in
*) &name
)->sin_addr
, 4);
345 memcpy (msg
+ len
, &((struct sockaddr_in
*) &name
)->sin_port
, 2);
347 } else if (name
.ss_family
== AF_INET6
) {
348 msg
[len
++] = 0x04; /* IPV6 address type */
350 memcpy (msg
+ len
, &((struct sockaddr_in6
*) &name
)->sin6_addr
, 16);
353 memcpy (msg
+ len
, &((struct sockaddr_in6
*) &name
)->sin6_port
, 2);
357 nice_socket_send (priv
->base_socket
, NULL
, len
, msg
);
358 priv
->state
= SOCKS_STATE_CONNECT
;
363 nice_debug ("Socks5 error");
364 if (priv
->base_socket
)
365 nice_socket_free (priv
->base_socket
);
366 priv
->base_socket
= NULL
;
367 priv
->state
= SOCKS_STATE_ERROR
;
373 socket_send (NiceSocket
*sock
, const NiceAddress
*to
,
374 guint len
, const gchar
*buf
)
376 Socks5Priv
*priv
= sock
->priv
;
378 if (priv
->state
== SOCKS_STATE_CONNECTED
) {
379 if (priv
->base_socket
)
380 return nice_socket_send (priv
->base_socket
, to
, len
, buf
);
383 } else if (priv
->state
== SOCKS_STATE_ERROR
) {
386 add_to_be_sent (sock
, to
, buf
, len
);
393 socket_is_reliable (NiceSocket
*sock
)
400 add_to_be_sent (NiceSocket
*sock
, const NiceAddress
*to
,
401 const gchar
*buf
, guint len
)
403 Socks5Priv
*priv
= sock
->priv
;
404 struct to_be_sent
*tbs
= NULL
;
409 tbs
= g_slice_new0 (struct to_be_sent
);
410 tbs
->buf
= g_memdup (buf
, len
);
414 g_queue_push_tail (&priv
->send_queue
, tbs
);
420 free_to_be_sent (struct to_be_sent
*tbs
)
423 g_slice_free (struct to_be_sent
, tbs
);