-Merge branch 'master' of ssh://gnunet.org/gnunet into gsoc2018/rest_api
[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 it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * @file util/socks.c
21  * @brief  SOCKS5 connection support
22  * @author Jeffrey Burdges
23  *
24  * These routines should be called only on newly active connections.
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28
29
30 #define LOG(kind,...) GNUNET_log_from (kind, "util-socks", __VA_ARGS__)
31
32 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-socks", syscall)
33
34
35 /* SOCKS5 authentication methods */
36 #define SOCKS5_AUTH_REJECT 0xFF /* No acceptable auth method */
37 #define SOCKS5_AUTH_NOAUTH 0x00 /* without authentication */
38 #define SOCKS5_AUTH_GSSAPI 0x01 /* GSSAPI */
39 #define SOCKS5_AUTH_USERPASS 0x02 /* User/Password */
40 #define SOCKS5_AUTH_CHAP 0x03 /* Challenge-Handshake Auth Proto. */
41 #define SOCKS5_AUTH_EAP 0x05 /* Extensible Authentication Proto. */
42 #define SOCKS5_AUTH_MAF 0x08 /* Multi-Authentication Framework */
43
44
45 /* SOCKS5 connection responces */
46 #define SOCKS5_REP_SUCCEEDED 0x00 /* succeeded */
47 #define SOCKS5_REP_FAIL 0x01 /* general SOCKS serer failure */
48 #define SOCKS5_REP_NALLOWED 0x02 /* connection not allowed by ruleset */
49 #define SOCKS5_REP_NUNREACH 0x03 /* Network unreachable */
50 #define SOCKS5_REP_HUNREACH 0x04 /* Host unreachable */
51 #define SOCKS5_REP_REFUSED 0x05 /* connection refused */
52 #define SOCKS5_REP_EXPIRED 0x06 /* TTL expired */
53 #define SOCKS5_REP_CNOTSUP 0x07 /* Command not supported */
54 #define SOCKS5_REP_ANOTSUP 0x08 /* Address not supported */
55 #define SOCKS5_REP_INVADDR 0x09 /* Inalid address */
56
57 const char * SOCKS5_REP_names(int rep)
58 {
59   switch (rep) {
60     case SOCKS5_REP_SUCCEEDED: return "succeeded";
61     case SOCKS5_REP_FAIL: return "general SOCKS server failure";
62     case SOCKS5_REP_NALLOWED: return "connection not allowed by ruleset";
63     case SOCKS5_REP_NUNREACH: return "Network unreachable";
64     case SOCKS5_REP_HUNREACH: return "Host unreachable";
65     case SOCKS5_REP_REFUSED: return "connection refused";
66     case SOCKS5_REP_EXPIRED: return "TTL expired";
67     case SOCKS5_REP_CNOTSUP: return "Command not supported";
68     case SOCKS5_REP_ANOTSUP: return "Address not supported";
69     case SOCKS5_REP_INVADDR: return "Invalid address";
70     default: return NULL;
71   }
72 };
73
74
75 /**
76  * Encode a string for the SOCKS5 protocol by prefixing it a byte stating its
77  * length and stipping the trailing zero byte.  Truncates any string longer
78  * than 255 bytes.
79  *
80  * @param b buffer to contain the encoded string
81  * @param s string to encode
82  * @return pointer to the end of the encoded string in the buffer
83  */
84 unsigned char *
85 SOCK5_proto_string(unsigned char * b,
86                    const char * s)
87 {
88   size_t l = strlen(s);
89
90   if (l > 255)
91   {
92     LOG (GNUNET_ERROR_TYPE_WARNING,
93          "SOCKS5 cannot handle hostnames, usernames, or passwords over 255 bytes, truncating.\n");
94     l=255;
95   }
96   *(b++) = (unsigned char) l;
97   strncpy ((char *)b, s, l);
98   return b+l;
99 }
100
101
102 #define SOCKS5_step_greet 0
103 #define SOCKS5_step_auth  1
104 #define SOCKS5_step_cmd   2
105 #define SOCKS5_step_done  3
106
107 /**
108  * State of the SOCKS5 handshake.
109  */
110 struct GNUNET_SOCKS_Handshake
111 {
112
113   /**
114    * Connection handle used for SOCKS5
115    */
116   struct GNUNET_CONNECTION_Handle *socks5_connection;
117
118   /**
119    * Connection handle initially returned to client
120    */
121   struct GNUNET_CONNECTION_Handle *target_connection;
122
123   /**
124    * Transmission handle on socks5_connection.
125    */
126   struct GNUNET_CONNECTION_TransmitHandle *th;
127
128   /**
129    * Our stage in the SOCKS5 handshake
130    */
131   int step;
132
133   /**
134    * Precomputed SOCKS5 handshake ouput buffer
135    */
136   unsigned char outbuf[1024];
137
138   /**
139    * Pointers delineating protoocol steps in the outbut buffer
140    */
141   unsigned char * (outstep[4]);
142
143   /**
144    * SOCKS5 handshake input buffer
145    */
146   unsigned char inbuf[1024];
147
148   /**
149    * Pointers delimiting the current step in the input buffer
150    */
151   unsigned char * instart;
152   unsigned char * inend;
153 };
154
155
156 /* Regitering prototypes */
157
158 void
159 register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want);
160
161   /* In fact, the client sends first rule in GNUNet suggests one could take
162    * large mac read sizes without fear of screwing up the proxied protocol,
163    * but we make a proper SOCKS5 client. */
164 #define register_reciever_wants(ih) ((SOCKS5_step_cmd == ih->step) ? 10 : 2)
165
166
167 struct GNUNET_CONNECTION_TransmitHandle *
168 register_sender (struct GNUNET_SOCKS_Handshake *ih);
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);
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   GNUNET_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 size_t
334 transmit_ready (void *cls,
335                 size_t size,
336                 void *buf)
337 {
338   struct GNUNET_SOCKS_Handshake * ih = cls;
339
340   /* connection.c has many routines that call us with buf == NULL :
341    * signal_transmit_error() - DNS, etc. active
342    *   connect_fail_continuation()
343    *     connect_probe_continuation() - timeout
344    *     try_connect_using_address() - DNS failure/timeout
345    *     transmit_timeout() - retry failed?
346    * GNUNET_CONNECTION_notify_transmit_ready() can schedule :
347    *   transmit_timeout() - DNS still working
348    *   connect_error() - DNS done but no socket?
349    * transmit_ready() - scheduler shutdown or timeout, or signal_transmit_error()
350    * We'd need to dig into the scheduler to guess at the reason, as
351    * connection.c tells us nothing itself, but mostly its timouts.
352    * Initially, we'll simply ignore this and leave massive timeouts, but
353    * maybe that should change for error handling pruposes.  It appears that
354    * successful operations, including DNS resolution, do not use this.  */
355   if (NULL == buf)
356   {
357     if (0 == ih->step)
358     {
359       LOG (GNUNET_ERROR_TYPE_WARNING,
360            "Timeout contacting SOCKS server, retrying indefinitely, but probably hopeless.\n");
361       register_sender (ih);
362     }
363     else
364     {
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
373   GNUNET_assert ( (1024 >= size) && (size > 0) );
374   GNUNET_assert ( (SOCKS5_step_done > ih->step) && (ih->step >= 0) );
375   unsigned char * b = ih->outstep[ih->step];
376   unsigned char * e = ih->outstep[ih->step+1];
377   GNUNET_assert (e <= &ih->outbuf[1024]);
378   unsigned int l = e - b;
379   GNUNET_assert (size >= l);
380   GNUNET_memcpy (buf,
381                  b,
382                  l);
383   register_reciever (ih,
384                      register_reciever_wants (ih));
385   return l;
386 }
387
388
389 /**
390  * Register SOCKS5 handshake sender
391  *
392  * @param ih handshake
393  * @return non-NULL if the notify callback was queued,
394  *         NULL if we are already going to notify someone else (busy)
395  */
396 struct GNUNET_CONNECTION_TransmitHandle *
397 register_sender (struct GNUNET_SOCKS_Handshake *ih)
398 {
399   struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_MINUTES;
400
401   GNUNET_assert (SOCKS5_step_done > ih->step);
402   GNUNET_assert (ih->step >= 0);
403   if (0 == ih->step)
404     timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3);
405   unsigned char * b = ih->outstep[ih->step];
406   unsigned char * e = ih->outstep[ih->step+1];
407   GNUNET_assert (ih->outbuf <= b && b < e && e < &ih->outbuf[1024]);
408   ih->th = GNUNET_CONNECTION_notify_transmit_ready (ih->socks5_connection,
409                                                     e - b,
410                                                     timeout,
411                                                     &transmit_ready,
412                                                     ih);
413   return ih->th;
414 }
415
416
417 /**
418  * Initialize a SOCKS5 handshake for authentication via username and
419  * password.  Tor uses SOCKS username and password authentication to assign
420  * programs unique circuits.
421  *
422  * @param user username for the proxy
423  * @param pass password for the proxy
424  * @return Valid SOCKS5 hanbdshake handle
425  */
426 struct GNUNET_SOCKS_Handshake *
427 GNUNET_SOCKS_init_handshake (const char *user, const char *pass)
428 {
429   struct GNUNET_SOCKS_Handshake *ih = GNUNET_new (struct GNUNET_SOCKS_Handshake);
430   unsigned char * b = ih->outbuf;
431
432   ih->outstep[SOCKS5_step_greet] = b;
433   *(b++) = 5; /* SOCKS5 */
434   unsigned char * n = b++;
435   *n = 1; /* Number of authentication methods */
436   /* We support no authentication even when requesting authentication,
437    * but this appears harmless, given the way that Tor uses authentication.
438    * And some SOCKS5 servers might require this.  */
439   *(b++) = SOCKS5_AUTH_NOAUTH;
440   if (NULL != user) {
441     *(b++) = SOCKS5_AUTH_USERPASS;
442     (*n)++;
443   }
444   /* There is no apperent reason to support authentication methods beyond
445    * username and password since afaik Tor does not support them. */
446
447   /* We authenticate with an empty username and password if the server demands
448    * them but we do not have any. */
449   if (user == NULL)
450     user = "";
451   if (pass == NULL)
452     pass = "";
453
454   ih->outstep[SOCKS5_step_auth] = b;
455   *(b++) = 1; /* subnegotiation ver.: 1 */
456   b = SOCK5_proto_string(b,user);
457   b = SOCK5_proto_string(b,pass);
458
459   ih->outstep[SOCKS5_step_cmd] = b;
460
461   ih->inend = ih->instart = ih->inbuf;
462
463   return ih;
464 }
465
466
467 /**
468  * Initialize a SOCKS5 handshake without authentication, thereby possibly
469  * sharing a Tor circuit with another process.
470  *
471  * @return Valid SOCKS5 hanbdshake handle
472  */
473 struct GNUNET_SOCKS_Handshake *
474 GNUNET_SOCKS_init_handshake_noauth ()
475 {
476   return GNUNET_SOCKS_init_handshake (NULL,NULL);
477 }
478
479
480 /**
481  * Build request that the SOCKS5 proxy open a TCP/IP stream to the given host
482  * and port.
483  *
484  * @param ih SOCKS5 handshake
485  * @param hostname
486  * @param port
487  */
488 void
489 GNUNET_SOCKS_set_handshake_destination (struct GNUNET_SOCKS_Handshake *ih,
490                                          const char *host, uint16_t port)
491 {
492   union {
493     struct in_addr in4;
494     struct in6_addr in6;
495   } ia;
496   unsigned char * b = ih->outstep[SOCKS5_step_cmd];
497
498   *(b++) = 5;  /* SOCKS5 */
499   *(b++) = 1;  /* Establish a TCP/IP stream */
500   *(b++) = 0;  /* reserved */
501
502   /* Specify destination */
503   if (1 == inet_pton(AF_INET,host,&ia.in4)) {
504     *(b++)= 1;  /* IPv4 */
505     GNUNET_memcpy (b, &ia.in4, sizeof(struct in_addr));
506     b += sizeof(struct in_addr);  /* 4 */
507   } else if (1 == inet_pton(AF_INET6,host,&ia.in6)) {
508     *(b++)= 4;  /* IPv6 */
509     GNUNET_memcpy (b, &ia.in6, sizeof(struct in6_addr));
510     b += sizeof(struct in6_addr);  /* 16 */
511   } else {
512     *(b++)= 3;  /* hostname */
513     b = SOCK5_proto_string (b, host);
514   }
515
516   /* Specify port */
517   *(uint16_t*)b = htons (port);
518   b += 2;
519
520   ih->outstep[SOCKS5_step_done] = b;
521 }
522
523
524 /**
525  * Run a SOCKS5 handshake on an open but unused TCP connection.
526  *
527  * @param ih SOCKS5 handshake, consumed here.
528  * @param c open unused connection, consumed here.
529  * @return Connection handle that becomes usable when the SOCKS5 handshake completes.
530  */
531 struct GNUNET_CONNECTION_Handle *
532 GNUNET_SOCKS_run_handshake(struct GNUNET_SOCKS_Handshake *ih,
533                             struct GNUNET_CONNECTION_Handle *c)
534 {
535   ih->socks5_connection=c;
536   ih->target_connection = GNUNET_CONNECTION_create_proxied_from_handshake (c);
537   register_sender (ih);
538
539   return ih->target_connection;
540 }
541
542
543 /**
544  * Check if a SOCKS proxy is required by a service.  Do not use local service
545  * if a SOCKS proxy port is configured as this could deanonymize a user.
546  *
547  * @param service_name name of service to connect to
548  * @param cfg configuration to use
549  * @return GNUNET_YES if so, GNUNET_NO if not
550  */
551 int
552 GNUNET_SOCKS_check_service (const char *service_name,
553                             const struct GNUNET_CONFIGURATION_Handle *cfg)
554 {
555   return GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSPORT") ||
556          GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSHOST");
557 }
558
559
560 /**
561  * Try to connect to a service configured to use a SOCKS5 proxy.
562  *
563  * @param service_name name of service to connect to
564  * @param cfg configuration to use
565  * @return Connection handle that becomes usable when the handshake completes.
566  *         NULL if SOCKS not configured or not configured properly
567  */
568 struct GNUNET_CONNECTION_Handle *
569 GNUNET_SOCKS_do_connect (const char *service_name,
570                          const struct GNUNET_CONFIGURATION_Handle *cfg)
571 {
572   struct GNUNET_SOCKS_Handshake *ih;
573   struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */
574   char *host0;
575   char *host1;
576   char *user;
577   char *pass;
578   unsigned long long port0;
579   unsigned long long port1;
580
581   if (GNUNET_YES !=
582       GNUNET_SOCKS_check_service (service_name, cfg))
583     return NULL;
584   if (GNUNET_OK !=
585       GNUNET_CONFIGURATION_get_value_number (cfg,
586                                              service_name,
587                                              "SOCKSPORT",
588                                              &port0))
589     port0 = 9050;
590   /* A typical Tor client should usually try port 9150 for the TBB too, but
591    * GNUnet can probably assume a system Tor installation. */
592   if (port0 > 65535 || port0 <= 0)
593   {
594     LOG (GNUNET_ERROR_TYPE_WARNING,
595          _("Attempting to use invalid port %d as SOCKS proxy for service `%s'.\n"),
596          port0,
597          service_name);
598     return NULL;
599   }
600   if ( (GNUNET_OK !=
601         GNUNET_CONFIGURATION_get_value_number (cfg,
602                                                service_name,
603                                                "PORT",
604                                                &port1)) ||
605        (port1 > 65535) ||
606        (port1 <= 0) ||
607        (GNUNET_OK !=
608         GNUNET_CONFIGURATION_get_value_string (cfg,
609                                                service_name,
610                                                "HOSTNAME",
611                                                &host1)))
612   {
613     LOG (GNUNET_ERROR_TYPE_WARNING,
614          _("Attempting to proxy service `%s' to invalid port %d or hostname.\n"),
615          service_name,
616          port1);
617     return NULL;
618   }
619   /* Appeared to still work after host0 corrupted, so either test case is broken, or
620      this whole routine is not being called. */
621   if (GNUNET_OK !=
622       GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0))
623     host0 = NULL;
624   socks5 = GNUNET_CONNECTION_create_from_connect (cfg,
625                                                   (host0 != NULL)
626                                                   ? host0
627                                                   :"127.0.0.1",
628                                                   port0);
629   GNUNET_free_non_null (host0);
630
631   /* Sets to NULL if they do not exist */
632   (void) GNUNET_CONFIGURATION_get_value_string (cfg,
633                                                 service_name,
634                                                 "SOCKSUSER",
635                                                 &user);
636   (void) GNUNET_CONFIGURATION_get_value_string (cfg,
637                                                 service_name,
638                                                 "SOCKSPASS",
639                                                 &pass);
640   ih = GNUNET_SOCKS_init_handshake(user,pass);
641   GNUNET_free_non_null (user);
642   GNUNET_free_non_null (pass);
643
644   GNUNET_SOCKS_set_handshake_destination (ih,
645                                           host1,
646                                           port1);
647   GNUNET_free (host1);
648   return GNUNET_SOCKS_run_handshake (ih,
649                                      socks5);
650 }
651
652 /* socks.c */