From 73a1e98cb971f7d1105f2b6b2399ae2eeec36a96 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 13 Jul 2011 18:58:11 +0200 Subject: [PATCH 01/36] Add support for managed {Client,Server}TransportPlugin parsing. --- src/or/config.c | 225 +++++++++++++++++++++++++++++++++++++++++------- src/or/or.h | 3 + 2 files changed, 197 insertions(+), 31 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index 0082ff9397..111b28b983 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -33,7 +33,9 @@ #include "rendservice.h" #include "rephist.h" #include "router.h" +#include "util.h" #include "routerlist.h" +#include "pluggable_transports.h" #ifdef MS_WINDOWS #include #endif @@ -298,6 +300,7 @@ static config_var_t _option_vars[] = { V(HTTPProxyAuthenticator, STRING, NULL), V(HTTPSProxy, STRING, NULL), V(HTTPSProxyAuthenticator, STRING, NULL), + VAR("ServerTransportPlugin", LINELIST, ServerTransportPlugin, NULL), V(Socks4Proxy, STRING, NULL), V(Socks5Proxy, STRING, NULL), V(Socks5ProxyUsername, STRING, NULL), @@ -572,6 +575,8 @@ static void config_register_addressmaps(or_options_t *options); static int parse_bridge_line(const char *line, int validate_only); static int parse_client_transport_line(const char *line, int validate_only); + +static int parse_server_transport_line(const char *line, int validate_only); static int parse_dir_server_line(const char *line, dirinfo_type_t required_type, int validate_only); @@ -1219,6 +1224,18 @@ options_act(or_options_t *old_options) } } + clear_transport_list(); + if (options->ServerTransportPlugin) { + for (cl = options->ServerTransportPlugin; cl; cl = cl->next) { + if (parse_server_transport_line(cl->value, 0)<0) { + log_warn(LD_BUG, + "Previously validated ServerTransportPlugin line " + "could not be added!"); + return -1; + } + } + } + if (options->Bridges) { mark_bridge_list(); for (cl = options->Bridges; cl; cl = cl->next) { @@ -3686,14 +3703,19 @@ options_validate(or_options_t *old_options, or_options_t *options, if (options->UseBridges && !options->TunnelDirConns) REJECT("TunnelDirConns set to 0 only works with UseBridges set to 0"); + for (cl = options->Bridges; cl; cl = cl->next) { + if (parse_bridge_line(cl->value, 1)<0) + REJECT("Bridge line did not parse. See logs for details."); + } + for (cl = options->ClientTransportPlugin; cl; cl = cl->next) { if (parse_client_transport_line(cl->value, 1)<0) REJECT("Transport line did not parse. See logs for details."); } - for (cl = options->Bridges; cl; cl = cl->next) { - if (parse_bridge_line(cl->value, 1)<0) - REJECT("Bridge line did not parse. See logs for details."); + for (cl = options->ServerTransportPlugin; cl; cl = cl->next) { + if (parse_server_transport_line(cl->value, 1)<0) + REJECT("Server transport line did not parse. See logs for details."); } if (options->ConstrainedSockets) { @@ -4652,28 +4674,35 @@ parse_bridge_line(const char *line, int validate_only) SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); tor_free(addrport); - tor_free(fingerprint); tor_free(transport_name); + tor_free(fingerprint); return r; } /** Read the contents of a ClientTransportPlugin line from * line. Return 0 if the line is well-formed, and -1 if it - * isn't. If validate_only is 0, and the line is well-formed, - * then add the transport described in the line to our internal - * transport list. -*/ + * isn't. + * + * If validate_only is 0, and the line is well-formed: + * - If it's an external proxy line, add the transport described in the line to + * our internal transport list. + * - If it's a managed proxy line, launch the managed proxy. */ static int parse_client_transport_line(const char *line, int validate_only) { smartlist_t *items = NULL; int r; - char *socks_ver_str=NULL; + char *field2=NULL; + char *name=NULL; char *addrport=NULL; - int socks_ver; tor_addr_t addr; uint16_t port = 0; + int socks_ver=PROXY_NONE; + + /* managed proxy options */ + int is_managed=0; + char **proxy_argv=NULL; items = smartlist_create(); smartlist_split_string(items, line, NULL, @@ -4685,39 +4714,69 @@ parse_client_transport_line(const char *line, int validate_only) } name = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); - socks_ver_str = smartlist_get(items, 1); + /* field2 is either a SOCKS version or "exec" */ + field2 = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); - if (!strcmp(socks_ver_str,"socks4")) + if (!strcmp(field2,"socks4")) { socks_ver = PROXY_SOCKS4; - else if (!strcmp(socks_ver_str,"socks5")) + } else if (!strcmp(field2,"socks5")) { socks_ver = PROXY_SOCKS5; - else { - log_warn(LD_CONFIG, "Strange ClientTransportPlugin proxy type '%s'.", - socks_ver_str); + } else if (!strcmp(field2,"exec")) { + is_managed=1; + } else { + log_warn(LD_CONFIG, "Strange ClientTransportPlugin field '%s'.", + field2); goto err; } - addrport = smartlist_get(items, 2); + if (!is_managed) { + addrport = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); - if (tor_addr_port_parse(addrport, &addr, &port)<0) { - log_warn(LD_CONFIG, "Error parsing transport " - "address '%s'", addrport); - goto err; - } - - if (!port) { - log_warn(LD_CONFIG, - "Transport address '%s' has no port.", addrport); - goto err; + if (tor_addr_port_parse(addrport, &addr, &port)<0) { + log_warn(LD_CONFIG, "Error parsing transport " + "address '%s'", addrport); + goto err; + } + if (!port) { + log_warn(LD_CONFIG, + "Transport address '%s' has no port.", addrport); + goto err; + } } if (!validate_only) { - log_debug(LD_DIR, "Transport %s found at %s:%d", name, - fmt_addr(&addr), (int)port); + if (is_managed) { /* if it's managed, and we are planning on + launching the proxy, use the rest of the line + as the argv. */ + char **tmp; + char *tmp_arg; + proxy_argv = tor_malloc_zero(sizeof(char*)*(smartlist_len(items)+1)); + tmp = proxy_argv; + while (smartlist_len(items)) { + tmp_arg = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); + *tmp++ = tor_strdup(tmp_arg); + tor_free(tmp_arg); + } + *tmp = NULL; /*terminated with NUL pointer, just like execve() likes it*/ - if (transport_add_from_config(&addr, port, name, socks_ver) < 0) - goto err; + if (pt_managed_launch_client_proxy(name, proxy_argv) < 0) { + log_warn(LD_CONFIG, "Error while launching managed proxy at '%s'", + proxy_argv[0]); + goto err; + } + } else { /* external */ + if (transport_add_from_config(&addr, port, name, + socks_ver) < 0) { + goto err; + } + log_debug(LD_DIR, "Transport %s found at %s:%d", name, + fmt_addr(&addr), (int)port); + } } r = 0; @@ -4729,6 +4788,110 @@ parse_client_transport_line(const char *line, int validate_only) done: SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); + tor_free(name); + tor_free(field2); + tor_free(addrport); + return r; +} + +/** Read the contents of a ServerTransportPlugin line from + * line. Return 0 if the line is well-formed, and -1 if it + * isn't. + * If validate_only is 0, the line is well-formed, and it's a + * managed proxy line, launch the managed proxy. */ +static int +parse_server_transport_line(const char *line, int validate_only) +{ + smartlist_t *items = NULL; + int r; + char *name=NULL; + char *field2=NULL; + char *addrport=NULL; + tor_addr_t addr; + uint16_t port = 0; + + /* managed proxy options */ + int is_managed=0; + char **proxy_argv=NULL; + + items = smartlist_create(); + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + + if (smartlist_len(items) < 3) { + log_warn(LD_CONFIG, "Too few arguments on ServerTransportPlugin line."); + goto err; + } + + name = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); + + /* field2 is either or "exec" */ + field2 = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); + + if (!(strstr(field2, ".") || strstr(field2, ":"))) { /* managed proxy */ + if (strcmp(field2, "exec")) { + log_warn(LD_CONFIG, "Unrecognizable field '%s' in " + "ServerTransportPlugin line", field2); + goto err; + } + is_managed=1; + } + + if (!is_managed) { + addrport = field2; + + if (tor_addr_port_parse(addrport, &addr, &port)<0) { + log_warn(LD_CONFIG, "Error parsing transport " + "address '%s'", addrport); + goto err; + } + if (!port) { + log_warn(LD_CONFIG, + "Transport address '%s' has no port.", addrport); + goto err; + } + } + + if (!validate_only) { + if (is_managed) { /* if it's managed, and we are planning on + launching the proxy, use the rest of the line + as the argv. */ + char **tmp; + char *tmp_arg; + proxy_argv = tor_malloc_zero(sizeof(char*)*(smartlist_len(items)+1)); + tmp = proxy_argv; + while (smartlist_len(items)) { + tmp_arg = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); + *tmp++ = tor_strdup(tmp_arg); + tor_free(tmp_arg); + } + *tmp = NULL; /*terminated with NUL pointer, just like execve() likes it*/ + + if (pt_managed_launch_server_proxy(name, proxy_argv) < 0) { + log_warn(LD_CONFIG, "Error while launching managed proxy at '%s'", + proxy_argv[0]); + goto err; + } + } else { + log_warn(LD_DIR, "Transport %s at %s:%d", name, + fmt_addr(&addr), (int)port); + } + } + + r = 0; + goto done; + + err: + r = -1; + + done: + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + tor_free(name); + tor_free(field2); return r; } diff --git a/src/or/or.h b/src/or/or.h index d1817d47f8..8bcfc82ce4 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2679,6 +2679,9 @@ typedef struct { config_line_t *ClientTransportPlugin; /**< List of client transport plugins. */ + config_line_t *ServerTransportPlugin; /**< List of client + transport plugins. */ + int BridgeRelay; /**< Boolean: are we acting as a bridge relay? We make * this explicit so we can change how we behave in the * future. */ From 810a7a5fa0973451881a874a08594937a8274429 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 13 Jul 2011 18:59:52 +0200 Subject: [PATCH 02/36] Make some utility functions. * Create a function that will get input from a stream, so that we can communicate with the managed proxy. * Hackish change to tor_spawn_background() so that we can specify an environ for our spawn. --- src/common/util.c | 60 +++++++++++++++++++++++++++++++++++++++++--- src/common/util.h | 16 ++++++++++-- src/test/test_util.c | 3 ++- 3 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src/common/util.c b/src/common/util.c index a5a6ea3e8b..5f4472bff3 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -2958,7 +2958,7 @@ format_helper_exit_status(unsigned char child_state, int saved_errno, */ int tor_spawn_background(const char *const filename, int *stdout_read, - int *stderr_read, const char **argv) + int *stderr_read, const char **argv, const char **envp) { #ifdef MS_WINDOWS (void) filename; (void) stdout_read; (void) stderr_read; (void) argv; @@ -3068,7 +3068,10 @@ tor_spawn_background(const char *const filename, int *stdout_read, /* Call the requested program. We need the cast because execvp doesn't define argv as const, even though it does not modify the arguments */ - execvp(filename, (char *const *) argv); + if (envp) + execve(filename, (char *const *) argv, (char*const*)envp); + else + execvp(filename, (char *const *) argv); /* If we got here, the exec or open(/dev/null) failed */ @@ -3128,6 +3131,57 @@ tor_spawn_background(const char *const filename, int *stdout_read, #endif } +/** Reads from stream and stores input in buf_out making + * sure it's below count bytes. + * If the string has a trailing newline, we strip it off. + * + * This function is specifically created to handle input from managed + * proxies, according to the pluggable transports spec. Make sure it + * fits your needs before using it. + * + * Returns: + * ST_CLOSED: If the stream is closed. + * ST_EAGAIN: If there is nothing to read and we should check back later. + * ST_TERM: If something is wrong with the stream. + * ST_OKAY: If everything went okay and we got a string in buf_out. */ +enum stream_status +get_string_from_pipe(FILE *stream, char *buf_out, size_t count) +{ + char *retval; + size_t len; + + retval = fgets(buf_out, count, stream); + + if (!retval) { + if (feof(stream)) { + /* Program has closed stream (probably it exited) */ + /* TODO: check error */ + return ST_CLOSED; + } else { + if (EAGAIN == errno) { + /* Nothing more to read, try again next time */ + return ST_EAGAIN; + } else { + /* There was a problem, abandon this child process */ + return ST_TERM; + } + } + } else { + len = strlen(buf_out); + tor_assert(len>0); + + if (buf_out[len - 1] == '\n') { + /* Remove the trailing newline */ + buf_out[len - 1] = '\0'; + } + + return ST_OKAY; + } + + /* We should never get here */ + return ST_TERM; +} + /** Read from stream, and send lines to log at the specified log level. * Returns 1 if stream is closed normally, -1 if there is a error reading, and * 0 otherwise. Handles lines from tor-fw-helper and @@ -3254,7 +3308,7 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port, /* Assume tor-fw-helper will succeed, start it later*/ time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_SUCCESS; - child_pid = tor_spawn_background(filename, &fd_out, &fd_err, argv); + child_pid = tor_spawn_background(filename, &fd_out, &fd_err, argv, NULL); if (child_pid < 0) { log_warn(LD_GENERAL, "Failed to start port forwarding helper %s", filename); diff --git a/src/common/util.h b/src/common/util.h index 2974ab7538..1b81fa3149 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -279,6 +279,16 @@ char *rate_limit_log(ratelim_t *lim, time_t now); ssize_t write_all(tor_socket_t fd, const char *buf, size_t count,int isSocket); ssize_t read_all(tor_socket_t fd, char *buf, size_t count, int isSocket); +/** Status of an I/O stream. */ +enum stream_status { + ST_OKAY, + ST_EAGAIN, + ST_TERM, + ST_CLOSED +}; + +enum stream_status get_string_from_pipe(FILE *stream, char *buf, size_t count); + /** Return values from file_status(); see that function's documentation * for details. */ typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR } file_status_t; @@ -340,14 +350,16 @@ void write_pidfile(char *filename); void tor_check_port_forwarding(const char *filename, int dir_port, int or_port, time_t now); +int tor_spawn_background(const char *const filename, int *stdout_read, + int *stderr_read, const char **argv, + const char **envp); + #ifdef MS_WINDOWS HANDLE load_windows_system_library(const TCHAR *library_name); #endif #ifdef UTIL_PRIVATE /* Prototypes for private functions only used by util.c (and unit tests) */ -int tor_spawn_background(const char *const filename, int *stdout_read, - int *stderr_read, const char **argv); void format_helper_exit_status(unsigned char child_state, int saved_errno, char *hex_errno); diff --git a/src/test/test_util.c b/src/test/test_util.c index c4769e6407..c778faacab 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -1389,7 +1389,8 @@ run_util_spawn_background(const char *argv[], const char *expected_out, char stdout_buf[100], stderr_buf[100]; /* Start the program */ - retval = tor_spawn_background(argv[0], &stdout_pipe, &stderr_pipe, argv); + retval = tor_spawn_background(argv[0], &stdout_pipe, &stderr_pipe, + argv, NULL); tt_int_op(retval, >, 0); tt_int_op(stdout_pipe, >, 0); tt_int_op(stderr_pipe, >, 0); From 9ba2d0e439e53f8307c808fe26e37b53892a604c Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 13 Jul 2011 19:00:28 +0200 Subject: [PATCH 03/36] Create the pluggable_transports.[ch] source files responsible for talking the 180 talk. --- src/or/Makefile.am | 2 + src/or/pluggable_transports.c | 613 ++++++++++++++++++++++++++++++++++ src/or/pluggable_transports.h | 59 ++++ 3 files changed, 674 insertions(+) create mode 100644 src/or/pluggable_transports.c create mode 100644 src/or/pluggable_transports.h diff --git a/src/or/Makefile.am b/src/or/Makefile.am index a12d56b73d..4dc5ee55f6 100644 --- a/src/or/Makefile.am +++ b/src/or/Makefile.am @@ -39,6 +39,7 @@ libtor_a_SOURCES = \ networkstatus.c \ nodelist.c \ onion.c \ + pluggable_transports.c \ policies.c \ reasons.c \ relay.c \ @@ -104,6 +105,7 @@ noinst_HEADERS = \ ntmain.h \ onion.h \ or.h \ + pluggable_transports.h \ policies.h \ reasons.h \ relay.h \ diff --git a/src/or/pluggable_transports.c b/src/or/pluggable_transports.c new file mode 100644 index 0000000000..5448c409cd --- /dev/null +++ b/src/or/pluggable_transports.c @@ -0,0 +1,613 @@ +/* Copyright (c) 2011, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file pluggable_transports.c + * \brief Pluggable Transports related code. + **/ + +#define PT_PRIVATE +#include "or.h" +#include "config.h" +#include "circuitbuild.h" +#include "pluggable_transports.h" + +/* ASN TIDY THESE UP*/ +static void set_environ(char ***envp, const char *method, + int is_server); +static INLINE int proxy_configuration_finished(managed_proxy_t *mp); + +static void managed_proxy_destroy(managed_proxy_t *mp, + int also_free_transports); +static void register_proxy_transports(managed_proxy_t *mp); +static void handle_finished_proxy(managed_proxy_t *mp); +static void configure_proxy(managed_proxy_t *mp); + +static void parse_method_error(char *line, int is_server_method); +#define parse_server_method_error(l) parse_method_error(l, 1) +#define parse_client_method_error(l) parse_method_error(l, 0) + +static INLINE void free_execve_args(char **arg); + +/** Managed proxy protocol strings */ +#define PROTO_ENV_ERROR "ENV-ERROR" +#define PROTO_NEG_SUCCESS "VERSION" +#define PROTO_NEG_FAIL "VERSION-ERROR no-version" +#define PROTO_CMETHOD "CMETHOD" +#define PROTO_SMETHOD "SMETHOD" +#define PROTO_CMETHOD_ERROR "CMETHOD-ERROR" +#define PROTO_SMETHOD_ERROR "SMETHOD-ERROR" +#define PROTO_CMETHODS_DONE "CMETHODS DONE" +#define PROTO_SMETHODS_DONE "SMETHODS DONE" + +/* The smallest valid managed proxy protocol line that can + appear. It's the size of "VERSION 1" */ +#define SMALLEST_MANAGED_LINE_SIZE 9 + +/** Number of environment variables for managed proxy clients/servers. */ +#define ENVIRON_SIZE_CLIENT 5 +#define ENVIRON_SIZE_SERVER 8 + +/** The first and only supported - at the moment - configuration + protocol version. */ +#define PROTO_VERSION_ONE 1 + +/** List of unconfigured managed proxies. */ +static smartlist_t *unconfigured_proxy_list = NULL; +/** Number of unconfigured managed proxies. */ +static int n_unconfigured_proxies = 0; + +/* The main idea is: + + A managed proxy is represented by a managed_proxy_t struct and can + spawn multiple transports. + + unconfigured_proxy_list is a list of all the unconfigured managed + proxies; everytime we spawn a managed proxy we add it in that + list. + In every run_scheduled_event() tick, we attempt to configure each + managed proxy further, using the configuration protocol defined in + the 180_pluggable_transport.txt proposal. + + When a managed proxy is fully configured, we register all its + transports to the circuitbuild.c subsystem - like we do with + external proxies - and then free the managed proxy struct + since it's no longer needed. */ + +/** Return true if there are still unconfigured managed proxies. */ +int +pt_proxies_configuration_pending(void) +{ + return !!n_unconfigured_proxies; +} + +/** Launch a proxy for method using proxy_argv as its + * arguments. If is_server, launch a server proxy. */ +int +pt_managed_launch_proxy(const char *method, + char **proxy_argv, int is_server) +{ + char **envp=NULL; + int retval; + FILE *stdout_read = NULL; + int stdout_pipe=-1, stderr_pipe=-1; + + /* prepare the environment variables for the managed proxy */ + set_environ(&envp, method, is_server); + + /* ASN we should probably check if proxy_argv[0] is executable by our user */ + retval = tor_spawn_background(proxy_argv[0], &stdout_pipe, + &stderr_pipe, (const char **)proxy_argv, + (const char **)envp); + if (retval < 0) { + log_warn(LD_GENERAL, "Spawn failed"); + return -1; + } + + /* free the memory allocated for the execve() */ + free_execve_args(envp); + free_execve_args(proxy_argv); + + /* Set stdout/stderr pipes to be non-blocking */ + fcntl(stdout_pipe, F_SETFL, O_NONBLOCK); + /* Open the buffered IO streams */ + stdout_read = fdopen(stdout_pipe, "r"); + + log_warn(LD_CONFIG, "The spawn is alive (%d)!", retval); + + /* create a managed proxy */ + managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t)); + mp->conf_state = PT_PROTO_INFANT; + mp->stdout = stdout_read; + mp->transports = smartlist_create(); + + /* register the managed proxy */ + if (!unconfigured_proxy_list) + unconfigured_proxy_list = smartlist_create(); + smartlist_add(unconfigured_proxy_list, mp); + + n_unconfigured_proxies++; /* ASN should we care about overflows here? + I say no. */ + + return 0; +} + +/** Check if any of the managed proxies we are currently trying to + * configure have anything new to say. This is called from + * run_scheduled_events(). */ +void +pt_configure_remaining_proxies(void) +{ + log_warn(LD_CONFIG, "We start configuring remaining managed proxies!"); + SMARTLIST_FOREACH_BEGIN(unconfigured_proxy_list, managed_proxy_t *, mp) { + if (proxy_configuration_finished(mp)) /* finished managed proxies + shouldn't be here */ + assert(0); + + configure_proxy(mp); + + } SMARTLIST_FOREACH_END(mp); +} + +/** Receive input from the managed proxy mp to get closer to + * finally configuring it. */ +static void +configure_proxy(managed_proxy_t *mp) +{ + enum stream_status r; + char stdout_buf[200]; + + while (1) { + memset(stdout_buf, 0, sizeof(stdout_buf)); + + r = get_string_from_pipe(mp->stdout, stdout_buf, + sizeof(stdout_buf) - 1); + + if (r == ST_CLOSED || r == ST_TERM) { + log_warn(LD_GENERAL, "Managed proxy stream closed. " + "Most probably application stopped running"); + mp->conf_state = PT_PROTO_BROKEN; + } else if (r == ST_EAGAIN) { + return; + } else { + tor_assert(r == ST_OKAY); + handle_proxy_line(stdout_buf, mp); + } + + /* if the proxy finished configuring, exit the loop. */ + if (proxy_configuration_finished(mp)) { + handle_finished_proxy(mp); + return; + } + } +} + +/** Handle a configured or broken managed proxy mp. */ +static void +handle_finished_proxy(managed_proxy_t *mp) +{ + switch (mp->conf_state) { + case PT_PROTO_BROKEN: /* if broken: */ + managed_proxy_destroy(mp, 1); /* destroy it and all its transports */ + break; + case PT_PROTO_CONFIGURED: /* if configured correctly: */ + register_proxy_transports(mp); /* register all its transports, */ + mp->conf_state = PT_PROTO_COMPLETED; /* mark it as completed, */ + managed_proxy_destroy(mp, 0); /* destroy the managed proxy struct, + keeping the transports intact */ + break; + default: + log_warn(LD_CONFIG, "Unfinished managed proxy in " + "handle_finished_proxy()."); + assert(0); + } + + n_unconfigured_proxies--; + tor_assert(n_unconfigured_proxies >= 0); +} + +/** Register all the transports supported by managed proxy mp. */ +static void +register_proxy_transports(managed_proxy_t *mp) +{ + SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) { + if (transport_add(t)<0) { + log_warn(LD_GENERAL, "Could not add transport %s. Skipping.", t->name); + transport_free(t); + } else { + log_warn(LD_GENERAL, "Succesfully registered transport %s", t->name); + } + } SMARTLIST_FOREACH_END(t); +} + +/** Free memory allocated by managed proxy mp. + * If also_free_transports is set, also free the transports + * associated with this managed proxy. */ +static void +managed_proxy_destroy(managed_proxy_t *mp, int also_free_transports) +{ + /* transport_free() all its transports */ + if (also_free_transports) + SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); + + /* free the transports smartlist */ + smartlist_clear(mp->transports); + smartlist_free(mp->transports); + + /* remove it from the list of managed proxies */ + smartlist_remove(unconfigured_proxy_list, mp); + + /* close its stdout stream */ + fclose(mp->stdout); + + tor_free(mp); +} + +/** Return true if the configuration of the managed proxy mp is + finished. */ +static INLINE int +proxy_configuration_finished(managed_proxy_t *mp) +{ + return (mp->conf_state == PT_PROTO_CONFIGURED || + mp->conf_state == PT_PROTO_BROKEN); +} + +/** Handle a configuration protocol line received from a + * managed proxy mp. */ +void +handle_proxy_line(char *line, managed_proxy_t *mp) +{ + printf("Judging line: %s\n", line); + + if (strlen(line) < SMALLEST_MANAGED_LINE_SIZE) { + log_warn(LD_GENERAL, "Managed proxy configuration line is too small. " + "Discarding"); + goto err; + } + + if (!strncmp(line, PROTO_ENV_ERROR, strlen(PROTO_ENV_ERROR))) { + if (mp->conf_state != PT_PROTO_INFANT) + goto err; + + parse_env_error(line); + goto err; + } else if (!strncmp(line, PROTO_NEG_FAIL, strlen(PROTO_NEG_FAIL))) { + if (mp->conf_state != PT_PROTO_INFANT) + goto err; + + log_warn(LD_CONFIG, "Managed proxy could not pick a " + "configuration protocol version."); + goto err; + } else if (!strncmp(line, PROTO_NEG_SUCCESS, + strlen(PROTO_NEG_SUCCESS))) { + if (mp->conf_state != PT_PROTO_INFANT) + goto err; + + if (parse_version(line,mp) < 0) + goto err; + + tor_assert(mp->conf_protocol != 0); + mp->conf_state = PT_PROTO_ACCEPTING_METHODS; + return; + } else if (!strncmp(line, PROTO_CMETHODS_DONE, + strlen(PROTO_CMETHODS_DONE))) { + if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) + goto err; + + log_warn(LD_CONFIG, "Client managed proxy configuration completed!"); + mp->conf_state = PT_PROTO_CONFIGURED; + return; + } else if (!strncmp(line, PROTO_SMETHODS_DONE, + strlen(PROTO_SMETHODS_DONE))) { + if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) + goto err; + + log_warn(LD_CONFIG, "Server managed proxy configuration completed!"); + mp->conf_state = PT_PROTO_CONFIGURED; + return; + } else if (!strncmp(line, PROTO_CMETHOD_ERROR, + strlen(PROTO_CMETHOD_ERROR))) { + if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) + goto err; + + parse_client_method_error(line); + goto err; + } else if (!strncmp(line, PROTO_SMETHOD_ERROR, + strlen(PROTO_SMETHOD_ERROR))) { + if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) + goto err; + + parse_server_method_error(line); + goto err; + } else if (!strncmp(line, PROTO_CMETHOD, strlen(PROTO_CMETHOD))) { + if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) + goto err; + + if (parse_cmethod_line(line, mp) < 0) + goto err; + + return; + } else if (!strncmp(line, PROTO_SMETHOD, strlen(PROTO_SMETHOD))) { + if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) + goto err; + + if (parse_smethod_line(line, mp) < 0) + goto err; + + return; + } + + log_warn(LD_CONFIG, "Unknown line received by managed proxy. (%s)", line); + + err: + mp->conf_state = PT_PROTO_BROKEN; + return; +} + +/** Parses an ENV-ERROR line and warns the user accordingly. */ +void +parse_env_error(char *line) +{ + tor_assert(!strncmp(line, PROTO_ENV_ERROR, strlen(PROTO_ENV_ERROR))); + + /* (Length of the protocol string) plus (a space) and (the first char of + the error message) */ + if (strlen(line) < (strlen(PROTO_ENV_ERROR) + 2)) + log_warn(LD_CONFIG, "Managed proxy sent us an %s without an error " + "message.", PROTO_ENV_ERROR); + + log_warn(LD_CONFIG, "Managed proxy couldn't understand the " + "pluggable transport environment variables. (%s)", + line+strlen(PROTO_ENV_ERROR)+1); +} + +/** Handles a VERSION line. Updates the configuration protocol + * version in mp. */ +int +parse_version(char *line, managed_proxy_t *mp) +{ + tor_assert(!strncmp(line, PROTO_NEG_SUCCESS, strlen(PROTO_NEG_SUCCESS))); + + if (strlen(line) < (strlen(PROTO_NEG_SUCCESS) + 2)) { + log_warn(LD_CONFIG, "Managed proxy sent us malformed %s line.", + PROTO_NEG_SUCCESS); + return -1; + } + + if (strcmp("1", line+strlen(PROTO_NEG_SUCCESS)+1)) { + log_warn(LD_CONFIG, "We don't support version '%s'. " + "We only support version '1'", line+strlen(PROTO_NEG_SUCCESS)+1); + return -1; + } + + mp->conf_protocol = PROTO_VERSION_ONE; /* temp. till more versions appear */ + return 0; +} + +/** Parses {C,S}METHOD-ERROR line and warns the user + * accordingly. If is_server it is an SMETHOD-ERROR, + * otherwise it is a CMETHOD-ERROR. */ +static void +parse_method_error(char *line, int is_server) +{ + const char* error = is_server ? + PROTO_SMETHOD_ERROR : PROTO_CMETHOD_ERROR; + + /* (Length of the protocol string) plus (a space) and (the first char of + the error message) */ + if (strlen(line) < (strlen(error) + 2)) + log_warn(LD_CONFIG, "Managed proxy sent us an %s without an error " + "message.", error); + + log_warn(LD_CONFIG, "%s managed proxy encountered a method error. (%s)", + is_server ? "Server" : "Client", + line+strlen(error)+1); +} + +/** Parses an SMETHOD line. */ +int +parse_smethod_line(char *line, managed_proxy_t *mp) +{ + int r; + smartlist_t *items = NULL; + + char *method_name=NULL; + + char *addrport=NULL; + tor_addr_t addr; + uint16_t port = 0; + + items = smartlist_create(); + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + if (smartlist_len(items) < 3) { + log_warn(LD_CONFIG, "Server managed proxy sent us a SMETHOD line " + "with too few arguments."); + goto err; + } + + tor_assert(!strcmp(smartlist_get(items,0),PROTO_SMETHOD)); + + method_name = smartlist_get(items,1); + + addrport = smartlist_get(items, 2); + if (tor_addr_port_parse(addrport, &addr, &port)<0) { + log_warn(LD_CONFIG, "Error parsing transport " + "address '%s'", addrport); + goto err; + } + + if (!port) { + log_warn(LD_CONFIG, + "Transport address '%s' has no port.", addrport); + goto err; + } + + /* For now, notify the user so that he knows where the server + transport is listening. */ + log_warn(LD_CONFIG, "Server transport %s at %s:%d.", + method_name, fmt_addr(&addr), (int)port); + + r=0; + goto done; + + err: + r = -1; + + done: + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + return r; +} + +/** Parses a CMETHOD line, and if well-formed it registers + * the new transport in mp. */ +int +parse_cmethod_line(char *line, managed_proxy_t *mp) +{ + int r; + smartlist_t *items = NULL; + + char *method_name=NULL; + + char *socks_ver_str=NULL; + int socks_ver=PROXY_NONE; + + char *addrport=NULL; + tor_addr_t addr; + uint16_t port = 0; + + transport_t *transport=NULL; + + items = smartlist_create(); + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + if (smartlist_len(items) < 4) { + log_warn(LD_CONFIG, "Client managed proxy sent us a CMETHOD line " + "with too few arguments."); + goto err; + } + + tor_assert(!strcmp(smartlist_get(items,0),PROTO_CMETHOD)); + + method_name = smartlist_get(items,1); + + socks_ver_str = smartlist_get(items,2); + + if (!strcmp(socks_ver_str,"socks4")) { + socks_ver = PROXY_SOCKS4; + } else if (!strcmp(socks_ver_str,"socks5")) { + socks_ver = PROXY_SOCKS5; + } else { + log_warn(LD_CONFIG, "Client managed proxy sent us a proxy protocol " + "we don't recognize. (%s)", socks_ver_str); + goto err; + } + + addrport = smartlist_get(items, 3); + if (tor_addr_port_parse(addrport, &addr, &port)<0) { + log_warn(LD_CONFIG, "Error parsing transport " + "address '%s'", addrport); + goto err; + } + + if (!port) { + log_warn(LD_CONFIG, + "Transport address '%s' has no port.", addrport); + goto err; + } + + transport = transport_create(&addr, port, method_name, socks_ver); + if (!transport) + goto err; + + smartlist_add(mp->transports, transport); + + log_warn(LD_CONFIG, "Transport %s at %s:%d with SOCKS %d. " + "Attached to managed proxy.", + method_name, fmt_addr(&addr), (int)port, socks_ver); + + r=0; + goto done; + + err: + r = -1; + + done: + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + return r; +} + +/** Prepares the envp of a pluggable transport managed proxy + * + * method is a line with transport methods to be launched. + * If is_server is set, prepare a server proxy envp. */ +static void +set_environ(char ***envp, const char *method, int is_server) +{ + or_options_t *options = get_options(); + char **tmp=NULL; + char *state_loc=NULL; + + int n_envs = is_server ? ENVIRON_SIZE_SERVER : ENVIRON_SIZE_CLIENT; + + /* allocate enough space for our env. vars and a NULL pointer */ + *envp = tor_malloc(sizeof(char*)*(n_envs+1)); + tmp = *envp; + + /* these should all be customizable */ + tor_asprintf(tmp++, "HOME=%s", getenv("HOME")); + tor_asprintf(tmp++, "PATH=%s", getenv("PATH")); + state_loc = get_datadir_fname("pt_state/"); + tor_asprintf(tmp++, "TOR_PT_STATE_LOCATION=%s", state_loc); + tor_free(state_loc); + tor_asprintf(tmp++, "TOR_PT_MANAGED_TRANSPORT_VER=1"); /* temp */ + if (is_server) { + /* ASN check for ORPort values, should we be here if it's 0? */ + tor_asprintf(tmp++, "TOR_PT_ORPORT=%d", options->ORPort); + tor_asprintf(tmp++, "TOR_PT_SERVER_BINDADDR=127.0.0.1:0"); + tor_asprintf(tmp++, "TOR_PT_SERVER_TRANSPORTS=%s", method); + tor_asprintf(tmp++, "TOR_PT_EXTENDED_SERVER_PORT=4200"); + } else { + tor_asprintf(tmp++, "TOR_PT_CLIENT_TRANSPORTS=%s", method); + } + *tmp = NULL; +} + +/* ASN is this too ugly/stupid? */ +/** Frees the array of pointers in arg used as arguments to + execve. */ +static INLINE void +free_execve_args(char **arg) +{ + char **tmp = arg; + while (*tmp) /* use the fact that the last element of the array is a + NULL pointer to know when to stop freeing */ + _tor_free(*tmp++); + + tor_free(arg); +} + +/** Release all storage held by the pluggable transports subsystem. */ +void +pt_free_all(void) +{ + if (unconfigured_proxy_list) { + /* If the proxy is in PT_PROTO_COMPLETED, it has registered its + transports and it's the duty of the circuitbuild.c subsystem to + free them. Otherwise, it hasn't registered its transports yet + and we should free them here. */ + SMARTLIST_FOREACH_BEGIN(unconfigured_proxy_list, managed_proxy_t *, mp) { + if (mp->conf_state == PT_PROTO_COMPLETED) + managed_proxy_destroy(mp,0); + else + managed_proxy_destroy(mp,1); + } SMARTLIST_FOREACH_END(mp); + + smartlist_clear(unconfigured_proxy_list); + smartlist_free(unconfigured_proxy_list); + unconfigured_proxy_list=NULL; + } +} + diff --git a/src/or/pluggable_transports.h b/src/or/pluggable_transports.h new file mode 100644 index 0000000000..80d5429e70 --- /dev/null +++ b/src/or/pluggable_transports.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2011, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file pluggable_transpots.h + * \brief Headers for pluggable_transpots.c + **/ + +#ifndef TOR_PLUGGABLE_TRANSPORTS_H +#define TOR_PLUGGABLE_TRANSPORTS_H + +int pt_managed_launch_proxy(const char *method, + char **proxy_argv, int is_server); + +#define pt_managed_launch_client_proxy(m, pa) \ + pt_managed_launch_proxy(m, pa, 0) +#define pt_managed_launch_server_proxy(m, pa) \ + pt_managed_launch_proxy(m, pa, 1) + +void pt_configure_remaining_proxies(void); + +int pt_proxies_configuration_pending(void); + +void pt_free_all(void); + +#ifdef PT_PRIVATE +/** State of the managed proxy configuration protocol. */ +enum pt_proto_state { + PT_PROTO_INFANT, /* was just born */ + PT_PROTO_ACCEPTING_METHODS, /* accepting methods */ + PT_PROTO_CONFIGURED, /* configured successfully */ + PT_PROTO_COMPLETED, /* configure and registered its transports */ + PT_PROTO_BROKEN +}; + +/** Structure containing information of a managed proxy. */ +typedef struct { + enum pt_proto_state conf_state; /* the current configuration state */ + int conf_protocol; /* the configuration protocol version used */ + + FILE *stdout; /* a stream to its stdout + (closed in managed_proxy_destroy()) */ + + smartlist_t *transports; /* list of transports this proxy spawns */ +} managed_proxy_t; + +int parse_cmethod_line(char *line, managed_proxy_t *mp); +int parse_smethod_line(char *line, managed_proxy_t *mp); + +int parse_version(char *line, managed_proxy_t *mp); +void parse_env_error(char *line); +void handle_proxy_line(char *line, managed_proxy_t *mp); + +#endif + +#endif + From 5492de76dde34cb56c5658b6311772281c08c200 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 13 Jul 2011 19:06:07 +0200 Subject: [PATCH 04/36] Put some last missing pieces together. * Add some utility transport functions in circuitbuild.[ch] so that we can use them from pt.c. * Make the accounting system consider traffic coming from proxies. * Make sure that we only fetch bridge descriptors when all the transports are configured. --- src/or/circuitbuild.c | 65 +++++++++++++++++++++++++++++++------------ src/or/circuitbuild.h | 5 ++++ src/or/connection.c | 24 ++++++++++++++-- src/or/connection.h | 1 + src/or/main.c | 11 ++++++-- 5 files changed, 83 insertions(+), 23 deletions(-) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index aa0e996d17..f9b5c38256 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -26,6 +26,7 @@ #include "nodelist.h" #include "onion.h" #include "policies.h" +#include "pluggable_transports.h" #include "relay.h" #include "rephist.h" #include "router.h" @@ -124,7 +125,6 @@ static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); static void entry_guards_changed(void); static const transport_t *transport_get_by_name(const char *name); -static void transport_free(transport_t *transport); static void bridge_free(bridge_info_t *bridge); /** @@ -4591,7 +4591,7 @@ clear_transport_list(void) } /** Free the pluggable transport struct transport. */ -static void +void transport_free(transport_t *transport) { if (!transport) @@ -4619,29 +4619,35 @@ transport_get_by_name(const char *name) return NULL; } -/** Remember a new pluggable transport proxy at addr:port. - * name is set to the name of the protocol this proxy uses. - * socks_ver is set to the SOCKS version of the proxy. - * - * Returns 0 on success, -1 on fail. */ -int -transport_add_from_config(const tor_addr_t *addr, uint16_t port, - const char *name, int socks_ver) +/** Returns a transport_t struct for a transport proxy supporting the + protocol name listening at addr:port using + SOCKS version socks_ver. */ +transport_t * +transport_create(const tor_addr_t *addr, uint16_t port, + const char *name, int socks_ver) { - transport_t *t; + transport_t *t = tor_malloc_zero(sizeof(transport_t)); - if (transport_get_by_name(name)) { /* check for duplicate names */ - log_warn(LD_CONFIG, "More than one transport has '%s' as " - "its name.", name); - return -1; - } - - t = tor_malloc_zero(sizeof(transport_t)); tor_addr_copy(&t->addr, addr); t->port = port; t->name = tor_strdup(name); t->socks_version = socks_ver; + return t; +} + +/** Adds transport t to the internal list of pluggable transports. */ +int +transport_add(transport_t *t) +{ + assert(t); + + if (transport_get_by_name(t->name)) { /* check for duplicate names */ + log_notice(LD_CONFIG, "More than one transports have '%s' as " + "their name.", t->name); + return -1; + } + if (!transport_list) transport_list = smartlist_create(); @@ -4649,6 +4655,23 @@ transport_add_from_config(const tor_addr_t *addr, uint16_t port, return 0; } +/** Remember a new pluggable transport proxy at addr:port. + * name is set to the name of the protocol this proxy uses. + * socks_ver is set to the SOCKS version of the proxy. */ +int +transport_add_from_config(const tor_addr_t *addr, uint16_t port, + const char *name, int socks_ver) +{ + transport_t *t = transport_create(addr, port, name, socks_ver); + + if (transport_add(t) < 0) { + transport_free(t); + return -1; + } else { + return 0; + } +} + /** Warns the user of possible pluggable transport misconfiguration. */ void validate_pluggable_transports_config(void) @@ -4897,6 +4920,12 @@ fetch_bridge_descriptors(or_options_t *options, time_t now) if (!bridge_list) return; + /* ASN Should we move this to launch_direct_bridge_descriptor_fetch() ? */ + /* If we still have unconfigured managed proxies, don't go and + connect to a bridge. */ + if (pt_proxies_configuration_pending()) + return; + SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) { if (!download_status_is_ready(&bridge->fetch_status, now, diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 74715b7d06..92449b45c2 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -142,6 +142,11 @@ int circuit_build_times_get_bw_scale(networkstatus_t *ns); void clear_transport_list(void); int transport_add_from_config(const tor_addr_t *addr, uint16_t port, const char *name, int socks_ver); +int transport_add(transport_t *t); +void transport_free(transport_t *transport); +transport_t *transport_create(const tor_addr_t *addr, uint16_t port, + const char *name, int socks_ver); + int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, const transport_t **transport); void validate_pluggable_transports_config(void); diff --git a/src/or/connection.c b/src/or/connection.c index 00f25e6b52..5e8f95f522 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -2068,15 +2068,20 @@ retry_all_listeners(smartlist_t *replaced_conns, return retval; } -/** Return 1 if we should apply rate limiting to conn, - * and 0 otherwise. Right now this just checks if it's an internal - * IP address or an internal connection. */ +/** Return 1 if we should apply rate limiting to conn, and 0 + * otherwise. + * Right now this just checks if it's an internal IP address or an + * internal connection. We also check if the connection uses pluggable + * transports, since we should then limit it even if it comes from an + * internal IP address. */ static int connection_is_rate_limited(connection_t *conn) { or_options_t *options = get_options(); if (conn->linked) return 0; /* Internal connection */ + else if (connection_uses_transport(conn)) /* pluggable transport proxy */ + return 1; else if (! options->CountPrivateBandwidth && (tor_addr_family(&conn->addr) == AF_UNSPEC || /* no address */ tor_addr_is_internal(&conn->addr, 0))) @@ -4147,6 +4152,19 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, return 0; } +/** Returns true if connection conn is using a pluggable + * transports proxy server. */ +int +connection_uses_transport(connection_t *conn) +{ + const transport_t *transport=NULL; + if (find_transport_by_bridge_addrport(&conn->addr, + conn->port,&transport) == 0) + return 1; + else + return 0; +} + /** Returns the global proxy type used by tor. */ static int get_proxy_type(void) diff --git a/src/or/connection.h b/src/or/connection.h index be3de88aaa..51cf2a845a 100644 --- a/src/or/connection.h +++ b/src/or/connection.h @@ -60,6 +60,7 @@ int connection_read_proxy_handshake(connection_t *conn); void log_failed_proxy_connection(connection_t *conn); int get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, const connection_t *conn); +int connection_uses_transport(connection_t *conn); int retry_all_listeners(smartlist_t *replaced_conns, smartlist_t *new_conns); diff --git a/src/or/main.c b/src/or/main.c index 4d43267e45..d79d9ebaaa 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -37,6 +37,7 @@ #include "ntmain.h" #include "onion.h" #include "policies.h" +#include "pluggable_transports.h" #include "relay.h" #include "rendclient.h" #include "rendcommon.h" @@ -1447,7 +1448,7 @@ run_scheduled_events(time_t now) } } - /** 10b. write bridge networkstatus file to disk */ + /** 10. write bridge networkstatus file to disk */ if (options->BridgeAuthoritativeDir && time_to_write_bridge_status_file < now) { networkstatus_dump_bridge_status_to_file(now); @@ -1455,6 +1456,7 @@ run_scheduled_events(time_t now) time_to_write_bridge_status_file = now+BRIDGE_STATUSFILE_INTERVAL; } + /** 11. check the port forwarding app */ if (time_to_check_port_forwarding < now && options->PortForwarding && is_server) { @@ -1466,7 +1468,11 @@ run_scheduled_events(time_t now) time_to_check_port_forwarding = now+PORT_FORWARDING_CHECK_INTERVAL; } - /** 11. write the heartbeat message */ + /** 11b. check pending unconfigured managed proxies */ + if (pt_proxies_configuration_pending()) + pt_configure_remaining_proxies(); + + /** 12. write the heartbeat message */ if (options->HeartbeatPeriod && time_to_next_heartbeat < now) { log_heartbeat(now); @@ -2258,6 +2264,7 @@ tor_free_all(int postfork) clear_pending_onions(); circuit_free_all(); entry_guards_free_all(); + pt_free_all(); connection_free_all(); buf_shrink_freelists(1); memarea_clear_freelist(); From ce419a78c56e38fedcb3bce66fc08283648aed9f Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 13 Jul 2011 19:06:14 +0200 Subject: [PATCH 05/36] Add some unit tests. --- src/test/Makefile.am | 1 + src/test/test.c | 2 + src/test/test_pt.c | 149 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 src/test/test_pt.c diff --git a/src/test/Makefile.am b/src/test/Makefile.am index a4f93d1c9e..0597b65cc8 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -19,6 +19,7 @@ test_SOURCES = \ test_data.c \ test_dir.c \ test_microdesc.c \ + test_pt.c \ test_util.c \ tinytest.c diff --git a/src/test/test.c b/src/test/test.c index e2f8b115d3..6aba2006d8 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1261,6 +1261,7 @@ extern struct testcase_t container_tests[]; extern struct testcase_t util_tests[]; extern struct testcase_t dir_tests[]; extern struct testcase_t microdesc_tests[]; +extern struct testcase_t pt_tests[]; static struct testgroup_t testgroups[] = { { "", test_array }, @@ -1270,6 +1271,7 @@ static struct testgroup_t testgroups[] = { { "util/", util_tests }, { "dir/", dir_tests }, { "dir/md/", microdesc_tests }, + { "pt/", pt_tests }, END_OF_GROUPS }; diff --git a/src/test/test_pt.c b/src/test/test_pt.c new file mode 100644 index 0000000000..02950b8daa --- /dev/null +++ b/src/test/test_pt.c @@ -0,0 +1,149 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2011, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#define PT_PRIVATE +#include "or.h" +#include "pluggable_transports.h" +#include "circuitbuild.h" +#include "test.h" + +static void +reset_mp(managed_proxy_t *mp) +{ + mp->conf_state = PT_PROTO_INFANT; + SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); + smartlist_clear(mp->transports); + smartlist_free(mp->transports); + mp->transports = smartlist_create(); +} + +static void +test_pt_parsing(void) +{ + char line[200]; + + managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t)); + mp->conf_state = PT_PROTO_INFANT; + mp->transports = smartlist_create(); + + /* incomplete cmethod */ + strcpy(line,"CMETHOD trebuchet"); + test_assert(parse_cmethod_line(line, mp) < 0); + + reset_mp(mp); + + /* wrong proxy type */ + strcpy(line,"CMETHOD trebuchet dog 127.0.0.1:1999"); + test_assert(parse_cmethod_line(line, mp) < 0); + + reset_mp(mp); + + /* wrong addrport */ + strcpy(line,"CMETHOD trebuchet socks4 abcd"); + test_assert(parse_cmethod_line(line, mp) < 0); + + reset_mp(mp); + + /* correct line */ + strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999"); + test_assert(parse_cmethod_line(line, mp) == 0); + test_assert(smartlist_len(mp->transports)); + + reset_mp(mp); + + /* incomplete smethod */ + strcpy(line,"SMETHOD trebuchet"); + test_assert(parse_smethod_line(line, mp) < 0); + + reset_mp(mp); + + /* wrong addr type */ + strcpy(line,"SMETHOD trebuchet abcd"); + test_assert(parse_smethod_line(line, mp) < 0); + + reset_mp(mp); + + /* cowwect */ + strcpy(line,"SMETHOD trebuchy 127.0.0.1:1999"); + test_assert(parse_smethod_line(line, mp) == 0); + + reset_mp(mp); + + /* unsupported version */ + strcpy(line,"VERSION 666"); + test_assert(parse_version(line, mp) < 0); + + /* incomplete VERSION */ + strcpy(line,"VERSION "); + test_assert(parse_version(line, mp) < 0); + + /* correct VERSION */ + strcpy(line,"VERSION 1"); + test_assert(parse_version(line, mp) == 0); + + done: + tor_free(mp); +} + +static void +test_pt_protocol(void) +{ + char line[200]; + + managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t)); + mp->conf_state = PT_PROTO_INFANT; + mp->transports = smartlist_create(); + + /* various wrong protocol runs: */ + + strcpy(line, "TEST TEST"); + handle_proxy_line(line, mp); + test_assert(mp->conf_state == PT_PROTO_BROKEN); + + reset_mp(mp); + + strcpy(line,"VERSION 1"); + handle_proxy_line(line, mp); + test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); + + strcpy(line,"VERSION 1"); + handle_proxy_line(line, mp); + test_assert(mp->conf_state == PT_PROTO_BROKEN); + + reset_mp(mp); + + strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999"); + handle_proxy_line(line, mp); + test_assert(mp->conf_state == PT_PROTO_BROKEN); + + reset_mp(mp); + + /* correct protocol run: */ + strcpy(line,"VERSION 1"); + handle_proxy_line(line, mp); + test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); + + strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999"); + handle_proxy_line(line, mp); + test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); + + strcpy(line,"CMETHODS DONE"); + handle_proxy_line(line, mp); + test_assert(mp->conf_state == PT_PROTO_CONFIGURED); + + done: + tor_free(mp); +} + +#define PT_LEGACY(name) \ + { #name, legacy_test_helper, 0, &legacy_setup, test_pt_ ## name } + +struct testcase_t pt_tests[] = { + PT_LEGACY(parsing), + PT_LEGACY(protocol), + END_OF_TESTCASES +}; + From 684aca7faffea93a8e3dcb2a582aa10797f71e7d Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 14 Jul 2011 01:03:35 +0200 Subject: [PATCH 06/36] Changed a couple of 180 spec stuff according to #3578. * Restored "proxy" in external ServerTransportPlugin lines. * Changed the extended OR port and ORPort env. vars to addr:port. --- src/or/circuitbuild.c | 2 +- src/or/config.c | 108 +++++++++++++++++----------------- src/or/pluggable_transports.c | 4 +- 3 files changed, 56 insertions(+), 58 deletions(-) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index f9b5c38256..003f579e75 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -4610,7 +4610,7 @@ transport_get_by_name(const char *name) if (!transport_list) return NULL; - + SMARTLIST_FOREACH_BEGIN(transport_list, const transport_t *, transport) { if (!strcmp(transport->name, name)) return transport; diff --git a/src/or/config.c b/src/or/config.c index 111b28b983..5f2f11dddf 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1224,7 +1224,6 @@ options_act(or_options_t *old_options) } } - clear_transport_list(); if (options->ServerTransportPlugin) { for (cl = options->ServerTransportPlugin; cl; cl = cl->next) { if (parse_server_transport_line(cl->value, 0)<0) { @@ -4732,26 +4731,10 @@ parse_client_transport_line(const char *line, int validate_only) goto err; } - if (!is_managed) { - addrport = smartlist_get(items, 0); - smartlist_del_keeporder(items, 0); - - if (tor_addr_port_parse(addrport, &addr, &port)<0) { - log_warn(LD_CONFIG, "Error parsing transport " - "address '%s'", addrport); - goto err; - } - if (!port) { - log_warn(LD_CONFIG, - "Transport address '%s' has no port.", addrport); - goto err; - } - } - - if (!validate_only) { - if (is_managed) { /* if it's managed, and we are planning on - launching the proxy, use the rest of the line - as the argv. */ + if (is_managed) { /* managed */ + if (!validate_only) { /* if we are not just validating, use the + rest of the line as the argv of the proxy + to be launched */ char **tmp; char *tmp_arg; proxy_argv = tor_malloc_zero(sizeof(char*)*(smartlist_len(items)+1)); @@ -4769,12 +4752,29 @@ parse_client_transport_line(const char *line, int validate_only) proxy_argv[0]); goto err; } - } else { /* external */ + } + } else { /* external */ + addrport = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); + + if (tor_addr_port_parse(addrport, &addr, &port)<0) { + log_warn(LD_CONFIG, "Error parsing transport " + "address '%s'", addrport); + goto err; + } + if (!port) { + log_warn(LD_CONFIG, + "Transport address '%s' has no port.", addrport); + goto err; + } + + if (!validate_only) { if (transport_add_from_config(&addr, port, name, socks_ver) < 0) { goto err; } - log_debug(LD_DIR, "Transport %s found at %s:%d", name, + + log_debug(LD_DIR, "Transport '%s' found at %s:%d", name, fmt_addr(&addr), (int)port); } } @@ -4805,7 +4805,7 @@ parse_server_transport_line(const char *line, int validate_only) smartlist_t *items = NULL; int r; char *name=NULL; - char *field2=NULL; + char *type=NULL; char *addrport=NULL; tor_addr_t addr; uint16_t port = 0; @@ -4826,38 +4826,20 @@ parse_server_transport_line(const char *line, int validate_only) name = smartlist_get(items, 0); smartlist_del_keeporder(items, 0); - /* field2 is either or "exec" */ - field2 = smartlist_get(items, 0); + type = smartlist_get(items, 0); smartlist_del_keeporder(items, 0); - if (!(strstr(field2, ".") || strstr(field2, ":"))) { /* managed proxy */ - if (strcmp(field2, "exec")) { - log_warn(LD_CONFIG, "Unrecognizable field '%s' in " - "ServerTransportPlugin line", field2); - goto err; - } + if (!strcmp(type, "exec")) { is_managed=1; + } else if (!strcmp(type, "proxy")) { + is_managed=0; + } else { + log_warn(LD_CONFIG, "Strange ServerTransportPlugin type '%s'", type); + goto err; } - if (!is_managed) { - addrport = field2; - - if (tor_addr_port_parse(addrport, &addr, &port)<0) { - log_warn(LD_CONFIG, "Error parsing transport " - "address '%s'", addrport); - goto err; - } - if (!port) { - log_warn(LD_CONFIG, - "Transport address '%s' has no port.", addrport); - goto err; - } - } - - if (!validate_only) { - if (is_managed) { /* if it's managed, and we are planning on - launching the proxy, use the rest of the line - as the argv. */ + if (is_managed) { /* managed */ + if (!validate_only) { char **tmp; char *tmp_arg; proxy_argv = tor_malloc_zero(sizeof(char*)*(smartlist_len(items)+1)); @@ -4870,13 +4852,29 @@ parse_server_transport_line(const char *line, int validate_only) } *tmp = NULL; /*terminated with NUL pointer, just like execve() likes it*/ - if (pt_managed_launch_server_proxy(name, proxy_argv) < 0) { + if (pt_managed_launch_server_proxy(name, proxy_argv) < 0) { /* launch it! */ log_warn(LD_CONFIG, "Error while launching managed proxy at '%s'", proxy_argv[0]); goto err; } - } else { - log_warn(LD_DIR, "Transport %s at %s:%d", name, + } + } else { /* external */ + addrport = smartlist_get(items, 0); + smartlist_del_keeporder(items, 0); + + if (tor_addr_port_parse(addrport, &addr, &port)<0) { + log_warn(LD_CONFIG, "Error parsing transport " + "address '%s'", addrport); + goto err; + } + if (!port) { + log_warn(LD_CONFIG, + "Transport address '%s' has no port.", addrport); + goto err; + } + + if (!validate_only) { + log_warn(LD_DIR, "Transport '%s' at %s:%d.", name, fmt_addr(&addr), (int)port); } } @@ -4891,7 +4889,7 @@ parse_server_transport_line(const char *line, int validate_only) SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); tor_free(name); - tor_free(field2); + tor_free(type); return r; } diff --git a/src/or/pluggable_transports.c b/src/or/pluggable_transports.c index 5448c409cd..49b0e131af 100644 --- a/src/or/pluggable_transports.c +++ b/src/or/pluggable_transports.c @@ -565,10 +565,10 @@ set_environ(char ***envp, const char *method, int is_server) tor_asprintf(tmp++, "TOR_PT_MANAGED_TRANSPORT_VER=1"); /* temp */ if (is_server) { /* ASN check for ORPort values, should we be here if it's 0? */ - tor_asprintf(tmp++, "TOR_PT_ORPORT=%d", options->ORPort); + tor_asprintf(tmp++, "TOR_PT_ORPORT=127.0.0.1:%d", options->ORPort); /* temp */ tor_asprintf(tmp++, "TOR_PT_SERVER_BINDADDR=127.0.0.1:0"); tor_asprintf(tmp++, "TOR_PT_SERVER_TRANSPORTS=%s", method); - tor_asprintf(tmp++, "TOR_PT_EXTENDED_SERVER_PORT=4200"); + tor_asprintf(tmp++, "TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200"); /* temp*/ } else { tor_asprintf(tmp++, "TOR_PT_CLIENT_TRANSPORTS=%s", method); } From 86b20e0d8ac0cc87cf85e34666d6cd25a9657521 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 14 Jul 2011 04:24:10 +0200 Subject: [PATCH 07/36] Reverting the accounting thing introduced in 5492de76 till I think how it should be done properly. --- src/or/connection.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/or/connection.c b/src/or/connection.c index 5e8f95f522..04dba2b9b0 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -2080,8 +2080,6 @@ connection_is_rate_limited(connection_t *conn) or_options_t *options = get_options(); if (conn->linked) return 0; /* Internal connection */ - else if (connection_uses_transport(conn)) /* pluggable transport proxy */ - return 1; else if (! options->CountPrivateBandwidth && (tor_addr_family(&conn->addr) == AF_UNSPEC || /* no address */ tor_addr_is_internal(&conn->addr, 0))) @@ -4158,11 +4156,9 @@ int connection_uses_transport(connection_t *conn) { const transport_t *transport=NULL; - if (find_transport_by_bridge_addrport(&conn->addr, - conn->port,&transport) == 0) - return 1; - else - return 0; + find_transport_by_bridge_addrport(&conn->addr, + conn->port,&transport); + return transport ? 1 : 0; } /** Returns the global proxy type used by tor. */ From d8c04c7ea52bc1ffbeec60d614970eccab3c9b4f Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 18 Jul 2011 02:19:38 +0200 Subject: [PATCH 08/36] Renamed pluggable_transports.[ch] to transports.[ch]. --- src/or/{pluggable_transports.c => transports.c} | 0 src/or/{pluggable_transports.h => transports.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/or/{pluggable_transports.c => transports.c} (100%) rename src/or/{pluggable_transports.h => transports.h} (100%) diff --git a/src/or/pluggable_transports.c b/src/or/transports.c similarity index 100% rename from src/or/pluggable_transports.c rename to src/or/transports.c diff --git a/src/or/pluggable_transports.h b/src/or/transports.h similarity index 100% rename from src/or/pluggable_transports.h rename to src/or/transports.h From a8f21f91cfa916b662d07dd486857fdf848c6f1d Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 18 Jul 2011 02:33:31 +0200 Subject: [PATCH 09/36] Updated #includes etc. to use transports.[ch]. --- src/or/Makefile.am | 4 ++-- src/or/circuitbuild.c | 2 +- src/or/config.c | 2 +- src/or/main.c | 2 +- src/or/transports.c | 4 ++-- src/or/transports.h | 8 ++++---- src/test/test_pt.c | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/or/Makefile.am b/src/or/Makefile.am index 4dc5ee55f6..41e89d7419 100644 --- a/src/or/Makefile.am +++ b/src/or/Makefile.am @@ -39,7 +39,7 @@ libtor_a_SOURCES = \ networkstatus.c \ nodelist.c \ onion.c \ - pluggable_transports.c \ + transports.c \ policies.c \ reasons.c \ relay.c \ @@ -105,7 +105,7 @@ noinst_HEADERS = \ ntmain.h \ onion.h \ or.h \ - pluggable_transports.h \ + transports.h \ policies.h \ reasons.h \ relay.h \ diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 003f579e75..3dba83ba30 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -26,7 +26,7 @@ #include "nodelist.h" #include "onion.h" #include "policies.h" -#include "pluggable_transports.h" +#include "transports.h" #include "relay.h" #include "rephist.h" #include "router.h" diff --git a/src/or/config.c b/src/or/config.c index 5f2f11dddf..da35270b4b 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -35,7 +35,7 @@ #include "router.h" #include "util.h" #include "routerlist.h" -#include "pluggable_transports.h" +#include "transports.h" #ifdef MS_WINDOWS #include #endif diff --git a/src/or/main.c b/src/or/main.c index d79d9ebaaa..5294e4ad0d 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -37,7 +37,7 @@ #include "ntmain.h" #include "onion.h" #include "policies.h" -#include "pluggable_transports.h" +#include "transports.h" #include "relay.h" #include "rendclient.h" #include "rendcommon.h" diff --git a/src/or/transports.c b/src/or/transports.c index 49b0e131af..aae39cd8f0 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -2,7 +2,7 @@ /* See LICENSE for licensing information */ /** - * \file pluggable_transports.c + * \file transports.c * \brief Pluggable Transports related code. **/ @@ -10,7 +10,7 @@ #include "or.h" #include "config.h" #include "circuitbuild.h" -#include "pluggable_transports.h" +#include "transports.h" /* ASN TIDY THESE UP*/ static void set_environ(char ***envp, const char *method, diff --git a/src/or/transports.h b/src/or/transports.h index 80d5429e70..17a68030d7 100644 --- a/src/or/transports.h +++ b/src/or/transports.h @@ -4,12 +4,12 @@ /* See LICENSE for licensing information */ /** - * \file pluggable_transpots.h - * \brief Headers for pluggable_transpots.c + * \file transports.h + * \brief Headers for transports.c **/ -#ifndef TOR_PLUGGABLE_TRANSPORTS_H -#define TOR_PLUGGABLE_TRANSPORTS_H +#ifndef TOR_TRANSPORTS_H +#define TOR_TRANSPORTS_H int pt_managed_launch_proxy(const char *method, char **proxy_argv, int is_server); diff --git a/src/test/test_pt.c b/src/test/test_pt.c index 02950b8daa..99fc5145e0 100644 --- a/src/test/test_pt.c +++ b/src/test/test_pt.c @@ -6,7 +6,7 @@ #include "orconfig.h" #define PT_PRIVATE #include "or.h" -#include "pluggable_transports.h" +#include "transports.h" #include "circuitbuild.h" #include "test.h" From 14c5a24fe74f7ebaf94c69721025f142d42ef1e0 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 18 Jul 2011 02:35:29 +0200 Subject: [PATCH 10/36] Replaced ST_* enum prefix for stream status with IO_STREAM_*. --- src/common/util.c | 18 +++++++++--------- src/common/util.h | 8 ++++---- src/or/transports.c | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/common/util.c b/src/common/util.c index 5f4472bff3..c2db5422dc 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -3140,10 +3140,10 @@ tor_spawn_background(const char *const filename, int *stdout_read, * fits your needs before using it. * * Returns: - * ST_CLOSED: If the stream is closed. - * ST_EAGAIN: If there is nothing to read and we should check back later. - * ST_TERM: If something is wrong with the stream. - * ST_OKAY: If everything went okay and we got a string in buf_out. */ + * IO_STREAM_CLOSED: If the stream is closed. + * IO_STREAM_EAGAIN: If there is nothing to read and we should check back later. + * IO_STREAM_TERM: If something is wrong with the stream. + * IO_STREAM_OKAY: If everything went okay and we got a string in buf_out. */ enum stream_status get_string_from_pipe(FILE *stream, char *buf_out, size_t count) { @@ -3156,14 +3156,14 @@ get_string_from_pipe(FILE *stream, char *buf_out, size_t count) if (feof(stream)) { /* Program has closed stream (probably it exited) */ /* TODO: check error */ - return ST_CLOSED; + return IO_STREAM_CLOSED; } else { if (EAGAIN == errno) { /* Nothing more to read, try again next time */ - return ST_EAGAIN; + return IO_STREAM_EAGAIN; } else { /* There was a problem, abandon this child process */ - return ST_TERM; + return IO_STREAM_TERM; } } } else { @@ -3175,11 +3175,11 @@ get_string_from_pipe(FILE *stream, char *buf_out, size_t count) buf_out[len - 1] = '\0'; } - return ST_OKAY; + return IO_STREAM_OKAY; } /* We should never get here */ - return ST_TERM; + return IO_STREAM_TERM; } /** Read from stream, and send lines to log at the specified log level. diff --git a/src/common/util.h b/src/common/util.h index 1b81fa3149..12dc106ace 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -281,10 +281,10 @@ ssize_t read_all(tor_socket_t fd, char *buf, size_t count, int isSocket); /** Status of an I/O stream. */ enum stream_status { - ST_OKAY, - ST_EAGAIN, - ST_TERM, - ST_CLOSED + IO_STREAM_OKAY, + IO_STREAM_EAGAIN, + IO_STREAM_TERM, + IO_STREAM_CLOSED }; enum stream_status get_string_from_pipe(FILE *stream, char *buf, size_t count); diff --git a/src/or/transports.c b/src/or/transports.c index aae39cd8f0..6589a8cd97 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -163,14 +163,14 @@ configure_proxy(managed_proxy_t *mp) r = get_string_from_pipe(mp->stdout, stdout_buf, sizeof(stdout_buf) - 1); - if (r == ST_CLOSED || r == ST_TERM) { + if (r == IO_STREAM_CLOSED || r == IO_STREAM_TERM) { log_warn(LD_GENERAL, "Managed proxy stream closed. " "Most probably application stopped running"); mp->conf_state = PT_PROTO_BROKEN; - } else if (r == ST_EAGAIN) { + } else if (r == IO_STREAM_EAGAIN) { return; } else { - tor_assert(r == ST_OKAY); + tor_assert(r == IO_STREAM_OKAY); handle_proxy_line(stdout_buf, mp); } From 51cdd30c01c47e3522bd49a23a83a566cf4de5a7 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 18 Jul 2011 16:42:31 +0200 Subject: [PATCH 11/36] Let's be smarter while parsing {Client,Server}TransportPlugin lines. --- src/or/config.c | 64 ++++++++++++++++++++------------------------- src/or/transports.c | 1 - 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index da35270b4b..02925f39b8 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -4702,22 +4702,25 @@ parse_client_transport_line(const char *line, int validate_only) /* managed proxy options */ int is_managed=0; char **proxy_argv=NULL; + char **tmp=NULL; + int proxy_argc,i; + + int line_length; items = smartlist_create(); smartlist_split_string(items, line, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); - if (smartlist_len(items) < 3) { + line_length = smartlist_len(items); + if (line_length < 3) { log_warn(LD_CONFIG, "Too few arguments on ClientTransportPlugin line."); goto err; } name = smartlist_get(items, 0); - smartlist_del_keeporder(items, 0); /* field2 is either a SOCKS version or "exec" */ - field2 = smartlist_get(items, 0); - smartlist_del_keeporder(items, 0); + field2 = smartlist_get(items, 1); if (!strcmp(field2,"socks4")) { socks_ver = PROXY_SOCKS4; @@ -4735,16 +4738,12 @@ parse_client_transport_line(const char *line, int validate_only) if (!validate_only) { /* if we are not just validating, use the rest of the line as the argv of the proxy to be launched */ - char **tmp; - char *tmp_arg; - proxy_argv = tor_malloc_zero(sizeof(char*)*(smartlist_len(items)+1)); + proxy_argc = line_length-2; + tor_assert(proxy_argc > 0); + proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1)); tmp = proxy_argv; - while (smartlist_len(items)) { - tmp_arg = smartlist_get(items, 0); - smartlist_del_keeporder(items, 0); - *tmp++ = tor_strdup(tmp_arg); - tor_free(tmp_arg); - } + for (i=0;i 0); + proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1)); tmp = proxy_argv; - while (smartlist_len(items)) { - tmp_arg = smartlist_get(items, 0); - smartlist_del_keeporder(items, 0); - *tmp++ = tor_strdup(tmp_arg); - tor_free(tmp_arg); - } + + for (i=0;i Date: Mon, 18 Jul 2011 17:06:16 +0200 Subject: [PATCH 12/36] Reuse get_string_from_pipe() in log_from_pipe(). --- src/common/util.c | 91 +++++++++++++++++++-------------------------- src/or/transports.c | 2 - 2 files changed, 38 insertions(+), 55 deletions(-) diff --git a/src/common/util.c b/src/common/util.c index c2db5422dc..7a7ee195ba 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -3173,6 +3173,12 @@ get_string_from_pipe(FILE *stream, char *buf_out, size_t count) if (buf_out[len - 1] == '\n') { /* Remove the trailing newline */ buf_out[len - 1] = '\0'; + } else { + /* No newline; check whether we overflowed the buffer */ + if (!feof(stream)) + log_warn(LD_GENERAL, + "Line from stream was truncated: %s", buf_out); + /* TODO: What to do with this error? */ } return IO_STREAM_OKAY; @@ -3192,65 +3198,44 @@ log_from_pipe(FILE *stream, int severity, const char *executable, int *child_status) { char buf[256]; + enum stream_status r; for (;;) { - char *retval; - retval = fgets(buf, sizeof(buf), stream); + r = get_string_from_pipe(stream, buf, sizeof(buf) - 1); - if (NULL == retval) { - if (feof(stream)) { - /* Program has closed stream (probably it exited) */ - /* TODO: check error */ - fclose(stream); - return 1; + if (r == IO_STREAM_CLOSED) { + fclose(stream); + return 1; + } else if (r == IO_STREAM_EAGAIN) { + return 0; + } else if (r == IO_STREAM_TERM) { + fclose(stream); + return -1; + } + + tor_assert(r == IO_STREAM_OKAY); + + /* Check if buf starts with SPAWN_ERROR_MESSAGE */ + if (strcmpstart(buf, SPAWN_ERROR_MESSAGE) == 0) { + /* Parse error message */ + int retval, child_state, saved_errno; + retval = tor_sscanf(buf, SPAWN_ERROR_MESSAGE "%x/%x", + &child_state, &saved_errno); + if (retval == 2) { + log_warn(LD_GENERAL, + "Failed to start child process \"%s\" in state %d: %s", + executable, child_state, strerror(saved_errno)); + if (child_status) + *child_status = 1; } else { - if (EAGAIN == errno) { - /* Nothing more to read, try again next time */ - return 0; - } else { - /* There was a problem, abandon this child process */ - fclose(stream); - return -1; - } + /* Failed to parse message from child process, log it as a + warning */ + log_warn(LD_GENERAL, + "Unexpected message from port forwarding helper \"%s\": %s", + executable, buf); } } else { - /* We have some data, log it and keep asking for more */ - size_t len; - - len = strlen(buf); - if (buf[len - 1] == '\n') { - /* Remove the trailing newline */ - buf[len - 1] = '\0'; - } else { - /* No newline; check whether we overflowed the buffer */ - if (!feof(stream)) - log_warn(LD_GENERAL, - "Line from port forwarding helper was truncated: %s", buf); - /* TODO: What to do with this error? */ - } - - /* Check if buf starts with SPAWN_ERROR_MESSAGE */ - if (strcmpstart(buf, SPAWN_ERROR_MESSAGE) == 0) { - /* Parse error message */ - int retval, child_state, saved_errno; - retval = tor_sscanf(buf, SPAWN_ERROR_MESSAGE "%x/%x", - &child_state, &saved_errno); - if (retval == 2) { - log_warn(LD_GENERAL, - "Failed to start child process \"%s\" in state %d: %s", - executable, child_state, strerror(saved_errno)); - if (child_status) - *child_status = 1; - } else { - /* Failed to parse message from child process, log it as a - warning */ - log_warn(LD_GENERAL, - "Unexpected message from port forwarding helper \"%s\": %s", - executable, buf); - } - } else { - log_fn(severity, LD_GENERAL, "Port forwarding helper says: %s", buf); - } + log_fn(severity, LD_GENERAL, "Port forwarding helper says: %s", buf); } } diff --git a/src/or/transports.c b/src/or/transports.c index 930cb8c0ce..392c43decd 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -157,8 +157,6 @@ configure_proxy(managed_proxy_t *mp) char stdout_buf[200]; while (1) { - memset(stdout_buf, 0, sizeof(stdout_buf)); - r = get_string_from_pipe(mp->stdout, stdout_buf, sizeof(stdout_buf) - 1); From cfb473ed348063e1f1abd709ac313f14d33cadf5 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 18 Jul 2011 17:08:55 +0200 Subject: [PATCH 13/36] Changed a printf() to a log_debug(). --- src/or/transports.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/or/transports.c b/src/or/transports.c index 392c43decd..21d76f80da 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -254,7 +254,7 @@ proxy_configuration_finished(managed_proxy_t *mp) void handle_proxy_line(char *line, managed_proxy_t *mp) { - printf("Judging line: %s\n", line); + log_debug(LD_CONFIG, "Judging line: %s\n", line); if (strlen(line) < SMALLEST_MANAGED_LINE_SIZE) { log_warn(LD_GENERAL, "Managed proxy configuration line is too small. " From 941709ee50654b9ef59836fadbd8c4e7029c9fc1 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 7 Aug 2011 18:05:40 +0200 Subject: [PATCH 14/36] Server transport proxies should bind on the same port each time, if possible. --- src/or/circuitbuild.c | 2 +- src/or/config.c | 235 +++++++++++++++++++++++++++++++++++++----- src/or/config.h | 4 + src/or/or.h | 2 + src/or/transports.c | 78 ++++++++++---- src/or/transports.h | 4 +- 6 files changed, 276 insertions(+), 49 deletions(-) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 3dba83ba30..fe57070ac1 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -4610,7 +4610,7 @@ transport_get_by_name(const char *name) if (!transport_list) return NULL; - + SMARTLIST_FOREACH_BEGIN(transport_list, const transport_t *, transport) { if (!strcmp(transport->name, name)) return transport; diff --git a/src/or/config.c b/src/or/config.c index 02925f39b8..dced47c030 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -473,6 +473,9 @@ static config_var_t _state_vars[] = { VAR("EntryGuardAddedBy", LINELIST_S, EntryGuards, NULL), V(EntryGuards, LINELIST_V, NULL), + VAR("TransportProxy", LINELIST_S, TransportProxies, NULL), + V(TransportProxies, LINELIST_V, NULL), + V(BWHistoryReadEnds, ISOTIME, NULL), V(BWHistoryReadInterval, UINT, "900"), V(BWHistoryReadValues, CSV, ""), @@ -499,7 +502,6 @@ static config_var_t _state_vars[] = { V(CircuitBuildAbandonedCount, UINT, "0"), VAR("CircuitBuildTimeBin", LINELIST_S, BuildtimeHistogram, NULL), VAR("BuildtimeHistogram", LINELIST_V, BuildtimeHistogram, NULL), - { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL } }; @@ -1212,29 +1214,6 @@ options_act(or_options_t *old_options) if (consider_adding_dir_authorities(options, old_options) < 0) return -1; - clear_transport_list(); - if (options->ClientTransportPlugin) { - for (cl = options->ClientTransportPlugin; cl; cl = cl->next) { - if (parse_client_transport_line(cl->value, 0)<0) { - log_warn(LD_BUG, - "Previously validated ClientTransportPlugin line " - "could not be added!"); - return -1; - } - } - } - - if (options->ServerTransportPlugin) { - for (cl = options->ServerTransportPlugin; cl; cl = cl->next) { - if (parse_server_transport_line(cl->value, 0)<0) { - log_warn(LD_BUG, - "Previously validated ServerTransportPlugin line " - "could not be added!"); - return -1; - } - } - } - if (options->Bridges) { mark_bridge_list(); for (cl = options->Bridges; cl; cl = cl->next) { @@ -1271,6 +1250,30 @@ options_act(or_options_t *old_options) rep_hist_load_mtbf_data(time(NULL)); } + + clear_transport_list(); + if (options->ClientTransportPlugin) { + for (cl = options->ClientTransportPlugin; cl; cl = cl->next) { + if (parse_client_transport_line(cl->value, 0)<0) { + log_warn(LD_BUG, + "Previously validated ClientTransportPlugin line " + "could not be added!"); + return -1; + } + } + } + + if (options->ServerTransportPlugin) { + for (cl = options->ServerTransportPlugin; cl; cl = cl->next) { + if (parse_server_transport_line(cl->value, 0)<0) { + log_warn(LD_BUG, + "Previously validated ServerTransportPlugin line " + "could not be added!"); + return -1; + } + } + } + /* Bail out at this point if we're not going to be a client or server: * we want to not fork, and to log stuff to stderr. */ if (!running_tor) @@ -5465,6 +5468,74 @@ options_get_datadir_fname2_suffix(or_options_t *options, return fname; } +/** Return true if line is a valid state TransportProxy line. + * Return false otherwise. */ +static int +state_transport_line_is_valid(char *line) +{ + smartlist_t *items = NULL; + char *addrport=NULL; + tor_addr_t addr; + uint16_t port = 0; + int r; + + items = smartlist_create(); + smartlist_split_string(items, line, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + + if (smartlist_len(items) != 2) { + log_warn(LD_CONFIG, "state: Not enough arguments in TransportProxy line."); + goto err; + } + + addrport = smartlist_get(items, 1); + if (tor_addr_port_parse(addrport, &addr, &port) < 0) { + log_warn(LD_CONFIG, "state: Could not parse addrport."); + goto err; + } + + if (!port) { + log_warn(LD_CONFIG, "state: Transport line did not contain port."); + goto err; + } + + r = 1; + goto done; + + err: + r = 0; + + done: + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + return r; +} + +/** Return 0 if all TransportProxy lines in state are well + * formed. Otherwise, return -1. */ +static int +validate_transports_in_state(or_state_t *state) +{ + int broken = 0; + + config_var_t *var = config_find_option(&state_format,"TransportProxies"); + if (!var) + return 0; + + config_line_t **value = STRUCT_VAR_P(state, var->var_offset); + config_line_t *search = NULL; + + for (search = *value ; search ; search = search->next) { + if (!state_transport_line_is_valid(search->value)<0) + broken = 1; + } + + if (broken) + log_warn(LD_CONFIG, "state: State file seems to be broken."); + + return 0; +} + /** Return 0 if every setting in state is reasonable, and a * permissible transition from old_state. Else warn and return -1. * Should have no side effects, except for normalizing the contents of @@ -5483,6 +5554,9 @@ or_state_validate(or_state_t *old_state, or_state_t *state, if (entry_guards_parse_state(state, 0, msg)<0) return -1; + if (validate_transports_in_state(state)<0) + return -1; + return 0; } @@ -5715,6 +5789,118 @@ or_state_save(time_t now) return 0; } +/** Return the config line for transport transport in the current state. + * Return NULL if there is no config line for transport. */ +static config_line_t * +get_transport_in_state_by_name(const char *transport) +{ + config_var_t *var = config_find_option(&state_format,"TransportProxies"); + if (!var) + return NULL; + + config_line_t **value = STRUCT_VAR_P(get_or_state(), var->var_offset); + config_line_t *search = *value; + + while (search) { + if (!strcmpstart(search->value, transport)) + return search; + + search = search->next; + } + return NULL; +} + +/** Return string containing the address:port part of the + * TransportProxy line for transport transport. If the + * line is corrupted, return NULL. */ +const char * +get_transport_bindaddr(const char *line, const char *transport) +{ + if (strlen(line) < strlen(transport) + 2) + return NULL; + else + return (line+strlen(transport)+1); +} + +/** Return a string containing the address:port that transport + * should use. */ +const char * +get_bindaddr_for_transport(const char *transport) +{ + static const char default_addrport[] = "127.0.0.1:0"; + const char *bindaddr = NULL; + + config_line_t *line = get_transport_in_state_by_name(transport); + if (!line) + return default_addrport; + + bindaddr = get_transport_bindaddr(line->value, transport); + + return bindaddr ? bindaddr : default_addrport; +} + +/** Save transport listening at addr:port to + * state */ +void +save_transport_to_state(const char *transport, + tor_addr_t *addr, uint16_t port) +{ + or_state_t *state = get_or_state(); + + char *transport_addrport=NULL; + + /** find where to write on the state */ + config_line_t **next, *line; + + /* see if this transport is already stored in state */ + config_line_t *transport_line = + get_transport_in_state_by_name(transport); + + if (transport_line) { /* if transport_exists_in_state() */ + const char *prev_bindaddr = /* get addrport stored in state */ + get_transport_bindaddr(transport_line->value, transport); + tor_asprintf(&transport_addrport, "%s:%d", fmt_addr(addr), (int)port); + + /* if transport in state has the same address as this one, life is good */ + if (!strcmp(prev_bindaddr, transport_addrport)) { + log_warn(LD_CONFIG, "Transport seems to have spawned on its usual address:port."); + goto done; + } else { /* addrport in state is different than the one we got */ + log_warn(LD_CONFIG, "Transport seems to have spawned on different address:port." + "Let's update the state file with the new address:port"); + tor_free(transport_line->value); /* free the old line */ + tor_asprintf(&transport_line->value, "%s %s:%d", transport, + fmt_addr(addr), + (int) port); /* replace old addrport line with new line */ + } + } else { /* never seen this one before; save it in state for next time */ + log_warn(LD_CONFIG, "It's the first time we see this transport. " + "Let's save its address:port"); + next = &state->TransportProxies; + /* find the last TransportProxy line in the state and point 'next' + right after it */ + line = state->TransportProxies; + while (line) { + next = &(line->next); + line = line->next; + } + + /* allocate space for the new line and fill it in */ + *next = line = tor_malloc_zero(sizeof(config_line_t)); + line->key = tor_strdup("TransportProxy"); + tor_asprintf(&line->value, "%s %s:%d", transport, + fmt_addr(addr), (int) port); + + next = &(line->next); + } + + if (!get_options()->AvoidDiskWrites) + or_state_mark_dirty(state, 0); + + done: + tor_free(transport_addrport); +} + /** Given a file name check to see whether the file exists but has not been * modified for a very long time. If so, remove it. */ void @@ -5782,4 +5968,3 @@ getinfo_helper_config(control_connection_t *conn, } return 0; } - diff --git a/src/or/config.h b/src/or/config.h index 49f7e25be6..dc3a828749 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -63,6 +63,10 @@ or_state_t *get_or_state(void); int did_last_state_file_write_fail(void); int or_state_save(time_t now); +void save_transport_to_state(const char *transport_name, + tor_addr_t *addr, uint16_t port); +const char * get_bindaddr_for_transport(const char *transport); + int options_need_geoip_info(or_options_t *options, const char **reason_out); int getinfo_helper_config(control_connection_t *conn, const char *question, char **answer, diff --git a/src/or/or.h b/src/or/or.h index 8bcfc82ce4..d07422f278 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3139,6 +3139,8 @@ typedef struct { /** A list of Entry Guard-related configuration lines. */ config_line_t *EntryGuards; + config_line_t *TransportProxies; + /** These fields hold information on the history of bandwidth usage for * servers. The "Ends" fields hold the time when we last updated the * bandwidth usage. The "Interval" fields hold the granularity, in seconds, diff --git a/src/or/transports.c b/src/or/transports.c index 21d76f80da..b96792f549 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -19,10 +19,11 @@ static INLINE int proxy_configuration_finished(managed_proxy_t *mp); static void managed_proxy_destroy(managed_proxy_t *mp, int also_free_transports); -static void register_proxy_transports(managed_proxy_t *mp); static void handle_finished_proxy(managed_proxy_t *mp); static void configure_proxy(managed_proxy_t *mp); +static void register_server_proxy(managed_proxy_t *mp); + static void parse_method_error(char *line, int is_server_method); #define parse_server_method_error(l) parse_method_error(l, 1) #define parse_client_method_error(l) parse_method_error(l, 0) @@ -119,6 +120,7 @@ pt_managed_launch_proxy(const char *method, mp->conf_state = PT_PROTO_INFANT; mp->stdout = stdout_read; mp->transports = smartlist_create(); + mp->is_server = is_server; /* register the managed proxy */ if (!unconfigured_proxy_list) @@ -179,6 +181,42 @@ configure_proxy(managed_proxy_t *mp) } } +/** Register server managed proxy mp transports to state */ +static void +register_server_proxy(managed_proxy_t *mp) +{ + if (mp->is_server) { + SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) { + save_transport_to_state(t->name,&t->addr,t->port); /* pass tor_addr_t? */ + } SMARTLIST_FOREACH_END(t); + } +} + +/** Register all the transports supported by client managed proxy + * mp to the bridge subsystem. */ +static void +register_client_proxy(managed_proxy_t *mp) +{ + SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) { + if (transport_add(t)<0) { + log_warn(LD_GENERAL, "Could not add transport %s. Skipping.", t->name); + transport_free(t); + } else { + log_warn(LD_GENERAL, "Succesfully registered transport %s", t->name); + } + } SMARTLIST_FOREACH_END(t); +} + +/** Register the transports of managed proxy mp. */ +static INLINE void +register_proxy(managed_proxy_t *mp) +{ + if (mp->is_server) + register_server_proxy(mp); + else + register_client_proxy(mp); +} + /** Handle a configured or broken managed proxy mp. */ static void handle_finished_proxy(managed_proxy_t *mp) @@ -188,7 +226,7 @@ handle_finished_proxy(managed_proxy_t *mp) managed_proxy_destroy(mp, 1); /* destroy it and all its transports */ break; case PT_PROTO_CONFIGURED: /* if configured correctly: */ - register_proxy_transports(mp); /* register all its transports, */ + register_proxy(mp); /* register transports */ mp->conf_state = PT_PROTO_COMPLETED; /* mark it as completed, */ managed_proxy_destroy(mp, 0); /* destroy the managed proxy struct, keeping the transports intact */ @@ -203,20 +241,6 @@ handle_finished_proxy(managed_proxy_t *mp) tor_assert(n_unconfigured_proxies >= 0); } -/** Register all the transports supported by managed proxy mp. */ -static void -register_proxy_transports(managed_proxy_t *mp) -{ - SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) { - if (transport_add(t)<0) { - log_warn(LD_GENERAL, "Could not add transport %s. Skipping.", t->name); - transport_free(t); - } else { - log_warn(LD_GENERAL, "Succesfully registered transport %s", t->name); - } - } SMARTLIST_FOREACH_END(t); -} - /** Free memory allocated by managed proxy mp. * If also_free_transports is set, also free the transports * associated with this managed proxy. */ @@ -254,8 +278,6 @@ proxy_configuration_finished(managed_proxy_t *mp) void handle_proxy_line(char *line, managed_proxy_t *mp) { - log_debug(LD_CONFIG, "Judging line: %s\n", line); - if (strlen(line) < SMALLEST_MANAGED_LINE_SIZE) { log_warn(LD_GENERAL, "Managed proxy configuration line is too small. " "Discarding"); @@ -401,7 +423,8 @@ parse_method_error(char *line, int is_server) line+strlen(error)+1); } -/** Parses an SMETHOD line. */ +/** Parses an SMETHOD line and if well-formed it registers the + * new transport in mp. */ int parse_smethod_line(char *line, managed_proxy_t *mp) { @@ -414,6 +437,8 @@ parse_smethod_line(char *line, managed_proxy_t *mp) tor_addr_t addr; uint16_t port = 0; + transport_t *transport=NULL; + items = smartlist_create(); smartlist_split_string(items, line, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); @@ -440,6 +465,12 @@ parse_smethod_line(char *line, managed_proxy_t *mp) goto err; } + transport = transport_create(&addr, port, method_name, PROXY_NONE); + if (!transport) + goto err; + + smartlist_add(mp->transports, transport); + /* For now, notify the user so that he knows where the server transport is listening. */ log_warn(LD_CONFIG, "Server transport %s at %s:%d.", @@ -553,23 +584,26 @@ set_environ(char ***envp, const char *method, int is_server) *envp = tor_malloc(sizeof(char*)*(n_envs+1)); tmp = *envp; + state_loc = get_datadir_fname("pt_state/"); + /* these should all be customizable */ tor_asprintf(tmp++, "HOME=%s", getenv("HOME")); tor_asprintf(tmp++, "PATH=%s", getenv("PATH")); - state_loc = get_datadir_fname("pt_state/"); tor_asprintf(tmp++, "TOR_PT_STATE_LOCATION=%s", state_loc); - tor_free(state_loc); tor_asprintf(tmp++, "TOR_PT_MANAGED_TRANSPORT_VER=1"); /* temp */ if (is_server) { /* ASN check for ORPort values, should we be here if it's 0? */ tor_asprintf(tmp++, "TOR_PT_ORPORT=127.0.0.1:%d", options->ORPort); /* temp */ - tor_asprintf(tmp++, "TOR_PT_SERVER_BINDADDR=127.0.0.1:0"); + tor_asprintf(tmp++, "TOR_PT_SERVER_BINDADDR=%s", + get_bindaddr_for_transport(method)); tor_asprintf(tmp++, "TOR_PT_SERVER_TRANSPORTS=%s", method); tor_asprintf(tmp++, "TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200"); /* temp*/ } else { tor_asprintf(tmp++, "TOR_PT_CLIENT_TRANSPORTS=%s", method); } *tmp = NULL; + + tor_free(state_loc); } /* ASN is this too ugly/stupid? */ diff --git a/src/or/transports.h b/src/or/transports.h index 17a68030d7..8bd79fe64d 100644 --- a/src/or/transports.h +++ b/src/or/transports.h @@ -40,10 +40,12 @@ typedef struct { enum pt_proto_state conf_state; /* the current configuration state */ int conf_protocol; /* the configuration protocol version used */ + int is_server; /* is it a server proxy? */ + FILE *stdout; /* a stream to its stdout (closed in managed_proxy_destroy()) */ - smartlist_t *transports; /* list of transports this proxy spawns */ + smartlist_t *transports; /* list of transport_t this proxy spawns */ } managed_proxy_t; int parse_cmethod_line(char *line, managed_proxy_t *mp); From ea3e9416c6c579735ff2b844a88605ae5e1cbbd2 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 12 Aug 2011 21:33:05 +0200 Subject: [PATCH 15/36] Spawn multiple protocols using a single managed proxy. If multiple torrc transport lines have the same argv, tor instructs a single managed proxy to launch multiple protocols. --- src/or/config.c | 42 +++++----- src/or/config.h | 2 +- src/or/transports.c | 196 ++++++++++++++++++++++++++++++++++---------- src/or/transports.h | 17 ++-- 4 files changed, 184 insertions(+), 73 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index dced47c030..41b6bba21d 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1228,7 +1228,7 @@ options_act(or_options_t *old_options) /* If we have pluggable transport related options enabled, see if we should warn the user about potential configuration problems. */ - if (options->Bridges || options->ClientTransportPlugin) + if (options->Bridges || options->ClientTransportPlugin || options->ServerTransportPlugin) validate_pluggable_transports_config(); if (running_tor && rend_config_services(options, 0)<0) { @@ -4745,15 +4745,14 @@ parse_client_transport_line(const char *line, int validate_only) tor_assert(proxy_argc > 0); proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1)); tmp = proxy_argv; - for (i=0;iline for transport transport. If the - * line is corrupted, return NULL. */ + * TransportProxy line for transport transport. + * If the line is corrupted, return NULL. */ const char * get_transport_bindaddr(const char *line, const char *transport) { @@ -5822,8 +5818,8 @@ get_transport_bindaddr(const char *line, const char *transport) return (line+strlen(transport)+1); } -/** Return a string containing the address:port that transport - * should use. */ +/** Return a static string containing the address:port a proxy + * transport should bind on. */ const char * get_bindaddr_for_transport(const char *transport) { @@ -5839,8 +5835,8 @@ get_bindaddr_for_transport(const char *transport) return bindaddr ? bindaddr : default_addrport; } -/** Save transport listening at addr:port to - * state */ +/** Save transport listening on addr:port to + state */ void save_transport_to_state(const char *transport, tor_addr_t *addr, uint16_t port) diff --git a/src/or/config.h b/src/or/config.h index dc3a828749..d09d90421d 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -65,7 +65,7 @@ int or_state_save(time_t now); void save_transport_to_state(const char *transport_name, tor_addr_t *addr, uint16_t port); -const char * get_bindaddr_for_transport(const char *transport); +const char *get_bindaddr_for_transport(const char *transport); int options_need_geoip_info(or_options_t *options, const char **reason_out); int getinfo_helper_config(control_connection_t *conn, diff --git a/src/or/transports.c b/src/or/transports.c index b96792f549..c414920d60 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -13,8 +13,7 @@ #include "transports.h" /* ASN TIDY THESE UP*/ -static void set_environ(char ***envp, const char *method, - int is_server); +static void set_environ(char ***envp, managed_proxy_t *mp); static INLINE int proxy_configuration_finished(managed_proxy_t *mp); static void managed_proxy_destroy(managed_proxy_t *mp, @@ -82,11 +81,55 @@ pt_proxies_configuration_pending(void) return !!n_unconfigured_proxies; } -/** Launch a proxy for method using proxy_argv as its - * arguments. If is_server, launch a server proxy. */ -int -pt_managed_launch_proxy(const char *method, - char **proxy_argv, int is_server) +/** Return true if mp has the same argv as proxy_argv */ +static int +managed_proxy_has_argv(managed_proxy_t *mp, char **proxy_argv) +{ + char **tmp1=proxy_argv; + char **tmp2=mp->argv; + + tor_assert(tmp1); + tor_assert(tmp2); + + while (*tmp1 && *tmp2) { + if (strcmp(*tmp1++, *tmp2++)) + return 0; + } + + if (!*tmp1 && !*tmp2) + return 1; + + return 0; +} + +/** Return a managed proxy with the same argv as proxy_argv. + * If no such managed proxy exists, return NULL. */ +static managed_proxy_t * +get_managed_proxy_by_argv(char **proxy_argv) +{ + if (!unconfigured_proxy_list) + return NULL; + + SMARTLIST_FOREACH_BEGIN(unconfigured_proxy_list, managed_proxy_t *, mp) { + if (managed_proxy_has_argv(mp, proxy_argv)) + return mp; + } SMARTLIST_FOREACH_END(mp); + + return NULL; +} + +/** Add transport to managed proxy mp. */ +static void +add_transport_to_proxy(char *transport, managed_proxy_t *mp) +{ + tor_assert(mp->transports_to_launch); + if (!smartlist_string_isin(mp->transports_to_launch, transport)) + smartlist_add(mp->transports_to_launch, tor_strdup(transport)); +} + +/** Launch managed proxy mp. */ +static int +launch_managed_proxy(managed_proxy_t *mp) { char **envp=NULL; int retval; @@ -94,11 +137,16 @@ pt_managed_launch_proxy(const char *method, int stdout_pipe=-1, stderr_pipe=-1; /* prepare the environment variables for the managed proxy */ - set_environ(&envp, method, is_server); + set_environ(&envp, mp); + + char **tmp = envp; + printf("PRINTING ENVP\n"); + while (*tmp) + printf("%s\n", *tmp++); /* ASN we should probably check if proxy_argv[0] is executable by our user */ - retval = tor_spawn_background(proxy_argv[0], &stdout_pipe, - &stderr_pipe, (const char **)proxy_argv, + retval = tor_spawn_background(mp->argv[0], &stdout_pipe, + &stderr_pipe, (const char **)mp->argv, (const char **)envp); if (retval < 0) { log_warn(LD_GENERAL, "Spawn failed"); @@ -115,20 +163,8 @@ pt_managed_launch_proxy(const char *method, log_warn(LD_CONFIG, "The spawn is alive (%d)!", retval); - /* create a managed proxy */ - managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t)); - mp->conf_state = PT_PROTO_INFANT; + mp->conf_state = PT_PROTO_LAUNCHED; mp->stdout = stdout_read; - mp->transports = smartlist_create(); - mp->is_server = is_server; - - /* register the managed proxy */ - if (!unconfigured_proxy_list) - unconfigured_proxy_list = smartlist_create(); - smartlist_add(unconfigured_proxy_list, mp); - - n_unconfigured_proxies++; /* ASN should we care about overflows here? - I say no. */ return 0; } @@ -150,14 +186,21 @@ pt_configure_remaining_proxies(void) } SMARTLIST_FOREACH_END(mp); } -/** Receive input from the managed proxy mp to get closer to - * finally configuring it. */ +/** Attempt to continue configuring managed proxy mp. */ static void configure_proxy(managed_proxy_t *mp) { enum stream_status r; char stdout_buf[200]; + /* if we haven't launched the proxy yet, do it now */ + if (mp->conf_state == PT_PROTO_INFANT) { + launch_managed_proxy(mp); + return; + } + + tor_assert(mp->conf_state != PT_PROTO_INFANT); + while (1) { r = get_string_from_pipe(mp->stdout, stdout_buf, sizeof(stdout_buf) - 1); @@ -255,12 +298,21 @@ managed_proxy_destroy(managed_proxy_t *mp, int also_free_transports) smartlist_clear(mp->transports); smartlist_free(mp->transports); + SMARTLIST_FOREACH(mp->transports_to_launch, char *, t, tor_free(t)); + + /* free the transports smartlist */ + smartlist_clear(mp->transports_to_launch); + smartlist_free(mp->transports_to_launch); + /* remove it from the list of managed proxies */ smartlist_remove(unconfigured_proxy_list, mp); /* close its stdout stream */ fclose(mp->stdout); + /* free the argv */ + free_execve_args(mp->argv); + tor_free(mp); } @@ -278,6 +330,8 @@ proxy_configuration_finished(managed_proxy_t *mp) void handle_proxy_line(char *line, managed_proxy_t *mp) { + printf("Judging line: %s\n", line); + if (strlen(line) < SMALLEST_MANAGED_LINE_SIZE) { log_warn(LD_GENERAL, "Managed proxy configuration line is too small. " "Discarding"); @@ -285,13 +339,13 @@ handle_proxy_line(char *line, managed_proxy_t *mp) } if (!strncmp(line, PROTO_ENV_ERROR, strlen(PROTO_ENV_ERROR))) { - if (mp->conf_state != PT_PROTO_INFANT) + if (mp->conf_state != PT_PROTO_LAUNCHED) goto err; parse_env_error(line); goto err; } else if (!strncmp(line, PROTO_NEG_FAIL, strlen(PROTO_NEG_FAIL))) { - if (mp->conf_state != PT_PROTO_INFANT) + if (mp->conf_state != PT_PROTO_LAUNCHED) goto err; log_warn(LD_CONFIG, "Managed proxy could not pick a " @@ -299,7 +353,7 @@ handle_proxy_line(char *line, managed_proxy_t *mp) goto err; } else if (!strncmp(line, PROTO_NEG_SUCCESS, strlen(PROTO_NEG_SUCCESS))) { - if (mp->conf_state != PT_PROTO_INFANT) + if (mp->conf_state != PT_PROTO_LAUNCHED) goto err; if (parse_version(line,mp) < 0) @@ -567,46 +621,104 @@ parse_cmethod_line(char *line, managed_proxy_t *mp) return r; } -/** Prepares the envp of a pluggable transport managed proxy - * - * method is a line with transport methods to be launched. - * If is_server is set, prepare a server proxy envp. */ +/** Return a string containing the address:port that transport + * should use. */ +static char * +get_bindaddr_for_proxy(managed_proxy_t *mp) +{ + char *bindaddr = NULL; + smartlist_t *string_tmp = smartlist_create(); + + tor_assert(mp->is_server); + + SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, char *, t) { + tor_asprintf(&bindaddr, "%s-%s", t, get_bindaddr_for_transport(t)); + smartlist_add(string_tmp, bindaddr); + } SMARTLIST_FOREACH_END(t); + + bindaddr = smartlist_join_strings(string_tmp, ",", 0, NULL); + + SMARTLIST_FOREACH(string_tmp, char *, t, tor_free(t)); + smartlist_free(string_tmp); + + return bindaddr; +} + +/** Prepare the envp of managed proxy mp */ static void -set_environ(char ***envp, const char *method, int is_server) +set_environ(char ***envp, managed_proxy_t *mp) { or_options_t *options = get_options(); char **tmp=NULL; char *state_loc=NULL; + char *transports_to_launch=NULL; + char *bindaddr=NULL; - int n_envs = is_server ? ENVIRON_SIZE_SERVER : ENVIRON_SIZE_CLIENT; + int n_envs = mp->is_server ? ENVIRON_SIZE_SERVER : ENVIRON_SIZE_CLIENT; /* allocate enough space for our env. vars and a NULL pointer */ *envp = tor_malloc(sizeof(char*)*(n_envs+1)); tmp = *envp; state_loc = get_datadir_fname("pt_state/"); + transports_to_launch = + smartlist_join_strings(mp->transports_to_launch, ",", 0, NULL); - /* these should all be customizable */ tor_asprintf(tmp++, "HOME=%s", getenv("HOME")); tor_asprintf(tmp++, "PATH=%s", getenv("PATH")); tor_asprintf(tmp++, "TOR_PT_STATE_LOCATION=%s", state_loc); tor_asprintf(tmp++, "TOR_PT_MANAGED_TRANSPORT_VER=1"); /* temp */ - if (is_server) { - /* ASN check for ORPort values, should we be here if it's 0? */ + if (mp->is_server) { + bindaddr = get_bindaddr_for_proxy(mp); + tor_asprintf(tmp++, "TOR_PT_ORPORT=127.0.0.1:%d", options->ORPort); /* temp */ - tor_asprintf(tmp++, "TOR_PT_SERVER_BINDADDR=%s", - get_bindaddr_for_transport(method)); - tor_asprintf(tmp++, "TOR_PT_SERVER_TRANSPORTS=%s", method); + tor_asprintf(tmp++, "TOR_PT_SERVER_BINDADDR=%s", bindaddr); + tor_asprintf(tmp++, "TOR_PT_SERVER_TRANSPORTS=%s", transports_to_launch); tor_asprintf(tmp++, "TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200"); /* temp*/ } else { - tor_asprintf(tmp++, "TOR_PT_CLIENT_TRANSPORTS=%s", method); + tor_asprintf(tmp++, "TOR_PT_CLIENT_TRANSPORTS=%s", transports_to_launch); } *tmp = NULL; tor_free(state_loc); + tor_free(transports_to_launch); + tor_free(bindaddr); +} + +/** Register transport using proxy with proxy_argv to + * the managed proxy subsystem. + * If is_server is true, then the proxy is a server proxy. */ +void +pt_kickstart_proxy(char *transport, char **proxy_argv, int is_server) +{ + managed_proxy_t *mp=NULL; + + mp = get_managed_proxy_by_argv(proxy_argv); + + if (!mp) { /* we haven't seen this proxy before */ + /* create a managed proxy */ + managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t)); + mp->conf_state = PT_PROTO_INFANT; + mp->is_server = is_server; + mp->argv = proxy_argv; + mp->transports = smartlist_create(); + + mp->transports_to_launch = smartlist_create(); + add_transport_to_proxy(transport, mp); + + /* register the managed proxy */ + if (!unconfigured_proxy_list) + unconfigured_proxy_list = smartlist_create(); + smartlist_add(unconfigured_proxy_list, mp); + + n_unconfigured_proxies++; /* ASN should we care about overflows here? + I say no. */ + } else { /* known proxy. just add transport to its transport list */ + add_transport_to_proxy(transport, mp); + free_execve_args(proxy_argv); + } } -/* ASN is this too ugly/stupid? */ /** Frees the array of pointers in arg used as arguments to execve. */ static INLINE void diff --git a/src/or/transports.h b/src/or/transports.h index 8bd79fe64d..c75797d217 100644 --- a/src/or/transports.h +++ b/src/or/transports.h @@ -11,13 +11,13 @@ #ifndef TOR_TRANSPORTS_H #define TOR_TRANSPORTS_H -int pt_managed_launch_proxy(const char *method, - char **proxy_argv, int is_server); +void pt_kickstart_proxy(char *method, char **proxy_argv, + int is_server); -#define pt_managed_launch_client_proxy(m, pa) \ - pt_managed_launch_proxy(m, pa, 0) -#define pt_managed_launch_server_proxy(m, pa) \ - pt_managed_launch_proxy(m, pa, 1) +#define pt_kickstart_client_proxy(m, pa) \ + pt_kickstart_proxy(m, pa, 0) +#define pt_kickstart_server_proxy(m, pa) \ + pt_kickstart_proxy(m, pa, 1) void pt_configure_remaining_proxies(void); @@ -29,6 +29,7 @@ void pt_free_all(void); /** State of the managed proxy configuration protocol. */ enum pt_proto_state { PT_PROTO_INFANT, /* was just born */ + PT_PROTO_LAUNCHED, /* was just launched */ PT_PROTO_ACCEPTING_METHODS, /* accepting methods */ PT_PROTO_CONFIGURED, /* configured successfully */ PT_PROTO_COMPLETED, /* configure and registered its transports */ @@ -38,6 +39,7 @@ enum pt_proto_state { /** Structure containing information of a managed proxy. */ typedef struct { enum pt_proto_state conf_state; /* the current configuration state */ + char **argv; /* the cli arguments of this proxy */ int conf_protocol; /* the configuration protocol version used */ int is_server; /* is it a server proxy? */ @@ -45,7 +47,8 @@ typedef struct { FILE *stdout; /* a stream to its stdout (closed in managed_proxy_destroy()) */ - smartlist_t *transports; /* list of transport_t this proxy spawns */ + smartlist_t *transports_to_launch; /* transports to-be-launched by this proxy */ + smartlist_t *transports; /* list of transport_t this proxy spawned */ } managed_proxy_t; int parse_cmethod_line(char *line, managed_proxy_t *mp); From db4cde38109c677db14316ac77c240d7d61db386 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 15 Aug 2011 17:26:03 +0200 Subject: [PATCH 16/36] Improve the code a tad. * Use strcmpstart() instead of strcmp(x,y,strlen(y)). * Warn the user if the managed proxy failed to launch. * Improve function documentation. * Use smartlist_len() instead of n_unconfigured_proxies. * Split managed_proxy_destroy() to managed_proxy_destroy() and managed_proxy_destroy_with_transports(). * Constification. --- src/common/util.c | 2 - src/common/util.h | 1 + src/or/config.c | 8 +- src/or/config.h | 2 +- src/or/transports.c | 207 +++++++++++++++++++++++--------------------- src/or/transports.h | 12 +-- 6 files changed, 119 insertions(+), 113 deletions(-) diff --git a/src/common/util.c b/src/common/util.c index 7a7ee195ba..0632c674e9 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -2941,8 +2941,6 @@ format_helper_exit_status(unsigned char child_state, int saved_errno, #define CHILD_STATE_EXEC 8 #define CHILD_STATE_FAILEXEC 9 -#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code " - /** Start a program in the background. If filename contains a '/', * then it will be treated as an absolute or relative path. Otherwise the * system path will be searched for filename. The strings in diff --git a/src/common/util.h b/src/common/util.h index 12dc106ace..8bf4f7b137 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -353,6 +353,7 @@ void tor_check_port_forwarding(const char *filename, int tor_spawn_background(const char *const filename, int *stdout_read, int *stderr_read, const char **argv, const char **envp); +#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code " #ifdef MS_WINDOWS HANDLE load_windows_system_library(const TCHAR *library_name); diff --git a/src/or/config.c b/src/or/config.c index 41b6bba21d..0b84f9214b 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1228,7 +1228,7 @@ options_act(or_options_t *old_options) /* If we have pluggable transport related options enabled, see if we should warn the user about potential configuration problems. */ - if (options->Bridges || options->ClientTransportPlugin || options->ServerTransportPlugin) + if (options->Bridges || options->ClientTransportPlugin) validate_pluggable_transports_config(); if (running_tor && rend_config_services(options, 0)<0) { @@ -4696,7 +4696,7 @@ parse_client_transport_line(const char *line, int validate_only) int r; char *field2=NULL; - char *name=NULL; + const char *name=NULL; char *addrport=NULL; tor_addr_t addr; uint16_t port = 0; @@ -4801,7 +4801,7 @@ parse_server_transport_line(const char *line, int validate_only) { smartlist_t *items = NULL; int r; - char *name=NULL; + const char *name=NULL; char *type=NULL; char *addrport=NULL; tor_addr_t addr; @@ -5839,7 +5839,7 @@ get_bindaddr_for_transport(const char *transport) state */ void save_transport_to_state(const char *transport, - tor_addr_t *addr, uint16_t port) + const tor_addr_t *addr, uint16_t port) { or_state_t *state = get_or_state(); diff --git a/src/or/config.h b/src/or/config.h index d09d90421d..45baf451f6 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -64,7 +64,7 @@ int did_last_state_file_write_fail(void); int or_state_save(time_t now); void save_transport_to_state(const char *transport_name, - tor_addr_t *addr, uint16_t port); + const tor_addr_t *addr, uint16_t port); const char *get_bindaddr_for_transport(const char *transport); int options_need_geoip_info(or_options_t *options, const char **reason_out); diff --git a/src/or/transports.c b/src/or/transports.c index c414920d60..21a302298f 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -11,19 +11,21 @@ #include "config.h" #include "circuitbuild.h" #include "transports.h" +#include "util.h" /* ASN TIDY THESE UP*/ -static void set_environ(char ***envp, managed_proxy_t *mp); -static INLINE int proxy_configuration_finished(managed_proxy_t *mp); +static void set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp); +static INLINE int proxy_configuration_finished(const managed_proxy_t *mp); + +static void managed_proxy_destroy_impl(managed_proxy_t *mp, + int also_free_transports); +#define managed_proxy_destroy(mp) managed_proxy_destroy_impl(mp, 0) +#define managed_proxy_destroy_with_transports(mp) managed_proxy_destroy_impl(mp, 1) -static void managed_proxy_destroy(managed_proxy_t *mp, - int also_free_transports); static void handle_finished_proxy(managed_proxy_t *mp); static void configure_proxy(managed_proxy_t *mp); -static void register_server_proxy(managed_proxy_t *mp); - -static void parse_method_error(char *line, int is_server_method); +static void parse_method_error(const char *line, int is_server_method); #define parse_server_method_error(l) parse_method_error(l, 1) #define parse_client_method_error(l) parse_method_error(l, 0) @@ -54,20 +56,19 @@ static INLINE void free_execve_args(char **arg); /** List of unconfigured managed proxies. */ static smartlist_t *unconfigured_proxy_list = NULL; -/** Number of unconfigured managed proxies. */ -static int n_unconfigured_proxies = 0; -/* The main idea is: +/* The main idea here is: A managed proxy is represented by a managed_proxy_t struct and can spawn multiple transports. unconfigured_proxy_list is a list of all the unconfigured managed - proxies; everytime we spawn a managed proxy we add it in that - list. - In every run_scheduled_event() tick, we attempt to configure each - managed proxy further, using the configuration protocol defined in - the 180_pluggable_transport.txt proposal. + proxies; everytime we find a managed proxy in torrc we add it in + that list. + In every run_scheduled_event() tick, we attempt to launch and then + configure each managed proxy, using the configuration protocol + defined in the 180_pluggable_transport.txt proposal. A managed + proxy might need several ticks to get fully configured. When a managed proxy is fully configured, we register all its transports to the circuitbuild.c subsystem - like we do with @@ -78,7 +79,8 @@ static int n_unconfigured_proxies = 0; int pt_proxies_configuration_pending(void) { - return !!n_unconfigured_proxies; + if (!unconfigured_proxy_list) return 0; + return !!smartlist_len(unconfigured_proxy_list); } /** Return true if mp has the same argv as proxy_argv */ @@ -120,7 +122,7 @@ get_managed_proxy_by_argv(char **proxy_argv) /** Add transport to managed proxy mp. */ static void -add_transport_to_proxy(char *transport, managed_proxy_t *mp) +add_transport_to_proxy(const char *transport, managed_proxy_t *mp) { tor_assert(mp->transports_to_launch); if (!smartlist_string_isin(mp->transports_to_launch, transport)) @@ -137,14 +139,8 @@ launch_managed_proxy(managed_proxy_t *mp) int stdout_pipe=-1, stderr_pipe=-1; /* prepare the environment variables for the managed proxy */ - set_environ(&envp, mp); + set_managed_proxy_environment(&envp, mp); - char **tmp = envp; - printf("PRINTING ENVP\n"); - while (*tmp) - printf("%s\n", *tmp++); - - /* ASN we should probably check if proxy_argv[0] is executable by our user */ retval = tor_spawn_background(mp->argv[0], &stdout_pipe, &stderr_pipe, (const char **)mp->argv, (const char **)envp); @@ -153,7 +149,7 @@ launch_managed_proxy(managed_proxy_t *mp) return -1; } - /* free the memory allocated for the execve() */ + /* free the memory allocated by set_managed_proxy_environment(). */ free_execve_args(envp); /* Set stdout/stderr pipes to be non-blocking */ @@ -177,8 +173,8 @@ pt_configure_remaining_proxies(void) { log_warn(LD_CONFIG, "We start configuring remaining managed proxies!"); SMARTLIST_FOREACH_BEGIN(unconfigured_proxy_list, managed_proxy_t *, mp) { - if (proxy_configuration_finished(mp)) /* finished managed proxies - shouldn't be here */ + /* configured proxies shouldn't be in unconfigured_proxy_list. */ + if (proxy_configuration_finished(mp)) assert(0); configure_proxy(mp); @@ -205,15 +201,16 @@ configure_proxy(managed_proxy_t *mp) r = get_string_from_pipe(mp->stdout, stdout_buf, sizeof(stdout_buf) - 1); - if (r == IO_STREAM_CLOSED || r == IO_STREAM_TERM) { + if (r == IO_STREAM_OKAY) { /* got a line; handle it! */ + handle_proxy_line((const char *)stdout_buf, mp); + } else if (r == IO_STREAM_EAGAIN) { /* check back later */ + return; + } else if (r == IO_STREAM_CLOSED || r == IO_STREAM_TERM) { /* snap! */ log_warn(LD_GENERAL, "Managed proxy stream closed. " "Most probably application stopped running"); mp->conf_state = PT_PROTO_BROKEN; - } else if (r == IO_STREAM_EAGAIN) { - return; - } else { - tor_assert(r == IO_STREAM_OKAY); - handle_proxy_line(stdout_buf, mp); + } else { /* unknown stream status */ + log_warn(LD_GENERAL, "Unknown stream status while configuring proxy."); } /* if the proxy finished configuring, exit the loop. */ @@ -226,7 +223,7 @@ configure_proxy(managed_proxy_t *mp) /** Register server managed proxy mp transports to state */ static void -register_server_proxy(managed_proxy_t *mp) +register_server_proxy(const managed_proxy_t *mp) { if (mp->is_server) { SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) { @@ -238,7 +235,7 @@ register_server_proxy(managed_proxy_t *mp) /** Register all the transports supported by client managed proxy * mp to the bridge subsystem. */ static void -register_client_proxy(managed_proxy_t *mp) +register_client_proxy(const managed_proxy_t *mp) { SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) { if (transport_add(t)<0) { @@ -252,7 +249,7 @@ register_client_proxy(managed_proxy_t *mp) /** Register the transports of managed proxy mp. */ static INLINE void -register_proxy(managed_proxy_t *mp) +register_proxy(const managed_proxy_t *mp) { if (mp->is_server) register_server_proxy(mp); @@ -260,35 +257,11 @@ register_proxy(managed_proxy_t *mp) register_client_proxy(mp); } -/** Handle a configured or broken managed proxy mp. */ -static void -handle_finished_proxy(managed_proxy_t *mp) -{ - switch (mp->conf_state) { - case PT_PROTO_BROKEN: /* if broken: */ - managed_proxy_destroy(mp, 1); /* destroy it and all its transports */ - break; - case PT_PROTO_CONFIGURED: /* if configured correctly: */ - register_proxy(mp); /* register transports */ - mp->conf_state = PT_PROTO_COMPLETED; /* mark it as completed, */ - managed_proxy_destroy(mp, 0); /* destroy the managed proxy struct, - keeping the transports intact */ - break; - default: - log_warn(LD_CONFIG, "Unfinished managed proxy in " - "handle_finished_proxy()."); - assert(0); - } - - n_unconfigured_proxies--; - tor_assert(n_unconfigured_proxies >= 0); -} - /** Free memory allocated by managed proxy mp. * If also_free_transports is set, also free the transports * associated with this managed proxy. */ static void -managed_proxy_destroy(managed_proxy_t *mp, int also_free_transports) +managed_proxy_destroy_impl(managed_proxy_t *mp, int also_free_transports) { /* transport_free() all its transports */ if (also_free_transports) @@ -316,19 +289,59 @@ managed_proxy_destroy(managed_proxy_t *mp, int also_free_transports) tor_free(mp); } + +/** Handle a configured or broken managed proxy mp. */ +static void +handle_finished_proxy(managed_proxy_t *mp) +{ + switch (mp->conf_state) { + case PT_PROTO_BROKEN: /* if broken: */ + managed_proxy_destroy_with_transports(mp); /* destroy it and all its transports */ + break; + case PT_PROTO_CONFIGURED: /* if configured correctly: */ + register_proxy(mp); /* register transports */ + mp->conf_state = PT_PROTO_COMPLETED; /* mark it as completed, */ + managed_proxy_destroy(mp); /* destroy the managed proxy struct, + keeping the transports intact */ + break; + default: + log_warn(LD_CONFIG, "Unfinished managed proxy in " + "handle_finished_proxy()."); + assert(0); + } + + tor_assert(smartlist_len(unconfigured_proxy_list) >= 0); +} + /** Return true if the configuration of the managed proxy mp is finished. */ static INLINE int -proxy_configuration_finished(managed_proxy_t *mp) +proxy_configuration_finished(const managed_proxy_t *mp) { return (mp->conf_state == PT_PROTO_CONFIGURED || mp->conf_state == PT_PROTO_BROKEN); } + +/** This function is called when a proxy sends an {S,C}METHODS DONE message, + */ +static void +handle_methods_done(const managed_proxy_t *mp) +{ + tor_assert(mp->transports); + + if (smartlist_len(mp->transports) == 0) + log_warn(LD_GENERAL, "Proxy was spawned successfully, " + "but it didn't laucn any pluggable transport listeners!"); + + log_warn(LD_CONFIG, "%s managed proxy configuration completed!", + mp->is_server ? "Server" : "Client"); +} + /** Handle a configuration protocol line received from a * managed proxy mp. */ void -handle_proxy_line(char *line, managed_proxy_t *mp) +handle_proxy_line(const char *line, managed_proxy_t *mp) { printf("Judging line: %s\n", line); @@ -338,21 +351,20 @@ handle_proxy_line(char *line, managed_proxy_t *mp) goto err; } - if (!strncmp(line, PROTO_ENV_ERROR, strlen(PROTO_ENV_ERROR))) { + if (!strcmpstart(line, PROTO_ENV_ERROR)) { if (mp->conf_state != PT_PROTO_LAUNCHED) goto err; parse_env_error(line); goto err; - } else if (!strncmp(line, PROTO_NEG_FAIL, strlen(PROTO_NEG_FAIL))) { + } else if (!strcmpstart(line, PROTO_NEG_FAIL)) { if (mp->conf_state != PT_PROTO_LAUNCHED) goto err; log_warn(LD_CONFIG, "Managed proxy could not pick a " "configuration protocol version."); goto err; - } else if (!strncmp(line, PROTO_NEG_SUCCESS, - strlen(PROTO_NEG_SUCCESS))) { + } else if (!strcmpstart(line, PROTO_NEG_SUCCESS)) { if (mp->conf_state != PT_PROTO_LAUNCHED) goto err; @@ -362,37 +374,35 @@ handle_proxy_line(char *line, managed_proxy_t *mp) tor_assert(mp->conf_protocol != 0); mp->conf_state = PT_PROTO_ACCEPTING_METHODS; return; - } else if (!strncmp(line, PROTO_CMETHODS_DONE, - strlen(PROTO_CMETHODS_DONE))) { + } else if (!strcmpstart(line, PROTO_CMETHODS_DONE)) { if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) goto err; - log_warn(LD_CONFIG, "Client managed proxy configuration completed!"); + handle_methods_done(mp); + mp->conf_state = PT_PROTO_CONFIGURED; return; - } else if (!strncmp(line, PROTO_SMETHODS_DONE, - strlen(PROTO_SMETHODS_DONE))) { + } else if (!strcmpstart(line, PROTO_SMETHODS_DONE)) { if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) goto err; - log_warn(LD_CONFIG, "Server managed proxy configuration completed!"); + handle_methods_done(mp); + mp->conf_state = PT_PROTO_CONFIGURED; return; - } else if (!strncmp(line, PROTO_CMETHOD_ERROR, - strlen(PROTO_CMETHOD_ERROR))) { + } else if (!strcmpstart(line, PROTO_CMETHOD_ERROR)) { if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) goto err; parse_client_method_error(line); goto err; - } else if (!strncmp(line, PROTO_SMETHOD_ERROR, - strlen(PROTO_SMETHOD_ERROR))) { + } else if (!strcmpstart(line, PROTO_SMETHOD_ERROR)) { if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) goto err; parse_server_method_error(line); goto err; - } else if (!strncmp(line, PROTO_CMETHOD, strlen(PROTO_CMETHOD))) { + } else if (!strcmpstart(line, PROTO_CMETHOD)) { if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) goto err; @@ -400,7 +410,7 @@ handle_proxy_line(char *line, managed_proxy_t *mp) goto err; return; - } else if (!strncmp(line, PROTO_SMETHOD, strlen(PROTO_SMETHOD))) { + } else if (!strcmpstart(line, PROTO_SMETHOD)) { if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS) goto err; @@ -408,6 +418,9 @@ handle_proxy_line(char *line, managed_proxy_t *mp) goto err; return; + } else if (!strcmpstart(line, SPAWN_ERROR_MESSAGE)) { + log_warn(LD_GENERAL, "Could not launch managed proxy executable!"); + goto err; } log_warn(LD_CONFIG, "Unknown line received by managed proxy. (%s)", line); @@ -419,10 +432,8 @@ handle_proxy_line(char *line, managed_proxy_t *mp) /** Parses an ENV-ERROR line and warns the user accordingly. */ void -parse_env_error(char *line) +parse_env_error(const char *line) { - tor_assert(!strncmp(line, PROTO_ENV_ERROR, strlen(PROTO_ENV_ERROR))); - /* (Length of the protocol string) plus (a space) and (the first char of the error message) */ if (strlen(line) < (strlen(PROTO_ENV_ERROR) + 2)) @@ -437,10 +448,8 @@ parse_env_error(char *line) /** Handles a VERSION line. Updates the configuration protocol * version in mp. */ int -parse_version(char *line, managed_proxy_t *mp) +parse_version(const char *line, managed_proxy_t *mp) { - tor_assert(!strncmp(line, PROTO_NEG_SUCCESS, strlen(PROTO_NEG_SUCCESS))); - if (strlen(line) < (strlen(PROTO_NEG_SUCCESS) + 2)) { log_warn(LD_CONFIG, "Managed proxy sent us malformed %s line.", PROTO_NEG_SUCCESS); @@ -461,7 +470,7 @@ parse_version(char *line, managed_proxy_t *mp) * accordingly. If is_server it is an SMETHOD-ERROR, * otherwise it is a CMETHOD-ERROR. */ static void -parse_method_error(char *line, int is_server) +parse_method_error(const char *line, int is_server) { const char* error = is_server ? PROTO_SMETHOD_ERROR : PROTO_CMETHOD_ERROR; @@ -480,7 +489,7 @@ parse_method_error(char *line, int is_server) /** Parses an SMETHOD line and if well-formed it registers the * new transport in mp. */ int -parse_smethod_line(char *line, managed_proxy_t *mp) +parse_smethod_line(const char *line, managed_proxy_t *mp) { int r; smartlist_t *items = NULL; @@ -545,7 +554,7 @@ parse_smethod_line(char *line, managed_proxy_t *mp) /** Parses a CMETHOD line, and if well-formed it registers * the new transport in mp. */ int -parse_cmethod_line(char *line, managed_proxy_t *mp) +parse_cmethod_line(const char *line, managed_proxy_t *mp) { int r; smartlist_t *items = NULL; @@ -622,9 +631,10 @@ parse_cmethod_line(char *line, managed_proxy_t *mp) } /** Return a string containing the address:port that transport - * should use. */ + * should use. It's the responsibility of the caller to free() the + * received string. */ static char * -get_bindaddr_for_proxy(managed_proxy_t *mp) +get_bindaddr_for_proxy(const managed_proxy_t *mp) { char *bindaddr = NULL; smartlist_t *string_tmp = smartlist_create(); @@ -646,7 +656,7 @@ get_bindaddr_for_proxy(managed_proxy_t *mp) /** Prepare the envp of managed proxy mp */ static void -set_environ(char ***envp, managed_proxy_t *mp) +set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp) { or_options_t *options = get_options(); char **tmp=NULL; @@ -660,7 +670,7 @@ set_environ(char ***envp, managed_proxy_t *mp) *envp = tor_malloc(sizeof(char*)*(n_envs+1)); tmp = *envp; - state_loc = get_datadir_fname("pt_state/"); + state_loc = get_datadir_fname("pt_state/"); /* XXX temp */ transports_to_launch = smartlist_join_strings(mp->transports_to_launch, ",", 0, NULL); @@ -671,10 +681,10 @@ set_environ(char ***envp, managed_proxy_t *mp) if (mp->is_server) { bindaddr = get_bindaddr_for_proxy(mp); - tor_asprintf(tmp++, "TOR_PT_ORPORT=127.0.0.1:%d", options->ORPort); /* temp */ + tor_asprintf(tmp++, "TOR_PT_ORPORT=127.0.0.1:%d", options->ORPort); /* XXX temp */ tor_asprintf(tmp++, "TOR_PT_SERVER_BINDADDR=%s", bindaddr); tor_asprintf(tmp++, "TOR_PT_SERVER_TRANSPORTS=%s", transports_to_launch); - tor_asprintf(tmp++, "TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200"); /* temp*/ + tor_asprintf(tmp++, "TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200"); /* XXX temp*/ } else { tor_asprintf(tmp++, "TOR_PT_CLIENT_TRANSPORTS=%s", transports_to_launch); } @@ -689,7 +699,7 @@ set_environ(char ***envp, managed_proxy_t *mp) * the managed proxy subsystem. * If is_server is true, then the proxy is a server proxy. */ void -pt_kickstart_proxy(char *transport, char **proxy_argv, int is_server) +pt_kickstart_proxy(const char *transport, char **proxy_argv, int is_server) { managed_proxy_t *mp=NULL; @@ -710,9 +720,6 @@ pt_kickstart_proxy(char *transport, char **proxy_argv, int is_server) if (!unconfigured_proxy_list) unconfigured_proxy_list = smartlist_create(); smartlist_add(unconfigured_proxy_list, mp); - - n_unconfigured_proxies++; /* ASN should we care about overflows here? - I say no. */ } else { /* known proxy. just add transport to its transport list */ add_transport_to_proxy(transport, mp); free_execve_args(proxy_argv); @@ -743,9 +750,9 @@ pt_free_all(void) and we should free them here. */ SMARTLIST_FOREACH_BEGIN(unconfigured_proxy_list, managed_proxy_t *, mp) { if (mp->conf_state == PT_PROTO_COMPLETED) - managed_proxy_destroy(mp,0); + managed_proxy_destroy(mp); else - managed_proxy_destroy(mp,1); + managed_proxy_destroy_with_transports(mp); } SMARTLIST_FOREACH_END(mp); smartlist_clear(unconfigured_proxy_list); diff --git a/src/or/transports.h b/src/or/transports.h index c75797d217..6fec1dcf7c 100644 --- a/src/or/transports.h +++ b/src/or/transports.h @@ -11,7 +11,7 @@ #ifndef TOR_TRANSPORTS_H #define TOR_TRANSPORTS_H -void pt_kickstart_proxy(char *method, char **proxy_argv, +void pt_kickstart_proxy(const char *method, char **proxy_argv, int is_server); #define pt_kickstart_client_proxy(m, pa) \ @@ -51,12 +51,12 @@ typedef struct { smartlist_t *transports; /* list of transport_t this proxy spawned */ } managed_proxy_t; -int parse_cmethod_line(char *line, managed_proxy_t *mp); -int parse_smethod_line(char *line, managed_proxy_t *mp); +int parse_cmethod_line(const char *line, managed_proxy_t *mp); +int parse_smethod_line(const char *line, managed_proxy_t *mp); -int parse_version(char *line, managed_proxy_t *mp); -void parse_env_error(char *line); -void handle_proxy_line(char *line, managed_proxy_t *mp); +int parse_version(const char *line, managed_proxy_t *mp); +void parse_env_error(const char *line); +void handle_proxy_line(const char *line, managed_proxy_t *mp); #endif From c852760b80c4b7e06d775bafdb1f386d0e8ced63 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sat, 10 Sep 2011 00:45:28 +0200 Subject: [PATCH 17/36] Replaced some leftover assert()s with tor_assert()s. --- src/or/circuitbuild.c | 2 +- src/or/transports.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index fe57070ac1..382016ecc7 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -4640,7 +4640,7 @@ transport_create(const tor_addr_t *addr, uint16_t port, int transport_add(transport_t *t) { - assert(t); + tor_assert(t); if (transport_get_by_name(t->name)) { /* check for duplicate names */ log_notice(LD_CONFIG, "More than one transports have '%s' as " diff --git a/src/or/transports.c b/src/or/transports.c index 21a302298f..6255a567b6 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -174,8 +174,7 @@ pt_configure_remaining_proxies(void) log_warn(LD_CONFIG, "We start configuring remaining managed proxies!"); SMARTLIST_FOREACH_BEGIN(unconfigured_proxy_list, managed_proxy_t *, mp) { /* configured proxies shouldn't be in unconfigured_proxy_list. */ - if (proxy_configuration_finished(mp)) - assert(0); + tor_assert(!proxy_configuration_finished(mp)); configure_proxy(mp); @@ -307,7 +306,7 @@ handle_finished_proxy(managed_proxy_t *mp) default: log_warn(LD_CONFIG, "Unfinished managed proxy in " "handle_finished_proxy()."); - assert(0); + tor_assert(0); } tor_assert(smartlist_len(unconfigured_proxy_list) >= 0); From 782810a8bf1fbc3feaca851a011a8124891d39fc Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 20:26:01 +0200 Subject: [PATCH 18/36] Introduce tor_terminate_process() function. --- src/common/util.c | 26 ++++++++++++++++++++++++++ src/common/util.h | 1 + 2 files changed, 27 insertions(+) diff --git a/src/common/util.c b/src/common/util.c index 0632c674e9..63172c36a3 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -28,6 +28,7 @@ #include #include #include +#include #else #include #include @@ -43,6 +44,7 @@ #include #include #include +#include #ifdef HAVE_NETINET_IN_H #include @@ -2930,6 +2932,30 @@ format_helper_exit_status(unsigned char child_state, int saved_errno, /* Maximum number of file descriptors, if we cannot get it via sysconf() */ #define DEFAULT_MAX_FD 256 +/** Terminate process running at PID pid. + * Code borrowed from Python's os.kill. */ +int +tor_terminate_process(pid_t pid) +{ +#ifdef MS_WINDOWS + DWORD pid_win = pid; + DWORD err; + HANDLE handle; + /* If the signal is outside of what GenerateConsoleCtrlEvent can use, + attempt to open and terminate the process. */ + handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + if (handle == NULL) + return -1; + + if (TerminateProcess(handle, sig) == 0) + return -1; + else + return 0; +#else /* *nix */ + return kill(pid, SIGTERM); +#endif +} + #define CHILD_STATE_INIT 0 #define CHILD_STATE_PIPE 1 #define CHILD_STATE_MAXFD 2 diff --git a/src/common/util.h b/src/common/util.h index 8bf4f7b137..7e889b10c7 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -350,6 +350,7 @@ void write_pidfile(char *filename); void tor_check_port_forwarding(const char *filename, int dir_port, int or_port, time_t now); +int tor_terminate_process(pid_t pid); int tor_spawn_background(const char *const filename, int *stdout_read, int *stderr_read, const char **argv, const char **envp); From fa514fb207f23cb6f0ade95bbd830834ea14811f Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 20:28:47 +0200 Subject: [PATCH 19/36] Prepare circuitbuild.[ch] and config.[ch] for SIGHUPs. * Create mark/sweep functions for transports. * Create a transport_resolve_conflicts() function that tries to resolve conflicts when registering transports. --- src/or/circuitbuild.c | 128 ++++++++++++++++++++++++++++++++++++------ src/or/circuitbuild.h | 8 +++ src/or/config.c | 10 ++-- 3 files changed, 125 insertions(+), 21 deletions(-) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 382016ecc7..bd06d31070 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -124,7 +124,6 @@ static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); static void entry_guards_changed(void); -static const transport_t *transport_get_by_name(const char *name); static void bridge_free(bridge_info_t *bridge); /** @@ -4579,6 +4578,32 @@ bridge_free(bridge_info_t *bridge) /** A list of pluggable transports found in torrc. */ static smartlist_t *transport_list = NULL; +/** Mark every entry of the transport list to be removed on our next call to + * sweep_transport_list unless it has first been un-marked. */ +void +mark_transport_list(void) +{ + if (!transport_list) + transport_list = smartlist_create(); + SMARTLIST_FOREACH(transport_list, transport_t *, t, + t->marked_for_removal = 1); +} + +/** Remove every entry of the transport list that was marked with + * mark_transport_list if it has not subsequently been un-marked. */ +void +sweep_transport_list(void) +{ + if (!transport_list) + transport_list = smartlist_create(); + SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, t) { + if (t->marked_for_removal) { + SMARTLIST_DEL_CURRENT(transport_list, t); + transport_free(t); + } + } SMARTLIST_FOREACH_END(t); +} + /** Initialize the pluggable transports list to empty, creating it if * needed. */ void @@ -4603,7 +4628,7 @@ transport_free(transport_t *transport) /** Returns the transport in our transport list that has the name name. * Else returns NULL. */ -static const transport_t * +transport_t * transport_get_by_name(const char *name) { tor_assert(name); @@ -4611,7 +4636,7 @@ transport_get_by_name(const char *name) if (!transport_list) return NULL; - SMARTLIST_FOREACH_BEGIN(transport_list, const transport_t *, transport) { + SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, transport) { if (!strcmp(transport->name, name)) return transport; } SMARTLIST_FOREACH_END(transport); @@ -4636,23 +4661,81 @@ transport_create(const tor_addr_t *addr, uint16_t port, return t; } -/** Adds transport t to the internal list of pluggable transports. */ +/** Resolve any conflicts that the insertion of transport t + * might cause. + * Return 0 if t is OK and should be registered, 1 if there is + * a transport identical to t already registered and -1 if + * t cannot be added due to conflicts. */ +static int +transport_resolve_conflicts(transport_t *t) +{ + /* This is how we resolve transport conflicts: + + If there is already a transport with the same name and addrport, + we either have duplicate torrc lines OR we are here post-HUP and + this transport was here pre-HUP as well. In any case, mark the + old transport so that it doesn't get removed and ignore the new + one. + + If there is already a transport with the same name but different + addrport: + * if it's marked for removal, it means that it either has a lower + priority than 't' in torrc (otherwise the mark would have been + cleared by the paragraph above), or it doesn't exist at all in + the post-HUP torrc. We destroy the old transport and register 't'. + * if it's *not* marked for removal, it means that it was newly + added in the post-HUP torrc or that it's of higher priority, in + this case we ignore 't'. */ + transport_t *t_tmp = transport_get_by_name(t->name); + if (t_tmp) { /* same name */ + if (tor_addr_eq(&t->addr, &t_tmp->addr) && (t->port == t_tmp->port)) { + /* same name *and* addrport */ + t_tmp->marked_for_removal = 0; + return 1; + } else { /* same name but different addrport */ + if (t_tmp->marked_for_removal) { /* marked for removal */ + log_warn(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' but " + "there was already a transport marked for deletion at '%s:%u'." + "We deleted the old transport and registered the new one.", + t->name, fmt_addr(&t->addr), t->port, + fmt_addr(&t_tmp->addr), t_tmp->port); + smartlist_remove(transport_list, t_tmp); + transport_free(t_tmp); + } else { /* *not* marked for removal */ + log_warn(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' which " + "already exists at '%s:%u'. Skipping.", t->name, + fmt_addr(&t->addr), t->port, + fmt_addr(&t_tmp->addr), t_tmp->port); + return -1; + } + } + } + + return 0; +} + +/** Add transport t to the internal list of pluggable + * transports. + * Returns 0 if the transport was added correctly, 1 if the same + * transport was already registered (in this case the caller must + * free the transport) and -1 if there was an error. */ int transport_add(transport_t *t) { tor_assert(t); - if (transport_get_by_name(t->name)) { /* check for duplicate names */ - log_notice(LD_CONFIG, "More than one transports have '%s' as " - "their name.", t->name); - return -1; + int r = transport_resolve_conflicts(t); + + switch (r) { + case 0: /* should register transport */ + if (!transport_list) + transport_list = smartlist_create(); + + smartlist_add(transport_list, t); + return 0; + default: /* should let the caller know the return code */ + return r; } - - if (!transport_list) - transport_list = smartlist_create(); - - smartlist_add(transport_list, t); - return 0; } /** Remember a new pluggable transport proxy at addr:port. @@ -4664,10 +4747,23 @@ transport_add_from_config(const tor_addr_t *addr, uint16_t port, { transport_t *t = transport_create(addr, port, name, socks_ver); - if (transport_add(t) < 0) { + int r = transport_add(t); + + switch (r) { + case -1: + default: + log_warn(LD_GENERAL, "Could not add transport %s at %s:%u. Skipping.", + t->name, fmt_addr(&t->addr), t->port); transport_free(t); return -1; - } else { + case 1: + log_warn(LD_GENERAL, "Succesfully registered transport %s at %s:%u.", + t->name, fmt_addr(&t->addr), t->port); + transport_free(t); /* falling */ + return 0; + case 0: + log_warn(LD_GENERAL, "Succesfully registered transport %s at %s:%u.", + t->name, fmt_addr(&t->addr), t->port); return 0; } } diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 92449b45c2..10e72879e6 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -22,6 +22,9 @@ typedef struct { tor_addr_t addr; /** Port of proxy */ uint16_t port; + /** Boolean: We are re-parsing our transport list, and we are going to remove + * this one if we don't find it in the list of configured transports. */ + unsigned marked_for_removal : 1; } transport_t; char *circuit_list_path(origin_circuit_t *circ, int verbose); @@ -77,6 +80,9 @@ int getinfo_helper_entry_guards(control_connection_t *conn, void mark_bridge_list(void); void sweep_bridge_list(void); +void mark_transport_list(void); +void sweep_transport_list(void); + int routerinfo_is_a_configured_bridge(const routerinfo_t *ri); int node_is_a_configured_bridge(const node_t *node); void learned_router_identity(const tor_addr_t *addr, uint16_t port, @@ -149,6 +155,8 @@ transport_t *transport_create(const tor_addr_t *addr, uint16_t port, int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, const transport_t **transport); +transport_t *transport_get_by_name(const char *name); + void validate_pluggable_transports_config(void); #endif diff --git a/src/or/config.c b/src/or/config.c index 0b84f9214b..829d5ffdbd 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1251,7 +1251,8 @@ options_act(or_options_t *old_options) } - clear_transport_list(); + mark_transport_list(); + pt_prepare_proxy_list_for_config_read(); if (options->ClientTransportPlugin) { for (cl = options->ClientTransportPlugin; cl; cl = cl->next) { if (parse_client_transport_line(cl->value, 0)<0) { @@ -1273,6 +1274,8 @@ options_act(or_options_t *old_options) } } } + sweep_transport_list(); + sweep_proxy_list(); /* Bail out at this point if we're not going to be a client or server: * we want to not fork, and to log stuff to stderr. */ @@ -4769,10 +4772,7 @@ parse_client_transport_line(const char *line, int validate_only) } if (!validate_only) { - if (transport_add_from_config(&addr, port, name, - socks_ver) < 0) { - goto err; - } + transport_add_from_config(&addr, port, name, socks_ver); log_debug(LD_DIR, "Transport '%s' found at %s:%d", name, fmt_addr(&addr), (int)port); From 1e92b24889bd64ccdd568366aaf989714d130f31 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 20:29:12 +0200 Subject: [PATCH 20/36] Update transports.[ch] to support SIGHUPs. --- src/or/transports.c | 321 ++++++++++++++++++++++++++++++++++---------- src/or/transports.h | 42 +++++- 2 files changed, 291 insertions(+), 72 deletions(-) diff --git a/src/or/transports.c b/src/or/transports.c index 6255a567b6..c4391c5e24 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -17,10 +17,7 @@ static void set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp); static INLINE int proxy_configuration_finished(const managed_proxy_t *mp); -static void managed_proxy_destroy_impl(managed_proxy_t *mp, - int also_free_transports); -#define managed_proxy_destroy(mp) managed_proxy_destroy_impl(mp, 0) -#define managed_proxy_destroy_with_transports(mp) managed_proxy_destroy_impl(mp, 1) +static void managed_proxy_destroy(managed_proxy_t *mp); static void handle_finished_proxy(managed_proxy_t *mp); static void configure_proxy(managed_proxy_t *mp); @@ -55,14 +52,16 @@ static INLINE void free_execve_args(char **arg); #define PROTO_VERSION_ONE 1 /** List of unconfigured managed proxies. */ -static smartlist_t *unconfigured_proxy_list = NULL; +static smartlist_t *managed_proxy_list = NULL; +/** Number of still unconfigured proxies. */ +static int unconfigured_proxies_n = 0; /* The main idea here is: A managed proxy is represented by a managed_proxy_t struct and can spawn multiple transports. - unconfigured_proxy_list is a list of all the unconfigured managed + managed_proxy_list is a list of all the unconfigured managed proxies; everytime we find a managed proxy in torrc we add it in that list. In every run_scheduled_event() tick, we attempt to launch and then @@ -79,8 +78,7 @@ static smartlist_t *unconfigured_proxy_list = NULL; int pt_proxies_configuration_pending(void) { - if (!unconfigured_proxy_list) return 0; - return !!smartlist_len(unconfigured_proxy_list); + return !! unconfigured_proxies_n; } /** Return true if mp has the same argv as proxy_argv */ @@ -109,10 +107,10 @@ managed_proxy_has_argv(managed_proxy_t *mp, char **proxy_argv) static managed_proxy_t * get_managed_proxy_by_argv(char **proxy_argv) { - if (!unconfigured_proxy_list) + if (!managed_proxy_list) return NULL; - SMARTLIST_FOREACH_BEGIN(unconfigured_proxy_list, managed_proxy_t *, mp) { + SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) { if (managed_proxy_has_argv(mp, proxy_argv)) return mp; } SMARTLIST_FOREACH_END(mp); @@ -129,22 +127,88 @@ add_transport_to_proxy(const char *transport, managed_proxy_t *mp) smartlist_add(mp->transports_to_launch, tor_strdup(transport)); } +/** Called when a SIGHUP occurs. + * Returns true if managed proxy mp needs to be restarted + * after the SIGHUP based on the new torrc. */ +static int +proxy_needs_restart(managed_proxy_t *mp) +{ + /* mp->transport_to_launch is populated with the names of the + transports that must be launched *after* the SIGHUP. + + Since only PT_PROTO_COMPLETED proxies reach this function, + mp->transports is populated with strings of the *names of the + transports* that were launched *before* the SIGHUP. + + If the two lists contain the same strings, we don't need to + restart the proxy, since it already does what we want. */ + + tor_assert(smartlist_len(mp->transports_to_launch) > 0); + tor_assert(mp->conf_state == PT_PROTO_COMPLETED); + + if (smartlist_len(mp->transports_to_launch) != smartlist_len(mp->transports)) + goto needs_restart; + + SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, char *, t_t_l) { + if (!smartlist_string_isin(mp->transports, t_t_l)) + goto needs_restart; + + } SMARTLIST_FOREACH_END(t_t_l); + + return 0; + + needs_restart: + return 1; +} + +/** Managed proxy mp must be restarted. Do all the necessary + * preparations and then flag its state so that it will be launched + * in the next tick. */ +static void +proxy_prepare_for_restart(managed_proxy_t *mp) +{ + transport_t *t_tmp = NULL; + + tor_assert(mp->conf_state == PT_PROTO_COMPLETED); + tor_assert(mp->pid); + + /* kill the old obfsproxy process */ + tor_terminate_process(mp->pid); + mp->pid = 0; + fclose(mp->stdout); + + /* destroy all its old transports. we no longer use them. */ + SMARTLIST_FOREACH_BEGIN(mp->transports, const char *, t_name) { + t_tmp = transport_get_by_name(t_name); + if (t_tmp) + t_tmp->marked_for_removal = 1; + } SMARTLIST_FOREACH_END(t_name); + sweep_transport_list(); + + /* free the transport names in mp->transports */ + SMARTLIST_FOREACH(mp->transports, char *, t_name, tor_free(t_name)); + smartlist_clear(mp->transports); + + /* flag it as an infant proxy so that it gets launched on next tick */ + mp->conf_state = PT_PROTO_INFANT; +} + /** Launch managed proxy mp. */ static int launch_managed_proxy(managed_proxy_t *mp) { char **envp=NULL; - int retval; + int pid; FILE *stdout_read = NULL; int stdout_pipe=-1, stderr_pipe=-1; /* prepare the environment variables for the managed proxy */ set_managed_proxy_environment(&envp, mp); - retval = tor_spawn_background(mp->argv[0], &stdout_pipe, - &stderr_pipe, (const char **)mp->argv, - (const char **)envp); - if (retval < 0) { + pid = tor_spawn_background(mp->argv[0], &stdout_pipe, + &stderr_pipe, (const char **)mp->argv, + (const char **)envp); + if (pid < 0) { log_warn(LD_GENERAL, "Spawn failed"); return -1; } @@ -157,10 +221,11 @@ launch_managed_proxy(managed_proxy_t *mp) /* Open the buffered IO streams */ stdout_read = fdopen(stdout_pipe, "r"); - log_warn(LD_CONFIG, "The spawn is alive (%d)!", retval); + log_warn(LD_CONFIG, "The spawn is alive (%d)!", pid); mp->conf_state = PT_PROTO_LAUNCHED; mp->stdout = stdout_read; + mp->pid = pid; return 0; } @@ -171,12 +236,32 @@ launch_managed_proxy(managed_proxy_t *mp) void pt_configure_remaining_proxies(void) { - log_warn(LD_CONFIG, "We start configuring remaining managed proxies!"); - SMARTLIST_FOREACH_BEGIN(unconfigured_proxy_list, managed_proxy_t *, mp) { - /* configured proxies shouldn't be in unconfigured_proxy_list. */ - tor_assert(!proxy_configuration_finished(mp)); + log_warn(LD_CONFIG, "We start configuring remaining managed proxies (%d)!", + unconfigured_proxies_n); + SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) { + tor_assert(mp->conf_state != PT_PROTO_BROKEN); - configure_proxy(mp); + if (mp->got_hup) { + mp->got_hup = 0; + + /* This proxy is marked by a SIGHUP. Check whether we need to + restart it. */ + if (proxy_needs_restart(mp)) { + proxy_prepare_for_restart(mp); + continue; + } else { /* it doesn't need to be restarted. */ + printf("No need for restart; status quo\n"); + unconfigured_proxies_n--; + tor_assert(unconfigured_proxies_n >= 0); + } + + continue; + } + + /* If the proxy is not fully configured, try to configure it + futher. */ + if (!proxy_configuration_finished(mp)) + configure_proxy(mp); } SMARTLIST_FOREACH_END(mp); } @@ -222,33 +307,55 @@ configure_proxy(managed_proxy_t *mp) /** Register server managed proxy mp transports to state */ static void -register_server_proxy(const managed_proxy_t *mp) +register_server_proxy(managed_proxy_t *mp) { - if (mp->is_server) { - SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) { - save_transport_to_state(t->name,&t->addr,t->port); /* pass tor_addr_t? */ - } SMARTLIST_FOREACH_END(t); - } + smartlist_t *sm_tmp = smartlist_create(); + + tor_assert(mp->conf_state != PT_PROTO_COMPLETED); + SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) { + save_transport_to_state(t->name,&t->addr,t->port); /* pass tor_addr_t? */ + smartlist_add(sm_tmp, tor_strdup(t->name)); + } SMARTLIST_FOREACH_END(t); + + smartlist_free(mp->transports); + mp->transports = sm_tmp; } /** Register all the transports supported by client managed proxy * mp to the bridge subsystem. */ static void -register_client_proxy(const managed_proxy_t *mp) +register_client_proxy(managed_proxy_t *mp) { + int r; + smartlist_t *sm_tmp = smartlist_create(); + + tor_assert(mp->conf_state != PT_PROTO_COMPLETED); SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) { - if (transport_add(t)<0) { + r = transport_add(t); + switch (r) { + case -1: log_warn(LD_GENERAL, "Could not add transport %s. Skipping.", t->name); transport_free(t); - } else { + break; + case 0: log_warn(LD_GENERAL, "Succesfully registered transport %s", t->name); + smartlist_add(sm_tmp, tor_strdup(t->name)); + break; + case 1: + log_warn(LD_GENERAL, "Succesfully registered transport %s", t->name); + smartlist_add(sm_tmp, tor_strdup(t->name)); + transport_free(t); + break; } } SMARTLIST_FOREACH_END(t); + + smartlist_free(mp->transports); + mp->transports = sm_tmp; } /** Register the transports of managed proxy mp. */ static INLINE void -register_proxy(const managed_proxy_t *mp) +register_proxy(managed_proxy_t *mp) { if (mp->is_server) register_server_proxy(mp); @@ -256,18 +363,17 @@ register_proxy(const managed_proxy_t *mp) register_client_proxy(mp); } -/** Free memory allocated by managed proxy mp. - * If also_free_transports is set, also free the transports - * associated with this managed proxy. */ +/** Free memory allocated by managed proxy mp. */ static void -managed_proxy_destroy_impl(managed_proxy_t *mp, int also_free_transports) +managed_proxy_destroy(managed_proxy_t *mp) { - /* transport_free() all its transports */ - if (also_free_transports) + printf("Destroying mp %p\n", mp); + if (mp->conf_state != PT_PROTO_COMPLETED) SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); + else + SMARTLIST_FOREACH(mp->transports, char *, t_name, tor_free(t_name)); /* free the transports smartlist */ - smartlist_clear(mp->transports); smartlist_free(mp->transports); SMARTLIST_FOREACH(mp->transports_to_launch, char *, t, tor_free(t)); @@ -277,31 +383,32 @@ managed_proxy_destroy_impl(managed_proxy_t *mp, int also_free_transports) smartlist_free(mp->transports_to_launch); /* remove it from the list of managed proxies */ - smartlist_remove(unconfigured_proxy_list, mp); + smartlist_remove(managed_proxy_list, mp); /* close its stdout stream */ - fclose(mp->stdout); + if (mp->stdout) + fclose(mp->stdout); /* free the argv */ free_execve_args(mp->argv); + if (mp->pid) + tor_terminate_process(mp->pid); + tor_free(mp); } - /** Handle a configured or broken managed proxy mp. */ static void handle_finished_proxy(managed_proxy_t *mp) { switch (mp->conf_state) { case PT_PROTO_BROKEN: /* if broken: */ - managed_proxy_destroy_with_transports(mp); /* destroy it and all its transports */ + managed_proxy_destroy(mp); /* annihilate it. */ break; case PT_PROTO_CONFIGURED: /* if configured correctly: */ register_proxy(mp); /* register transports */ - mp->conf_state = PT_PROTO_COMPLETED; /* mark it as completed, */ - managed_proxy_destroy(mp); /* destroy the managed proxy struct, - keeping the transports intact */ + mp->conf_state = PT_PROTO_COMPLETED; /* mark it as completed. */ break; default: log_warn(LD_CONFIG, "Unfinished managed proxy in " @@ -309,7 +416,8 @@ handle_finished_proxy(managed_proxy_t *mp) tor_assert(0); } - tor_assert(smartlist_len(unconfigured_proxy_list) >= 0); + unconfigured_proxies_n--; + tor_assert(unconfigured_proxies_n >= 0); } /** Return true if the configuration of the managed proxy mp is @@ -322,8 +430,7 @@ proxy_configuration_finished(const managed_proxy_t *mp) } -/** This function is called when a proxy sends an {S,C}METHODS DONE message, - */ +/** This function is called when a proxy sends an {S,C}METHODS DONE message. */ static void handle_methods_done(const managed_proxy_t *mp) { @@ -694,6 +801,30 @@ set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp) tor_free(bindaddr); } +/** Create and return a new managed proxy for transport using + * proxy_argv. If is_server is true, it's a server + * managed proxy. */ +static managed_proxy_t * +managed_proxy_create(const char *transport, char **proxy_argv, int is_server) +{ + managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t)); + mp->conf_state = PT_PROTO_INFANT; + mp->is_server = is_server; + mp->argv = proxy_argv; + mp->transports = smartlist_create(); + + mp->transports_to_launch = smartlist_create(); + add_transport_to_proxy(transport, mp); + + /* register the managed proxy */ + if (!managed_proxy_list) + managed_proxy_list = smartlist_create(); + smartlist_add(managed_proxy_list, mp); + unconfigured_proxies_n++; + + return mp; +} + /** Register transport using proxy with proxy_argv to * the managed proxy subsystem. * If is_server is true, then the proxy is a server proxy. */ @@ -705,21 +836,28 @@ pt_kickstart_proxy(const char *transport, char **proxy_argv, int is_server) mp = get_managed_proxy_by_argv(proxy_argv); if (!mp) { /* we haven't seen this proxy before */ - /* create a managed proxy */ - managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t)); - mp->conf_state = PT_PROTO_INFANT; - mp->is_server = is_server; - mp->argv = proxy_argv; - mp->transports = smartlist_create(); + managed_proxy_create(transport, proxy_argv, is_server); - mp->transports_to_launch = smartlist_create(); - add_transport_to_proxy(transport, mp); + } else { /* known proxy. add its transport to its transport list */ + if (mp->got_hup) { + /* If the managed proxy we found is marked by a SIGHUP, it means + that it's not useless and should be kept. If it's marked for + removal, unmark it and increase the unconfigured proxies so + that we try to restart it if we need to. Afterwards, check if + a transport_t for 'transport' used to exist before the SIGHUP + and make sure it doesn't get deleted because we might reuse + it. */ + if (mp->marked_for_removal) { + mp->marked_for_removal = 0; + unconfigured_proxies_n++; + } + + transport_t *old_transport = NULL; + old_transport = transport_get_by_name(transport); + if (old_transport) + old_transport->marked_for_removal = 0; + } - /* register the managed proxy */ - if (!unconfigured_proxy_list) - unconfigured_proxy_list = smartlist_create(); - smartlist_add(unconfigured_proxy_list, mp); - } else { /* known proxy. just add transport to its transport list */ add_transport_to_proxy(transport, mp); free_execve_args(proxy_argv); } @@ -738,25 +876,66 @@ free_execve_args(char **arg) tor_free(arg); } + +/** Tor will read its config, prepare the managed proxy list so that + * proxies that are not used in the new config will shutdown, and + * proxies that need to spawn more transports will do so. */ +void +pt_prepare_proxy_list_for_config_read(void) +{ + if (!managed_proxy_list) + return; + + SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) { + /* Destroy unconfigured proxies. */ + if (mp->conf_state != PT_PROTO_COMPLETED) { + managed_proxy_destroy(mp); + unconfigured_proxies_n--; + continue; + } + + tor_assert(mp->conf_state == PT_PROTO_COMPLETED); + + mp->marked_for_removal = 1; + mp->got_hup = 1; + SMARTLIST_FOREACH(mp->transports_to_launch, char *, t, tor_free(t)); + smartlist_clear(mp->transports_to_launch); + } SMARTLIST_FOREACH_END(mp); + + tor_assert(unconfigured_proxies_n == 0); +} + +/** The tor config was read, destroy all managed proxies that were + * marked by a previous call to prepare_proxy_list_for_config_read() + * and are not used by the new config. */ +void +sweep_proxy_list(void) +{ + if (!managed_proxy_list) + return; + + SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) { + if (mp->marked_for_removal) { + SMARTLIST_DEL_CURRENT(managed_proxy_list, mp); + managed_proxy_destroy(mp); + } + } SMARTLIST_FOREACH_END(mp); +} + /** Release all storage held by the pluggable transports subsystem. */ void pt_free_all(void) { - if (unconfigured_proxy_list) { + if (managed_proxy_list) { /* If the proxy is in PT_PROTO_COMPLETED, it has registered its transports and it's the duty of the circuitbuild.c subsystem to free them. Otherwise, it hasn't registered its transports yet and we should free them here. */ - SMARTLIST_FOREACH_BEGIN(unconfigured_proxy_list, managed_proxy_t *, mp) { - if (mp->conf_state == PT_PROTO_COMPLETED) - managed_proxy_destroy(mp); - else - managed_proxy_destroy_with_transports(mp); - } SMARTLIST_FOREACH_END(mp); + SMARTLIST_FOREACH(managed_proxy_list, managed_proxy_t *, mp, + managed_proxy_destroy(mp)); - smartlist_clear(unconfigured_proxy_list); - smartlist_free(unconfigured_proxy_list); - unconfigured_proxy_list=NULL; + smartlist_free(managed_proxy_list); + managed_proxy_list=NULL; } } diff --git a/src/or/transports.h b/src/or/transports.h index 6fec1dcf7c..48b7839cfb 100644 --- a/src/or/transports.h +++ b/src/or/transports.h @@ -25,6 +25,9 @@ int pt_proxies_configuration_pending(void); void pt_free_all(void); +void pt_prepare_proxy_list_for_config_read(void); +void sweep_proxy_list(void); + #ifdef PT_PRIVATE /** State of the managed proxy configuration protocol. */ enum pt_proto_state { @@ -47,8 +50,45 @@ typedef struct { FILE *stdout; /* a stream to its stdout (closed in managed_proxy_destroy()) */ + int pid; /* The Process ID this managed proxy is using. */ + + /** Boolean: We are re-parsing our config, and we are going to + * remove this managed proxy if we don't find it any transport + * plugins that use it. */ + unsigned int marked_for_removal : 1; + + /** Boolean: We got a SIGHUP while this proxy was running. We use + * this flag to signify that this proxy might need to be restarted + * so that it can listen for other transports according to the new + * torrc. */ + unsigned int got_hup : 1; + smartlist_t *transports_to_launch; /* transports to-be-launched by this proxy */ - smartlist_t *transports; /* list of transport_t this proxy spawned */ + + /* The 'transports' list contains all the transports this proxy has + launched. + + Before a managed_proxy_t reaches the PT_PROTO_COMPLETED phase, + this smartlist contains a 'transport_t' for every transport it + has launched. + + When the managed_proxy_t reaches the PT_PROTO_COMPLETED phase, it + registers all its transports to the circuitbuild.c subsystem. At + that point the 'transport_t's are owned by the circuitbuild.c + subsystem. + + To avoid carrying dangling 'transport_t's in this smartlist, + right before the managed_proxy_t reaches the PT_PROTO_COMPLETED + phase we replace all 'transport_t's with strings of their + transport names. + + So, tl;dr: + When (conf_state != PT_PROTO_COMPLETED) this list carries + (transport_t *). + When (conf_state == PT_PROTO_COMPLETED) this list carries + (char *). + */ + smartlist_t *transports; } managed_proxy_t; int parse_cmethod_line(const char *line, managed_proxy_t *mp); From a002f0e7c09dc664148a018fc69ac416789330dd Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 20:29:52 +0200 Subject: [PATCH 21/36] Update the transports.c documentation based on the new data. --- src/or/transports.c | 82 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 12 deletions(-) diff --git a/src/or/transports.c b/src/or/transports.c index c4391c5e24..7d483a36d1 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -56,23 +56,81 @@ static smartlist_t *managed_proxy_list = NULL; /** Number of still unconfigured proxies. */ static int unconfigured_proxies_n = 0; -/* The main idea here is: +/** "The main idea is:" - A managed proxy is represented by a managed_proxy_t struct and can - spawn multiple transports. + Each managed proxy is represented by a 'managed_proxy_t'. + Each managed proxy can support multiple transports. + Each managed proxy gets configured through a multistep process. + + 'managed_proxy_list' contains all the managed proxies this tor + instance is supporting. + In the 'managed_proxy_list' there are 'unconfigured_proxies_n' + managed proxies that are still unconfigured. - managed_proxy_list is a list of all the unconfigured managed - proxies; everytime we find a managed proxy in torrc we add it in - that list. In every run_scheduled_event() tick, we attempt to launch and then - configure each managed proxy, using the configuration protocol - defined in the 180_pluggable_transport.txt proposal. A managed - proxy might need several ticks to get fully configured. + configure the unconfiged managed proxies, using the configuration + protocol defined in the 180_pluggable_transport.txt proposal. A + managed proxy might need several ticks to get fully configured. When a managed proxy is fully configured, we register all its - transports to the circuitbuild.c subsystem - like we do with - external proxies - and then free the managed proxy struct - since it's no longer needed. */ + transports to the circuitbuild.c subsystem. At that point the + transports are owned by the circuitbuild.c subsystem. + + When a managed proxy fails to follow the 180 configuration + protocol, it gets marked as broken and gets destroyed. + + "In a little more technical detail:" + + While we are serially parsing torrc, we store all the transports + that a proxy should spawn in its 'transports_to_launch' element. + + When we finish reading the torrc, we spawn the managed proxy and + expect {S,C}METHOD lines from its output. We add transports + described by METHOD lines to its 'transports' element, as + 'transport_t' structs. + + When the managed proxy stops spitting METHOD lines (signified by a + '{S,C}METHODS DONE' message) we register all the transports + collected to the circuitbuild.c subsystem. At this point, the + 'transport_t's can be transformed into dangling pointers at any + point by the circuitbuild.c subsystem, and so we replace all + 'transport_t's with strings describing the transport names. We + can still go from a transport name to a 'transport_t' using the + fact that transport names uniquely identify 'transport_t's. + + "In even more technical detail I shall describe what happens when + the SIGHUP bell tolls:" + + We immediately destroy all unconfigured proxies (We shouldn't have + unconfigured proxies in the first place, except when SIGHUP rings + immediately after tor is launched.). + + We mark all managed proxies and transports to signify that they + must be removed if they don't contribute by the new torrc. We also + mark all managed proxies to signify that they might need to be + restarted so that they end up supporting all the transports the + new torrc wants them to support. + We also clear the 'transports_to_launch' list so that we can put + there the transports we need to launch on each proxy according to + the new torrc. + + We then start parsing torrc again, everytime we encounter a + transport line using a known pre-SIGHUP managed proxy, we cleanse + that proxy from the removal mark. + + We also mark it as unconfigured so that on the next scheduled + events tick, we investigate whether we need to restart the proxy + so that it spawns the new 'transport_to_launch' list. Of course, + if the post-SIGHUP 'transports_to_launch' list is identical to the + pre-SIGHUP one, it means that no changes were introduced to this + proxy during the SIGHUP and no restart has to take place. + + During the post-SIGHUP torrc parsing, we unmark all transports we + encounter. This happens in the case that no restart is needed, we + can continue using the old transports normally. If we end up + restarting the proxy, we destroy and unregister all old transports + from the circuitbuild.c subsystem since they become useless. +*/ /** Return true if there are still unconfigured managed proxies. */ int From 9bf34eb65b9533bf9a53952acf2994b9ee973ff2 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 20:30:08 +0200 Subject: [PATCH 22/36] Allow interwined {Client,Server}TransportPlugin lines. --- src/or/transports.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/or/transports.c b/src/or/transports.c index 7d483a36d1..91ff5184a7 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -163,13 +163,14 @@ managed_proxy_has_argv(managed_proxy_t *mp, char **proxy_argv) /** Return a managed proxy with the same argv as proxy_argv. * If no such managed proxy exists, return NULL. */ static managed_proxy_t * -get_managed_proxy_by_argv(char **proxy_argv) +get_managed_proxy_by_argv_and_type(char **proxy_argv, int is_server) { if (!managed_proxy_list) return NULL; SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) { - if (managed_proxy_has_argv(mp, proxy_argv)) + if (managed_proxy_has_argv(mp, proxy_argv) && + mp->is_server == is_server) return mp; } SMARTLIST_FOREACH_END(mp); @@ -891,7 +892,7 @@ pt_kickstart_proxy(const char *transport, char **proxy_argv, int is_server) { managed_proxy_t *mp=NULL; - mp = get_managed_proxy_by_argv(proxy_argv); + mp = get_managed_proxy_by_argv_and_type(proxy_argv, is_server); if (!mp) { /* we haven't seen this proxy before */ managed_proxy_create(transport, proxy_argv, is_server); From 0dcf327248d9e971b2bad9fcd498c3b18f2f70c0 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 20:33:27 +0200 Subject: [PATCH 23/36] Remove connection_uses_transport() since it was unused. --- src/or/connection.c | 11 ----------- src/or/connection.h | 1 - 2 files changed, 12 deletions(-) diff --git a/src/or/connection.c b/src/or/connection.c index 04dba2b9b0..05688e5a4e 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -4150,17 +4150,6 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, return 0; } -/** Returns true if connection conn is using a pluggable - * transports proxy server. */ -int -connection_uses_transport(connection_t *conn) -{ - const transport_t *transport=NULL; - find_transport_by_bridge_addrport(&conn->addr, - conn->port,&transport); - return transport ? 1 : 0; -} - /** Returns the global proxy type used by tor. */ static int get_proxy_type(void) diff --git a/src/or/connection.h b/src/or/connection.h index 51cf2a845a..be3de88aaa 100644 --- a/src/or/connection.h +++ b/src/or/connection.h @@ -60,7 +60,6 @@ int connection_read_proxy_handshake(connection_t *conn); void log_failed_proxy_connection(connection_t *conn); int get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type, const connection_t *conn); -int connection_uses_transport(connection_t *conn); int retry_all_listeners(smartlist_t *replaced_conns, smartlist_t *new_conns); From 2703e41d8b6ffcad653af68a8261c22b5a1ed26f Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 20:57:01 +0200 Subject: [PATCH 24/36] Improve how we access or_state_t. * Use get_or_state()->VirtualOption instead of relying on config_find_option(), STRUCT_VAR_P and voodoo. --- src/or/config.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index 829d5ffdbd..bacdae32ea 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -5513,16 +5513,11 @@ static int validate_transports_in_state(or_state_t *state) { int broken = 0; + config_line_t *line; - config_var_t *var = config_find_option(&state_format,"TransportProxies"); - if (!var) - return 0; - - config_line_t **value = STRUCT_VAR_P(state, var->var_offset); - config_line_t *search = NULL; - - for (search = *value ; search ; search = search->next) { - if (!state_transport_line_is_valid(search->value)<0) + for (line = state->TransportProxies ; line ; line = line->next) { + tor_assert(!strcmp(line->key, "TransportProxy")); + if (!state_transport_line_is_valid(line->value)<0) broken = 1; } @@ -5790,18 +5785,13 @@ or_state_save(time_t now) static config_line_t * get_transport_in_state_by_name(const char *transport) { - config_var_t *var = config_find_option(&state_format,"TransportProxies"); - if (!var) - return NULL; + or_state_t *or_state = get_or_state(); + config_line_t *line; - config_line_t **value = STRUCT_VAR_P(get_or_state(), var->var_offset); - config_line_t *search = *value; - - while (search) { - if (!strcmpstart(search->value, transport)) - return search; - - search = search->next; + for (line = or_state->TransportProxies ; line ; line = line->next) { + tor_assert(!strcmp(line->key, "TransportProxy")); + if (!strcmpstart(line->value, transport)) + return line; } return NULL; } From ebc232bb79c8816d17eea75d3a29c1ecb25da0b0 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 21:22:37 +0200 Subject: [PATCH 25/36] Fix bug in get_transport_in_state_by_name() when using strcmpstart(). We now split the state lines into smartlists and compare the token properly. Not that efficient but it's surely correct. --- src/or/config.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index bacdae32ea..792124c08b 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -5787,13 +5787,34 @@ get_transport_in_state_by_name(const char *transport) { or_state_t *or_state = get_or_state(); config_line_t *line; + config_line_t *ret = NULL; + smartlist_t *items = NULL; for (line = or_state->TransportProxies ; line ; line = line->next) { tor_assert(!strcmp(line->key, "TransportProxy")); - if (!strcmpstart(line->value, transport)) - return line; + + items = smartlist_create(); + smartlist_split_string(items, line->value, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + if (smartlist_len(items) != 2) /* broken state */ + goto done; + + if (!strcmp(smartlist_get(items, 0), transport)) { + ret = line; + goto done; + } + + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + items = NULL; } - return NULL; + + done: + if (items) { + SMARTLIST_FOREACH(items, char*, s, tor_free(s)); + smartlist_free(items); + } + return ret; } /** Return string containing the address:port part of the From 9a42ec685751b5c5fd21f33cd788810d997f0d6e Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 21:33:02 +0200 Subject: [PATCH 26/36] Be more defensive in get_transport_bindaddr(). Make sure that lines in get_transport_bindaddr() begin with the name of the transport and a space. --- src/or/config.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index 792124c08b..79c1b1e199 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -5823,10 +5823,24 @@ get_transport_in_state_by_name(const char *transport) const char * get_transport_bindaddr(const char *line, const char *transport) { - if (strlen(line) < strlen(transport) + 2) - return NULL; - else + char *line_tmp = NULL; + + if (strlen(line) < strlen(transport) + 2) { + goto broken_state; + } else { + /* line should start with the name of the transport and a space. + (for example, "obfs2 127.0.0.1:47245") */ + tor_asprintf(&line_tmp, "%s ", transport); + if (strcmpstart(line, line_tmp)) + goto broken_state; + + tor_free(line_tmp); return (line+strlen(transport)+1); + } + + broken_state: + tor_free(line_tmp); + return NULL; } /** Return a static string containing the address:port a proxy From 31361074216534b0a4c6377730c09b261ca4ef4e Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 23:33:31 +0200 Subject: [PATCH 27/36] Trivial fixes around the code. * C90-fy. * Remove ASN comments. * Don't smartlist_clear() before smartlist_free(). * Plug a mem. leak. --- src/or/circuitbuild.c | 4 ++-- src/or/config.c | 12 ++++++------ src/or/transports.c | 17 ++++++++++++----- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index bd06d31070..7338e24308 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -4722,9 +4722,10 @@ transport_resolve_conflicts(transport_t *t) int transport_add(transport_t *t) { + int r; tor_assert(t); - int r = transport_resolve_conflicts(t); + r = transport_resolve_conflicts(t); switch (r) { case 0: /* should register transport */ @@ -5016,7 +5017,6 @@ fetch_bridge_descriptors(or_options_t *options, time_t now) if (!bridge_list) return; - /* ASN Should we move this to launch_direct_bridge_descriptor_fetch() ? */ /* If we still have unconfigured managed proxies, don't go and connect to a bridge. */ if (pt_proxies_configuration_pending()) diff --git a/src/or/config.c b/src/or/config.c index 79c1b1e199..d36418b0d5 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1226,11 +1226,6 @@ options_act(or_options_t *old_options) sweep_bridge_list(); } - /* If we have pluggable transport related options enabled, see if we - should warn the user about potential configuration problems. */ - if (options->Bridges || options->ClientTransportPlugin) - validate_pluggable_transports_config(); - if (running_tor && rend_config_services(options, 0)<0) { log_warn(LD_BUG, "Previously validated hidden services line could not be added!"); @@ -1277,6 +1272,11 @@ options_act(or_options_t *old_options) sweep_transport_list(); sweep_proxy_list(); + /* If we have pluggable transport related options enabled, see if we + should warn the user about potential configuration problems. */ + if (options->Bridges || options->ClientTransportPlugin) + validate_pluggable_transports_config(); + /* Bail out at this point if we're not going to be a client or server: * we want to not fork, and to log stuff to stderr. */ if (!running_tor) @@ -5820,7 +5820,7 @@ get_transport_in_state_by_name(const char *transport) /** Return string containing the address:port part of the * TransportProxy line for transport transport. * If the line is corrupted, return NULL. */ -const char * +static const char * get_transport_bindaddr(const char *line, const char *transport) { char *line_tmp = NULL; diff --git a/src/or/transports.c b/src/or/transports.c index 91ff5184a7..1b7249fae2 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -13,7 +13,6 @@ #include "transports.h" #include "util.h" -/* ASN TIDY THESE UP*/ static void set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp); static INLINE int proxy_configuration_finished(const managed_proxy_t *mp); @@ -372,11 +371,16 @@ register_server_proxy(managed_proxy_t *mp) tor_assert(mp->conf_state != PT_PROTO_COMPLETED); SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) { - save_transport_to_state(t->name,&t->addr,t->port); /* pass tor_addr_t? */ + save_transport_to_state(t->name, &t->addr, t->port); smartlist_add(sm_tmp, tor_strdup(t->name)); } SMARTLIST_FOREACH_END(t); + /* Since server proxies don't register their transports in the + circuitbuild.c subsystem, it's our duty to free them when we + switch mp->transports to strings. */ + SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); smartlist_free(mp->transports); + mp->transports = sm_tmp; } @@ -438,7 +442,6 @@ managed_proxy_destroy(managed_proxy_t *mp) SMARTLIST_FOREACH(mp->transports_to_launch, char *, t, tor_free(t)); /* free the transports smartlist */ - smartlist_clear(mp->transports_to_launch); smartlist_free(mp->transports_to_launch); /* remove it from the list of managed proxies */ @@ -469,8 +472,12 @@ handle_finished_proxy(managed_proxy_t *mp) register_proxy(mp); /* register transports */ mp->conf_state = PT_PROTO_COMPLETED; /* mark it as completed. */ break; + case PT_PROTO_INFANT: + case PT_PROTO_LAUNCHED: + case PT_PROTO_ACCEPTING_METHODS: + case PT_PROTO_COMPLETED: default: - log_warn(LD_CONFIG, "Unfinished managed proxy in " + log_warn(LD_CONFIG, "Unexpected managed proxy state in " "handle_finished_proxy()."); tor_assert(0); } @@ -891,6 +898,7 @@ void pt_kickstart_proxy(const char *transport, char **proxy_argv, int is_server) { managed_proxy_t *mp=NULL; + transport_t *old_transport = NULL; mp = get_managed_proxy_by_argv_and_type(proxy_argv, is_server); @@ -911,7 +919,6 @@ pt_kickstart_proxy(const char *transport, char **proxy_argv, int is_server) unconfigured_proxies_n++; } - transport_t *old_transport = NULL; old_transport = transport_get_by_name(transport); if (old_transport) old_transport->marked_for_removal = 0; From c6811c57cb75b2c594b2a6fffaca0c5ae4c19e0a Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 23:34:11 +0200 Subject: [PATCH 28/36] Enforce transport names being C identifiers. Introduce string_is_C_identifier() and use it to enforce transport names according to the 180 spec. --- src/common/util.c | 28 ++++++++++++++++++++++++++++ src/common/util.h | 2 ++ src/or/config.c | 8 ++++++++ src/or/transports.c | 10 ++++++++++ 4 files changed, 48 insertions(+) diff --git a/src/common/util.c b/src/common/util.c index 63172c36a3..5fc2cbeabc 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -719,6 +719,34 @@ find_str_at_start_of_line(const char *haystack, const char *needle) return NULL; } +/** Returns true if string could be a C identifier. + A C identifier must begin with a letter or an underscore and the + rest of its characters can be letters, numbers or underscores. No + length limit is imposed. */ +int +string_is_C_identifier(const char *string) +{ + size_t iter; + size_t length = strlen(string); + if (!length) + return 0; + + for (iter = 0; iter < length ; iter++) { + if (iter == 0) { + if (!(TOR_ISALPHA(string[iter]) || + string[iter] == '_')) + return 0; + } else { + if (!(TOR_ISALPHA(string[iter]) || + TOR_ISDIGIT(string[iter]) || + string[iter] == '_')) + return 0; + } + } + + return 1; +} + /** Return true iff the 'len' bytes at 'mem' are all zero. */ int tor_mem_is_zero(const char *mem, size_t len) diff --git a/src/common/util.h b/src/common/util.h index 7e889b10c7..04ae7cbc33 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -203,6 +203,8 @@ const char *find_whitespace(const char *s) ATTR_PURE; const char *find_whitespace_eos(const char *s, const char *eos) ATTR_PURE; const char *find_str_at_start_of_line(const char *haystack, const char *needle) ATTR_PURE; +int string_is_C_identifier(const char *string); + int tor_mem_is_zero(const char *mem, size_t len) ATTR_PURE; int tor_digest_is_zero(const char *digest) ATTR_PURE; int tor_digest256_is_zero(const char *digest) ATTR_PURE; diff --git a/src/or/config.c b/src/or/config.c index d36418b0d5..58668b1734 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -4724,6 +4724,10 @@ parse_client_transport_line(const char *line, int validate_only) } name = smartlist_get(items, 0); + if (!string_is_C_identifier(name)) { + log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).", name); + goto err; + } /* field2 is either a SOCKS version or "exec" */ field2 = smartlist_get(items, 1); @@ -4826,6 +4830,10 @@ parse_server_transport_line(const char *line, int validate_only) } name = smartlist_get(items, 0); + if (!string_is_C_identifier(name)) { + log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).", name); + goto err; + } type = smartlist_get(items, 1); diff --git a/src/or/transports.c b/src/or/transports.c index 1b7249fae2..6d1ddebe5d 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -686,6 +686,11 @@ parse_smethod_line(const char *line, managed_proxy_t *mp) tor_assert(!strcmp(smartlist_get(items,0),PROTO_SMETHOD)); method_name = smartlist_get(items,1); + if (!string_is_C_identifier(method_name)) { + log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).", + method_name); + goto err; + } addrport = smartlist_get(items, 2); if (tor_addr_port_parse(addrport, &addr, &port)<0) { @@ -754,6 +759,11 @@ parse_cmethod_line(const char *line, managed_proxy_t *mp) tor_assert(!strcmp(smartlist_get(items,0),PROTO_CMETHOD)); method_name = smartlist_get(items,1); + if (!string_is_C_identifier(method_name)) { + log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).", + method_name); + goto err; + } socks_ver_str = smartlist_get(items,2); From de7565f87fba14973038fbcd740ff9fecaa28b4e Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 23:34:36 +0200 Subject: [PATCH 29/36] Make check-spaces happy. --- src/common/util.c | 6 ++++-- src/or/circuitbuild.c | 10 +++++----- src/or/config.c | 9 +++++---- src/or/transports.c | 11 ++++++----- src/or/transports.h | 3 ++- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/common/util.c b/src/common/util.c index 5fc2cbeabc..502840bc3e 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -3193,9 +3193,11 @@ tor_spawn_background(const char *const filename, int *stdout_read, * * Returns: * IO_STREAM_CLOSED: If the stream is closed. - * IO_STREAM_EAGAIN: If there is nothing to read and we should check back later. + * IO_STREAM_EAGAIN: If there is nothing to read and we should check back + * later. * IO_STREAM_TERM: If something is wrong with the stream. - * IO_STREAM_OKAY: If everything went okay and we got a string in buf_out. */ + * IO_STREAM_OKAY: If everything went okay and we got a string + * in buf_out. */ enum stream_status get_string_from_pipe(FILE *stream, char *buf_out, size_t count) { diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 7338e24308..b4c234301e 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -4695,15 +4695,15 @@ transport_resolve_conflicts(transport_t *t) } else { /* same name but different addrport */ if (t_tmp->marked_for_removal) { /* marked for removal */ log_warn(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' but " - "there was already a transport marked for deletion at '%s:%u'." - "We deleted the old transport and registered the new one.", - t->name, fmt_addr(&t->addr), t->port, + "there was already a transport marked for deletion at " + "'%s:%u'. We deleted the old transport and registered the " + "new one.", t->name, fmt_addr(&t->addr), t->port, fmt_addr(&t_tmp->addr), t_tmp->port); smartlist_remove(transport_list, t_tmp); transport_free(t_tmp); } else { /* *not* marked for removal */ - log_warn(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' which " - "already exists at '%s:%u'. Skipping.", t->name, + log_warn(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' " + "which already exists at '%s:%u'. Skipping.", t->name, fmt_addr(&t->addr), t->port, fmt_addr(&t_tmp->addr), t_tmp->port); return -1; diff --git a/src/or/config.c b/src/or/config.c index 58668b1734..df06739bc7 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1245,7 +1245,6 @@ options_act(or_options_t *old_options) rep_hist_load_mtbf_data(time(NULL)); } - mark_transport_list(); pt_prepare_proxy_list_for_config_read(); if (options->ClientTransportPlugin) { @@ -5892,11 +5891,13 @@ save_transport_to_state(const char *transport, /* if transport in state has the same address as this one, life is good */ if (!strcmp(prev_bindaddr, transport_addrport)) { - log_warn(LD_CONFIG, "Transport seems to have spawned on its usual address:port."); + log_warn(LD_CONFIG, "Transport seems to have spawned on its usual " + "address:port."); goto done; } else { /* addrport in state is different than the one we got */ - log_warn(LD_CONFIG, "Transport seems to have spawned on different address:port." - "Let's update the state file with the new address:port"); + log_warn(LD_CONFIG, "Transport seems to have spawned on different " + "address:port. Let's update the state file with the new " + "address:port"); tor_free(transport_line->value); /* free the old line */ tor_asprintf(&transport_line->value, "%s %s:%d", transport, fmt_addr(addr), diff --git a/src/or/transports.c b/src/or/transports.c index 6d1ddebe5d..01cbfca9df 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -13,7 +13,8 @@ #include "transports.h" #include "util.h" -static void set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp); +static void set_managed_proxy_environment(char ***envp, + const managed_proxy_t *mp); static INLINE int proxy_configuration_finished(const managed_proxy_t *mp); static void managed_proxy_destroy(managed_proxy_t *mp); @@ -495,7 +496,6 @@ proxy_configuration_finished(const managed_proxy_t *mp) mp->conf_state == PT_PROTO_BROKEN); } - /** This function is called when a proxy sends an {S,C}METHODS DONE message. */ static void handle_methods_done(const managed_proxy_t *mp) @@ -863,10 +863,12 @@ set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp) if (mp->is_server) { bindaddr = get_bindaddr_for_proxy(mp); - tor_asprintf(tmp++, "TOR_PT_ORPORT=127.0.0.1:%d", options->ORPort); /* XXX temp */ + /* XXX temp */ + tor_asprintf(tmp++, "TOR_PT_ORPORT=127.0.0.1:%d", options->ORPort); tor_asprintf(tmp++, "TOR_PT_SERVER_BINDADDR=%s", bindaddr); tor_asprintf(tmp++, "TOR_PT_SERVER_TRANSPORTS=%s", transports_to_launch); - tor_asprintf(tmp++, "TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200"); /* XXX temp*/ + /* XXX temp*/ + tor_asprintf(tmp++, "TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200"); } else { tor_asprintf(tmp++, "TOR_PT_CLIENT_TRANSPORTS=%s", transports_to_launch); } @@ -952,7 +954,6 @@ free_execve_args(char **arg) tor_free(arg); } - /** Tor will read its config, prepare the managed proxy list so that * proxies that are not used in the new config will shutdown, and * proxies that need to spawn more transports will do so. */ diff --git a/src/or/transports.h b/src/or/transports.h index 48b7839cfb..57bfb5ca17 100644 --- a/src/or/transports.h +++ b/src/or/transports.h @@ -63,7 +63,8 @@ typedef struct { * torrc. */ unsigned int got_hup : 1; - smartlist_t *transports_to_launch; /* transports to-be-launched by this proxy */ + /* transports to-be-launched by this proxy */ + smartlist_t *transports_to_launch; /* The 'transports' list contains all the transports this proxy has launched. From e8715b30411062d09832e912d87d526dc203e4f0 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 23:35:00 +0200 Subject: [PATCH 30/36] Constification. --- src/or/config.c | 2 +- src/or/transports.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index df06739bc7..f2cb6cde5c 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -5474,7 +5474,7 @@ options_get_datadir_fname2_suffix(or_options_t *options, /** Return true if line is a valid state TransportProxy line. * Return false otherwise. */ static int -state_transport_line_is_valid(char *line) +state_transport_line_is_valid(const char *line) { smartlist_t *items = NULL; char *addrport=NULL; diff --git a/src/or/transports.c b/src/or/transports.c index 01cbfca9df..a3abfed729 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -141,7 +141,7 @@ pt_proxies_configuration_pending(void) /** Return true if mp has the same argv as proxy_argv */ static int -managed_proxy_has_argv(managed_proxy_t *mp, char **proxy_argv) +managed_proxy_has_argv(const managed_proxy_t *mp, char **proxy_argv) { char **tmp1=proxy_argv; char **tmp2=mp->argv; @@ -190,7 +190,7 @@ add_transport_to_proxy(const char *transport, managed_proxy_t *mp) * Returns true if managed proxy mp needs to be restarted * after the SIGHUP based on the new torrc. */ static int -proxy_needs_restart(managed_proxy_t *mp) +proxy_needs_restart(const managed_proxy_t *mp) { /* mp->transport_to_launch is populated with the names of the transports that must be launched *after* the SIGHUP. From d0416ce3ec67ca87448153c8b2416dd7901013c6 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Sun, 11 Sep 2011 23:51:29 +0200 Subject: [PATCH 31/36] Don't warn of stray Bridges if managed proxies are still unconfigured. With managed proxies you would always get the error message: "You have a Bridge line using the X pluggable transport, but there doesn't seem to be a corresponding ClientTransportPlugin line." because the check happened directly after parse_client_transport_line() when managed proxies were not fully configured and their transports were not registered. The fix is to move the validation to run_scheduled_events() and make sure that all managed proxies are configured first. --- src/or/circuitbuild.c | 13 ++++++++++--- src/or/circuitbuild.h | 2 +- src/or/config.c | 5 ----- src/or/main.c | 9 +++++++++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index b4c234301e..ed813046a9 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -4769,11 +4769,14 @@ transport_add_from_config(const tor_addr_t *addr, uint16_t port, } } -/** Warns the user of possible pluggable transport misconfiguration. */ -void +/** Warn the user of possible pluggable transport misconfiguration. + * Return 0 if the validation happened, -1 if we should postpone the + * validation. */ +int validate_pluggable_transports_config(void) { - if (bridge_list) { + /* Don't validate if managed proxies are not yet fully configured. */ + if (bridge_list && !pt_proxies_configuration_pending()) { SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) { /* Skip bridges without transports. */ if (!b->transport_name) @@ -4787,6 +4790,10 @@ validate_pluggable_transports_config(void) "corresponding ClientTransportPlugin line.", b->transport_name); } SMARTLIST_FOREACH_END(b); + + return 0; + } else { + return -1; } } diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 10e72879e6..dca541d6ff 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -157,7 +157,7 @@ int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port, const transport_t **transport); transport_t *transport_get_by_name(const char *name); -void validate_pluggable_transports_config(void); +int validate_pluggable_transports_config(void); #endif diff --git a/src/or/config.c b/src/or/config.c index f2cb6cde5c..8bd47b5008 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1271,11 +1271,6 @@ options_act(or_options_t *old_options) sweep_transport_list(); sweep_proxy_list(); - /* If we have pluggable transport related options enabled, see if we - should warn the user about potential configuration problems. */ - if (options->Bridges || options->ClientTransportPlugin) - validate_pluggable_transports_config(); - /* Bail out at this point if we're not going to be a client or server: * we want to not fork, and to log stuff to stderr. */ if (!running_tor) diff --git a/src/or/main.c b/src/or/main.c index 5294e4ad0d..6297f0f3e2 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1068,6 +1068,7 @@ run_scheduled_events(time_t now) static int should_init_bridge_stats = 1; static time_t time_to_retry_dns_init = 0; static time_t time_to_next_heartbeat = 0; + static int has_validated_pt = 0; or_options_t *options = get_options(); int is_server = server_mode(options); int i; @@ -1472,6 +1473,14 @@ run_scheduled_events(time_t now) if (pt_proxies_configuration_pending()) pt_configure_remaining_proxies(); + /** 11c. validate pluggable transports configuration if we need to */ + if (!has_validated_pt && + (options->Bridges || options->ClientTransportPlugin)) { + if (validate_pluggable_transports_config() == 0) { + has_validated_pt = 1; + } + } + /** 12. write the heartbeat message */ if (options->HeartbeatPeriod && time_to_next_heartbeat < now) { From 2e73f9b3eeb37d0307197e48ed62e1def40e44a8 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 12 Sep 2011 00:10:07 +0200 Subject: [PATCH 32/36] Put some sense into our logging. Transform our logging severities to something more sensible. Remove sneaky printf()s. --- src/common/util.c | 2 +- src/or/circuitbuild.c | 26 ++++++++++++------------ src/or/config.c | 12 +++++------ src/or/transports.c | 46 ++++++++++++++++++++++--------------------- 4 files changed, 44 insertions(+), 42 deletions(-) diff --git a/src/common/util.c b/src/common/util.c index 502840bc3e..4a66e93537 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -3230,7 +3230,7 @@ get_string_from_pipe(FILE *stream, char *buf_out, size_t count) } else { /* No newline; check whether we overflowed the buffer */ if (!feof(stream)) - log_warn(LD_GENERAL, + log_info(LD_GENERAL, "Line from stream was truncated: %s", buf_out); /* TODO: What to do with this error? */ } diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index ed813046a9..86154bac2e 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -4694,18 +4694,18 @@ transport_resolve_conflicts(transport_t *t) return 1; } else { /* same name but different addrport */ if (t_tmp->marked_for_removal) { /* marked for removal */ - log_warn(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' but " - "there was already a transport marked for deletion at " - "'%s:%u'. We deleted the old transport and registered the " - "new one.", t->name, fmt_addr(&t->addr), t->port, - fmt_addr(&t_tmp->addr), t_tmp->port); + log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' " + "but there was already a transport marked for deletion at " + "'%s:%u'. We deleted the old transport and registered the " + "new one.", t->name, fmt_addr(&t->addr), t->port, + fmt_addr(&t_tmp->addr), t_tmp->port); smartlist_remove(transport_list, t_tmp); transport_free(t_tmp); } else { /* *not* marked for removal */ - log_warn(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' " - "which already exists at '%s:%u'. Skipping.", t->name, - fmt_addr(&t->addr), t->port, - fmt_addr(&t_tmp->addr), t_tmp->port); + log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' " + "which already exists at '%s:%u'. Skipping.", t->name, + fmt_addr(&t->addr), t->port, + fmt_addr(&t_tmp->addr), t_tmp->port); return -1; } } @@ -4753,17 +4753,17 @@ transport_add_from_config(const tor_addr_t *addr, uint16_t port, switch (r) { case -1: default: - log_warn(LD_GENERAL, "Could not add transport %s at %s:%u. Skipping.", - t->name, fmt_addr(&t->addr), t->port); + log_notice(LD_GENERAL, "Could not add transport %s at %s:%u. Skipping.", + t->name, fmt_addr(&t->addr), t->port); transport_free(t); return -1; case 1: - log_warn(LD_GENERAL, "Succesfully registered transport %s at %s:%u.", + log_info(LD_GENERAL, "Succesfully registered transport %s at %s:%u.", t->name, fmt_addr(&t->addr), t->port); transport_free(t); /* falling */ return 0; case 0: - log_warn(LD_GENERAL, "Succesfully registered transport %s at %s:%u.", + log_info(LD_GENERAL, "Succesfully registered transport %s at %s:%u.", t->name, fmt_addr(&t->addr), t->port); return 0; } diff --git a/src/or/config.c b/src/or/config.c index 8bd47b5008..3d83b99e70 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -4772,8 +4772,8 @@ parse_client_transport_line(const char *line, int validate_only) if (!validate_only) { transport_add_from_config(&addr, port, name, socks_ver); - log_debug(LD_DIR, "Transport '%s' found at %s:%d", name, - fmt_addr(&addr), (int)port); + log_info(LD_DIR, "Transport '%s' found at %s:%d", name, + fmt_addr(&addr), (int)port); } } @@ -4871,7 +4871,7 @@ parse_server_transport_line(const char *line, int validate_only) } if (!validate_only) { - log_warn(LD_DIR, "Transport '%s' at %s:%d.", name, + log_info(LD_DIR, "Server transport '%s' at %s:%d.", name, fmt_addr(&addr), (int)port); } } @@ -5886,11 +5886,11 @@ save_transport_to_state(const char *transport, /* if transport in state has the same address as this one, life is good */ if (!strcmp(prev_bindaddr, transport_addrport)) { - log_warn(LD_CONFIG, "Transport seems to have spawned on its usual " + log_info(LD_CONFIG, "Transport seems to have spawned on its usual " "address:port."); goto done; } else { /* addrport in state is different than the one we got */ - log_warn(LD_CONFIG, "Transport seems to have spawned on different " + log_info(LD_CONFIG, "Transport seems to have spawned on different " "address:port. Let's update the state file with the new " "address:port"); tor_free(transport_line->value); /* free the old line */ @@ -5899,7 +5899,7 @@ save_transport_to_state(const char *transport, (int) port); /* replace old addrport line with new line */ } } else { /* never seen this one before; save it in state for next time */ - log_warn(LD_CONFIG, "It's the first time we see this transport. " + log_info(LD_CONFIG, "It's the first time we see this transport. " "Let's save its address:port"); next = &state->TransportProxies; /* find the last TransportProxy line in the state and point 'next' diff --git a/src/or/transports.c b/src/or/transports.c index a3abfed729..8fafcf4c4d 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -268,7 +268,8 @@ launch_managed_proxy(managed_proxy_t *mp) &stderr_pipe, (const char **)mp->argv, (const char **)envp); if (pid < 0) { - log_warn(LD_GENERAL, "Spawn failed"); + log_warn(LD_GENERAL, "Managed proxy at '%s' failed at launch.", + mp->argv[0]); return -1; } @@ -280,7 +281,7 @@ launch_managed_proxy(managed_proxy_t *mp) /* Open the buffered IO streams */ stdout_read = fdopen(stdout_pipe, "r"); - log_warn(LD_CONFIG, "The spawn is alive (%d)!", pid); + log_info(LD_CONFIG, "Managed proxy has spawned at PID %d.", pid); mp->conf_state = PT_PROTO_LAUNCHED; mp->stdout = stdout_read; @@ -295,8 +296,8 @@ launch_managed_proxy(managed_proxy_t *mp) void pt_configure_remaining_proxies(void) { - log_warn(LD_CONFIG, "We start configuring remaining managed proxies (%d)!", - unconfigured_proxies_n); + log_debug(LD_CONFIG, "Configuring remaining managed proxies (%d)!", + unconfigured_proxies_n); SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) { tor_assert(mp->conf_state != PT_PROTO_BROKEN); @@ -306,10 +307,12 @@ pt_configure_remaining_proxies(void) /* This proxy is marked by a SIGHUP. Check whether we need to restart it. */ if (proxy_needs_restart(mp)) { + log_info(LD_GENERAL, "Preparing managed proxy for restart."); proxy_prepare_for_restart(mp); continue; } else { /* it doesn't need to be restarted. */ - printf("No need for restart; status quo\n"); + log_info(LD_GENERAL, "Nothing changed for managed proxy after HUP: " + "not restarting."); unconfigured_proxies_n--; tor_assert(unconfigured_proxies_n >= 0); } @@ -349,11 +352,11 @@ configure_proxy(managed_proxy_t *mp) } else if (r == IO_STREAM_EAGAIN) { /* check back later */ return; } else if (r == IO_STREAM_CLOSED || r == IO_STREAM_TERM) { /* snap! */ - log_warn(LD_GENERAL, "Managed proxy stream closed. " - "Most probably application stopped running"); + log_notice(LD_GENERAL, "Managed proxy stream closed. " + "Most probably application stopped running"); mp->conf_state = PT_PROTO_BROKEN; } else { /* unknown stream status */ - log_warn(LD_GENERAL, "Unknown stream status while configuring proxy."); + log_notice(LD_GENERAL, "Unknown stream status while configuring proxy."); } /* if the proxy finished configuring, exit the loop. */ @@ -398,15 +401,15 @@ register_client_proxy(managed_proxy_t *mp) r = transport_add(t); switch (r) { case -1: - log_warn(LD_GENERAL, "Could not add transport %s. Skipping.", t->name); + log_notice(LD_GENERAL, "Could not add transport %s. Skipping.", t->name); transport_free(t); break; case 0: - log_warn(LD_GENERAL, "Succesfully registered transport %s", t->name); + log_info(LD_GENERAL, "Succesfully registered transport %s", t->name); smartlist_add(sm_tmp, tor_strdup(t->name)); break; case 1: - log_warn(LD_GENERAL, "Succesfully registered transport %s", t->name); + log_info(LD_GENERAL, "Succesfully registered transport %s", t->name); smartlist_add(sm_tmp, tor_strdup(t->name)); transport_free(t); break; @@ -431,7 +434,6 @@ register_proxy(managed_proxy_t *mp) static void managed_proxy_destroy(managed_proxy_t *mp) { - printf("Destroying mp %p\n", mp); if (mp->conf_state != PT_PROTO_COMPLETED) SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); else @@ -503,10 +505,10 @@ handle_methods_done(const managed_proxy_t *mp) tor_assert(mp->transports); if (smartlist_len(mp->transports) == 0) - log_warn(LD_GENERAL, "Proxy was spawned successfully, " - "but it didn't laucn any pluggable transport listeners!"); + log_notice(LD_GENERAL, "Proxy was spawned successfully, " + "but it didn't laucn any pluggable transport listeners!"); - log_warn(LD_CONFIG, "%s managed proxy configuration completed!", + log_info(LD_CONFIG, "%s managed proxy configuration completed!", mp->is_server ? "Server" : "Client"); } @@ -515,7 +517,7 @@ handle_methods_done(const managed_proxy_t *mp) void handle_proxy_line(const char *line, managed_proxy_t *mp) { - printf("Judging line: %s\n", line); + log_debug(LD_GENERAL, "Got a line from managed proxy: %s\n", line); if (strlen(line) < SMALLEST_MANAGED_LINE_SIZE) { log_warn(LD_GENERAL, "Managed proxy configuration line is too small. " @@ -609,8 +611,8 @@ parse_env_error(const char *line) /* (Length of the protocol string) plus (a space) and (the first char of the error message) */ if (strlen(line) < (strlen(PROTO_ENV_ERROR) + 2)) - log_warn(LD_CONFIG, "Managed proxy sent us an %s without an error " - "message.", PROTO_ENV_ERROR); + log_notice(LD_CONFIG, "Managed proxy sent us an %s without an error " + "message.", PROTO_ENV_ERROR); log_warn(LD_CONFIG, "Managed proxy couldn't understand the " "pluggable transport environment variables. (%s)", @@ -628,8 +630,8 @@ parse_version(const char *line, managed_proxy_t *mp) return -1; } - if (strcmp("1", line+strlen(PROTO_NEG_SUCCESS)+1)) { - log_warn(LD_CONFIG, "We don't support version '%s'. " + if (strcmp("1", line+strlen(PROTO_NEG_SUCCESS)+1)) { /* hardcoded temp */ + log_warn(LD_CONFIG, "Managed proxy tried to negotiate on version '%s'. " "We only support version '1'", line+strlen(PROTO_NEG_SUCCESS)+1); return -1; } @@ -713,7 +715,7 @@ parse_smethod_line(const char *line, managed_proxy_t *mp) /* For now, notify the user so that he knows where the server transport is listening. */ - log_warn(LD_CONFIG, "Server transport %s at %s:%d.", + log_info(LD_CONFIG, "Server transport %s at %s:%d.", method_name, fmt_addr(&addr), (int)port); r=0; @@ -796,7 +798,7 @@ parse_cmethod_line(const char *line, managed_proxy_t *mp) smartlist_add(mp->transports, transport); - log_warn(LD_CONFIG, "Transport %s at %s:%d with SOCKS %d. " + log_info(LD_CONFIG, "Transport %s at %s:%d with SOCKS %d. " "Attached to managed proxy.", method_name, fmt_addr(&addr), (int)port, socks_ver); From e2703e36545babce19cd248299a5a12cdd11dff2 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 23 Sep 2011 17:50:56 +0200 Subject: [PATCH 33/36] Improve wording in some comments and log messages. --- src/or/circuitbuild.c | 10 +++--- src/or/config.c | 6 ++-- src/or/transports.c | 79 +++++++++++++++++++++++-------------------- 3 files changed, 51 insertions(+), 44 deletions(-) diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 86154bac2e..ddd7931e68 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -4675,7 +4675,8 @@ transport_resolve_conflicts(transport_t *t) we either have duplicate torrc lines OR we are here post-HUP and this transport was here pre-HUP as well. In any case, mark the old transport so that it doesn't get removed and ignore the new - one. + one. Our caller has to free the new transport so we return '1' to + signify this. If there is already a transport with the same name but different addrport: @@ -4703,8 +4704,8 @@ transport_resolve_conflicts(transport_t *t) transport_free(t_tmp); } else { /* *not* marked for removal */ log_notice(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' " - "which already exists at '%s:%u'. Skipping.", t->name, - fmt_addr(&t->addr), t->port, + "but the same transport already exists at '%s:%u'. " + "Skipping.", t->name, fmt_addr(&t->addr), t->port, fmt_addr(&t_tmp->addr), t_tmp->port); return -1; } @@ -4731,10 +4732,9 @@ transport_add(transport_t *t) case 0: /* should register transport */ if (!transport_list) transport_list = smartlist_create(); - smartlist_add(transport_list, t); return 0; - default: /* should let the caller know the return code */ + default: /* let our caller know the return code */ return r; } } diff --git a/src/or/config.c b/src/or/config.c index 3d83b99e70..95017b349c 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -5879,8 +5879,8 @@ save_transport_to_state(const char *transport, config_line_t *transport_line = get_transport_in_state_by_name(transport); - if (transport_line) { /* if transport_exists_in_state() */ - const char *prev_bindaddr = /* get addrport stored in state */ + if (transport_line) { /* if transport already exists in state... */ + const char *prev_bindaddr = /* get its addrport... */ get_transport_bindaddr(transport_line->value, transport); tor_asprintf(&transport_addrport, "%s:%d", fmt_addr(addr), (int)port); @@ -5889,7 +5889,7 @@ save_transport_to_state(const char *transport, log_info(LD_CONFIG, "Transport seems to have spawned on its usual " "address:port."); goto done; - } else { /* addrport in state is different than the one we got */ + } else { /* if addrport in state is different than the one we got */ log_info(LD_CONFIG, "Transport seems to have spawned on different " "address:port. Let's update the state file with the new " "address:port"); diff --git a/src/or/transports.c b/src/or/transports.c index 8fafcf4c4d..c67fc68a0e 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -106,30 +106,32 @@ static int unconfigured_proxies_n = 0; immediately after tor is launched.). We mark all managed proxies and transports to signify that they - must be removed if they don't contribute by the new torrc. We also - mark all managed proxies to signify that they might need to be - restarted so that they end up supporting all the transports the - new torrc wants them to support. - We also clear the 'transports_to_launch' list so that we can put - there the transports we need to launch on each proxy according to - the new torrc. + must be removed if they don't contribute by the new torrc + (marked_for_removal). + We also mark all managed proxies to signify that they might need + to be restarted so that they end up supporting all the transports + the new torrc wants them to support (got_hup). + We also clear their 'transports_to_launch' list so that we can put + there the transports we need to launch according to the new torrc. - We then start parsing torrc again, everytime we encounter a - transport line using a known pre-SIGHUP managed proxy, we cleanse - that proxy from the removal mark. + We then start parsing torrc again. + + Everytime we encounter a transport line using a known pre-SIGHUP + managed proxy, we cleanse that proxy from the removal mark. We also mark it as unconfigured so that on the next scheduled events tick, we investigate whether we need to restart the proxy - so that it spawns the new 'transport_to_launch' list. Of course, - if the post-SIGHUP 'transports_to_launch' list is identical to the + so that it also spawns the new transports. + If the post-SIGHUP 'transports_to_launch' list is identical to the pre-SIGHUP one, it means that no changes were introduced to this proxy during the SIGHUP and no restart has to take place. - During the post-SIGHUP torrc parsing, we unmark all transports we - encounter. This happens in the case that no restart is needed, we - can continue using the old transports normally. If we end up - restarting the proxy, we destroy and unregister all old transports - from the circuitbuild.c subsystem since they become useless. + During the post-SIGHUP torrc parsing, we unmark all transports + spawned by managed proxies that we find in our torrc. + We do that so that if we don't need to restart a managed proxy, we + can continue using its old transports normally. + If we end up restarting the proxy, we destroy and unregister all + old transports from the circuitbuild.c subsystem. */ /** Return true if there are still unconfigured managed proxies. */ @@ -186,18 +188,16 @@ add_transport_to_proxy(const char *transport, managed_proxy_t *mp) smartlist_add(mp->transports_to_launch, tor_strdup(transport)); } -/** Called when a SIGHUP occurs. - * Returns true if managed proxy mp needs to be restarted - * after the SIGHUP based on the new torrc. */ +/** Called when a SIGHUP occurs. Returns true if managed proxy + * mp needs to be restarted after the SIGHUP, based on the new + * torrc. */ static int proxy_needs_restart(const managed_proxy_t *mp) { /* mp->transport_to_launch is populated with the names of the transports that must be launched *after* the SIGHUP. - - Since only PT_PROTO_COMPLETED proxies reach this function, - mp->transports is populated with strings of the *names of the - transports* that were launched *before* the SIGHUP. + mp->transports is populated with the names of the transports that + were launched *before* the SIGHUP. If the two lists contain the same strings, we don't need to restart the proxy, since it already does what we want. */ @@ -221,7 +221,7 @@ proxy_needs_restart(const managed_proxy_t *mp) } /** Managed proxy mp must be restarted. Do all the necessary - * preparations and then flag its state so that it will be launched + * preparations and then flag its state so that it will be relaunched * in the next tick. */ static void proxy_prepare_for_restart(managed_proxy_t *mp) @@ -371,6 +371,9 @@ configure_proxy(managed_proxy_t *mp) static void register_server_proxy(managed_proxy_t *mp) { + /* After we register this proxy's transports, we switch its + mp->transports to a list containing strings of its transport + names. (See transports.h) */ smartlist_t *sm_tmp = smartlist_create(); tor_assert(mp->conf_state != PT_PROTO_COMPLETED); @@ -394,6 +397,9 @@ static void register_client_proxy(managed_proxy_t *mp) { int r; + /* After we register this proxy's transports, we switch its + mp->transports to a list containing strings of its transport + names. (See transports.h) */ smartlist_t *sm_tmp = smartlist_create(); tor_assert(mp->conf_state != PT_PROTO_COMPLETED); @@ -442,9 +448,8 @@ managed_proxy_destroy(managed_proxy_t *mp) /* free the transports smartlist */ smartlist_free(mp->transports); + /* free the transports_to_launch smartlist */ SMARTLIST_FOREACH(mp->transports_to_launch, char *, t, tor_free(t)); - - /* free the transports smartlist */ smartlist_free(mp->transports_to_launch); /* remove it from the list of managed proxies */ @@ -472,8 +477,8 @@ handle_finished_proxy(managed_proxy_t *mp) managed_proxy_destroy(mp); /* annihilate it. */ break; case PT_PROTO_CONFIGURED: /* if configured correctly: */ - register_proxy(mp); /* register transports */ - mp->conf_state = PT_PROTO_COMPLETED; /* mark it as completed. */ + register_proxy(mp); /* register its transports */ + mp->conf_state = PT_PROTO_COMPLETED; /* and mark it as completed. */ break; case PT_PROTO_INFANT: case PT_PROTO_LAUNCHED: @@ -944,7 +949,7 @@ pt_kickstart_proxy(const char *transport, char **proxy_argv, int is_server) } /** Frees the array of pointers in arg used as arguments to - execve. */ + execve(2). */ static INLINE void free_execve_args(char **arg) { @@ -956,9 +961,10 @@ free_execve_args(char **arg) tor_free(arg); } -/** Tor will read its config, prepare the managed proxy list so that - * proxies that are not used in the new config will shutdown, and - * proxies that need to spawn more transports will do so. */ +/** Tor will read its config. + * Prepare the managed proxy list so that proxies not used in the new + * config will shutdown, and proxies that need to spawn different + * transports will do so. */ void pt_prepare_proxy_list_for_config_read(void) { @@ -984,9 +990,10 @@ pt_prepare_proxy_list_for_config_read(void) tor_assert(unconfigured_proxies_n == 0); } -/** The tor config was read, destroy all managed proxies that were - * marked by a previous call to prepare_proxy_list_for_config_read() - * and are not used by the new config. */ +/** The tor config was read. + * Destroy all managed proxies that were marked by a previous call to + * prepare_proxy_list_for_config_read() and are not used by the new + * config. */ void sweep_proxy_list(void) { From 105cc42e96ea979b1111f3ba0d410c510cd229f0 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 7 Oct 2011 14:13:41 +0200 Subject: [PATCH 34/36] Support multiple transports in a single transport line. Support multiple comma-separated transpotrs in a single {Client,Server}TransportPlugin line. --- src/or/config.c | 78 ++++++++++++++++++++++++++++++++++----------- src/or/transports.c | 22 ++++++++----- src/or/transports.h | 10 +++--- 3 files changed, 78 insertions(+), 32 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index 95017b349c..536324d0ba 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -4693,7 +4693,8 @@ parse_client_transport_line(const char *line, int validate_only) int r; char *field2=NULL; - const char *name=NULL; + const char *transports=NULL; + smartlist_t *transport_list=NULL; char *addrport=NULL; tor_addr_t addr; uint16_t port = 0; @@ -4717,11 +4718,20 @@ parse_client_transport_line(const char *line, int validate_only) goto err; } - name = smartlist_get(items, 0); - if (!string_is_C_identifier(name)) { - log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).", name); - goto err; - } + /* Get the first line element, split it to commas into + transport_list (in case it's multiple transports) and validate + the transport names. */ + transports = smartlist_get(items, 0); + transport_list = smartlist_create(); + smartlist_split_string(transport_list, transports, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport_name) { + if (!string_is_C_identifier(transport_name)) { + log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).", + transport_name); + goto err; + } + } SMARTLIST_FOREACH_END(transport_name); /* field2 is either a SOCKS version or "exec" */ field2 = smartlist_get(items, 1); @@ -4753,9 +4763,15 @@ parse_client_transport_line(const char *line, int validate_only) *tmp = NULL; /*terminated with NUL pointer, just like execve() likes it*/ /* kickstart the thing */ - pt_kickstart_client_proxy(name, proxy_argv); + pt_kickstart_client_proxy(transport_list, proxy_argv); } } else { /* external */ + if (smartlist_len(transport_list) != 1) { + log_warn(LD_CONFIG, "You can't have an external proxy with " + "more than one transports."); + goto err; + } + addrport = smartlist_get(items, 2); if (tor_addr_port_parse(addrport, &addr, &port)<0) { @@ -4770,10 +4786,11 @@ parse_client_transport_line(const char *line, int validate_only) } if (!validate_only) { - transport_add_from_config(&addr, port, name, socks_ver); + transport_add_from_config(&addr, port, smartlist_get(transport_list, 0), + socks_ver); - log_info(LD_DIR, "Transport '%s' found at %s:%d", name, - fmt_addr(&addr), (int)port); + log_info(LD_DIR, "Transport '%s' found at %s:%d", + transports, fmt_addr(&addr), (int)port); } } @@ -4786,6 +4803,9 @@ parse_client_transport_line(const char *line, int validate_only) done: SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); + SMARTLIST_FOREACH(transport_list, char*, s, tor_free(s)); + smartlist_free(transport_list); + return r; } @@ -4799,7 +4819,8 @@ parse_server_transport_line(const char *line, int validate_only) { smartlist_t *items = NULL; int r; - const char *name=NULL; + const char *transports=NULL; + smartlist_t *transport_list=NULL; char *type=NULL; char *addrport=NULL; tor_addr_t addr; @@ -4823,11 +4844,20 @@ parse_server_transport_line(const char *line, int validate_only) goto err; } - name = smartlist_get(items, 0); - if (!string_is_C_identifier(name)) { - log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).", name); - goto err; - } + /* Get the first line element, split it to commas into + transport_list (in case it's multiple transports) and validate + the transport names. */ + transports = smartlist_get(items, 0); + transport_list = smartlist_create(); + smartlist_split_string(transport_list, transports, ",", + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport_name) { + if (!string_is_C_identifier(transport_name)) { + log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).", + transport_name); + goto err; + } + } SMARTLIST_FOREACH_END(transport_name); type = smartlist_get(items, 1); @@ -4854,9 +4884,15 @@ parse_server_transport_line(const char *line, int validate_only) *tmp = NULL; /*terminated with NUL pointer, just like execve() likes it*/ /* kickstart the thing */ - pt_kickstart_server_proxy(name, proxy_argv); + pt_kickstart_server_proxy(transport_list, proxy_argv); } } else { /* external */ + if (smartlist_len(transport_list) != 1) { + log_warn(LD_CONFIG, "You can't have an external proxy with " + "more than one transports."); + goto err; + } + addrport = smartlist_get(items, 2); if (tor_addr_port_parse(addrport, &addr, &port)<0) { @@ -4871,8 +4907,8 @@ parse_server_transport_line(const char *line, int validate_only) } if (!validate_only) { - log_info(LD_DIR, "Server transport '%s' at %s:%d.", name, - fmt_addr(&addr), (int)port); + log_info(LD_DIR, "Server transport '%s' at %s:%d.", + transports, fmt_addr(&addr), (int)port); } } @@ -4885,6 +4921,9 @@ parse_server_transport_line(const char *line, int validate_only) done: SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); + SMARTLIST_FOREACH(transport_list, char*, s, tor_free(s)); + smartlist_free(transport_list); + return r; } @@ -5993,3 +6032,4 @@ getinfo_helper_config(control_connection_t *conn, } return 0; } + diff --git a/src/or/transports.c b/src/or/transports.c index c67fc68a0e..465b8e1bc2 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -890,7 +890,8 @@ set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp) * proxy_argv. If is_server is true, it's a server * managed proxy. */ static managed_proxy_t * -managed_proxy_create(const char *transport, char **proxy_argv, int is_server) +managed_proxy_create(const smartlist_t *transport_list, + char **proxy_argv, int is_server) { managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t)); mp->conf_state = PT_PROTO_INFANT; @@ -899,7 +900,8 @@ managed_proxy_create(const char *transport, char **proxy_argv, int is_server) mp->transports = smartlist_create(); mp->transports_to_launch = smartlist_create(); - add_transport_to_proxy(transport, mp); + SMARTLIST_FOREACH(transport_list, const char *, transport, + add_transport_to_proxy(transport, mp)); /* register the managed proxy */ if (!managed_proxy_list) @@ -914,7 +916,8 @@ managed_proxy_create(const char *transport, char **proxy_argv, int is_server) * the managed proxy subsystem. * If is_server is true, then the proxy is a server proxy. */ void -pt_kickstart_proxy(const char *transport, char **proxy_argv, int is_server) +pt_kickstart_proxy(const smartlist_t *transport_list, + char **proxy_argv, int is_server) { managed_proxy_t *mp=NULL; transport_t *old_transport = NULL; @@ -922,7 +925,7 @@ pt_kickstart_proxy(const char *transport, char **proxy_argv, int is_server) mp = get_managed_proxy_by_argv_and_type(proxy_argv, is_server); if (!mp) { /* we haven't seen this proxy before */ - managed_proxy_create(transport, proxy_argv, is_server); + managed_proxy_create(transport_list, proxy_argv, is_server); } else { /* known proxy. add its transport to its transport list */ if (mp->got_hup) { @@ -938,12 +941,15 @@ pt_kickstart_proxy(const char *transport, char **proxy_argv, int is_server) unconfigured_proxies_n++; } - old_transport = transport_get_by_name(transport); - if (old_transport) - old_transport->marked_for_removal = 0; + SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport) { + old_transport = transport_get_by_name(transport); + if (old_transport) + old_transport->marked_for_removal = 0; + } SMARTLIST_FOREACH_END(transport); } - add_transport_to_proxy(transport, mp); + SMARTLIST_FOREACH(transport_list, const char *, transport, + add_transport_to_proxy(transport, mp)); free_execve_args(proxy_argv); } } diff --git a/src/or/transports.h b/src/or/transports.h index 57bfb5ca17..0b5cd5f44e 100644 --- a/src/or/transports.h +++ b/src/or/transports.h @@ -11,13 +11,13 @@ #ifndef TOR_TRANSPORTS_H #define TOR_TRANSPORTS_H -void pt_kickstart_proxy(const char *method, char **proxy_argv, +void pt_kickstart_proxy(const smartlist_t *transport_list, char **proxy_argv, int is_server); -#define pt_kickstart_client_proxy(m, pa) \ - pt_kickstart_proxy(m, pa, 0) -#define pt_kickstart_server_proxy(m, pa) \ - pt_kickstart_proxy(m, pa, 1) +#define pt_kickstart_client_proxy(tl, pa) \ + pt_kickstart_proxy(tl, pa, 0) +#define pt_kickstart_server_proxy(tl, pa) \ + pt_kickstart_proxy(tl, pa, 1) void pt_configure_remaining_proxies(void); From 3be9d76fa2e56a9715e8151d9b6802da5b38512a Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 7 Oct 2011 15:44:44 +0200 Subject: [PATCH 35/36] =?UTF-8?q?Make=20it=20compile=20on=20Windows?= =?UTF-8?q?=E2=84=A2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/util.c | 8 +++----- src/or/transports.c | 20 ++++++++++++++------ src/or/transports.h | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/common/util.c b/src/common/util.c index 4a66e93537..a0777eae3d 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -2966,20 +2966,18 @@ int tor_terminate_process(pid_t pid) { #ifdef MS_WINDOWS - DWORD pid_win = pid; - DWORD err; HANDLE handle; /* If the signal is outside of what GenerateConsoleCtrlEvent can use, attempt to open and terminate the process. */ handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - if (handle == NULL) + if (!handle) return -1; - if (TerminateProcess(handle, sig) == 0) + if (!TerminateProcess(handle, 0)) return -1; else return 0; -#else /* *nix */ +#else /* Unix */ return kill(pid, SIGTERM); #endif } diff --git a/src/or/transports.c b/src/or/transports.c index 465b8e1bc2..c531fe70b4 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -234,7 +234,7 @@ proxy_prepare_for_restart(managed_proxy_t *mp) /* kill the old obfsproxy process */ tor_terminate_process(mp->pid); mp->pid = 0; - fclose(mp->stdout); + fclose(mp->_stdout); /* destroy all its old transports. we no longer use them. */ SMARTLIST_FOREACH_BEGIN(mp->transports, const char *, t_name) { @@ -277,14 +277,22 @@ launch_managed_proxy(managed_proxy_t *mp) free_execve_args(envp); /* Set stdout/stderr pipes to be non-blocking */ - fcntl(stdout_pipe, F_SETFL, O_NONBLOCK); +#ifdef _WIN32 + { + u_long nonblocking = 1; + ioctlsocket(stdout_pipe, FIONBIO, &nonblocking); + } +#else + fcntl(stdout_pipe, F_SETFL, O_NONBLOCK); +#endif + /* Open the buffered IO streams */ stdout_read = fdopen(stdout_pipe, "r"); log_info(LD_CONFIG, "Managed proxy has spawned at PID %d.", pid); mp->conf_state = PT_PROTO_LAUNCHED; - mp->stdout = stdout_read; + mp->_stdout = stdout_read; mp->pid = pid; return 0; @@ -344,7 +352,7 @@ configure_proxy(managed_proxy_t *mp) tor_assert(mp->conf_state != PT_PROTO_INFANT); while (1) { - r = get_string_from_pipe(mp->stdout, stdout_buf, + r = get_string_from_pipe(mp->_stdout, stdout_buf, sizeof(stdout_buf) - 1); if (r == IO_STREAM_OKAY) { /* got a line; handle it! */ @@ -456,8 +464,8 @@ managed_proxy_destroy(managed_proxy_t *mp) smartlist_remove(managed_proxy_list, mp); /* close its stdout stream */ - if (mp->stdout) - fclose(mp->stdout); + if (mp->_stdout) + fclose(mp->_stdout); /* free the argv */ free_execve_args(mp->argv); diff --git a/src/or/transports.h b/src/or/transports.h index 0b5cd5f44e..4a93387596 100644 --- a/src/or/transports.h +++ b/src/or/transports.h @@ -47,7 +47,7 @@ typedef struct { int is_server; /* is it a server proxy? */ - FILE *stdout; /* a stream to its stdout + FILE *_stdout; /* a stream to its stdout (closed in managed_proxy_destroy()) */ int pid; /* The Process ID this managed proxy is using. */ From 1174bb95ce79767cfaee4f50ce70f42e7eb01b2e Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 7 Oct 2011 15:44:58 +0200 Subject: [PATCH 36/36] Revive our beautiful unit tests. They broke when the PT_PROTO_INFANT proxy state was added. --- src/test/test_pt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/test_pt.c b/src/test/test_pt.c index 99fc5145e0..f97b21fa0d 100644 --- a/src/test/test_pt.c +++ b/src/test/test_pt.c @@ -13,11 +13,9 @@ static void reset_mp(managed_proxy_t *mp) { - mp->conf_state = PT_PROTO_INFANT; + mp->conf_state = PT_PROTO_LAUNCHED; SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); smartlist_clear(mp->transports); - smartlist_free(mp->transports); - mp->transports = smartlist_create(); } static void @@ -94,7 +92,7 @@ test_pt_protocol(void) char line[200]; managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t)); - mp->conf_state = PT_PROTO_INFANT; + mp->conf_state = PT_PROTO_LAUNCHED; mp->transports = smartlist_create(); /* various wrong protocol runs: */