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) GNUNET_log_from_strerror (kind, "util-socks", syscall)
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 */
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 */
59 const char * SOCKS5_REP_names(int 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";
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
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
87 SOCK5_proto_string(unsigned char * b,
94 LOG (GNUNET_ERROR_TYPE_WARNING,
95 "SOCKS5 cannot handle hostnames, usernames, or passwords over 255 bytes, truncating.\n");
98 *(b++) = (unsigned char) l;
99 strncpy ((char *)b, s, l);
104 #define SOCKS5_step_greet 0
105 #define SOCKS5_step_auth 1
106 #define SOCKS5_step_cmd 2
107 #define SOCKS5_step_done 3
110 * State of the SOCKS5 handshake.
112 struct GNUNET_SOCKS_Handshake
116 * Connection handle used for SOCKS5
118 struct GNUNET_CONNECTION_Handle *socks5_connection;
121 * Connection handle initially returned to client
123 struct GNUNET_CONNECTION_Handle *target_connection;
126 * Transmission handle on socks5_connection.
128 struct GNUNET_CONNECTION_TransmitHandle *th;
131 * Our stage in the SOCKS5 handshake
136 * Precomputed SOCKS5 handshake ouput buffer
138 unsigned char outbuf[1024];
141 * Pointers delineating protoocol steps in the outbut buffer
143 unsigned char * (outstep[4]);
146 * SOCKS5 handshake input buffer
148 unsigned char inbuf[1024];
151 * Pointers delimiting the current step in the input buffer
153 unsigned char * instart;
154 unsigned char * inend;
158 /* Regitering prototypes */
161 register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want);
163 /* In fact, the client sends first rule in GNUNet suggests one could take
164 * large mac read sizes without fear of screwing up the proxied protocol,
165 * but we make a proper SOCKS5 client. */
166 #define register_reciever_wants(ih) ((SOCKS5_step_cmd == ih->step) ? 10 : 2)
169 struct GNUNET_CONNECTION_TransmitHandle *
170 register_sender (struct GNUNET_SOCKS_Handshake *ih);
174 * Conclude the SOCKS5 handshake successfully.
176 * @param ih SOCKS5 handshake, consumed here.
177 * @param c open unused connection, consumed here.
178 * @return Connection handle that becomes usable when the handshake completes.
181 SOCKS5_handshake_done(struct GNUNET_SOCKS_Handshake *ih)
183 GNUNET_CONNECTION_acivate_proxied (ih->target_connection);
188 * Read one step in the SOCKS5 handshake.
190 * @param ih SOCKS5 Handshake
193 SOCKS5_handshake_step (struct GNUNET_SOCKS_Handshake *ih)
195 unsigned char * b = ih->instart;
196 size_t available = ih->inend - b;
198 int want = register_reciever_wants(ih);
199 if (available < want) {
200 register_reciever (ih, want - available);
203 GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
205 case SOCKS5_step_greet: /* SOCKS5 server's greeting */
208 LOG (GNUNET_ERROR_TYPE_ERROR,
209 "Not a SOCKS5 server\n");
213 case SOCKS5_AUTH_NOAUTH:
214 ih->step=SOCKS5_step_cmd; /* no authentication to do */
216 case SOCKS5_AUTH_USERPASS:
217 ih->step=SOCKS5_step_auth;
219 case SOCKS5_AUTH_REJECT:
220 LOG (GNUNET_ERROR_TYPE_ERROR,
221 "No authentication method accepted\n");
224 LOG (GNUNET_ERROR_TYPE_ERROR,
225 "Not a SOCKS5 server / Nonsensical authentication\n");
230 case SOCKS5_step_auth: /* SOCKS5 server's responce to authentication */
233 LOG (GNUNET_ERROR_TYPE_ERROR,
234 "SOCKS5 authentication failed\n");
237 ih->step=SOCKS5_step_cmd;
240 case SOCKS5_step_cmd: /* SOCKS5 server's responce to command */
243 LOG (GNUNET_ERROR_TYPE_ERROR,
244 "SOCKS5 protocol error\n");
248 LOG (GNUNET_ERROR_TYPE_ERROR,
249 "SOCKS5 connection error : %s\n",
250 SOCKS5_REP_names(b[1]));
254 /* There is no reason to verify host and port afaik. */
257 b += sizeof(struct in_addr); /* 4 */
260 b += sizeof(struct in6_addr); /* 16 */
262 case 3: /* hostname */
268 register_reciever (ih, b - ih->inend);
271 ih->step = SOCKS5_step_done;
272 LOG (GNUNET_ERROR_TYPE_DEBUG,
273 "SOCKS5 server : %s\n",
274 SOCKS5_REP_names(b[1]));
276 SOCKS5_handshake_done (ih);
278 case SOCKS5_step_done:
282 /* Do not reschedule the sender unless we're done reading.
283 * I imagine this lets us avoid ever cancelling the transmit handle. */
284 register_sender (ih);
289 * Callback to read from the SOCKS5 proxy.
291 * @param client the service
292 * @param handler function to call with the message
293 * @param handler_cls closure for @a handler
297 const void *buf, size_t available,
298 const struct sockaddr * addr,
299 socklen_t addrlen, int errCode)
301 struct GNUNET_SOCKS_Handshake * ih = cls;
302 GNUNET_assert (&ih->inend[available] < &ih->inbuf[1024]);
303 GNUNET_memcpy(ih->inend, buf, available);
304 ih->inend += available;
305 SOCKS5_handshake_step (ih);
310 * Register callback to read from the SOCKS5 proxy.
312 * @param client the service
313 * @param handler function to call with the message
314 * @param handler_cls closure for @a handler
317 register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want)
319 GNUNET_CONNECTION_receive (ih->socks5_connection,
321 GNUNET_TIME_relative_get_minute_ (),
328 * Register SOCKS5 handshake sender
330 * @param cls closure (SOCKS handshake)
331 * @param size number of bytes available in @a buf
332 * @param buf where the callee should write the message
333 * @return number of bytes written to @a buf
336 transmit_ready (void *cls,
340 struct GNUNET_SOCKS_Handshake * ih = cls;
342 /* connection.c has many routines that call us with buf == NULL :
343 * signal_transmit_error() - DNS, etc. active
344 * connect_fail_continuation()
345 * connect_probe_continuation() - timeout
346 * try_connect_using_address() - DNS failure/timeout
347 * transmit_timeout() - retry failed?
348 * GNUNET_CONNECTION_notify_transmit_ready() can schedule :
349 * transmit_timeout() - DNS still working
350 * connect_error() - DNS done but no socket?
351 * transmit_ready() - scheduler shutdown or timeout, or signal_transmit_error()
352 * We'd need to dig into the scheduler to guess at the reason, as
353 * connection.c tells us nothing itself, but mostly its timouts.
354 * Initially, we'll simply ignore this and leave massive timeouts, but
355 * maybe that should change for error handling pruposes. It appears that
356 * successful operations, including DNS resolution, do not use this. */
361 LOG (GNUNET_ERROR_TYPE_WARNING,
362 "Timeout contacting SOCKS server, retrying indefinitely, but probably hopeless.\n");
363 register_sender (ih);
367 LOG (GNUNET_ERROR_TYPE_ERROR,
368 "Timeout during mid SOCKS handshake (step %u), probably not a SOCKS server.\n",
375 GNUNET_assert ( (1024 >= size) && (size > 0) );
376 GNUNET_assert ( (SOCKS5_step_done > ih->step) && (ih->step >= 0) );
377 unsigned char * b = ih->outstep[ih->step];
378 unsigned char * e = ih->outstep[ih->step+1];
379 GNUNET_assert (e <= &ih->outbuf[1024]);
380 unsigned int l = e - b;
381 GNUNET_assert (size >= l);
385 register_reciever (ih,
386 register_reciever_wants (ih));
392 * Register SOCKS5 handshake sender
394 * @param ih handshake
395 * @return non-NULL if the notify callback was queued,
396 * NULL if we are already going to notify someone else (busy)
398 struct GNUNET_CONNECTION_TransmitHandle *
399 register_sender (struct GNUNET_SOCKS_Handshake *ih)
401 struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_MINUTES;
403 GNUNET_assert (SOCKS5_step_done > ih->step);
404 GNUNET_assert (ih->step >= 0);
406 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3);
407 unsigned char * b = ih->outstep[ih->step];
408 unsigned char * e = ih->outstep[ih->step+1];
409 GNUNET_assert (ih->outbuf <= b && b < e && e < &ih->outbuf[1024]);
410 ih->th = GNUNET_CONNECTION_notify_transmit_ready (ih->socks5_connection,
420 * Initialize a SOCKS5 handshake for authentication via username and
421 * password. Tor uses SOCKS username and password authentication to assign
422 * programs unique circuits.
424 * @param user username for the proxy
425 * @param pass password for the proxy
426 * @return Valid SOCKS5 hanbdshake handle
428 struct GNUNET_SOCKS_Handshake *
429 GNUNET_SOCKS_init_handshake (const char *user, const char *pass)
431 struct GNUNET_SOCKS_Handshake *ih = GNUNET_new (struct GNUNET_SOCKS_Handshake);
432 unsigned char * b = ih->outbuf;
434 ih->outstep[SOCKS5_step_greet] = b;
435 *(b++) = 5; /* SOCKS5 */
436 unsigned char * n = b++;
437 *n = 1; /* Number of authentication methods */
438 /* We support no authentication even when requesting authentication,
439 * but this appears harmless, given the way that Tor uses authentication.
440 * And some SOCKS5 servers might require this. */
441 *(b++) = SOCKS5_AUTH_NOAUTH;
443 *(b++) = SOCKS5_AUTH_USERPASS;
446 /* There is no apperent reason to support authentication methods beyond
447 * username and password since afaik Tor does not support them. */
449 /* We authenticate with an empty username and password if the server demands
450 * them but we do not have any. */
456 ih->outstep[SOCKS5_step_auth] = b;
457 *(b++) = 1; /* subnegotiation ver.: 1 */
458 b = SOCK5_proto_string(b,user);
459 b = SOCK5_proto_string(b,pass);
461 ih->outstep[SOCKS5_step_cmd] = b;
463 ih->inend = ih->instart = ih->inbuf;
470 * Initialize a SOCKS5 handshake without authentication, thereby possibly
471 * sharing a Tor circuit with another process.
473 * @return Valid SOCKS5 hanbdshake handle
475 struct GNUNET_SOCKS_Handshake *
476 GNUNET_SOCKS_init_handshake_noauth ()
478 return GNUNET_SOCKS_init_handshake (NULL,NULL);
483 * Build request that the SOCKS5 proxy open a TCP/IP stream to the given host
486 * @param ih SOCKS5 handshake
491 GNUNET_SOCKS_set_handshake_destination (struct GNUNET_SOCKS_Handshake *ih,
492 const char *host, uint16_t port)
498 unsigned char * b = ih->outstep[SOCKS5_step_cmd];
500 *(b++) = 5; /* SOCKS5 */
501 *(b++) = 1; /* Establish a TCP/IP stream */
502 *(b++) = 0; /* reserved */
504 /* Specify destination */
505 if (1 == inet_pton(AF_INET,host,&ia.in4)) {
506 *(b++)= 1; /* IPv4 */
507 GNUNET_memcpy (b, &ia.in4, sizeof(struct in_addr));
508 b += sizeof(struct in_addr); /* 4 */
509 } else if (1 == inet_pton(AF_INET6,host,&ia.in6)) {
510 *(b++)= 4; /* IPv6 */
511 GNUNET_memcpy (b, &ia.in6, sizeof(struct in6_addr));
512 b += sizeof(struct in6_addr); /* 16 */
514 *(b++)= 3; /* hostname */
515 b = SOCK5_proto_string (b, host);
519 *(uint16_t*)b = htons (port);
522 ih->outstep[SOCKS5_step_done] = b;
527 * Run a SOCKS5 handshake on an open but unused TCP connection.
529 * @param ih SOCKS5 handshake, consumed here.
530 * @param c open unused connection, consumed here.
531 * @return Connection handle that becomes usable when the SOCKS5 handshake completes.
533 struct GNUNET_CONNECTION_Handle *
534 GNUNET_SOCKS_run_handshake(struct GNUNET_SOCKS_Handshake *ih,
535 struct GNUNET_CONNECTION_Handle *c)
537 ih->socks5_connection=c;
538 ih->target_connection = GNUNET_CONNECTION_create_proxied_from_handshake (c);
539 register_sender (ih);
541 return ih->target_connection;
546 * Check if a SOCKS proxy is required by a service. Do not use local service
547 * if a SOCKS proxy port is configured as this could deanonymize a user.
549 * @param service_name name of service to connect to
550 * @param cfg configuration to use
551 * @return GNUNET_YES if so, GNUNET_NO if not
554 GNUNET_SOCKS_check_service (const char *service_name,
555 const struct GNUNET_CONFIGURATION_Handle *cfg)
557 return GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSPORT") ||
558 GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSHOST");
563 * Try to connect to a service configured to use a SOCKS5 proxy.
565 * @param service_name name of service to connect to
566 * @param cfg configuration to use
567 * @return Connection handle that becomes usable when the handshake completes.
568 * NULL if SOCKS not configured or not configured properly
570 struct GNUNET_CONNECTION_Handle *
571 GNUNET_SOCKS_do_connect (const char *service_name,
572 const struct GNUNET_CONFIGURATION_Handle *cfg)
574 struct GNUNET_SOCKS_Handshake *ih;
575 struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */
580 unsigned long long port0;
581 unsigned long long port1;
584 GNUNET_SOCKS_check_service (service_name, cfg))
587 GNUNET_CONFIGURATION_get_value_number (cfg,
592 /* A typical Tor client should usually try port 9150 for the TBB too, but
593 * GNUnet can probably assume a system Tor installation. */
594 if (port0 > 65535 || port0 <= 0)
596 LOG (GNUNET_ERROR_TYPE_WARNING,
597 _("Attempting to use invalid port %d as SOCKS proxy for service `%s'.\n"),
603 GNUNET_CONFIGURATION_get_value_number (cfg,
610 GNUNET_CONFIGURATION_get_value_string (cfg,
615 LOG (GNUNET_ERROR_TYPE_WARNING,
616 _("Attempting to proxy service `%s' to invalid port %d or hostname.\n"),
621 /* Appeared to still work after host0 corrupted, so either test case is broken, or
622 this whole routine is not being called. */
624 GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0))
626 socks5 = GNUNET_CONNECTION_create_from_connect (cfg,
631 GNUNET_free_non_null (host0);
633 /* Sets to NULL if they do not exist */
634 (void) GNUNET_CONFIGURATION_get_value_string (cfg,
638 (void) GNUNET_CONFIGURATION_get_value_string (cfg,
642 ih = GNUNET_SOCKS_init_handshake(user,pass);
643 GNUNET_free_non_null (user);
644 GNUNET_free_non_null (pass);
646 GNUNET_SOCKS_set_handshake_destination (ih,
650 return GNUNET_SOCKS_run_handshake (ih,