commit 8b686d98c47226dfc4d7c87d6a472b592135ae07 Merge: 3256627 99621bc Author: Nick Mathewson nickm@torproject.org Date: Wed Apr 27 14:36:30 2011 -0400
Merge maint-0.2.2 for the bug1090-part1-squashed branch
Resolved conflicts in: doc/tor.1.txt src/or/circuitbuild.c src/or/circuituse.c src/or/connection_edge.c src/or/connection_edge.h src/or/directory.c src/or/rendclient.c src/or/routerlist.c src/or/routerlist.h
These were mostly releated to the routerinfo_t->node_t conversion.
changes/bug1090-general | 73 ++++++++++++++++ changes/bug1090-launch-warning | 5 + changes/exitnodes_reliable | 7 ++ doc/tor.1.txt | 75 ++++++++++++---- src/or/circuitbuild.c | 187 +++++++++++++++++++++++----------------- src/or/circuitlist.c | 70 +++++++++++++++ src/or/circuitlist.h | 1 + src/or/circuituse.c | 76 ++++++++++------ src/or/circuituse.h | 2 + src/or/config.c | 24 +++-- src/or/connection_edge.c | 117 +++++++++++++++++++------ src/or/connection_edge.h | 4 +- src/or/directory.c | 31 ++++++- src/or/or.h | 11 ++- src/or/rendclient.c | 85 ++++++++++++++++--- src/or/rendclient.h | 1 + src/or/rendcommon.c | 2 +- src/or/rendservice.c | 40 +++++++-- src/or/router.c | 20 ++++ src/or/routerlist.c | 73 ++++++++++++++-- src/or/routerlist.h | 8 ++- 21 files changed, 712 insertions(+), 200 deletions(-)
diff --cc doc/tor.1.txt index 5a70cd2,866a702..f24eaba --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@@ -512,27 -508,55 +526,54 @@@ The following options are useful only f
**ExcludeExitNodes** __node__,__node__,__...__:: A list of identity fingerprints, nicknames, country codes and address - patterns of nodes to never use when picking an exit node. Note that any + patterns of nodes to never use when picking an exit node---that is, a + node that delivers traffic for you outside the Tor network. Note that any node listed in ExcludeNodes is automatically considered to be part of this - list. - - **EntryNodes** __node__,__node__,__...__:: - A list of identity fingerprints, nicknames, country codes and address - patterns of nodes to use for the first hop in normal circuits. These are - treated only as preferences unless StrictNodes (see below) is also set. + list too. See also the caveats on the "ExitNodes" option below
- **ExitNodes** __node__,__node__,__...__:: A list of identity fingerprints, nicknames, country codes and address - patterns of nodes to use for the last hop in normal exit circuits. These - are treated only as preferences unless StrictNodes (see below) is also set. + patterns of nodes to use as exit node---that is, a + node that delivers traffic for you outside the Tor network. + + + + Note that if you list too few nodes here, or if you exclude too many exit + nodes with ExcludeExitNodes, you can degrade functionality. For example, + if none of the exits you list allows traffic on port 80 or 443, you won't + be able to browse the web. + + + + Note also that not every circuit is used to deliver traffic outside of + the Tor network. It is normal to see non-exit circuits (such as those + used to connect to hidden services, those that do directory fetches, + those used for self-tests, and so on) that end at a non-exit node. To + keep a node from being used entirely, see ExcludeNodes and StrictNodes. + + + + The ExcludeNodes option overrides this option: any node listed in both + ExitNodes and ExcludeNodes is treated as excluded. + + + + The .exit address notation, if enabled, overrides this option. + + **EntryNodes** __node__,__node__,__...__:: - A list of identity fingerprints and nicknames of nodes - to use for the first hop in your normal circuits. (Country codes and - address patterns are not yet supported.) This includes all ++ A list of identity fingerprints, nicknames, and country codes of nodes ++ to use for the first hop in your normal circuits. ++ This includes all + circuits except for direct connections to directory servers. The Bridge + option overrides this option; if you have configured bridges and + UseBridges is 1, the Bridges are used as your entry nodes. + + + + The ExcludeNodes option overrides this option: any node listed in both + EntryNodes and ExcludeNodes is treated as excluded.
**StrictNodes** **0**|**1**:: - If 1 and EntryNodes config option is set, Tor will never use any nodes - besides those listed in EntryNodes for the first hop of a normal circuit. - If 1 and ExitNodes config option is set, Tor will never use any nodes - besides those listed in ExitNodes for the last hop of a normal exit - circuit. Note that Tor might still use these nodes for non-exit circuits - such as one-hop directory fetches or hidden service support circuits. + If StrictNodes is set to 1, Tor will treat the ExcludeNodes option as a + requirement to follow for all the circuits you generate, even if doing so + will break functionality for you. If StrictNodes is set to 0, Tor will + still try to avoid nodes in the ExcludeNodes list, but it will err on the + side of avoiding unexpected errors. Specifically, StrictNodes 0 tells + Tor that it is okay to use an excluded node when it is *necessary* to + perform self-tests, connect to + a hidden service, provide a hidden service to a client, fulfill a .exit + request, upload directory information, or download directory information. + (Default: 0)
**FascistFirewall** **0**|**1**:: If 1, Tor will only create outgoing connections to ORs running on ports diff --cc src/or/circuitbuild.c index ff656fd,90572d5..cc78d99 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@@ -2673,18 -2686,26 +2674,25 @@@ choose_good_exit_server_general(int nee n_supported[i] = -1; continue; /* skip routers that are known to be down or bad exits */ } - if (node_is_unreliable(node, need_uptime, need_capacity, 0) && - (!options->ExitNodes || - !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 - * they ask for is rare. Or something. */ - + if (options->_ExcludeExitNodesUnion && - routerset_contains_router(options->_ExcludeExitNodesUnion, router)) { ++ routerset_contains_node(options->_ExcludeExitNodesUnion, node)) { n_supported[i] = -1; - continue; /* skip routers that are not suitable, unless we have - * ExitNodes set, in which case we asked for it */ + continue; /* user asked us not to use it, no matter what */ + } + if (options->ExitNodes && - !routerset_contains_router(options->ExitNodes, router)) { ++ !routerset_contains_node(options->ExitNodes, node)) { + n_supported[i] = -1; + continue; /* not one of our chosen exit nodes */ + } + - if (router_is_unreliable(router, need_uptime, need_capacity, 0)) { ++ if (node_is_unreliable(node, need_uptime, need_capacity, 0)) { + n_supported[i] = -1; + continue; /* skip routers that are not suitable. Don't worry if + * this makes us reject all the possible routers: if so, + * we'll retry later in this function with need_update and + * need_capacity set to 0. */ } - if (!(router->is_valid || options->_AllowInvalid & ALLOW_INVALID_EXIT)) { + if (!(node->is_valid || options->_AllowInvalid & ALLOW_INVALID_EXIT)) { /* if it's invalid and we don't want it */ n_supported[i] = -1; // log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- invalid router.", @@@ -2704,10 -2724,11 +2712,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), node, 1)) { - if (connection_ap_can_use_exit(TO_EDGE_CONN(conn), router)) { ++ if (connection_ap_can_use_exit(TO_EDGE_CONN(conn), node)) { ++n_supported[i]; // log_fn(LOG_DEBUG,"%s is supported. n_supported[%d] now %d.", // router->nickname, i, n_supported[i]); @@@ -2741,22 -2762,13 +2749,14 @@@ /* If any routers definitely support any pending connections, choose one * at random. */ if (best_support > 0) { - smartlist_t *supporting = smartlist_create(), *use = smartlist_create(); + smartlist_t *supporting = 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_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_node_disjunction(use, supporting, NULL, - options->_ExcludeExitNodesUnion, 1); - } - node = node_sl_choose_by_bandwidth(use, WEIGHT_FOR_EXIT); - smartlist_free(use); - router = routerlist_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT); ++ node = node_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT); smartlist_free(supporting); } else { /* Either there are no pending connections, or no routers even seem to @@@ -2786,32 -2797,20 +2785,21 @@@ 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_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_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. */ - node = node_sl_choose_by_bandwidth(use, WEIGHT_FOR_EXIT); - router = routerlist_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT); - if (router) ++ node = node_sl_choose_by_bandwidth(supporting, WEIGHT_FOR_EXIT); + if (node) break; smartlist_clear(supporting); - smartlist_clear(use); } SMARTLIST_FOREACH(needed_ports, uint16_t *, cp, tor_free(cp)); smartlist_free(needed_ports); @@@ -2820,14 -2818,15 +2807,15 @@@ }
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) { + if (options->ExitNodes) { log_warn(LD_CIRC, - "No specified exit routers seem to be running, and " - "StrictNodes is set: can't choose an exit."); + "No specified %sexit routers seem to be running: " + "can't choose an exit.", + options->_ExcludeExitNodesUnion ? "non-excluded " : ""); } return NULL; } @@@ -3990,15 -3974,16 +3990,17 @@@ entry_guards_prepend_from_config(or_opt
/* Split entry guards into those on the list and those not. */
- /* 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); + /* XXXX023 Now that we allow countries and IP ranges in EntryNodes, this is + * potentially an enormous list. For now, we disable such values for + * EntryNodes in options_validate(); really, this wants a better solution. + * Perhaps we should do this calculation once whenever the list of routers + * changes or the entrynodes setting changes. + */ - routerset_get_all_routers(entry_routers, options->EntryNodes, - options->ExcludeNodes, 0); - SMARTLIST_FOREACH(entry_routers, routerinfo_t *, ri, - smartlist_add(entry_fps,ri->cache_info.identity_digest)); ++ routerset_get_all_nodes(entry_nodes, options->EntryNodes, ++ options->ExcludeNodes, 0); + SMARTLIST_FOREACH(entry_nodes, const node_t *,node, + smartlist_add(entry_fps, (void*)node->identity)); + SMARTLIST_FOREACH(entry_guards, entry_guard_t *, e, { if (smartlist_digest_isin(entry_fps, e->identity)) smartlist_add(old_entry_guards_on_list, e); @@@ -4018,19 -4003,15 +4020,15 @@@ /* 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 */ - if (options->StrictNodes) { - SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e, - entry_guard_free(e)); - } else { - smartlist_add_all(entry_guards, old_entry_guards_not_on_list); - } + /* Finally, free the remaining previously configured guards that are not in + * EntryNodes. */ + SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e, + entry_guard_free(e));
- smartlist_free(entry_routers); + smartlist_free(entry_nodes); smartlist_free(entry_fps); smartlist_free(old_entry_guards_on_list); smartlist_free(old_entry_guards_not_on_list); @@@ -4098,17 -4066,19 +4084,18 @@@ choose_random_entry(cpath_build_state_
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 0 /* since EntryNodes is always strict now, this clause is moot */ if (options->EntryNodes && - !routerset_contains_router(options->EntryNodes, r)) { + !routerset_contains_node(options->EntryNodes, node)) { /* We've come to the end of our preferred entry nodes. */ if (smartlist_len(live_entry_guards)) goto choose_and_finish; /* only choose from the ones we like */ @@@ -4121,7 -4091,8 +4108,8 @@@ "No relays from EntryNodes available. Using others."); } } + #endif - smartlist_add(live_entry_guards, r); + smartlist_add(live_entry_guards, (void*)node); if (!entry->made_contact) { /* Always start with the first not-yet-contacted entry * guard. Otherwise we might add several new ones, pick @@@ -4171,10 -4142,14 +4159,14 @@@ need_capacity = 0; goto retry; } + #if 0 + /* Removing this retry logic: if we only allow one exit, and it is in the + same family as all our entries, then we are just plain not going to win + here. */ - if (!r && entry_list_is_constrained(options) && consider_exit_family) { - /* still no? if we're using bridges, - * and our chosen exit is in the same family as all our - * bridges, then be flexible about families. */ + if (!node && entry_list_is_constrained(options) && consider_exit_family) { + /* still no? if we're using bridges or have strictentrynodes + * set, and our chosen exit is in the same family as all our + * bridges/entry guards, then be flexible about families. */ consider_exit_family = 0; goto retry; } diff --cc src/or/circuituse.c index e58d5e0,fd1cf6b..30fd818 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@@ -128,7 -127,7 +128,7 @@@ circuit_is_acceptable(circuit_t *circ, return 0; } } - if (exitnode && !connection_ap_can_use_exit(conn, exitnode, 0)) { - if (exitrouter && !connection_ap_can_use_exit(conn, exitrouter)) { ++ if (exitnode && !connection_ap_can_use_exit(conn, exitnode)) { /* can't exit from this router */ return 0; } @@@ -505,14 -511,14 +512,14 @@@ circuit_stream_is_being_handled(edge_co if (build_state->is_internal || build_state->onehop_tunnel) continue;
- exitrouter = build_state_get_exit_router(build_state); - if (exitrouter && (!need_uptime || build_state->need_uptime)) { + exitnode = build_state_get_exit_node(build_state); + if (exitnode && (!need_uptime || build_state->need_uptime)) { int ok; if (conn) { - ok = connection_ap_can_use_exit(conn, exitnode, 0); - ok = connection_ap_can_use_exit(conn, exitrouter); ++ ok = connection_ap_can_use_exit(conn, exitnode); } else { - addr_policy_result_t r = compare_addr_to_addr_policy( - 0, port, exitrouter->exit_policy); + addr_policy_result_t r; + r = compare_addr_to_node_policy(0, port, exitnode); ok = r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED; } if (ok) { @@@ -1279,11 -1293,12 +1286,12 @@@ circuit_get_open_circ_or_launch(edge_co } else { /* XXXX023 Duplicates checks in connection_ap_handshake_attach_circuit: * refactor into a single function? */ - routerinfo_t *router = router_get_by_nickname(conn->chosen_exit_name, 1); + const node_t *node = node_get_by_nickname(conn->chosen_exit_name, 1); int opt = conn->chosen_exit_optional; - if (node && !connection_ap_can_use_exit(conn, node, 0)) { - if (router && !connection_ap_can_use_exit(conn, router)) { ++ if (node && !connection_ap_can_use_exit(conn, node)) { log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP, - "Requested exit point '%s' would refuse request. %s.", + "Requested exit point '%s' is excluded or " + "would refuse request. %s.", conn->chosen_exit_name, opt ? "Trying others" : "Closing"); if (opt) { conn->chosen_exit_optional = 0; @@@ -1601,9 -1627,10 +1620,10 @@@ connection_ap_handshake_attach_circuit( } return -1; } - if (node && !connection_ap_can_use_exit(conn, node, 0)) { - if (router && !connection_ap_can_use_exit(conn, router)) { ++ if (node && !connection_ap_can_use_exit(conn, node)) { log_fn(opt ? LOG_INFO : LOG_WARN, LD_APP, - "Requested exit point '%s' would refuse request. %s.", + "Requested exit point '%s' is excluded or " + "would refuse request. %s.", conn->chosen_exit_name, opt ? "Trying others" : "Closing"); if (opt) { conn->chosen_exit_optional = 0; diff --cc src/or/connection_edge.c index 508b06b,082cd5f..29ab6c5 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@@ -808,6 -809,56 +809,56 @@@ clear_trackexithost_mappings(const cha tor_free(suffix); }
+ /** Remove all TRACKEXIT mappings from the addressmap for which the target + * host is unknown or no longer allowed. */ + void + addressmap_clear_excluded_trackexithosts(or_options_t *options) + { + const routerset_t *allow_nodes = options->ExitNodes; + const routerset_t *exclude_nodes = options->_ExcludeExitNodesUnion; + + if (!addressmap) + return; + if (routerset_is_empty(allow_nodes)) + allow_nodes = NULL; + if (allow_nodes == NULL && routerset_is_empty(exclude_nodes)) + return; + + STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) { + size_t len; + const char *target = ent->new_address, *dot; + char *nodename; - routerinfo_t *ri; /* XXX023 Use node_t. */ ++ const node_t *node; + + if (strcmpend(target, ".exit")) { + /* Not a .exit mapping */ + continue; + } else if (ent->source != ADDRMAPSRC_TRACKEXIT) { + /* Not a trackexit mapping. */ + continue; + } + len = strlen(target); + if (len < 6) + continue; /* malformed. */ + dot = target + len - 6; /* dot now points to just before .exit */ + dot = strrchr(dot, '.'); /* dot now points to the . before .exit or NULL */ + if (!dot) { + nodename = tor_strndup(target, len-5); + } else { + nodename = tor_strndup(dot+1, strlen(dot+1)-5); + } - ri = router_get_by_nickname(nodename, 0); ++ node = node_get_by_nickname(nodename, 0); + tor_free(nodename); - if (!ri || - (allow_nodes && !routerset_contains_router(allow_nodes, ri)) || - routerset_contains_router(exclude_nodes, ri)) { ++ if (!node || ++ (allow_nodes && !routerset_contains_node(allow_nodes, node)) || ++ routerset_contains_node(exclude_nodes, node)) { + /* We don't know this one, or we want to be rid of it. */ + addressmap_ent_remove(address, ent); + MAP_DEL_CURRENT(address); + } + } STRMAP_FOREACH_END; + } + /** Remove all entries from the addressmap that were set via the * configuration file or the command line. */ void @@@ -1607,10 -1662,19 +1662,18 @@@ connection_ap_handshake_rewrite_and_att /* foo.exit -- modify conn->chosen_exit_node to specify the exit * node, and conn->address to hold only the address portion. */ char *s = strrchr(socks->address,'.'); + + /* If StrictNodes is not set, then .exit overrides ExcludeNodes. */ + routerset_t *excludeset = options->StrictNodes ? + options->_ExcludeExitNodesUnion : options->ExcludeExitNodes; - /*XXX023 make this a node_t. */ - routerinfo_t *router; ++ const node_t *node; + tor_assert(!automap); if (s) { + /* The address was of the form "(stuff).(name).exit */ if (s[1] != '\0') { conn->chosen_exit_name = tor_strdup(s+1); - router = router_get_by_nickname(conn->chosen_exit_name, 1); ++ node = node_get_by_nickname(conn->chosen_exit_name, 1); if (remapped_to_exit) /* 5 tries before it expires the addressmap */ conn->chosen_exit_retries = TRACKHOSTEXITS_RETRIES; *s = 0; @@@ -1623,20 -1688,33 +1687,34 @@@ return -1; } } else { - const node_t *r; + /* It looks like they just asked for "foo.exit". */ ++ conn->chosen_exit_name = tor_strdup(socks->address); - r = node_get_by_nickname(conn->chosen_exit_name, 1); - *socks->address = 0; - if (r) { - node_get_address_string(r, socks->address, sizeof(socks->address)); - } else { - log_warn(LD_APP, - "Unrecognized server in exit address '%s.exit'. Refusing.", - safe_str_client(socks->address)); - connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); - return -1; - router = router_get_by_nickname(conn->chosen_exit_name, 1); - if (router) { ++ node = node_get_by_nickname(conn->chosen_exit_name, 1); ++ if (node) { + *socks->address = 0; - strlcpy(socks->address, router->address, sizeof(socks->address)); ++ node_get_address_string(node, socks->address, sizeof(socks->address)); } } + /* Now make sure that the chosen exit exists... */ - if (!router) { ++ if (!node) { + log_warn(LD_APP, + "Unrecognized relay in exit address '%s.exit'. Refusing.", + safe_str_client(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + /* ...and make sure that it isn't excluded. */ - if (routerset_contains_router(excludeset, router)) { ++ if (routerset_contains_node(excludeset, node)) { + log_warn(LD_APP, + "Excluded relay in exit address '%s.exit'. Refusing.", + safe_str_client(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + /* XXXX022-1090 Should we also allow foo.bar.exit if ExitNodes is set and + Bar is not listed in it? I say yes, but our revised manpage branch + implies no. */ }
if (addresstype != ONION_HOSTNAME) { @@@ -2977,13 -3044,9 +3055,9 @@@ connection_edge_is_rendezvous_stream(ed * to exit from it, or 0 if it probably will not allow it. * (We might be uncertain if conn's destination address has not yet been * resolved.) - * - * If <b>excluded_means_no</b> is 1 and Exclude*Nodes is set and excludes - * this relay, return 0. */ int - connection_ap_can_use_exit(edge_connection_t *conn, const node_t *exit, - int excluded_means_no) -connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit) ++connection_ap_can_use_exit(edge_connection_t *conn, const node_t *exit) { or_options_t *options = get_options();
@@@ -3027,17 -3096,8 +3101,8 @@@ return 0; } if (options->_ExcludeExitNodesUnion && - (options->StrictNodes || excluded_means_no) && - routerset_contains_router(options->_ExcludeExitNodesUnion, exit)) { + routerset_contains_node(options->_ExcludeExitNodesUnion, exit)) { - /* If we are trying to avoid this node as exit, and we have StrictNodes - * set, then this is not a suitable exit. Refuse it. - * - * If we don't have StrictNodes set, then this function gets called in - * two contexts. First, we've got a circuit open and we want to know - * whether we can use it. In that case, we somehow built this circuit - * despite having the last hop in ExcludeExitNodes, so we should be - * willing to use it. Second, we are evaluating whether this is an - * acceptable exit for a new circuit. In that case, skip it. */ + /* Not a suitable exit. Refuse it. */ return 0; }
diff --cc src/or/connection_edge.h index 62a79db,70d0dd2..562db5b --- a/src/or/connection_edge.h +++ b/src/or/connection_edge.h @@@ -48,9 -47,7 +48,8 @@@ int connection_exit_begin_conn(cell_t * int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ); void connection_exit_connect(edge_connection_t *conn); int connection_edge_is_rendezvous_stream(edge_connection_t *conn); -int connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit); +int connection_ap_can_use_exit(edge_connection_t *conn, - const node_t *exit, - int excluded_means_no); ++ const node_t *exit); void connection_ap_expire_beginning(void); void connection_ap_attach_pending(void); void connection_ap_fail_onehop(const char *failed_digest, diff --cc src/or/directory.c index 6bef581,0c095fe..33ebf52 --- a/src/or/directory.c +++ b/src/or/directory.c @@@ -296,6 -291,16 +300,16 @@@ directory_post_to_dirservers(uint8_t di if ((type & ds->type) == 0) continue;
+ if (options->ExcludeNodes && options->StrictNodes && - routerset_contains_routerstatus(options->ExcludeNodes, rs)) { ++ routerset_contains_routerstatus(options->ExcludeNodes, rs, -1)) { + log_warn(LD_DIR, "Wanted to contact authority '%s' for %s, but " + "it's in our ExcludedNodes list and StrictNodes is set. " + "Skipping.", + ds->nickname, + dir_conn_purpose_to_string(dir_purpose)); + continue; + } + found = 1; /* at least one authority of this type was listed */ if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR) ds->has_accepted_serverdesc = 0; @@@ -527,13 -510,15 +541,15 @@@ directory_initiate_command_routerstatus time_t if_modified_since, const rend_data_t *rend_query) { + or_options_t *options = get_options(); - routerinfo_t *router; + const node_t *node; char address_buf[INET_NTOA_BUF_LEN+1]; struct in_addr in; const char *address; tor_addr_t addr; - router = router_get_by_digest(status->identity_digest); + node = node_get_by_id(status->identity_digest); + - if (!router && anonymized_connection) { + if (!node && anonymized_connection) { log_info(LD_DIR, "Not sending anonymized request to directory '%s'; we " "don't have its router descriptor.", status->nickname); return; @@@ -546,6 -530,17 +562,17 @@@ address = address_buf; } tor_addr_from_ipv4h(&addr, status->addr); + + if (options->ExcludeNodes && options->StrictNodes && - routerset_contains_routerstatus(options->ExcludeNodes, status)) { ++ routerset_contains_routerstatus(options->ExcludeNodes, status, -1)) { + log_warn(LD_DIR, "Wanted to contact directory mirror '%s' for %s, but " + "it's in our ExcludedNodes list and StrictNodes is set. " + "Skipping. This choice might make your Tor not work.", + status->nickname, + dir_conn_purpose_to_string(dir_purpose)); + return; + } + directory_initiate_command_rend(address, &addr, status->or_port, status->dir_port, status->version_supports_conditional_consensus, diff --cc src/or/rendclient.c index 47161eb,65e632f..da6cfa3 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@@ -753,29 -753,78 +756,78 @@@ rend_client_get_random_intro(const rend return NULL; }
+ /* See if we can get a node that complies with ExcludeNodes */ + if ((result = rend_client_get_random_intro_impl(entry, 1, 1))) + return result; + /* If not, and StrictNodes is not set, see if we can return any old node + */ + if (!get_options()->StrictNodes) + return rend_client_get_random_intro_impl(entry, 0, 1); + return NULL; + } + + /** As rend_client_get_random_intro, except assume that StrictNodes is set + * iff <b>strict</b> is true. If <b>warnings</b> is false, don't complain + * to the user when we're out of nodes, even if StrictNodes is true. + */ + static extend_info_t * + rend_client_get_random_intro_impl(const rend_cache_entry_t *entry, + const int strict, + const int warnings) + { + int i; + + rend_intro_point_t *intro; - routerinfo_t *router; + or_options_t *options = get_options(); + smartlist_t *usable_nodes; + int n_excluded = 0; + + /* We'll keep a separate list of the usable nodes. If this becomes empty, + * no nodes are usable. */ + usable_nodes = smartlist_create(); + smartlist_add_all(usable_nodes, entry->parsed->intro_nodes); + again: - if (smartlist_len(entry->parsed->intro_nodes) == 0) + if (smartlist_len(usable_nodes) == 0) { + if (n_excluded && get_options()->StrictNodes && warnings) { + /* We only want to warn if StrictNodes is really set. Otherwise + * we're just about to retry anyways. + */ + log_warn(LD_REND, "All introduction points for hidden service are " + "at excluded relays, and StrictNodes is set. Skipping."); + } + smartlist_free(usable_nodes); return NULL; + }
- i = crypto_rand_int(smartlist_len(entry->parsed->intro_nodes)); - intro = smartlist_get(entry->parsed->intro_nodes, i); + i = crypto_rand_int(smartlist_len(usable_nodes)); + intro = smartlist_get(usable_nodes, i); /* Do we need to look up the router or is the extend info complete? */ if (!intro->extend_info->onion_key) { + const node_t *node; if (tor_digest_is_zero(intro->extend_info->identity_digest)) - router = router_get_by_hexdigest(intro->extend_info->nickname); + node = node_get_by_hex_id(intro->extend_info->nickname); else - router = router_get_by_digest(intro->extend_info->identity_digest); - if (!router) { + node = node_get_by_id(intro->extend_info->identity_digest); + if (!node) { log_info(LD_REND, "Unknown router with nickname '%s'; trying another.", intro->extend_info->nickname); - rend_intro_point_free(intro); - smartlist_del(entry->parsed->intro_nodes, i); + smartlist_del(usable_nodes, i); goto again; } extend_info_free(intro->extend_info); - intro->extend_info = extend_info_from_router(router); + intro->extend_info = extend_info_from_node(node); } + /* Check if we should refuse to talk to this router. */ + if (options->ExcludeNodes && strict && + routerset_contains_extendinfo(options->ExcludeNodes, + intro->extend_info)) { + n_excluded++; + smartlist_del(usable_nodes, i); + goto again; + } + + smartlist_free(usable_nodes); return extend_info_dup(intro->extend_info); }
diff --cc src/or/router.c index eb4d6b5,0ef4728..8edbb47 --- a/src/or/router.c +++ b/src/or/router.c @@@ -849,14 -847,33 +849,34 @@@ decide_to_advertise_dirport(or_options_ void consider_testing_reachability(int test_or, int test_dir) { - routerinfo_t *me = router_get_my_routerinfo(); + const routerinfo_t *me = router_get_my_routerinfo(); int orport_reachable = check_whether_orport_reachable(); tor_addr_t addr; + or_options_t *options = get_options(); if (!me) return;
- if (routerset_contains_router(options->ExcludeNodes, me) && ++ if (routerset_contains_router(options->ExcludeNodes, me, -1) && + options->StrictNodes) { + /* If we've excluded ourself, and StrictNodes is set, we can't test + * ourself. */ + if (test_or || test_dir) { + #define SELF_EXCLUDED_WARN_INTERVAL 3600 + static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL); + char *msg; + if ((msg = rate_limit_log(&warning_limit, approx_time()))) { + log_warn(LD_CIRC, "Can't peform self-tests for this relay: we have " + "listed ourself in ExcludeNodes, and StrictNodes is set. " + "We cannot learn whether we are usable, and will not " + "be able to advertise ourself.%s", msg); + tor_free(msg); + } + } + return; + } + if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) { + extend_info_t *ei; log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.", !orport_reachable ? "reachability" : "bandwidth", me->address, me->or_port); diff --cc src/or/routerlist.c index 8c68a34,d9f099b..d5dc478 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@@ -1072,10 -1067,11 +1072,11 @@@ router_pick_trusteddirserver(authority_ * 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) { + or_options_t *options = get_options(); - routerstatus_t *result; + const node_t *result; smartlist_t *direct, *tunnel; smartlist_t *trusted_direct, *trusted_tunnel; smartlist_t *overloaded_direct, *overloaded_tunnel; @@@ -1096,19 -1095,16 +1100,20 @@@ 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; ++ const country_t country = node->country; + 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 || @@@ -1116,17 -1112,20 +1121,23 @@@ 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; + if (try_excluding && options->ExcludeNodes && - routerset_contains_routerstatus(options->ExcludeNodes, status)) { ++ routerset_contains_routerstatus(options->ExcludeNodes, status, ++ country)) { + ++n_excluded; + 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 && @@@ -1165,7 -1164,16 +1176,16 @@@ smartlist_free(trusted_tunnel); smartlist_free(overloaded_direct); smartlist_free(overloaded_tunnel); + + if (result == NULL && try_excluding && !options->StrictNodes && n_excluded) { + /* If we got no result, and we are excluding nodes, and StrictNodes is + * not set, try again without excluding nodes. */ + try_excluding = 0; + n_excluded = 0; + goto retry_without_exclude; + } + - return result; + return result ? result->rs : NULL; }
/** Choose randomly from among the trusted dirservers that are up. Flags @@@ -1175,17 -1183,18 +1195,19 @@@ static const routerstatus_t router_pick_trusteddirserver_impl(authority_type_t type, int flags, int *n_busy_out) { + or_options_t *options = get_options(); 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; + int try_excluding = 1, n_excluded = 0;
if (!trusted_dir_servers) return NULL; @@@ -1208,6 -1219,12 +1232,12 @@@ continue; if (requireother && me && router_digest_is_me(d->digest)) continue; + if (try_excluding && options->ExcludeNodes && + routerset_contains_routerstatus(options->ExcludeNodes, - &d->fake_status)) { ++ &d->fake_status, -1)) { + ++n_excluded; + continue; + }
/* XXXX IP6 proposal 118 */ tor_addr_from_ipv4h(&addr, d->addr); @@@ -1364,45 -1380,21 +1403,45 @@@ nodelist_add_node_family(smartlist_t *s }
/* 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); ++ routerset_get_all_nodes(sl, rs, NULL, 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; }
@@@ -1512,10 -1538,12 +1551,12 @@@ routerlist_find_my_routerinfo(void /** Find a router that's up, that has this IP address, and * that allows exit to this address:port, or return NULL if there * isn't a good one. + * Don't exit enclave to excluded relays -- it wouldn't actually + * hurt anything, but this way there are fewer confused users. */ -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 -1555,14 +1568,13 @@@
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) + ADDR_POLICY_ACCEPTED && - !routerset_contains_router(options->_ExcludeExitNodesUnion, router)) - return router; ++ !routerset_contains_node(options->_ExcludeExitNodesUnion, node)) + return node; }); return NULL; } @@@ -5564,55 -5552,50 +5607,59 @@@ routerset_contains_routerstatus(const r 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. */ + * <b>out</b>, but never add any that are part of <b>excludeset</b>. + * If <b>running_only</b>, only add the running ones. */ void -routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset, - const routerset_t *excludeset, int running_only) -{ +routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset, - int running_only) ++ const routerset_t *excludeset, 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)). */ + * we can do a lookup in O(len(routerset)). */ SMARTLIST_FOREACH(routerset->list, const char *, name, { - routerinfo_t *router = router_get_by_nickname(name, 1); - if (router) { - if (!running_only || router->is_running) - if (!routerset_contains_router(excludeset, router)) - 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); ++ if (!routerset_contains_node(excludeset, node)) ++ 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_node(routerset, node)) - if (routerset_contains_router(routerset, router) && - !routerset_contains_router(excludeset, router)) - smartlist_add(out, router); ++ if (routerset_contains_node(routerset, node) && ++ !routerset_contains_node(excludeset, node)) + smartlist_add(out, (void*)node); }); } }
+ #if 0 -/** 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 @@@ -5642,11 -5625,12 +5689,12 @@@ routersets_get_node_disjunction(smartli } }); } + #endif
-/** 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; diff --cc src/or/routerlist.h index bb7a098,fec1870..794fc0c --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@@ -169,25 -167,28 +169,31 @@@ int routerset_parse(routerset_t *target void routerset_union(routerset_t *target, const routerset_t *source); int routerset_is_list(const routerset_t *set); int routerset_needs_geoip(const routerset_t *set); + int routerset_is_empty(const routerset_t *set); -int routerset_contains_router(const routerset_t *set, routerinfo_t *ri); +int routerset_contains_router(const routerset_t *set, const routerinfo_t *ri, + country_t country); int routerset_contains_routerstatus(const routerset_t *set, - routerstatus_t *rs); + const routerstatus_t *rs, + country_t country); int routerset_contains_extendinfo(const routerset_t *set, const extend_info_t *ei); -void routerset_get_all_routers(smartlist_t *out, const routerset_t *routerset, - const routerset_t *excludeset, - int running_only); ++ +int routerset_contains_node(const routerset_t *set, const node_t *node); +void routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset, ++ const routerset_t *excludeset, + int running_only); + #if 0 -void routersets_get_disjunction(smartlist_t *target, const smartlist_t *source, +void routersets_get_node_disjunction(smartlist_t *target, + const smartlist_t *source, const routerset_t *include, const routerset_t *exclude, int running_only); + #endif -void routerset_subtract_routers(smartlist_t *out, +void routerset_subtract_nodes(smartlist_t *out, - const routerset_t *routerset); + const routerset_t *routerset); ++ char *routerset_to_string(const routerset_t *routerset); -void routerset_refresh_countries(routerset_t *target); int routerset_equal(const routerset_t *old, const routerset_t *new); void routerset_free(routerset_t *routerset); -void routerinfo_set_country(routerinfo_t *ri); -void routerlist_refresh_countries(void); void refresh_all_country_info(void);
int hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,