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