From 2520ee34c6d1b5eb83a6c3ffdaf1e8b3013b619f Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 13 Jun 2018 13:27:00 +0300 Subject: Require live consensus to compute responsible HSDirs. Here is how this changes the HSv3 client-side and service-side: For service side we already required live consensus to upload descriptors (see 9e900d1db7c8c9e164b5b14d5cdd4099c1ce45f0) so we should never get there without a live consensus. For the client-side we now require a live consensus to attempt to connect to HS. While this changes the client behavior in principle, it doesn't really change it, because we always required live consensus to set HSDir indices, so before this patch a client with no live consensus would try to compute responsible HSDirs without any HSDir indices and bug out. This makes the client behavior more consistent, by requiring a live consensus (and hence a semi-synced clock) for the client to connect to an HS entirely. The alternative would have been to allow setting HSDir indices with a non-live consensus, but this would cause the various problems outlined by commit b89d2fa1db2379bffd2e2b4c851c3facc57b6ed8. --- src/or/hs_common.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/or/hs_common.c b/src/or/hs_common.c index 3081ad216c..6f51e1d131 100644 --- a/src/or/hs_common.c +++ b/src/or/hs_common.c @@ -1332,15 +1332,17 @@ hs_get_responsible_hsdirs(const ed25519_public_key_t *blinded_pk, sorted_nodes = smartlist_new(); + /* Make sure we actually have a live consensus */ + networkstatus_t *c = networkstatus_get_live_consensus(approx_time()); + if (!c || smartlist_len(c->routerstatus_list) == 0) { + log_warn(LD_REND, "No live consensus so we can't get the responsible " + "hidden service directories."); + goto done; + } + /* Add every node_t that support HSDir v3 for which we do have a valid * hsdir_index already computed for them for this consensus. */ { - networkstatus_t *c = networkstatus_get_latest_consensus(); - if (!c || smartlist_len(c->routerstatus_list) == 0) { - log_warn(LD_REND, "No valid consensus so we can't get the responsible " - "hidden service directories."); - goto done; - } SMARTLIST_FOREACH_BEGIN(c->routerstatus_list, const routerstatus_t *, rs) { /* Even though this node_t object won't be modified and should be const, * we can't add const object in a smartlist_t. */ -- cgit v1.2.3-54-g00ecf From a686464420801c5aa58bde1babbf96d3b8520b00 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Tue, 12 Jun 2018 14:29:06 +0300 Subject: Recreate voting schedule before use if it's outdated. --- src/or/voting_schedule.c | 26 +++++++++++++++++++++++++- src/or/voting_schedule.h | 4 ++++ 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/or/voting_schedule.c b/src/or/voting_schedule.c index 1d66b5e225..d230a6dbcd 100644 --- a/src/or/voting_schedule.c +++ b/src/or/voting_schedule.c @@ -83,6 +83,10 @@ get_voting_schedule(const or_options_t *options, time_t now, int severity) interval = (int)( consensus->fresh_until - consensus->valid_after ); vote_delay = consensus->vote_seconds; dist_delay = consensus->dist_seconds; + + /* Note down the consensus valid after, so that we detect outdated voting + * schedules in case of skewed clocks etc. */ + new_voting_schedule->live_consensus_valid_after = consensus->valid_after; } else { interval = options->TestingV3AuthInitialVotingInterval; vote_delay = options->TestingV3AuthInitialVoteDelay; @@ -138,14 +142,34 @@ voting_schedule_t voting_schedule; time_t voting_schedule_get_next_valid_after_time(void) { + time_t now = approx_time(); + bool need_to_recalculate_voting_schedule = false; + /* This is a safe guard in order to make sure that the voting schedule * static object is at least initialized. Using this function with a zeroed * voting schedule can lead to bugs. */ if (tor_mem_is_zero((const char *) &voting_schedule, sizeof(voting_schedule))) { - voting_schedule_recalculate_timing(get_options(), time(NULL)); + need_to_recalculate_voting_schedule = true; + goto done; /* no need for next check if we have to recalculate anyway */ + } + + /* Also make sure we are not using an outdated voting schedule. If we have a + * newer consensus, make sure we recalculate the voting schedule. */ + const networkstatus_t *ns = networkstatus_get_live_consensus(now); + if (ns && ns->valid_after != voting_schedule.live_consensus_valid_after) { + log_info(LD_DIR, "Voting schedule is outdated: recalculating (%d/%d)", + (int) ns->valid_after, + (int) voting_schedule.live_consensus_valid_after); + need_to_recalculate_voting_schedule = true; + } + + done: + if (need_to_recalculate_voting_schedule) { + voting_schedule_recalculate_timing(get_options(), now); voting_schedule.created_on_demand = 1; } + return voting_schedule.interval_starts; } diff --git a/src/or/voting_schedule.h b/src/or/voting_schedule.h index 4f9d584031..087701408e 100644 --- a/src/or/voting_schedule.h +++ b/src/or/voting_schedule.h @@ -43,6 +43,10 @@ typedef struct { * timings only for the first vote even though this object was initilized * prior to voting. */ int created_on_demand; + + /** The valid-after time of the last live consensus that filled this voting + * schedule. It's used to detect outdated voting schedules. */ + time_t live_consensus_valid_after; } voting_schedule_t; /* Public API. */ -- cgit v1.2.3-54-g00ecf From b7b7dab00d321d2c3e2a2d52e76d9e1190836420 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 13 Jun 2018 13:28:39 +0300 Subject: Recreate nodelist before use if it's outdated. We currently only do the check when we are about to use the HSDir indices. --- src/or/hs_common.c | 3 +++ src/or/nodelist.c | 30 ++++++++++++++++++++++++++++++ src/or/nodelist.h | 1 + 3 files changed, 34 insertions(+) (limited to 'src') diff --git a/src/or/hs_common.c b/src/or/hs_common.c index 6f51e1d131..5354055bb0 100644 --- a/src/or/hs_common.c +++ b/src/or/hs_common.c @@ -1340,6 +1340,9 @@ hs_get_responsible_hsdirs(const ed25519_public_key_t *blinded_pk, goto done; } + /* Ensure the nodelist is fresh, since it contains the HSDir indices. */ + nodelist_ensure_freshness(c); + /* Add every node_t that support HSDir v3 for which we do have a valid * hsdir_index already computed for them for this consensus. */ { diff --git a/src/or/nodelist.c b/src/or/nodelist.c index bc9a79940b..ce1830083f 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -113,6 +113,11 @@ typedef struct nodelist_t { /* Set of addresses that belong to nodes we believe in. */ address_set_t *node_addrs; + + /* The valid-after time of the last live consensus that initialized the + * nodelist. We use this to detect outdated nodelists that need to be + * rebuilt using a newer consensus. */ + time_t live_consensus_valid_after; } nodelist_t; static inline unsigned int @@ -630,6 +635,12 @@ nodelist_set_consensus(networkstatus_t *ns) } } SMARTLIST_FOREACH_END(node); } + + /* If the consensus is live, note down the consensus valid-after that formed + * the nodelist. */ + if (networkstatus_is_live(ns, approx_time())) { + the_nodelist->live_consensus_valid_after = ns->valid_after; + } } /** Helper: return true iff a node has a usable amount of information*/ @@ -854,6 +865,25 @@ nodelist_assert_ok(void) digestmap_free(dm, NULL); } +/** Ensure that the nodelist has been created with the most recent consensus. + * If that's not the case, make it so. */ +void +nodelist_ensure_freshness(networkstatus_t *ns) +{ + tor_assert(ns); + + /* We don't even have a nodelist: this is a NOP. */ + if (!the_nodelist) { + return; + } + + if (the_nodelist->live_consensus_valid_after != ns->valid_after) { + log_info(LD_GENERAL, "Nodelist was not fresh: rebuilding. (%d / %d)", + (int) the_nodelist->live_consensus_valid_after, + (int) ns->valid_after); + nodelist_set_consensus(ns); + } +} /** Return a list of a node_t * for every node we know about. The caller * MUST NOT modify the list. (You can set and clear flags in the nodes if * you must, but you must not add or remove nodes.) */ diff --git a/src/or/nodelist.h b/src/or/nodelist.h index 1ffba2e8df..dbe9ad18ff 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -29,6 +29,7 @@ const node_t *node_get_by_hex_id(const char *identity_digest, node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out); node_t *nodelist_add_microdesc(microdesc_t *md); void nodelist_set_consensus(networkstatus_t *ns); +void nodelist_ensure_freshness(networkstatus_t *ns); int nodelist_probably_contains_address(const tor_addr_t *addr); void nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md); -- cgit v1.2.3-54-g00ecf