2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
23 * @brief SOCKS5 connection support
24 * @author Jeffrey Burdges
26 * These routines should be called only on newly active connections.
29 #include "gnunet_util_lib.h"
32 #define LOG(kind, ...) GNUNET_log_from(kind, "util-socks", __VA_ARGS__)
34 #define LOG_STRERROR(kind, syscall) \
35 GNUNET_log_from_strerror(kind, "util-socks", syscall)
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 */
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 */
61 SOCKS5_REP_names(int rep)
65 case SOCKS5_REP_SUCCEEDED:
69 return "general SOCKS server failure";
71 case SOCKS5_REP_NALLOWED:
72 return "connection not allowed by ruleset";
74 case SOCKS5_REP_NUNREACH:
75 return "Network unreachable";
77 case SOCKS5_REP_HUNREACH:
78 return "Host unreachable";
80 case SOCKS5_REP_REFUSED:
81 return "connection refused";
83 case SOCKS5_REP_EXPIRED:
86 case SOCKS5_REP_CNOTSUP:
87 return "Command not supported";
89 case SOCKS5_REP_ANOTSUP:
90 return "Address not supported";
92 case SOCKS5_REP_INVADDR:
93 return "Invalid address";
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
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
111 SOCK5_proto_string(unsigned char *b, const char *s)
113 size_t l = strlen(s);
117 LOG(GNUNET_ERROR_TYPE_WARNING,
118 "SOCKS5 cannot handle hostnames, usernames, or passwords over 255 bytes, truncating.\n");
121 *(b++) = (unsigned char)l;
127 #define SOCKS5_step_greet 0
128 #define SOCKS5_step_auth 1
129 #define SOCKS5_step_cmd 2
130 #define SOCKS5_step_done 3
133 * State of the SOCKS5 handshake.
135 struct GNUNET_SOCKS_Handshake {
137 * Connection handle used for SOCKS5
139 struct GNUNET_CONNECTION_Handle *socks5_connection;
142 * Connection handle initially returned to client
144 struct GNUNET_CONNECTION_Handle *target_connection;
147 * Transmission handle on socks5_connection.
149 struct GNUNET_CONNECTION_TransmitHandle *th;
152 * Our stage in the SOCKS5 handshake
157 * Precomputed SOCKS5 handshake ouput buffer
159 unsigned char outbuf[1024];
162 * Pointers delineating protoocol steps in the outbut buffer
164 unsigned char *(outstep[4]);
167 * SOCKS5 handshake input buffer
169 unsigned char inbuf[1024];
172 * Pointers delimiting the current step in the input buffer
174 unsigned char *instart;
175 unsigned char *inend;
179 /* Regitering prototypes */
182 register_reciever(struct GNUNET_SOCKS_Handshake *ih, int want);
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)
190 struct GNUNET_CONNECTION_TransmitHandle *
191 register_sender(struct GNUNET_SOCKS_Handshake *ih);
195 * Conclude the SOCKS5 handshake successfully.
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.
202 SOCKS5_handshake_done(struct GNUNET_SOCKS_Handshake *ih)
204 GNUNET_CONNECTION_acivate_proxied(ih->target_connection);
209 * Read one step in the SOCKS5 handshake.
211 * @param ih SOCKS5 Handshake
214 SOCKS5_handshake_step(struct GNUNET_SOCKS_Handshake *ih)
216 unsigned char *b = ih->instart;
217 size_t available = ih->inend - b;
219 int want = register_reciever_wants(ih);
221 if (available < want)
223 register_reciever(ih, want - available);
226 GNUNET_assert(SOCKS5_step_done > ih->step && ih->step >= 0);
229 case SOCKS5_step_greet: /* SOCKS5 server's greeting */
232 LOG(GNUNET_ERROR_TYPE_ERROR, "Not a SOCKS5 server\n");
237 case SOCKS5_AUTH_NOAUTH:
238 ih->step = SOCKS5_step_cmd; /* no authentication to do */
241 case SOCKS5_AUTH_USERPASS:
242 ih->step = SOCKS5_step_auth;
245 case SOCKS5_AUTH_REJECT:
246 LOG(GNUNET_ERROR_TYPE_ERROR, "No authentication method accepted\n");
250 LOG(GNUNET_ERROR_TYPE_ERROR,
251 "Not a SOCKS5 server / Nonsensical authentication\n");
257 case SOCKS5_step_auth: /* SOCKS5 server's responce to authentication */
260 LOG(GNUNET_ERROR_TYPE_ERROR, "SOCKS5 authentication failed\n");
263 ih->step = SOCKS5_step_cmd;
267 case SOCKS5_step_cmd: /* SOCKS5 server's responce to command */
270 LOG(GNUNET_ERROR_TYPE_ERROR, "SOCKS5 protocol error\n");
275 LOG(GNUNET_ERROR_TYPE_ERROR,
276 "SOCKS5 connection error : %s\n",
277 SOCKS5_REP_names(b[1]));
281 /* There is no reason to verify host and port afaik. */
285 b += sizeof(struct in_addr); /* 4 */
289 b += sizeof(struct in6_addr); /* 16 */
292 case 3: /* hostname */
299 register_reciever(ih, b - ih->inend);
302 ih->step = SOCKS5_step_done;
303 LOG(GNUNET_ERROR_TYPE_DEBUG,
304 "SOCKS5 server : %s\n",
305 SOCKS5_REP_names(b[1]));
307 SOCKS5_handshake_done(ih);
310 case SOCKS5_step_done:
314 /* Do not reschedule the sender unless we're done reading.
315 * I imagine this lets us avoid ever cancelling the transmit handle. */
321 * Callback to read from the SOCKS5 proxy.
323 * @param client the service
324 * @param handler function to call with the message
325 * @param handler_cls closure for @a handler
331 const struct sockaddr *addr,
335 struct GNUNET_SOCKS_Handshake *ih = cls;
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);
345 * Register callback to read from the SOCKS5 proxy.
347 * @param client the service
348 * @param handler function to call with the message
349 * @param handler_cls closure for @a handler
352 register_reciever(struct GNUNET_SOCKS_Handshake *ih, int want)
354 GNUNET_CONNECTION_receive(ih->socks5_connection,
356 GNUNET_TIME_relative_get_minute_(),
363 * Register SOCKS5 handshake sender
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
371 transmit_ready(void *cls, size_t size, void *buf)
373 struct GNUNET_SOCKS_Handshake *ih = cls;
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. */
394 LOG(GNUNET_ERROR_TYPE_WARNING,
395 "Timeout contacting SOCKS server, retrying indefinitely, but probably hopeless.\n");
400 LOG(GNUNET_ERROR_TYPE_ERROR,
401 "Timeout during mid SOCKS handshake (step %u), probably not a SOCKS server.\n",
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));
422 * Register SOCKS5 handshake sender
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)
428 struct GNUNET_CONNECTION_TransmitHandle *
429 register_sender(struct GNUNET_SOCKS_Handshake *ih)
431 struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_MINUTES;
433 GNUNET_assert(SOCKS5_step_done > ih->step);
434 GNUNET_assert(ih->step >= 0);
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,
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.
454 * @param user username for the proxy
455 * @param pass password for the proxy
456 * @return Valid SOCKS5 hanbdshake handle
458 struct GNUNET_SOCKS_Handshake *
459 GNUNET_SOCKS_init_handshake(const char *user, const char *pass)
461 struct GNUNET_SOCKS_Handshake *ih =
462 GNUNET_new(struct GNUNET_SOCKS_Handshake);
463 unsigned char *b = ih->outbuf;
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;
475 *(b++) = SOCKS5_AUTH_USERPASS;
478 /* There is no apperent reason to support authentication methods beyond
479 * username and password since afaik Tor does not support them. */
481 /* We authenticate with an empty username and password if the server demands
482 * them but we do not have any. */
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);
493 ih->outstep[SOCKS5_step_cmd] = b;
495 ih->inend = ih->instart = ih->inbuf;
502 * Initialize a SOCKS5 handshake without authentication, thereby possibly
503 * sharing a Tor circuit with another process.
505 * @return Valid SOCKS5 hanbdshake handle
507 struct GNUNET_SOCKS_Handshake *
508 GNUNET_SOCKS_init_handshake_noauth()
510 return GNUNET_SOCKS_init_handshake(NULL, NULL);
515 * Build request that the SOCKS5 proxy open a TCP/IP stream to the given host
518 * @param ih SOCKS5 handshake
523 GNUNET_SOCKS_set_handshake_destination(struct GNUNET_SOCKS_Handshake *ih,
531 unsigned char *b = ih->outstep[SOCKS5_step_cmd];
533 *(b++) = 5; /* SOCKS5 */
534 *(b++) = 1; /* Establish a TCP/IP stream */
535 *(b++) = 0; /* reserved */
537 /* Specify destination */
538 if (1 == inet_pton(AF_INET, host, &ia.in4))
540 *(b++) = 1; /* IPv4 */
541 GNUNET_memcpy(b, &ia.in4, sizeof(struct in_addr));
542 b += sizeof(struct in_addr); /* 4 */
544 else if (1 == inet_pton(AF_INET6, host, &ia.in6))
546 *(b++) = 4; /* IPv6 */
547 GNUNET_memcpy(b, &ia.in6, sizeof(struct in6_addr));
548 b += sizeof(struct in6_addr); /* 16 */
552 *(b++) = 3; /* hostname */
553 b = SOCK5_proto_string(b, host);
557 *(uint16_t *)b = htons(port);
560 ih->outstep[SOCKS5_step_done] = b;
565 * Run a SOCKS5 handshake on an open but unused TCP connection.
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.
571 struct GNUNET_CONNECTION_Handle *
572 GNUNET_SOCKS_run_handshake(struct GNUNET_SOCKS_Handshake *ih,
573 struct GNUNET_CONNECTION_Handle *c)
575 ih->socks5_connection = c;
576 ih->target_connection = GNUNET_CONNECTION_create_proxied_from_handshake(c);
579 return ih->target_connection;
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.
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
592 GNUNET_SOCKS_check_service(const char *service_name,
593 const struct GNUNET_CONFIGURATION_Handle *cfg)
595 return GNUNET_CONFIGURATION_have_value(cfg, service_name, "SOCKSPORT") ||
596 GNUNET_CONFIGURATION_have_value(cfg, service_name, "SOCKSHOST");
601 * Try to connect to a service configured to use a SOCKS5 proxy.
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
608 struct GNUNET_CONNECTION_Handle *
609 GNUNET_SOCKS_do_connect(const char *service_name,
610 const struct GNUNET_CONFIGURATION_Handle *cfg)
612 struct GNUNET_SOCKS_Handshake *ih;
613 struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */
618 unsigned long long port0;
619 unsigned long long port1;
621 if (GNUNET_YES != GNUNET_SOCKS_check_service(service_name, cfg))
623 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg,
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)
632 LOG(GNUNET_ERROR_TYPE_WARNING,
634 "Attempting to use invalid port %d as SOCKS proxy for service `%s'.\n"),
639 if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg,
643 (port1 > 65535) || (port1 <= 0) ||
644 (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(cfg,
649 LOG(GNUNET_ERROR_TYPE_WARNING,
651 "Attempting to proxy service `%s' to invalid port %d or hostname.\n"),
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,
663 socks5 = GNUNET_CONNECTION_create_from_connect(cfg,
664 (host0 != NULL) ? host0
667 GNUNET_free_non_null(host0);
669 /* Sets to NULL if they do not exist */
670 (void)GNUNET_CONFIGURATION_get_value_string(cfg,
674 (void)GNUNET_CONFIGURATION_get_value_string(cfg,
678 ih = GNUNET_SOCKS_init_handshake(user, pass);
679 GNUNET_free_non_null(user);
680 GNUNET_free_non_null(pass);
682 GNUNET_SOCKS_set_handshake_destination(ih, host1, port1);
684 return GNUNET_SOCKS_run_handshake(ih, socks5);