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/>.
21 * @brief SOCKS5 connection support
22 * @author Jeffrey Burdges
24 * These routines should be called only on newly active connections.
27 #include "gnunet_util_lib.h"
30 #define LOG(kind,...) GNUNET_log_from (kind, "util-socks", __VA_ARGS__)
32 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-socks", syscall)
35 /* SOCKS5 authentication methods */
36 #define SOCKS5_AUTH_REJECT 0xFF /* No acceptable auth method */
37 #define SOCKS5_AUTH_NOAUTH 0x00 /* without authentication */
38 #define SOCKS5_AUTH_GSSAPI 0x01 /* GSSAPI */
39 #define SOCKS5_AUTH_USERPASS 0x02 /* User/Password */
40 #define SOCKS5_AUTH_CHAP 0x03 /* Challenge-Handshake Auth Proto. */
41 #define SOCKS5_AUTH_EAP 0x05 /* Extensible Authentication Proto. */
42 #define SOCKS5_AUTH_MAF 0x08 /* Multi-Authentication Framework */
45 /* SOCKS5 connection responces */
46 #define SOCKS5_REP_SUCCEEDED 0x00 /* succeeded */
47 #define SOCKS5_REP_FAIL 0x01 /* general SOCKS serer failure */
48 #define SOCKS5_REP_NALLOWED 0x02 /* connection not allowed by ruleset */
49 #define SOCKS5_REP_NUNREACH 0x03 /* Network unreachable */
50 #define SOCKS5_REP_HUNREACH 0x04 /* Host unreachable */
51 #define SOCKS5_REP_REFUSED 0x05 /* connection refused */
52 #define SOCKS5_REP_EXPIRED 0x06 /* TTL expired */
53 #define SOCKS5_REP_CNOTSUP 0x07 /* Command not supported */
54 #define SOCKS5_REP_ANOTSUP 0x08 /* Address not supported */
55 #define SOCKS5_REP_INVADDR 0x09 /* Inalid address */
57 const char * SOCKS5_REP_names(int rep)
60 case SOCKS5_REP_SUCCEEDED: return "succeeded";
61 case SOCKS5_REP_FAIL: return "general SOCKS server failure";
62 case SOCKS5_REP_NALLOWED: return "connection not allowed by ruleset";
63 case SOCKS5_REP_NUNREACH: return "Network unreachable";
64 case SOCKS5_REP_HUNREACH: return "Host unreachable";
65 case SOCKS5_REP_REFUSED: return "connection refused";
66 case SOCKS5_REP_EXPIRED: return "TTL expired";
67 case SOCKS5_REP_CNOTSUP: return "Command not supported";
68 case SOCKS5_REP_ANOTSUP: return "Address not supported";
69 case SOCKS5_REP_INVADDR: return "Invalid address";
76 * Encode a string for the SOCKS5 protocol by prefixing it a byte stating its
77 * length and stipping the trailing zero byte. Truncates any string longer
80 * @param b buffer to contain the encoded string
81 * @param s string to encode
82 * @return pointer to the end of the encoded string in the buffer
85 SOCK5_proto_string(unsigned char * b,
92 LOG (GNUNET_ERROR_TYPE_WARNING,
93 "SOCKS5 cannot handle hostnames, usernames, or passwords over 255 bytes, truncating.\n");
96 *(b++) = (unsigned char) l;
97 strncpy ((char *)b, s, l);
102 #define SOCKS5_step_greet 0
103 #define SOCKS5_step_auth 1
104 #define SOCKS5_step_cmd 2
105 #define SOCKS5_step_done 3
108 * State of the SOCKS5 handshake.
110 struct GNUNET_SOCKS_Handshake
114 * Connection handle used for SOCKS5
116 struct GNUNET_CONNECTION_Handle *socks5_connection;
119 * Connection handle initially returned to client
121 struct GNUNET_CONNECTION_Handle *target_connection;
124 * Transmission handle on socks5_connection.
126 struct GNUNET_CONNECTION_TransmitHandle *th;
129 * Our stage in the SOCKS5 handshake
134 * Precomputed SOCKS5 handshake ouput buffer
136 unsigned char outbuf[1024];
139 * Pointers delineating protoocol steps in the outbut buffer
141 unsigned char * (outstep[4]);
144 * SOCKS5 handshake input buffer
146 unsigned char inbuf[1024];
149 * Pointers delimiting the current step in the input buffer
151 unsigned char * instart;
152 unsigned char * inend;
156 /* Regitering prototypes */
159 register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want);
161 /* In fact, the client sends first rule in GNUNet suggests one could take
162 * large mac read sizes without fear of screwing up the proxied protocol,
163 * but we make a proper SOCKS5 client. */
164 #define register_reciever_wants(ih) ((SOCKS5_step_cmd == ih->step) ? 10 : 2)
167 struct GNUNET_CONNECTION_TransmitHandle *
168 register_sender (struct GNUNET_SOCKS_Handshake *ih);
172 * Conclude the SOCKS5 handshake successfully.
174 * @param ih SOCKS5 handshake, consumed here.
175 * @param c open unused connection, consumed here.
176 * @return Connection handle that becomes usable when the handshake completes.
179 SOCKS5_handshake_done(struct GNUNET_SOCKS_Handshake *ih)
181 GNUNET_CONNECTION_acivate_proxied (ih->target_connection);
186 * Read one step in the SOCKS5 handshake.
188 * @param ih SOCKS5 Handshake
191 SOCKS5_handshake_step (struct GNUNET_SOCKS_Handshake *ih)
193 unsigned char * b = ih->instart;
194 size_t available = ih->inend - b;
196 int want = register_reciever_wants(ih);
197 if (available < want) {
198 register_reciever (ih, want - available);
201 GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
203 case SOCKS5_step_greet: /* SOCKS5 server's greeting */
206 LOG (GNUNET_ERROR_TYPE_ERROR,
207 "Not a SOCKS5 server\n");
211 case SOCKS5_AUTH_NOAUTH:
212 ih->step=SOCKS5_step_cmd; /* no authentication to do */
214 case SOCKS5_AUTH_USERPASS:
215 ih->step=SOCKS5_step_auth;
217 case SOCKS5_AUTH_REJECT:
218 LOG (GNUNET_ERROR_TYPE_ERROR,
219 "No authentication method accepted\n");
222 LOG (GNUNET_ERROR_TYPE_ERROR,
223 "Not a SOCKS5 server / Nonsensical authentication\n");
228 case SOCKS5_step_auth: /* SOCKS5 server's responce to authentication */
231 LOG (GNUNET_ERROR_TYPE_ERROR,
232 "SOCKS5 authentication failed\n");
235 ih->step=SOCKS5_step_cmd;
238 case SOCKS5_step_cmd: /* SOCKS5 server's responce to command */
241 LOG (GNUNET_ERROR_TYPE_ERROR,
242 "SOCKS5 protocol error\n");
246 LOG (GNUNET_ERROR_TYPE_ERROR,
247 "SOCKS5 connection error : %s\n",
248 SOCKS5_REP_names(b[1]));
252 /* There is no reason to verify host and port afaik. */
255 b += sizeof(struct in_addr); /* 4 */
258 b += sizeof(struct in6_addr); /* 16 */
260 case 3: /* hostname */
266 register_reciever (ih, b - ih->inend);
269 ih->step = SOCKS5_step_done;
270 LOG (GNUNET_ERROR_TYPE_DEBUG,
271 "SOCKS5 server : %s\n",
272 SOCKS5_REP_names(b[1]));
274 SOCKS5_handshake_done (ih);
276 case SOCKS5_step_done:
280 /* Do not reschedule the sender unless we're done reading.
281 * I imagine this lets us avoid ever cancelling the transmit handle. */
282 register_sender (ih);
287 * Callback to read from the SOCKS5 proxy.
289 * @param client the service
290 * @param handler function to call with the message
291 * @param handler_cls closure for @a handler
295 const void *buf, size_t available,
296 const struct sockaddr * addr,
297 socklen_t addrlen, int errCode)
299 struct GNUNET_SOCKS_Handshake * ih = cls;
300 GNUNET_assert (&ih->inend[available] < &ih->inbuf[1024]);
301 GNUNET_memcpy(ih->inend, buf, available);
302 ih->inend += available;
303 SOCKS5_handshake_step (ih);
308 * Register callback to read from the SOCKS5 proxy.
310 * @param client the service
311 * @param handler function to call with the message
312 * @param handler_cls closure for @a handler
315 register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want)
317 GNUNET_CONNECTION_receive (ih->socks5_connection,
319 GNUNET_TIME_relative_get_minute_ (),
326 * Register SOCKS5 handshake sender
328 * @param cls closure (SOCKS handshake)
329 * @param size number of bytes available in @a buf
330 * @param buf where the callee should write the message
331 * @return number of bytes written to @a buf
334 transmit_ready (void *cls,
338 struct GNUNET_SOCKS_Handshake * ih = cls;
340 /* connection.c has many routines that call us with buf == NULL :
341 * signal_transmit_error() - DNS, etc. active
342 * connect_fail_continuation()
343 * connect_probe_continuation() - timeout
344 * try_connect_using_address() - DNS failure/timeout
345 * transmit_timeout() - retry failed?
346 * GNUNET_CONNECTION_notify_transmit_ready() can schedule :
347 * transmit_timeout() - DNS still working
348 * connect_error() - DNS done but no socket?
349 * transmit_ready() - scheduler shutdown or timeout, or signal_transmit_error()
350 * We'd need to dig into the scheduler to guess at the reason, as
351 * connection.c tells us nothing itself, but mostly its timouts.
352 * Initially, we'll simply ignore this and leave massive timeouts, but
353 * maybe that should change for error handling pruposes. It appears that
354 * successful operations, including DNS resolution, do not use this. */
359 LOG (GNUNET_ERROR_TYPE_WARNING,
360 "Timeout contacting SOCKS server, retrying indefinitely, but probably hopeless.\n");
361 register_sender (ih);
365 LOG (GNUNET_ERROR_TYPE_ERROR,
366 "Timeout during mid SOCKS handshake (step %u), probably not a SOCKS server.\n",
373 GNUNET_assert ( (1024 >= size) && (size > 0) );
374 GNUNET_assert ( (SOCKS5_step_done > ih->step) && (ih->step >= 0) );
375 unsigned char * b = ih->outstep[ih->step];
376 unsigned char * e = ih->outstep[ih->step+1];
377 GNUNET_assert (e <= &ih->outbuf[1024]);
378 unsigned int l = e - b;
379 GNUNET_assert (size >= l);
383 register_reciever (ih,
384 register_reciever_wants (ih));
390 * Register SOCKS5 handshake sender
392 * @param ih handshake
393 * @return non-NULL if the notify callback was queued,
394 * NULL if we are already going to notify someone else (busy)
396 struct GNUNET_CONNECTION_TransmitHandle *
397 register_sender (struct GNUNET_SOCKS_Handshake *ih)
399 struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_MINUTES;
401 GNUNET_assert (SOCKS5_step_done > ih->step);
402 GNUNET_assert (ih->step >= 0);
404 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3);
405 unsigned char * b = ih->outstep[ih->step];
406 unsigned char * e = ih->outstep[ih->step+1];
407 GNUNET_assert (ih->outbuf <= b && b < e && e < &ih->outbuf[1024]);
408 ih->th = GNUNET_CONNECTION_notify_transmit_ready (ih->socks5_connection,
418 * Initialize a SOCKS5 handshake for authentication via username and
419 * password. Tor uses SOCKS username and password authentication to assign
420 * programs unique circuits.
422 * @param user username for the proxy
423 * @param pass password for the proxy
424 * @return Valid SOCKS5 hanbdshake handle
426 struct GNUNET_SOCKS_Handshake *
427 GNUNET_SOCKS_init_handshake (const char *user, const char *pass)
429 struct GNUNET_SOCKS_Handshake *ih = GNUNET_new (struct GNUNET_SOCKS_Handshake);
430 unsigned char * b = ih->outbuf;
432 ih->outstep[SOCKS5_step_greet] = b;
433 *(b++) = 5; /* SOCKS5 */
434 unsigned char * n = b++;
435 *n = 1; /* Number of authentication methods */
436 /* We support no authentication even when requesting authentication,
437 * but this appears harmless, given the way that Tor uses authentication.
438 * And some SOCKS5 servers might require this. */
439 *(b++) = SOCKS5_AUTH_NOAUTH;
441 *(b++) = SOCKS5_AUTH_USERPASS;
444 /* There is no apperent reason to support authentication methods beyond
445 * username and password since afaik Tor does not support them. */
447 /* We authenticate with an empty username and password if the server demands
448 * them but we do not have any. */
454 ih->outstep[SOCKS5_step_auth] = b;
455 *(b++) = 1; /* subnegotiation ver.: 1 */
456 b = SOCK5_proto_string(b,user);
457 b = SOCK5_proto_string(b,pass);
459 ih->outstep[SOCKS5_step_cmd] = b;
461 ih->inend = ih->instart = ih->inbuf;
468 * Initialize a SOCKS5 handshake without authentication, thereby possibly
469 * sharing a Tor circuit with another process.
471 * @return Valid SOCKS5 hanbdshake handle
473 struct GNUNET_SOCKS_Handshake *
474 GNUNET_SOCKS_init_handshake_noauth ()
476 return GNUNET_SOCKS_init_handshake (NULL,NULL);
481 * Build request that the SOCKS5 proxy open a TCP/IP stream to the given host
484 * @param ih SOCKS5 handshake
489 GNUNET_SOCKS_set_handshake_destination (struct GNUNET_SOCKS_Handshake *ih,
490 const char *host, uint16_t port)
496 unsigned char * b = ih->outstep[SOCKS5_step_cmd];
498 *(b++) = 5; /* SOCKS5 */
499 *(b++) = 1; /* Establish a TCP/IP stream */
500 *(b++) = 0; /* reserved */
502 /* Specify destination */
503 if (1 == inet_pton(AF_INET,host,&ia.in4)) {
504 *(b++)= 1; /* IPv4 */
505 GNUNET_memcpy (b, &ia.in4, sizeof(struct in_addr));
506 b += sizeof(struct in_addr); /* 4 */
507 } else if (1 == inet_pton(AF_INET6,host,&ia.in6)) {
508 *(b++)= 4; /* IPv6 */
509 GNUNET_memcpy (b, &ia.in6, sizeof(struct in6_addr));
510 b += sizeof(struct in6_addr); /* 16 */
512 *(b++)= 3; /* hostname */
513 b = SOCK5_proto_string (b, host);
517 *(uint16_t*)b = htons (port);
520 ih->outstep[SOCKS5_step_done] = b;
525 * Run a SOCKS5 handshake on an open but unused TCP connection.
527 * @param ih SOCKS5 handshake, consumed here.
528 * @param c open unused connection, consumed here.
529 * @return Connection handle that becomes usable when the SOCKS5 handshake completes.
531 struct GNUNET_CONNECTION_Handle *
532 GNUNET_SOCKS_run_handshake(struct GNUNET_SOCKS_Handshake *ih,
533 struct GNUNET_CONNECTION_Handle *c)
535 ih->socks5_connection=c;
536 ih->target_connection = GNUNET_CONNECTION_create_proxied_from_handshake (c);
537 register_sender (ih);
539 return ih->target_connection;
544 * Check if a SOCKS proxy is required by a service. Do not use local service
545 * if a SOCKS proxy port is configured as this could deanonymize a user.
547 * @param service_name name of service to connect to
548 * @param cfg configuration to use
549 * @return GNUNET_YES if so, GNUNET_NO if not
552 GNUNET_SOCKS_check_service (const char *service_name,
553 const struct GNUNET_CONFIGURATION_Handle *cfg)
555 return GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSPORT") ||
556 GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSHOST");
561 * Try to connect to a service configured to use a SOCKS5 proxy.
563 * @param service_name name of service to connect to
564 * @param cfg configuration to use
565 * @return Connection handle that becomes usable when the handshake completes.
566 * NULL if SOCKS not configured or not configured properly
568 struct GNUNET_CONNECTION_Handle *
569 GNUNET_SOCKS_do_connect (const char *service_name,
570 const struct GNUNET_CONFIGURATION_Handle *cfg)
572 struct GNUNET_SOCKS_Handshake *ih;
573 struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */
578 unsigned long long port0;
579 unsigned long long port1;
582 GNUNET_SOCKS_check_service (service_name, cfg))
585 GNUNET_CONFIGURATION_get_value_number (cfg,
590 /* A typical Tor client should usually try port 9150 for the TBB too, but
591 * GNUnet can probably assume a system Tor installation. */
592 if (port0 > 65535 || port0 <= 0)
594 LOG (GNUNET_ERROR_TYPE_WARNING,
595 _("Attempting to use invalid port %d as SOCKS proxy for service `%s'.\n"),
601 GNUNET_CONFIGURATION_get_value_number (cfg,
608 GNUNET_CONFIGURATION_get_value_string (cfg,
613 LOG (GNUNET_ERROR_TYPE_WARNING,
614 _("Attempting to proxy service `%s' to invalid port %d or hostname.\n"),
619 /* Appeared to still work after host0 corrupted, so either test case is broken, or
620 this whole routine is not being called. */
622 GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0))
624 socks5 = GNUNET_CONNECTION_create_from_connect (cfg,
629 GNUNET_free_non_null (host0);
631 /* Sets to NULL if they do not exist */
632 (void) GNUNET_CONFIGURATION_get_value_string (cfg,
636 (void) GNUNET_CONFIGURATION_get_value_string (cfg,
640 ih = GNUNET_SOCKS_init_handshake(user,pass);
641 GNUNET_free_non_null (user);
642 GNUNET_free_non_null (pass);
644 GNUNET_SOCKS_set_handshake_destination (ih,
648 return GNUNET_SOCKS_run_handshake (ih,