diff options
Diffstat (limited to 'src/or/networkstatus.c')
-rw-r--r-- | src/or/networkstatus.c | 486 |
1 files changed, 303 insertions, 183 deletions
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index d8e2c00273..040405555c 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1,17 +1,44 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2016, The Tor Project, Inc. */ + * Copyright (c) 2007-2017, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file networkstatus.c - * \brief Functions and structures for handling network status documents as a - * client or cache. + * \brief Functions and structures for handling networkstatus documents as a + * client or as a directory cache. + * + * A consensus networkstatus object is created by the directory + * authorities. It authenticates a set of network parameters--most + * importantly, the list of all the relays in the network. This list + * of relays is represented as an array of routerstatus_t objects. + * + * There are currently two flavors of consensus. With the older "NS" + * flavor, each relay is associated with a digest of its router + * descriptor. Tor instances that use this consensus keep the list of + * router descriptors as routerinfo_t objects stored and managed in + * routerlist.c. With the newer "microdesc" flavor, each relay is + * associated with a digest of the microdescriptor that the authorities + * made for it. These are stored and managed in microdesc.c. Information + * about the router is divided between the the networkstatus and the + * microdescriptor according to the general rule that microdescriptors + * should hold information that changes much less frequently than the + * information in the networkstatus. + * + * Modern clients use microdescriptor networkstatuses. Directory caches + * need to keep both kinds of networkstatus document, so they can serve them. + * + * This module manages fetching, holding, storing, updating, and + * validating networkstatus objects. The download-and-validate process + * is slightly complicated by the fact that the keys you need to + * validate a consensus are stored in the authority certificates, which + * you might not have yet when you download the consensus. */ #define NETWORKSTATUS_PRIVATE #include "or.h" +#include "bridges.h" #include "channel.h" #include "circuitmux.h" #include "circuitmux_ewma.h" @@ -19,12 +46,14 @@ #include "config.h" #include "connection.h" #include "connection_or.h" +#include "consdiffmgr.h" #include "control.h" #include "directory.h" #include "dirserv.h" #include "dirvote.h" #include "dos.h" #include "entrynodes.h" +#include "hibernate.h" #include "main.h" #include "microdesc.h" #include "networkstatus.h" @@ -34,23 +63,19 @@ #include "router.h" #include "routerlist.h" #include "routerparse.h" +#include "scheduler.h" #include "shared_random.h" #include "transports.h" #include "torcert.h" - -/** Map from lowercase nickname to identity digest of named server, if any. */ -static strmap_t *named_server_map = NULL; -/** Map from lowercase nickname to (void*)1 for all names that are listed - * as unnamed for some server in the consensus. */ -static strmap_t *unnamed_server_map = NULL; +#include "channelpadding.h" /** Most recently received and validated v3 "ns"-flavored consensus network * status. */ -static networkstatus_t *current_ns_consensus = NULL; +STATIC networkstatus_t *current_ns_consensus = NULL; -/** Most recently received and validated v3 "microdec"-flavored consensus +/** Most recently received and validated v3 "microdesc"-flavored consensus * network status. */ -static networkstatus_t *current_md_consensus = NULL; +STATIC networkstatus_t *current_md_consensus = NULL; /** A v3 consensus networkstatus that we've received, but which we don't * have enough certificates to be happy about. */ @@ -82,9 +107,9 @@ static time_t time_to_download_next_consensus[N_CONSENSUS_FLAVORS]; static download_status_t consensus_dl_status[N_CONSENSUS_FLAVORS] = { { 0, 0, 0, DL_SCHED_CONSENSUS, DL_WANT_ANY_DIRSERVER, - DL_SCHED_INCREMENT_FAILURE, DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 }, + DL_SCHED_INCREMENT_FAILURE, 0, 0 }, { 0, 0, 0, DL_SCHED_CONSENSUS, DL_WANT_ANY_DIRSERVER, - DL_SCHED_INCREMENT_FAILURE, DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 }, + DL_SCHED_INCREMENT_FAILURE, 0, 0 }, }; #define N_CONSENSUS_BOOTSTRAP_SCHEDULES 2 @@ -101,10 +126,10 @@ static download_status_t consensus_bootstrap_dl_status[N_CONSENSUS_BOOTSTRAP_SCHEDULES] = { { 0, 0, 0, DL_SCHED_CONSENSUS, DL_WANT_AUTHORITY, - DL_SCHED_INCREMENT_ATTEMPT, DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 }, + DL_SCHED_INCREMENT_ATTEMPT, 0, 0 }, /* During bootstrap, DL_WANT_ANY_DIRSERVER means "use fallbacks". */ { 0, 0, 0, DL_SCHED_CONSENSUS, DL_WANT_ANY_DIRSERVER, - DL_SCHED_INCREMENT_ATTEMPT, DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 }, + DL_SCHED_INCREMENT_ATTEMPT, 0, 0 }, }; /** True iff we have logged a warning about this OR's version being older than @@ -114,7 +139,6 @@ static int have_warned_about_old_version = 0; * listed by the authorities. */ static int have_warned_about_new_version = 0; -static void routerstatus_list_update_named_server_map(void); static void update_consensus_bootstrap_multiple_downloads( time_t now, const or_options_t *options); @@ -152,60 +176,74 @@ networkstatus_reset_download_failures(void) download_status_reset(&consensus_bootstrap_dl_status[i]); } +/** + * Read and and return the cached consensus of type <b>flavorname</b>. If + * <b>unverified</b> is false, get the one we haven't verified. Return NULL if + * the file isn't there. */ +static char * +networkstatus_read_cached_consensus_impl(int flav, + const char *flavorname, + int unverified_consensus) +{ + char buf[128]; + const char *prefix; + if (unverified_consensus) { + prefix = "unverified"; + } else { + prefix = "cached"; + } + if (flav == FLAV_NS) { + tor_snprintf(buf, sizeof(buf), "%s-consensus", prefix); + } else { + tor_snprintf(buf, sizeof(buf), "%s-%s-consensus", prefix, flavorname); + } + + char *filename = get_cachedir_fname(buf); + char *result = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL); + tor_free(filename); + return result; +} + +/** Return a new string containing the current cached consensus of flavor + * <b>flavorname</b>. */ +char * +networkstatus_read_cached_consensus(const char *flavorname) + { + int flav = networkstatus_parse_flavor_name(flavorname); + if (flav < 0) + return NULL; + return networkstatus_read_cached_consensus_impl(flav, flavorname, 0); +} + /** Read every cached v3 consensus networkstatus from the disk. */ int router_reload_consensus_networkstatus(void) { - char *filename; - char *s; const unsigned int flags = NSSET_FROM_CACHE | NSSET_DONT_DOWNLOAD_CERTS; int flav; /* FFFF Suppress warnings if cached consensus is bad? */ for (flav = 0; flav < N_CONSENSUS_FLAVORS; ++flav) { - char buf[128]; const char *flavor = networkstatus_get_flavor_name(flav); - if (flav == FLAV_NS) { - filename = get_datadir_fname("cached-consensus"); - } else { - tor_snprintf(buf, sizeof(buf), "cached-%s-consensus", flavor); - filename = get_datadir_fname(buf); - } - s = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL); + char *s = networkstatus_read_cached_consensus_impl(flav, flavor, 0); if (s) { if (networkstatus_set_current_consensus(s, flavor, flags, NULL) < -1) { - log_warn(LD_FS, "Couldn't load consensus %s networkstatus from \"%s\"", - flavor, filename); + log_warn(LD_FS, "Couldn't load consensus %s networkstatus from cache", + flavor); } tor_free(s); } - tor_free(filename); - - if (flav == FLAV_NS) { - filename = get_datadir_fname("unverified-consensus"); - } else { - tor_snprintf(buf, sizeof(buf), "unverified-%s-consensus", flavor); - filename = get_datadir_fname(buf); - } - s = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL); + s = networkstatus_read_cached_consensus_impl(flav, flavor, 1); if (s) { if (networkstatus_set_current_consensus(s, flavor, flags|NSSET_WAS_WAITING_FOR_CERTS, NULL)) { - log_info(LD_FS, "Couldn't load consensus %s networkstatus from \"%s\"", - flavor, filename); - } + log_info(LD_FS, "Couldn't load unverified consensus %s networkstatus " + "from cache", flavor); + } tor_free(s); } - tor_free(filename); - } - - if (!networkstatus_get_latest_consensus()) { - if (!named_server_map) - named_server_map = strmap_new(); - if (!unnamed_server_map) - unnamed_server_map = strmap_new(); } update_certificate_downloads(time(NULL)); @@ -217,8 +255,8 @@ router_reload_consensus_networkstatus(void) } /** Free all storage held by the vote_routerstatus object <b>rs</b>. */ -STATIC void -vote_routerstatus_free(vote_routerstatus_t *rs) +void +vote_routerstatus_free_(vote_routerstatus_t *rs) { vote_microdesc_hash_t *h, *next; if (!rs) @@ -236,7 +274,7 @@ vote_routerstatus_free(vote_routerstatus_t *rs) /** Free all storage held by the routerstatus object <b>rs</b>. */ void -routerstatus_free(routerstatus_t *rs) +routerstatus_free_(routerstatus_t *rs) { if (!rs) return; @@ -246,7 +284,7 @@ routerstatus_free(routerstatus_t *rs) /** Free all storage held in <b>sig</b> */ void -document_signature_free(document_signature_t *sig) +document_signature_free_(document_signature_t *sig) { tor_free(sig->signature); tor_free(sig); @@ -264,7 +302,7 @@ document_signature_dup(const document_signature_t *sig) /** Free all storage held in <b>ns</b>. */ void -networkstatus_vote_free(networkstatus_t *ns) +networkstatus_vote_free_(networkstatus_t *ns) { if (!ns) return; @@ -745,41 +783,6 @@ router_get_consensus_status_by_id(const char *digest) return router_get_mutable_consensus_status_by_id(digest); } -/** Given a nickname (possibly verbose, possibly a hexadecimal digest), return - * the corresponding routerstatus_t, or NULL if none exists. Warn the - * user if <b>warn_if_unnamed</b> is set, and they have specified a router by - * nickname, but the Named flag isn't set for that router. */ -const routerstatus_t * -router_get_consensus_status_by_nickname(const char *nickname, - int warn_if_unnamed) -{ - const node_t *node = node_get_by_nickname(nickname, warn_if_unnamed); - if (node) - return node->rs; - else - return NULL; -} - -/** Return the identity digest that's mapped to officially by - * <b>nickname</b>. */ -const char * -networkstatus_get_router_digest_by_nickname(const char *nickname) -{ - if (!named_server_map) - return NULL; - return strmap_get_lc(named_server_map, nickname); -} - -/** Return true iff <b>nickname</b> is disallowed from being the nickname - * of any server. */ -int -networkstatus_nickname_is_unnamed(const char *nickname) -{ - if (!unnamed_server_map) - return 0; - return strmap_get_lc(unnamed_server_map, nickname) != NULL; -} - /** How frequently do directory authorities re-download fresh networkstatus * documents? */ #define AUTHORITY_NS_CACHE_INTERVAL (10*60) @@ -789,8 +792,11 @@ networkstatus_nickname_is_unnamed(const char *nickname) #define NONAUTHORITY_NS_CACHE_INTERVAL (60*60) /** Return true iff, given the options listed in <b>options</b>, <b>flavor</b> - * is the flavor of a consensus networkstatus that we would like to fetch. */ -static int + * is the flavor of a consensus networkstatus that we would like to fetch. + * + * For certificate fetches, use we_want_to_fetch_unknown_auth_certs, and + * for serving fetched documents, use directory_caches_dir_info. */ +int we_want_to_fetch_flavor(const or_options_t *options, int flavor) { if (flavor < 0 || flavor > N_CONSENSUS_FLAVORS) { @@ -812,6 +818,29 @@ we_want_to_fetch_flavor(const or_options_t *options, int flavor) return flavor == usable_consensus_flavor(); } +/** Return true iff, given the options listed in <b>options</b>, we would like + * to fetch and store unknown authority certificates. + * + * For consensus and descriptor fetches, use we_want_to_fetch_flavor, and + * for serving fetched certificates, use directory_caches_unknown_auth_certs. + */ +int +we_want_to_fetch_unknown_auth_certs(const or_options_t *options) +{ + if (authdir_mode_v3(options) || + directory_caches_unknown_auth_certs((options))) { + /* We want to serve all certs to others, regardless if we would use + * them ourselves. */ + return 1; + } + if (options->FetchUselessDescriptors) { + /* Unknown certificates are definitely useless. */ + return 1; + } + /* Otherwise, don't fetch unknown certificates. */ + return 0; +} + /** How long will we hang onto a possibly live consensus for which we're * fetching certs before we check whether there is a better one? */ #define DELAY_WHILE_FETCHING_CERTS (20*60) @@ -914,14 +943,11 @@ update_consensus_networkstatus_downloads(time_t now) update_consensus_bootstrap_multiple_downloads(now, options); } else { /* Check if we failed downloading a consensus too recently */ - int max_dl_tries = options->TestingConsensusMaxDownloadTries; /* Let's make sure we remembered to update consensus_dl_status */ tor_assert(consensus_dl_status[i].schedule == DL_SCHED_CONSENSUS); - if (!download_status_is_ready(&consensus_dl_status[i], - now, - max_dl_tries)) { + if (!download_status_is_ready(&consensus_dl_status[i], now)) { continue; } @@ -948,17 +974,9 @@ update_consensus_networkstatus_downloads(time_t now) static void update_consensus_bootstrap_attempt_downloads( time_t now, - const or_options_t *options, download_status_t *dls, download_want_authority_t want_authority) { - int use_fallbacks = networkstatus_consensus_can_use_extra_fallbacks(options); - int max_dl_tries = options->ClientBootstrapConsensusMaxDownloadTries; - if (!use_fallbacks) { - max_dl_tries = - options->ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries; - } - const char *resource = networkstatus_get_flavor_name( usable_consensus_flavor()); @@ -967,7 +985,7 @@ update_consensus_bootstrap_attempt_downloads( /* Allow for multiple connections in the same second, if the schedule value * is 0. */ - while (download_status_is_ready(dls, now, max_dl_tries)) { + while (download_status_is_ready(dls, now)) { log_info(LD_DIR, "Launching %s bootstrap %s networkstatus consensus " "download.", resource, (want_authority == DL_WANT_AUTHORITY ? "authority" @@ -1018,7 +1036,7 @@ update_consensus_bootstrap_multiple_downloads(time_t now, if (!check_consensus_waiting_for_certs(usable_flavor, now, dls_f)) { /* During bootstrap, DL_WANT_ANY_DIRSERVER means "use fallbacks". */ - update_consensus_bootstrap_attempt_downloads(now, options, dls_f, + update_consensus_bootstrap_attempt_downloads(now, dls_f, DL_WANT_ANY_DIRSERVER); } } @@ -1028,7 +1046,7 @@ update_consensus_bootstrap_multiple_downloads(time_t now, &consensus_bootstrap_dl_status[CONSENSUS_BOOTSTRAP_SOURCE_AUTHORITY]; if (!check_consensus_waiting_for_certs(usable_flavor, now, dls_a)) { - update_consensus_bootstrap_attempt_downloads(now, options, dls_a, + update_consensus_bootstrap_attempt_downloads(now, dls_a, DL_WANT_AUTHORITY); } } @@ -1181,8 +1199,18 @@ should_delay_dir_fetches(const or_options_t *options, const char **msg_out) return 1; } + if (we_are_hibernating()) { + if (msg_out) { + *msg_out = "We are hibernating or shutting down."; + } + log_info(LD_DIR, "Delaying dir fetches (Hibernating or shutting down)"); + return 1; + } + if (options->UseBridges) { - if (!any_bridge_descriptors_known()) { + /* If we know that none of our bridges can possibly work, avoid fetching + * directory documents. But if some of them might work, try again. */ + if (num_bridges_usable(1) == 0) { if (msg_out) { *msg_out = "No running bridges"; } @@ -1318,14 +1346,47 @@ networkstatus_get_latest_consensus_by_flavor,(consensus_flavor_t f)) MOCK_IMPL(networkstatus_t *, networkstatus_get_live_consensus,(time_t now)) { - if (networkstatus_get_latest_consensus() && - networkstatus_get_latest_consensus()->valid_after <= now && - now <= networkstatus_get_latest_consensus()->valid_until) - return networkstatus_get_latest_consensus(); + networkstatus_t *ns = networkstatus_get_latest_consensus(); + if (ns && networkstatus_is_live(ns, now)) + return ns; else return NULL; } +/** Given a consensus in <b>ns</b>, return true iff currently live and + * unexpired. */ +int +networkstatus_is_live(const networkstatus_t *ns, time_t now) +{ + return (ns->valid_after <= now && now <= ns->valid_until); +} + +/** Determine if <b>consensus</b> is valid or expired recently enough that + * we can still use it. + * + * Return 1 if the consensus is reasonably live, or 0 if it is too old. + */ +int +networkstatus_consensus_reasonably_live(const networkstatus_t *consensus, + time_t now) +{ + if (BUG(!consensus)) + return 0; + + return networkstatus_valid_until_is_reasonably_live(consensus->valid_until, + now); +} + +/** As networkstatus_consensus_reasonably_live, but takes a valid_until + * time rather than an entire consensus. */ +int +networkstatus_valid_until_is_reasonably_live(time_t valid_until, + time_t now) +{ +#define REASONABLY_LIVE_TIME (24*60*60) + return (now <= valid_until + REASONABLY_LIVE_TIME); +} + /* XXXX remove this in favor of get_live_consensus. But actually, * leave something like it for bridge users, who need to not totally * lose if they spend a while fetching a new consensus. */ @@ -1334,12 +1395,11 @@ networkstatus_get_live_consensus,(time_t now)) networkstatus_t * networkstatus_get_reasonably_live_consensus(time_t now, int flavor) { -#define REASONABLY_LIVE_TIME (24*60*60) networkstatus_t *consensus = networkstatus_get_latest_consensus_by_flavor(flavor); if (consensus && consensus->valid_after <= now && - now <= consensus->valid_until+REASONABLY_LIVE_TIME) + networkstatus_consensus_reasonably_live(consensus, now)) return consensus; else return NULL; @@ -1439,6 +1499,32 @@ networkstatus_consensus_is_already_downloading(const char *resource) return answer; } +/* Does the current, reasonably live consensus have IPv6 addresses? + * Returns 1 if there is a reasonably live consensus and its consensus method + * includes IPv6 addresses in the consensus. + * Otherwise, if there is no consensus, or the method does not include IPv6 + * addresses, returns 0. */ +int +networkstatus_consensus_has_ipv6(const or_options_t* options) +{ + const networkstatus_t *cons = networkstatus_get_reasonably_live_consensus( + approx_time(), + usable_consensus_flavor()); + + /* If we have no consensus, we have no IPv6 in it */ + if (!cons) { + return 0; + } + + /* Different flavours of consensus gained IPv6 at different times */ + if (we_use_microdescriptors_for_circuits(options)) { + return + cons->consensus_method >= MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS; + } else { + return cons->consensus_method >= MIN_METHOD_FOR_A_LINES; + } +} + /** Given two router status entries for the same router identity, return 1 if * if the contents have changed between them. Otherwise, return 0. */ static int @@ -1503,13 +1589,22 @@ notify_control_networkstatus_changed(const networkstatus_t *old_c, smartlist_free(changed); } -/* Called when the consensus has changed from old_c to new_c. */ +/* Called before the consensus changes from old_c to new_c. */ static void -notify_networkstatus_changed(const networkstatus_t *old_c, - const networkstatus_t *new_c) +notify_before_networkstatus_changes(const networkstatus_t *old_c, + const networkstatus_t *new_c) { notify_control_networkstatus_changed(old_c, new_c); dos_consensus_has_changed(new_c); + relay_consensus_has_changed(new_c); +} + +/* Called after a new consensus has been put in the global state. It is safe + * to use the consensus getters in this function. */ +static void +notify_after_networkstatus_changes(void) +{ + scheduler_notify_networkstatus_changed(); } /** Copy all the ancillary information (like router download status and so on) @@ -1569,7 +1664,7 @@ networkstatus_set_current_consensus_from_ns(networkstatus_t *c, } return current_md_consensus ? 0 : -1; } -#endif //TOR_UNIT_TESTS +#endif /* defined(TOR_UNIT_TESTS) */ /** * Return true if any option is set in <b>options</b> to make us behave @@ -1584,7 +1679,8 @@ any_client_port_set(const or_options_t *options) return (options->SocksPort_set || options->TransPort_set || options->NATDPort_set || - options->DNSPort_set); + options->DNSPort_set || + options->HTTPTunnelPort_set); } /** @@ -1610,7 +1706,7 @@ handle_missing_protocol_warning_impl(const networkstatus_t *c, } tor_free(protocol_warning); if (should_exit) - exit(1); + exit(1); // XXXX bad exit: should return from main. } /** Called when we have received a networkstatus <b>c</b>. If there are @@ -1659,7 +1755,7 @@ networkstatus_set_current_consensus(const char *consensus, { networkstatus_t *c=NULL; int r, result = -1; - time_t now = time(NULL); + time_t now = approx_time(); const or_options_t *options = get_options(); char *unverified_fname = NULL, *consensus_fname = NULL; int flav = networkstatus_parse_flavor_name(flavor); @@ -1691,7 +1787,7 @@ networkstatus_set_current_consensus(const char *consensus, if (from_cache && !was_waiting_for_certs) { /* We previously stored this; check _now_ to make sure that version-kills - * really work. This happens even before we check signatures: we did so + * really work. This happens even before we check signatures: we did so * before when we stored this to disk. This does mean an attacker who can * write to the datadir can make us not start: such an attacker could * already harm us by replacing our guards, which would be worse. */ @@ -1711,9 +1807,9 @@ networkstatus_set_current_consensus(const char *consensus, } if (flav != usable_consensus_flavor() && - !directory_caches_dir_info(options)) { - /* This consensus is totally boring to us: we won't use it, and we won't - * serve it. Drop it. */ + !we_want_to_fetch_flavor(options, flav)) { + /* This consensus is totally boring to us: we won't use it, we didn't want + * it, and we won't serve it. Drop it. */ goto done; } @@ -1724,15 +1820,15 @@ networkstatus_set_current_consensus(const char *consensus, } if (!strcmp(flavor, "ns")) { - consensus_fname = get_datadir_fname("cached-consensus"); - unverified_fname = get_datadir_fname("unverified-consensus"); + consensus_fname = get_cachedir_fname("cached-consensus"); + unverified_fname = get_cachedir_fname("unverified-consensus"); if (current_ns_consensus) { current_digests = ¤t_ns_consensus->digests; current_valid_after = current_ns_consensus->valid_after; } } else if (!strcmp(flavor, "microdesc")) { - consensus_fname = get_datadir_fname("cached-microdesc-consensus"); - unverified_fname = get_datadir_fname("unverified-microdesc-consensus"); + consensus_fname = get_cachedir_fname("cached-microdesc-consensus"); + unverified_fname = get_cachedir_fname("unverified-microdesc-consensus"); if (current_md_consensus) { current_digests = ¤t_md_consensus->digests; current_valid_after = current_md_consensus->valid_after; @@ -1741,9 +1837,9 @@ networkstatus_set_current_consensus(const char *consensus, cached_dir_t *cur; char buf[128]; tor_snprintf(buf, sizeof(buf), "cached-%s-consensus", flavor); - consensus_fname = get_datadir_fname(buf); + consensus_fname = get_cachedir_fname(buf); tor_snprintf(buf, sizeof(buf), "unverified-%s-consensus", flavor); - unverified_fname = get_datadir_fname(buf); + unverified_fname = get_cachedir_fname(buf); cur = dirserv_get_consensus(flavor); if (cur) { current_digests = &cur->digests; @@ -1834,8 +1930,11 @@ networkstatus_set_current_consensus(const char *consensus, const int is_usable_flavor = flav == usable_consensus_flavor(); + /* Before we switch to the new consensus, notify that we are about to change + * it using the old consensus and the new one. */ if (is_usable_flavor) { - notify_networkstatus_changed(networkstatus_get_latest_consensus(), c); + notify_before_networkstatus_changes(networkstatus_get_latest_consensus(), + c); } if (flav == FLAV_NS) { if (current_ns_consensus) { @@ -1878,14 +1977,21 @@ networkstatus_set_current_consensus(const char *consensus, } if (is_usable_flavor) { + /* Notify that we just changed the consensus so the current global value + * can be looked at. */ + notify_after_networkstatus_changes(); + + /* The "current" consensus has just been set and it is a usable flavor so + * the first thing we need to do is recalculate the voting schedule static + * object so we can use the timings in there needed by some subsystems + * such as hidden service and shared random. */ + dirvote_recalculate_timing(options, now); + nodelist_set_consensus(c); /* XXXXNM Microdescs: needs a non-ns variant. ???? NM*/ update_consensus_networkstatus_fetch_time(now); - dirvote_recalculate_timing(options, now); - routerstatus_list_update_named_server_map(); - /* Update ewma and adjust policy if needed; first cache the old value */ old_ewma_enabled = cell_ewma_enabled(); /* Change the cell EWMA settings */ @@ -1904,6 +2010,7 @@ networkstatus_set_current_consensus(const char *consensus, circuit_build_times_new_consensus_params( get_circuit_build_times_mutable(), c); + channelpadding_new_consensus_params(c); } /* Reset the failure count only if this consensus is actually valid. */ @@ -1914,11 +2021,15 @@ networkstatus_set_current_consensus(const char *consensus, download_status_failed(&consensus_dl_status[flav], 0); } - if (directory_caches_dir_info(options)) { + if (we_want_to_fetch_flavor(options, flav)) { dirserv_set_cached_consensus_networkstatus(consensus, flavor, &c->digests, + c->digest_sha3_as_signed, c->valid_after); + if (dir_server_mode(get_options())) { + consdiffmgr_add_consensus(consensus, c); + } } if (!from_cache) { @@ -1933,16 +2044,21 @@ networkstatus_set_current_consensus(const char *consensus, char tbuf[ISO_TIME_LEN+1]; char dbuf[64]; long delta = now - c->valid_after; + char *flavormsg = NULL; format_iso_time(tbuf, c->valid_after); format_time_interval(dbuf, sizeof(dbuf), delta); log_warn(LD_GENERAL, "Our clock is %s behind the time published in the " "consensus network status document (%s UTC). Tor needs an " "accurate clock to work correctly. Please check your time and " "date settings!", dbuf, tbuf); - control_event_general_status(LOG_WARN, - "CLOCK_SKEW MIN_SKEW=%ld SOURCE=CONSENSUS", delta); + tor_asprintf(&flavormsg, "%s flavor consensus", flavor); + clock_skew_warning(NULL, delta, 1, LD_GENERAL, flavormsg, "CONSENSUS"); + tor_free(flavormsg); } + /* We got a new consesus. Reset our md fetch fail cache */ + microdesc_reset_outdated_dirservers_list(); + router_dir_info_changed(); result = 0; @@ -1966,6 +2082,7 @@ networkstatus_note_certs_arrived(const char *source_dir) { int i; for (i=0; i<N_CONSENSUS_FLAVORS; ++i) { + const char *flavor_name = networkstatus_get_flavor_name(i); consensus_waiting_for_certs_t *waiting = &consensus_waiting_for_certs[i]; if (!waiting->consensus) continue; @@ -1973,7 +2090,7 @@ networkstatus_note_certs_arrived(const char *source_dir) char *waiting_body = waiting->body; if (!networkstatus_set_current_consensus( waiting_body, - networkstatus_get_flavor_name(i), + flavor_name, NSSET_WAS_WAITING_FOR_CERTS, source_dir)) { tor_free(waiting_body); @@ -2048,31 +2165,6 @@ routers_update_all_from_networkstatus(time_t now, int dir_version) } } -/** Update our view of the list of named servers from the most recently - * retrieved networkstatus consensus. */ -static void -routerstatus_list_update_named_server_map(void) -{ - networkstatus_t *ns = networkstatus_get_latest_consensus(); - if (!ns) - return; - - strmap_free(named_server_map, tor_free_); - named_server_map = strmap_new(); - strmap_free(unnamed_server_map, NULL); - unnamed_server_map = strmap_new(); - smartlist_t *rslist = ns->routerstatus_list; - SMARTLIST_FOREACH_BEGIN(rslist, const routerstatus_t *, rs) { - if (rs->is_named) { - strmap_set_lc(named_server_map, rs->nickname, - tor_memdup(rs->identity_digest, DIGEST_LEN)); - } - if (rs->is_unnamed) { - strmap_set_lc(unnamed_server_map, rs->nickname, (void*)1); - } - } SMARTLIST_FOREACH_END(rs); -} - /** Given a list <b>routers</b> of routerinfo_t *, update each status field * according to our current consensus networkstatus. May re-order * <b>routers</b>. */ @@ -2151,7 +2243,9 @@ signed_descs_update_status_from_consensus_networkstatus(smartlist_t *descs) char * networkstatus_getinfo_helper_single(const routerstatus_t *rs) { - return routerstatus_format_entry(rs, NULL, NULL, NS_CONTROL_PORT, NULL); + return routerstatus_format_entry(rs, NULL, NULL, NS_CONTROL_PORT, + ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD, + NULL); } /** Alloc and return a string describing routerstatuses for the most @@ -2164,13 +2258,13 @@ networkstatus_getinfo_helper_single(const routerstatus_t *rs) char * networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now) { - time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; + const time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH; char *answer; routerlist_t *rl = router_get_routerlist(); smartlist_t *statuses; - uint8_t purpose = router_purpose_from_string(purpose_string); + const uint8_t purpose = router_purpose_from_string(purpose_string); routerstatus_t rs; - int bridge_auth = authdir_mode_bridge(get_options()); + const int bridge_auth = authdir_mode_bridge(get_options()); if (purpose == ROUTER_PURPOSE_UNKNOWN) { log_info(LD_DIR, "Unrecognized purpose '%s' when listing router statuses.", @@ -2187,6 +2281,7 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now) continue; if (ri->purpose != purpose) continue; + /* TODO: modifying the running flag in a getinfo is a bad idea */ if (bridge_auth && ri->purpose == ROUTER_PURPOSE_BRIDGE) dirserv_set_router_is_running(ri, now); /* then generate and write out status lines for each of them */ @@ -2205,25 +2300,34 @@ void networkstatus_dump_bridge_status_to_file(time_t now) { char *status = networkstatus_getinfo_by_purpose("bridge", now); - const or_options_t *options = get_options(); char *fname = NULL; char *thresholds = NULL; char *published_thresholds_and_status = NULL; char published[ISO_TIME_LEN+1]; + const routerinfo_t *me = router_get_my_routerinfo(); + char fingerprint[FINGERPRINT_LEN+1]; + char *fingerprint_line = NULL; + if (me && crypto_pk_get_fingerprint(me->identity_pkey, + fingerprint, 0) >= 0) { + tor_asprintf(&fingerprint_line, "fingerprint %s\n", fingerprint); + } else { + log_warn(LD_BUG, "Error computing fingerprint for bridge status."); + } format_iso_time(published, now); dirserv_compute_bridge_flag_thresholds(); thresholds = dirserv_get_flag_thresholds_line(); tor_asprintf(&published_thresholds_and_status, - "published %s\nflag-thresholds %s\n%s", - published, thresholds, status); - tor_asprintf(&fname, "%s"PATH_SEPARATOR"networkstatus-bridges", - options->DataDirectory); + "published %s\nflag-thresholds %s\n%s%s", + published, thresholds, fingerprint_line ? fingerprint_line : "", + status); + fname = get_datadir_fname("networkstatus-bridges"); write_str_to_file(fname,published_thresholds_and_status,0); tor_free(thresholds); tor_free(published_thresholds_and_status); tor_free(fname); tor_free(status); + tor_free(fingerprint_line); } /* DOCDOC get_net_param_from_list */ @@ -2270,9 +2374,9 @@ get_net_param_from_list(smartlist_t *net_params, const char *param_name, * Make sure the value parsed from the consensus is at least * <b>min_val</b> and at most <b>max_val</b> and raise/cap the parsed value * if necessary. */ -int32_t -networkstatus_get_param(const networkstatus_t *ns, const char *param_name, - int32_t default_val, int32_t min_val, int32_t max_val) +MOCK_IMPL(int32_t, +networkstatus_get_param, (const networkstatus_t *ns, const char *param_name, + int32_t default_val, int32_t min_val, int32_t max_val)) { if (!ns) /* if they pass in null, go find it ourselves */ ns = networkstatus_get_latest_consensus(); @@ -2285,6 +2389,25 @@ networkstatus_get_param(const networkstatus_t *ns, const char *param_name, } /** + * As networkstatus_get_param(), but check torrc_value before checking the + * consensus. If torrc_value is in-range, then return it instead of the + * value from the consensus. + */ +int32_t +networkstatus_get_overridable_param(const networkstatus_t *ns, + int32_t torrc_value, + const char *param_name, + int32_t default_val, + int32_t min_val, int32_t max_val) +{ + if (torrc_value >= min_val && torrc_value <= max_val) + return torrc_value; + else + return networkstatus_get_param( + ns, param_name, default_val, min_val, max_val); +} + +/** * Retrieve the consensus parameter that governs the * fixed-point precision of our network balancing 'bandwidth-weights' * (which are themselves integer consensus values). We divide them @@ -2360,12 +2483,11 @@ networkstatus_parse_flavor_name(const char *flavname) * running, or otherwise not a descriptor that we would make any * use of even if we had it. Else return 1. */ int -client_would_use_router(const routerstatus_t *rs, time_t now, - const or_options_t *options) +client_would_use_router(const routerstatus_t *rs, time_t now) { - if (!rs->is_flagged_running && !options->FetchUselessDescriptors) { + if (!rs->is_flagged_running) { /* 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. */ + * (Fetching and storing depends on by we_want_to_fetch_flavor().) */ return 0; } if (rs->published_on + OLD_ROUTER_DESC_MAX_AGE < now) { @@ -2421,7 +2543,8 @@ getinfo_helper_networkstatus(control_connection_t *conn, } status = router_get_consensus_status_by_id(d); } else if (!strcmpstart(question, "ns/name/")) { - status = router_get_consensus_status_by_nickname(question+8, 0); + const node_t *n = node_get_by_nickname(question+8, 0); + status = n ? n->rs : NULL; } else if (!strcmpstart(question, "ns/purpose/")) { *answer = networkstatus_getinfo_by_purpose(question+11, time(NULL)); return *answer ? 0 : -1; @@ -2528,8 +2651,5 @@ networkstatus_free_all(void) } tor_free(waiting->body); } - - strmap_free(named_server_map, tor_free_); - strmap_free(unnamed_server_map, NULL); } |