aboutsummaryrefslogtreecommitdiff
path: root/src/or/circuitbuild.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/circuitbuild.c')
-rw-r--r--src/or/circuitbuild.c1238
1 files changed, 838 insertions, 400 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 72ec9e4880..07598e242f 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -23,8 +23,10 @@
#include "directory.h"
#include "main.h"
#include "networkstatus.h"
+#include "nodelist.h"
#include "onion.h"
#include "policies.h"
+#include "transports.h"
#include "relay.h"
#include "rephist.h"
#include "router.h"
@@ -55,8 +57,8 @@ extern circuit_t *global_circuitlist;
/** An entry_guard_t represents our information about a chosen long-term
* first hop, known as a "helper" node in the literature. We can't just
- * use a routerinfo_t, since we want to remember these even when we
- * don't have a directory. */
+ * use a node_t, since we want to remember these even when we
+ * don't have any directory info. */
typedef struct {
char nickname[MAX_NICKNAME_LEN+1];
char identity[DIGEST_LEN];
@@ -78,6 +80,28 @@ typedef struct {
* at which we last failed to connect to it. */
} entry_guard_t;
+/** Information about a configured bridge. Currently this just matches the
+ * ones in the torrc file, but one day we may be able to learn about new
+ * bridges on our own, and remember them in the state file. */
+typedef struct {
+ /** Address of the bridge. */
+ tor_addr_t addr;
+ /** TLS port for the bridge. */
+ uint16_t port;
+ /** Boolean: We are re-parsing our bridge list, and we are going to remove
+ * this one if we don't find it in the list of configured bridges. */
+ unsigned marked_for_removal : 1;
+ /** Expected identity digest, or all zero bytes if we don't know what the
+ * digest should be. */
+ char identity[DIGEST_LEN];
+
+ /** Name of pluggable transport protocol taken from its config line. */
+ char *transport_name;
+
+ /** When should we next try to fetch a descriptor for this bridge? */
+ download_status_t fetch_status;
+} bridge_info_t;
+
/** A list of our chosen entry guards. */
static smartlist_t *entry_guards = NULL;
/** A value of 1 means that the entry_guards list has changed
@@ -95,11 +119,13 @@ static int circuit_deliver_create_cell(circuit_t *circ,
static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit);
static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
static int onion_extend_cpath(origin_circuit_t *circ);
-static int count_acceptable_routers(smartlist_t *routers);
+static int count_acceptable_nodes(smartlist_t *routers);
static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
static void entry_guards_changed(void);
+static void bridge_free(bridge_info_t *bridge);
+
/**
* This function decides if CBT learning should be disabled. It returns
* true if one or more of the following four conditions are met:
@@ -649,8 +675,7 @@ circuit_build_times_update_state(circuit_build_times_t *cbt,
if (histogram[i] == 0) continue;
*next = line = tor_malloc_zero(sizeof(config_line_t));
line->key = tor_strdup("CircuitBuildTimeBin");
- line->value = tor_malloc(25);
- tor_snprintf(line->value, 25, "%d %d",
+ tor_asprintf(&line->value, "%d %d",
CBT_BIN_TO_MS(i), histogram[i]);
next = &(line->next);
}
@@ -768,7 +793,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
loaded_times = tor_malloc_zero(sizeof(build_time_t)*state->TotalBuildTimes);
for (line = state->BuildtimeHistogram; line; line = line->next) {
- smartlist_t *args = smartlist_create();
+ smartlist_t *args = smartlist_new();
smartlist_split_string(args, line->value, " ",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
if (smartlist_len(args) < 2) {
@@ -1515,27 +1540,24 @@ circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names)
const char *states[] = {"closed", "waiting for keys", "open"};
char *s;
- elements = smartlist_create();
+ elements = smartlist_new();
if (verbose) {
const char *nickname = build_state_get_exit_nickname(circ->build_state);
- char *cp;
- tor_asprintf(&cp, "%s%s circ (length %d%s%s):",
+ smartlist_add_asprintf(elements, "%s%s circ (length %d%s%s):",
circ->build_state->is_internal ? "internal" : "exit",
circ->build_state->need_uptime ? " (high-uptime)" : "",
circ->build_state->desired_path_len,
circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", last hop ",
circ->_base.state == CIRCUIT_STATE_OPEN ? "" :
(nickname?nickname:"*unnamed*"));
- smartlist_add(elements, cp);
}
hop = circ->cpath;
do {
- routerinfo_t *ri;
- routerstatus_t *rs;
char *elt;
const char *id;
+ const node_t *node;
if (!hop)
break;
if (!verbose && hop->state != CPATH_STATE_OPEN)
@@ -1545,10 +1567,8 @@ circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names)
id = hop->extend_info->identity_digest;
if (verbose_names) {
elt = tor_malloc(MAX_VERBOSE_NICKNAME_LEN+1);
- if ((ri = router_get_by_digest(id))) {
- router_get_verbose_nickname(elt, ri);
- } else if ((rs = router_get_consensus_status_by_id(id))) {
- routerstatus_get_verbose_nickname(elt, rs);
+ if ((node = node_get_by_id(id))) {
+ node_get_verbose_nickname(node, elt);
} else if (is_legal_nickname(hop->extend_info->nickname)) {
elt[0] = '$';
base16_encode(elt+1, HEX_DIGEST_LEN+1, id, DIGEST_LEN);
@@ -1560,9 +1580,9 @@ circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names)
base16_encode(elt+1, HEX_DIGEST_LEN+1, id, DIGEST_LEN);
}
} else { /* ! verbose_names */
- if ((ri = router_get_by_digest(id)) &&
- ri->is_named) {
- elt = tor_strdup(hop->extend_info->nickname);
+ node = node_get_by_id(id);
+ if (node && node_is_named(node)) {
+ elt = tor_strdup(node_get_nickname(node));
} else {
elt = tor_malloc(HEX_DIGEST_LEN+2);
elt[0] = '$';
@@ -1571,11 +1591,8 @@ circuit_list_path_impl(origin_circuit_t *circ, int verbose, int verbose_names)
}
tor_assert(elt);
if (verbose) {
- size_t len = strlen(elt)+2+strlen(states[hop->state])+1;
- char *v = tor_malloc(len);
tor_assert(hop->state <= 2);
- tor_snprintf(v,len,"%s(%s)",elt,states[hop->state]);
- smartlist_add(elements, v);
+ smartlist_add_asprintf(elements,"%s(%s)",elt,states[hop->state]);
tor_free(elt);
} else {
smartlist_add(elements, elt);
@@ -1631,31 +1648,28 @@ void
circuit_rep_hist_note_result(origin_circuit_t *circ)
{
crypt_path_t *hop;
- char *prev_digest = NULL;
- routerinfo_t *router;
+ const char *prev_digest = NULL;
hop = circ->cpath;
if (!hop) /* circuit hasn't started building yet. */
return;
if (server_mode(get_options())) {
- routerinfo_t *me = router_get_my_routerinfo();
+ const routerinfo_t *me = router_get_my_routerinfo();
if (!me)
return;
prev_digest = me->cache_info.identity_digest;
}
do {
- router = router_get_by_digest(hop->extend_info->identity_digest);
- if (router) {
+ const node_t *node = node_get_by_id(hop->extend_info->identity_digest);
+ if (node) { /* Why do we check this? We know the identity. -NM XXXX */
if (prev_digest) {
if (hop->state == CPATH_STATE_OPEN)
- rep_hist_note_extend_succeeded(prev_digest,
- router->cache_info.identity_digest);
+ rep_hist_note_extend_succeeded(prev_digest, node->identity);
else {
- rep_hist_note_extend_failed(prev_digest,
- router->cache_info.identity_digest);
+ rep_hist_note_extend_failed(prev_digest, node->identity);
break;
}
}
- prev_digest = router->cache_info.identity_digest;
+ prev_digest = node->identity;
} else {
prev_digest = NULL;
}
@@ -1811,7 +1825,7 @@ circuit_n_conn_done(or_connection_t *or_conn, int status)
or_conn->nickname ? or_conn->nickname : "NULL",
or_conn->_base.address, status);
- pending_circs = smartlist_create();
+ pending_circs = smartlist_new();
circuit_get_all_pending_on_or_conn(pending_circs, or_conn);
SMARTLIST_FOREACH_BEGIN(pending_circs, circuit_t *, circ)
@@ -1924,7 +1938,7 @@ int
inform_testing_reachability(void)
{
char dirbuf[128];
- routerinfo_t *me = router_get_my_routerinfo();
+ const routerinfo_t *me = router_get_my_routerinfo();
if (!me)
return 0;
control_event_server_status(LOG_NOTICE,
@@ -1953,7 +1967,7 @@ inform_testing_reachability(void)
static INLINE int
should_use_create_fast_for_circuit(origin_circuit_t *circ)
{
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
tor_assert(circ->cpath);
tor_assert(circ->cpath->extend_info);
@@ -1997,7 +2011,7 @@ int
circuit_send_next_onion_skin(origin_circuit_t *circ)
{
crypt_path_t *hop;
- routerinfo_t *router;
+ const node_t *node;
char payload[2+4+DIGEST_LEN+ONIONSKIN_CHALLENGE_LEN];
char *onionskin;
size_t payload_len;
@@ -2013,7 +2027,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
else
control_event_bootstrap(BOOTSTRAP_STATUS_CIRCUIT_CREATE, 0);
- router = router_get_by_digest(circ->_base.n_conn->identity_digest);
+ node = node_get_by_id(circ->_base.n_conn->identity_digest);
fast = should_use_create_fast_for_circuit(circ);
if (!fast) {
/* We are an OR and we know the right onion key: we should
@@ -2047,7 +2061,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
log_info(LD_CIRC,"First hop: finished sending %s cell to '%s'",
fast ? "CREATE_FAST" : "CREATE",
- router ? router_describe(router) : "<unnamed>");
+ node ? node_describe(node) : "<unnamed>");
} else {
tor_assert(circ->cpath->state == CPATH_STATE_OPEN);
tor_assert(circ->_base.state == CIRCUIT_STATE_BUILDING);
@@ -2089,7 +2103,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
if (circ->build_state->onehop_tunnel)
control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_STATUS, 0);
if (!can_complete_circuit && !circ->build_state->onehop_tunnel) {
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
can_complete_circuit=1;
/* FFFF Log a count of known routers here */
log_notice(LD_GENERAL,
@@ -2097,6 +2111,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
"Looks like client functionality is working.");
control_event_bootstrap(BOOTSTRAP_STATUS_DONE, 0);
control_event_client_status(LOG_NOTICE, "CIRCUIT_ESTABLISHED");
+ clear_broken_connection_map(1);
if (server_mode(options) && !check_whether_orport_reachable()) {
inform_testing_reachability();
consider_testing_reachability(1, 1);
@@ -2305,17 +2320,17 @@ int
circuit_init_cpath_crypto(crypt_path_t *cpath, const char *key_data,
int reverse)
{
- crypto_digest_env_t *tmp_digest;
- crypto_cipher_env_t *tmp_crypto;
+ crypto_digest_t *tmp_digest;
+ crypto_cipher_t *tmp_crypto;
tor_assert(cpath);
tor_assert(key_data);
tor_assert(!(cpath->f_crypto || cpath->b_crypto ||
cpath->f_digest || cpath->b_digest));
- cpath->f_digest = crypto_new_digest_env();
+ cpath->f_digest = crypto_digest_new();
crypto_digest_add_bytes(cpath->f_digest, key_data, DIGEST_LEN);
- cpath->b_digest = crypto_new_digest_env();
+ cpath->b_digest = crypto_digest_new();
crypto_digest_add_bytes(cpath->b_digest, key_data+DIGEST_LEN, DIGEST_LEN);
if (!(cpath->f_crypto =
@@ -2503,7 +2518,8 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
append_cell_to_circuit_queue(TO_CIRCUIT(circ),
circ->p_conn, &cell, CELL_DIRECTION_IN, 0);
- log_debug(LD_CIRC,"Finished sending 'created' cell.");
+ log_debug(LD_CIRC,"Finished sending '%s' cell.",
+ circ->is_first_hop ? "created_fast" : "created");
if (!is_local_addr(&circ->p_conn->_base.addr) &&
!connection_or_nonopen_was_started_here(circ->p_conn)) {
@@ -2524,12 +2540,12 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
*/
static int
new_route_len(uint8_t purpose, extend_info_t *exit,
- smartlist_t *routers)
+ smartlist_t *nodes)
{
int num_acceptable_routers;
int routelen;
- tor_assert(routers);
+ tor_assert(nodes);
routelen = DEFAULT_ROUTE_LEN;
if (exit &&
@@ -2537,10 +2553,10 @@ new_route_len(uint8_t purpose, extend_info_t *exit,
purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)
routelen++;
- num_acceptable_routers = count_acceptable_routers(routers);
+ num_acceptable_routers = count_acceptable_nodes(nodes);
log_debug(LD_CIRC,"Chosen route length %d (%d/%d routers suitable).",
- routelen, num_acceptable_routers, smartlist_len(routers));
+ routelen, num_acceptable_routers, smartlist_len(nodes));
if (num_acceptable_routers < 2) {
log_info(LD_CIRC,
@@ -2558,24 +2574,12 @@ new_route_len(uint8_t purpose, extend_info_t *exit,
return routelen;
}
-/** Fetch the list of predicted ports, dup it into a smartlist of
- * uint16_t's, remove the ones that are already handled by an
- * existing circuit, and return it.
- */
+/** Return a newly allocated list of uint16_t * for each predicted port not
+ * handled by a current circuit. */
static smartlist_t *
circuit_get_unhandled_ports(time_t now)
{
- smartlist_t *source = rep_hist_get_predicted_ports(now);
- smartlist_t *dest = smartlist_create();
- uint16_t *tmp;
- int i;
-
- for (i = 0; i < smartlist_len(source); ++i) {
- tmp = tor_malloc(sizeof(uint16_t));
- memcpy(tmp, smartlist_get(source, i), sizeof(uint16_t));
- smartlist_add(dest, tmp);
- }
-
+ smartlist_t *dest = rep_hist_get_predicted_ports(now);
circuit_remove_handled_ports(dest);
return dest;
}
@@ -2609,12 +2613,12 @@ circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
return enough;
}
-/** Return 1 if <b>router</b> can handle one or more of the ports in
+/** Return 1 if <b>node</b> can handle one or more of the ports in
* <b>needed_ports</b>, else return 0.
*/
static int
-router_handles_some_port(routerinfo_t *router, smartlist_t *needed_ports)
-{
+node_handles_some_port(const node_t *node, smartlist_t *needed_ports)
+{ /* XXXX MOVE */
int i;
uint16_t port;
@@ -2624,7 +2628,10 @@ router_handles_some_port(routerinfo_t *router, smartlist_t *needed_ports)
needed_ports is explicitly a smartlist of uint16_t's */
port = *(uint16_t *)smartlist_get(needed_ports, i);
tor_assert(port);
- r = compare_addr_to_addr_policy(0, port, router->exit_policy);
+ if (node)
+ r = compare_tor_addr_to_node_policy(NULL, port, node);
+ else
+ continue;
if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED)
return 1;
}
@@ -2636,14 +2643,18 @@ router_handles_some_port(routerinfo_t *router, smartlist_t *needed_ports)
static int
ap_stream_wants_exit_attention(connection_t *conn)
{
- if (conn->type == CONN_TYPE_AP &&
- conn->state == AP_CONN_STATE_CIRCUIT_WAIT &&
+ entry_connection_t *entry;
+ if (conn->type != CONN_TYPE_AP)
+ return 0;
+ entry = TO_ENTRY_CONN(conn);
+
+ if (conn->state == AP_CONN_STATE_CIRCUIT_WAIT &&
!conn->marked_for_close &&
- !(TO_EDGE_CONN(conn)->want_onehop) && /* ignore one-hop streams */
- !(TO_EDGE_CONN(conn)->use_begindir) && /* ignore targeted dir fetches */
- !(TO_EDGE_CONN(conn)->chosen_exit_name) && /* ignore defined streams */
+ !(entry->want_onehop) && /* ignore one-hop streams */
+ !(entry->use_begindir) && /* ignore targeted dir fetches */
+ !(entry->chosen_exit_name) && /* ignore defined streams */
!connection_edge_is_rendezvous_stream(TO_EDGE_CONN(conn)) &&
- !circuit_stream_is_being_handled(TO_EDGE_CONN(conn), 0,
+ !circuit_stream_is_being_handled(TO_ENTRY_CONN(conn), 0,
MIN_CIRCUITS_HANDLING_STREAM))
return 1;
return 0;
@@ -2657,18 +2668,17 @@ ap_stream_wants_exit_attention(connection_t *conn)
*
* Return NULL if we can't find any suitable routers.
*/
-static routerinfo_t *
-choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
- int need_capacity)
+static const node_t *
+choose_good_exit_server_general(int need_uptime, int need_capacity)
{
int *n_supported;
- int i;
int n_pending_connections = 0;
smartlist_t *connections;
int best_support = -1;
int n_best_support=0;
- routerinfo_t *router;
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
+ const smartlist_t *the_nodes;
+ const node_t *node=NULL;
connections = get_connection_array();
@@ -2689,10 +2699,11 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
*
* -1 means "Don't use this router at all."
*/
- n_supported = tor_malloc(sizeof(int)*smartlist_len(dir->routers));
- for (i = 0; i < smartlist_len(dir->routers); ++i) {/* iterate over routers */
- router = smartlist_get(dir->routers, i);
- if (router_is_me(router)) {
+ the_nodes = nodelist_get_list();
+ n_supported = tor_malloc(sizeof(int)*smartlist_len(the_nodes));
+ SMARTLIST_FOREACH_BEGIN(the_nodes, const node_t *, node) {
+ const int i = node_sl_idx;
+ if (router_digest_is_me(node->identity)) {
n_supported[i] = -1;
// log_fn(LOG_DEBUG,"Skipping node %s -- it's me.", router->nickname);
/* XXX there's probably a reverse predecessor attack here, but
@@ -2700,41 +2711,44 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
*/
continue;
}
- if (!router->is_running || router->is_bad_exit) {
+ if (!node_has_descriptor(node)) {
+ n_supported[i] = -1;
+ continue;
+ }
+ if (!node->is_running || node->is_bad_exit) {
n_supported[i] = -1;
continue; /* skip routers that are known to be down or bad exits */
}
-
- if (options->_ExcludeExitNodesUnion &&
- routerset_contains_router(options->_ExcludeExitNodesUnion, router)) {
+ if (routerset_contains_node(options->_ExcludeExitNodesUnion, node)) {
n_supported[i] = -1;
continue; /* user asked us not to use it, no matter what */
}
if (options->ExitNodes &&
- !routerset_contains_router(options->ExitNodes, router)) {
+ !routerset_contains_node(options->ExitNodes, node)) {
n_supported[i] = -1;
continue; /* not one of our chosen exit nodes */
}
- if (router_is_unreliable(router, need_uptime, need_capacity, 0)) {
+ if (node_is_unreliable(node, need_uptime, need_capacity, 0)) {
n_supported[i] = -1;
continue; /* skip routers that are not suitable. Don't worry if
* this makes us reject all the possible routers: if so,
* we'll retry later in this function with need_update and
* need_capacity set to 0. */
}
- if (!(router->is_valid || options->_AllowInvalid & ALLOW_INVALID_EXIT)) {
+ if (!(node->is_valid || options->_AllowInvalid & ALLOW_INVALID_EXIT)) {
/* if it's invalid and we don't want it */
n_supported[i] = -1;
// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- invalid router.",
// router->nickname, i);
continue; /* skip invalid routers */
}
- if (options->ExcludeSingleHopRelays && router->allow_single_hop_exits) {
+ if (options->ExcludeSingleHopRelays &&
+ node_allows_single_hop_exits(node)) {
n_supported[i] = -1;
continue;
}
- if (router_exit_policy_rejects_all(router)) {
+ if (node_exit_policy_rejects_all(node)) {
n_supported[i] = -1;
// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- it rejects all.",
// router->nickname, i);
@@ -2742,11 +2756,10 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
}
n_supported[i] = 0;
/* iterate over connections */
- SMARTLIST_FOREACH(connections, connection_t *, conn,
- {
+ SMARTLIST_FOREACH_BEGIN(connections, connection_t *, conn) {
if (!ap_stream_wants_exit_attention(conn))
continue; /* Skip everything but APs in CIRCUIT_WAIT */
- if (connection_ap_can_use_exit(TO_EDGE_CONN(conn), router)) {
+ if (connection_ap_can_use_exit(TO_ENTRY_CONN(conn), node)) {
++n_supported[i];
// log_fn(LOG_DEBUG,"%s is supported. n_supported[%d] now %d.",
// router->nickname, i, n_supported[i]);
@@ -2754,7 +2767,7 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
// log_fn(LOG_DEBUG,"%s (index %d) would reject this stream.",
// router->nickname, i);
}
- }); /* End looping over connections. */
+ } SMARTLIST_FOREACH_END(conn);
if (n_pending_connections > 0 && n_supported[i] == 0) {
/* Leave best_support at -1 if that's where it is, so we can
* distinguish it later. */
@@ -2771,7 +2784,7 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
* count of equally good routers.*/
++n_best_support;
}
- }
+ } SMARTLIST_FOREACH_END(node);
log_info(LD_CIRC,
"Found %d servers that might support %d/%d pending connections.",
n_best_support, best_support >= 0 ? best_support : 0,
@@ -2780,13 +2793,14 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
/* If any routers definitely support any pending connections, choose one
* at random. */
if (best_support > 0) {
- smartlist_t *supporting = smartlist_create();
+ smartlist_t *supporting = smartlist_new();
- for (i = 0; i < smartlist_len(dir->routers); i++)
- if (n_supported[i] == best_support)
- smartlist_add(supporting, smartlist_get(dir->routers, i));
+ SMARTLIST_FOREACH(the_nodes, const node_t *, node, {
+ if (n_supported[node_sl_idx] == best_support)
+ smartlist_add(supporting, (void*)node);
+ });
- router = routerlist_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT);
+ node = node_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT);
smartlist_free(supporting);
} else {
/* Either there are no pending connections, or no routers even seem to
@@ -2804,29 +2818,28 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
need_capacity?", fast":"",
need_uptime?", stable":"");
tor_free(n_supported);
- return choose_good_exit_server_general(dir, 0, 0);
+ return choose_good_exit_server_general(0, 0);
}
log_notice(LD_CIRC, "All routers are down or won't exit%s -- "
"choosing a doomed exit at random.",
options->_ExcludeExitNodesUnion ? " or are Excluded" : "");
}
- supporting = smartlist_create();
+ supporting = smartlist_new();
needed_ports = circuit_get_unhandled_ports(time(NULL));
for (attempt = 0; attempt < 2; attempt++) {
/* try once to pick only from routers that satisfy a needed port,
* then if there are none, pick from any that support exiting. */
- for (i = 0; i < smartlist_len(dir->routers); i++) {
- router = smartlist_get(dir->routers, i);
- if (n_supported[i] != -1 &&
- (attempt || router_handles_some_port(router, needed_ports))) {
+ SMARTLIST_FOREACH_BEGIN(the_nodes, const node_t *, node) {
+ if (n_supported[node_sl_idx] != -1 &&
+ (attempt || node_handles_some_port(node, needed_ports))) {
// log_fn(LOG_DEBUG,"Try %d: '%s' is a possibility.",
// try, router->nickname);
- smartlist_add(supporting, router);
+ smartlist_add(supporting, (void*)node);
}
- }
+ } SMARTLIST_FOREACH_END(node);
- router = routerlist_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT);
- if (router)
+ node = node_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT);
+ if (node)
break;
smartlist_clear(supporting);
}
@@ -2836,9 +2849,9 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
}
tor_free(n_supported);
- if (router) {
- log_info(LD_CIRC, "Chose exit server '%s'", router_describe(router));
- return router;
+ if (node) {
+ log_info(LD_CIRC, "Chose exit server '%s'", node_describe(node));
+ return node;
}
if (options->ExitNodes) {
log_warn(LD_CIRC,
@@ -2859,12 +2872,12 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
* For client-side rendezvous circuits, choose a random node, weighted
* toward the preferences in 'options'.
*/
-static routerinfo_t *
-choose_good_exit_server(uint8_t purpose, routerlist_t *dir,
+static const node_t *
+choose_good_exit_server(uint8_t purpose,
int need_uptime, int need_capacity, int is_internal)
{
- or_options_t *options = get_options();
- router_crn_flags_t flags = 0;
+ const or_options_t *options = get_options();
+ router_crn_flags_t flags = CRN_NEED_DESC;
if (need_uptime)
flags |= CRN_NEED_UPTIME;
if (need_capacity)
@@ -2877,7 +2890,7 @@ choose_good_exit_server(uint8_t purpose, routerlist_t *dir,
if (is_internal) /* pick it like a middle hop */
return router_choose_random_node(NULL, options->ExcludeNodes, flags);
else
- return choose_good_exit_server_general(dir,need_uptime,need_capacity);
+ return choose_good_exit_server_general(need_uptime,need_capacity);
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
if (options->_AllowInvalid & ALLOW_INVALID_RENDEZVOUS)
flags |= CRN_ALLOW_INVALID;
@@ -2893,7 +2906,7 @@ choose_good_exit_server(uint8_t purpose, routerlist_t *dir,
static void
warn_if_last_router_excluded(origin_circuit_t *circ, const extend_info_t *exit)
{
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
routerset_t *rs = options->ExcludeNodes;
const char *description;
uint8_t purpose = circ->_base.purpose;
@@ -2970,13 +2983,12 @@ static int
onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
{
cpath_build_state_t *state = circ->build_state;
- routerlist_t *rl = router_get_routerlist();
if (state->onehop_tunnel) {
log_debug(LD_CIRC, "Launching a one-hop circuit for dir tunnel.");
state->desired_path_len = 1;
} else {
- int r = new_route_len(circ->_base.purpose, exit, rl->routers);
+ int r = new_route_len(circ->_base.purpose, exit, nodelist_get_list());
if (r < 1) /* must be at least 1 */
return -1;
state->desired_path_len = r;
@@ -2988,14 +3000,15 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
extend_info_describe(exit));
exit = extend_info_dup(exit);
} else { /* we have to decide one */
- routerinfo_t *router =
- choose_good_exit_server(circ->_base.purpose, rl, state->need_uptime,
+ const node_t *node =
+ choose_good_exit_server(circ->_base.purpose, state->need_uptime,
state->need_capacity, state->is_internal);
- if (!router) {
+ if (!node) {
log_warn(LD_CIRC,"failed to choose an exit server");
return -1;
}
- exit = extend_info_from_router(router);
+ exit = extend_info_from_node(node, 0);
+ tor_assert(exit);
}
state->chosen_exit = exit;
return 0;
@@ -3046,35 +3059,30 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit)
* and available for building circuits through.
*/
static int
-count_acceptable_routers(smartlist_t *routers)
+count_acceptable_nodes(smartlist_t *nodes)
{
- int i, n;
int num=0;
- routerinfo_t *r;
- n = smartlist_len(routers);
- for (i=0;i<n;i++) {
- r = smartlist_get(routers, i);
-// log_debug(LD_CIRC,
+ SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) {
+ // log_debug(LD_CIRC,
// "Contemplating whether router %d (%s) is a new option.",
// i, r->nickname);
- if (r->is_running == 0) {
+ if (! node->is_running)
// log_debug(LD_CIRC,"Nope, the directory says %d is not running.",i);
- goto next_i_loop;
- }
- if (r->is_valid == 0) {
+ continue;
+ if (! node->is_valid)
// log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i);
- goto next_i_loop;
+ continue;
+ if (! node_has_descriptor(node))
+ continue;
/* XXX This clause makes us count incorrectly: if AllowInvalidRouters
* allows this node in some places, then we're getting an inaccurate
* count. For now, be conservative and don't count it. But later we
* should try to be smarter. */
- }
- num++;
+ ++num;
+ } SMARTLIST_FOREACH_END(node);
+
// log_debug(LD_CIRC,"I like %d. num_acceptable_routers now %d.",i, num);
- next_i_loop:
- ; /* C requires an explicit statement after the label */
- }
return num;
}
@@ -3102,31 +3110,29 @@ onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop)
* circuit. In particular, make sure we don't pick the exit node or its
* family, and make sure we don't duplicate any previous nodes or their
* families. */
-static routerinfo_t *
+static const node_t *
choose_good_middle_server(uint8_t purpose,
cpath_build_state_t *state,
crypt_path_t *head,
int cur_len)
{
int i;
- routerinfo_t *r, *choice;
+ const node_t *r, *choice;
crypt_path_t *cpath;
smartlist_t *excluded;
- or_options_t *options = get_options();
- router_crn_flags_t flags = 0;
+ const or_options_t *options = get_options();
+ router_crn_flags_t flags = CRN_NEED_DESC;
tor_assert(_CIRCUIT_PURPOSE_MIN <= purpose &&
purpose <= _CIRCUIT_PURPOSE_MAX);
log_debug(LD_CIRC, "Contemplating intermediate hop: random choice.");
- excluded = smartlist_create();
- if ((r = build_state_get_exit_router(state))) {
- smartlist_add(excluded, r);
- routerlist_add_family(excluded, r);
+ excluded = smartlist_new();
+ if ((r = build_state_get_exit_node(state))) {
+ nodelist_add_node_and_family(excluded, r);
}
for (i = 0, cpath = head; i < cur_len; ++i, cpath=cpath->next) {
- if ((r = router_get_by_digest(cpath->extend_info->identity_digest))) {
- smartlist_add(excluded, r);
- routerlist_add_family(excluded, r);
+ if ((r = node_get_by_id(cpath->extend_info->identity_digest))) {
+ nodelist_add_node_and_family(excluded, r);
}
}
@@ -3149,44 +3155,43 @@ choose_good_middle_server(uint8_t purpose,
* If <b>state</b> is NULL, we're choosing a router to serve as an entry
* guard, not for any particular circuit.
*/
-static routerinfo_t *
+static const node_t *
choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
{
- routerinfo_t *r, *choice;
+ const node_t *choice;
smartlist_t *excluded;
- or_options_t *options = get_options();
- router_crn_flags_t flags = CRN_NEED_GUARD;
+ const or_options_t *options = get_options();
+ router_crn_flags_t flags = CRN_NEED_GUARD|CRN_NEED_DESC;
+ const node_t *node;
if (state && options->UseEntryGuards &&
(purpose != CIRCUIT_PURPOSE_TESTING || options->BridgeRelay)) {
+ /* This is request for an entry server to use for a regular circuit,
+ * and we use entry guard nodes. Just return one of the guard nodes. */
return choose_random_entry(state);
}
- excluded = smartlist_create();
+ excluded = smartlist_new();
- if (state && (r = build_state_get_exit_router(state))) {
- smartlist_add(excluded, r);
- routerlist_add_family(excluded, r);
+ if (state && (node = build_state_get_exit_node(state))) {
+ /* Exclude the exit node from the state, if we have one. Also exclude its
+ * family. */
+ nodelist_add_node_and_family(excluded, node);
}
if (firewall_is_fascist_or()) {
- /*XXXX This could slow things down a lot; use a smarter implementation */
- /* exclude all ORs that listen on the wrong port, if anybody notices. */
- routerlist_t *rl = router_get_routerlist();
- int i;
-
- for (i=0; i < smartlist_len(rl->routers); i++) {
- r = smartlist_get(rl->routers, i);
- if (!fascist_firewall_allows_or(r))
- smartlist_add(excluded, r);
- }
+ /* Exclude all ORs that we can't reach through our firewall */
+ smartlist_t *nodes = nodelist_get_list();
+ SMARTLIST_FOREACH(nodes, const node_t *, node, {
+ if (!fascist_firewall_allows_node(node))
+ smartlist_add(excluded, (void*)node);
+ });
}
- /* and exclude current entry guards, if applicable */
+ /* and exclude current entry guards and their families, if applicable */
if (options->UseEntryGuards && entry_guards) {
SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
{
- if ((r = router_get_by_digest(entry->identity))) {
- smartlist_add(excluded, r);
- routerlist_add_family(excluded, r);
+ if ((node = node_get_by_id(entry->identity))) {
+ nodelist_add_node_and_family(excluded, node);
}
});
}
@@ -3242,14 +3247,23 @@ onion_extend_cpath(origin_circuit_t *circ)
if (cur_len == state->desired_path_len - 1) { /* Picking last node */
info = extend_info_dup(state->chosen_exit);
} else if (cur_len == 0) { /* picking first node */
- routerinfo_t *r = choose_good_entry_server(purpose, state);
- if (r)
- info = extend_info_from_router(r);
+ const node_t *r = choose_good_entry_server(purpose, state);
+ if (r) {
+ /* If we're extending to a bridge, use the preferred address
+ rather than the primary, for potentially extending to an IPv6
+ bridge. */
+ int use_pref_addr = (r->ri != NULL &&
+ r->ri->purpose == ROUTER_PURPOSE_BRIDGE);
+ info = extend_info_from_node(r, use_pref_addr);
+ tor_assert(info);
+ }
} else {
- routerinfo_t *r =
+ const node_t *r =
choose_good_middle_server(purpose, state, circ->cpath, cur_len);
- if (r)
- info = extend_info_from_router(r);
+ if (r) {
+ info = extend_info_from_node(r, 0);
+ tor_assert(info);
+ }
}
if (!info) {
@@ -3292,7 +3306,7 @@ onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice)
/** Allocate a new extend_info object based on the various arguments. */
extend_info_t *
extend_info_alloc(const char *nickname, const char *digest,
- crypto_pk_env_t *onion_key,
+ crypto_pk_t *onion_key,
const tor_addr_t *addr, uint16_t port)
{
extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t));
@@ -3306,16 +3320,47 @@ extend_info_alloc(const char *nickname, const char *digest,
return info;
}
-/** Allocate and return a new extend_info_t that can be used to build a
- * circuit to or through the router <b>r</b>. */
+/** Allocate and return a new extend_info_t that can be used to build
+ * a circuit to or through the router <b>r</b>. Use the primary
+ * address of the router unless <b>for_direct_connect</b> is true, in
+ * which case the preferred address is used instead. */
extend_info_t *
-extend_info_from_router(routerinfo_t *r)
+extend_info_from_router(const routerinfo_t *r, int for_direct_connect)
{
- tor_addr_t addr;
+ tor_addr_port_t ap;
tor_assert(r);
- tor_addr_from_ipv4h(&addr, r->addr);
+
+ if (for_direct_connect)
+ router_get_pref_orport(r, &ap);
+ else
+ router_get_prim_orport(r, &ap);
return extend_info_alloc(r->nickname, r->cache_info.identity_digest,
- r->onion_pkey, &addr, r->or_port);
+ r->onion_pkey, &ap.addr, ap.port);
+}
+
+/** Allocate and return a new extend_info that can be used to build a
+ * circuit to or through the node <b>node</b>. Use the primary address
+ * of the node unless <b>for_direct_connect</b> is true, in which case
+ * the preferred address is used instead. May return NULL if there is
+ * not enough info about <b>node</b> to extend to it--for example, if
+ * there is no routerinfo_t or microdesc_t.
+ **/
+extend_info_t *
+extend_info_from_node(const node_t *node, int for_direct_connect)
+{
+ if (node->ri) {
+ return extend_info_from_router(node->ri, for_direct_connect);
+ } else if (node->rs && node->md) {
+ tor_addr_t addr;
+ tor_addr_from_ipv4h(&addr, node->rs->addr);
+ return extend_info_alloc(node->rs->nickname,
+ node->identity,
+ node->md->onion_pkey,
+ &addr,
+ node->rs->or_port);
+ } else {
+ return NULL;
+ }
}
/** Release storage held by an extend_info_t struct. */
@@ -3324,7 +3369,7 @@ extend_info_free(extend_info_t *info)
{
if (!info)
return;
- crypto_free_pk_env(info->onion_key);
+ crypto_pk_free(info->onion_key);
tor_free(info);
}
@@ -3348,12 +3393,12 @@ extend_info_dup(extend_info_t *info)
* If there is no chosen exit, or if we don't know the routerinfo_t for
* the chosen exit, return NULL.
*/
-routerinfo_t *
-build_state_get_exit_router(cpath_build_state_t *state)
+const node_t *
+build_state_get_exit_node(cpath_build_state_t *state)
{
if (!state || !state->chosen_exit)
return NULL;
- return router_get_by_digest(state->chosen_exit->identity_digest);
+ return node_get_by_id(state->chosen_exit->identity_digest);
}
/** Return the nickname for the chosen exit router in <b>state</b>. If
@@ -3375,10 +3420,10 @@ build_state_get_exit_nickname(cpath_build_state_t *state)
*
* If it's not usable, set *<b>reason</b> to a static string explaining why.
*/
-/*XXXX take a routerstatus, not a routerinfo. */
static int
-entry_guard_set_status(entry_guard_t *e, routerinfo_t *ri,
- time_t now, or_options_t *options, const char **reason)
+entry_guard_set_status(entry_guard_t *e, const node_t *node,
+ time_t now, const or_options_t *options,
+ const char **reason)
{
char buf[HEX_DIGEST_LEN+1];
int changed = 0;
@@ -3386,18 +3431,19 @@ entry_guard_set_status(entry_guard_t *e, routerinfo_t *ri,
*reason = NULL;
/* Do we want to mark this guard as bad? */
- if (!ri)
+ if (!node)
*reason = "unlisted";
- else if (!ri->is_running)
+ else if (!node->is_running)
*reason = "down";
- else if (options->UseBridges && ri->purpose != ROUTER_PURPOSE_BRIDGE)
+ else if (options->UseBridges && (!node->ri ||
+ node->ri->purpose != ROUTER_PURPOSE_BRIDGE))
*reason = "not a bridge";
- else if (options->UseBridges && !routerinfo_is_a_configured_bridge(ri))
+ else if (options->UseBridges && !node_is_a_configured_bridge(node))
*reason = "not a configured bridge";
- else if (!options->UseBridges && !ri->is_possible_guard &&
- !routerset_contains_router(options->EntryNodes,ri))
+ else if (!options->UseBridges && !node->is_possible_guard &&
+ !routerset_contains_node(options->EntryNodes,node))
*reason = "not recommended as a guard";
- else if (routerset_contains_router(options->ExcludeNodes, ri))
+ else if (routerset_contains_node(options->ExcludeNodes, node))
*reason = "excluded";
if (*reason && ! e->bad_since) {
@@ -3441,7 +3487,7 @@ entry_is_time_to_retry(entry_guard_t *e, time_t now)
return now > (e->last_attempted + 36*60*60);
}
-/** Return the router corresponding to <b>e</b>, if <b>e</b> is
+/** Return the node corresponding to <b>e</b>, if <b>e</b> is
* working well enough that we are willing to use it as an entry
* right now. (Else return NULL.) In particular, it must be
* - Listed as either up or never yet contacted;
@@ -3455,12 +3501,12 @@ entry_is_time_to_retry(entry_guard_t *e, time_t now)
*
* If the answer is no, set *<b>msg</b> to an explanation of why.
*/
-static INLINE routerinfo_t *
+static INLINE const node_t *
entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity,
int assume_reachable, const char **msg)
{
- routerinfo_t *r;
- or_options_t *options = get_options();
+ const node_t *node;
+ const or_options_t *options = get_options();
tor_assert(msg);
if (e->bad_since) {
@@ -3473,38 +3519,39 @@ entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity,
*msg = "unreachable";
return NULL;
}
- r = router_get_by_digest(e->identity);
- if (!r) {
+ node = node_get_by_id(e->identity);
+ if (!node || !node_has_descriptor(node)) {
*msg = "no descriptor";
return NULL;
}
- if (options->UseBridges) {
- if (r->purpose != ROUTER_PURPOSE_BRIDGE) {
+ if (get_options()->UseBridges) {
+ if (node_get_purpose(node) != ROUTER_PURPOSE_BRIDGE) {
*msg = "not a bridge";
return NULL;
}
- if (!routerinfo_is_a_configured_bridge(r)) {
+ if (!node_is_a_configured_bridge(node)) {
*msg = "not a configured bridge";
return NULL;
}
- } else if (r->purpose != ROUTER_PURPOSE_GENERAL) {
- *msg = "not general-purpose";
- return NULL;
+ } else { /* !get_options()->UseBridges */
+ if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) {
+ *msg = "not general-purpose";
+ return NULL;
+ }
}
- if (options->EntryNodes &&
- routerset_contains_router(options->EntryNodes, r)) {
+ if (routerset_contains_node(options->EntryNodes, node)) {
/* they asked for it, they get it */
need_uptime = need_capacity = 0;
}
- if (router_is_unreliable(r, need_uptime, need_capacity, 0)) {
+ if (node_is_unreliable(node, need_uptime, need_capacity, 0)) {
*msg = "not fast/stable";
return NULL;
}
- if (!fascist_firewall_allows_or(r)) {
+ if (!fascist_firewall_allows_node(node)) {
*msg = "unreachable by config";
return NULL;
}
- return r;
+ return node;
}
/** Return the number of entry guards that we think are usable. */
@@ -3540,25 +3587,23 @@ is_an_entry_guard(const char *digest)
static void
log_entry_guards(int severity)
{
- smartlist_t *elements = smartlist_create();
+ smartlist_t *elements = smartlist_new();
char *s;
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e)
{
const char *msg = NULL;
- char *cp;
if (entry_is_live(e, 0, 1, 0, &msg))
- tor_asprintf(&cp, "%s [%s] (up %s)",
+ smartlist_add_asprintf(elements, "%s [%s] (up %s)",
e->nickname,
hex_str(e->identity, DIGEST_LEN),
e->made_contact ? "made-contact" : "never-contacted");
else
- tor_asprintf(&cp, "%s [%s] (%s, %s)",
+ smartlist_add_asprintf(elements, "%s [%s] (%s, %s)",
e->nickname,
hex_str(e->identity, DIGEST_LEN),
msg,
e->made_contact ? "made-contact" : "never-contacted");
- smartlist_add(elements, cp);
}
SMARTLIST_FOREACH_END(e);
@@ -3584,7 +3629,7 @@ control_event_guard_deferred(void)
#if 0
int n = 0;
const char *msg;
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
if (!entry_guards)
return;
SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry,
@@ -3606,15 +3651,15 @@ control_event_guard_deferred(void)
* If <b>chosen</b> is defined, use that one, and if it's not
* already in our entry_guards list, put it at the *beginning*.
* Else, put the one we pick at the end of the list. */
-static routerinfo_t *
-add_an_entry_guard(routerinfo_t *chosen, int reset_status)
+static const node_t *
+add_an_entry_guard(const node_t *chosen, int reset_status, int prepend)
{
- routerinfo_t *router;
+ const node_t *node;
entry_guard_t *entry;
if (chosen) {
- router = chosen;
- entry = is_an_entry_guard(router->cache_info.identity_digest);
+ node = chosen;
+ entry = is_an_entry_guard(node->identity);
if (entry) {
if (reset_status) {
entry->bad_since = 0;
@@ -3623,15 +3668,15 @@ add_an_entry_guard(routerinfo_t *chosen, int reset_status)
return NULL;
}
} else {
- router = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL);
- if (!router)
+ node = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL);
+ if (!node)
return NULL;
}
entry = tor_malloc_zero(sizeof(entry_guard_t));
- log_info(LD_CIRC, "Chose '%s' as new entry guard.",
- router_describe(router));
- strlcpy(entry->nickname, router->nickname, sizeof(entry->nickname));
- memcpy(entry->identity, router->cache_info.identity_digest, DIGEST_LEN);
+ log_info(LD_CIRC, "Chose %s as new entry guard.",
+ node_describe(node));
+ strlcpy(entry->nickname, node_get_nickname(node), sizeof(entry->nickname));
+ memcpy(entry->identity, node->identity, DIGEST_LEN);
/* Choose expiry time smudged over the past month. The goal here
* is to a) spread out when Tor clients rotate their guards, so they
* don't all select them on the same day, and b) avoid leaving a
@@ -3639,27 +3684,27 @@ add_an_entry_guard(routerinfo_t *chosen, int reset_status)
* this guard. For details, see the Jan 2010 or-dev thread. */
entry->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30);
entry->chosen_by_version = tor_strdup(VERSION);
- if (chosen) /* prepend */
+ if (prepend)
smartlist_insert(entry_guards, 0, entry);
- else /* append */
+ else
smartlist_add(entry_guards, entry);
control_event_guard(entry->nickname, entry->identity, "NEW");
control_event_guard_deferred();
log_entry_guards(LOG_INFO);
- return router;
+ return node;
}
/** If the use of entry guards is configured, choose more entry guards
* until we have enough in the list. */
static void
-pick_entry_guards(or_options_t *options)
+pick_entry_guards(const or_options_t *options)
{
int changed = 0;
tor_assert(entry_guards);
while (num_live_entry_guards() < options->NumEntryGuards) {
- if (!add_an_entry_guard(NULL, 0))
+ if (!add_an_entry_guard(NULL, 0, 0))
break;
changed = 1;
}
@@ -3702,9 +3747,8 @@ remove_obsolete_entry_guards(time_t now)
msg = "does not seem to be from any recognized version of Tor";
version_is_bad = 1;
} else {
- size_t len = strlen(ver)+5;
- char *tor_ver = tor_malloc(len);
- tor_snprintf(tor_ver, len, "Tor %s", ver);
+ char *tor_ver = NULL;
+ tor_asprintf(&tor_ver, "Tor %s", ver);
if ((tor_version_as_new_as(tor_ver, "0.1.0.10-alpha") &&
!tor_version_as_new_as(tor_ver, "0.1.2.16-dev")) ||
(tor_version_as_new_as(tor_ver, "0.2.0.0-alpha") &&
@@ -3785,7 +3829,7 @@ remove_dead_entry_guards(time_t now)
* think that things are unlisted.
*/
void
-entry_guards_compute_status(or_options_t *options, time_t now)
+entry_guards_compute_status(const or_options_t *options, time_t now)
{
int changed = 0;
digestmap_t *reasons;
@@ -3799,7 +3843,7 @@ entry_guards_compute_status(or_options_t *options, time_t now)
reasons = digestmap_new();
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry)
{
- routerinfo_t *r = router_get_by_digest(entry->identity);
+ const node_t *r = node_get_by_id(entry->identity);
const char *reason = NULL;
if (entry_guard_set_status(entry, r, now, options, &reason))
changed = 1;
@@ -3818,7 +3862,7 @@ entry_guards_compute_status(or_options_t *options, time_t now)
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
const char *reason = digestmap_get(reasons, entry->identity);
const char *live_msg = "";
- routerinfo_t *r = entry_is_live(entry, 0, 1, 0, &live_msg);
+ const node_t *r = entry_is_live(entry, 0, 1, 0, &live_msg);
log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.",
entry->nickname,
hex_str(entry->identity, DIGEST_LEN),
@@ -3936,7 +3980,7 @@ entry_guard_register_connect_status(const char *digest, int succeeded,
break;
if (e->made_contact) {
const char *msg;
- routerinfo_t *r = entry_is_live(e, 0, 1, 1, &msg);
+ const node_t *r = entry_is_live(e, 0, 1, 1, &msg);
if (r && e->unreachable_since) {
refuse_conn = 1;
e->can_retry = 1;
@@ -3972,12 +4016,12 @@ entry_nodes_should_be_added(void)
should_add_entry_nodes = 1;
}
-/** Add all nodes in EntryNodes that aren't currently guard nodes to the list
- * of guard nodes, at the front. */
+/** Adjust the entry guards list so that it only contains entries from
+ * EntryNodes, adding new entries from EntryNodes to the list as needed. */
static void
-entry_guards_prepend_from_config(or_options_t *options)
+entry_guards_set_from_config(const or_options_t *options)
{
- smartlist_t *entry_routers, *entry_fps;
+ smartlist_t *entry_nodes, *worse_entry_nodes, *entry_fps;
smartlist_t *old_entry_guards_on_list, *old_entry_guards_not_on_list;
tor_assert(entry_guards);
@@ -3997,23 +4041,19 @@ entry_guards_prepend_from_config(or_options_t *options)
tor_free(string);
}
- entry_routers = smartlist_create();
- entry_fps = smartlist_create();
- old_entry_guards_on_list = smartlist_create();
- old_entry_guards_not_on_list = smartlist_create();
+ entry_nodes = smartlist_new();
+ worse_entry_nodes = smartlist_new();
+ entry_fps = smartlist_new();
+ old_entry_guards_on_list = smartlist_new();
+ old_entry_guards_not_on_list = smartlist_new();
/* Split entry guards into those on the list and those not. */
- /* XXXX023 Now that we allow countries and IP ranges in EntryNodes, this is
- * potentially an enormous list. For now, we disable such values for
- * EntryNodes in options_validate(); really, this wants a better solution.
- * Perhaps we should do this calculation once whenever the list of routers
- * changes or the entrynodes setting changes.
- */
- routerset_get_all_routers(entry_routers, options->EntryNodes,
- options->ExcludeNodes, 0);
- SMARTLIST_FOREACH(entry_routers, routerinfo_t *, ri,
- smartlist_add(entry_fps,ri->cache_info.identity_digest));
+ routerset_get_all_nodes(entry_nodes, options->EntryNodes,
+ options->ExcludeNodes, 0);
+ SMARTLIST_FOREACH(entry_nodes, const node_t *,node,
+ smartlist_add(entry_fps, (void*)node->identity));
+
SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, {
if (smartlist_digest_isin(entry_fps, e->identity))
smartlist_add(old_entry_guards_on_list, e);
@@ -4021,27 +4061,47 @@ entry_guards_prepend_from_config(or_options_t *options)
smartlist_add(old_entry_guards_not_on_list, e);
});
- /* Remove all currently configured entry guards from entry_routers. */
- SMARTLIST_FOREACH(entry_routers, routerinfo_t *, ri, {
- if (is_an_entry_guard(ri->cache_info.identity_digest)) {
- SMARTLIST_DEL_CURRENT(entry_routers, ri);
+ /* Remove all currently configured guard nodes, excluded nodes, unreachable
+ * nodes, or non-Guard nodes from entry_nodes. */
+ SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) {
+ if (is_an_entry_guard(node->identity)) {
+ SMARTLIST_DEL_CURRENT(entry_nodes, node);
+ continue;
+ } else if (routerset_contains_node(options->ExcludeNodes, node)) {
+ SMARTLIST_DEL_CURRENT(entry_nodes, node);
+ continue;
+ } else if (!fascist_firewall_allows_node(node)) {
+ SMARTLIST_DEL_CURRENT(entry_nodes, node);
+ continue;
+ } else if (! node->is_possible_guard) {
+ smartlist_add(worse_entry_nodes, (node_t*)node);
+ SMARTLIST_DEL_CURRENT(entry_nodes, node);
}
- });
+ } SMARTLIST_FOREACH_END(node);
/* Now build the new entry_guards list. */
smartlist_clear(entry_guards);
/* First, the previously configured guards that are in EntryNodes. */
smartlist_add_all(entry_guards, old_entry_guards_on_list);
+ /* Next, scramble the rest of EntryNodes, putting the guards first. */
+ smartlist_shuffle(entry_nodes);
+ smartlist_shuffle(worse_entry_nodes);
+ smartlist_add_all(entry_nodes, worse_entry_nodes);
+
/* Next, the rest of EntryNodes */
- SMARTLIST_FOREACH(entry_routers, routerinfo_t *, ri, {
- add_an_entry_guard(ri, 0);
- });
+ SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) {
+ add_an_entry_guard(node, 0, 0);
+ if (smartlist_len(entry_guards) > options->NumEntryGuards * 10)
+ break;
+ } SMARTLIST_FOREACH_END(node);
+ log_notice(LD_GENERAL, "%d entries in guards", smartlist_len(entry_guards));
/* Finally, free the remaining previously configured guards that are not in
* EntryNodes. */
SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e,
entry_guard_free(e));
- smartlist_free(entry_routers);
+ smartlist_free(entry_nodes);
+ smartlist_free(worse_entry_nodes);
smartlist_free(entry_fps);
smartlist_free(old_entry_guards_on_list);
smartlist_free(old_entry_guards_not_on_list);
@@ -4053,7 +4113,7 @@ entry_guards_prepend_from_config(or_options_t *options)
* list already and we must stick to it.
*/
int
-entry_list_is_constrained(or_options_t *options)
+entry_list_is_constrained(const or_options_t *options)
{
if (options->EntryNodes)
return 1;
@@ -4067,28 +4127,29 @@ entry_list_is_constrained(or_options_t *options)
* make sure not to pick this circuit's exit or any node in the
* exit's family. If <b>state</b> is NULL, we're looking for a random
* guard (likely a bridge). */
-routerinfo_t *
+const node_t *
choose_random_entry(cpath_build_state_t *state)
{
- or_options_t *options = get_options();
- smartlist_t *live_entry_guards = smartlist_create();
- smartlist_t *exit_family = smartlist_create();
- routerinfo_t *chosen_exit = state?build_state_get_exit_router(state) : NULL;
- routerinfo_t *r = NULL;
+ const or_options_t *options = get_options();
+ smartlist_t *live_entry_guards = smartlist_new();
+ smartlist_t *exit_family = smartlist_new();
+ const node_t *chosen_exit =
+ state?build_state_get_exit_node(state) : NULL;
+ const node_t *node = NULL;
int need_uptime = state ? state->need_uptime : 0;
int need_capacity = state ? state->need_capacity : 0;
int preferred_min, consider_exit_family = 0;
if (chosen_exit) {
- routerlist_add_family(exit_family, chosen_exit);
+ nodelist_add_node_and_family(exit_family, chosen_exit);
consider_exit_family = 1;
}
if (!entry_guards)
- entry_guards = smartlist_create();
+ entry_guards = smartlist_new();
if (should_add_entry_nodes)
- entry_guards_prepend_from_config(options);
+ entry_guards_set_from_config(options);
if (!entry_list_is_constrained(options) &&
smartlist_len(entry_guards) < options->NumEntryGuards)
@@ -4096,25 +4157,24 @@ choose_random_entry(cpath_build_state_t *state)
retry:
smartlist_clear(live_entry_guards);
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry)
- {
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
const char *msg;
- r = entry_is_live(entry, need_uptime, need_capacity, 0, &msg);
- if (!r)
+ node = entry_is_live(entry, need_uptime, need_capacity, 0, &msg);
+ if (!node)
continue; /* down, no point */
- if (r == chosen_exit)
+ if (node == chosen_exit)
continue; /* don't pick the same node for entry and exit */
- if (consider_exit_family && smartlist_isin(exit_family, r))
+ if (consider_exit_family && smartlist_isin(exit_family, node))
continue; /* avoid relays that are family members of our exit */
#if 0 /* since EntryNodes is always strict now, this clause is moot */
if (options->EntryNodes &&
- !routerset_contains_router(options->EntryNodes, r)) {
+ !routerset_contains_node(options->EntryNodes, node)) {
/* We've come to the end of our preferred entry nodes. */
if (smartlist_len(live_entry_guards))
goto choose_and_finish; /* only choose from the ones we like */
if (options->StrictNodes) {
/* in theory this case should never happen, since
- * entry_guards_prepend_from_config() drops unwanted relays */
+ * entry_guards_set_from_config() drops unwanted relays */
tor_fragile_assert();
} else {
log_info(LD_CIRC,
@@ -4122,7 +4182,7 @@ choose_random_entry(cpath_build_state_t *state)
}
}
#endif
- smartlist_add(live_entry_guards, r);
+ smartlist_add(live_entry_guards, (void*)node);
if (!entry->made_contact) {
/* Always start with the first not-yet-contacted entry
* guard. Otherwise we might add several new ones, pick
@@ -4131,9 +4191,8 @@ choose_random_entry(cpath_build_state_t *state)
goto choose_and_finish;
}
if (smartlist_len(live_entry_guards) >= options->NumEntryGuards)
- break; /* we have enough */
- }
- SMARTLIST_FOREACH_END(entry);
+ goto choose_and_finish; /* we have enough */
+ } SMARTLIST_FOREACH_END(entry);
if (entry_list_is_constrained(options)) {
/* If we prefer the entry nodes we've got, and we have at least
@@ -4153,8 +4212,8 @@ choose_random_entry(cpath_build_state_t *state)
/* XXX if guard doesn't imply fast and stable, then we need
* to tell add_an_entry_guard below what we want, or it might
* be a long time til we get it. -RD */
- r = add_an_entry_guard(NULL, 0);
- if (r) {
+ node = add_an_entry_guard(NULL, 0, 0);
+ if (node) {
entry_guards_changed();
/* XXX we start over here in case the new node we added shares
* a family with our exit node. There's a chance that we'll just
@@ -4164,11 +4223,11 @@ choose_random_entry(cpath_build_state_t *state)
goto retry;
}
}
- if (!r && need_uptime) {
+ if (!node && need_uptime) {
need_uptime = 0; /* try without that requirement */
goto retry;
}
- if (!r && need_capacity) {
+ if (!node && need_capacity) {
/* still no? last attempt, try without requiring capacity */
need_capacity = 0;
goto retry;
@@ -4177,10 +4236,10 @@ choose_random_entry(cpath_build_state_t *state)
/* Removing this retry logic: if we only allow one exit, and it is in the
same family as all our entries, then we are just plain not going to win
here. */
- if (!r && entry_list_is_constrained(options) && consider_exit_family) {
- /* still no? if we're using bridges,
- * and our chosen exit is in the same family as all our
- * bridges, then be flexible about families. */
+ if (!node && entry_list_is_constrained(options) && consider_exit_family) {
+ /* still no? if we're using bridges or have strictentrynodes
+ * set, and our chosen exit is in the same family as all our
+ * bridges/entry guards, then be flexible about families. */
consider_exit_family = 0;
goto retry;
}
@@ -4192,16 +4251,16 @@ choose_random_entry(cpath_build_state_t *state)
if (entry_list_is_constrained(options)) {
/* We need to weight by bandwidth, because our bridges or entryguards
* were not already selected proportional to their bandwidth. */
- r = routerlist_sl_choose_by_bandwidth(live_entry_guards, WEIGHT_FOR_GUARD);
+ node = node_sl_choose_by_bandwidth(live_entry_guards, WEIGHT_FOR_GUARD);
} else {
/* We choose uniformly at random here, because choose_good_entry_server()
* already weights its choices by bandwidth, so we don't want to
* *double*-weight our guard selection. */
- r = smartlist_choose(live_entry_guards);
+ node = smartlist_choose(live_entry_guards);
}
smartlist_free(live_entry_guards);
smartlist_free(exit_family);
- return r;
+ return node;
}
/** Parse <b>state</b> and learn about the entry guards it describes.
@@ -4214,7 +4273,7 @@ int
entry_guards_parse_state(or_state_t *state, int set, char **msg)
{
entry_guard_t *node = NULL;
- smartlist_t *new_entry_guards = smartlist_create();
+ smartlist_t *new_entry_guards = smartlist_new();
config_line_t *line;
time_t now = time(NULL);
const char *state_version = state->TorVersion;
@@ -4223,7 +4282,7 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
*msg = NULL;
for (line = state->EntryGuards; line; line = line->next) {
if (!strcasecmp(line->key, "EntryGuard")) {
- smartlist_t *args = smartlist_create();
+ smartlist_t *args = smartlist_new();
node = tor_malloc_zero(sizeof(entry_guard_t));
/* all entry guards on disk have been contacted */
node->made_contact = 1;
@@ -4369,7 +4428,7 @@ entry_guards_update_state(or_state_t *state)
next = &state->EntryGuards;
*next = NULL;
if (!entry_guards)
- entry_guards = smartlist_create();
+ entry_guards = smartlist_new();
SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
{
char dbuf[HEX_DIGEST_LEN+1];
@@ -4377,10 +4436,8 @@ entry_guards_update_state(or_state_t *state)
continue; /* don't write this one to disk */
*next = line = tor_malloc_zero(sizeof(config_line_t));
line->key = tor_strdup("EntryGuard");
- line->value = tor_malloc(HEX_DIGEST_LEN+MAX_NICKNAME_LEN+2);
base16_encode(dbuf, sizeof(dbuf), e->identity, DIGEST_LEN);
- tor_snprintf(line->value,HEX_DIGEST_LEN+MAX_NICKNAME_LEN+2,
- "%s %s", e->nickname, dbuf);
+ tor_asprintf(&line->value, "%s %s", e->nickname, dbuf);
next = &(line->next);
if (e->unreachable_since) {
*next = line = tor_malloc_zero(sizeof(config_line_t));
@@ -4404,15 +4461,11 @@ entry_guards_update_state(or_state_t *state)
!strchr(e->chosen_by_version, ' ')) {
char d[HEX_DIGEST_LEN+1];
char t[ISO_TIME_LEN+1];
- size_t val_len;
*next = line = tor_malloc_zero(sizeof(config_line_t));
line->key = tor_strdup("EntryGuardAddedBy");
- val_len = (HEX_DIGEST_LEN+1+strlen(e->chosen_by_version)
- +1+ISO_TIME_LEN+1);
- line->value = tor_malloc(val_len);
base16_encode(d, sizeof(d), e->identity, DIGEST_LEN);
format_iso_time(t, e->chosen_on_date);
- tor_snprintf(line->value, val_len, "%s %s %s",
+ tor_asprintf(&line->value, "%s %s %s",
d, e->chosen_by_version, t);
next = &(line->next);
}
@@ -4438,17 +4491,15 @@ getinfo_helper_entry_guards(control_connection_t *conn,
if (!strcmp(question,"entry-guards") ||
!strcmp(question,"helper-nodes")) {
- smartlist_t *sl = smartlist_create();
+ smartlist_t *sl = smartlist_new();
char tbuf[ISO_TIME_LEN+1];
char nbuf[MAX_VERBOSE_NICKNAME_LEN+1];
if (!entry_guards)
- entry_guards = smartlist_create();
+ entry_guards = smartlist_new();
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
- size_t len = MAX_VERBOSE_NICKNAME_LEN+ISO_TIME_LEN+32;
- char *c = tor_malloc(len);
const char *status = NULL;
time_t when = 0;
- routerinfo_t *ri;
+ const node_t *node;
if (!e->made_contact) {
status = "never-connected";
@@ -4459,9 +4510,9 @@ getinfo_helper_entry_guards(control_connection_t *conn,
status = "up";
}
- ri = router_get_by_digest(e->identity);
- if (ri) {
- router_get_verbose_nickname(nbuf, ri);
+ node = node_get_by_id(e->identity);
+ if (node) {
+ node_get_verbose_nickname(node, nbuf);
} else {
nbuf[0] = '$';
base16_encode(nbuf+1, sizeof(nbuf)-1, e->identity, DIGEST_LEN);
@@ -4471,11 +4522,10 @@ getinfo_helper_entry_guards(control_connection_t *conn,
if (when) {
format_iso_time(tbuf, when);
- tor_snprintf(c, len, "%s %s %s\n", nbuf, status, tbuf);
+ smartlist_add_asprintf(sl, "%s %s %s\n", nbuf, status, tbuf);
} else {
- tor_snprintf(c, len, "%s %s\n", nbuf, status);
+ smartlist_add_asprintf(sl, "%s %s\n", nbuf, status);
}
- smartlist_add(sl, c);
} SMARTLIST_FOREACH_END(e);
*answer = smartlist_join_strings(sl, "", 0, NULL);
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
@@ -4484,24 +4534,6 @@ getinfo_helper_entry_guards(control_connection_t *conn,
return 0;
}
-/** Information about a configured bridge. Currently this just matches the
- * ones in the torrc file, but one day we may be able to learn about new
- * bridges on our own, and remember them in the state file. */
-typedef struct {
- /** Address of the bridge. */
- tor_addr_t addr;
- /** TLS port for the bridge. */
- uint16_t port;
- /** Boolean: We are re-parsing our bridge list, and we are going to remove
- * this one if we don't find it in the list of configured bridges. */
- unsigned marked_for_removal : 1;
- /** Expected identity digest, or all zero bytes if we don't know what the
- * digest should be. */
- char identity[DIGEST_LEN];
- /** When should we next try to fetch a descriptor for this bridge? */
- download_status_t fetch_status;
-} bridge_info_t;
-
/** A list of configured bridges. Whenever we actually get a descriptor
* for one, we add it as an entry guard. Note that the order of bridges
* in this list does not necessarily correspond to the order of bridges
@@ -4514,7 +4546,7 @@ void
mark_bridge_list(void)
{
if (!bridge_list)
- bridge_list = smartlist_create();
+ bridge_list = smartlist_new();
SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b,
b->marked_for_removal = 1);
}
@@ -4525,11 +4557,11 @@ void
sweep_bridge_list(void)
{
if (!bridge_list)
- bridge_list = smartlist_create();
+ bridge_list = smartlist_new();
SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, b) {
if (b->marked_for_removal) {
SMARTLIST_DEL_CURRENT(bridge_list, b);
- tor_free(b);
+ bridge_free(b);
}
} SMARTLIST_FOREACH_END(b);
}
@@ -4539,11 +4571,244 @@ static void
clear_bridge_list(void)
{
if (!bridge_list)
- bridge_list = smartlist_create();
- SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, tor_free(b));
+ bridge_list = smartlist_new();
+ SMARTLIST_FOREACH(bridge_list, bridge_info_t *, b, bridge_free(b));
smartlist_clear(bridge_list);
}
+/** Free the bridge <b>bridge</b>. */
+static void
+bridge_free(bridge_info_t *bridge)
+{
+ if (!bridge)
+ return;
+
+ tor_free(bridge->transport_name);
+ 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;
+ }
+}
+
+/** 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)
+{
+ /* 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)
+ continue;
+ /* See if the user has Bridges that specify nonexistent
+ pluggable transports. We should warn the user in such case,
+ since it's probably misconfiguration. */
+ if (!transport_get_by_name(b->transport_name))
+ log_warn(LD_CONFIG, "You have a Bridge line using the %s "
+ "pluggable transport, but there doesn't seem to be a "
+ "corresponding ClientTransportPlugin line.",
+ b->transport_name);
+ } SMARTLIST_FOREACH_END(b);
+
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
/** 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).
* Else return NULL. */
@@ -4570,21 +4835,53 @@ get_configured_bridge_by_addr_port_digest(const tor_addr_t *addr,
/** Wrapper around get_configured_bridge_by_addr_port_digest() to look
* it up via router descriptor <b>ri</b>. */
static bridge_info_t *
-get_configured_bridge_by_routerinfo(routerinfo_t *ri)
+get_configured_bridge_by_routerinfo(const routerinfo_t *ri)
{
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, ri->addr);
- return get_configured_bridge_by_addr_port_digest(&addr,
- ri->or_port, ri->cache_info.identity_digest);
+ tor_addr_port_t ap;
+
+ router_get_pref_orport(ri, &ap);
+ return get_configured_bridge_by_addr_port_digest(&ap.addr, ap.port,
+ ri->cache_info.identity_digest);
}
/** Return 1 if <b>ri</b> is one of our known bridges, else 0. */
int
-routerinfo_is_a_configured_bridge(routerinfo_t *ri)
+routerinfo_is_a_configured_bridge(const routerinfo_t *ri)
{
return get_configured_bridge_by_routerinfo(ri) ? 1 : 0;
}
+/** Return 1 if <b>node</b> is one of our configured bridges, else 0. */
+int
+node_is_a_configured_bridge(const node_t *node)
+{
+ int retval = 0; /* Negative. */
+ smartlist_t *orports = NULL;
+
+ if (!node)
+ goto out;
+
+ orports = node_get_all_orports(node);
+ if (orports == NULL)
+ goto out;
+
+ SMARTLIST_FOREACH_BEGIN(orports, tor_addr_port_t *, orport) {
+ if (get_configured_bridge_by_addr_port_digest(&orport->addr, orport->port,
+ node->identity) != NULL) {
+ retval = 1;
+ goto out;
+ }
+ } SMARTLIST_FOREACH_END(orport);
+
+ out:
+ if (orports != NULL) {
+ SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p));
+ smartlist_free(orports);
+ orports = NULL;
+ }
+ return retval;
+}
+
/** We made a connection to a router at <b>addr</b>:<b>port</b>
* without knowing its digest. Its digest turned out to be <b>digest</b>.
* If it was a bridge, and we still don't know its digest, record it.
@@ -4604,10 +4901,12 @@ learned_router_identity(const tor_addr_t *addr, uint16_t port,
/** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
* is set, it tells us the identity key too. If we already had the
- * bridge in our list, unmark it, and don't actually add anything new. */
+ * bridge in our list, unmark it, and don't actually add anything new.
+ * If <b>transport_name</b> is non-NULL - the bridge is associated with a
+ * pluggable transport - we assign the transport to the bridge. */
void
bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *digest)
+ const char *digest, const char *transport_name)
{
bridge_info_t *b;
@@ -4621,9 +4920,11 @@ bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
b->port = port;
if (digest)
memcpy(b->identity, digest, DIGEST_LEN);
+ if (transport_name)
+ b->transport_name = tor_strdup(transport_name);
b->fetch_status.schedule = DL_SCHED_BRIDGE;
if (!bridge_list)
- bridge_list = smartlist_create();
+ bridge_list = smartlist_new();
smartlist_add(bridge_list, b);
}
@@ -4658,12 +4959,48 @@ find_bridge_by_digest(const char *digest)
return NULL;
}
+/** If <b>addr</b> and <b>port</b> match the address and port of a
+ * bridge of ours that uses pluggable transports, place its transport
+ * in <b>transport</b>.
+ *
+ * Return 0 on success (found a transport, or found a bridge with no
+ * transport, or found no bridge); return -1 if we should be using a
+ * transport, but the transport could not be found.
+ */
+int
+find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
+ const transport_t **transport)
+{
+ *transport = NULL;
+ if (!bridge_list)
+ return 0;
+
+ SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) {
+ if (tor_addr_eq(&bridge->addr, addr) &&
+ (bridge->port == port)) { /* bridge matched */
+ if (bridge->transport_name) { /* it also uses pluggable transports */
+ *transport = transport_get_by_name(bridge->transport_name);
+ if (*transport == NULL) { /* it uses pluggable transports, but
+ the transport could not be found! */
+ return -1;
+ }
+ return 0;
+ } else { /* bridge matched, but it doesn't use transports. */
+ break;
+ }
+ }
+ } SMARTLIST_FOREACH_END(bridge);
+
+ *transport = NULL;
+ return 0;
+}
+
/** We need to ask <b>bridge</b> for its server descriptor. */
static void
launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
{
char *address;
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
if (connection_get_by_type_addr_port_purpose(
CONN_TYPE_DIR, &bridge->addr, bridge->port,
@@ -4705,15 +5042,20 @@ retry_bridge_descriptor_fetch_directly(const char *digest)
* descriptor, fetch a new copy of its descriptor -- either directly
* from the bridge or via a bridge authority. */
void
-fetch_bridge_descriptors(or_options_t *options, time_t now)
+fetch_bridge_descriptors(const or_options_t *options, time_t now)
{
- int num_bridge_auths = get_n_authorities(BRIDGE_AUTHORITY);
+ int num_bridge_auths = get_n_authorities(BRIDGE_DIRINFO);
int ask_bridge_directly;
int can_use_bridge_authority;
if (!bridge_list)
return;
+ /* 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,
@@ -4772,26 +5114,89 @@ fetch_bridge_descriptors(or_options_t *options, time_t now)
}
/** If our <b>bridge</b> is configured to be a different address than
- * the bridge gives in its routerinfo <b>ri</b>, rewrite the routerinfo
+ * the bridge gives in <b>node</b>, rewrite the routerinfo
* we received to use the address we meant to use. Now we handle
* multihomed bridges better.
*/
static void
-rewrite_routerinfo_address_for_bridge(bridge_info_t *bridge, routerinfo_t *ri)
+rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
{
+ /* XXXX move this function. */
+ /* XXXX overridden addresses should really live in the node_t, so that the
+ * routerinfo_t and the microdesc_t can be immutable. But we can only
+ * do that safely if we know that no function that connects to an OR
+ * does so through an address from any source other than node_get_addr().
+ */
tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, ri->addr);
- if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
- bridge->port == ri->or_port)
- return; /* they match, so no need to do anything */
+ if (node->ri) {
+ routerinfo_t *ri = node->ri;
+ tor_addr_from_ipv4h(&addr, ri->addr);
+
+ if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
+ bridge->port == ri->or_port) ||
+ (!tor_addr_compare(&bridge->addr, &ri->ipv6_addr, CMP_EXACT) &&
+ bridge->port == ri->ipv6_orport)) {
+ /* they match, so no need to do anything */
+ } else {
+ if (tor_addr_family(&bridge->addr) == AF_INET) {
+ ri->addr = tor_addr_to_ipv4h(&bridge->addr);
+ tor_free(ri->address);
+ ri->address = tor_dup_ip(ri->addr);
+ ri->or_port = bridge->port;
+ log_info(LD_DIR,
+ "Adjusted bridge routerinfo for '%s' to match configured "
+ "address %s:%d.",
+ ri->nickname, ri->address, ri->or_port);
+ } else if (tor_addr_family(&bridge->addr) == AF_INET6) {
+ tor_addr_copy(&ri->ipv6_addr, &bridge->addr);
+ ri->ipv6_orport = bridge->port;
+ log_info(LD_DIR,
+ "Adjusted bridge routerinfo for '%s' to match configured "
+ "address %s:%d.",
+ ri->nickname, fmt_addr(&ri->ipv6_addr), ri->ipv6_orport);
+ } else {
+ log_err(LD_BUG, "Address family not supported: %d.",
+ tor_addr_family(&bridge->addr));
+ return;
+ }
+ }
+
+ /* Indicate that we prefer connecting to this bridge over the
+ protocol that the bridge address indicates. Last bridge
+ descriptor handled wins. */
+ ri->ipv6_preferred = tor_addr_family(&bridge->addr) == AF_INET6;
+
+ /* XXXipv6 we lack support for falling back to another address for
+ the same relay, warn the user */
+ if (!tor_addr_is_null(&ri->ipv6_addr))
+ {
+ tor_addr_port_t ap;
+ router_get_pref_orport(ri, &ap);
+ log_notice(LD_CONFIG,
+ "Bridge '%s' has both an IPv4 and an IPv6 address. "
+ "Will prefer using its %s address (%s:%d).",
+ ri->nickname,
+ ri->ipv6_preferred ? "IPv6" : "IPv4",
+ fmt_addr(&ap.addr), ap.port);
+ }
+ }
+ if (node->rs) {
+ routerstatus_t *rs = node->rs;
+ tor_addr_from_ipv4h(&addr, rs->addr);
- ri->addr = tor_addr_to_ipv4h(&bridge->addr);
- tor_free(ri->address);
- ri->address = tor_dup_ip(ri->addr);
- ri->or_port = bridge->port;
- log_info(LD_DIR, "Adjusted bridge '%s' to match configured address %s:%d.",
- ri->nickname, ri->address, ri->or_port);
+ if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
+ bridge->port == rs->or_port) {
+ /* they match, so no need to do anything */
+ } else {
+ rs->addr = tor_addr_to_ipv4h(&bridge->addr);
+ rs->or_port = bridge->port;
+ log_info(LD_DIR,
+ "Adjusted bridge routerstatus for '%s' to match "
+ "configured address %s:%d.",
+ rs->nickname, fmt_addr(&bridge->addr), rs->or_port);
+ }
+ }
}
/** We just learned a descriptor for a bridge. See if that
@@ -4805,18 +5210,21 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
int first = !any_bridge_descriptors_known();
bridge_info_t *bridge = get_configured_bridge_by_routerinfo(ri);
time_t now = time(NULL);
- ri->is_running = 1;
+ router_set_status(ri->cache_info.identity_digest, 1);
if (bridge) { /* if we actually want to use this one */
+ node_t *node;
/* it's here; schedule its re-fetch for a long time from now. */
if (!from_cache)
download_status_reset(&bridge->fetch_status);
- rewrite_routerinfo_address_for_bridge(bridge, ri);
+ node = node_get_mutable_by_id(ri->cache_info.identity_digest);
+ tor_assert(node);
+ rewrite_node_address_for_bridge(bridge, node);
+ add_an_entry_guard(node, 1, 1);
- add_an_entry_guard(ri, 1);
- log_notice(LD_DIR, "new bridge descriptor '%s' (%s)", ri->nickname,
- from_cache ? "cached" : "fresh");
+ log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname,
+ from_cache ? "cached" : "fresh", router_describe(ri));
/* set entry->made_contact so if it goes down we don't drop it from
* our entry node list */
entry_guard_register_connect_status(ri->cache_info.identity_digest,
@@ -4867,21 +5275,20 @@ any_pending_bridge_descriptor_fetches(void)
* down. Else return 0. If <b>act</b> is 1, then mark the down guards
* up; else just observe and report. */
static int
-entries_retry_helper(or_options_t *options, int act)
+entries_retry_helper(const or_options_t *options, int act)
{
- routerinfo_t *ri;
+ const node_t *node;
int any_known = 0;
int any_running = 0;
- int purpose = options->UseBridges ?
- ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL;
+ int need_bridges = options->UseBridges != 0;
if (!entry_guards)
- entry_guards = smartlist_create();
- SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e,
- {
- ri = router_get_by_digest(e->identity);
- if (ri && ri->purpose == purpose) {
+ entry_guards = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ node = node_get_by_id(e->identity);
+ if (node && node_has_descriptor(node) &&
+ node_is_bridge(node) == need_bridges) {
any_known = 1;
- if (ri->is_running)
+ if (node->is_running)
any_running = 1; /* some entry is both known and running */
else if (act) {
/* Mark all current connections to this OR as unhealthy, since
@@ -4890,15 +5297,15 @@ entries_retry_helper(or_options_t *options, int act)
* the node down and undermine the retry attempt. We mark even
* the established conns, since if the network just came back
* we'll want to attach circuits to fresh conns. */
- connection_or_set_bad_connections(ri->cache_info.identity_digest, 1);
+ connection_or_set_bad_connections(node->identity, 1);
/* mark this entry node for retry */
- router_set_status(ri->cache_info.identity_digest, 1);
+ router_set_status(node->identity, 1);
e->can_retry = 1;
e->bad_since = 0;
}
}
- });
+ } SMARTLIST_FOREACH_END(e);
log_debug(LD_DIR, "%d: any_known %d, any_running %d",
act, any_known, any_running);
return any_known && !any_running;
@@ -4907,7 +5314,7 @@ entries_retry_helper(or_options_t *options, int act)
/** Do we know any descriptors for our bridges / entrynodes, and are
* all the ones we have descriptors for down? */
int
-entries_known_but_down(or_options_t *options)
+entries_known_but_down(const or_options_t *options)
{
tor_assert(entry_list_is_constrained(options));
return entries_retry_helper(options, 0);
@@ -4915,12 +5322,40 @@ entries_known_but_down(or_options_t *options)
/** Mark all down known bridges / entrynodes up. */
void
-entries_retry_all(or_options_t *options)
+entries_retry_all(const or_options_t *options)
{
tor_assert(entry_list_is_constrained(options));
entries_retry_helper(options, 1);
}
+/** Return true if we've ever had a bridge running a Tor version that can't
+ * provide microdescriptors to us. In that case fall back to asking for
+ * full descriptors. Eventually all bridges will support microdescriptors
+ * and we can take this check out; see bug 4013. */
+int
+any_bridges_dont_support_microdescriptors(void)
+{
+ const node_t *node;
+ static int ever_answered_yes = 0;
+ if (!get_options()->UseBridges || !entry_guards)
+ return 0;
+ if (ever_answered_yes)
+ return 1; /* if we ever answer 'yes', always answer 'yes' */
+ SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
+ node = node_get_by_id(e->identity);
+ if (node && node->ri &&
+ node_is_bridge(node) && node_is_a_configured_bridge(node) &&
+ !tor_version_supports_microdescriptors(node->ri->platform)) {
+ /* This is one of our current bridges, and we know enough about
+ * it to know that it won't be able to answer our microdescriptor
+ * questions. */
+ ever_answered_yes = 1;
+ return 1;
+ }
+ } SMARTLIST_FOREACH_END(e);
+ return 0;
+}
+
/** Release all storage held by the list of entry guards and related
* memory structs. */
void
@@ -4933,7 +5368,10 @@ entry_guards_free_all(void)
entry_guards = NULL;
}
clear_bridge_list();
+ clear_transport_list();
smartlist_free(bridge_list);
+ smartlist_free(transport_list);
bridge_list = NULL;
+ transport_list = NULL;
}