1 /* GNet - Networking library
2 * Copyright (C) 2001-2002 Marius Eriksen, David Helder
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 #include "gnet-private.h"
21 #include "socks.h"
22 #include "socks-private.h"
23
24
25
26 /* **************************************** */
27
28
29 static int socks_negotiate_connect (GTcpSocket *s, const GInetAddr *dst);
30 static int socks4_negotiate_connect (GIOChannel *ioc, const GInetAddr *dst);
31 static int socks5_negotiate_connect (GIOChannel *ioc, const GInetAddr *dst);
32
33
34 GTcpSocket*
_gnet_socks_tcp_socket_new(const GInetAddr * addr)35 _gnet_socks_tcp_socket_new (const GInetAddr* addr)
36 {
37 GInetAddr* ss_addr = NULL;
38 GTcpSocket* s;
39 int rv;
40
41 g_return_val_if_fail (addr != NULL, NULL);
42
43 /* Get SOCKS server */
44 ss_addr = gnet_socks_get_server();
45 if (!ss_addr)
46 return NULL;
47
48 /* Connect to SOCKS server */
49 s = gnet_tcp_socket_new_direct (ss_addr);
50 gnet_inetaddr_delete (ss_addr);
51 if (!s)
52 return NULL;
53
54 /* Negotiate connection */
55 rv = socks_negotiate_connect (s, addr);
56 if (rv < 0)
57 {
58 gnet_tcp_socket_delete (s);
59 return NULL;
60 }
61
62 return s;
63 }
64
65
66
67 /* **************************************** */
68
69 typedef struct
70 {
71 GInetAddr* addr;
72 GTcpSocketNewAsyncFunc func;
73 gpointer data;
74 GDestroyNotify notify;
75 } SocksAsyncData;
76
77 static void
socks_async_cb(GTcpSocket * socket,gpointer data)78 socks_async_cb (GTcpSocket* socket, gpointer data)
79 {
80 SocksAsyncData *ad = (SocksAsyncData *) data;
81
82 if (socket != NULL) {
83 int rv;
84
85 rv = socks_negotiate_connect (socket, ad->addr);
86 if (rv < 0)
87 goto error;
88
89 (ad->func) (socket, ad->data);
90
91 gnet_inetaddr_delete (ad->addr);
92 if (ad->notify)
93 ad->notify (ad->data);
94 g_free (ad);
95 return;
96 }
97
98 error:
99 {
100 (ad->func) (NULL, ad->data);
101
102 gnet_tcp_socket_delete (socket);
103 gnet_inetaddr_delete (ad->addr);
104 if (ad->notify)
105 ad->notify (ad->data);
106 g_free (ad);
107 }
108 }
109
110 GTcpSocketNewAsyncID
_gnet_socks_tcp_socket_new_async_full(const GInetAddr * addr,GTcpSocketNewAsyncFunc func,gpointer data,GDestroyNotify notify,GMainContext * context,gint priority)111 _gnet_socks_tcp_socket_new_async_full (const GInetAddr * addr,
112 GTcpSocketNewAsyncFunc func, gpointer data, GDestroyNotify notify,
113 GMainContext * context, gint priority)
114 {
115 GTcpSocketNewAsyncID async_id;
116 SocksAsyncData *ad;
117 GInetAddr *ss_addr = NULL;
118
119 g_return_val_if_fail (addr != NULL, NULL);
120 g_return_val_if_fail (func != NULL, NULL);
121
122 /* Get SOCKS server */
123 ss_addr = gnet_socks_get_server();
124 if (!ss_addr)
125 return NULL;
126
127 /* Create data */
128 ad = g_new0 (SocksAsyncData, 1);
129 ad->addr = gnet_inetaddr_clone (addr);
130 ad->func = func;
131 ad->data = data;
132 ad->notify = notify;
133
134 /* Connect to SOCKS server */
135 async_id = gnet_tcp_socket_new_async_direct_full (ss_addr, socks_async_cb,
136 ad, (GDestroyNotify) NULL, context, priority);
137
138 gnet_inetaddr_delete (ss_addr);
139
140 return async_id; /* async_id might be NULL */
141 }
142
143 GTcpSocketNewAsyncID
_gnet_socks_tcp_socket_new_async(const GInetAddr * addr,GTcpSocketNewAsyncFunc func,gpointer data)144 _gnet_socks_tcp_socket_new_async (const GInetAddr * addr,
145 GTcpSocketNewAsyncFunc func, gpointer data)
146 {
147 GTcpSocketNewAsyncID async_id;
148
149 g_return_val_if_fail (addr != NULL, NULL);
150 g_return_val_if_fail (func != NULL, NULL);
151
152 async_id = _gnet_socks_tcp_socket_new_async_full (addr, func, data,
153 (GDestroyNotify) NULL, NULL, G_PRIORITY_DEFAULT);
154
155 return async_id;
156 }
157
158 /* **************************************** */
159
160 static int
socks_negotiate_connect(GTcpSocket * s,const GInetAddr * dst)161 socks_negotiate_connect (GTcpSocket *s, const GInetAddr *dst)
162 {
163 GIOChannel *ioc;
164 int ver, ret;
165
166 ioc = gnet_tcp_socket_get_io_channel(s);
167 ver = gnet_socks_get_version();
168 if (ver == 5)
169 ret = socks5_negotiate_connect (ioc, dst);
170 else if (ver == 4)
171 ret = socks4_negotiate_connect (ioc, dst);
172 else
173 ret = -1;
174
175 return ret;
176 }
177
178
179 static int
socks4_negotiate_connect(GIOChannel * ioc,const GInetAddr * dst)180 socks4_negotiate_connect (GIOChannel *ioc, const GInetAddr *dst)
181 {
182 struct socks4_h s4h;
183 struct sockaddr_in *sa_in;
184 gsize len;
185
186 sa_in = (struct sockaddr_in*)&dst->sa;
187
188 s4h.vn = 4;
189 s4h.cd = 1;
190 s4h.dport = (short)sa_in->sin_port;
191 s4h.dip = (long)sa_in->sin_addr.s_addr;
192 s4h.userid = 0;
193
194 if (gnet_io_channel_writen(ioc, &s4h, 9, &len) != G_IO_ERROR_NONE)
195 return -1;
196 if (gnet_io_channel_readn(ioc, &s4h, 8, &len) != G_IO_ERROR_NONE)
197 return -1;
198
199 if ((s4h.cd != 90) || (s4h.vn != 0))
200 return -1;
201
202 return 0;
203 }
204
205
206 static int
socks5_negotiate_connect(GIOChannel * ioc,const GInetAddr * dst)207 socks5_negotiate_connect (GIOChannel *ioc, const GInetAddr *dst)
208 {
209 unsigned char s5r[3];
210 struct socks5_h s5h;
211 struct sockaddr_in *sa_in;
212 gsize len;
213
214 s5r[0] = 5;
215 s5r[1] = 1; /* XXX no authentication yet */
216 s5r[2] = 0;
217
218 if (gnet_io_channel_writen(ioc, s5r, 3, &len) != G_IO_ERROR_NONE)
219 return -1;
220 if (gnet_io_channel_readn(ioc, s5r, 2, &len) != G_IO_ERROR_NONE)
221 return -1;
222 if ((s5r[0] != 5) || (s5r[1] != 0))
223 return -1;
224
225 sa_in = (struct sockaddr_in*)&dst->sa;
226
227 /* fill in SOCKS5 request */
228 s5h.vn = 5;
229 s5h.cd = 1;
230 s5h.rsv = 0;
231 s5h.atyp = 1;
232 s5h.dip = (long)sa_in->sin_addr.s_addr;
233 s5h.dport = (short)sa_in->sin_port;
234
235 if (gnet_io_channel_writen(ioc, (gchar*)&s5h, 10, &len) != G_IO_ERROR_NONE)
236 return -1;
237 if (gnet_io_channel_readn(ioc, (gchar*)&s5h, 10, &len) != G_IO_ERROR_NONE)
238 return -1;
239 if (s5h.cd != 0)
240 return -1;
241
242 return 0;
243 }
244
245
246 /* **************************************** */
247
248 static int socks5_negotiate_bind (GTcpSocket* socket, int port);
249
250 static gboolean socks_tcp_socket_server_accept_async_cb (GIOChannel* iochannel,
251 GIOCondition condition,
252 gpointer data);
253
254
255 GTcpSocket*
_gnet_socks_tcp_socket_server_new(gint port)256 _gnet_socks_tcp_socket_server_new (gint port)
257 {
258 GInetAddr* ss_addr = NULL;
259 GTcpSocket* s;
260 int rv;
261
262 /* We only support SOCKS 5 */
263 if (gnet_socks_get_version () != 5)
264 return NULL;
265
266 /* Get SOCKS server */
267 ss_addr = gnet_socks_get_server();
268 if (!ss_addr)
269 return NULL;
270
271 /* Connect to SOCKS server */
272 s = gnet_tcp_socket_new_direct (ss_addr);
273 gnet_inetaddr_delete (ss_addr);
274 if (!s)
275 return NULL;
276
277 /* Negotiate connection */
278 rv = socks5_negotiate_bind (s, port);
279 if (rv < 0)
280 {
281 gnet_tcp_socket_delete (s);
282 return NULL;
283 }
284
285 return s;
286 }
287
288
289 static int
socks5_negotiate_bind(GTcpSocket * socket,int port)290 socks5_negotiate_bind (GTcpSocket* socket, int port)
291 {
292 GIOChannel *ioc;
293 unsigned char s5r[3];
294 struct socks5_h s5h;
295 gsize len;
296
297 ioc = gnet_tcp_socket_get_io_channel(socket);
298
299 s5r[0] = 5;
300 s5r[1] = 1; /* no authentication */
301 s5r[2] = 0;
302
303 if (gnet_io_channel_writen(ioc, s5r, 3, &len) != G_IO_ERROR_NONE)
304 goto error;
305 if (gnet_io_channel_readn(ioc, s5r, 2, &len) != G_IO_ERROR_NONE)
306 goto error;
307 if ((s5r[0] != 5) || (s5r[1] != 0))
308 goto error;
309
310 /* fill in SOCKS5 request */
311 s5h.vn = 5;
312 s5h.cd = 2; /* bind */
313 s5h.rsv = 0;
314 s5h.atyp = 1;
315 s5h.dip = 0; /* FIX: this works with nylon; i will check on rfc */
316 s5h.dport = g_htons(port);
317
318 if (gnet_io_channel_writen(ioc, (gchar*)&s5h, 10, &len) != G_IO_ERROR_NONE)
319 goto error;
320 /* this reply simply confirms */
321 if (gnet_io_channel_readn(ioc, (gchar*)&s5h, 10, &len) != G_IO_ERROR_NONE)
322 goto error;
323 /* make sure we have a connection */
324 if (s5h.cd != 0)
325 goto error;
326
327 /* Copy the address */
328 GNET_SOCKADDR_IN(socket->sa).sin_addr.s_addr = s5h.dip;
329 GNET_SOCKADDR_IN(socket->sa).sin_port = s5h.dport;
330
331 return 0;
332
333 error:
334 return -1;
335 }
336
337
338 /* XXX 0 server SOCKS compliant? */
339
340 GTcpSocket*
_gnet_socks_tcp_socket_server_accept(GTcpSocket * socket)341 _gnet_socks_tcp_socket_server_accept (GTcpSocket* socket)
342 {
343 gint server_port;
344 struct socks5_h s5h;
345 gsize len;
346 GIOChannel* iochannel;
347 GIOError error;
348 GTcpSocket* s;
349 GTcpSocket* new_socket;
350
351 g_return_val_if_fail (socket, NULL);
352
353 /* Save server port */
354 server_port = g_ntohs(GNET_SOCKADDR_IN(socket->sa).sin_port);
355
356 /* this reply reveals the connecting hosts ip and port */
357 iochannel = gnet_tcp_socket_get_io_channel(socket);
358 error = gnet_io_channel_readn(iochannel, (gchar*) &s5h, 10, &len);
359 if (error != G_IO_ERROR_NONE)
360 return NULL;
361
362 /* The client socket is the server socket */
363 /* FIXME: this code should be in tcp.c, just like the struct definition */
364 s = g_new0(GTcpSocket, 1);
365 s->sockfd = socket->sockfd;
366 GNET_SOCKADDR_IN(s->sa).sin_addr.s_addr = s5h.dip;
367 GNET_SOCKADDR_IN(s->sa).sin_port = s5h.dport;
368 s->ref_count = 1;
369
370 /* Create a new server socket (we just use the sockfd) */
371 new_socket = _gnet_socks_tcp_socket_server_new (server_port);
372 if (new_socket == NULL)
373 {
374 g_free (s); /* ok, we copied sockfd */
375 return NULL;
376 }
377
378 /* Copy the fd over and delete the new socket */
379 socket->sockfd = new_socket->sockfd;
380 g_free (new_socket); /* ok, we copied sockfd */
381
382 /* Hand over IOChannel */
383 if (socket->accept_watch)
384 {
385 g_source_remove (socket->accept_watch);
386 socket->accept_watch = 0;
387 }
388 s->iochannel = socket->iochannel;
389 socket->iochannel = NULL;
390
391 /* Reset the async watch if necessary */
392 if (socket->accept_func)
393 {
394 GIOChannel* iochannel;
395
396 /* This will recreate the IOChannel */
397 iochannel = gnet_tcp_socket_get_io_channel (socket);
398
399 /* Set the watch on the new IO channel */
400 socket->accept_watch = g_io_add_watch(iochannel,
401 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
402 socks_tcp_socket_server_accept_async_cb, socket);
403 }
404
405 return s;
406 }
407
408
409 void
_gnet_socks_tcp_socket_server_accept_async(GTcpSocket * socket,GTcpSocketAcceptFunc accept_func,gpointer user_data)410 _gnet_socks_tcp_socket_server_accept_async (GTcpSocket * socket,
411 GTcpSocketAcceptFunc accept_func, gpointer user_data)
412 {
413 GIOChannel* iochannel;
414
415 g_return_if_fail (socket);
416 g_return_if_fail (accept_func);
417 g_return_if_fail (!socket->accept_func);
418
419 /* Save callback */
420 socket->accept_func = accept_func;
421 socket->accept_data = user_data;
422
423 /* Add read watch */
424 iochannel = gnet_tcp_socket_get_io_channel (socket);
425 socket->accept_watch = g_io_add_watch(iochannel,
426 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
427 socks_tcp_socket_server_accept_async_cb, socket);
428 }
429
430
431
432 static gboolean
socks_tcp_socket_server_accept_async_cb(GIOChannel * iochannel,GIOCondition condition,gpointer data)433 socks_tcp_socket_server_accept_async_cb (GIOChannel* iochannel, GIOCondition condition,
434 gpointer data)
435 {
436 GTcpSocket* server = (GTcpSocket*) data;
437
438 g_assert (server);
439
440 if (condition & G_IO_IN)
441 {
442 GTcpSocket* client;
443
444 client = _gnet_socks_tcp_socket_server_accept (server);
445 if (!client)
446 return TRUE;
447
448 (server->accept_func)(server, client, server->accept_data);
449
450 return FALSE;
451 }
452 else /* error */
453 {
454 gnet_tcp_socket_ref (server);
455
456 (server->accept_func)(server, NULL, server->accept_data);
457
458 server->accept_watch = 0;
459 server->accept_func = NULL;
460 server->accept_data = NULL;
461
462 gnet_tcp_socket_unref (server);
463
464 return FALSE;
465 }
466
467 return FALSE;
468 }
469