2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 Jeffrey Burdges (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
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, "socks", __VA_ARGS__)
34 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "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
86 unsigned char * SOCK5_proto_string(unsigned char * b, const char * s)
90 LOG (GNUNET_ERROR_TYPE_WARNING,
91 "SOCKS5 cannot handle hostnames, usernames, or passwords over 255 bytes, truncating.\n");
94 *(b++) = (unsigned char)l;
95 strncpy((char *)b,s,l);
100 #define SOCKS5_step_greet 0
101 #define SOCKS5_step_auth 1
102 #define SOCKS5_step_cmd 2
103 #define SOCKS5_step_done 3
106 * State of the SOCKS5 handshake.
108 struct GNUNET_SOCKS_Handshake
112 * Connection handle used for SOCKS5
114 struct GNUNET_CONNECTION_Handle *socks5_connection;
117 * Connection handle initially returned to client
119 struct GNUNET_CONNECTION_Handle *target_connection;
122 * Transmission handle on socks5_connection.
124 struct GNUNET_CONNECTION_TransmitHandle *th;
127 * Our stage in the SOCKS5 handshake
132 * Precomputed SOCKS5 handshake ouput buffer
134 unsigned char outbuf[1024];
137 * Pointers delineating protoocol steps in the outbut buffer
139 unsigned char * (outstep[4]);
142 * SOCKS5 handshake input buffer
144 unsigned char inbuf[1024];
147 * Pointers delimiting the current step in the input buffer
149 unsigned char * instart;
150 unsigned char * inend;
154 /* Regitering prototypes */
157 register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want);
159 /* In fact, the client sends first rule in GNUNet suggests one could take
160 * large mac read sizes without fear of screwing up the proxied protocol,
161 * but we make a proper SOCKS5 client. */
162 #define register_reciever_wants(ih) ((SOCKS5_step_cmd == ih->step) ? 10 : 2)
165 struct GNUNET_CONNECTION_TransmitHandle *
166 register_sender (struct GNUNET_SOCKS_Handshake *ih);
170 * Conclude the SOCKS5 handshake successfully.
172 * @param ih SOCKS5 handshake, consumed here.
173 * @param c open unused connection, consumed here.
174 * @return Connection handle that becomes usable when the handshake completes.
177 SOCKS5_handshake_done(struct GNUNET_SOCKS_Handshake *ih)
179 GNUNET_CONNECTION_acivate_proxied (ih->target_connection);
184 * Read one step in the SOCKS5 handshake.
186 * @param ih SOCKS5 Handshake
189 SOCKS5_handshake_step (struct GNUNET_SOCKS_Handshake *ih)
191 unsigned char * b = ih->instart;
192 size_t available = ih->inend - b;
194 int want = register_reciever_wants(ih);
195 if (available < want) {
196 register_reciever (ih, want - available);
199 GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
201 case SOCKS5_step_greet: /* SOCKS5 server's greeting */
204 LOG (GNUNET_ERROR_TYPE_ERROR,
205 "Not a SOCKS5 server\n");
209 case SOCKS5_AUTH_NOAUTH:
210 ih->step=SOCKS5_step_cmd; /* no authentication to do */
212 case SOCKS5_AUTH_USERPASS:
213 ih->step=SOCKS5_step_auth;
215 case SOCKS5_AUTH_REJECT:
216 LOG (GNUNET_ERROR_TYPE_ERROR,
217 "No authentication method accepted\n");
220 LOG (GNUNET_ERROR_TYPE_ERROR,
221 "Not a SOCKS5 server / Nonsensical authentication\n");
226 case SOCKS5_step_auth: /* SOCKS5 server's responce to authentication */
229 LOG (GNUNET_ERROR_TYPE_ERROR,
230 "SOCKS5 authentication failed\n");
233 ih->step=SOCKS5_step_cmd;
236 case SOCKS5_step_cmd: /* SOCKS5 server's responce to command */
239 LOG (GNUNET_ERROR_TYPE_ERROR,
240 "SOCKS5 protocol error\n");
244 LOG (GNUNET_ERROR_TYPE_ERROR,
245 "SOCKS5 connection error : %s\n",
246 SOCKS5_REP_names(b[1]));
250 /* There is no reason to verify host and port afaik. */
253 b += sizeof(struct in_addr); /* 4 */
256 b += sizeof(struct in6_addr); /* 16 */
258 case 3: /* hostname */
264 register_reciever (ih, b - ih->inend);
267 ih->step = SOCKS5_step_done;
268 LOG (GNUNET_ERROR_TYPE_DEBUG,
269 "SOCKS5 server : %s\n",
270 SOCKS5_REP_names(b[1]));
272 SOCKS5_handshake_done (ih);
274 case SOCKS5_step_done:
279 /* Do not reschedule the sender unless we're done reading.
280 * I imagine this lets us avoid ever cancelling the transmit handle. */
281 register_sender (ih);
286 * Callback to read from the SOCKS5 proxy.
288 * @param client the service
289 * @param handler function to call with the message
290 * @param handler_cls closure for @a handler
294 const void *buf, size_t available,
295 const struct sockaddr * addr,
296 socklen_t addrlen, int errCode)
298 printf("Meow(%d)",available);
299 struct GNUNET_SOCKS_Handshake * ih = cls;
300 GNUNET_assert (&ih->inend[available] < &ih->inbuf[1024]);
301 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 printf("register_reciever on step %u for %d bytes.\n", ih->step, want );
318 GNUNET_CONNECTION_receive (ih->socks5_connection,
320 GNUNET_TIME_relative_get_minute_ (),
327 * Register SOCKS5 handshake sender
329 * @param cls closure (SOCKS handshake)
330 * @param size number of bytes available in @a buf
331 * @param buf where the callee should write the message
332 * @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. */
359 enum GNUNET_SCHEDULER_Reason reason = GNUNET_SCHEDULER_get_reason ();
360 if (0 != (reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
362 if (0 != (reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) {
364 LOG (GNUNET_ERROR_TYPE_WARNING,
365 "Timeout contacting SOCKS server, retrying indefinitely, but probably hopeless.\n");
366 register_sender (ih);
368 LOG (GNUNET_ERROR_TYPE_ERROR,
369 "Timeout during mid SOCKS handshake (step %u), probably not a SOCKS server.\n",
375 printf("Erronious socks.c transmit_ready() callback on step %u with reason %u.\n",
377 /* if (reason == 48) register_sender (ih); */
378 /* GNUNET_break(0); */
381 printf("Good socks.c transmit_ready() callback on step %u with reason %u.\n",
382 ih->step, GNUNET_SCHEDULER_get_reason () );
384 GNUNET_assert (1024 >= size && size > 0);
385 GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
386 unsigned char * b = ih->outstep[ih->step];
387 unsigned char * e = ih->outstep[ih->step+1];
388 GNUNET_assert (e <= &ih->outbuf[1024]);
390 GNUNET_assert (size >= l && l >= 0);
392 register_reciever (ih, register_reciever_wants(ih));
393 printf("sent(%d)\n",l);
399 * Register SOCKS5 handshake sender
401 * @param ih handshake
402 * @return non-NULL if the notify callback was queued,
403 * NULL if we are already going to notify someone else (busy)
405 struct GNUNET_CONNECTION_TransmitHandle *
406 register_sender (struct GNUNET_SOCKS_Handshake *ih)
408 struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_MINUTES;
410 GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
412 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3);
413 unsigned char * b = ih->outstep[ih->step];
414 unsigned char * e = ih->outstep[ih->step+1];
415 GNUNET_assert (ih->outbuf <= b && b < e && e < &ih->outbuf[1024]);
416 printf("register_sender on step %u for %u bytes.\n", ih->step, (unsigned)(e - b) );
417 ih->th = GNUNET_CONNECTION_notify_transmit_ready (ih->socks5_connection,
427 * Initialize a SOCKS5 handshake for authentication via username and
428 * password. Tor uses SOCKS username and password authentication to assign
429 * programs unique circuits.
431 * @param user username for the proxy
432 * @param pass password for the proxy
433 * @return Valid SOCKS5 hanbdshake handle
435 struct GNUNET_SOCKS_Handshake *
436 GNUNET_SOCKS_init_handshake (const char *user, const char *pass)
438 struct GNUNET_SOCKS_Handshake *ih = GNUNET_new (struct GNUNET_SOCKS_Handshake);
439 unsigned char * b = ih->outbuf;
441 ih->outstep[SOCKS5_step_greet] = b;
442 *(b++) = 5; /* SOCKS5 */
443 unsigned char * n = b++;
444 *n = 1; /* Number of authentication methods */
445 /* We support no authentication even when requesting authentication,
446 * but this appears harmless, given the way that Tor uses authentication.
447 * And some SOCKS5 servers might require this. */
448 *(b++) = SOCKS5_AUTH_NOAUTH;
450 *(b++) = SOCKS5_AUTH_USERPASS;
453 /* There is no apperent reason to support authentication methods beyond
454 * username and password since afaik Tor does not support them. */
456 /* We authenticate with an empty username and password if the server demands
457 * them but we do not have any. */
463 ih->outstep[SOCKS5_step_auth] = b;
464 *(b++) = 1; /* subnegotiation ver.: 1 */
465 b = SOCK5_proto_string(b,user);
466 b = SOCK5_proto_string(b,pass);
468 ih->outstep[SOCKS5_step_cmd] = b;
475 * Initialize a SOCKS5 handshake without authentication, thereby possibly
476 * sharing a Tor circuit with another process.
478 * @return Valid SOCKS5 hanbdshake handle
480 struct GNUNET_SOCKS_Handshake *
481 GNUNET_SOCKS_init_handshake_noauth ()
483 return GNUNET_SOCKS_init_handshake (NULL,NULL);
488 * Build request that the SOCKS5 proxy open a TCP/IP stream to the given host
491 * @param ih SOCKS5 handshake
496 GNUNET_SOCKS_set_handshake_destination (struct GNUNET_SOCKS_Handshake *ih,
497 const char *host, uint16_t port)
503 unsigned char * b = ih->outstep[SOCKS5_step_cmd];
505 *(b++) = 5; /* SOCKS5 */
506 *(b++) = 1; /* Establish a TCP/IP stream */
507 *(b++) = 0; /* reserved */
509 /* Specify destination */
510 if (1 == inet_pton(AF_INET,host,&ia.in4)) {
511 *(b++)= 1; /* IPv4 */
512 memcpy (b, &ia.in4, sizeof(struct in_addr));
513 b += sizeof(struct in_addr); /* 4 */
514 } else if (1 == inet_pton(AF_INET6,host,&ia.in6)) {
515 *(b++)= 4; /* IPv6 */
516 memcpy (b, &ia.in6, sizeof(struct in6_addr));
517 b += sizeof(struct in6_addr); /* 16 */
519 *(b++)= 3; /* hostname */
520 b = SOCK5_proto_string (b, host);
524 *(uint16_t*)b = htons (port);
527 ih->outstep[SOCKS5_step_done] = b;
532 * Run a SOCKS5 handshake on an open but unused TCP connection.
534 * @param ih SOCKS5 handshake, consumed here.
535 * @param c open unused connection, consumed here.
536 * @return Connection handle that becomes usable when the SOCKS5 handshake completes.
538 struct GNUNET_CONNECTION_Handle *
539 GNUNET_SOCKS_run_handshake(struct GNUNET_SOCKS_Handshake *ih,
540 struct GNUNET_CONNECTION_Handle *c)
542 ih->socks5_connection=c;
543 ih->target_connection = GNUNET_CONNECTION_create_proxied_from_handshake (c);
544 register_sender (ih);
546 return ih->target_connection;
551 * Check if a SOCKS proxy is required by a service. Do not use local service
552 * if a SOCKS proxy port is configured as this could deanonymize a user.
554 * @param service_name name of service to connect to
555 * @param cfg configuration to use
556 * @return GNUNET_YES if so, GNUNET_NO if not
559 GNUNET_SOCKS_check_service (const char *service_name,
560 const struct GNUNET_CONFIGURATION_Handle *cfg)
562 return GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSPORT") ||
563 GNUNET_CONFIGURATION_have_value (cfg, service_name, "SOCKSHOST");
568 * Try to connect to a service configured to use a SOCKS5 proxy.
570 * @param service_name name of service to connect to
571 * @param cfg configuration to use
572 * @return Connection handle that becomes usable when the handshake completes.
573 * NULL if SOCKS not configured or not configured properly
575 struct GNUNET_CONNECTION_Handle *
576 GNUNET_SOCKS_do_connect (const char *service_name,
577 const struct GNUNET_CONFIGURATION_Handle *cfg)
579 struct GNUNET_SOCKS_Handshake *ih;
580 struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */
581 char *host0,*host1,*user,*pass;
582 unsigned long long port0,port1;
584 if (GNUNET_YES != GNUNET_SOCKS_check_service (service_name, cfg))
587 GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "SOCKSPORT", &port0))
589 /* A typical Tor client should usually try port 9150 for the TBB too, but
590 * GUNNet can probably assume a system Tor instalation. */
592 GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0))
594 if (port0 > 65535 || port0 <= 0)
596 LOG (GNUNET_ERROR_TYPE_WARNING,
598 ("Attempting to use invalid port %d as SOCKS proxy for service `%s'.\n"),
604 GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port1))
605 || (port1 > 65535) || (port1 <= 0) ||
607 GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME", &host1)))
609 LOG (GNUNET_ERROR_TYPE_WARNING,
611 ("Attempting to proxy service `%s' to invalid port %d or hostname `%s'.\n"),
612 service_name,port1,host1);
616 socks5 = GNUNET_CONNECTION_create_from_connect (cfg, host0, port0);
619 /* Sets to NULL if they do not exist */
620 GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSUSER", &user);
621 GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSPASS", &pass);
622 ih = GNUNET_SOCKS_init_handshake(user,pass);
623 if (NULL != user) GNUNET_free (user);
624 if (NULL != pass) GNUNET_free (pass);
626 GNUNET_SOCKS_set_handshake_destination (ih,host1,port1);
629 return GNUNET_SOCKS_run_handshake(ih,socks5);