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.
18 * @brief SOCKS5 connection support
19 * @author Jeffrey Burdges
21 * These routines should be called only on newly active connections.
24 #include "gnunet_util_lib.h"
27 #define LOG(kind,...) GNUNET_log_from (kind, "util-socks", __VA_ARGS__)
29 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-socks", syscall)
32 /* SOCKS5 authentication methods */
33 #define SOCKS5_AUTH_REJECT 0xFF /* No acceptable auth method */
34 #define SOCKS5_AUTH_NOAUTH 0x00 /* without authentication */
35 #define SOCKS5_AUTH_GSSAPI 0x01 /* GSSAPI */
36 #define SOCKS5_AUTH_USERPASS 0x02 /* User/Password */
37 #define SOCKS5_AUTH_CHAP 0x03 /* Challenge-Handshake Auth Proto. */
38 #define SOCKS5_AUTH_EAP 0x05 /* Extensible Authentication Proto. */
39 #define SOCKS5_AUTH_MAF 0x08 /* Multi-Authentication Framework */
42 /* SOCKS5 connection responces */
43 #define SOCKS5_REP_SUCCEEDED 0x00 /* succeeded */
44 #define SOCKS5_REP_FAIL 0x01 /* general SOCKS serer failure */
45 #define SOCKS5_REP_NALLOWED 0x02 /* connection not allowed by ruleset */
46 #define SOCKS5_REP_NUNREACH 0x03 /* Network unreachable */
47 #define SOCKS5_REP_HUNREACH 0x04 /* Host unreachable */
48 #define SOCKS5_REP_REFUSED 0x05 /* connection refused */
49 #define SOCKS5_REP_EXPIRED 0x06 /* TTL expired */
50 #define SOCKS5_REP_CNOTSUP 0x07 /* Command not supported */
51 #define SOCKS5_REP_ANOTSUP 0x08 /* Address not supported */
52 #define SOCKS5_REP_INVADDR 0x09 /* Inalid address */
54 const char * SOCKS5_REP_names(int rep)
57 case SOCKS5_REP_SUCCEEDED: return "succeeded";
58 case SOCKS5_REP_FAIL: return "general SOCKS server failure";
59 case SOCKS5_REP_NALLOWED: return "connection not allowed by ruleset";
60 case SOCKS5_REP_NUNREACH: return "Network unreachable";
61 case SOCKS5_REP_HUNREACH: return "Host unreachable";
62 case SOCKS5_REP_REFUSED: return "connection refused";
63 case SOCKS5_REP_EXPIRED: return "TTL expired";
64 case SOCKS5_REP_CNOTSUP: return "Command not supported";
65 case SOCKS5_REP_ANOTSUP: return "Address not supported";
66 case SOCKS5_REP_INVADDR: return "Invalid address";
73 * Encode a string for the SOCKS5 protocol by prefixing it a byte stating its
74 * length and stipping the trailing zero byte. Truncates any string longer
77 * @param b buffer to contain the encoded string
78 * @param s string to encode
79 * @return pointer to the end of the encoded string in the buffer
82 SOCK5_proto_string(unsigned char * b,
89 LOG (GNUNET_ERROR_TYPE_WARNING,
90 "SOCKS5 cannot handle hostnames, usernames, or passwords over 255 bytes, truncating.\n");
93 *(b++) = (unsigned char) l;
94 strncpy ((char *)b, s, l);
99 #define SOCKS5_step_greet 0
100 #define SOCKS5_step_auth 1
101 #define SOCKS5_step_cmd 2
102 #define SOCKS5_step_done 3
105 * State of the SOCKS5 handshake.
107 struct GNUNET_SOCKS_Handshake
111 * Connection handle used for SOCKS5
113 struct GNUNET_CONNECTION_Handle *socks5_connection;
116 * Connection handle initially returned to client
118 struct GNUNET_CONNECTION_Handle *target_connection;
121 * Transmission handle on socks5_connection.
123 struct GNUNET_CONNECTION_TransmitHandle *th;
126 * Our stage in the SOCKS5 handshake
131 * Precomputed SOCKS5 handshake ouput buffer
133 unsigned char outbuf[1024];
136 * Pointers delineating protoocol steps in the outbut buffer
138 unsigned char * (outstep[4]);
141 * SOCKS5 handshake input buffer
143 unsigned char inbuf[1024];
146 * Pointers delimiting the current step in the input buffer
148 unsigned char * instart;
149 unsigned char * inend;
153 /* Regitering prototypes */
156 register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want);
158 /* In fact, the client sends first rule in GNUNet suggests one could take
159 * large mac read sizes without fear of screwing up the proxied protocol,
160 * but we make a proper SOCKS5 client. */
161 #define register_reciever_wants(ih) ((SOCKS5_step_cmd == ih->step) ? 10 : 2)
164 struct GNUNET_CONNECTION_TransmitHandle *
165 register_sender (struct GNUNET_SOCKS_Handshake *ih);
169 * Conclude the SOCKS5 handshake successfully.
171 * @param ih SOCKS5 handshake, consumed here.
172 * @param c open unused connection, consumed here.
173 * @return Connection handle that becomes usable when the handshake completes.
176 SOCKS5_handshake_done(struct GNUNET_SOCKS_Handshake *ih)
178 GNUNET_CONNECTION_acivate_proxied (ih->target_connection);
183 * Read one step in the SOCKS5 handshake.
185 * @param ih SOCKS5 Handshake
188 SOCKS5_handshake_step (struct GNUNET_SOCKS_Handshake *ih)
190 unsigned char * b = ih->instart;
191 size_t available = ih->inend - b;
193 int want = register_reciever_wants(ih);
194 if (available < want) {
195 register_reciever (ih, want - available);
198 GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
200 case SOCKS5_step_greet: /* SOCKS5 server's greeting */
203 LOG (GNUNET_ERROR_TYPE_ERROR,
204 "Not a SOCKS5 server\n");
208 case SOCKS5_AUTH_NOAUTH:
209 ih->step=SOCKS5_step_cmd; /* no authentication to do */
211 case SOCKS5_AUTH_USERPASS:
212 ih->step=SOCKS5_step_auth;
214 case SOCKS5_AUTH_REJECT:
215 LOG (GNUNET_ERROR_TYPE_ERROR,
216 "No authentication method accepted\n");
219 LOG (GNUNET_ERROR_TYPE_ERROR,
220 "Not a SOCKS5 server / Nonsensical authentication\n");
225 case SOCKS5_step_auth: /* SOCKS5 server's responce to authentication */
228 LOG (GNUNET_ERROR_TYPE_ERROR,
229 "SOCKS5 authentication failed\n");
232 ih->step=SOCKS5_step_cmd;
235 case SOCKS5_step_cmd: /* SOCKS5 server's responce to command */
238 LOG (GNUNET_ERROR_TYPE_ERROR,
239 "SOCKS5 protocol error\n");
243 LOG (GNUNET_ERROR_TYPE_ERROR,
244 "SOCKS5 connection error : %s\n",
245 SOCKS5_REP_names(b[1]));
249 /* There is no reason to verify host and port afaik. */
252 b += sizeof(struct in_addr); /* 4 */
255 b += sizeof(struct in6_addr); /* 16 */
257 case 3: /* hostname */
263 register_reciever (ih, b - ih->inend);
266 ih->step = SOCKS5_step_done;
267 LOG (GNUNET_ERROR_TYPE_DEBUG,
268 "SOCKS5 server : %s\n",
269 SOCKS5_REP_names(b[1]));
271 SOCKS5_handshake_done (ih);
273 case SOCKS5_step_done:
277 /* Do not reschedule the sender unless we're done reading.
278 * I imagine this lets us avoid ever cancelling the transmit handle. */
279 register_sender (ih);
284 * Callback to read from the SOCKS5 proxy.
286 * @param client the service
287 * @param handler function to call with the message
288 * @param handler_cls closure for @a handler
292 const void *buf, size_t available,
293 const struct sockaddr * addr,
294 socklen_t addrlen, int errCode)
296 struct GNUNET_SOCKS_Handshake * ih = cls;
297 GNUNET_assert (&ih->inend[available] < &ih->inbuf[1024]);
298 GNUNET_memcpy(ih->inend, buf, available);
299 ih->inend += available;
300 SOCKS5_handshake_step (ih);
305 * Register callback to read from the SOCKS5 proxy.
307 * @param client the service
308 * @param handler function to call with the message
309 * @param handler_cls closure for @a handler
312 register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want)
314 GNUNET_CONNECTION_receive (ih->socks5_connection,
316 GNUNET_TIME_relative_get_minute_ (),
323 * Register SOCKS5 handshake sender
325 * @param cls closure (SOCKS handshake)
326 * @param size number of bytes available in @a buf
327 * @param buf where the callee should write the message
328 * @return number of bytes written to @a buf
331 transmit_ready (void *cls,
335 struct GNUNET_SOCKS_Handshake * ih = cls;
337 /* connection.c has many routines that call us with buf == NULL :
338 * signal_transmit_error() - DNS, etc. active
339 * connect_fail_continuation()
340 * connect_probe_continuation() - timeout
341 * try_connect_using_address() - DNS failure/timeout
342 * transmit_timeout() - retry failed?
343 * GNUNET_CONNECTION_notify_transmit_ready() can schedule :
344 * transmit_timeout() - DNS still working
345 * connect_error() - DNS done but no socket?
346 * transmit_ready() - scheduler shutdown or timeout, or signal_transmit_error()
347 * We'd need to dig into the scheduler to guess at the reason, as
348 * connection.c tells us nothing itself, but mostly its timouts.
349 * Initially, we'll simply ignore this and leave massive timeouts, but
350 * maybe that should change for error handling pruposes. It appears that
351 * successful operations, including DNS resolution, do not use this. */
356 LOG (GNUNET_ERROR_TYPE_WARNING,
357 "Timeout contacting SOCKS server, retrying indefinitely, but probably hopeless.\n");
358 register_sender (ih);
362 LOG (GNUNET_ERROR_TYPE_ERROR,
363 "Timeout during mid SOCKS handshake (step %u), probably not a SOCKS server.\n",
370 GNUNET_assert ( (1024 >= size) && (size > 0) );
371 GNUNET_assert ( (SOCKS5_step_done > ih->step) && (ih->step >= 0) );
372 unsigned char * b = ih->outstep[ih->step];
373 unsigned char * e = ih->outstep[ih->step+1];
374 GNUNET_assert (e <= &ih->outbuf[1024]);
375 unsigned int l = e - b;
376 GNUNET_assert (size >= l);
380 register_reciever (ih,
381 register_reciever_wants (ih));
387 * Register SOCKS5 handshake sender
389 * @param ih handshake
390 * @return non-NULL if the notify callback was queued,
391 * NULL if we are already going to notify someone else (busy)
393 struct GNUNET_CONNECTION_TransmitHandle *
394 register_sender (struct GNUNET_SOCKS_Handshake *ih)
396 struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_MINUTES;
398 GNUNET_assert (SOCKS5_step_done > ih->step);
399 GNUNET_assert (ih->step >= 0);
401 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3);
402 unsigned char * b = ih->outstep[ih->step];
403 unsigned char * e = ih->outstep[ih->step+1];
404 GNUNET_assert (ih->outbuf <= b && b < e && e < &ih->outbuf[1024]);
405 ih->th = GNUNET_CONNECTION_notify_transmit_ready (ih->socks5_connection,
415 * Initialize a SOCKS5 handshake for authentication via username and
416 * password. Tor uses SOCKS username and password authentication to assign
417 * programs unique circuits.
419 * @param user username for the proxy
420 * @param pass password for the proxy
421 * @return Valid SOCKS5 hanbdshake handle
423 struct GNUNET_SOCKS_Handshake *
424 GNUNET_SOCKS_init_handshake (const char *user, const char *pass)
426 struct GNUNET_SOCKS_Handshake *ih = GNUNET_new (struct GNUNET_SOCKS_Handshake);
427 unsigned char * b = ih->outbuf;
429 ih->outstep[SOCKS5_step_greet] = b;
430 *(b++) = 5; /* SOCKS5 */
431 unsigned char * n = b++;
432 *n = 1; /* Number of authentication methods */
433 /* We support no authentication even when requesting authentication,
434 * but this appears harmless, given the way that Tor uses authentication.
435 * And some SOCKS5 servers might require this. */
436 *(b++) = SOCKS5_AUTH_NOAUTH;
438 *(b++) = SOCKS5_AUTH_USERPASS;
441 /* There is no apperent reason to support authentication methods beyond
442 * username and password since afaik Tor does not support them. */
444 /* We authenticate with an empty username and password if the server demands
445 * them but we do not have any. */
451 ih->outstep[SOCKS5_step_auth] = b;
452 *(b++) = 1; /* subnegotiation ver.: 1 */
453 b = SOCK5_proto_string(b,user);
454 b = SOCK5_proto_string(b,pass);
456 ih->outstep[SOCKS5_step_cmd] = b;
458 ih->inend = ih->instart = ih->inbuf;
465 * Initialize a SOCKS5 handshake without authentication, thereby possibly
466 * sharing a Tor circuit with another process.
468 * @return Valid SOCKS5 hanbdshake handle
470 struct GNUNET_SOCKS_Handshake *
471 GNUNET_SOCKS_init_handshake_noauth ()
473 return GNUNET_SOCKS_init_handshake (NULL,NULL);
478 * Build request that the SOCKS5 proxy open a TCP/IP stream to the given host
481 * @param ih SOCKS5 handshake
486 GNUNET_SOCKS_set_handshake_destination (struct GNUNET_SOCKS_Handshake *ih,
487 const char *host, uint16_t port)
493 unsigned char * b = ih->outstep[SOCKS5_step_cmd];
495 *(b++) = 5; /* SOCKS5 */
496 *(b++) = 1; /* Establish a TCP/IP stream */
497 *(b++) = 0; /* reserved */
499 /* Specify destination */
500 if (1 == inet_pton(AF_INET,host,&ia.in4)) {
501 *(b++)= 1; /* IPv4 */
502 GNUNET_memcpy (b, &ia.in4, sizeof(struct in_addr));
503 b += sizeof(struct in_addr); /* 4 */
504 } else if (1 == inet_pton(AF_INET6,host,&ia.in6)) {
505 *(b++)= 4; /* IPv6 */
506 GNUNET_memcpy (b, &ia.in6, sizeof(struct in6_addr));
507 b += sizeof(struct in6_addr); /* 16 */
509 *(b++)= 3; /* hostname */
510 b = SOCK5_proto_string (b, host);
514 *(uint16_t*)b = htons (port);
517 ih->outstep[SOCKS5_step_done] = b;
522 * Run a SOCKS5 handshake on an open but unused TCP connection.
524 * @param ih SOCKS5 handshake, consumed here.
525 * @param c open unused connection, consumed here.
526 * @return Connection handle that becomes usable when the SOCKS5 handshake completes.
528 struct GNUNET_CONNECTION_Handle *
529 GNUNET_SOCKS_run_handshake(struct GNUNET_SOCKS_Handshake *ih,
530 struct GNUNET_CONNECTION_Handle *c)
532 ih->socks5_connection=c;
533 ih->target_connection = GNUNET_CONNECTION_create_proxied_from_handshake (c);
534 register_sender (ih);
536 return ih->target_connection;
541 * Check if a SOCKS proxy is required by a service. Do not use local service
542 * if a SOCKS proxy port is configured as this could deanonymize a user.
544 * @param service_name name of service to connect to
545 * @param cfg configuration to use
546 * @return GNUNET_YES if so, GNUNET_NO if not
549 GNUNET_SOCKS_check_service (const char *service_name,
550 const struct GNUNET_CONFIGURATION_Handle *cfg)
552 return GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSPORT") ||
553 GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSHOST");
558 * Try to connect to a service configured to use a SOCKS5 proxy.
560 * @param service_name name of service to connect to
561 * @param cfg configuration to use
562 * @return Connection handle that becomes usable when the handshake completes.
563 * NULL if SOCKS not configured or not configured properly
565 struct GNUNET_CONNECTION_Handle *
566 GNUNET_SOCKS_do_connect (const char *service_name,
567 const struct GNUNET_CONFIGURATION_Handle *cfg)
569 struct GNUNET_SOCKS_Handshake *ih;
570 struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */
575 unsigned long long port0;
576 unsigned long long port1;
579 GNUNET_SOCKS_check_service (service_name, cfg))
582 GNUNET_CONFIGURATION_get_value_number (cfg,
587 /* A typical Tor client should usually try port 9150 for the TBB too, but
588 * GNUnet can probably assume a system Tor installation. */
589 if (port0 > 65535 || port0 <= 0)
591 LOG (GNUNET_ERROR_TYPE_WARNING,
592 _("Attempting to use invalid port %d as SOCKS proxy for service `%s'.\n"),
598 GNUNET_CONFIGURATION_get_value_number (cfg,
605 GNUNET_CONFIGURATION_get_value_string (cfg,
610 LOG (GNUNET_ERROR_TYPE_WARNING,
611 _("Attempting to proxy service `%s' to invalid port %d or hostname.\n"),
616 /* Appeared to still work after host0 corrupted, so either test case is broken, or
617 this whole routine is not being called. */
619 GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0))
621 socks5 = GNUNET_CONNECTION_create_from_connect (cfg,
626 GNUNET_free_non_null (host0);
628 /* Sets to NULL if they do not exist */
629 (void) GNUNET_CONFIGURATION_get_value_string (cfg,
633 (void) GNUNET_CONFIGURATION_get_value_string (cfg,
637 ih = GNUNET_SOCKS_init_handshake(user,pass);
638 GNUNET_free_non_null (user);
639 GNUNET_free_non_null (pass);
641 GNUNET_SOCKS_set_handshake_destination (ih,
645 return GNUNET_SOCKS_run_handshake (ih,