commit e91a8c5589be1f562563a73c6e866a3b84afee87 Merge: f1c365b 0588330 Author: Nick Mathewson nickm@torproject.org Date: Mon Mar 14 16:34:33 2011 -0400
Merge remote branch 'origin/maint-0.2.2'
Resolved nontrivial conflict around rewrite_x_address_for_bridge and learned_bridge_descriptor. Now, since leanred_bridge_descriptor works on nodes, we must make sure that rewrite_node_address_for_bridge also works on nodes.
Conflicts: src/or/circuitbuild.c
changes/bug2510 | 8 +++++++ changes/bug2511 | 6 +++++ src/or/circuitbuild.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++- src/or/or.h | 1 + src/or/routerlist.c | 17 ++++++++++++++- 5 files changed, 84 insertions(+), 3 deletions(-)
diff --combined src/or/circuitbuild.c index 7ad3b07,a54f232..e2b5f13 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@@ -23,7 -23,6 +23,7 @@@ #include "directory.h" #include "main.h" #include "networkstatus.h" +#include "nodelist.h" #include "onion.h" #include "policies.h" #include "relay.h" @@@ -55,8 -54,8 +55,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]; @@@ -95,7 -94,7 +95,7 @@@ static int circuit_deliver_create_cell( 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); @@@ -1514,9 -1513,10 +1514,9 @@@ circuit_list_path_impl(origin_circuit_
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) @@@ -1526,8 -1526,10 +1526,8 @@@ 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); @@@ -1539,9 -1541,9 +1539,9 @@@ 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] = '$'; @@@ -1610,28 -1612,31 +1610,28 @@@ voi 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; } @@@ -1901,7 -1906,7 +1901,7 @@@ in 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, @@@ -1973,7 -1978,7 +1973,7 @@@ in 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; @@@ -1989,7 -1994,7 +1989,7 @@@ 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 @@@ -2023,7 -2028,7 +2023,7 @@@ 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->nickname : "<unnamed>"); + node ? node_get_nickname(node) : "<unnamed>"); } else { tor_assert(circ->cpath->state == CPATH_STATE_OPEN); tor_assert(circ->_base.state == CIRCUIT_STATE_BUILDING); @@@ -2036,7 -2041,7 +2036,7 @@@ struct timeval end; long timediff; tor_gettimeofday(&end); - timediff = tv_mdiff(&circ->_base.highres_created, &end); + timediff = tv_mdiff(&circ->_base.timestamp_created, &end);
/* * If the circuit build time is much greater than we would have cut @@@ -2499,12 -2504,12 +2499,12 @@@ onionskin_answer(or_circuit_t *circ, ui */ 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 && @@@ -2512,10 -2517,10 +2512,10 @@@ 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, @@@ -2533,12 -2538,24 +2533,12 @@@ 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; } @@@ -2572,12 -2589,12 +2572,12 @@@ circuit_all_predicted_ports_handled(tim 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;
@@@ -2587,10 -2604,7 +2587,10 @@@ 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_addr_to_node_policy(0, port, node); + else + continue; if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED) return 1; } @@@ -2623,17 -2637,18 +2623,17 @@@ ap_stream_wants_exit_attention(connecti * * 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 smartlist_t *the_nodes; + const node_t *node=NULL;
connections = get_connection_array();
@@@ -2654,11 -2669,10 +2654,11 @@@ * * -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 @@@ -2666,15 -2680,13 +2666,15 @@@ */ continue; } - if (!router->is_running || router->is_bad_exit) { + if (!node_has_descriptor(node)) + 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 (router_is_unreliable(router, need_uptime, need_capacity, 0) && + if (node_is_unreliable(node, need_uptime, need_capacity, 0) && (!options->ExitNodes || - !routerset_contains_router(options->ExitNodes, router))) { + !routerset_contains_node(options->ExitNodes, node))) { /* FFFF Someday, differentiate between a routerset that names * routers, and a routerset that names countries, and only do this * check if they've asked for specific exit relays. Or if the country @@@ -2683,19 -2695,18 +2683,19 @@@ continue; /* skip routers that are not suitable, unless we have * ExitNodes set, in which case we asked for it */ } - 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); @@@ -2703,10 -2714,11 +2703,10 @@@ } 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, 1)) { + if (connection_ap_can_use_exit(TO_EDGE_CONN(conn), node, 1)) { ++n_supported[i]; // log_fn(LOG_DEBUG,"%s is supported. n_supported[%d] now %d.", // router->nickname, i, n_supported[i]); @@@ -2714,7 -2726,7 +2714,7 @@@ // 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. */ @@@ -2731,7 -2743,7 +2731,7 @@@ * 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, @@@ -2742,19 -2754,18 +2742,19 @@@ if (best_support > 0) { smartlist_t *supporting = smartlist_create(), *use = smartlist_create();
- 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); + });
- routersets_get_disjunction(use, supporting, options->ExitNodes, + routersets_get_node_disjunction(use, supporting, options->ExitNodes, options->_ExcludeExitNodesUnion, 1); if (smartlist_len(use) == 0 && options->ExitNodes && !options->StrictNodes) { /* give up on exitnodes and try again */ - routersets_get_disjunction(use, supporting, NULL, + routersets_get_node_disjunction(use, supporting, NULL, options->_ExcludeExitNodesUnion, 1); } - router = routerlist_sl_choose_by_bandwidth(use, WEIGHT_FOR_EXIT); + node = node_sl_choose_by_bandwidth(use, WEIGHT_FOR_EXIT); smartlist_free(use); smartlist_free(supporting); } else { @@@ -2773,7 -2784,7 +2773,7 @@@ 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.", @@@ -2785,29 -2796,28 +2785,29 @@@ 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 (!node_has_descriptor(node)) + continue; + 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);
- routersets_get_disjunction(use, supporting, options->ExitNodes, + routersets_get_node_disjunction(use, supporting, options->ExitNodes, options->_ExcludeExitNodesUnion, 1); if (smartlist_len(use) == 0 && options->ExitNodes && !options->StrictNodes) { /* give up on exitnodes and try again */ - routersets_get_disjunction(use, supporting, NULL, + routersets_get_node_disjunction(use, supporting, NULL, options->_ExcludeExitNodesUnion, 1); } /* FFF sometimes the above results in null, when the requested * exit node is considered down by the consensus. we should pick * it anyway, since the user asked for it. */ - router = routerlist_sl_choose_by_bandwidth(use, WEIGHT_FOR_EXIT); - if (router) + node = node_sl_choose_by_bandwidth(use, WEIGHT_FOR_EXIT); + if (node) break; smartlist_clear(supporting); smartlist_clear(use); @@@ -2819,9 -2829,9 +2819,9 @@@ }
tor_free(n_supported); - if (router) { - log_info(LD_CIRC, "Chose exit server '%s'", router->nickname); - return router; + if (node) { + log_info(LD_CIRC, "Chose exit server '%s'", node_get_nickname(node)); + return node; } if (options->ExitNodes && options->StrictNodes) { log_warn(LD_CIRC, @@@ -2841,12 -2851,12 +2841,12 @@@ * 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; + router_crn_flags_t flags = CRN_NEED_DESC; if (need_uptime) flags |= CRN_NEED_UPTIME; if (need_capacity) @@@ -2859,7 -2869,7 +2859,7 @@@ 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; @@@ -2940,12 -2950,13 +2940,12 @@@ static in 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; @@@ -2956,15 -2967,14 +2956,15 @@@ log_info(LD_CIRC,"Using requested exit node '%s'", exit->nickname); 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); + tor_assert(exit); } state->chosen_exit = exit; return 0; @@@ -3015,30 -3025,35 +3015,30 @@@ circuit_extend_to_new_exit(origin_circu * 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; } @@@ -3066,31 -3081,31 +3066,31 @@@ onion_append_to_cpath(crypt_path_t **he * 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; + 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); + if ((r = build_state_get_exit_node(state))) { + smartlist_add(excluded, (void*) r); + nodelist_add_node_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))) { + smartlist_add(excluded, (void*)r); + nodelist_add_node_family(excluded, r); } }
@@@ -3113,45 -3128,44 +3113,45 @@@ * 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; + 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();
- 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. */ + smartlist_add(excluded, (void*)node); + nodelist_add_node_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))) { + smartlist_add(excluded, (void*)node); + nodelist_add_node_family(excluded, node); } }); } @@@ -3207,18 -3221,14 +3207,18 @@@ onion_extend_cpath(origin_circuit_t *ci 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) { + info = extend_info_from_node(r); + 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); + tor_assert(info); + } }
if (!info) { @@@ -3277,7 -3287,7 +3277,7 @@@ extend_info_alloc(const char *nickname /** Allocate and return a new extend_info_t that can be used to build a * circuit to or through the router <b>r</b>. */ extend_info_t * -extend_info_from_router(routerinfo_t *r) +extend_info_from_router(const routerinfo_t *r) { tor_addr_t addr; tor_assert(r); @@@ -3286,29 -3296,6 +3286,29 @@@ r->onion_pkey, &addr, r->or_port); }
+/** Allocate and return a new extend_info that can be used to build a ircuit + * to or through the node <b>node</b>. 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) +{ + if (node->ri) { + return extend_info_from_router(node->ri); + } 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. */ void extend_info_free(extend_info_t *info) @@@ -3339,12 -3326,12 +3339,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 @@@ -3366,8 -3353,9 +3366,8 @@@ build_state_get_exit_nickname(cpath_bui * * 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, +entry_guard_set_status(entry_guard_t *e, const node_t *node, time_t now, or_options_t *options, const char **reason) { char buf[HEX_DIGEST_LEN+1]; @@@ -3376,17 -3364,16 +3376,17 @@@ *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 && !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) { @@@ -3430,7 -3417,7 +3430,7 @@@ entry_is_time_to_retry(entry_guard_t *e 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; @@@ -3444,11 -3431,11 +3444,11 @@@ * * 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; + const node_t *node; or_options_t *options = get_options(); tor_assert(msg);
@@@ -3462,36 -3449,33 +3462,36 @@@ *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 (get_options()->UseBridges && r->purpose != ROUTER_PURPOSE_BRIDGE) { - *msg = "not a bridge"; - return NULL; - } - if (!get_options()->UseBridges && r->purpose != ROUTER_PURPOSE_GENERAL) { - *msg = "not general-purpose"; - return NULL; + if (get_options()->UseBridges) { + if (node_get_purpose(node) != ROUTER_PURPOSE_BRIDGE) { + *msg = "not a bridge"; + 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)) { + 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. */ @@@ -3589,15 -3573,15 +3589,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) { - 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; @@@ -3606,15 -3590,14 +3606,15 @@@ 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->nickname); - 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_get_nickname(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 @@@ -3629,7 -3612,7 +3629,7 @@@ 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 @@@ -3783,7 -3766,7 +3783,7 @@@ entry_guards_compute_status(or_options_ 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; @@@ -3804,7 -3787,7 +3804,7 @@@ 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' is %s, %s%s%s, and %s%s.", entry->nickname, entry->unreachable_since ? "unreachable" : "reachable", @@@ -3921,7 -3904,7 +3921,7 @@@ entry_guard_register_connect_status(con 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; @@@ -3962,7 -3945,7 +3962,7 @@@ entry_nodes_should_be_added(void static void entry_guards_prepend_from_config(or_options_t *options) { - smartlist_t *entry_routers, *entry_fps; + smartlist_t *entry_nodes, *entry_fps; smartlist_t *old_entry_guards_on_list, *old_entry_guards_not_on_list; tor_assert(entry_guards);
@@@ -3982,22 -3965,22 +3982,22 @@@ tor_free(string); }
- entry_routers = smartlist_create(); + entry_nodes = smartlist_create(); entry_fps = smartlist_create(); old_entry_guards_on_list = smartlist_create(); old_entry_guards_not_on_list = smartlist_create();
/* Split entry guards into those on the list and those not. */
- /* XXXX022 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, 0); - SMARTLIST_FOREACH(entry_routers, routerinfo_t *, ri, - smartlist_add(entry_fps,ri->cache_info.identity_digest)); + /* Now that we allow countries and IP ranges in EntryNodes, this is + * potentially an enormous list. It's not so bad though because we + * only call this function when a) we're making a new circuit, and b) + * we've called directory_info_has_arrived() or changed our EntryNodes + * since the last time we made a circuit. */ + routerset_get_all_nodes(entry_nodes, options->EntryNodes, 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); @@@ -4006,9 -3989,9 +4006,9 @@@ });
/* 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); + SMARTLIST_FOREACH(entry_nodes, const node_t *, node, { + if (is_an_entry_guard(node->identity)) { + SMARTLIST_DEL_CURRENT(entry_nodes, node); } });
@@@ -4017,8 -4000,8 +4017,8 @@@ /* First, the previously configured guards that are in EntryNodes. */ smartlist_add_all(entry_guards, old_entry_guards_on_list); /* Next, the rest of EntryNodes */ - SMARTLIST_FOREACH(entry_routers, routerinfo_t *, ri, { - add_an_entry_guard(ri, 0); + SMARTLIST_FOREACH(entry_nodes, const node_t *, node, { + add_an_entry_guard(node, 0); }); /* Finally, the remaining previously configured guards that are not in * EntryNodes, unless we're strict in which case we drop them */ @@@ -4029,7 -4012,7 +4029,7 @@@ smartlist_add_all(entry_guards, old_entry_guards_not_on_list); }
- smartlist_free(entry_routers); + smartlist_free(entry_nodes); smartlist_free(entry_fps); smartlist_free(old_entry_guards_on_list); smartlist_free(old_entry_guards_not_on_list); @@@ -4067,21 -4050,20 +4067,21 @@@ entry_list_is_totally_static(or_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 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_family(exit_family, chosen_exit); consider_exit_family = 1; }
@@@ -4097,17 -4079,18 +4097,17 @@@
retry: smartlist_clear(live_entry_guards); - SMARTLIST_FOREACH(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 (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 */ @@@ -4120,7 -4103,7 +4120,7 @@@ "No relays from EntryNodes available. Using others."); } } - 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 @@@ -4130,7 -4113,7 +4130,7 @@@ } if (smartlist_len(live_entry_guards) >= options->NumEntryGuards) break; /* 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 @@@ -4150,8 -4133,8 +4150,8 @@@ /* 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); + 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 @@@ -4161,16 -4144,16 +4161,16 @@@ 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; } - if (!r && entry_list_is_constrained(options) && consider_exit_family) { + 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. */ @@@ -4184,16 -4167,16 +4184,16 @@@ 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. @@@ -4440,7 -4423,7 +4440,7 @@@ getinfo_helper_entry_guards(control_con 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"; @@@ -4451,9 -4434,9 +4451,9 @@@ 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); @@@ -4530,7 -4513,7 +4530,7 @@@ get_configured_bridge_by_addr_port_dige /** 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); @@@ -4540,7 -4523,7 +4540,7 @@@
/** 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; } @@@ -4688,6 -4671,29 +4688,55 @@@ fetch_bridge_descriptors(or_options_t * SMARTLIST_FOREACH_END(bridge); }
+ /** 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 ++ */ + 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) { ++ /* they match, so no need to do anything */ ++ } else { ++ 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 (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 '%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 * digest is in our entry guard list, and add it if not. */ void @@@ -4699,17 -4705,16 +4748,19 @@@ learned_bridge_descriptor(routerinfo_t 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 */ - const node_t *node; ++ 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);
- node = node_get_by_id(ri->cache_info.identity_digest); - 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); + - add_an_entry_guard(ri, 1); log_notice(LD_DIR, "new bridge descriptor '%s' (%s)", ri->nickname, from_cache ? "cached" : "fresh"); /* set entry->made_contact so if it goes down we don't drop it from @@@ -4764,18 -4769,19 +4815,18 @@@ any_pending_bridge_descriptor_fetches(v static int entries_retry_helper(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) { + 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 @@@ -4784,15 -4790,15 +4835,15 @@@ * 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; diff --combined src/or/or.h index 323c472,910bf8d..553afbd --- a/src/or/or.h +++ b/src/or/or.h @@@ -83,13 -83,6 +83,13 @@@ #define snprintf _snprintf #endif
+#ifdef USE_BUFFEREVENTS +#include <event2/bufferevent.h> +#include <event2/buffer.h> +#include <event2/util.h> +#endif + +#include "crypto.h" #include "tortls.h" #include "../common/torlog.h" #include "container.h" @@@ -391,9 -384,7 +391,9 @@@ typedef enum /** A connection to a hidden service directory server: download a v2 rendezvous * descriptor. */ #define DIR_PURPOSE_FETCH_RENDDESC_V2 18 -#define _DIR_PURPOSE_MAX 18 +/** A connection to a directory server: download a microdescriptor. */ +#define DIR_PURPOSE_FETCH_MICRODESC 19 +#define _DIR_PURPOSE_MAX 19
/** True iff <b>p</b> is a purpose corresponding to uploading data to a * directory server. */ @@@ -814,9 -805,6 +814,9 @@@ typedef enum * Tor 0.1.2.x is obsolete, we can remove this. */ #define DEFAULT_CLIENT_NICKNAME "client"
+/** Name chosen by routers that don't configure nicknames */ +#define UNNAMED_ROUTER_NICKNAME "Unnamed" + /** Number of bytes in a SOCKS4 header. */ #define SOCKS4_NETWORK_LEN 8
@@@ -862,8 -850,8 +862,8 @@@ typedef struct cell_t typedef struct var_cell_t { uint8_t command; circid_t circ_id; - uint16_t payload_len; - uint8_t payload[1]; + uint16_t payload_len; /**< The actual length of <b>payload</b>. */ + uint8_t payload[FLEXIBLE_ARRAY_MEMBER]; } var_cell_t;
/** A cell as packed for writing to the network. */ @@@ -980,7 -968,6 +980,7 @@@ typedef struct connection_t /** Our socket; -1 if this connection is closed, or has no socket. */ evutil_socket_t s; int conn_array_index; /**< Index into the global connection array. */ + struct event *read_event; /**< Libevent event structure. */ struct event *write_event; /**< Libevent event structure. */ buf_t *inbuf; /**< Buffer holding data read over this connection. */ @@@ -991,11 -978,6 +991,11 @@@ * read? */ time_t timestamp_lastwritten; /**< When was the last time libevent said we * could write? */ + +#ifdef USE_BUFFEREVENTS + struct bufferevent *bufev; /**< A Libevent buffered IO structure. */ +#endif + time_t timestamp_created; /**< When was this connection_t created? */
/* XXXX_IP6 make this IPv6-capable */ @@@ -1095,16 -1077,10 +1095,16 @@@ typedef struct or_connection_t /* bandwidth* and *_bucket only used by ORs in OPEN state: */ int bandwidthrate; /**< Bytes/s added to the bucket. (OPEN ORs only.) */ int bandwidthburst; /**< Max bucket size for this conn. (OPEN ORs only.) */ +#ifndef USE_BUFFEREVENTS int read_bucket; /**< When this hits 0, stop receiving. Every second we * add 'bandwidthrate' to this, capping it at * bandwidthburst. (OPEN ORs only) */ int write_bucket; /**< When this hits 0, stop writing. Like read_bucket. */ +#else + /** DOCDOC */ + /* XXXX we could share this among all connections. */ + struct ev_token_bucket_cfg *bucket_cfg; +#endif int n_circuits; /**< How many circuits use this connection as p_conn or * n_conn ? */
@@@ -1212,13 -1188,8 +1212,13 @@@ typedef struct edge_connection_t typedef struct dir_connection_t { connection_t _base;
- char *requested_resource; /**< Which 'resource' did we ask the directory - * for? */ + /** Which 'resource' did we ask the directory for? This is typically the part + * of the URL string that defines, relative to the directory conn purpose, + * what thing we want. For example, in router descriptor downloads by + * descriptor digest, it contains "d/", then one ore more +-separated + * fingerprints. + **/ + char *requested_resource; unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */
/* Used only for server sides of some dir connections, to implement @@@ -1309,51 -1280,6 +1309,51 @@@ static INLINE control_connection_t *TO_ return DOWNCAST(control_connection_t, c); }
+/* Conditional macros to help write code that works whether bufferevents are + disabled or not. + + We can't just write: + if (conn->bufev) { + do bufferevent stuff; + } else { + do other stuff; + } + because the bufferevent stuff won't even compile unless we have a fairly + new version of Libevent. Instead, we say: + IF_HAS_BUFFEREVENT(conn, { do_bufferevent_stuff } ); + or: + IF_HAS_BUFFEREVENT(conn, { + do bufferevent stuff; + }) ELSE_IF_NO_BUFFEREVENT { + do non-bufferevent stuff; + } + If we're compiling with bufferevent support, then the macros expand more or + less to: + if (conn->bufev) { + do_bufferevent_stuff; + } else { + do non-bufferevent stuff; + } + and if we aren't using bufferevents, they expand more or less to: + { do non-bufferevent stuff; } +*/ +#ifdef USE_BUFFEREVENTS +#define HAS_BUFFEREVENT(c) (((c)->bufev) != NULL) +#define IF_HAS_BUFFEREVENT(c, stmt) \ + if ((c)->bufev) do { \ + stmt ; \ + } while (0) +#define ELSE_IF_NO_BUFFEREVENT ; else +#define IF_HAS_NO_BUFFEREVENT(c) \ + if (NULL == (c)->bufev) +#else +#define HAS_BUFFEREVENT(c) (0) +#define IF_HAS_BUFFEREVENT(c, stmt) (void)0 +#define ELSE_IF_NO_BUFFEREVENT ; +#define IF_HAS_NO_BUFFEREVENT(c) \ + if (1) +#endif + /** What action type does an address policy indicate: accept or reject? */ typedef enum { ADDR_POLICY_ACCEPT=1, @@@ -1517,49 -1443,59 +1517,49 @@@ typedef struct char *contact_info; /**< Declared contact info for this router. */ unsigned int is_hibernating:1; /**< Whether the router claims to be * hibernating */ - unsigned int has_old_dnsworkers:1; /**< Whether the router is using - * dnsworker code. */ - unsigned int caches_extra_info:1; /**< Whether the router caches and serves - * extrainfo documents. */ - unsigned int allow_single_hop_exits:1; /**< Whether the router allows - * single hop exits. */ - - /* local info */ - unsigned int is_running:1; /**< As far as we know, is this OR currently - * running? */ - unsigned int is_valid:1; /**< Has a trusted dirserver validated this OR? - * (For Authdir: Have we validated this OR?) - */ - unsigned int is_named:1; /**< Do we believe the nickname that this OR gives - * us? */ - unsigned int is_fast:1; /** Do we think this is a fast OR? */ - unsigned int is_stable:1; /** Do we think this is a stable OR? */ - unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */ - unsigned int is_exit:1; /**< Do we think this is an OK exit? */ - unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked, - * or otherwise nasty? */ - unsigned int is_bad_directory:1; /**< Do we think this directory is junky, - * underpowered, or otherwise useless? */ + unsigned int caches_extra_info:1; /**< Whether the router says it caches and + * serves extrainfo documents. */ + unsigned int allow_single_hop_exits:1; /**< Whether the router says + * it allows single hop exits. */ + unsigned int wants_to_be_hs_dir:1; /**< True iff this router claims to be * a hidden service directory. */ - unsigned int is_hs_dir:1; /**< True iff this router is a hidden service - * directory according to the authorities. */ unsigned int policy_is_reject_star:1; /**< True iff the exit policy for this * router rejects everything. */ /** True if, after we have added this router, we should re-launch * tests for it. */ unsigned int needs_retest_if_added:1;
-/** Tor can use this router for general positions in circuits. */ +/** Tor can use this router for general positions in circuits; we got it + * from a directory server as usual, or we're an authority and a server + * uploaded it. */ #define ROUTER_PURPOSE_GENERAL 0 -/** Tor should avoid using this router for circuit-building. */ +/** Tor should avoid using this router for circuit-building: we got it + * from a crontroller. If the controller wants to use it, it'll have to + * ask for it by identity. */ #define ROUTER_PURPOSE_CONTROLLER 1 -/** Tor should use this router only for bridge positions in circuits. */ +/** Tor should use this router only for bridge positions in circuits: we got + * it via a directory request from the bridge itself, or a bridge + * authority. x*/ #define ROUTER_PURPOSE_BRIDGE 2 /** Tor should not use this router; it was marked in cached-descriptors with * a purpose we didn't recognize. */ #define ROUTER_PURPOSE_UNKNOWN 255
- uint8_t purpose; /** What positions in a circuit is this router good for? */ + /* In what way did we find out about this router? One of ROUTER_PURPOSE_*. + * Routers of different purposes are kept segregated and used for different + * things; see notes on ROUTER_PURPOSE_* macros above. + */ + uint8_t purpose;
/* The below items are used only by authdirservers for * reachability testing. */ + /** When was the last time we could reach this OR? */ time_t last_reachable; /** When did we start testing reachability for this OR? */ time_t testing_since; - /** According to the geoip db what country is this router in? */ - country_t country; + } routerinfo_t;
/** Information needed to keep and cache a signed extra-info document. */ @@@ -1585,9 -1521,8 +1585,9 @@@ typedef struct routerstatus_t * has. */ char identity_digest[DIGEST_LEN]; /**< Digest of the router's identity * key. */ - char descriptor_digest[DIGEST_LEN]; /**< Digest of the router's most recent - * descriptor. */ + /** Digest of the router's most recent descriptor or microdescriptor. + * If it's a descriptor, we only use the first DIGEST_LEN bytes. */ + char descriptor_digest[DIGEST256_LEN]; uint32_t addr; /**< IPv4 address for this router. */ uint16_t or_port; /**< OR port for this router. */ uint16_t dir_port; /**< Directory port for this router. */ @@@ -1595,11 -1530,7 +1595,11 @@@ unsigned int is_exit:1; /**< True iff this router is a good exit. */ unsigned int is_stable:1; /**< True iff this router stays up a long time. */ unsigned int is_fast:1; /**< True iff this router has good bandwidth. */ - unsigned int is_running:1; /**< True iff this router is up. */ + /** True iff this router is called 'running' in the consensus. We give it + * this funny name so that we don't accidentally use this bit as a view of + * whether we think the router is *currently* running. If that's what you + * want to know, look at is_running in node_t. */ + unsigned int is_flagged_running:1; unsigned int is_named:1; /**< True iff "nickname" belongs to this router. */ unsigned int is_unnamed:1; /**< True iff "nickname" belongs to another * router. */ @@@ -1651,31 -1582,15 +1651,31 @@@ * from this authority.) Applies in v2 networkstatus document only. */ unsigned int need_to_mirror:1; - unsigned int name_lookup_warned:1; /**< Have we warned the user for referring - * to this (unnamed) router by nickname? - */ time_t last_dir_503_at; /**< When did this router last tell us that it * was too busy to serve directory info? */ download_status_t dl_status;
} routerstatus_t;
+/** A single entry in a parsed policy summary, describing a range of ports. */ +typedef struct short_policy_entry_t { + uint16_t min_port, max_port; +} short_policy_entry_t; + +/** A short_poliy_t is the parsed version of a policy summary. */ +typedef struct short_policy_t { + /** True if the members of 'entries' are port ranges to accept; false if + * they are port ranges to reject */ + unsigned int is_accept : 1; + /** The actual number of values in 'entries'. */ + unsigned int n_entries : 31; + /** An array of 0 or more short_policy_entry_t values, each describing a + * range of ports that this policy accepts or rejects (depending on the + * value of is_accept). + */ + short_policy_entry_t entries[FLEXIBLE_ARRAY_MEMBER]; +} short_policy_t; + /** A microdescriptor is the smallest amount of information needed to build a * circuit through a router. They are generated by the directory authorities, * using information from the uploaded routerinfo documents. They are not @@@ -1717,83 -1632,15 +1717,83 @@@ typedef struct microdesc_t crypto_pk_env_t *onion_pkey; /** As routerinfo_t.family */ smartlist_t *family; - /** Encoded exit policy summary */ - char *exitsummary; /**< exit policy summary - - * XXX this probably should not stay a string. */ + /** Exit policy summary */ + short_policy_t *exit_policy; } microdesc_t;
+/** A node_t represents a Tor router. + * + * Specifically, a node_t is a Tor router as we are using it: a router that + * we are considering for circuits, connections, and so on. A node_t is a + * thin wrapper around the routerstatus, routerinfo, and microdesc for a + * single wrapper, and provides a consistent interface for all of them. + * + * Also, a node_t has mutable state. While a routerinfo, a routerstatus, + * and a microdesc have[*] only the information read from a router + * descriptor, a consensus entry, and a microdescriptor (respectively)... + * a node_t has flags based on *our own current opinion* of the node. + * + * [*] Actually, there is some leftover information in each that is mutable. + * We should try to excise that. + */ +typedef struct node_t { + /* Indexing information */ + + /** Used to look up the node_t by its identity digest. */ + HT_ENTRY(node_t) ht_ent; + /** Position of the node within the list of nodes */ + int nodelist_idx; + + /** The identity digest of this node_t. No more than one node_t per + * identity may exist at a time. */ + char identity[DIGEST_LEN]; + + microdesc_t *md; + routerinfo_t *ri; + routerstatus_t *rs; + + /* local info: copied from routerstatus, then possibly frobbed based + * on experience. Authorities set this stuff directly. */ + + unsigned int is_running:1; /**< As far as we know, is this OR currently + * running? */ + unsigned int is_valid:1; /**< Has a trusted dirserver validated this OR? + * (For Authdir: Have we validated this OR?) + */ + unsigned int is_fast:1; /** Do we think this is a fast OR? */ + unsigned int is_stable:1; /** Do we think this is a stable OR? */ + unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */ + unsigned int is_exit:1; /**< Do we think this is an OK exit? */ + unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked, + * or otherwise nasty? */ + unsigned int is_bad_directory:1; /**< Do we think this directory is junky, + * underpowered, or otherwise useless? */ + unsigned int is_hs_dir:1; /**< True iff this router is a hidden service + * directory according to the authorities. */ + + /* Local info: warning state. */ + + unsigned int name_lookup_warned:1; /**< Have we warned the user for referring + * to this (unnamed) router by nickname? + */ + + /** Local info: we treat this node as if it rejects everything */ + unsigned int rejects_all:1; + + /* Local info: derived. */ + + /** According to the geoip db what country is this router in? */ + country_t country; +} node_t; + /** How many times will we try to download a router's descriptor before giving * up? */ #define MAX_ROUTERDESC_DOWNLOAD_FAILURES 8
+/** How many times will we try to download a microdescriptor before giving + * up? */ +#define MAX_MICRODESC_DOWNLOAD_FAILURES 8 + /** Contents of a v2 (non-consensus, non-vote) network status object. */ typedef struct networkstatus_v2_t { /** When did we receive the network-status document? */ @@@ -2269,12 -2116,10 +2269,12 @@@ typedef struct circuit_t * length ONIONSKIN_CHALLENGE_LEN. */ char *n_conn_onionskin;
- time_t timestamp_created; /**< When was this circuit created? */ + /** When was this circuit created? We keep this timestamp with a higher + * resolution than most so that the circuit-build-time tracking code can + * get millisecond resolution. */ + struct timeval timestamp_created; time_t timestamp_dirty; /**< When the circuit was first used, or 0 if the * circuit is clean. */ - struct timeval highres_created; /**< When exactly was the circuit created? */
uint16_t marked_for_close; /**< Should we close this circuit at the end of * the main loop? (If true, holds the line number @@@ -2499,7 -2344,6 +2499,7 @@@ typedef struct
config_line_t *Logs; /**< New-style list of configuration lines * for logs */ + int LogTimeGranularity; /**< Log resolution in milliseconds. */
int LogMessageDomains; /**< Boolean: Should we log the domain(s) in which * each log message occurs? */ @@@ -2722,9 -2566,6 +2722,9 @@@ * authorizations for hidden services */ char *ContactInfo; /**< Contact info to be published in the directory. */
+ int HeartbeatPeriod; /**< Log heartbeat messages after this many seconds + * have passed. */ + char *HTTPProxy; /**< hostname[:port] to use as http proxy, if any. */ tor_addr_t HTTPProxyAddr; /**< Parsed IPv4 addr for http proxy, if any. */ uint16_t HTTPProxyPort; /**< Parsed port for http proxy, if any. */ @@@ -2762,8 -2603,7 +2762,8 @@@
char *MyFamily; /**< Declared family for this OR. */ config_line_t *NodeFamilies; /**< List of config lines for - * node families */ + * node families */ + smartlist_t *NodeFamilySets; /**< List of parsed NodeFamilies values. */ config_line_t *AuthDirBadDir; /**< Address policy for descriptors to * mark as bad dir mirrors. */ config_line_t *AuthDirBadExit; /**< Address policy for descriptors to @@@ -2868,10 -2708,6 +2868,10 @@@ * possible. */ int PreferTunneledDirConns; /**< If true, avoid dirservers that don't * support BEGIN_DIR, when possible. */ + int PortForwarding; /**< If true, use NAT-PMP or UPnP to automatically + * forward the DirPort and ORPort on the NAT device */ + char *PortForwardingHelper; /** < Filename or full path of the port + forwarding helper executable */ int AllowNonRFC953Hostnames; /**< If true, we allow connections to hostnames * with weird characters. */ /** If true, we try resolving hostnames with weird characters. */ @@@ -2909,9 -2745,6 +2909,9 @@@ /** If true, the user wants us to collect statistics on port usage. */ int ExitPortStatistics;
+ /** If true, the user wants us to collect connection statistics. */ + int ConnDirectionStatistics; + /** If true, the user wants us to collect cell statistics. */ int CellStatistics;
@@@ -3008,12 -2841,6 +3008,12 @@@ */ double CircuitPriorityHalflife;
+ /** If true, do not enable IOCP on windows with bufferevents, even if + * we think we could. */ + int DisableIOCP; + /** For testing only: will go away in 0.2.3.x. */ + int _UseFilteringSSLBufferevents; + /** Set to true if the TestingTorNetwork configuration option is set. * This is used so that options_validate() has a chance to realize that * the defaults have changed. */ @@@ -3133,6 -2960,8 +3133,6 @@@ struct socks_request_t * every connection. */ };
-/* all the function prototypes go here */ - /********************************* circuitbuild.c **********************/
/** How many hops does a general-purpose circuit have by default? */ @@@ -3524,7 -3353,7 +3524,7 @@@ typedef enum ADDR_POLICY_PROBABLY_ACCEPTED=1, /** Part of the address was unknown, but as far as we can tell, it was * rejected. */ - ADDR_POLICY_PROBABLY_REJECTED=2 + ADDR_POLICY_PROBABLY_REJECTED=2, } addr_policy_result_t;
/********************************* rephist.c ***************************/ @@@ -3655,8 -3484,6 +3655,8 @@@ typedef struct trusted_dir_server_t * fetches to _any_ single directory server.] */ #define PDS_NO_EXISTING_SERVERDESC_FETCH (1<<3) +#define PDS_NO_EXISTING_MICRODESC_FETCH (1<<4) + #define _PDS_PREFER_TUNNELED_DIR_CONNS (1<<16)
/** Possible ways to weight routers when choosing one randomly. See @@@ -3674,8 -3501,7 +3674,8 @@@ typedef enum CRN_NEED_GUARD = 1<<2, CRN_ALLOW_INVALID = 1<<3, /* XXXX not used, apparently. */ - CRN_WEIGHT_AS_EXIT = 1<<5 + CRN_WEIGHT_AS_EXIT = 1<<5, + CRN_NEED_DESC = 1<<6 } router_crn_flags_t;
/** Return value for router_add_to_routerlist() and dirserv_add_descriptor() */ @@@ -3687,6 -3513,7 +3687,7 @@@ typedef enum was_router_added_t ROUTER_NOT_IN_CONSENSUS = -3, ROUTER_NOT_IN_CONSENSUS_OR_NETWORKSTATUS = -4, ROUTER_AUTHDIR_REJECTS = -5, + ROUTER_WAS_NOT_WANTED = -6 } was_router_added_t;
/********************************* routerparse.c ************************/ diff --combined src/or/routerlist.c index 66066f6,4421d5c..1205fd1 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@@ -22,9 -22,7 +22,9 @@@ #include "geoip.h" #include "hibernate.h" #include "main.h" +#include "microdesc.h" #include "networkstatus.h" +#include "nodelist.h" #include "policies.h" #include "reasons.h" #include "rendcommon.h" @@@ -39,21 -37,20 +39,21 @@@ /****************************************************************************/
/* static function prototypes */ -static routerstatus_t *router_pick_directory_server_impl( +static const routerstatus_t *router_pick_directory_server_impl( authority_type_t auth, int flags); -static routerstatus_t *router_pick_trusteddirserver_impl( +static const routerstatus_t *router_pick_trusteddirserver_impl( authority_type_t auth, int flags, int *n_busy_out); static void mark_all_trusteddirservers_up(void); -static int router_nickname_matches(routerinfo_t *router, const char *nickname); +static int router_nickname_matches(const routerinfo_t *router, + const char *nickname); +static int node_nickname_matches(const node_t *router, + const char *nickname); static void trusted_dir_server_free(trusted_dir_server_t *ds); -static void launch_router_descriptor_downloads(smartlist_t *downloadable, - routerstatus_t *source, - time_t now); static int signed_desc_digest_is_recognized(signed_descriptor_t *desc); static void update_router_have_minimum_dir_info(void); -static const char *signed_descriptor_get_body_impl(signed_descriptor_t *desc, - int with_annotations); +static const char *signed_descriptor_get_body_impl( + const signed_descriptor_t *desc, + int with_annotations); static void list_pending_downloads(digestmap_t *result, int purpose, const char *prefix);
@@@ -315,7 -312,6 +315,7 @@@ trusted_dirs_remove_old_certs(void time_t now = time(NULL); #define DEAD_CERT_LIFETIME (2*24*60*60) #define OLD_CERT_LIFETIME (7*24*60*60) +#define CERT_EXPIRY_SKEW (60*60) if (!trusted_dir_certs) return;
@@@ -332,7 -328,7 +332,7 @@@ time_t cert_published; if (newest == cert) continue; - expired = ftime_definitely_after(now, cert->expires); + expired = time_definitely_after(now, cert->expires, CERT_EXPIRY_SKEW); cert_published = cert->cache_info.published_on; /* Store expired certs for 48 hours after a newer arrives; */ @@@ -524,7 -520,7 +524,7 @@@ authority_certs_fetch_missing(networkst continue; cl = get_cert_list(ds->v3_identity_digest); SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert, { - if (!ftime_definitely_after(now, cert->expires)) { + if (! time_definitely_after(now, cert->expires, CERT_EXPIRY_SKEW)) { /* It's not expired, and we weren't looking for something to * verify a consensus with. Call it done. */ download_status_reset(&cl->dl_status); @@@ -604,7 -600,7 +604,7 @@@ router_should_rebuild_store(desc_store_ /** Return the desc_store_t in <b>rl</b> that should be used to store * <b>sd</b>. */ static INLINE desc_store_t * -desc_get_store(routerlist_t *rl, signed_descriptor_t *sd) +desc_get_store(routerlist_t *rl, const signed_descriptor_t *sd) { if (sd->is_extrainfo) return &rl->extrainfo_store; @@@ -930,10 -926,10 +930,10 @@@ router_get_trusted_dir_servers(void * Don't pick an authority if any non-authority is viable; try to avoid using * servers that have returned 503 recently. */ -routerstatus_t * +const routerstatus_t * router_pick_directory_server(authority_type_t type, int flags) { - routerstatus_t *choice; + const routerstatus_t *choice; if (get_options()->PreferTunneledDirConns) flags |= _PDS_PREFER_TUNNELED_DIR_CONNS;
@@@ -962,8 -958,8 +962,8 @@@ in router_get_my_share_of_directory_requests(double *v2_share_out, double *v3_share_out) { - routerinfo_t *me = router_get_my_routerinfo(); - routerstatus_t *rs; + const routerinfo_t *me = router_get_my_routerinfo(); + const routerstatus_t *rs; const int pds_flags = PDS_ALLOW_SELF|PDS_IGNORE_FASCISTFIREWALL; *v2_share_out = *v3_share_out = 0.0; if (!me) @@@ -1036,10 -1032,10 +1036,10 @@@ trusteddirserver_get_by_v3_auth_digest( /** Try to find a running trusted dirserver. Flags are as for * router_pick_directory_server. */ -routerstatus_t * +const routerstatus_t * router_pick_trusteddirserver(authority_type_t type, int flags) { - routerstatus_t *choice; + const routerstatus_t *choice; int busy = 0; if (get_options()->PreferTunneledDirConns) flags |= _PDS_PREFER_TUNNELED_DIR_CONNS; @@@ -1051,8 -1047,7 +1051,8 @@@ /* If the reason that we got no server is that servers are "busy", * we must be excluding good servers because we already have serverdesc * fetches with them. Do not mark down servers up because of this. */ - tor_assert((flags & PDS_NO_EXISTING_SERVERDESC_FETCH)); + tor_assert((flags & (PDS_NO_EXISTING_SERVERDESC_FETCH| + PDS_NO_EXISTING_MICRODESC_FETCH))); return NULL; }
@@@ -1072,10 -1067,10 +1072,10 @@@ * If the _PDS_PREFER_TUNNELED_DIR_CONNS flag is set, prefer directory servers * that we can use with BEGINDIR. */ -static routerstatus_t * +static const routerstatus_t * router_pick_directory_server_impl(authority_type_t type, int flags) { - routerstatus_t *result; + const node_t *result; smartlist_t *direct, *tunnel; smartlist_t *trusted_direct, *trusted_tunnel; smartlist_t *overloaded_direct, *overloaded_tunnel; @@@ -1096,54 -1091,49 +1096,54 @@@ overloaded_tunnel = smartlist_create();
/* Find all the running dirservers we know about. */ - SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, - status) { + SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { int is_trusted; - int is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now; + int is_overloaded; tor_addr_t addr; - if (!status->is_running || !status->dir_port || !status->is_valid) + const routerstatus_t *status = node->rs; + if (!status) continue; - if (status->is_bad_directory) + + if (!node->is_running || !status->dir_port || !node->is_valid) + continue; + if (node->is_bad_directory) continue; - if (requireother && router_digest_is_me(status->identity_digest)) + if (requireother && router_digest_is_me(node->identity)) continue; if (type & V3_AUTHORITY) { if (!(status->version_supports_v3_dir || - router_digest_is_trusted_dir_type(status->identity_digest, + router_digest_is_trusted_dir_type(node->identity, V3_AUTHORITY))) continue; } - is_trusted = router_digest_is_trusted_dir(status->identity_digest); - if ((type & V2_AUTHORITY) && !(status->is_v2_dir || is_trusted)) + is_trusted = router_digest_is_trusted_dir(node->identity); + if ((type & V2_AUTHORITY) && !(node->rs->is_v2_dir || is_trusted)) continue; if ((type & EXTRAINFO_CACHE) && - !router_supports_extrainfo(status->identity_digest, 0)) + !router_supports_extrainfo(node->identity, 0)) continue;
/* XXXX IP6 proposal 118 */ - tor_addr_from_ipv4h(&addr, status->addr); + tor_addr_from_ipv4h(&addr, node->rs->addr); + + is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now;
if (prefer_tunnel && status->version_supports_begindir && (!fascistfirewall || fascist_firewall_allows_address_or(&addr, status->or_port))) smartlist_add(is_trusted ? trusted_tunnel : - is_overloaded ? overloaded_tunnel : tunnel, status); + is_overloaded ? overloaded_tunnel : tunnel, (void*)node); else if (!fascistfirewall || fascist_firewall_allows_address_dir(&addr, status->dir_port)) smartlist_add(is_trusted ? trusted_direct : - is_overloaded ? overloaded_direct : direct, status); - } SMARTLIST_FOREACH_END(status); + is_overloaded ? overloaded_direct : direct, (void*)node); + } SMARTLIST_FOREACH_END(node);
if (smartlist_len(tunnel)) { - result = routerstatus_sl_choose_by_bandwidth(tunnel, WEIGHT_FOR_DIR); + result = node_sl_choose_by_bandwidth(tunnel, WEIGHT_FOR_DIR); } else if (smartlist_len(overloaded_tunnel)) { - result = routerstatus_sl_choose_by_bandwidth(overloaded_tunnel, + result = node_sl_choose_by_bandwidth(overloaded_tunnel, WEIGHT_FOR_DIR); } else if (smartlist_len(trusted_tunnel)) { /* FFFF We don't distinguish between trusteds and overloaded trusteds @@@ -1152,10 -1142,10 +1152,10 @@@ * is a feature, but it could easily be a bug. -RD */ result = smartlist_choose(trusted_tunnel); } else if (smartlist_len(direct)) { - result = routerstatus_sl_choose_by_bandwidth(direct, WEIGHT_FOR_DIR); + result = node_sl_choose_by_bandwidth(direct, WEIGHT_FOR_DIR); } else if (smartlist_len(overloaded_direct)) { - result = routerstatus_sl_choose_by_bandwidth(overloaded_direct, - WEIGHT_FOR_DIR); + result = node_sl_choose_by_bandwidth(overloaded_direct, + WEIGHT_FOR_DIR); } else { result = smartlist_choose(trusted_direct); } @@@ -1165,26 -1155,25 +1165,26 @@@ smartlist_free(trusted_tunnel); smartlist_free(overloaded_direct); smartlist_free(overloaded_tunnel); - return result; + return result ? result->rs : NULL; }
/** Choose randomly from among the trusted dirservers that are up. Flags * are as for router_pick_directory_server_impl(). */ -static routerstatus_t * +static const routerstatus_t * router_pick_trusteddirserver_impl(authority_type_t type, int flags, int *n_busy_out) { smartlist_t *direct, *tunnel; smartlist_t *overloaded_direct, *overloaded_tunnel; - routerinfo_t *me = router_get_my_routerinfo(); - routerstatus_t *result; + const routerinfo_t *me = router_get_my_routerinfo(); + const routerstatus_t *result; time_t now = time(NULL); const int requireother = ! (flags & PDS_ALLOW_SELF); const int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL); const int prefer_tunnel = (flags & _PDS_PREFER_TUNNELED_DIR_CONNS); const int no_serverdesc_fetching =(flags & PDS_NO_EXISTING_SERVERDESC_FETCH); + const int no_microdesc_fetching =(flags & PDS_NO_EXISTING_MICRODESC_FETCH); int n_busy = 0;
if (!trusted_dir_servers) @@@ -1223,13 -1212,6 +1223,13 @@@ continue; } } + if (no_microdesc_fetching) { + if (connection_get_by_type_addr_port_purpose( + CONN_TYPE_DIR, &addr, d->dir_port, DIR_PURPOSE_FETCH_MICRODESC)) { + ++n_busy; + continue; + } + }
if (prefer_tunnel && d->or_port && @@@ -1268,18 -1250,22 +1268,18 @@@ static void mark_all_trusteddirservers_up(void) { - if (routerlist) { - SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router, - if (router_digest_is_trusted_dir(router->cache_info.identity_digest) && - router->dir_port > 0) { - router->is_running = 1; - }); - } + SMARTLIST_FOREACH(nodelist_get_list(), node_t *, node, { + if (router_digest_is_trusted_dir(node->identity)) + node->is_running = 1; + }); if (trusted_dir_servers) { SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, dir, { routerstatus_t *rs; dir->is_running = 1; download_status_reset(&dir->v2_ns_dl_status); - rs = router_get_consensus_status_by_id(dir->digest); - if (rs && !rs->is_running) { - rs->is_running = 1; + rs = router_get_mutable_consensus_status_by_id(dir->digest); + if (rs) { rs->last_dir_503_at = 0; control_event_networkstatus_changed_single(rs); } @@@ -1303,14 -1289,25 +1303,14 @@@ router_reset_status_download_failures(v mark_all_trusteddirservers_up(); }
-/** Return true iff router1 and router2 have the same /16 network. */ +/** Return true iff router1 and router2 have similar enough network addresses + * that we should treat them as being in the same family */ static INLINE int -routers_in_same_network_family(routerinfo_t *r1, routerinfo_t *r2) -{ - return (r1->addr & 0xffff0000) == (r2->addr & 0xffff0000); -} - -/** Look through the routerlist and identify routers that - * advertise the same /16 network address as <b>router</b>. - * Add each of them to <b>sl</b>. - */ -static void -routerlist_add_network_family(smartlist_t *sl, routerinfo_t *router) +addrs_in_same_network_family(const tor_addr_t *a1, + const tor_addr_t *a2) { - SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, r, - { - if (router != r && routers_in_same_network_family(router, r)) - smartlist_add(sl, r); - }); + /* XXXX MOVE ? */ + return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC); }
/** Add all the family of <b>router</b> to the smartlist <b>sl</b>. @@@ -1318,132 -1315,122 +1318,132 @@@ * or pick more than one relay from a family for our entry guard list. */ void -routerlist_add_family(smartlist_t *sl, routerinfo_t *router) +nodelist_add_node_family(smartlist_t *sl, const node_t *node) { - routerinfo_t *r; - config_line_t *cl; + /* XXXX MOVE */ + const smartlist_t *all_nodes = nodelist_get_list(); + const smartlist_t *declared_family; or_options_t *options = get_options();
- /* First, add any routers with similar network addresses. */ - if (options->EnforceDistinctSubnets) - routerlist_add_network_family(sl, router); + tor_assert(node);
- if (router->declared_family) { - /* Add every r such that router declares familyness with r, and r + declared_family = node_get_declared_family(node); + + /* First, add any nodes with similar network addresses. */ + if (options->EnforceDistinctSubnets) { + tor_addr_t node_addr; + node_get_addr(node, &node_addr); + + SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) { + tor_addr_t a; + node_get_addr(node2, &a); + if (addrs_in_same_network_family(&a, &node_addr)) + smartlist_add(sl, (void*)node2); + } SMARTLIST_FOREACH_END(node2); + } + + /* Now, add all nodes in the declared_family of this node, if they + * also declare this node to be in their family. */ + if (declared_family) { + /* Add every r such that router declares familyness with node, and node * declares familyhood with router. */ - SMARTLIST_FOREACH(router->declared_family, const char *, n, - { - if (!(r = router_get_by_nickname(n, 0))) - continue; - if (!r->declared_family) - continue; - SMARTLIST_FOREACH(r->declared_family, const char *, n2, - { - if (router_nickname_matches(router, n2)) - smartlist_add(sl, r); - }); - }); + SMARTLIST_FOREACH_BEGIN(declared_family, const char *, name) { + const node_t *node2; + const smartlist_t *family2; + if (!(node2 = node_get_by_nickname(name, 0))) + continue; + if (!(family2 = node_get_declared_family(node2))) + continue; + SMARTLIST_FOREACH_BEGIN(family2, const char *, name2) { + if (node_nickname_matches(node, name2)) { + smartlist_add(sl, (void*)node2); + break; + } + } SMARTLIST_FOREACH_END(name2); + } SMARTLIST_FOREACH_END(name); }
/* If the user declared any families locally, honor those too. */ - for (cl = options->NodeFamilies; cl; cl = cl->next) { - if (router_nickname_is_in_list(router, cl->value)) { - add_nickname_list_to_smartlist(sl, cl->value, 0); - } + if (options->NodeFamilySets) { + SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, { + if (routerset_contains_node(rs, node)) { + routerset_get_all_nodes(sl, rs, 0); + } + }); + } +} + +/** Given a <b>router</b>, add every node_t in its family to <b>sl</b>. + * + * Note the type mismatch: This function takes a routerinfo, but adds nodes + * to the smartlist! + */ +static void +routerlist_add_nodes_in_family(smartlist_t *sl, const routerinfo_t *router) +{ + /* XXXX MOVE ? */ + node_t fake_node; + const node_t *node = node_get_by_id(router->cache_info.identity_digest);; + if (node == NULL) { + memset(&fake_node, 0, sizeof(fake_node)); + fake_node.ri = (routerinfo_t *)router; + memcpy(fake_node.identity, router->cache_info.identity_digest, DIGEST_LEN); + node = &fake_node; } + nodelist_add_node_family(sl, node); }
-/** Return true iff r is named by some nickname in <b>lst</b>. */ +/** Return true iff <b>node</b> is named by some nickname in <b>lst</b>. */ static INLINE int -router_in_nickname_smartlist(smartlist_t *lst, routerinfo_t *r) +node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node) { + /* XXXX MOVE */ if (!lst) return 0; - SMARTLIST_FOREACH(lst, const char *, name, - if (router_nickname_matches(r, name)) - return 1;); + SMARTLIST_FOREACH(lst, const char *, name, { + if (node_nickname_matches(node, name)) + return 1; + }); return 0; }
/** Return true iff r1 and r2 are in the same family, but not the same * router. */ int -routers_in_same_family(routerinfo_t *r1, routerinfo_t *r2) +nodes_in_same_family(const node_t *node1, const node_t *node2) { + /* XXXX MOVE */ or_options_t *options = get_options(); - config_line_t *cl; - - if (options->EnforceDistinctSubnets && routers_in_same_network_family(r1,r2)) - return 1;
- if (router_in_nickname_smartlist(r1->declared_family, r2) && - router_in_nickname_smartlist(r2->declared_family, r1)) - return 1; - - for (cl = options->NodeFamilies; cl; cl = cl->next) { - if (router_nickname_is_in_list(r1, cl->value) && - router_nickname_is_in_list(r2, cl->value)) + /* Are they in the same family because of their addresses? */ + if (options->EnforceDistinctSubnets) { + tor_addr_t a1, a2; + node_get_addr(node1, &a1); + node_get_addr(node2, &a2); + if (addrs_in_same_network_family(&a1, &a2)) return 1; } - return 0; -}
-/** Given a (possibly NULL) comma-and-whitespace separated list of nicknames, - * see which nicknames in <b>list</b> name routers in our routerlist, and add - * the routerinfos for those routers to <b>sl</b>. If <b>must_be_running</b>, - * only include routers that we think are running. - * Warn if any non-Named routers are specified by nickname. - */ -void -add_nickname_list_to_smartlist(smartlist_t *sl, const char *list, - int must_be_running) -{ - routerinfo_t *router; - smartlist_t *nickname_list; - int have_dir_info = router_have_minimum_dir_info(); - - if (!list) - return; /* nothing to do */ - tor_assert(sl); - - nickname_list = smartlist_create(); - if (!warned_nicknames) - warned_nicknames = smartlist_create(); + /* Are they in the same family because the agree they are? */ + { + const smartlist_t *f1, *f2; + f1 = node_get_declared_family(node1); + f2 = node_get_declared_family(node2); + if (f1 && f2 && + node_in_nickname_smartlist(f1, node2) && + node_in_nickname_smartlist(f2, node1)) + return 1; + }
- smartlist_split_string(nickname_list, list, ",", - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); + /* Are they in the same option because the user says they are? */ + if (options->NodeFamilySets) { + SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, { + if (routerset_contains_node(rs, node1) && + routerset_contains_node(rs, node2)) + return 1; + }); + }
- SMARTLIST_FOREACH(nickname_list, const char *, nick, { - int warned; - if (!is_legal_nickname_or_hexdigest(nick)) { - log_warn(LD_CONFIG, "Nickname '%s' is misformed; skipping", nick); - continue; - } - router = router_get_by_nickname(nick, 1); - warned = smartlist_string_isin(warned_nicknames, nick); - if (router) { - if (!must_be_running || router->is_running) { - smartlist_add(sl,router); - } - } else if (!router_get_consensus_status_by_nickname(nick,1)) { - if (!warned) { - log_fn(have_dir_info ? LOG_WARN : LOG_INFO, LD_CONFIG, - "Nickname list includes '%s' which isn't a known router.",nick); - smartlist_add(warned_nicknames, tor_strdup(nick)); - } - } - }); - SMARTLIST_FOREACH(nickname_list, char *, nick, tor_free(nick)); - smartlist_free(nickname_list); + return 0; }
/** Return 1 iff any member of the (possibly NULL) comma-separated list @@@ -1451,7 -1438,7 +1451,7 @@@ * return 0. */ int -router_nickname_is_in_list(routerinfo_t *router, const char *list) +router_nickname_is_in_list(const routerinfo_t *router, const char *list) { smartlist_t *nickname_list; int v = 0; @@@ -1470,32 -1457,34 +1470,32 @@@ return v; }
-/** Add every suitable router from our routerlist to <b>sl</b>, so that +/** Add every suitable node from our nodelist to <b>sl</b>, so that * we can pick a node for a circuit. */ static void -router_add_running_routers_to_smartlist(smartlist_t *sl, int allow_invalid, - int need_uptime, int need_capacity, - int need_guard) -{ - if (!routerlist) - return; +router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid, + int need_uptime, int need_capacity, + int need_guard, int need_desc) +{ /* XXXX MOVE */ + SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { + if (!node->is_running || + (!node->is_valid && !allow_invalid)) + continue; + if (need_desc && !(node->ri || (node->rs && node->md))) + continue; + if (node->ri && node->ri->purpose != ROUTER_PURPOSE_GENERAL) + continue; + if (node_is_unreliable(node, need_uptime, need_capacity, need_guard)) + continue;
- SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router, - { - if (router->is_running && - router->purpose == ROUTER_PURPOSE_GENERAL && - (router->is_valid || allow_invalid) && - !router_is_unreliable(router, need_uptime, - need_capacity, need_guard)) { - /* If it's running, and it's suitable according to the - * other flags we had in mind */ - smartlist_add(sl, router); - } - }); + smartlist_add(sl, (void *)node); + } SMARTLIST_FOREACH_END(node); }
/** Look through the routerlist until we find a router that has my key. Return it. */ -routerinfo_t * +const routerinfo_t * routerlist_find_my_routerinfo(void) { if (!routerlist) @@@ -1513,9 -1502,9 +1513,9 @@@ * that allows exit to this address:port, or return NULL if there * isn't a good one. */ -routerinfo_t * +const node_t * router_find_exact_exit_enclave(const char *address, uint16_t port) -{ +{/*XXXX MOVE*/ uint32_t addr; struct in_addr in; tor_addr_t a; @@@ -1526,12 -1515,13 +1526,12 @@@
tor_addr_from_ipv4h(&a, addr);
- SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router, - { - if (router->addr == addr && - router->is_running && - compare_tor_addr_to_addr_policy(&a, port, router->exit_policy) == + SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, { + if (node_get_addr_ipv4h(node) == addr && + node->is_running && + compare_tor_addr_to_node_policy(&a, port, node) == ADDR_POLICY_ACCEPTED) - return router; + return node; }); return NULL; } @@@ -1543,14 -1533,14 +1543,14 @@@ * If <b>need_guard</b>, we require that the router is a possible entry guard. */ int -router_is_unreliable(routerinfo_t *router, int need_uptime, - int need_capacity, int need_guard) +node_is_unreliable(const node_t *node, int need_uptime, + int need_capacity, int need_guard) { - if (need_uptime && !router->is_stable) + if (need_uptime && !node->is_stable) return 1; - if (need_capacity && !router->is_fast) + if (need_capacity && !node->is_fast) return 1; - if (need_guard && !router->is_possible_guard) + if (need_guard && !node->is_possible_guard) return 1; return 0; } @@@ -1558,7 -1548,7 +1558,7 @@@ /** Return the smaller of the router's configured BandwidthRate * and its advertised capacity. */ uint32_t -router_get_advertised_bandwidth(routerinfo_t *router) +router_get_advertised_bandwidth(const routerinfo_t *router) { if (router->bandwidthcapacity < router->bandwidthrate) return router->bandwidthcapacity; @@@ -1572,7 -1562,7 +1572,7 @@@ /** Return the smaller of the router's configured BandwidthRate * and its advertised capacity, capped by max-believe-bw. */ uint32_t -router_get_advertised_bandwidth_capped(routerinfo_t *router) +router_get_advertised_bandwidth_capped(const routerinfo_t *router) { uint32_t result = router->bandwidthcapacity; if (result > router->bandwidthrate) @@@ -1614,10 -1604,13 +1614,10 @@@ kb_to_bytes(uint32_t bw }
/** Helper function: - * choose a random element of smartlist <b>sl</b>, weighted by + * choose a random element of smartlist <b>sl</b> of nodes, weighted by * the advertised bandwidth of each element using the consensus * bandwidth weights. * - * If <b>statuses</b> is zero, then <b>sl</b> is a list of - * routerinfo_t's. Otherwise it's a list of routerstatus_t's. - * * If <b>rule</b>==WEIGHT_FOR_EXIT. we're picking an exit node: consider all * nodes' bandwidth equally regardless of their Exit status, since there may * be some in the list because they exit to obscure ports. If @@@ -1627,9 -1620,10 +1627,9 @@@ * guard node: consider all guard's bandwidth equally. Otherwise, weight * guards proportionally less. */ -static void * -smartlist_choose_by_bandwidth_weights(smartlist_t *sl, - bandwidth_weight_rule_t rule, - int statuses) +static const node_t * +smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl, + bandwidth_weight_rule_t rule) { int64_t weight_scale; int64_t rand_bw; @@@ -1723,14 -1717,15 +1723,14 @@@ bandwidths = tor_malloc_zero(sizeof(double)*smartlist_len(sl));
// Cycle through smartlist and total the bandwidth. - for (i = 0; i < (unsigned)smartlist_len(sl); ++i) { + SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) { int is_exit = 0, is_guard = 0, is_dir = 0, this_bw = 0, is_me = 0; double weight = 1; - if (statuses) { - routerstatus_t *status = smartlist_get(sl, i); - is_exit = status->is_exit && !status->is_bad_exit; - is_guard = status->is_possible_guard; - is_dir = (status->dir_port != 0); - if (!status->has_bandwidth) { + is_exit = node->is_exit && ! node->is_bad_exit; + is_guard = node->is_possible_guard; + is_dir = node_is_dir(node); + if (node->rs) { + if (!node->rs->has_bandwidth) { tor_free(bandwidths); /* This should never happen, unless all the authorites downgrade * to 0.2.0 or rogue routerstatuses get inserted into our consensus. */ @@@ -1739,17 -1734,26 +1739,17 @@@ "old router selection algorithm."); return NULL; } - this_bw = kb_to_bytes(status->bandwidth); - if (router_digest_is_me(status->identity_digest)) - is_me = 1; + this_bw = kb_to_bytes(node->rs->bandwidth); + } else if (node->ri) { + /* bridge or other descriptor not in our consensus */ + this_bw = bridge_get_advertised_bandwidth_bounded(node->ri); + have_unknown = 1; } else { - routerstatus_t *rs; - routerinfo_t *router = smartlist_get(sl, i); - rs = router_get_consensus_status_by_id( - router->cache_info.identity_digest); - is_exit = router->is_exit && !router->is_bad_exit; - is_guard = router->is_possible_guard; - is_dir = (router->dir_port != 0); - if (rs && rs->has_bandwidth) { - this_bw = kb_to_bytes(rs->bandwidth); - } else { /* bridge or other descriptor not in our consensus */ - this_bw = bridge_get_advertised_bandwidth_bounded(router); - have_unknown = 1; - } - if (router_digest_is_me(router->cache_info.identity_digest)) - is_me = 1; + /* We can't use this one. */ + continue; } + is_me = router_digest_is_me(node->identity); + if (is_guard && is_exit) { weight = (is_dir ? Wdb*Wd : Wd); } else if (is_guard) { @@@ -1760,11 -1764,11 +1760,11 @@@ weight = (is_dir ? Wmb*Wm : Wm); }
- bandwidths[i] = weight*this_bw; + bandwidths[node_sl_idx] = weight*this_bw; weighted_bw += weight*this_bw; if (is_me) sl_last_weighted_bw_of_me = weight*this_bw; - } + } SMARTLIST_FOREACH_END(node);
/* XXXX022 this is a kludge to expose these values. */ sl_last_total_weighted_bw = weighted_bw; @@@ -1812,9 -1816,12 +1812,9 @@@ }
/** Helper function: - * choose a random element of smartlist <b>sl</b>, weighted by + * choose a random node_t element of smartlist <b>sl</b>, weighted by * the advertised bandwidth of each element. * - * If <b>statuses</b> is zero, then <b>sl</b> is a list of - * routerinfo_t's. Otherwise it's a list of routerstatus_t's. - * * If <b>rule</b>==WEIGHT_FOR_EXIT. we're picking an exit node: consider all * nodes' bandwidth equally regardless of their Exit status, since there may * be some in the list because they exit to obscure ports. If @@@ -1824,11 -1831,13 +1824,11 @@@ * guard node: consider all guard's bandwidth equally. Otherwise, weight * guards proportionally less. */ -static void * -smartlist_choose_by_bandwidth(smartlist_t *sl, bandwidth_weight_rule_t rule, - int statuses) +static const node_t * +smartlist_choose_node_by_bandwidth(smartlist_t *sl, + bandwidth_weight_rule_t rule) { - unsigned int i; - routerinfo_t *router; - routerstatus_t *status=NULL; + unsigned i; int32_t *bandwidths; int is_exit; int is_guard; @@@ -1869,34 -1878,49 +1869,34 @@@ guard_bits = bitarray_init_zero(smartlist_len(sl));
/* Iterate over all the routerinfo_t or routerstatus_t, and */ - for (i = 0; i < (unsigned)smartlist_len(sl); ++i) { + SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) { /* first, learn what bandwidth we think i has */ int is_known = 1; int32_t flags = 0; uint32_t this_bw = 0; - if (statuses) { - status = smartlist_get(sl, i); - if (router_digest_is_me(status->identity_digest)) - me_idx = i; - router = router_get_by_digest(status->identity_digest); - is_exit = status->is_exit; - is_guard = status->is_possible_guard; - if (status->has_bandwidth) { - this_bw = kb_to_bytes(status->bandwidth); + i = node_sl_idx; + + if (router_digest_is_me(node->identity)) + me_idx = node_sl_idx; + + is_exit = node->is_exit; + is_guard = node->is_possible_guard; + if (node->rs) { + if (node->rs->has_bandwidth) { + this_bw = kb_to_bytes(node->rs->bandwidth); } else { /* guess */ /* XXX022 once consensuses always list bandwidths, we can take * this guessing business out. -RD */ is_known = 0; - flags = status->is_fast ? 1 : 0; + flags = node->rs->is_fast ? 1 : 0; flags |= is_exit ? 2 : 0; flags |= is_guard ? 4 : 0; } - } else { - routerstatus_t *rs; - router = smartlist_get(sl, i); - rs = router_get_consensus_status_by_id( - router->cache_info.identity_digest); - if (router_digest_is_me(router->cache_info.identity_digest)) - me_idx = i; - is_exit = router->is_exit; - is_guard = router->is_possible_guard; - if (rs && rs->has_bandwidth) { - this_bw = kb_to_bytes(rs->bandwidth); - } else if (rs) { /* guess; don't trust the descriptor */ - /* XXX022 once consensuses always list bandwidths, we can take - * this guessing business out. -RD */ - is_known = 0; - flags = router->is_fast ? 1 : 0; - flags |= is_exit ? 2 : 0; - flags |= is_guard ? 4 : 0; - } else /* bridge or other descriptor not in our consensus */ - this_bw = bridge_get_advertised_bandwidth_bounded(router); + } else if (node->ri) { + /* Must be a bridge if we're willing to use it */ + this_bw = bridge_get_advertised_bandwidth_bounded(node->ri); } + if (is_exit) bitarray_set(exit_bits, i); if (is_guard) @@@ -1916,9 -1940,9 +1916,9 @@@ total_nonexit_bw += this_bw; } else { ++n_unknown; - bandwidths[i] = -flags; + bandwidths[node_sl_idx] = -flags; } - } + } SMARTLIST_FOREACH_END(node);
/* Now, fill in the unknown values. */ if (n_unknown) { @@@ -2060,23 -2084,40 +2060,23 @@@ return smartlist_get(sl, i); }
-/** Choose a random element of router list <b>sl</b>, weighted by - * the advertised bandwidth of each router. - */ -routerinfo_t * -routerlist_sl_choose_by_bandwidth(smartlist_t *sl, - bandwidth_weight_rule_t rule) -{ - routerinfo_t *ret; - if ((ret = smartlist_choose_by_bandwidth_weights(sl, rule, 0))) { - return ret; - } else { - return smartlist_choose_by_bandwidth(sl, rule, 0); - } -} - /** Choose a random element of status list <b>sl</b>, weighted by - * the advertised bandwidth of each status. - */ -routerstatus_t * -routerstatus_sl_choose_by_bandwidth(smartlist_t *sl, - bandwidth_weight_rule_t rule) -{ - /* We are choosing neither exit nor guard here. Weight accordingly. */ - routerstatus_t *ret; - if ((ret = smartlist_choose_by_bandwidth_weights(sl, rule, 1))) { + * the advertised bandwidth of each node */ +const node_t * +node_sl_choose_by_bandwidth(smartlist_t *sl, + bandwidth_weight_rule_t rule) +{ /*XXXX MOVE */ + const node_t *ret; + if ((ret = smartlist_choose_node_by_bandwidth_weights(sl, rule))) { return ret; } else { - return smartlist_choose_by_bandwidth(sl, rule, 1); + return smartlist_choose_node_by_bandwidth(sl, rule); } }
-/** Return a random running router from the routerlist. Never - * pick a node whose routerinfo is in - * <b>excludedsmartlist</b>, or whose routerinfo matches <b>excludedset</b>, +/** Return a random running node from the nodelist. Never + * pick a node that is in + * <b>excludedsmartlist</b>, or which matches <b>excludedset</b>, * even if they are the only nodes available. * If <b>CRN_NEED_UPTIME</b> is set in flags and any router has more than * a minimum uptime, return one of those. @@@ -2088,26 -2129,21 +2088,26 @@@ * If <b>CRN_WEIGHT_AS_EXIT</b> is set in flags, we weight bandwidths as if * picking an exit node, otherwise we weight bandwidths for picking a relay * node (that is, possibly discounting exit nodes). + * If <b>CRN_NEED_DESC</b> is set in flags, we only consider nodes that + * have a routerinfo or microdescriptor -- that is, enough info to be + * used to build a circuit. */ -routerinfo_t * +const node_t * router_choose_random_node(smartlist_t *excludedsmartlist, routerset_t *excludedset, router_crn_flags_t flags) -{ +{ /* XXXX MOVE */ const int need_uptime = (flags & CRN_NEED_UPTIME) != 0; const int need_capacity = (flags & CRN_NEED_CAPACITY) != 0; const int need_guard = (flags & CRN_NEED_GUARD) != 0; const int allow_invalid = (flags & CRN_ALLOW_INVALID) != 0; const int weight_for_exit = (flags & CRN_WEIGHT_AS_EXIT) != 0; + const int need_desc = (flags & CRN_NEED_DESC) != 0;
smartlist_t *sl=smartlist_create(), - *excludednodes=smartlist_create(); - routerinfo_t *choice = NULL, *r; + *excludednodes=smartlist_create(); + const node_t *choice = NULL; + const routerinfo_t *r; bandwidth_weight_rule_t rule;
tor_assert(!(weight_for_exit && need_guard)); @@@ -2117,30 -2153,29 +2117,30 @@@ /* Exclude relays that allow single hop exit circuits, if the user * wants to (such relays might be risky) */ if (get_options()->ExcludeSingleHopRelays) { - routerlist_t *rl = router_get_routerlist(); - SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r, - if (r->allow_single_hop_exits) { - smartlist_add(excludednodes, r); + SMARTLIST_FOREACH(nodelist_get_list(), node_t *, node, + if (node_allows_single_hop_exits(node)) { + smartlist_add(excludednodes, node); }); }
if ((r = routerlist_find_my_routerinfo())) { - smartlist_add(excludednodes, r); - routerlist_add_family(excludednodes, r); + const node_t *me = node_get_by_id(r->cache_info.identity_digest); + if (me) + smartlist_add(excludednodes, (void *)me); + routerlist_add_nodes_in_family(excludednodes, r); }
- router_add_running_routers_to_smartlist(sl, allow_invalid, - need_uptime, need_capacity, - need_guard); + router_add_running_nodes_to_smartlist(sl, allow_invalid, + need_uptime, need_capacity, + need_guard, need_desc); smartlist_subtract(sl,excludednodes); if (excludedsmartlist) smartlist_subtract(sl,excludedsmartlist); if (excludedset) - routerset_subtract_routers(sl,excludedset); + routerset_subtract_nodes(sl,excludedset);
// Always weight by bandwidth - choice = routerlist_sl_choose_by_bandwidth(sl, rule); + choice = node_sl_choose_by_bandwidth(sl, rule);
smartlist_free(sl); if (!choice && (need_uptime || need_capacity || need_guard)) { @@@ -2163,88 -2198,35 +2163,88 @@@ return choice; }
-/** Helper: Return true iff the <b>identity_digest</b> and <b>nickname</b> - * combination of a router, encoded in hexadecimal, matches <b>hexdigest</b> - * (which is optionally prefixed with a single dollar sign). Return false if - * <b>hexdigest</b> is malformed, or it doesn't match. */ -static INLINE int -hex_digest_matches(const char *hexdigest, const char *identity_digest, - const char *nickname, int is_named) +/** Helper: given an extended nickname in <b>hexdigest</b> try to decode it. + * Return 0 on success, -1 on failure. Store the result into the + * DIGEST_LEN-byte buffer at <b>digest_out</b>, the single character at + * <b>nickname_qualifier_char_out</b>, and the MAXNICKNAME_LEN+1-byte buffer + * at <b>nickname_out</b>. + * + * The recognized format is: + * HexName = Dollar? HexDigest NamePart? + * Dollar = '?' + * HexDigest = HexChar*20 + * HexChar = 'a'..'f' | 'A'..'F' | '0'..'9' + * NamePart = QualChar Name + * QualChar = '=' | '~' + * Name = NameChar*(1..MAX_NICKNAME_LEN) + * NameChar = Any ASCII alphanumeric character + */ +int +hex_digest_nickname_decode(const char *hexdigest, + char *digest_out, + char *nickname_qualifier_char_out, + char *nickname_out) { - char digest[DIGEST_LEN]; size_t len; + tor_assert(hexdigest); if (hexdigest[0] == '$') ++hexdigest;
len = strlen(hexdigest); - if (len < HEX_DIGEST_LEN) + if (len < HEX_DIGEST_LEN) { + return -1; + } else if (len > HEX_DIGEST_LEN && (hexdigest[HEX_DIGEST_LEN] == '=' || + hexdigest[HEX_DIGEST_LEN] == '~') && + len <= HEX_DIGEST_LEN+1+MAX_NICKNAME_LEN) { + *nickname_qualifier_char_out = hexdigest[HEX_DIGEST_LEN]; + strlcpy(nickname_out, hexdigest+HEX_DIGEST_LEN+1 , MAX_NICKNAME_LEN+1); + } else if (len == HEX_DIGEST_LEN) { + ; + } else { + return -1; + } + + if (base16_decode(digest_out, DIGEST_LEN, hexdigest, HEX_DIGEST_LEN)<0) + return -1; + return 0; +} + +/** Helper: Return true iff the <b>identity_digest</b> and <b>nickname</b> + * combination of a router, encoded in hexadecimal, matches <b>hexdigest</b> + * (which is optionally prefixed with a single dollar sign). Return false if + * <b>hexdigest</b> is malformed, or it doesn't match. */ +static int +hex_digest_nickname_matches(const char *hexdigest, const char *identity_digest, + const char *nickname, int is_named) +{ + char digest[DIGEST_LEN]; + char nn_char='\0'; + char nn_buf[MAX_NICKNAME_LEN+1]; + + if (hex_digest_nickname_decode(hexdigest, digest, &nn_char, nn_buf) == -1) return 0; - else if (len > HEX_DIGEST_LEN && - (hexdigest[HEX_DIGEST_LEN] == '=' || - hexdigest[HEX_DIGEST_LEN] == '~')) { - if (strcasecmp(hexdigest+HEX_DIGEST_LEN+1, nickname)) + + if (nn_char == '=' || nn_char == '~') { + if (strcasecmp(nn_buf, nickname)) return 0; - if (hexdigest[HEX_DIGEST_LEN] == '=' && !is_named) + if (nn_char == '=' && !is_named) return 0; }
- if (base16_decode(digest, DIGEST_LEN, hexdigest, HEX_DIGEST_LEN)<0) - return 0; - return (!memcmp(digest, identity_digest, DIGEST_LEN)); + return !memcmp(digest, identity_digest, DIGEST_LEN); +} + +/* Return true iff <b>router</b> is listed as named in the current + * consensus. */ +static int +router_is_named(const routerinfo_t *router) +{ + const char *digest = + networkstatus_get_router_digest_by_nickname(router->nickname); + + return (digest && + !memcmp(digest, router->cache_info.identity_digest, DIGEST_LEN)); }
/** Return true iff the digest of <b>router</b>'s identity key, @@@ -2252,12 -2234,10 +2252,12 @@@ * optionally prefixed with a single dollar sign). Return false if * <b>hexdigest</b> is malformed, or it doesn't match. */ static INLINE int -router_hex_digest_matches(routerinfo_t *router, const char *hexdigest) +router_hex_digest_matches(const routerinfo_t *router, const char *hexdigest) { - return hex_digest_matches(hexdigest, router->cache_info.identity_digest, - router->nickname, router->is_named); + return hex_digest_nickname_matches(hexdigest, + router->cache_info.identity_digest, + router->nickname, + router_is_named(router)); }
/** Return true if <b>router</b>'s nickname matches <b>nickname</b> @@@ -2265,43 -2245,20 +2265,43 @@@ * matches a hexadecimal value stored in <b>nickname</b>. Return * false otherwise. */ static int -router_nickname_matches(routerinfo_t *router, const char *nickname) +router_nickname_matches(const routerinfo_t *router, const char *nickname) { if (nickname[0]!='$' && !strcasecmp(router->nickname, nickname)) return 1; return router_hex_digest_matches(router, nickname); }
+/** Return true if <b>node</b>'s nickname matches <b>nickname</b> + * (case-insensitive), or if <b>node's</b> identity key digest + * matches a hexadecimal value stored in <b>nickname</b>. Return + * false otherwise. */ +static int +node_nickname_matches(const node_t *node, const char *nickname) +{ + const char *n = node_get_nickname(node); + if (n && nickname[0]!='$' && !strcasecmp(n, nickname)) + return 1; + return hex_digest_nickname_matches(nickname, + node->identity, + n, + node_is_named(node)); +} + /** Return the router in our routerlist whose (case-insensitive) * nickname or (case-sensitive) hexadecimal key digest is * <b>nickname</b>. Return NULL if no such router is known. */ -routerinfo_t * +const routerinfo_t * router_get_by_nickname(const char *nickname, int warn_if_unnamed) { +#if 1 + const node_t *node = node_get_by_nickname(nickname, warn_if_unnamed); + if (node) + return node->ri; + else + return NULL; +#else int maybedigest; char digest[DIGEST_LEN]; routerinfo_t *best_match=NULL; @@@ -2347,14 -2304,15 +2347,14 @@@ if (warn_if_unnamed && n_matches > 1) { smartlist_t *fps = smartlist_create(); int any_unwarned = 0; - SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router, - { + SMARTLIST_FOREACH_BEGIN(routerlist->routers, routerinfo_t *, router) { routerstatus_t *rs; char *desc; size_t dlen; char fp[HEX_DIGEST_LEN+1]; if (strcasecmp(router->nickname, nickname)) continue; - rs = router_get_consensus_status_by_id( + rs = router_get_mutable_consensus_status_by_id( router->cache_info.identity_digest); if (rs && !rs->name_lookup_warned) { rs->name_lookup_warned = 1; @@@ -2367,7 -2325,7 +2367,7 @@@ tor_snprintf(desc, dlen, ""$%s" for the one at %s:%d", fp, router->address, router->or_port); smartlist_add(fps, desc); - }); + } SMARTLIST_FOREACH_END(router); if (any_unwarned) { char *alternatives = smartlist_join_strings(fps, "; ",0,NULL); log_warn(LD_CONFIG, @@@ -2380,7 -2338,7 +2380,7 @@@ SMARTLIST_FOREACH(fps, char *, cp, tor_free(cp)); smartlist_free(fps); } else if (warn_if_unnamed) { - routerstatus_t *rs = router_get_consensus_status_by_id( + routerstatus_t *rs = router_get_mutable_consensus_status_by_id( best_match->cache_info.identity_digest); if (rs && !rs->name_lookup_warned) { char fp[HEX_DIGEST_LEN+1]; @@@ -2396,8 -2354,8 +2396,8 @@@ } return best_match; } - return NULL; +#endif }
/** Try to find a routerinfo for <b>digest</b>. If we don't have one, @@@ -2406,7 -2364,7 +2406,7 @@@ int router_digest_version_as_new_as(const char *digest, const char *cutoff) { - routerinfo_t *router = router_get_by_digest(digest); + const routerinfo_t *router = router_get_by_id_digest(digest); if (!router) return 1; return tor_version_as_new_as(router->platform, cutoff); @@@ -2460,20 -2418,44 +2460,20 @@@ hexdigest_to_digest(const char *hexdige
/** Return the router in our routerlist whose hexadecimal key digest * is <b>hexdigest</b>. Return NULL if no such router is known. */ -routerinfo_t * +const routerinfo_t * router_get_by_hexdigest(const char *hexdigest) { - char digest[DIGEST_LEN]; - size_t len; - routerinfo_t *ri; - - tor_assert(hexdigest); - if (!routerlist) - return NULL; - if (hexdigest[0]=='$') - ++hexdigest; - len = strlen(hexdigest); - if (hexdigest_to_digest(hexdigest, digest) < 0) + if (is_legal_nickname(hexdigest)) return NULL;
- ri = router_get_by_digest(digest); - - if (ri && len > HEX_DIGEST_LEN) { - if (hexdigest[HEX_DIGEST_LEN] == '=') { - if (strcasecmp(ri->nickname, hexdigest+HEX_DIGEST_LEN+1) || - !ri->is_named) - return NULL; - } else if (hexdigest[HEX_DIGEST_LEN] == '~') { - if (strcasecmp(ri->nickname, hexdigest+HEX_DIGEST_LEN+1)) - return NULL; - } else { - return NULL; - } - } - - return ri; + /* It's not a legal nickname, so it must be a hexdigest or nothing. */ + return router_get_by_nickname(hexdigest, 1); }
-/** Return the router in our routerlist whose 20-byte key digest - * is <b>digest</b>. Return NULL if no such router is known. */ +/** As router_get_by_id_digest,but return a pointer that you're allowed to + * modify */ routerinfo_t * -router_get_by_digest(const char *digest) +router_get_mutable_by_digest(const char *digest) { tor_assert(digest);
@@@ -2484,14 -2466,6 +2484,14 @@@ return rimap_get(routerlist->identity_map, digest); }
+/** Return the router in our routerlist whose 20-byte key digest + * is <b>digest</b>. Return NULL if no such router is known. */ +const routerinfo_t * +router_get_by_id_digest(const char *digest) +{ + return router_get_mutable_by_digest(digest); +} + /** Return the router in our routerlist whose 20-byte descriptor * is <b>digest</b>. Return NULL if no such router is known. */ signed_descriptor_t * @@@ -2542,7 -2516,7 +2542,7 @@@ extrainfo_get_by_descriptor_digest(cons * The caller must not free the string returned. */ static const char * -signed_descriptor_get_body_impl(signed_descriptor_t *desc, +signed_descriptor_get_body_impl(const signed_descriptor_t *desc, int with_annotations) { const char *r = NULL; @@@ -2591,7 -2565,7 +2591,7 @@@ * The caller must not free the string returned. */ const char * -signed_descriptor_get_body(signed_descriptor_t *desc) +signed_descriptor_get_body(const signed_descriptor_t *desc) { return signed_descriptor_get_body_impl(desc, 0); } @@@ -2599,7 -2573,7 +2599,7 @@@ /** As signed_descriptor_get_body(), but points to the beginning of the * annotations section rather than the beginning of the descriptor. */ const char * -signed_descriptor_get_annotations(signed_descriptor_t *desc) +signed_descriptor_get_annotations(const signed_descriptor_t *desc) { return signed_descriptor_get_body_impl(desc, 1); } @@@ -2652,6 -2626,7 +2652,6 @@@ routerinfo_free(routerinfo_t *router } addr_policy_list_free(router->exit_policy);
- /* XXXX Remove if this turns out to affect performance. */ memset(router, 77, sizeof(routerinfo_t));
tor_free(router); @@@ -2666,6 -2641,7 +2666,6 @@@ extrainfo_free(extrainfo_t *extrainfo tor_free(extrainfo->cache_info.signed_descriptor_body); tor_free(extrainfo->pending_sig);
- /* XXXX remove this if it turns out to slow us down. */ memset(extrainfo, 88, sizeof(extrainfo_t)); /* debug bad memory usage */ tor_free(extrainfo); } @@@ -2679,6 -2655,7 +2679,6 @@@ signed_descriptor_free(signed_descripto
tor_free(sd->signed_descriptor_body);
- /* XXXX remove this once more bugs go away. */ memset(sd, 99, sizeof(signed_descriptor_t)); /* Debug bad mem usage */ tor_free(sd); } @@@ -2784,7 -2761,8 +2784,7 @@@ routerlist_insert(routerlist_t *rl, rou routerinfo_t *ri_old; signed_descriptor_t *sd_old; { - /* XXXX Remove if this slows us down. */ - routerinfo_t *ri_generated = router_get_my_routerinfo(); + const routerinfo_t *ri_generated = router_get_my_routerinfo(); tor_assert(ri_generated != ri); } tor_assert(ri->cache_info.routerlist_index == -1); @@@ -2806,7 -2784,6 +2806,7 @@@ &ri->cache_info); smartlist_add(rl->routers, ri); ri->cache_info.routerlist_index = smartlist_len(rl->routers) - 1; + nodelist_add_routerinfo(ri); router_dir_info_changed(); #ifdef DEBUG_ROUTERLIST routerlist_assert_ok(rl); @@@ -2827,6 -2804,7 +2827,6 @@@ extrainfo_insert(routerlist_t *rl, extr extrainfo_t *ei_tmp;
{ - /* XXXX remove this code if it slows us down. */ extrainfo_t *ei_generated = router_get_my_extrainfo(); tor_assert(ei_generated != ei); } @@@ -2872,7 -2850,8 +2872,7 @@@ static voi routerlist_insert_old(routerlist_t *rl, routerinfo_t *ri) { { - /* XXXX remove this code if it slows us down. */ - routerinfo_t *ri_generated = router_get_my_routerinfo(); + const routerinfo_t *ri_generated = router_get_my_routerinfo(); tor_assert(ri_generated != ri); } tor_assert(ri->cache_info.routerlist_index == -1); @@@ -2912,8 -2891,6 +2912,8 @@@ routerlist_remove(routerlist_t *rl, rou tor_assert(0 <= idx && idx < smartlist_len(rl->routers)); tor_assert(smartlist_get(rl->routers, idx) == ri);
+ nodelist_remove_routerinfo(ri); + /* make sure the rephist module knows that it's not running */ rep_hist_note_router_unreachable(ri->cache_info.identity_digest, now);
@@@ -3025,7 -3002,8 +3025,7 @@@ routerlist_replace(routerlist_t *rl, ro routerinfo_t *ri_tmp; extrainfo_t *ei_tmp; { - /* XXXX Remove this if it turns out to slow us down. */ - routerinfo_t *ri_generated = router_get_my_routerinfo(); + const routerinfo_t *ri_generated = router_get_my_routerinfo(); tor_assert(ri_generated != ri_new); } tor_assert(ri_old != ri_new); @@@ -3035,9 -3013,6 +3035,9 @@@ tor_assert(0 <= idx && idx < smartlist_len(rl->routers)); tor_assert(smartlist_get(rl->routers, idx) == ri_old);
+ nodelist_remove_routerinfo(ri_old); + nodelist_add_routerinfo(ri_new); + router_dir_info_changed(); if (idx >= 0) { smartlist_set(rl->routers, idx, ri_new); @@@ -3184,27 -3159,28 +3184,27 @@@ routerlist_reset_warnings(void void router_set_status(const char *digest, int up) { - routerinfo_t *router; - routerstatus_t *status; + node_t *node; tor_assert(digest);
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d, if (!memcmp(d->digest, digest, DIGEST_LEN)) d->is_running = up);
- router = router_get_by_digest(digest); - if (router) { - log_debug(LD_DIR,"Marking router '%s/%s' as %s.", - router->nickname, router->address, up ? "up" : "down"); - if (!up && router_is_me(router) && !we_are_hibernating()) + node = node_get_mutable_by_id(digest); + if (node) { +#if 0 + char buf[MAX_VERBOSE_NICKNAME_LEN+1]; + node_get_verbose_nickname(node,buf); + log_debug(LD_DIR,"Marking router %s as %s.", + buf, up ? "up" : "down"); +#endif + if (!up && node_is_me(node) && !we_are_hibernating()) log_warn(LD_NET, "We just marked ourself as down. Are your external " "addresses reachable?"); - router->is_running = up; - } - status = router_get_consensus_status_by_id(digest); - if (status && status->is_running != up) { - status->is_running = up; - control_event_networkstatus_changed_single(status); + node->is_running = up; } + router_dir_info_changed(); }
@@@ -3233,7 -3209,8 +3233,8 @@@ router_add_to_routerlist(routerinfo_t * int from_cache, int from_fetch) { const char *id_digest; - int authdir = authdir_mode_handles_descs(get_options(), router->purpose); + or_options_t *options = get_options(); + int authdir = authdir_mode_handles_descs(options, router->purpose); int authdir_believes_valid = 0; routerinfo_t *old_router; networkstatus_t *consensus = networkstatus_get_latest_consensus(); @@@ -3247,7 -3224,7 +3248,7 @@@
id_digest = router->cache_info.identity_digest;
- old_router = router_get_by_digest(id_digest); + old_router = router_get_mutable_by_digest(id_digest);
/* Make sure that we haven't already got this exact descriptor. */ if (sdmap_get(routerlist->desc_digest_map, @@@ -3278,12 -3255,12 +3279,12 @@@
if (authdir) { if (authdir_wants_to_reject_router(router, msg, - !from_cache && !from_fetch)) { + !from_cache && !from_fetch, + &authdir_believes_valid)) { tor_assert(*msg); routerinfo_free(router); return ROUTER_AUTHDIR_REJECTS; } - authdir_believes_valid = router->is_valid; } else if (from_fetch) { /* Only check the descriptor digest against the network statuses when * we are receiving in response to a fetch. */ @@@ -3310,15 -3287,14 +3311,15 @@@ SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns, { routerstatus_t *rs = - networkstatus_v2_find_entry(ns, id_digest); + networkstatus_v2_find_mutable_entry(ns, id_digest); if (rs && !memcmp(rs->descriptor_digest, router->cache_info.signed_descriptor_digest, DIGEST_LEN)) rs->need_to_mirror = 0; }); if (consensus) { - routerstatus_t *rs = networkstatus_vote_find_entry(consensus, id_digest); + routerstatus_t *rs = networkstatus_vote_find_mutable_entry( + consensus, id_digest); if (rs && !memcmp(rs->descriptor_digest, router->cache_info.signed_descriptor_digest, DIGEST_LEN)) { @@@ -3339,6 -3315,20 +3340,20 @@@ return ROUTER_NOT_IN_CONSENSUS; }
+ /* If we're reading a bridge descriptor from our cache, and we don't + * recognize it as one of our currently configured bridges, drop the + * descriptor. Otherwise we could end up using it as one of our entry + * guards even if it isn't in our Bridge config lines. */ + if (router->purpose == ROUTER_PURPOSE_BRIDGE && from_cache && + !authdir_mode_bridge(options) && + !routerinfo_is_a_configured_bridge(router)) { + log_info(LD_DIR, "Dropping bridge descriptor for '%s' because we have " + "no bridge configured at that address.", router->nickname); + *msg = "Router descriptor was not a configured bridge."; + routerinfo_free(router); + return ROUTER_WAS_NOT_WANTED; + } + /* If we have a router with the same identity key, choose the newer one. */ if (old_router) { if (!in_consensus && (router->cache_info.published_on <= @@@ -3918,7 -3908,7 +3933,7 @@@ router_load_extrainfo_from_string(cons static int signed_desc_digest_is_recognized(signed_descriptor_t *desc) { - routerstatus_t *rs; + const routerstatus_t *rs; networkstatus_t *consensus = networkstatus_get_latest_consensus(); int caches = directory_caches_dir_info(get_options()); const smartlist_t *networkstatus_v2_list = networkstatus_get_v2_list(); @@@ -3951,34 -3941,33 +3966,34 @@@ routerlist_retry_directory_downloads(ti router_reset_descriptor_download_failures(); update_networkstatus_downloads(now); update_router_descriptor_downloads(now); + update_microdesc_downloads(now); }
-/** Return 1 if all running sufficiently-stable routers will reject +/** Return 1 if all running sufficiently-stable routers we can use will reject * addr:port, return 0 if any might accept it. */ int -router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port, - int need_uptime) -{ +router_exit_policy_all_nodes_reject(uint32_t addr, uint16_t port, + int need_uptime) +{ /* XXXX MOVE */ addr_policy_result_t r; - if (!routerlist) return 1;
- SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router, - { - if (router->is_running && - !router_is_unreliable(router, need_uptime, 0, 0)) { - r = compare_addr_to_addr_policy(addr, port, router->exit_policy); + SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { + if (node->is_running && + !node_is_unreliable(node, need_uptime, 0, 0)) { + + r = compare_addr_to_node_policy(addr, port, node); + if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED) return 0; /* this one could be ok. good enough. */ } - }); + } SMARTLIST_FOREACH_END(node); return 1; /* all will reject. */ }
/** Return true iff <b>router</b> does not permit exit streams. */ int -router_exit_policy_rejects_all(routerinfo_t *router) +router_exit_policy_rejects_all(const routerinfo_t *router) { return router->policy_is_reject_star; } @@@ -4113,9 -4102,7 +4128,9 @@@ any_trusted_dir_is_v1_authority(void /** For every current directory connection whose purpose is <b>purpose</b>, * and where the resource being downloaded begins with <b>prefix</b>, split * rest of the resource into base16 fingerprints, decode them, and set the - * corresponding elements of <b>result</b> to a nonzero value. */ + * corresponding elements of <b>result</b> to a nonzero value. + * DOCDOC purpose==microdesc + */ static void list_pending_downloads(digestmap_t *result, int purpose, const char *prefix) @@@ -4123,23 -4110,20 +4138,23 @@@ const size_t p_len = strlen(prefix); smartlist_t *tmp = smartlist_create(); smartlist_t *conns = get_connection_array(); + int flags = DSR_HEX; + if (purpose == DIR_PURPOSE_FETCH_MICRODESC) + flags = DSR_DIGEST256|DSR_BASE64;
tor_assert(result);
- SMARTLIST_FOREACH(conns, connection_t *, conn, - { + SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) { if (conn->type == CONN_TYPE_DIR && conn->purpose == purpose && !conn->marked_for_close) { const char *resource = TO_DIR_CONN(conn)->requested_resource; if (!strcmpstart(resource, prefix)) dir_split_resource_into_fingerprints(resource + p_len, - tmp, NULL, DSR_HEX); + tmp, NULL, flags); } - }); + } SMARTLIST_FOREACH_END(conn); + SMARTLIST_FOREACH(tmp, char *, d, { digestmap_set(result, d, (void*)1); @@@ -4159,21 -4143,13 +4174,21 @@@ list_pending_descriptor_downloads(diges list_pending_downloads(result, purpose, "d/"); }
-/** Launch downloads for all the descriptors whose digests are listed - * as digests[i] for lo <= i < hi. (Lo and hi may be out of range.) - * If <b>source</b> is given, download from <b>source</b>; otherwise, - * download from an appropriate random directory server. +/** DOCDOC */ +/*XXXX NM should use digest256, if one comes into being. */ +void +list_pending_microdesc_downloads(digestmap_t *result) +{ + list_pending_downloads(result, DIR_PURPOSE_FETCH_MICRODESC, "d/"); +} + +/** Launch downloads for all the descriptors whose digests or digests256 + * are listed as digests[i] for lo <= i < hi. (Lo and hi may be out of + * range.) If <b>source</b> is given, download from <b>source</b>; + * otherwise, download from an appropriate random directory server. */ static void -initiate_descriptor_downloads(routerstatus_t *source, +initiate_descriptor_downloads(const routerstatus_t *source, int purpose, smartlist_t *digests, int lo, int hi, int pds_flags) @@@ -4181,20 -4157,6 +4196,20 @@@ int i, n = hi-lo; char *resource, *cp; size_t r_len; + + int digest_len = DIGEST_LEN, enc_digest_len = HEX_DIGEST_LEN; + char sep = '+'; + int b64_256 = 0; + + if (purpose == DIR_PURPOSE_FETCH_MICRODESC) { + /* Microdescriptors are downloaded by "-"-separated base64-encoded + * 256-bit digests. */ + digest_len = DIGEST256_LEN; + enc_digest_len = BASE64_DIGEST256_LEN; + sep = '-'; + b64_256 = 1; + } + if (n <= 0) return; if (lo < 0) @@@ -4202,19 -4164,15 +4217,19 @@@ if (hi > smartlist_len(digests)) hi = smartlist_len(digests);
- r_len = 8 + (HEX_DIGEST_LEN+1)*n; + r_len = 8 + (enc_digest_len+1)*n; cp = resource = tor_malloc(r_len); memcpy(cp, "d/", 2); cp += 2; for (i = lo; i < hi; ++i) { - base16_encode(cp, r_len-(cp-resource), - smartlist_get(digests,i), DIGEST_LEN); - cp += HEX_DIGEST_LEN; - *cp++ = '+'; + if (b64_256) { + digest256_to_base64(cp, smartlist_get(digests, i)); + } else { + base16_encode(cp, r_len-(cp-resource), + smartlist_get(digests,i), digest_len); + } + cp += enc_digest_len; + *cp++ = sep; } memcpy(cp-1, ".z", 3);
@@@ -4237,7 -4195,7 +4252,7 @@@ static INLINE int client_would_use_router(routerstatus_t *rs, time_t now, or_options_t *options) { - if (!rs->is_running && !options->FetchUselessDescriptors) { + if (!rs->is_flagged_running && !options->FetchUselessDescriptors) { /* If we had this router descriptor, we wouldn't even bother using it. * But, if we want to have a complete list, fetch it anyway. */ return 0; @@@ -4261,7 -4219,6 +4276,7 @@@ * So use 96 because it's a nice number. */ #define MAX_DL_PER_REQUEST 96 +#define MAX_MICRODESC_DL_PER_REQUEST 92 /** Don't split our requests so finely that we are requesting fewer than * this number per server. */ #define MIN_DL_PER_REQUEST 4 @@@ -4276,33 -4233,21 +4291,33 @@@ * them until they have more, or until this amount of time has passed. */ #define MAX_CLIENT_INTERVAL_WITHOUT_REQUEST (10*60)
-/** Given a list of router descriptor digests in <b>downloadable</b>, decide - * whether to delay fetching until we have more. If we don't want to delay, - * launch one or more requests to the appropriate directory authorities. */ -static void -launch_router_descriptor_downloads(smartlist_t *downloadable, - routerstatus_t *source, time_t now) +/** Given a <b>purpose</b> (FETCH_MICRODESC or FETCH_SERVERDESC) and a list of + * router descriptor digests or microdescriptor digest256s in + * <b>downloadable</b>, decide whether to delay fetching until we have more. + * If we don't want to delay, launch one or more requests to the appropriate + * directory authorities. + */ +void +launch_descriptor_downloads(int purpose, + smartlist_t *downloadable, + const routerstatus_t *source, time_t now) { int should_delay = 0, n_downloadable; or_options_t *options = get_options(); + const char *descname; + + tor_assert(purpose == DIR_PURPOSE_FETCH_SERVERDESC || + purpose == DIR_PURPOSE_FETCH_MICRODESC); + + descname = (purpose == DIR_PURPOSE_FETCH_SERVERDESC) ? + "routerdesc" : "microdesc";
n_downloadable = smartlist_len(downloadable); if (!directory_fetches_dir_info_early(options)) { if (n_downloadable >= MAX_DL_TO_DELAY) { log_debug(LD_DIR, - "There are enough downloadable routerdescs to launch requests."); + "There are enough downloadable %ss to launch requests.", + descname); should_delay = 0; } else { should_delay = (last_routerdesc_download_attempted + @@@ -4310,15 -4255,13 +4325,15 @@@ if (!should_delay && n_downloadable) { if (last_routerdesc_download_attempted) { log_info(LD_DIR, - "There are not many downloadable routerdescs, but we've " + "There are not many downloadable %ss, but we've " "been waiting long enough (%d seconds). Downloading.", + descname, (int)(now-last_routerdesc_download_attempted)); } else { log_info(LD_DIR, - "There are not many downloadable routerdescs, but we haven't " - "tried downloading descriptors recently. Downloading."); + "There are not many downloadable %ss, but we haven't " + "tried downloading descriptors recently. Downloading.", + descname); } } } @@@ -4345,19 -4288,12 +4360,19 @@@ * update_router_descriptor_downloads() later on, once the connections * have succeeded or failed. */ - pds_flags |= PDS_NO_EXISTING_SERVERDESC_FETCH; + pds_flags |= (purpose == DIR_PURPOSE_FETCH_MICRODESC) ? + PDS_NO_EXISTING_MICRODESC_FETCH : + PDS_NO_EXISTING_SERVERDESC_FETCH; }
n_per_request = CEIL_DIV(n_downloadable, MIN_REQUESTS); - if (n_per_request > MAX_DL_PER_REQUEST) - n_per_request = MAX_DL_PER_REQUEST; + if (purpose == DIR_PURPOSE_FETCH_MICRODESC) { + if (n_per_request > MAX_MICRODESC_DL_PER_REQUEST) + n_per_request = MAX_MICRODESC_DL_PER_REQUEST; + } else { + if (n_per_request > MAX_DL_PER_REQUEST) + n_per_request = MAX_DL_PER_REQUEST; + } if (n_per_request < MIN_DL_PER_REQUEST) n_per_request = MIN_DL_PER_REQUEST;
@@@ -4372,7 -4308,7 +4387,7 @@@ req_plural, n_downloadable, rtr_plural, n_per_request); smartlist_sort_digests(downloadable); for (i=0; i < n_downloadable; i += n_per_request) { - initiate_descriptor_downloads(source, DIR_PURPOSE_FETCH_SERVERDESC, + initiate_descriptor_downloads(source, purpose, downloadable, i, i+n_per_request, pds_flags); } @@@ -4562,14 -4498,15 +4577,14 @@@ update_consensus_router_descriptor_down
map = digestmap_new(); list_pending_descriptor_downloads(map, 0); - SMARTLIST_FOREACH(consensus->routerstatus_list, void *, rsp, - { + SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, void *, rsp) { routerstatus_t *rs = is_vote ? &(((vote_routerstatus_t *)rsp)->status) : rsp; signed_descriptor_t *sd; if ((sd = router_get_by_descriptor_digest(rs->descriptor_digest))) { - routerinfo_t *ri; + const routerinfo_t *ri; ++n_have; - if (!(ri = router_get_by_digest(rs->identity_digest)) || + if (!(ri = router_get_by_id_digest(rs->identity_digest)) || memcmp(ri->cache_info.signed_descriptor_digest, sd->signed_descriptor_digest, DIGEST_LEN)) { /* We have a descriptor with this digest, but either there is no @@@ -4602,8 -4539,7 +4617,8 @@@ if (is_vote && source) { char time_bufnew[ISO_TIME_LEN+1]; char time_bufold[ISO_TIME_LEN+1]; - routerinfo_t *oldrouter = router_get_by_digest(rs->identity_digest); + const routerinfo_t *oldrouter; + oldrouter = router_get_by_id_digest(rs->identity_digest); format_iso_time(time_bufnew, rs->published_on); if (oldrouter) format_iso_time(time_bufold, oldrouter->cache_info.published_on); @@@ -4613,7 -4549,7 +4628,7 @@@ source->nickname, oldrouter ? "known" : "unknown"); } smartlist_add(downloadable, rs->descriptor_digest); - }); + } SMARTLIST_FOREACH_END(rsp);
if (!authdir_mode_handles_descs(options, ROUTER_PURPOSE_GENERAL) && smartlist_len(no_longer_old)) { @@@ -4645,8 -4581,7 +4660,8 @@@ smartlist_len(downloadable), n_delayed, n_have, n_in_oldrouters, n_would_reject, n_wouldnt_use, n_inprogress);
- launch_router_descriptor_downloads(downloadable, source, now); + launch_descriptor_downloads(DIR_PURPOSE_FETCH_SERVERDESC, + downloadable, source, now);
digestmap_free(map, NULL); done: @@@ -4671,13 -4606,10 +4686,13 @@@ update_router_descriptor_downloads(time if (directory_fetches_dir_info_early(options)) { update_router_descriptor_cache_downloads_v2(now); } + update_consensus_router_descriptor_downloads(now, 0, - networkstatus_get_reasonably_live_consensus(now)); + networkstatus_get_reasonably_live_consensus(now, FLAV_NS));
/* XXXX021 we could be smarter here; see notes on bug 652. */ + /* XXXX NM Microdescs: if we're not fetching microdescriptors, we need + * to make something else invoke this. */ /* If we're a server that doesn't have a configured address, we rely on * directory fetches to learn when our address changes. So if we haven't * tried to get any routerdescs in a long time, try a dummy fetch now. */ @@@ -4724,7 -4656,7 +4739,7 @@@ update_extrainfo_downloads(time_t now sd = &((routerinfo_t*)smartlist_get(lst, i))->cache_info; if (sd->is_extrainfo) continue; /* This should never happen. */ - if (old_routers && !router_get_by_digest(sd->identity_digest)) + if (old_routers && !router_get_by_id_digest(sd->identity_digest)) continue; /* Couldn't check the signature if we got it. */ if (sd->extrainfo_is_bogus) continue; @@@ -4825,7 -4757,7 +4840,7 @@@ count_usable_descriptors(int *num_prese
SMARTLIST_FOREACH(consensus->routerstatus_list, routerstatus_t *, rs, { - if (in_set && ! routerset_contains_routerstatus(in_set, rs)) + if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1)) continue; if (client_would_use_router(rs, now, options)) { ++*num_usable; /* the consensus says we want it. */ @@@ -4848,7 -4780,7 +4863,7 @@@ count_loading_descriptors_progress(void int num_present = 0, num_usable=0; time_t now = time(NULL); const networkstatus_t *consensus = - networkstatus_get_reasonably_live_consensus(now); + networkstatus_get_reasonably_live_consensus(now, FLAV_NS); double fraction;
if (!consensus) @@@ -4878,7 -4810,7 +4893,7 @@@ update_router_have_minimum_dir_info(voi int res; or_options_t *options = get_options(); const networkstatus_t *consensus = - networkstatus_get_reasonably_live_consensus(now); + networkstatus_get_reasonably_live_consensus(now, FLAV_NS);
if (!consensus) { if (!networkstatus_get_latest_consensus()) @@@ -4988,7 -4920,7 +5003,7 @@@ router_reset_descriptor_download_failur * would not cause a recent (post 0.1.1.6) dirserver to republish. */ int -router_differences_are_cosmetic(routerinfo_t *r1, routerinfo_t *r2) +router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2) { time_t r1pub, r2pub; long time_difference; @@@ -4996,7 -4928,7 +5011,7 @@@
/* r1 should be the one that was published first. */ if (r1->cache_info.published_on > r2->cache_info.published_on) { - routerinfo_t *ri_tmp = r2; + const routerinfo_t *ri_tmp = r2; r2 = r1; r1 = ri_tmp; } @@@ -5015,6 -4947,7 +5030,6 @@@ (r1->contact_info && r2->contact_info && strcasecmp(r1->contact_info, r2->contact_info)) || r1->is_hibernating != r2->is_hibernating || - r1->has_old_dnsworkers != r2->has_old_dnsworkers || cmp_addr_policies(r1->exit_policy, r2->exit_policy)) return 0; if ((r1->declared_family == NULL) != (r2->declared_family == NULL)) @@@ -5069,8 -5002,7 +5084,8 @@@ * incompatibility (if any). **/ int -routerinfo_incompatible_with_extrainfo(routerinfo_t *ri, extrainfo_t *ei, +routerinfo_incompatible_with_extrainfo(const routerinfo_t *ri, + extrainfo_t *ei, signed_descriptor_t *sd, const char **msg) { @@@ -5078,7 -5010,7 +5093,7 @@@ tor_assert(ri); tor_assert(ei); if (!sd) - sd = &ri->cache_info; + sd = (signed_descriptor_t*)&ri->cache_info;
if (ei->bad_sig) { if (msg) *msg = "Extrainfo signature was bad, or signed with wrong key."; @@@ -5142,7 -5074,7 +5157,7 @@@ /** Assert that the internal representation of <b>rl</b> is * self-consistent. */ void -routerlist_assert_ok(routerlist_t *rl) +routerlist_assert_ok(const routerlist_t *rl) { routerinfo_t *r2; signed_descriptor_t *sd2; @@@ -5232,7 -5164,7 +5247,7 @@@ * If <b>router</b> is NULL, it just frees its internal memory and returns. */ const char * -esc_router_info(routerinfo_t *router) +esc_router_info(const routerinfo_t *router) { static char *info=NULL; char *esc_contact, *esc_platform; @@@ -5334,6 -5266,38 +5349,6 @@@ routerset_get_countryname(const char *c return country; }
-#if 0 -/** Add the GeoIP database's integer index (+1) of a valid two-character - * country code to the routerset's <b>countries</b> bitarray. Return the - * integer index if the country code is valid, -1 otherwise.*/ -static int -routerset_add_country(const char *c) -{ - char country[3]; - country_t cc; - - /* XXXX: Country codes must be of the form {[a-z?]{2}} but this accepts - {[.]{2}}. Do we need to be strict? -RH */ - /* Nope; if the country code is bad, we'll get 0 when we look it up. */ - - if (!geoip_is_loaded()) { - log(LOG_WARN, LD_CONFIG, "GeoIP database not loaded: Cannot add country" - "entry %s, ignoring.", c); - return -1; - } - - memcpy(country, c+1, 2); - country[2] = '\0'; - tor_strlower(country); - - if ((cc=geoip_get_country(country))==-1) { - log(LOG_WARN, LD_CONFIG, "Country code '%s' is not valid, ignoring.", - country); - } - return cc; -} -#endif - /** Update the routerset's <b>countries</b> bitarray_t. Called whenever * the GeoIP database is reloaded. */ @@@ -5435,7 -5399,7 +5450,7 @@@ refresh_all_country_info(void if (options->_ExcludeExitNodesUnion) routerset_refresh_countries(options->_ExcludeExitNodesUnion);
- routerlist_refresh_countries(); + nodelist_refresh_countries(); }
/** Add all members of the set <b>source</b> to <b>target</b>. */ @@@ -5485,10 -5449,11 +5500,10 @@@ routerset_is_empty(const routerset_t *s static int routerset_contains(const routerset_t *set, const tor_addr_t *addr, uint16_t orport, - const char *nickname, const char *id_digest, int is_named, + const char *nickname, const char *id_digest, country_t country) { if (!set || !set->list) return 0; - (void) is_named; /* not supported */ if (nickname && strmap_get_lc(set->names, nickname)) return 4; if (id_digest && digestmap_get(set->digests, id_digest)) @@@ -5516,14 -5481,13 +5531,14 @@@ routerset_contains_extendinfo(const rou ei->port, ei->nickname, ei->identity_digest, -1 /*country*/); }
-/** Return true iff <b>ri</b> is in <b>set</b>. */ +/** Return true iff <b>ri</b> is in <b>set</b>. If country is <b>-1</b>, we + * look up the country. */ int -routerset_contains_router(const routerset_t *set, routerinfo_t *ri) +routerset_contains_router(const routerset_t *set, const routerinfo_t *ri, + country_t country) { tor_addr_t addr; tor_addr_from_ipv4h(&addr, ri->addr); @@@ -5532,15 -5496,13 +5547,15 @@@ ri->or_port, ri->nickname, ri->cache_info.identity_digest, - ri->is_named, - ri->country); + country); }
-/** Return true iff <b>rs</b> is in <b>set</b>. */ +/** Return true iff <b>rs</b> is in <b>set</b>. If country is <b>-1</b>, we + * look up the country. */ int -routerset_contains_routerstatus(const routerset_t *set, routerstatus_t *rs) +routerset_contains_routerstatus(const routerset_t *set, + const routerstatus_t *rs, + country_t country) { tor_addr_t addr; tor_addr_from_ipv4h(&addr, rs->addr); @@@ -5549,55 -5511,46 +5564,55 @@@ rs->or_port, rs->nickname, rs->identity_digest, - rs->is_named, - -1); + country); +} + +/** Return true iff <b>node</b> is in <b>set</b>. */ +int +routerset_contains_node(const routerset_t *set, const node_t *node) +{ + if (node->rs) + return routerset_contains_routerstatus(set, node->rs, node->country); + else if (node->ri) + return routerset_contains_router(set, node->ri, node->country); + else + return 0; }
-/** Add every known routerinfo_t that is a member of <b>routerset</b> to +/** Add every known node_t that is a member of <b>routerset</b> to * <b>out</b>. If <b>running_only</b>, only add the running ones. */ void -routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset, - int running_only) -{ +routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset, + int running_only) +{ /* XXXX MOVE */ tor_assert(out); if (!routerset || !routerset->list) return; - if (!warned_nicknames) - warned_nicknames = smartlist_create(); - if (routerset_is_list(routerset)) {
+ if (routerset_is_list(routerset)) { /* No routers are specified by type; all are given by name or digest. * we can do a lookup in O(len(list)). */ SMARTLIST_FOREACH(routerset->list, const char *, name, { - routerinfo_t *router = router_get_by_nickname(name, 1); - if (router) { - if (!running_only || router->is_running) - smartlist_add(out, router); + const node_t *node = node_get_by_nickname(name, 1); + if (node) { + if (!running_only || node->is_running) + smartlist_add(out, (void*)node); } }); } else { /* We need to iterate over the routerlist to get all the ones of the * right kind. */ - routerlist_t *rl = router_get_routerlist(); - SMARTLIST_FOREACH(rl->routers, routerinfo_t *, router, { - if (running_only && !router->is_running) + smartlist_t *nodes = nodelist_get_list(); + SMARTLIST_FOREACH(nodes, const node_t *, node, { + if (running_only && !node->is_running) continue; - if (routerset_contains_router(routerset, router)) - smartlist_add(out, router); + if (routerset_contains_node(routerset, node)) + smartlist_add(out, (void*)node); }); } }
-/** Add to <b>target</b> every routerinfo_t from <b>source</b> except: +/** Add to <b>target</b> every node_t from <b>source</b> except: * * 1) Don't add it if <b>include</b> is non-empty and the relay isn't in * <b>include</b>; and @@@ -5606,39 -5559,39 +5621,39 @@@ * 3) If <b>running_only</b>, don't add non-running routers. */ void -routersets_get_disjunction(smartlist_t *target, +routersets_get_node_disjunction(smartlist_t *target, const smartlist_t *source, const routerset_t *include, const routerset_t *exclude, int running_only) { - SMARTLIST_FOREACH(source, routerinfo_t *, router, { + SMARTLIST_FOREACH(source, const node_t *, node, { int include_result; - if (running_only && !router->is_running) + if (running_only && !node->is_running) continue; if (!routerset_is_empty(include)) - include_result = routerset_contains_router(include, router); + include_result = routerset_contains_node(include, node); else include_result = 1;
if (include_result) { - int exclude_result = routerset_contains_router(exclude, router); + int exclude_result = routerset_contains_node(exclude, node); if (include_result >= exclude_result) - smartlist_add(target, router); + smartlist_add(target, (void*)node); } }); }
-/** Remove every routerinfo_t from <b>lst</b> that is in <b>routerset</b>. */ +/** Remove every node_t from <b>lst</b> that is in <b>routerset</b>. */ void -routerset_subtract_routers(smartlist_t *lst, const routerset_t *routerset) -{ +routerset_subtract_nodes(smartlist_t *lst, const routerset_t *routerset) +{ /*XXXX MOVE ? */ tor_assert(lst); if (!routerset) return; - SMARTLIST_FOREACH(lst, routerinfo_t *, r, { - if (routerset_contains_router(routerset, r)) { + SMARTLIST_FOREACH(lst, const node_t *, node, { + if (routerset_contains_node(routerset, node)) { //log_debug(LD_DIR, "Subtracting %s",r->nickname); - SMARTLIST_DEL_CURRENT(lst, r); + SMARTLIST_DEL_CURRENT(lst, node); } }); } @@@ -5699,23 -5652,18 +5714,23 @@@ routerset_free(routerset_t *routerset /** Refresh the country code of <b>ri</b>. This function MUST be called on * each router when the GeoIP database is reloaded, and on all new routers. */ void -routerinfo_set_country(routerinfo_t *ri) +node_set_country(node_t *node) { - ri->country = geoip_get_country_by_ip(ri->addr); + if (node->rs) + node->country = geoip_get_country_by_ip(node->rs->addr); + else if (node->ri) + node->country = geoip_get_country_by_ip(node->ri->addr); + else + node->country = -1; }
/** Set the country code of all routers in the routerlist. */ void -routerlist_refresh_countries(void) +nodelist_refresh_countries(void) /* MOVE */ { - routerlist_t *rl = router_get_routerlist(); - SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, - routerinfo_set_country(ri)); + smartlist_t *nodes = nodelist_get_list(); + SMARTLIST_FOREACH(nodes, node_t *, node, + node_set_country(node)); }
/** Determine the routers that are responsible for <b>id</b> (binary) and @@@ -5764,9 -5712,9 +5779,9 @@@ hid_serv_get_responsible_directories(sm int hid_serv_acting_as_directory(void) { - routerinfo_t *me = router_get_my_routerinfo(); + const routerinfo_t *me = router_get_my_routerinfo(); networkstatus_t *c; - routerstatus_t *rs; + const routerstatus_t *rs; if (!me) return 0; if (!get_options()->HidServDirectoryV2) { @@@ -5798,7 -5746,7 +5813,7 @@@ int hid_serv_responsible_for_desc_id(const char *query) { - routerinfo_t *me; + const routerinfo_t *me; routerstatus_t *last_rs; const char *my_id, *last_id; int result;