diff --git a/src/or/config.c b/src/or/config.c index 7f789c4..6a748de 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -695,17 +695,17 @@ static int options_act_reversible(const or_options_t *old_options, char **msg); static int options_transition_allowed(const or_options_t *old, const or_options_t *new, char **msg); static int options_transition_affects_workers( const or_options_t *old_options, const or_options_t *new_options); static int options_transition_affects_descriptor( const or_options_t *old_options, const or_options_t *new_options); static int check_nickname_list(char **lst, const char *name, char **msg); -static char *get_bindaddr_from_transport_listen_line(const char *line, +static smartlist_t *get_bindaddr_from_transport_listen_line(const char *line, const char *transport); static int parse_ports(or_options_t *options, int validate_only, char **msg_out, int *n_ports_out, int *world_writable_control_socket); static int check_server_ports(const smartlist_t *ports, const or_options_t *options, int *num_low_ports_out); @@ -3944,20 +3944,21 @@ options_validate(or_options_t *old_options, or_options_t *options, "line will be ignored.", escaped(options->ServerTransportPlugin->value)); } for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) { /** If get_bindaddr_from_transport_listen_line() fails with 'transport' being NULL, it means that something went wrong while parsing the ServerTransportListenAddr line. */ - char *bindaddr = get_bindaddr_from_transport_listen_line(cl->value, NULL); - if (!bindaddr) + smartlist_t *bindaddr_list = get_bindaddr_from_transport_listen_line(cl->value, NULL); + if (!bindaddr_list) REJECT("ServerTransportListenAddr did not parse. See logs for details."); - tor_free(bindaddr); + SMARTLIST_FOREACH(bindaddr_list, char*, s, tor_free(s)); + smartlist_free(bindaddr_list); } if (options->ServerTransportListenAddr && !options->ServerTransportPlugin) { log_notice(LD_GENERAL, "You need at least a single managed-proxy to " "specify a transport listen address. The " "ServerTransportListenAddr line will be ignored."); } @@ -5854,59 +5855,70 @@ parse_transport_line(const or_options_t *options, * string. Return NULL if the line was not * well-formed. * * If transport is set, return NULL if the line is not * referring to transport. * * The returned string is allocated on the heap and it's the * responsibility of the caller to free it. */ -static char * +static smartlist_t * get_bindaddr_from_transport_listen_line(const char *line,const char *transport) { smartlist_t *items = NULL; + smartlist_t *bindaddr_list = NULL; const char *parsed_transport = NULL; char *addrport = NULL; tor_addr_t addr; uint16_t port = 0; + int ap; items = smartlist_new(); smartlist_split_string(items, line, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); if (smartlist_len(items) < 2) { log_warn(LD_CONFIG,"Too few arguments on ServerTransportListenAddr line."); goto err; } parsed_transport = smartlist_get(items, 0); - addrport = tor_strdup(smartlist_get(items, 1)); - /* If 'transport' is given, check if it matches the one on the line */ if (transport && strcmp(transport, parsed_transport)) goto err; - /* Validate addrport */ - if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port, -1)<0) { - log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr " - "address '%s'", addrport); - goto err; + bindaddr_list = smartlist_new(); + for (ap = 1; ap < smartlist_len(items); ++ap) { + addrport = tor_strdup(smartlist_get(items, ap)); + /* Validate addrport */ + if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port, -1)<0) { + log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr " + "address '%s'", addrport); + SMARTLIST_FOREACH(bindaddr_list, char*, s, tor_free(s)); + smartlist_free(bindaddr_list); + bindaddr_list = NULL; + goto err; + } + smartlist_add_strdup(bindaddr_list, addrport); + tor_free(addrport); + addrport = NULL; } goto done; err: - tor_free(addrport); + if (addrport) + tor_free(addrport); addrport = NULL; done: SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); - return addrport; + return bindaddr_list; } /** Given a ServerTransportOptions line, return a smartlist * with the options. Return NULL if the line was not well-formed. * * If transport is set, return NULL if the line is not * referring to transport. * @@ -5960,27 +5972,27 @@ get_options_from_transport_options_line(const char *line,const char *transport) return options; } /** Given the name of a pluggable transport in transport, check * the configuration file to see if the user has explicitly asked for * it to listen on a specific port. Return a string if * so, otherwise NULL. */ -char * +smartlist_t * get_transport_bindaddr_from_config(const char *transport) { config_line_t *cl; const or_options_t *options = get_options(); for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) { - char *bindaddr = + smartlist_t *bindaddr_list = get_bindaddr_from_transport_listen_line(cl->value, transport); - if (bindaddr) - return bindaddr; + if (bindaddr_list) + return bindaddr_list; } return NULL; } /** Given the name of a pluggable transport in transport, check * the configuration file to see if the user has asked us to pass any * parameters to the pluggable transport. Return a smartlist diff --git a/src/or/config.h b/src/or/config.h index 6645532..b574080 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -107,17 +107,17 @@ smartlist_t *get_list_of_ports_to_forward(void); int getinfo_helper_config(control_connection_t *conn, const char *question, char **answer, const char **errmsg); uint32_t get_effective_bwrate(const or_options_t *options); uint32_t get_effective_bwburst(const or_options_t *options); -char *get_transport_bindaddr_from_config(const char *transport); +smartlist_t *get_transport_bindaddr_from_config(const char *transport); int init_cookie_authentication(const char *fname, const char *header, int cookie_len, int group_readable, uint8_t **cookie_out, int *cookie_is_set_out); or_options_t *options_new(void); int config_parse_commandline(int argc, char **argv, int ignore_errors, diff --git a/src/or/statefile.c b/src/or/statefile.c index a95ba85..e2db29a 100644 --- a/src/or/statefile.c +++ b/src/or/statefile.c @@ -174,17 +174,17 @@ state_transport_line_is_valid(const char *line) tor_addr_t addr; uint16_t port = 0; int r; items = smartlist_new(); smartlist_split_string(items, line, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); - if (smartlist_len(items) != 2) { + 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_lookup(addrport, &addr, &port) < 0) { log_warn(LD_CONFIG, "state: Could not parse addrport."); goto err; @@ -519,17 +519,17 @@ get_transport_in_state_by_name(const char *transport) smartlist_t *items = NULL; for (line = or_state->TransportProxies ; line ; line = line->next) { tor_assert(!strcmp(line->key, "TransportProxy")); items = smartlist_new(); smartlist_split_string(items, line->value, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); - if (smartlist_len(items) != 2) /* broken state */ + 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)); @@ -569,108 +569,113 @@ get_transport_bindaddr(const char *line, const char *transport) broken_state: tor_free(line_tmp); return NULL; } /** Return a string containing the address:port that a proxy transport * should bind on. The string is stored on the heap and must be freed * by the caller of this function. */ -char * +smartlist_t * get_stored_bindaddr_for_server_transport(const char *transport) { char *default_addrport = NULL; const char *stored_bindaddr = NULL; config_line_t *line = NULL; + smartlist_t *ret = NULL; { /* See if the user explicitly asked for a specific listening address for this transport. */ - char *conf_bindaddr = get_transport_bindaddr_from_config(transport); - if (conf_bindaddr) - return conf_bindaddr; + smartlist_t *conf_binaddr_list = get_transport_bindaddr_from_config(transport); + if (conf_binaddr_list) + return conf_binaddr_list; } line = get_transport_in_state_by_name(transport); if (!line) /* Found no references in state for this transport. */ goto no_bindaddr_found; stored_bindaddr = get_transport_bindaddr(line->value, transport); - if (stored_bindaddr) /* found stored bindaddr in state file. */ - return tor_strdup(stored_bindaddr); + if (stored_bindaddr) { /* found stored bindaddr in state file. */ + ret = smartlist_new(); + smartlist_split_string(ret, stored_bindaddr, NULL, + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); + return ret; + } no_bindaddr_found: /** If we didn't find references for this pluggable transport in the state file, we should instruct the pluggable transport proxy to listen on INADDR_ANY on a random ephemeral port. */ + ret = smartlist_new(); tor_asprintf(&default_addrport, "%s:%s", fmt_addr32(INADDR_ANY), "0"); - return default_addrport; + smartlist_add(ret, default_addrport); + return ret; } /** Save transport listening on addr:port to state */ void save_transport_to_state(const char *transport, - const tor_addr_t *addr, uint16_t port) + /*const tor_addr_t *addr, uint16_t port*/ + const char *bind_addresses) { 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 already exists in state... */ const char *prev_bindaddr = /* get its addrport... */ get_transport_bindaddr(transport_line->value, transport); - transport_addrport = tor_strdup(fmt_addrport(addr, port)); /* if transport in state has the same address as this one, life is good */ - if (!strcmp(prev_bindaddr, transport_addrport)) { + if (!strcmp(prev_bindaddr, bind_addresses)) { log_info(LD_CONFIG, "Transport seems to have spawned on its usual " "address:port."); goto done; } 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"); tor_free(transport_line->value); /* free the old line */ /* replace old addrport line with new line */ tor_asprintf(&transport_line->value, "%s %s", transport, - fmt_addrport(addr, port)); + bind_addresses); } } else { /* never seen this one before; save it in state for next time */ 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' 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", transport, fmt_addrport(addr, port)); + tor_asprintf(&line->value, "%s %s", transport, bind_addresses); next = &(line->next); } if (!get_options()->AvoidDiskWrites) or_state_mark_dirty(state, 0); done: - tor_free(transport_addrport); + return; } STATIC void or_state_free(or_state_t *state) { if (!state) return; diff --git a/src/or/statefile.h b/src/or/statefile.h index b137434..f4a9e03 100644 --- a/src/or/statefile.h +++ b/src/or/statefile.h @@ -7,18 +7,19 @@ #ifndef TOR_STATEFILE_H #define TOR_STATEFILE_H MOCK_DECL(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, - const tor_addr_t *addr, uint16_t port); -char *get_stored_bindaddr_for_server_transport(const char *transport); + /*const tor_addr_t *addr, uint16_t port*/ + const char *bind_addresses); +smartlist_t *get_stored_bindaddr_for_server_transport(const char *transport); int or_state_load(void); int or_state_loaded(void); void or_state_free_all(void); #ifdef STATEFILE_PRIVATE STATIC config_line_t *get_transport_in_state_by_name(const char *transport); STATIC void or_state_free(or_state_t *state); STATIC or_state_t *or_state_new(void); diff --git a/src/or/transports.c b/src/or/transports.c index feeff6e..afee05e 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -667,24 +667,53 @@ configure_proxy(managed_proxy_t *mp) return configuration_finished; } /** Register server managed proxy mp transports to state */ static void register_server_proxy(const managed_proxy_t *mp) { + char *ap; /* ap means address:port */ + smartlist_t *ap_list; + strmap_t *transport_to_ap_list = strmap_new(); + 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); log_notice(LD_GENERAL, "Registered server transport '%s' at '%s'", t->name, fmt_addrport(&t->addr, t->port)); control_event_transport_launched("server", t->name, &t->addr, t->port); + + ap = tor_strdup(fmt_addrport(&t->addr, t->port)); + + ap_list = strmap_get(transport_to_ap_list, t->name); + if (!ap_list) { + ap_list = smartlist_new(); + strmap_set(transport_to_ap_list, t->name, ap_list); + } + smartlist_add(ap_list, ap); } SMARTLIST_FOREACH_END(t); + + STRMAP_FOREACH(transport_to_ap_list, t_name, smartlist_t *, t_ap_list) { + char *all_ap; + + tor_assert(smartlist_len(t_ap_list) != 0); + smartlist_sort_strings(t_ap_list); + all_ap = smartlist_join_strings(t_ap_list, " ", 0, NULL); + + save_transport_to_state(t_name, all_ap); + tor_free(all_ap); + all_ap = NULL; + + SMARTLIST_FOREACH(t_ap_list, char*, s, tor_free(s)); + smartlist_free(t_ap_list); + } STRMAP_FOREACH_END; + + strmap_free(transport_to_ap_list, NULL); } /** Register all the transports supported by client managed proxy * mp to the bridge subsystem. */ static void register_client_proxy(const managed_proxy_t *mp) { int r; @@ -1271,25 +1300,27 @@ get_transport_options_for_server_proxy(const managed_proxy_t *mp) /** Return the string that tor should place in TOR_PT_SERVER_BINDADDR * while configuring the server managed proxy in mp. The * string is stored in the heap, and it's the responsibility of * the caller to deallocate it after its use. */ static char * get_bindaddr_for_server_proxy(const managed_proxy_t *mp) { char *bindaddr_result = NULL; - char *bindaddr_tmp = NULL; + smartlist_t *bindaddr_tmp = NULL; smartlist_t *string_tmp = smartlist_new(); tor_assert(mp->is_server); SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, char *, t) { bindaddr_tmp = get_stored_bindaddr_for_server_transport(t); - smartlist_add_asprintf(string_tmp, "%s-%s", t, bindaddr_tmp); + SMARTLIST_FOREACH_BEGIN(bindaddr_tmp, char *, a_addrport) { + smartlist_add_asprintf(string_tmp, "%s-%s", t, a_addrport); + } SMARTLIST_FOREACH_END(a_addrport); tor_free(bindaddr_tmp); } SMARTLIST_FOREACH_END(t); bindaddr_result = smartlist_join_strings(string_tmp, ",", 0, NULL); SMARTLIST_FOREACH(string_tmp, char *, t, tor_free(t)); smartlist_free(string_tmp);