Merge remote-tracking branch 'asn/bug3589'

This commit is contained in:
Nick Mathewson 2012-07-17 12:05:08 -04:00
commit ec8bdc5da8
7 changed files with 360 additions and 298 deletions

3
changes/bug3589 Normal file
View File

@ -0,0 +1,3 @@
o Major features:
- Bridges now report the pluggable transports they support to the
bridge authority. Implements ticket 3589.

View File

@ -4970,199 +4970,6 @@ bridge_free(bridge_info_t *bridge)
tor_free(bridge); tor_free(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_new();
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_new();
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
clear_transport_list(void)
{
if (!transport_list)
transport_list = smartlist_new();
SMARTLIST_FOREACH(transport_list, transport_t *, t, transport_free(t));
smartlist_clear(transport_list);
}
/** Free the pluggable transport struct <b>transport</b>. */
void
transport_free(transport_t *transport)
{
if (!transport)
return;
tor_free(transport->name);
tor_free(transport);
}
/** Returns the transport in our transport list that has the name <b>name</b>.
* Else returns NULL. */
transport_t *
transport_get_by_name(const char *name)
{
tor_assert(name);
if (!transport_list)
return NULL;
SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, transport) {
if (!strcmp(transport->name, name))
return transport;
} SMARTLIST_FOREACH_END(transport);
return NULL;
}
/** Returns a transport_t struct for a transport proxy supporting the
protocol <b>name</b> listening at <b>addr</b>:<b>port</b> using
SOCKS version <b>socks_ver</b>. */
transport_t *
transport_new(const tor_addr_t *addr, uint16_t port,
const char *name, int socks_ver)
{
transport_t *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;
}
/** Resolve any conflicts that the insertion of transport <b>t</b>
* might cause.
* Return 0 if <b>t</b> is OK and should be registered, 1 if there is
* a transport identical to <b>t</b> already registered and -1 if
* <b>t</b> 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. 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:
* 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_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_notice(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' "
"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;
}
}
}
return 0;
}
/** Add transport <b>t</b> 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)
{
int r;
tor_assert(t);
r = transport_resolve_conflicts(t);
switch (r) {
case 0: /* should register transport */
if (!transport_list)
transport_list = smartlist_new();
smartlist_add(transport_list, t);
return 0;
default: /* let our caller know the return code */
return r;
}
}
/** Remember a new pluggable transport proxy at <b>addr</b>:<b>port</b>.
* <b>name</b> is set to the name of the protocol this proxy uses.
* <b>socks_ver</b> 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_new(addr, port, name, socks_ver);
int r = transport_add(t);
switch (r) {
case -1:
default:
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_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_info(LD_GENERAL, "Succesfully registered transport %s at %s:%u.",
t->name, fmt_addr(&t->addr), t->port);
return 0;
}
}
/** Return a bridge pointer if <b>ri</b> is one of our known bridges /** Return a bridge pointer if <b>ri</b> is one of our known bridges
* (either by comparing keys if possible, else by comparing addr/port). * (either by comparing keys if possible, else by comparing addr/port).
@ -5800,10 +5607,7 @@ entry_guards_free_all(void)
entry_guards = NULL; entry_guards = NULL;
} }
clear_bridge_list(); clear_bridge_list();
clear_transport_list();
smartlist_free(bridge_list); smartlist_free(bridge_list);
smartlist_free(transport_list);
bridge_list = NULL; bridge_list = NULL;
transport_list = NULL;
} }

View File

@ -12,21 +12,6 @@
#ifndef _TOR_CIRCUITBUILD_H #ifndef _TOR_CIRCUITBUILD_H
#define _TOR_CIRCUITBUILD_H #define _TOR_CIRCUITBUILD_H
/** Represents a pluggable transport proxy used by a bridge. */
typedef struct {
/** SOCKS version: One of PROXY_SOCKS4, PROXY_SOCKS5. */
int socks_version;
/** Name of pluggable transport protocol */
char *name;
/** Address of proxy */
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); char *circuit_list_path(origin_circuit_t *circ, int verbose);
char *circuit_list_path_for_controller(origin_circuit_t *circ); char *circuit_list_path_for_controller(origin_circuit_t *circ);
void circuit_log_path(int severity, unsigned int domain, void circuit_log_path(int severity, unsigned int domain,
@ -82,8 +67,6 @@ int getinfo_helper_entry_guards(control_connection_t *conn,
void mark_bridge_list(void); void mark_bridge_list(void);
void sweep_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 routerinfo_is_a_configured_bridge(const routerinfo_t *ri);
int node_is_a_configured_bridge(const node_t *node); int node_is_a_configured_bridge(const node_t *node);
@ -151,21 +134,12 @@ void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
/* DOCDOC circuit_build_times_get_bw_scale */ /* DOCDOC circuit_build_times_get_bw_scale */
int circuit_build_times_get_bw_scale(networkstatus_t *ns); 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_new(const tor_addr_t *addr, uint16_t port,
const char *name, int socks_ver);
/* DOCDOC find_transport_name_by_bridge_addrport */ /* DOCDOC find_transport_name_by_bridge_addrport */
const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr, const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr,
uint16_t port); uint16_t port);
typedef struct transport_t transport_t;
int find_transport_by_bridge_addrport(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); const transport_t **transport);
transport_t *transport_get_by_name(const char *name);
#endif #endif

View File

@ -34,6 +34,7 @@
#include "rendcommon.h" #include "rendcommon.h"
#include "rephist.h" #include "rephist.h"
#include "router.h" #include "router.h"
#include "transports.h"
#include "routerparse.h" #include "routerparse.h"
#ifdef USE_BUFFEREVENTS #ifdef USE_BUFFEREVENTS

View File

@ -27,6 +27,7 @@
#include "router.h" #include "router.h"
#include "routerlist.h" #include "routerlist.h"
#include "routerparse.h" #include "routerparse.h"
#include "transports.h"
/** /**
* \file router.c * \file router.c
@ -2344,6 +2345,13 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
} }
} }
/* Add information about the pluggable transports we support. */
if (options->ServerTransportPlugin) {
char *pluggable_transports = pt_get_extra_info_descriptor_string();
if (pluggable_transports)
smartlist_add(chunks, pluggable_transports);
}
if (should_record_bridge_info(options) && write_stats_to_extrainfo) { if (should_record_bridge_info(options) && write_stats_to_extrainfo) {
const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now); const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now);
if (bridge_stats) { if (bridge_stats) {

View File

@ -39,13 +39,17 @@
* transport_t structs. * transport_t structs.
* *
* When the managed proxy stops spitting METHOD lines (signified by a * When the managed proxy stops spitting METHOD lines (signified by a
* '{S,C}METHODS DONE' message) we register all the transports * '{S,C}METHODS DONE' message) we pass copies of its transports to
* collected to the circuitbuild.c subsystem. At this point, the * the bridge subsystem. We keep copies of the 'transport_t's on the
* pointers to transport_t can be transformed into dangling pointers * managed proxy to be able to associate the proxy with its
* at any point by the circuitbuild.c subsystem, and so we replace all * transports, and we pass copies to the bridge subsystem so that
* transport_t pointers with strings describing the transport names. * transports can be associated with bridges.
* We can still go from a transport name to a transport_t using the * [ XXX We should try see whether the two copies are really needed
* fact that each transport name uniquely identifies a transport_t. * and maybe cut it into a single copy of the 'transport_t' shared
* between the managed proxy and the bridge subsystem. Preliminary
* analysis shows that both copies are needed with the current code
* logic, because of race conditions that can cause dangling
* pointers. ]
* *
* <b>In even more detail, this is what happens when a SIGHUP * <b>In even more detail, this is what happens when a SIGHUP
* occurs:</b> * occurs:</b>
@ -127,6 +131,219 @@ static INLINE void free_execve_args(char **arg);
protocol version. */ protocol version. */
#define PROTO_VERSION_ONE 1 #define PROTO_VERSION_ONE 1
/** A list of pluggable transports found in torrc. */
static smartlist_t *transport_list = NULL;
/** Returns a transport_t struct for a transport proxy supporting the
protocol <b>name</b> listening at <b>addr</b>:<b>port</b> using
SOCKS version <b>socks_ver</b>. */
static transport_t *
transport_new(const tor_addr_t *addr, uint16_t port,
const char *name, int socks_ver)
{
transport_t *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;
}
/** Free the pluggable transport struct <b>transport</b>. */
void
transport_free(transport_t *transport)
{
if (!transport)
return;
tor_free(transport->name);
tor_free(transport);
}
/** 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_new();
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_new();
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. */
static void
clear_transport_list(void)
{
if (!transport_list)
transport_list = smartlist_new();
SMARTLIST_FOREACH(transport_list, transport_t *, t, transport_free(t));
smartlist_clear(transport_list);
}
/** Return a deep copy of <b>transport</b>. */
static transport_t *
transport_copy(const transport_t *transport)
{
transport_t *new_transport = NULL;
tor_assert(transport);
new_transport = tor_malloc_zero(sizeof(transport_t));
new_transport->socks_version = transport->socks_version;
new_transport->name = tor_strdup(transport->name);
tor_addr_copy(&new_transport->addr, &transport->addr);
new_transport->port = transport->port;
new_transport->marked_for_removal = transport->marked_for_removal;
return new_transport;
}
/** Returns the transport in our transport list that has the name <b>name</b>.
* Else returns NULL. */
transport_t *
transport_get_by_name(const char *name)
{
tor_assert(name);
if (!transport_list)
return NULL;
SMARTLIST_FOREACH_BEGIN(transport_list, transport_t *, transport) {
if (!strcmp(transport->name, name))
return transport;
} SMARTLIST_FOREACH_END(transport);
return NULL;
}
/** Resolve any conflicts that the insertion of transport <b>t</b>
* might cause.
* Return 0 if <b>t</b> is OK and should be registered, 1 if there is
* a transport identical to <b>t</b> already registered and -1 if
* <b>t</b> cannot be added due to conflicts. */
static int
transport_resolve_conflicts(const 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. 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:
* 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_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_notice(LD_GENERAL, "You tried to add transport '%s' at '%s:%u' "
"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;
}
}
}
return 0;
}
/** Add transport <b>t</b> 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. */
static int
transport_add(transport_t *t)
{
int r;
tor_assert(t);
r = transport_resolve_conflicts(t);
switch (r) {
case 0: /* should register transport */
if (!transport_list)
transport_list = smartlist_new();
smartlist_add(transport_list, t);
return 0;
default: /* let our caller know the return code */
return r;
}
}
/** Remember a new pluggable transport proxy at <b>addr</b>:<b>port</b>.
* <b>name</b> is set to the name of the protocol this proxy uses.
* <b>socks_ver</b> 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_new(addr, port, name, socks_ver);
int r = transport_add(t);
switch (r) {
case -1:
default:
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_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_info(LD_GENERAL, "Succesfully registered transport %s at %s:%u.",
t->name, fmt_addr(&t->addr), t->port);
return 0;
}
}
/** List of unconfigured managed proxies. */ /** List of unconfigured managed proxies. */
static smartlist_t *managed_proxy_list = NULL; static smartlist_t *managed_proxy_list = NULL;
/** Number of still unconfigured proxies. */ /** Number of still unconfigured proxies. */
@ -217,11 +434,11 @@ proxy_needs_restart(const managed_proxy_t *mp)
{ {
/* mp->transport_to_launch is populated with the names of the /* mp->transport_to_launch is populated with the names of the
transports that must be launched *after* the SIGHUP. transports that must be launched *after* the SIGHUP.
mp->transports is populated with the names of the transports that mp->transports is populated with the transports that were
were launched *before* the SIGHUP. launched *before* the SIGHUP.
If the two lists contain the same strings, we don't need to Check if all the transports that need to be launched are already
restart the proxy, since it already does what we want. */ launched: */
tor_assert(smartlist_len(mp->transports_to_launch) > 0); tor_assert(smartlist_len(mp->transports_to_launch) > 0);
tor_assert(mp->conf_state == PT_PROTO_COMPLETED); tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
@ -229,11 +446,11 @@ proxy_needs_restart(const managed_proxy_t *mp)
if (smartlist_len(mp->transports_to_launch) != smartlist_len(mp->transports)) if (smartlist_len(mp->transports_to_launch) != smartlist_len(mp->transports))
goto needs_restart; goto needs_restart;
SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, char *, t_t_l) { SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) {
if (!smartlist_string_isin(mp->transports, t_t_l)) if (!smartlist_string_isin(mp->transports_to_launch, t->name))
goto needs_restart; goto needs_restart;
} SMARTLIST_FOREACH_END(t_t_l); } SMARTLIST_FOREACH_END(t);
return 0; return 0;
@ -245,6 +462,7 @@ proxy_needs_restart(const managed_proxy_t *mp)
* preparations and then flag its state so that it will be relaunched * preparations and then flag its state so that it will be relaunched
* in the next tick. */ * in the next tick. */
static void static void
proxy_prepare_for_restart(managed_proxy_t *mp) proxy_prepare_for_restart(managed_proxy_t *mp)
{ {
transport_t *t_tmp = NULL; transport_t *t_tmp = NULL;
@ -255,16 +473,17 @@ proxy_prepare_for_restart(managed_proxy_t *mp)
tor_process_handle_destroy(mp->process_handle, 1); tor_process_handle_destroy(mp->process_handle, 1);
mp->process_handle = NULL; mp->process_handle = NULL;
/* destroy all its old transports. we no longer use them. */ /* destroy all its registered transports, since we will no longer
SMARTLIST_FOREACH_BEGIN(mp->transports, const char *, t_name) { use them. */
t_tmp = transport_get_by_name(t_name); SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) {
t_tmp = transport_get_by_name(t->name);
if (t_tmp) if (t_tmp)
t_tmp->marked_for_removal = 1; t_tmp->marked_for_removal = 1;
} SMARTLIST_FOREACH_END(t_name); } SMARTLIST_FOREACH_END(t);
sweep_transport_list(); sweep_transport_list();
/* free the transport names in mp->transports */ /* free the transport in mp->transports */
SMARTLIST_FOREACH(mp->transports, char *, t_name, tor_free(t_name)); SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
smartlist_clear(mp->transports); smartlist_clear(mp->transports);
/* flag it as an infant proxy so that it gets launched on next tick */ /* flag it as an infant proxy so that it gets launched on next tick */
@ -315,6 +534,7 @@ launch_managed_proxy(managed_proxy_t *mp)
void void
pt_configure_remaining_proxies(void) pt_configure_remaining_proxies(void)
{ {
int at_least_a_proxy_config_finished = 0;
smartlist_t *tmp = smartlist_new(); smartlist_t *tmp = smartlist_new();
log_debug(LD_CONFIG, "Configuring remaining managed proxies (%d)!", log_debug(LD_CONFIG, "Configuring remaining managed proxies (%d)!",
@ -352,11 +572,17 @@ pt_configure_remaining_proxies(void)
if (!proxy_configuration_finished(mp)) if (!proxy_configuration_finished(mp))
configure_proxy(mp); configure_proxy(mp);
if (proxy_configuration_finished(mp))
at_least_a_proxy_config_finished = 1;
} SMARTLIST_FOREACH_END(mp); } SMARTLIST_FOREACH_END(mp);
smartlist_free(tmp); smartlist_free(tmp);
check_if_restarts_needed = 0; check_if_restarts_needed = 0;
assert_unconfigured_count_ok(); assert_unconfigured_count_ok();
if (at_least_a_proxy_config_finished)
mark_my_descriptor_dirty("configured managed proxies");
} }
#ifdef _WIN32 #ifdef _WIN32
@ -468,68 +694,48 @@ configure_proxy(managed_proxy_t *mp)
/** Register server managed proxy <b>mp</b> transports to state */ /** Register server managed proxy <b>mp</b> transports to state */
static void static void
register_server_proxy(managed_proxy_t *mp) register_server_proxy(const 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_new();
tor_assert(mp->conf_state != PT_PROTO_COMPLETED); tor_assert(mp->conf_state != PT_PROTO_COMPLETED);
SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) { SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
save_transport_to_state(t->name, &t->addr, t->port); save_transport_to_state(t->name, &t->addr, t->port);
log_notice(LD_GENERAL, "Registered server transport '%s' at '%s:%d'", log_notice(LD_GENERAL, "Registered server transport '%s' at '%s:%d'",
t->name, fmt_addr(&t->addr), (int)t->port); t->name, fmt_addr(&t->addr), (int)t->port);
smartlist_add(sm_tmp, tor_strdup(t->name));
} SMARTLIST_FOREACH_END(t); } 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;
} }
/** Register all the transports supported by client managed proxy /** Register all the transports supported by client managed proxy
* <b>mp</b> to the bridge subsystem. */ * <b>mp</b> to the bridge subsystem. */
static void static void
register_client_proxy(managed_proxy_t *mp) register_client_proxy(const managed_proxy_t *mp)
{ {
int r; 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_new();
tor_assert(mp->conf_state != PT_PROTO_COMPLETED); tor_assert(mp->conf_state != PT_PROTO_COMPLETED);
SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) { SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
r = transport_add(t); transport_t *transport_tmp = transport_copy(t);
r = transport_add(transport_tmp);
switch (r) { switch (r) {
case -1: case -1:
log_notice(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); transport_free(transport_tmp);
break; break;
case 0: case 0:
log_info(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; break;
case 1: case 1:
log_info(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(transport_tmp);
transport_free(t);
break; break;
} }
} SMARTLIST_FOREACH_END(t); } SMARTLIST_FOREACH_END(t);
smartlist_free(mp->transports);
mp->transports = sm_tmp;
} }
/** Register the transports of managed proxy <b>mp</b>. */ /** Register the transports of managed proxy <b>mp</b>. */
static INLINE void static INLINE void
register_proxy(managed_proxy_t *mp) register_proxy(const managed_proxy_t *mp)
{ {
if (mp->is_server) if (mp->is_server)
register_server_proxy(mp); register_server_proxy(mp);
@ -542,10 +748,7 @@ static void
managed_proxy_destroy(managed_proxy_t *mp, managed_proxy_destroy(managed_proxy_t *mp,
int also_terminate_process) int also_terminate_process)
{ {
if (mp->conf_state != PT_PROTO_COMPLETED)
SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); 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 */ /* free the transports smartlist */
smartlist_free(mp->transports); smartlist_free(mp->transports);
@ -1181,6 +1384,64 @@ pt_prepare_proxy_list_for_config_read(void)
tor_assert(unconfigured_proxies_n == 0); tor_assert(unconfigured_proxies_n == 0);
} }
/** Return the pluggable transport string that we should display in
* our extra-info descriptor. If we shouldn't display such a string,
* or we have nothing to display, return NULL. The string is
* allocated on the heap and it's the responsibility of the caller to
* free it. */
char *
pt_get_extra_info_descriptor_string(void)
{
char *the_string = NULL;
smartlist_t *string_chunks = NULL;
if (!managed_proxy_list)
return NULL;
string_chunks = smartlist_new();
/* For each managed proxy, add its transports to the chunks list. */
SMARTLIST_FOREACH_BEGIN(managed_proxy_list, const managed_proxy_t *, mp) {
if ((!mp->is_server) || (mp->conf_state != PT_PROTO_COMPLETED))
continue;
tor_assert(mp->transports);
SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) {
/* If the transport proxy returned "0.0.0.0" as its address, and
* we know our external IP address, use it. Otherwise, use the
* returned address. */
const char *addr_str = fmt_addr(&t->addr);
uint32_t external_ip_address = 0;
if (tor_addr_is_null(&t->addr) &&
router_pick_published_address(get_options(),
&external_ip_address) >= 0) {
/* returned addr was 0.0.0.0 and we found our external IP
address: use it. */
addr_str = fmt_addr32(external_ip_address);
}
smartlist_add_asprintf(string_chunks,
"transport %s %s:%u",
t->name, addr_str, t->port);
} SMARTLIST_FOREACH_END(t);
} SMARTLIST_FOREACH_END(mp);
if (smartlist_len(string_chunks) == 0) {
smartlist_free(string_chunks);
return NULL;
}
/* Join all the chunks into the final string. */
the_string = smartlist_join_strings(string_chunks, "\n", 1, NULL);
SMARTLIST_FOREACH(string_chunks, char *, s, tor_free(s));
smartlist_free(string_chunks);
return the_string;
}
/** The tor config was read. /** The tor config was read.
* Destroy all managed proxies that were marked by a previous call to * 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 * prepare_proxy_list_for_config_read() and are not used by the new
@ -1204,6 +1465,12 @@ sweep_proxy_list(void)
void void
pt_free_all(void) pt_free_all(void)
{ {
if (transport_list) {
clear_transport_list();
smartlist_free(transport_list);
transport_list = NULL;
}
if (managed_proxy_list) { if (managed_proxy_list) {
/* If the proxy is in PT_PROTO_COMPLETED, it has registered its /* If the proxy is in PT_PROTO_COMPLETED, it has registered its
transports and it's the duty of the circuitbuild.c subsystem to transports and it's the duty of the circuitbuild.c subsystem to

View File

@ -11,6 +11,30 @@
#ifndef TOR_TRANSPORTS_H #ifndef TOR_TRANSPORTS_H
#define TOR_TRANSPORTS_H #define TOR_TRANSPORTS_H
/** Represents a pluggable transport used by a bridge. */
typedef struct transport_t {
/** SOCKS version: One of PROXY_SOCKS4, PROXY_SOCKS5. */
int socks_version;
/** Name of pluggable transport protocol */
char *name;
/** The IP address where the transport bound and is waiting for
* connections. */
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;
void mark_transport_list(void);
void sweep_transport_list(void);
int transport_add_from_config(const tor_addr_t *addr, uint16_t port,
const char *name, int socks_ver);
void transport_free(transport_t *transport);
transport_t *transport_get_by_name(const char *name);
void pt_kickstart_proxy(const smartlist_t *transport_list, char **proxy_argv, void pt_kickstart_proxy(const smartlist_t *transport_list, char **proxy_argv,
int is_server); int is_server);
@ -23,6 +47,8 @@ void pt_configure_remaining_proxies(void);
int pt_proxies_configuration_pending(void); int pt_proxies_configuration_pending(void);
char *pt_get_extra_info_descriptor_string(void);
void pt_free_all(void); void pt_free_all(void);
void pt_prepare_proxy_list_for_config_read(void); void pt_prepare_proxy_list_for_config_read(void);
@ -68,28 +94,7 @@ typedef struct {
smartlist_t *transports_to_launch; smartlist_t *transports_to_launch;
/* The 'transports' list contains all the transports this proxy has /* The 'transports' list contains all the transports this proxy has
launched. 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; smartlist_t *transports;
} managed_proxy_t; } managed_proxy_t;