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