uncrustify as demanded.
[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    * Connection handle used for SOCKS5
138    */
139   struct GNUNET_CONNECTION_Handle *socks5_connection;
140
141   /**
142    * Connection handle initially returned to client
143    */
144   struct GNUNET_CONNECTION_Handle *target_connection;
145
146   /**
147    * Transmission handle on socks5_connection.
148    */
149   struct GNUNET_CONNECTION_TransmitHandle *th;
150
151   /**
152    * Our stage in the SOCKS5 handshake
153    */
154   int step;
155
156   /**
157    * Precomputed SOCKS5 handshake ouput buffer
158    */
159   unsigned char outbuf[1024];
160
161   /**
162    * Pointers delineating protoocol steps in the outbut buffer
163    */
164   unsigned char *(outstep[4]);
165
166   /**
167    * SOCKS5 handshake input buffer
168    */
169   unsigned char inbuf[1024];
170
171   /**
172    * Pointers delimiting the current step in the input buffer
173    */
174   unsigned char *instart;
175   unsigned char *inend;
176 };
177
178
179 /* Regitering prototypes */
180
181 void
182 register_reciever(struct GNUNET_SOCKS_Handshake *ih, int want);
183
184 /* In fact, the client sends first rule in GNUnet suggests one could take
185  * large mac read sizes without fear of screwing up the proxied protocol,
186  * but we make a proper SOCKS5 client. */
187 #define register_reciever_wants(ih) ((SOCKS5_step_cmd == ih->step) ? 10 : 2)
188
189
190 struct GNUNET_CONNECTION_TransmitHandle *
191 register_sender(struct GNUNET_SOCKS_Handshake *ih);
192
193
194 /**
195  * Conclude the SOCKS5 handshake successfully.
196  *
197  * @param ih SOCKS5 handshake, consumed here.
198  * @param c open unused connection, consumed here.
199  * @return Connection handle that becomes usable when the handshake completes.
200  */
201 void
202 SOCKS5_handshake_done(struct GNUNET_SOCKS_Handshake *ih)
203 {
204   GNUNET_CONNECTION_acivate_proxied(ih->target_connection);
205 }
206
207
208 /**
209  * Read one step in the SOCKS5 handshake.
210  *
211  * @param ih SOCKS5 Handshake
212  */
213 void
214 SOCKS5_handshake_step(struct GNUNET_SOCKS_Handshake *ih)
215 {
216   unsigned char *b = ih->instart;
217   size_t available = ih->inend - b;
218
219   int want = register_reciever_wants(ih);
220
221   if (available < want)
222     {
223       register_reciever(ih, want - available);
224       return;
225     }
226   GNUNET_assert(SOCKS5_step_done > ih->step && ih->step >= 0);
227   switch (ih->step)
228     {
229     case SOCKS5_step_greet: /* SOCKS5 server's greeting */
230       if (b[0] != 5)
231         {
232           LOG(GNUNET_ERROR_TYPE_ERROR, "Not a SOCKS5 server\n");
233           GNUNET_assert(0);
234         }
235       switch (b[1])
236         {
237         case SOCKS5_AUTH_NOAUTH:
238           ih->step = SOCKS5_step_cmd; /* no authentication to do */
239           break;
240
241         case SOCKS5_AUTH_USERPASS:
242           ih->step = SOCKS5_step_auth;
243           break;
244
245         case SOCKS5_AUTH_REJECT:
246           LOG(GNUNET_ERROR_TYPE_ERROR, "No authentication method accepted\n");
247           return;
248
249         default:
250           LOG(GNUNET_ERROR_TYPE_ERROR,
251               "Not a SOCKS5 server / Nonsensical authentication\n");
252           return;
253         }
254       b += 2;
255       break;
256
257     case SOCKS5_step_auth: /* SOCKS5 server's responce to authentication */
258       if (b[1] != 0)
259         {
260           LOG(GNUNET_ERROR_TYPE_ERROR, "SOCKS5 authentication failed\n");
261           GNUNET_assert(0);
262         }
263       ih->step = SOCKS5_step_cmd;
264       b += 2;
265       break;
266
267     case SOCKS5_step_cmd: /* SOCKS5 server's responce to command */
268       if (b[0] != 5)
269         {
270           LOG(GNUNET_ERROR_TYPE_ERROR, "SOCKS5 protocol error\n");
271           GNUNET_assert(0);
272         }
273       if (0 != b[1])
274         {
275           LOG(GNUNET_ERROR_TYPE_ERROR,
276               "SOCKS5 connection error : %s\n",
277               SOCKS5_REP_names(b[1]));
278           return;
279         }
280       b += 3;
281       /* There is no reason to verify host and port afaik. */
282       switch (*(b++))
283         {
284         case 1: /* IPv4 */
285           b += sizeof(struct in_addr); /* 4 */
286           break;
287
288         case 4: /* IPv6 */
289           b += sizeof(struct in6_addr); /* 16 */
290           break;
291
292         case 3: /* hostname */
293           b += *b;
294           break;
295         }
296       b += 2; /* port */
297       if (b > ih->inend)
298         {
299           register_reciever(ih, b - ih->inend);
300           return;
301         }
302       ih->step = SOCKS5_step_done;
303       LOG(GNUNET_ERROR_TYPE_DEBUG,
304           "SOCKS5 server : %s\n",
305           SOCKS5_REP_names(b[1]));
306       ih->instart = b;
307       SOCKS5_handshake_done(ih);
308       return;
309
310     case SOCKS5_step_done:
311       GNUNET_assert(0);
312     }
313   ih->instart = b;
314   /* Do not reschedule the sender unless we're done reading.
315    * I imagine this lets us avoid ever cancelling the transmit handle. */
316   register_sender(ih);
317 }
318
319
320 /**
321  * Callback to read from the SOCKS5 proxy.
322  *
323  * @param client the service
324  * @param handler function to call with the message
325  * @param handler_cls closure for @a handler
326  */
327 void
328 reciever(void *cls,
329          const void *buf,
330          size_t available,
331          const struct sockaddr *addr,
332          socklen_t addrlen,
333          int errCode)
334 {
335   struct GNUNET_SOCKS_Handshake *ih = cls;
336
337   GNUNET_assert(&ih->inend[available] < &ih->inbuf[1024]);
338   GNUNET_memcpy(ih->inend, buf, available);
339   ih->inend += available;
340   SOCKS5_handshake_step(ih);
341 }
342
343
344 /**
345  * Register callback to read from the SOCKS5 proxy.
346  *
347  * @param client the service
348  * @param handler function to call with the message
349  * @param handler_cls closure for @a handler
350  */
351 void
352 register_reciever(struct GNUNET_SOCKS_Handshake *ih, int want)
353 {
354   GNUNET_CONNECTION_receive(ih->socks5_connection,
355                             want,
356                             GNUNET_TIME_relative_get_minute_(),
357                             &reciever,
358                             ih);
359 }
360
361
362 /**
363  * Register SOCKS5 handshake sender
364  *
365  * @param cls closure (SOCKS handshake)
366  * @param size number of bytes available in @a buf
367  * @param buf where the callee should write the message
368  * @return number of bytes written to @a buf
369  */
370 size_t
371 transmit_ready(void *cls, size_t size, void *buf)
372 {
373   struct GNUNET_SOCKS_Handshake *ih = cls;
374
375   /* connection.c has many routines that call us with buf == NULL :
376    * signal_transmit_error() - DNS, etc. active
377    *   connect_fail_continuation()
378    *     connect_probe_continuation() - timeout
379    *     try_connect_using_address() - DNS failure/timeout
380    *     transmit_timeout() - retry failed?
381    * GNUNET_CONNECTION_notify_transmit_ready() can schedule :
382    *   transmit_timeout() - DNS still working
383    *   connect_error() - DNS done but no socket?
384    * transmit_ready() - scheduler shutdown or timeout, or signal_transmit_error()
385    * We'd need to dig into the scheduler to guess at the reason, as
386    * connection.c tells us nothing itself, but mostly its timouts.
387    * Initially, we'll simply ignore this and leave massive timeouts, but
388    * maybe that should change for error handling pruposes.  It appears that
389    * successful operations, including DNS resolution, do not use this.  */
390   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     struct in_addr in4;
529     struct in6_addr in6;
530   } ia;
531   unsigned char *b = ih->outstep[SOCKS5_step_cmd];
532
533   *(b++) = 5; /* SOCKS5 */
534   *(b++) = 1; /* Establish a TCP/IP stream */
535   *(b++) = 0; /* reserved */
536
537   /* Specify destination */
538   if (1 == inet_pton(AF_INET, host, &ia.in4))
539     {
540       *(b++) = 1; /* IPv4 */
541       GNUNET_memcpy(b, &ia.in4, sizeof(struct in_addr));
542       b += sizeof(struct in_addr); /* 4 */
543     }
544   else if (1 == inet_pton(AF_INET6, host, &ia.in6))
545     {
546       *(b++) = 4; /* IPv6 */
547       GNUNET_memcpy(b, &ia.in6, sizeof(struct in6_addr));
548       b += sizeof(struct in6_addr); /* 16 */
549     }
550   else
551     {
552       *(b++) = 3; /* hostname */
553       b = SOCK5_proto_string(b, host);
554     }
555
556   /* Specify port */
557   *(uint16_t *)b = htons(port);
558   b += 2;
559
560   ih->outstep[SOCKS5_step_done] = b;
561 }
562
563
564 /**
565  * Run a SOCKS5 handshake on an open but unused TCP connection.
566  *
567  * @param ih SOCKS5 handshake, consumed here.
568  * @param c open unused connection, consumed here.
569  * @return Connection handle that becomes usable when the SOCKS5 handshake completes.
570  */
571 struct GNUNET_CONNECTION_Handle *
572 GNUNET_SOCKS_run_handshake(struct GNUNET_SOCKS_Handshake *ih,
573                            struct GNUNET_CONNECTION_Handle *c)
574 {
575   ih->socks5_connection = c;
576   ih->target_connection = GNUNET_CONNECTION_create_proxied_from_handshake(c);
577   register_sender(ih);
578
579   return ih->target_connection;
580 }
581
582
583 /**
584  * Check if a SOCKS proxy is required by a service.  Do not use local service
585  * if a SOCKS proxy port is configured as this could deanonymize a user.
586  *
587  * @param service_name name of service to connect to
588  * @param cfg configuration to use
589  * @return GNUNET_YES if so, GNUNET_NO if not
590  */
591 int
592 GNUNET_SOCKS_check_service(const char *service_name,
593                            const struct GNUNET_CONFIGURATION_Handle *cfg)
594 {
595   return GNUNET_CONFIGURATION_have_value(cfg, service_name, "SOCKSPORT") ||
596          GNUNET_CONFIGURATION_have_value(cfg, service_name, "SOCKSHOST");
597 }
598
599
600 /**
601  * Try to connect to a service configured to use a SOCKS5 proxy.
602  *
603  * @param service_name name of service to connect to
604  * @param cfg configuration to use
605  * @return Connection handle that becomes usable when the handshake completes.
606  *         NULL if SOCKS not configured or not configured properly
607  */
608 struct GNUNET_CONNECTION_Handle *
609 GNUNET_SOCKS_do_connect(const char *service_name,
610                         const struct GNUNET_CONFIGURATION_Handle *cfg)
611 {
612   struct GNUNET_SOCKS_Handshake *ih;
613   struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */
614   char *host0;
615   char *host1;
616   char *user;
617   char *pass;
618   unsigned long long port0;
619   unsigned long long port1;
620
621   if (GNUNET_YES != GNUNET_SOCKS_check_service(service_name, cfg))
622     return NULL;
623   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg,
624                                                          service_name,
625                                                          "SOCKSPORT",
626                                                          &port0))
627     port0 = 9050;
628   /* A typical Tor client should usually try port 9150 for the TBB too, but
629    * GNUnet can probably assume a system Tor installation. */
630   if (port0 > 65535 || port0 <= 0)
631     {
632       LOG(GNUNET_ERROR_TYPE_WARNING,
633           _(
634             "Attempting to use invalid port %d as SOCKS proxy for service `%s'.\n"),
635           port0,
636           service_name);
637       return NULL;
638     }
639   if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg,
640                                                           service_name,
641                                                           "PORT",
642                                                           &port1)) ||
643       (port1 > 65535) || (port1 <= 0) ||
644       (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg,
645                                                           service_name,
646                                                           "HOSTNAME",
647                                                           &host1)))
648     {
649       LOG(GNUNET_ERROR_TYPE_WARNING,
650           _(
651             "Attempting to proxy service `%s' to invalid port %d or hostname.\n"),
652           service_name,
653           port1);
654       return NULL;
655     }
656   /* Appeared to still work after host0 corrupted, so either test case is broken, or
657      this whole routine is not being called. */
658   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg,
659                                                          service_name,
660                                                          "SOCKSHOST",
661                                                          &host0))
662     host0 = NULL;
663   socks5 = GNUNET_CONNECTION_create_from_connect(cfg,
664                                                  (host0 != NULL) ? host0
665                                                  : "127.0.0.1",
666                                                  port0);
667   GNUNET_free_non_null(host0);
668
669   /* Sets to NULL if they do not exist */
670   (void)GNUNET_CONFIGURATION_get_value_string(cfg,
671                                               service_name,
672                                               "SOCKSUSER",
673                                               &user);
674   (void)GNUNET_CONFIGURATION_get_value_string(cfg,
675                                               service_name,
676                                               "SOCKSPASS",
677                                               &pass);
678   ih = GNUNET_SOCKS_init_handshake(user, pass);
679   GNUNET_free_non_null(user);
680   GNUNET_free_non_null(pass);
681
682   GNUNET_SOCKS_set_handshake_destination(ih, host1, port1);
683   GNUNET_free(host1);
684   return GNUNET_SOCKS_run_handshake(ih, socks5);
685 }
686
687 /* socks.c */