Initial SOCKS5 proxy code. This will not yet work properly.
[oweals/gnunet.git] / src / util / socks.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2013 Jeffrey Burdges (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file util/socks.c
23  * @brief  SOCKS5 connection support
24  * @author Jeffrey Burdges
25  *
26  * These routines should be called only on newly active connections.
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "socks", __VA_ARGS__)
33
34 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "socks", syscall)
35
36
37
38 /* SOCKS5 authentication methods */
39 #define SOCKS5_AUTH_REJECT 0xFF /* No acceptable auth method */
40 #define SOCKS5_AUTH_NOAUTH 0x00 /* without authentication */
41 #define SOCKS5_AUTH_GSSAPI 0x01 /* GSSAPI */
42 #define SOCKS5_AUTH_USERPASS 0x02 /* User/Password */
43 #define SOCKS5_AUTH_CHAP 0x03 /* Challenge-Handshake Auth Proto. */
44 #define SOCKS5_AUTH_EAP 0x05 /* Extensible Authentication Proto. */
45 #define SOCKS5_AUTH_MAF 0x08 /* Multi-Authentication Framework */
46
47
48 /* SOCKS5 connection responces */
49 #define SOCKS5_REP_SUCCEEDED 0x00 /* succeeded */
50 #define SOCKS5_REP_FAIL 0x01 /* general SOCKS serer failure */
51 #define SOCKS5_REP_NALLOWED 0x02 /* connection not allowed by ruleset */
52 #define SOCKS5_REP_NUNREACH 0x03 /* Network unreachable */
53 #define SOCKS5_REP_HUNREACH 0x04 /* Host unreachable */
54 #define SOCKS5_REP_REFUSED 0x05 /* connection refused */
55 #define SOCKS5_REP_EXPIRED 0x06 /* TTL expired */
56 #define SOCKS5_REP_CNOTSUP 0x07 /* Command not supported */
57 #define SOCKS5_REP_ANOTSUP 0x08 /* Address not supported */
58 #define SOCKS5_REP_INVADDR 0x09 /* Inalid address */
59
60 const char * SOCKS5_REP_names(int rep)
61 {
62   switch (rep) {
63     case SOCKS5_REP_SUCCEEDED: return "succeeded";
64     case SOCKS5_REP_FAIL: return "general SOCKS server failure";
65     case SOCKS5_REP_NALLOWED: return "connection not allowed by ruleset";
66     case SOCKS5_REP_NUNREACH: return "Network unreachable";
67     case SOCKS5_REP_HUNREACH: return "Host unreachable";
68     case SOCKS5_REP_REFUSED: return "connection refused";
69     case SOCKS5_REP_EXPIRED: return "TTL expired";
70     case SOCKS5_REP_CNOTSUP: return "Command not supported";
71     case SOCKS5_REP_ANOTSUP: return "Address not supported";
72     case SOCKS5_REP_INVADDR: return "Invalid address";
73     default: return NULL;
74   }
75 };
76
77
78 /**
79  * Encode a string for the SOCKS5 protocol by prefixing it a byte stating its
80  * length and stipping the trailing zero byte.  Truncates any string longer
81  * than 255 bytes.
82  *
83  * @param b buffer to contain the encoded string
84  * @param s string to encode
85  * @return pointer to the end of the encoded string in the buffer
86  */
87 unsigned char * SOCK5_proto_string(unsigned char * b, const char * s)
88 {
89   size_t l = strlen(s);
90   if (l>255) {
91     LOG (GNUNET_ERROR_TYPE_WARNING,
92          "SOCKS5 cannot handle hostnames, usernames, or passwords over 255 bytes, truncating.\n");
93     l=255;
94   }
95   *(b++) = (unsigned char)l;
96   strncpy((char *)b,s,l);
97   return b+l;
98 }
99
100
101 #define SOCKS5_step_greet 0
102 #define SOCKS5_step_auth  1
103 #define SOCKS5_step_cmd   2
104 #define SOCKS5_step_done  3
105
106 /**
107  * State of the SOCKS5 handshake.
108  */
109 struct GNUNET_SOCKS_Handshake 
110 {
111
112   /**
113    * Connection handle used for SOCKS5
114    */
115   struct GNUNET_CONNECTION_Handle *socks5_connection;
116
117   /**
118    * Connection handle initially returned to client
119    */
120   struct GNUNET_CONNECTION_Handle *target_connection;
121
122   /**
123    * Transmission handle on socks5_connection.
124    */
125   struct GNUNET_CONNECTION_TransmitHandle *th;
126
127   /**
128    * Our stage in the SOCKS5 handshake 
129    */
130   int step;
131
132   /**
133    * Precomputed SOCKS5 handshake ouput buffer
134    */
135   unsigned char outbuf[1024];
136
137   /**
138    * Pointers delineating protoocol steps in the outbut buffer
139    */
140   unsigned char * (outstep[4]);
141
142   /**
143    * SOCKS5 handshake input buffer
144    */
145   unsigned char inbuf[1024];
146
147   /**
148    * Pointers delimiting the current step in the input buffer
149    */
150   unsigned char * instart;
151   unsigned char * inend;
152 };
153
154
155 /* Regitering prototypes */
156
157 void
158 register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want);
159
160   /* In fact, the client sends first rule in GNUNet suggests one could take
161    * large mac read sizes without fear of screwing up the proxied protocol,
162    * but we make a proper SOCKS5 client. */
163 #define register_reciever_wants(ih) ((SOCKS5_step_cmd == ih->step) ? 10 : 2)
164
165
166 struct GNUNET_CONNECTION_TransmitHandle *
167 register_sender (struct GNUNET_SOCKS_Handshake *ih, 
168                  struct GNUNET_TIME_Relative timeout);
169
170
171 /**
172  * Conclude the SOCKS5 handshake successfully.
173  *
174  * @param ih SOCKS5 handshake, consumed here.
175  * @param c open unused connection, consumed here.
176  * @return Connection handle that becomes usable when the handshake completes.
177  */
178 void
179 SOCKS5_handshake_done(struct GNUNET_SOCKS_Handshake *ih)
180 {
181   GNUNET_CONNECTION_acivate_proxied (ih->target_connection);
182 }
183
184
185 /**
186  * Read one step in the SOCKS5 handshake.
187  *
188  * @param ih SOCKS5 Handshake
189  */
190 void
191 SOCKS5_handshake_step (struct GNUNET_SOCKS_Handshake *ih)
192 {
193   unsigned char * b = ih->instart;
194   size_t available = ih->inend - b;
195
196   int want = register_reciever_wants(ih);
197   if (available < want) {
198     register_reciever (ih, want - available);
199     return;
200   }
201   GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
202   switch (ih->step) {
203     case SOCKS5_step_greet:  /* SOCKS5 server's greeting */
204       if (b[0] != 5) 
205       {
206         LOG (GNUNET_ERROR_TYPE_ERROR,
207              "Not a SOCKS5 server\n");
208         GNUNET_assert (0);
209       }
210       switch (b[1]) {
211         case SOCKS5_AUTH_NOAUTH:
212           ih->step=SOCKS5_step_cmd;  /* no authentication to do */
213           break;
214         case SOCKS5_AUTH_USERPASS:
215           ih->step=SOCKS5_step_auth;
216           break;
217         case SOCKS5_AUTH_REJECT:
218           LOG (GNUNET_ERROR_TYPE_ERROR,
219                "No authentication method accepted\n");
220           return;
221         default:
222           LOG (GNUNET_ERROR_TYPE_ERROR,
223                "Not a SOCKS5 server / Nonsensical authentication\n");
224           return;
225       }
226       b += 2;
227       break;
228     case SOCKS5_step_auth:  /* SOCKS5 server's responce to authentication */
229       if (b[1] != 0)
230       {
231         LOG (GNUNET_ERROR_TYPE_ERROR,
232              "SOCKS5 authentication failed\n");
233         GNUNET_assert (0);
234       }
235       ih->step=SOCKS5_step_cmd;
236       b += 2;
237       break;
238     case SOCKS5_step_cmd:  /* SOCKS5 server's responce to command */
239       if (b[0] != 5) 
240       {
241         LOG (GNUNET_ERROR_TYPE_ERROR,
242              "SOCKS5 protocol error\n");
243         GNUNET_assert (0);
244       }
245       if (0 != b[1]) {
246         LOG (GNUNET_ERROR_TYPE_ERROR,
247              "SOCKS5 connection error : %s\n",
248              SOCKS5_REP_names(b[1]));
249         return;
250       }
251       b += 3;
252       /* There is no reason to verify host and port afaik. */
253       switch (*(b++)) {
254         case 1: /* IPv4 */
255           b += sizeof(struct in_addr);  /* 4 */
256           break;
257         case 4: /* IPv6 */
258           b += sizeof(struct in6_addr);  /* 16 */
259           break;
260         case 3: /* hostname */
261           b += *b;
262           break;
263       }
264       b += 2;  /* port */
265       if (b > ih->inend) {
266         register_reciever (ih, b - ih->inend);
267         return;
268       }
269       ih->step = SOCKS5_step_done;
270       LOG (GNUNET_ERROR_TYPE_DEBUG,
271            "SOCKS5 server : %s\n",
272            SOCKS5_REP_names(b[1]));
273       ih->instart = b;
274       SOCKS5_handshake_done (ih);
275       return;
276     case SOCKS5_step_done: 
277       GNUNET_assert (0);
278   }
279   ih->instart = b;
280   /* Do not reschedule the sender unless we're done reading. 
281    * I imagine this lets us avoid ever cancelling the transmit handle. */
282   register_sender (ih, GNUNET_TIME_relative_get_minute_ ());
283 }
284
285
286 /**
287  * Callback to read from the SOCKS5 proxy.
288  *
289  * @param client the service
290  * @param handler function to call with the message
291  * @param handler_cls closure for @a handler
292  */
293 void
294 reciever (void *cls, 
295           const void *buf, size_t available,
296           const struct sockaddr * addr,
297           socklen_t addrlen, int errCode)
298 {
299   struct GNUNET_SOCKS_Handshake * ih = cls;
300   GNUNET_assert (&ih->inend[available] < &ih->inbuf[1024]);
301   memcpy(ih->inend, buf, available);
302   ih->inend += available;
303   SOCKS5_handshake_step (ih);
304 }
305
306
307 /**
308  * Register callback to read from the SOCKS5 proxy.
309  *
310  * @param client the service
311  * @param handler function to call with the message
312  * @param handler_cls closure for @a handler
313  */
314 void
315 register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want)
316 {
317   GNUNET_CONNECTION_receive (ih->socks5_connection,
318                              want,
319                              GNUNET_TIME_relative_get_minute_ (),
320                              &reciever,
321                              ih);
322 }
323
324
325 /**
326  * Register SOCKS5 handshake sender
327  *
328  * @param cls closure (SOCKS handshake)
329  * @param size number of bytes available in @a buf
330  * @param buf where the callee should write the message
331  * @return number of bytes written to @a buf
332  */
333
334 size_t
335 transmit_ready (void *cls, 
336                 size_t size,
337                 void *buf)
338 {
339   struct GNUNET_SOCKS_Handshake * ih = cls;
340
341   /* connection.c has many routines that call us with buf == NULL :
342    * signal_transmit_error() - DNS, etc. active
343    *   connect_fail_continuation()
344    *     connect_probe_continuation() - timeout
345    *     try_connect_using_address() - DNS failure/timeout
346    *     transmit_timeout() - retry failed?
347    * GNUNET_CONNECTION_notify_transmit_ready() can schedule :
348    *   transmit_timeout() - DNS still working
349    *   connect_error() - DNS done but no socket?
350    * transmit_ready() - scheduler shutdown or timeout, or signal_transmit_error() 
351    * We'd need to dig into the scheduler to guess at the reason, as
352    * connection.c tells us nothing itself, but mostly its timouts.
353    * Initially, we'll simply ignore this and leave massive timeouts, but
354    * maybe that should change for error handling pruposes.  It appears that
355    * successful operations, including DNS resolution, do not use this.  */
356   if (NULL==buf)
357   {
358     GNUNET_break (0);
359     return 0;
360   }
361
362   GNUNET_assert (1024 >= size && size > 0);
363   GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
364   unsigned char * b = ih->outstep[ih->step];
365   unsigned char * e = ih->outstep[ih->step++];
366   GNUNET_assert (e <= &ih->outbuf[1024]);
367   unsigned l = e - b;
368   GNUNET_assert (size >= l && l >= 0);
369   memcpy(b, buf, l);
370   register_reciever (ih, register_reciever_wants(ih));
371   return l;
372 }
373
374
375 /**
376  * Register SOCKS5 handshake sender
377  *
378  * @param ih handshake
379  * @return non-NULL if the notify callback was queued,
380  *         NULL if we are already going to notify someone else (busy)
381  */
382 struct GNUNET_CONNECTION_TransmitHandle *
383 register_sender (struct GNUNET_SOCKS_Handshake *ih, 
384                  struct GNUNET_TIME_Relative timeout)
385 {
386   GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
387   unsigned char * b = ih->outstep[ih->step];
388   unsigned char * e = ih->outstep[ih->step+1];
389   GNUNET_assert (ih->outbuf <= b && b < e && e < &ih->outbuf[1024]);
390   ih->th = GNUNET_CONNECTION_notify_transmit_ready (ih->socks5_connection,
391                                                     e - b,
392                                                     timeout,
393                                                     &transmit_ready,
394                                                     ih);
395   return ih->th;
396 }
397
398
399 /**
400  * Initialize a SOCKS5 handshake for authentication via username and
401  * password.  Tor uses SOCKS username and password authentication to assign
402  * programs unique circuits. 
403  *
404  * @param user username for the proxy
405  * @param pass password for the proxy
406  * @return Valid SOCKS5 hanbdshake handle
407  */
408 struct GNUNET_SOCKS_Handshake *
409 GNUNET_SOCKS_init_handshake (const char *user, const char *pass)
410 {
411   struct GNUNET_SOCKS_Handshake *ih = GNUNET_new (struct GNUNET_SOCKS_Handshake);
412   unsigned char * b = ih->outbuf;
413
414   ih->outstep[SOCKS5_step_greet] = b;
415   *(b++) = 5; /* SOCKS5 */
416   unsigned char * n = b++;
417   *n = 1; /* Number of authentication methods */
418   /* We support no authentication even when requesting authentication,
419    * but this appears harmless, given the way that Tor uses authentication. 
420    * And some SOCKS5 servers might require this.  */
421   *(b++) = SOCKS5_AUTH_NOAUTH;
422   if (NULL != user) {
423     *(b++) = SOCKS5_AUTH_USERPASS;
424     (*n)++;
425   }
426   /* There is no apperent reason to support authentication methods beyond
427    * username and password since afaik Tor does not support them. */
428
429   /* We authenticate with an empty username and password if the server demands 
430    * them but we do not have any. */
431   if (user == NULL)
432     user = "";
433   if (user == NULL)
434     pass = "";
435
436   ih->outstep[SOCKS5_step_auth] = b;
437   *(b++) = 1; /* subnegotiation ver.: 1 */
438   b = SOCK5_proto_string(b,user);
439   b = SOCK5_proto_string(b,pass);
440
441   ih->outstep[SOCKS5_step_cmd] = b;
442
443   return ih;
444 }
445
446
447 /**
448  * Initialize a SOCKS5 handshake without authentication, thereby possibly 
449  * sharing a Tor circuit with another process.
450  *
451  * @return Valid SOCKS5 hanbdshake handle
452  */
453 struct GNUNET_SOCKS_Handshake *
454 GNUNET_SOCKS_init_handshake_noauth ()
455 {
456   return GNUNET_SOCKS_init_handshake (NULL,NULL);
457 }
458
459
460 /**
461  * Build request that the SOCKS5 proxy open a TCP/IP stream to the given host
462  * and port.  
463  *
464  * @param ih SOCKS5 handshake
465  * @param hostname 
466  * @param port 
467  */
468 void
469 GNUNET_SOCKS_set_handshake_destination (struct GNUNET_SOCKS_Handshake *ih,
470                                          const char *host, uint16_t port)
471 {
472   union {
473     struct in_addr in4;
474     struct in6_addr in6;
475   } ia;
476   unsigned char * b = ih->outstep[SOCKS5_step_cmd];
477
478   *(b++) = 5;  /* SOCKS5 */
479   *(b++) = 1;  /* Establish a TCP/IP stream */
480   *(b++) = 0;  /* reserved */
481
482   /* Specify destination */
483   if (1 == inet_pton(AF_INET,host,&ia.in4)) {
484     *(b++)= 1;  /* IPv4 */
485     memcpy (b, &ia.in4, sizeof(struct in_addr));
486     b += sizeof(struct in_addr);  /* 4 */
487   } else if (1 == inet_pton(AF_INET6,host,&ia.in6)) {
488     *(b++)= 4;  /* IPv6 */
489     memcpy (b, &ia.in6, sizeof(struct in6_addr));
490     b += sizeof(struct in6_addr);  /* 16 */
491   } else {
492     *(b++)= 3;  /* hostname */
493     b = SOCK5_proto_string (b, host);
494   }
495
496   /* Specify port */
497   *(uint16_t*)b = htons (port);
498   b += 2;
499
500   ih->outstep[SOCKS5_step_done] = b;
501 }
502
503
504 /**
505  * Run a SOCKS5 handshake on an open but unused TCP connection.
506  *
507  * @param ih SOCKS5 handshake, consumed here.
508  * @param c open unused connection, consumed here.
509  * @return Connection handle that becomes usable when the SOCKS5 handshake completes.
510  */
511 struct GNUNET_CONNECTION_Handle * 
512 GNUNET_SOCKS_run_handshake(struct GNUNET_SOCKS_Handshake *ih,
513                             struct GNUNET_CONNECTION_Handle *c)
514 {
515   ih->socks5_connection=c;
516   ih->target_connection = GNUNET_CONNECTION_create_proxied_from_handshake (c);
517   register_sender (ih, GNUNET_TIME_relative_get_forever_ () );
518   return ih->target_connection;
519 }
520
521
522 /**
523  * Check if a SOCKS proxy is required by a service.  Do not use local service
524  * if a SOCKS proxy port is configured as this could deanonymize a user.
525  *
526  * @param service_name name of service to connect to
527  * @param cfg configuration to use
528  * @return GNUNET_YES if so, GNUNET_NO if not
529  */
530 int
531 GNUNET_SOCKS_check_service (const char *service_name,
532                             const struct GNUNET_CONFIGURATION_Handle *cfg)
533 {
534   return GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSPORT") ||
535          GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSHOST");
536 }
537
538
539 /**
540  * Try to connect to a service configured to use a SOCKS5 proxy.
541  *
542  * @param service_name name of service to connect to
543  * @param cfg configuration to use
544  * @return Connection handle that becomes usable when the handshake completes.
545  *         NULL if SOCKS not configured or not configured properly
546  */
547 struct GNUNET_CONNECTION_Handle *
548 GNUNET_SOCKS_do_connect (const char *service_name,
549                           const struct GNUNET_CONFIGURATION_Handle *cfg)
550 {
551   struct GNUNET_SOCKS_Handshake *ih;
552   struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */
553   char *host0,*host1,*user,*pass;
554   unsigned long long port0,port1;
555
556   if (GNUNET_YES != GNUNET_SOCKS_check_service (service_name, cfg))
557     return NULL;
558   if (GNUNET_OK !=
559       GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "SOCKSPORT", &port0))
560     port0 = 9050;
561   /* A typical Tor client should usually try port 9150 for the TBB too, but 
562    * GUNNet can probably assume a system Tor instalation. */
563   if (GNUNET_OK !=
564       GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0))
565     host0 = "127.0.0.1";
566   if (port0 > 65535 || port0 <= 0)
567   {
568     LOG (GNUNET_ERROR_TYPE_WARNING,
569          _
570          ("Attempting to use invalid port or hostname for SOCKS proxy for service `%s'.\n"),
571          service_name);
572     return NULL;
573   }
574
575   if ((GNUNET_OK !=
576        GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port1))
577       || (port1 > 65535) || (port1 <= 0) ||
578        (GNUNET_OK !=
579         GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOST", &host1)))
580   {
581     LOG (GNUNET_ERROR_TYPE_WARNING,
582          _
583          ("Attempting to proxy service `%s' to invalid port or hostname.\n"),
584          service_name);
585     return NULL;
586   }
587
588   socks5 = GNUNET_CONNECTION_create_from_connect (cfg, host0, port0);
589   GNUNET_free (host0);
590
591   /* Sets to NULL if they do not exist */
592   GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSUSER", &user);
593   GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSPASS", &pass);
594   ih = GNUNET_SOCKS_init_handshake(user,pass);
595   GNUNET_SOCKS_set_handshake_destination (ih,host1,port1);
596   GNUNET_free (host1);
597
598   return GNUNET_SOCKS_run_handshake(ih,socks5);
599 }
600
601 /* socks.c */