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