diff options
author | Nick Mathewson <nickm@torproject.org> | 2012-12-25 23:22:54 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2012-12-25 23:22:54 -0500 |
commit | 265aab298ad923425e136013f6c439b5fba32558 (patch) | |
tree | 89e923f121b91bdc4b7b4bf6f5f85d25e1b8d2a8 /src | |
parent | 68dae4cf3563e536e0693648cefcd0c69e512bff (diff) | |
parent | c2c6e8e5b2262ccbeeb3e3f954a9b52bc2096bd1 (diff) | |
download | tor-265aab298ad923425e136013f6c439b5fba32558.tar.gz tor-265aab298ad923425e136013f6c439b5fba32558.zip |
Merge branch 'directory_guards_rebased'
Diffstat (limited to 'src')
-rw-r--r-- | src/or/circuituse.c | 4 | ||||
-rw-r--r-- | src/or/config.c | 2 | ||||
-rw-r--r-- | src/or/directory.c | 67 | ||||
-rw-r--r-- | src/or/entrynodes.c | 132 | ||||
-rw-r--r-- | src/or/entrynodes.h | 4 | ||||
-rw-r--r-- | src/or/or.h | 3 |
6 files changed, 176 insertions, 36 deletions
diff --git a/src/or/circuituse.c b/src/or/circuituse.c index e14f9d03ca..298f31a8dc 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -467,7 +467,7 @@ circuit_expire_building(void) "No circuits are opened. Relaxing timeout for " "a circuit with channel state %s. %d guards are live.", channel_state_to_string(victim->n_chan->state), - num_live_entry_guards()); + num_live_entry_guards(0)); /* We count the timeout here for CBT, because technically this * was a timeout, and the timeout value needs to reset if we @@ -484,7 +484,7 @@ circuit_expire_building(void) "However, it appears the circuit has timed out anyway. " "%d guards are live. ", channel_state_to_string(victim->n_chan->state), - (long)circ_times.close_ms, num_live_entry_guards()); + (long)circ_times.close_ms, num_live_entry_guards(0)); } } diff --git a/src/or/config.c b/src/or/config.c index b81edf749c..db4e1bf901 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -308,6 +308,7 @@ static config_var_t option_vars_[] = { OBSOLETE("NoPublish"), VAR("NodeFamily", LINELIST, NodeFamilies, NULL), V(NumCPUs, UINT, "0"), + V(NumDirectoryGuards, UINT, "3"), V(NumEntryGuards, UINT, "3"), V(ORListenAddress, LINELIST, NULL), VPORT(ORPort, LINELIST, NULL), @@ -382,6 +383,7 @@ static config_var_t option_vars_[] = { V(UpdateBridgesFromAuthority, BOOL, "0"), V(UseBridges, BOOL, "0"), V(UseEntryGuards, BOOL, "1"), + V(UseEntryGuardsAsDirGuards, BOOL, "1"), V(UseMicrodescriptors, AUTOBOOL, "auto"), V(User, STRING, NULL), V(UserspaceIOCPBuffers, BOOL, "0"), diff --git a/src/or/directory.c b/src/or/directory.c index 198fb6d40f..d774dc0138 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -334,6 +334,60 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, } } +/** Return true iff, according to the values in <b>options</b>, we should be + * using directory guards for direct downloads of directory information. */ +static int +should_use_directory_guards(const or_options_t *options) +{ + /* Public (non-bridge) servers never use directory guards. */ + if (public_server_mode(options)) + return 0; + /* If guards are disabled, or directory guards are disabled, we can't + * use directory guards. + */ + if (!options->UseEntryGuards || !options->UseEntryGuardsAsDirGuards) + return 0; + /* If we're configured to fetch directory info aggressively or of a + * nonstandard type, don't use directory guards. */ + if (options->DownloadExtraInfo || options->FetchDirInfoEarly || + options->FetchDirInfoExtraEarly || options->FetchUselessDescriptors || + options->FetchV2Networkstatus) + return 0; + if (! options->PreferTunneledDirConns) + return 0; + return 1; +} + +/** Pick an unconsetrained directory server from among our guards, the latest + * networkstatus, or the fallback dirservers, for use in downloading + * information of type <b>type</b>, and return its routerstatus. */ +static const routerstatus_t * +directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags, + uint8_t dir_purpose) +{ + const routerstatus_t *rs; + const or_options_t *options = get_options(); + + if (options->UseBridges) + log_warn(LD_BUG, "Called when we have UseBridges set."); + + if (should_use_directory_guards(options)) { + const node_t *node = choose_random_dirguard(type); + if (node) + rs = node->rs; + } else { + /* anybody with a non-zero dirport will do */ + rs = router_pick_directory_server(type, pds_flags); + } + if (!rs) { + log_info(LD_DIR, "No router found for %s; falling back to " + "dirserver list.", dir_conn_purpose_to_string(dir_purpose)); + rs = router_pick_fallback_dirserver(type, pds_flags); + } + + return rs; +} + /** Start a connection to a random running directory server, using * connection purpose <b>dir_purpose</b>, intending to fetch descriptors * of purpose <b>router_purpose</b>, and requesting <b>resource</b>. @@ -469,14 +523,13 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose, } } if (!rs && type != BRIDGE_DIRINFO) { - /* anybody with a non-zero dirport will do */ - rs = router_pick_directory_server(type, pds_flags); + /* */ + rs = directory_pick_generic_dirserver(type, pds_flags, + dir_purpose); if (!rs) { - log_info(LD_DIR, "No router found for %s; falling back to " - "dirserver list.", dir_conn_purpose_to_string(dir_purpose)); - rs = router_pick_fallback_dirserver(type, pds_flags); - if (!rs) - get_via_tor = 1; /* last resort: try routing it via Tor */ + /*XXXX024 I'm pretty sure this can never do any good, since + * rs isn't set. */ + get_via_tor = 1; /* last resort: try routing it via Tor */ } } } diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index 8712241f62..eb79938fca 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -61,6 +61,9 @@ static smartlist_t *entry_guards = NULL; static int entry_guards_dirty = 0; static void bridge_free(bridge_info_t *bridge); +static const node_t *choose_random_entry_impl(cpath_build_state_t *state, + int for_directory, + dirinfo_type_t dirtype); /** Return the list of entry guards, creating it if necessary. */ const smartlist_t * @@ -125,6 +128,16 @@ entry_guard_set_status(entry_guard_t *e, const node_t *node, control_event_guard(e->nickname, e->identity, "GOOD"); changed = 1; } + + if (node) { + int is_dir = node_is_dir(node) && node->rs && + node->rs->version_supports_microdesc_cache; + if (e->is_dir_cache != is_dir) { + e->is_dir_cache = is_dir; + changed = 1; + } + } + return changed; } @@ -160,10 +173,13 @@ entry_is_time_to_retry(entry_guard_t *e, time_t now) * is true). * * If the answer is no, set *<b>msg</b> to an explanation of why. + * + * If need_descriptor is true, only return the node if we currently have + * a descriptor (routerinfo or microdesc) for it. */ static INLINE const node_t * entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity, - int assume_reachable, const char **msg) + int assume_reachable, int need_descriptor, const char **msg) { const node_t *node; const or_options_t *options = get_options(); @@ -184,7 +200,11 @@ entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity, return NULL; } node = node_get_by_id(e->identity); - if (!node || !node_has_descriptor(node)) { + if (!node) { + *msg = "no node info"; + return NULL; + } + if (need_descriptor && !node_has_descriptor(node)) { *msg = "no descriptor"; return NULL; } @@ -220,17 +240,18 @@ entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity, /** Return the number of entry guards that we think are usable. */ int -num_live_entry_guards(void) +num_live_entry_guards(int for_directory) { int n = 0; const char *msg; if (! entry_guards) return 0; - SMARTLIST_FOREACH(entry_guards, entry_guard_t *, entry, - { - if (entry_is_live(entry, 0, 1, 0, &msg)) + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { + if (for_directory && !entry->is_dir_cache) + continue; + if (entry_is_live(entry, 0, 1, 0, !for_directory, &msg)) ++n; - }); + } SMARTLIST_FOREACH_END(entry); return n; } @@ -257,7 +278,7 @@ log_entry_guards(int severity) SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) { const char *msg = NULL; - if (entry_is_live(e, 0, 1, 0, &msg)) + if (entry_is_live(e, 0, 1, 0, 0, &msg)) smartlist_add_asprintf(elements, "%s [%s] (up %s)", e->nickname, hex_str(e->identity, DIGEST_LEN), @@ -316,7 +337,8 @@ control_event_guard_deferred(void) * already in our entry_guards list, put it at the *beginning*. * Else, put the one we pick at the end of the list. */ static const node_t * -add_an_entry_guard(const node_t *chosen, int reset_status, int prepend) +add_an_entry_guard(const node_t *chosen, int reset_status, int prepend, + int for_directory) { const node_t *node; entry_guard_t *entry; @@ -329,18 +351,32 @@ add_an_entry_guard(const node_t *chosen, int reset_status, int prepend) entry->bad_since = 0; entry->can_retry = 1; } + entry->is_dir_cache = node->rs && + node->rs->version_supports_microdesc_cache; return NULL; } - } else { + } else if (!for_directory) { node = choose_good_entry_server(CIRCUIT_PURPOSE_C_GENERAL, NULL); if (!node) return NULL; + } else { + const routerstatus_t *rs; + rs = router_pick_directory_server(MICRODESC_DIRINFO|V3_DIRINFO, + PDS_PREFER_TUNNELED_DIR_CONNS_); + if (!rs) + return NULL; + node = node_get_by_id(rs->identity_digest); + if (!node) + return NULL; } entry = tor_malloc_zero(sizeof(entry_guard_t)); log_info(LD_CIRC, "Chose %s as new entry guard.", node_describe(node)); strlcpy(entry->nickname, node_get_nickname(node), sizeof(entry->nickname)); memcpy(entry->identity, node->identity, DIGEST_LEN); + entry->is_dir_cache = node_is_dir(node) && + node->rs && node->rs->version_supports_microdesc_cache; + /* 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 @@ -361,14 +397,16 @@ add_an_entry_guard(const node_t *chosen, int reset_status, int prepend) /** If the use of entry guards is configured, choose more entry guards * until we have enough in the list. */ static void -pick_entry_guards(const or_options_t *options) +pick_entry_guards(const or_options_t *options, int for_directory) { int changed = 0; + const int num_needed = for_directory ? options->NumDirectoryGuards : + options->NumEntryGuards; tor_assert(entry_guards); - while (num_live_entry_guards() < options->NumEntryGuards) { - if (!add_an_entry_guard(NULL, 0, 0)) + while (num_live_entry_guards(for_directory) < num_needed) { + if (!add_an_entry_guard(NULL, 0, 0, for_directory)) break; changed = 1; } @@ -531,7 +569,7 @@ entry_guards_compute_status(const or_options_t *options, time_t now) SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { const char *reason = digestmap_get(reasons, entry->identity); const char *live_msg = ""; - const node_t *r = entry_is_live(entry, 0, 1, 0, &live_msg); + const node_t *r = entry_is_live(entry, 0, 1, 0, 0, &live_msg); log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.", entry->nickname, hex_str(entry->identity, DIGEST_LEN), @@ -543,7 +581,7 @@ entry_guards_compute_status(const or_options_t *options, time_t now) r ? "" : live_msg); } SMARTLIST_FOREACH_END(entry); log_info(LD_CIRC, " (%d/%d entry guards are usable/new)", - num_live_entry_guards(), smartlist_len(entry_guards)); + num_live_entry_guards(0), smartlist_len(entry_guards)); log_entry_guards(LOG_INFO); entry_guards_changed(); } @@ -610,7 +648,7 @@ entry_guard_register_connect_status(const char *digest, int succeeded, "Connection to never-contacted entry guard '%s' (%s) failed. " "Removing from the list. %d/%d entry guards usable/new.", entry->nickname, buf, - num_live_entry_guards()-1, smartlist_len(entry_guards)-1); + num_live_entry_guards(0)-1, smartlist_len(entry_guards)-1); control_event_guard(entry->nickname, entry->identity, "DROPPED"); entry_guard_free(entry); smartlist_del_keeporder(entry_guards, idx); @@ -649,7 +687,7 @@ entry_guard_register_connect_status(const char *digest, int succeeded, break; if (e->made_contact) { const char *msg; - const node_t *r = entry_is_live(e, 0, 1, 1, &msg); + const node_t *r = entry_is_live(e, 0, 1, 1, 0, &msg); if (r && e->unreachable_since) { refuse_conn = 1; e->can_retry = 1; @@ -661,7 +699,7 @@ entry_guard_register_connect_status(const char *digest, int succeeded, "Connected to new entry guard '%s' (%s). Marking earlier " "entry guards up. %d/%d entry guards usable/new.", entry->nickname, buf, - num_live_entry_guards(), smartlist_len(entry_guards)); + num_live_entry_guards(0), smartlist_len(entry_guards)); log_entry_guards(LOG_INFO); changed = 1; } @@ -759,7 +797,7 @@ entry_guards_set_from_config(const or_options_t *options) /* Next, the rest of EntryNodes */ SMARTLIST_FOREACH_BEGIN(entry_nodes, const node_t *, node) { - add_an_entry_guard(node, 0, 0); + add_an_entry_guard(node, 0, 0, 0); if (smartlist_len(entry_guards) > options->NumEntryGuards * 10) break; } SMARTLIST_FOREACH_END(node); @@ -799,6 +837,22 @@ entry_list_is_constrained(const or_options_t *options) const node_t * choose_random_entry(cpath_build_state_t *state) { + return choose_random_entry_impl(state, 0, 0); +} + +/** Pick a live (up and listed) directory guard from entry_guards for + * downloading information of type <b>type</b>. */ +const node_t * +choose_random_dirguard(dirinfo_type_t type) +{ + return choose_random_entry_impl(NULL, 1, type); +} + +/** Helper for choose_random{entry,dirguard}. */ +static const node_t * +choose_random_entry_impl(cpath_build_state_t *state, int for_directory, + dirinfo_type_t dirinfo_type) +{ const or_options_t *options = get_options(); smartlist_t *live_entry_guards = smartlist_new(); smartlist_t *exit_family = smartlist_new(); @@ -808,6 +862,15 @@ choose_random_entry(cpath_build_state_t *state) int need_uptime = state ? state->need_uptime : 0; int need_capacity = state ? state->need_capacity : 0; int preferred_min, consider_exit_family = 0; + int need_descriptor = !for_directory; + const int num_needed = for_directory ? options->NumDirectoryGuards : + options->NumEntryGuards; + + /* Checking dirinfo_type isn't required yet, since we only choose directory + guards that can support microdescs, routerinfos, and networkstatuses, AND + we don't use directory guards if we're configured to do direct downloads + of anything else. */ + (void) dirinfo_type; if (chosen_exit) { nodelist_add_node_and_family(exit_family, chosen_exit); @@ -821,16 +884,21 @@ choose_random_entry(cpath_build_state_t *state) entry_guards_set_from_config(options); if (!entry_list_is_constrained(options) && - smartlist_len(entry_guards) < options->NumEntryGuards) - pick_entry_guards(options); + smartlist_len(entry_guards) < num_needed) + pick_entry_guards(options, for_directory); retry: smartlist_clear(live_entry_guards); SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { const char *msg; - node = entry_is_live(entry, need_uptime, need_capacity, 0, &msg); + node = entry_is_live(entry, need_uptime, need_capacity, 0, + need_descriptor, &msg); if (!node) continue; /* down, no point */ + if (for_directory) { + if (!entry->is_dir_cache) + continue; /* We need a directory and didn't get one. */ + } if (node == chosen_exit) continue; /* don't pick the same node for entry and exit */ if (consider_exit_family && smartlist_isin(exit_family, node)) @@ -859,7 +927,7 @@ choose_random_entry(cpath_build_state_t *state) * guard list without needing to. */ goto choose_and_finish; } - if (smartlist_len(live_entry_guards) >= options->NumEntryGuards) + if (smartlist_len(live_entry_guards) >= num_needed) goto choose_and_finish; /* we have enough */ } SMARTLIST_FOREACH_END(entry); @@ -881,7 +949,7 @@ choose_random_entry(cpath_build_state_t *state) /* XXX if guard doesn't imply fast and stable, then we need * to tell add_an_entry_guard below what we want, or it might * be a long time til we get it. -RD */ - node = add_an_entry_guard(NULL, 0, 0); + node = add_an_entry_guard(NULL, 0, 0, for_directory); if (node) { entry_guards_changed(); /* XXX we start over here in case the new node we added shares @@ -972,6 +1040,17 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg) "Bad hex digest for EntryGuard"); } } + if (smartlist_len(args) >= 3) { + const char *is_cache = smartlist_get(args, 2); + if (!strcasecmp(is_cache, "DirCache")) { + node->is_dir_cache = 1; + } else if (!strcasecmp(is_cache, "NoDirCache")) { + node->is_dir_cache = 0; + } else { + log_warn(LD_CONFIG, "Bogus third argument to EntryGuard line: %s", + escaped(is_cache)); + } + } SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); smartlist_free(args); if (*msg) @@ -1138,7 +1217,8 @@ entry_guards_update_state(or_state_t *state) *next = line = tor_malloc_zero(sizeof(config_line_t)); line->key = tor_strdup("EntryGuard"); base16_encode(dbuf, sizeof(dbuf), e->identity, DIGEST_LEN); - tor_asprintf(&line->value, "%s %s", e->nickname, dbuf); + tor_asprintf(&line->value, "%s %s %sDirCache", e->nickname, dbuf, + e->is_dir_cache ? "" : "No"); next = &(line->next); if (e->unreachable_since) { *next = line = tor_malloc_zero(sizeof(config_line_t)); @@ -1795,7 +1875,7 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache) node = node_get_mutable_by_id(ri->cache_info.identity_digest); tor_assert(node); rewrite_node_address_for_bridge(bridge, node); - add_an_entry_guard(node, 1, 1); + add_an_entry_guard(node, 1, 1, 0); log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname, from_cache ? "cached" : "fresh", router_describe(ri)); diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h index 4d031c3593..ae5d2307e7 100644 --- a/src/or/entrynodes.h +++ b/src/or/entrynodes.h @@ -35,6 +35,7 @@ typedef struct entry_guard_t { * for this node already? */ unsigned int path_bias_disabled : 1; /**< Have we disabled this node because * of path bias issues? */ + unsigned int is_dir_cache : 1; /**< Is this node a directory cache? */ time_t bad_since; /**< 0 if this guard is currently usable, or the time at * which it was observed to become (according to the * directory or the user configuration) unusable. */ @@ -52,7 +53,7 @@ typedef struct entry_guard_t { entry_guard_t *entry_guard_get_by_id_digest(const char *digest); void entry_guards_changed(void); const smartlist_t *get_entry_guards(void); -int num_live_entry_guards(void); +int num_live_entry_guards(int for_directory); #endif @@ -62,6 +63,7 @@ int entry_guard_register_connect_status(const char *digest, int succeeded, void entry_nodes_should_be_added(void); int entry_list_is_constrained(const or_options_t *options); const node_t *choose_random_entry(cpath_build_state_t *state); +const node_t *choose_random_dirguard(dirinfo_type_t t); int entry_guards_parse_state(or_state_t *state, int set, char **msg); void entry_guards_update_state(or_state_t *state); int getinfo_helper_entry_guards(control_connection_t *conn, diff --git a/src/or/or.h b/src/or/or.h index a65ca44ed6..c9ede7508f 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3614,6 +3614,9 @@ typedef struct { int UseEntryGuards; /**< Boolean: Do we try to enter from a smallish number * of fixed nodes? */ int NumEntryGuards; /**< How many entry guards do we try to establish? */ + int UseEntryGuardsAsDirGuards; /** Boolean: Do we try to get directory info + * from a smallish number of fixed nodes? */ + int NumDirectoryGuards; /**< How many dir guards do we try to establish? */ int RephistTrackTime; /**< How many seconds do we keep rephist info? */ int FastFirstHopPK; /**< If Tor believes it is safe, should we save a third * of our PK time by sending CREATE_FAST cells? */ |