diff options
Diffstat (limited to 'src/feature/dirauth')
-rw-r--r-- | src/feature/dirauth/dirauth_config.c | 5 | ||||
-rw-r--r-- | src/feature/dirauth/dirauth_options.inc | 2 | ||||
-rw-r--r-- | src/feature/dirauth/dirauth_stub.c | 1 | ||||
-rw-r--r-- | src/feature/dirauth/dirauth_sys.c | 1 | ||||
-rw-r--r-- | src/feature/dirauth/dircollate.c | 5 | ||||
-rw-r--r-- | src/feature/dirauth/dirvote.c | 194 | ||||
-rw-r--r-- | src/feature/dirauth/dirvote.h | 65 | ||||
-rw-r--r-- | src/feature/dirauth/guardfraction.c | 2 | ||||
-rw-r--r-- | src/feature/dirauth/include.am | 6 | ||||
-rw-r--r-- | src/feature/dirauth/keypin.c | 8 | ||||
-rw-r--r-- | src/feature/dirauth/shared_random.c | 4 | ||||
-rw-r--r-- | src/feature/dirauth/shared_random_state.c | 8 | ||||
-rw-r--r-- | src/feature/dirauth/voting_schedule.c | 188 | ||||
-rw-r--r-- | src/feature/dirauth/voting_schedule.h | 93 |
14 files changed, 488 insertions, 94 deletions
diff --git a/src/feature/dirauth/dirauth_config.c b/src/feature/dirauth/dirauth_config.c index ca16dc8424..a0b6de7eca 100644 --- a/src/feature/dirauth/dirauth_config.c +++ b/src/feature/dirauth/dirauth_config.c @@ -20,8 +20,9 @@ /* Required for dirinfo_type_t in or_options_t */ #include "core/or/or.h" #include "app/config/config.h" +#include "app/config/resolve_addr.h" -#include "feature/dircommon/voting_schedule.h" +#include "feature/dirauth/voting_schedule.h" #include "feature/stats/rephist.h" #include "feature/dirauth/authmode.h" @@ -305,7 +306,7 @@ options_act_dirauth(const or_options_t *old_options) /* We may need to reschedule some dirauth stuff if our status changed. */ if (old_options) { if (options_transition_affects_dirauth_timing(old_options, options)) { - voting_schedule_recalculate_timing(options, time(NULL)); + dirauth_sched_recalculate_timing(options, time(NULL)); reschedule_dirvote(options); } } diff --git a/src/feature/dirauth/dirauth_options.inc b/src/feature/dirauth/dirauth_options.inc index 21f4996c39..2aa07a6c88 100644 --- a/src/feature/dirauth/dirauth_options.inc +++ b/src/feature/dirauth/dirauth_options.inc @@ -46,7 +46,7 @@ CONF_VAR(AuthDirTestEd25519LinkKeys, BOOL, 0, "1") /** Authority only: key=value pairs that we add to our networkstatus * consensus vote on the 'params' line. */ -CONF_VAR(ConsensusParams, STRING, 0, NULL) +CONF_VAR(ConsensusParams, LINELIST, 0, NULL) /** Authority only: minimum number of measured bandwidths we must see * before we only believe measured bandwidths to assign flags. */ diff --git a/src/feature/dirauth/dirauth_stub.c b/src/feature/dirauth/dirauth_stub.c index 15a195b0fb..9f48ce14fd 100644 --- a/src/feature/dirauth/dirauth_stub.c +++ b/src/feature/dirauth/dirauth_stub.c @@ -26,6 +26,7 @@ static const config_format_t dirauth_options_stub_fmt = { const struct subsys_fns_t sys_dirauth = { .name = "dirauth", + SUBSYS_DECLARE_LOCATION(), .supported = false, .level = DIRAUTH_SUBSYS_LEVEL, diff --git a/src/feature/dirauth/dirauth_sys.c b/src/feature/dirauth/dirauth_sys.c index 56ac501e16..07c5743877 100644 --- a/src/feature/dirauth/dirauth_sys.c +++ b/src/feature/dirauth/dirauth_sys.c @@ -60,6 +60,7 @@ dirauth_set_options(void *arg) const struct subsys_fns_t sys_dirauth = { .name = "dirauth", + SUBSYS_DECLARE_LOCATION(), .supported = true, .level = DIRAUTH_SUBSYS_LEVEL, .initialize = subsys_dirauth_initialize, diff --git a/src/feature/dirauth/dircollate.c b/src/feature/dirauth/dircollate.c index b35cb021ff..2657f53853 100644 --- a/src/feature/dirauth/dircollate.c +++ b/src/feature/dirauth/dircollate.c @@ -90,9 +90,9 @@ ddmap_entry_set_digests(ddmap_entry_t *ent, } HT_PROTOTYPE(double_digest_map, ddmap_entry_t, node, ddmap_entry_hash, - ddmap_entry_eq) + ddmap_entry_eq); HT_GENERATE2(double_digest_map, ddmap_entry_t, node, ddmap_entry_hash, - ddmap_entry_eq, 0.6, tor_reallocarray, tor_free_) + ddmap_entry_eq, 0.6, tor_reallocarray, tor_free_); /** Helper: add a single vote_routerstatus_t <b>vrs</b> to the collator * <b>dc</b>, indexing it by its RSA key digest, and by the 2-tuple of its RSA @@ -324,4 +324,3 @@ dircollator_get_votes_for_router(dircollator_t *dc, int idx) return digestmap_get(dc->by_collated_rsa_sha1, smartlist_get(dc->all_rsa_sha1_lst, idx)); } - diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index e230815ca3..828ecbc372 100644 --- a/src/feature/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -6,6 +6,7 @@ #define DIRVOTE_PRIVATE #include "core/or/or.h" #include "app/config/config.h" +#include "app/config/resolve_addr.h" #include "core/or/policies.h" #include "core/or/protover.h" #include "core/or/tor_version_st.h" @@ -36,7 +37,7 @@ #include "feature/stats/rephist.h" #include "feature/client/entrynodes.h" /* needed for guardfraction methods */ #include "feature/nodelist/torcert.h" -#include "feature/dircommon/voting_schedule.h" +#include "feature/dirauth/voting_schedule.h" #include "feature/dirauth/dirvote.h" #include "feature/dirauth/authmode.h" @@ -321,43 +322,47 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, tor_free(digest_algo_b64_digest_bw_file); } - smartlist_add_asprintf(chunks, - "network-status-version 3\n" - "vote-status %s\n" - "consensus-methods %s\n" - "published %s\n" - "valid-after %s\n" - "fresh-until %s\n" - "valid-until %s\n" - "voting-delay %d %d\n" - "%s%s" /* versions */ - "%s" /* protocols */ - "known-flags %s\n" - "flag-thresholds %s\n" - "params %s\n" - "%s" /* bandwidth file headers */ - "%s" /* bandwidth file digest */ - "dir-source %s %s %s %s %d %d\n" - "contact %s\n" - "%s" /* shared randomness information */ - , - v3_ns->type == NS_TYPE_VOTE ? "vote" : "opinion", - methods, - published, va, fu, vu, - v3_ns->vote_seconds, v3_ns->dist_seconds, - client_versions_line, - server_versions_line, - protocols_lines, - flags, - flag_thresholds, - params, - bw_headers_line ? bw_headers_line : "", - bw_file_digest ? bw_file_digest: "", - voter->nickname, fingerprint, voter->address, - fmt_addr32(addr), voter->dir_port, voter->or_port, - voter->contact, - shared_random_vote_str ? - shared_random_vote_str : ""); + const char *ip_str = fmt_addr32(addr); + + if (ip_str[0]) { + smartlist_add_asprintf(chunks, + "network-status-version 3\n" + "vote-status %s\n" + "consensus-methods %s\n" + "published %s\n" + "valid-after %s\n" + "fresh-until %s\n" + "valid-until %s\n" + "voting-delay %d %d\n" + "%s%s" /* versions */ + "%s" /* protocols */ + "known-flags %s\n" + "flag-thresholds %s\n" + "params %s\n" + "%s" /* bandwidth file headers */ + "%s" /* bandwidth file digest */ + "dir-source %s %s %s %s %d %d\n" + "contact %s\n" + "%s" /* shared randomness information */ + , + v3_ns->type == NS_TYPE_VOTE ? "vote" : "opinion", + methods, + published, va, fu, vu, + v3_ns->vote_seconds, v3_ns->dist_seconds, + client_versions_line, + server_versions_line, + protocols_lines, + flags, + flag_thresholds, + params, + bw_headers_line ? bw_headers_line : "", + bw_file_digest ? bw_file_digest: "", + voter->nickname, fingerprint, voter->address, + ip_str, voter->dir_port, voter->or_port, + voter->contact, + shared_random_vote_str ? + shared_random_vote_str : ""); + } tor_free(params); tor_free(flags); @@ -367,6 +372,9 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key, tor_free(bw_headers_line); tor_free(bw_file_digest); + if (ip_str[0] == '\0') + goto err; + if (!tor_digest_is_zero(voter->legacy_id_digest)) { char fpbuf[HEX_DIGEST_LEN+1]; base16_encode(fpbuf, sizeof(fpbuf), voter->legacy_id_digest, DIGEST_LEN); @@ -886,7 +894,7 @@ dirvote_get_intermediate_param_value(const smartlist_t *param_list, int ok; value = (int32_t) tor_parse_long(integer_str, 10, INT32_MIN, INT32_MAX, &ok, NULL); - if (BUG(! ok)) + if (BUG(!ok)) return default_val; ++n_found; } @@ -2853,7 +2861,7 @@ dirvote_act(const or_options_t *options, time_t now) "Mine is %s.", keys, hex_str(c->cache_info.identity_digest, DIGEST_LEN)); tor_free(keys); - voting_schedule_recalculate_timing(options, now); + dirauth_sched_recalculate_timing(options, now); } #define IF_TIME_FOR_NEXT_ACTION(when_field, done_field) \ @@ -2899,7 +2907,7 @@ dirvote_act(const or_options_t *options, time_t now) networkstatus_get_latest_consensus_by_flavor(FLAV_NS)); /* XXXX We will want to try again later if we haven't got enough * signatures yet. Implement this if it turns out to ever happen. */ - voting_schedule_recalculate_timing(options, now); + dirauth_sched_recalculate_timing(options, now); return voting_schedule.voting_starts; } ENDIF @@ -2966,7 +2974,7 @@ dirvote_perform_vote(void) if (!contents) return -1; - pending_vote = dirvote_add_vote(contents, &msg, &status); + pending_vote = dirvote_add_vote(contents, 0, &msg, &status); tor_free(contents); if (!pending_vote) { log_warn(LD_DIR, "Couldn't store my own vote! (I told myself, '%s'.)", @@ -3122,13 +3130,45 @@ list_v3_auth_ids(void) return keys; } +/* Check the voter information <b>vi</b>, and assert that at least one + * signature is good. Asserts on failure. */ +static void +assert_any_sig_good(const networkstatus_voter_info_t *vi) +{ + int any_sig_good = 0; + SMARTLIST_FOREACH(vi->sigs, document_signature_t *, sig, + if (sig->good_signature) + any_sig_good = 1); + tor_assert(any_sig_good); +} + +/* Add <b>cert</b> to our list of known authority certificates. */ +static void +add_new_cert_if_needed(const struct authority_cert_t *cert) +{ + tor_assert(cert); + if (!authority_cert_get_by_digests(cert->cache_info.identity_digest, + cert->signing_key_digest)) { + /* Hey, it's a new cert! */ + trusted_dirs_load_certs_from_string( + cert->cache_info.signed_descriptor_body, + TRUSTED_DIRS_CERTS_SRC_FROM_VOTE, 1 /*flush*/, + NULL); + if (!authority_cert_get_by_digests(cert->cache_info.identity_digest, + cert->signing_key_digest)) { + log_warn(LD_BUG, "We added a cert, but still couldn't find it."); + } + } +} + /** Called when we have received a networkstatus vote in <b>vote_body</b>. * Parse and validate it, and on success store it as a pending vote (which we * then return). Return NULL on failure. Sets *<b>msg_out</b> and * *<b>status_out</b> to an HTTP response and status code. (V3 authority * only) */ pending_vote_t * -dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out) +dirvote_add_vote(const char *vote_body, time_t time_posted, + const char **msg_out, int *status_out) { networkstatus_t *vote; networkstatus_voter_info_t *vi; @@ -3159,13 +3199,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out) } tor_assert(smartlist_len(vote->voters) == 1); vi = get_voter(vote); - { - int any_sig_good = 0; - SMARTLIST_FOREACH(vi->sigs, document_signature_t *, sig, - if (sig->good_signature) - any_sig_good = 1); - tor_assert(any_sig_good); - } + assert_any_sig_good(vi); ds = trusteddirserver_get_by_v3_auth_digest(vi->identity_digest); if (!ds) { char *keys = list_v3_auth_ids(); @@ -3178,19 +3212,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out) *msg_out = "Vote not from a recognized v3 authority"; goto err; } - tor_assert(vote->cert); - if (!authority_cert_get_by_digests(vote->cert->cache_info.identity_digest, - vote->cert->signing_key_digest)) { - /* Hey, it's a new cert! */ - trusted_dirs_load_certs_from_string( - vote->cert->cache_info.signed_descriptor_body, - TRUSTED_DIRS_CERTS_SRC_FROM_VOTE, 1 /*flush*/, - NULL); - if (!authority_cert_get_by_digests(vote->cert->cache_info.identity_digest, - vote->cert->signing_key_digest)) { - log_warn(LD_BUG, "We added a cert, but still couldn't find it."); - } - } + add_new_cert_if_needed(vote->cert); /* Is it for the right period? */ if (vote->valid_after != voting_schedule.interval_starts) { @@ -3203,6 +3225,23 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out) goto err; } + /* Check if we received it, as a post, after the cutoff when we + * start asking other dir auths for it. If we do, the best plan + * is to discard it, because using it greatly increases the chances + * of a split vote for this round (some dir auths got it in time, + * some didn't). */ + if (time_posted && time_posted > voting_schedule.fetch_missing_votes) { + char tbuf1[ISO_TIME_LEN+1], tbuf2[ISO_TIME_LEN+1]; + format_iso_time(tbuf1, time_posted); + format_iso_time(tbuf2, voting_schedule.fetch_missing_votes); + log_warn(LD_DIR, "Rejecting posted vote from %s received at %s; " + "our cutoff for received votes is %s. Check your clock, " + "CPU load, and network load. Also check the authority that " + "posted the vote.", vi->address, tbuf1, tbuf2); + *msg_out = "Posted vote received too late, would be dangerous to count it"; + goto err; + } + /* Fetch any new router descriptors we just learned about */ update_consensus_router_descriptor_downloads(time(NULL), 1, vote); @@ -4462,6 +4501,11 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, hostname = tor_dup_ip(addr); } + if (!hostname) { + log_err(LD_BUG, "Failed to determine hostname AND duplicate address"); + return NULL; + } + if (d_options->VersioningAuthoritativeDirectory) { client_versions = format_recommended_version_list(d_options->RecommendedClientVersions, 0); @@ -4613,7 +4657,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, else last_consensus_interval = options->TestingV3AuthInitialVotingInterval; v3_out->valid_after = - voting_schedule_get_start_of_next_interval(now, + voting_sched_get_start_of_interval_after(now, (int)last_consensus_interval, options->TestingV3AuthVotingStartOffset); format_iso_time(tbuf, v3_out->valid_after); @@ -4635,17 +4679,14 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, /* These are hardwired, to avoid disaster. */ v3_out->recommended_relay_protocols = - tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=4 Microdesc=1-2 Relay=2"); + tor_strdup(DIRVOTE_RECOMMEND_RELAY_PROTO); v3_out->recommended_client_protocols = - tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=4 Microdesc=1-2 Relay=2"); - v3_out->required_client_protocols = - tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=4 Microdesc=1-2 Relay=2"); + tor_strdup(DIRVOTE_RECOMMEND_CLIENT_PROTO); + v3_out->required_relay_protocols = - tor_strdup("Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=3-4 Microdesc=1 Relay=1-2"); + tor_strdup(DIRVOTE_REQUIRE_RELAY_PROTO); + v3_out->required_client_protocols = + tor_strdup(DIRVOTE_REQUIRE_CLIENT_PROTO); /* We are not allowed to vote to require anything we don't have. */ tor_assert(protover_all_supported(v3_out->required_relay_protocols, NULL)); @@ -4668,9 +4709,12 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, smartlist_sort_strings(v3_out->known_flags); if (d_options->ConsensusParams) { + config_line_t *paramline = d_options->ConsensusParams; v3_out->net_params = smartlist_new(); - smartlist_split_string(v3_out->net_params, - d_options->ConsensusParams, NULL, 0, 0); + for ( ; paramline; paramline = paramline->next) { + smartlist_split_string(v3_out->net_params, + paramline->value, NULL, 0, 0); + } smartlist_sort_strings(v3_out->net_params); } v3_out->bw_file_headers = bw_file_headers; diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h index 675f4ee148..a9b356b387 100644 --- a/src/feature/dirauth/dirvote.h +++ b/src/feature/dirauth/dirvote.h @@ -94,6 +94,7 @@ void dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items, /* Storing signatures and votes functions */ struct pending_vote_t * dirvote_add_vote(const char *vote_body, + time_t time_posted, const char **msg_out, int *status_out); int dirvote_add_signatures(const char *detached_signatures_body, @@ -142,9 +143,13 @@ dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items, } static inline struct pending_vote_t * -dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out) +dirvote_add_vote(const char *vote_body, + time_t time_posted, + const char **msg_out, + int *status_out) { (void) vote_body; + (void) time_posted; /* If the dirauth module is disabled, this should NEVER be called else we * failed to safeguard the dirauth module. */ tor_assert_nonfatal_unreached(); @@ -230,6 +235,64 @@ char *networkstatus_get_detached_signatures(smartlist_t *consensuses); STATIC microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method); +/** The recommended relay protocols for this authority's votes. + * Recommending a new protocol causes old tor versions to log a warning. + */ +#define DIRVOTE_RECOMMEND_RELAY_PROTO \ + "Cons=2 " \ + "Desc=2 " \ + "DirCache=2 " \ + "HSDir=2 " \ + "HSIntro=4 " \ + "HSRend=2 " \ + "Link=4-5 " \ + "LinkAuth=3 " \ + "Microdesc=2 " \ + "Relay=2" + +/** The recommended client protocols for this authority's votes. + * Recommending a new protocol causes old tor versions to log a warning. + */ +#define DIRVOTE_RECOMMEND_CLIENT_PROTO \ + "Cons=2 " \ + "Desc=2 " \ + "DirCache=2 " \ + "HSDir=2 " \ + "HSIntro=4 " \ + "HSRend=2 " \ + "Link=4-5 " \ + "Microdesc=2 " \ + "Relay=2" + +/** The required relay protocols for this authority's votes. + * WARNING: Requiring a new protocol causes old tor versions to shut down. + * Requiring the wrong protocols can break the tor network. + * See Proposal 303: When and how to remove support for protocol versions. + */ +#define DIRVOTE_REQUIRE_RELAY_PROTO \ + "Cons=2 " \ + "Desc=2 " \ + "DirCache=2 " \ + "HSDir=2 " \ + "HSIntro=4 " \ + "HSRend=2 " \ + "Link=4-5 " \ + "LinkAuth=3 " \ + "Microdesc=2 " \ + "Relay=2" + +/** The required relay protocols for this authority's votes. + * WARNING: Requiring a new protocol causes old tor versions to shut down. + * Requiring the wrong protocols can break the tor network. + * See Proposal 303: When and how to remove support for protocol versions. + */ +#define DIRVOTE_REQUIRE_CLIENT_PROTO \ + "Cons=2 " \ + "Desc=2 " \ + "Link=4 " \ + "Microdesc=2 " \ + "Relay=2" + #endif /* defined(DIRVOTE_PRIVATE) */ #endif /* !defined(TOR_DIRVOTE_H) */ diff --git a/src/feature/dirauth/guardfraction.c b/src/feature/dirauth/guardfraction.c index 40189ce494..b84f804f5f 100644 --- a/src/feature/dirauth/guardfraction.c +++ b/src/feature/dirauth/guardfraction.c @@ -188,7 +188,7 @@ guardfraction_file_parse_inputs_line(const char *inputs_line, * * guardfraction-file-version 1 * written-at <date and time> - * n-inputs <number of consesuses parsed> <number of days considered> + * n-inputs <number of consensuses parsed> <number of days considered> * * guard-seen <fpr 1> <guardfraction percentage> <consensus appearances> * guard-seen <fpr 2> <guardfraction percentage> <consensus appearances> diff --git a/src/feature/dirauth/include.am b/src/feature/dirauth/include.am index 2ef629ae35..e26f120d4e 100644 --- a/src/feature/dirauth/include.am +++ b/src/feature/dirauth/include.am @@ -19,7 +19,8 @@ MODULE_DIRAUTH_SOURCES = \ src/feature/dirauth/recommend_pkg.c \ src/feature/dirauth/shared_random.c \ src/feature/dirauth/shared_random_state.c \ - src/feature/dirauth/voteflags.c + src/feature/dirauth/voteflags.c \ + src/feature/dirauth/voting_schedule.c # ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ @@ -43,7 +44,8 @@ noinst_HEADERS += \ src/feature/dirauth/shared_random.h \ src/feature/dirauth/shared_random_state.h \ src/feature/dirauth/vote_microdesc_hash_st.h \ - src/feature/dirauth/voteflags.h + src/feature/dirauth/voteflags.h \ + src/feature/dirauth/voting_schedule.h if BUILD_MODULE_DIRAUTH LIBTOR_APP_A_SOURCES += $(MODULE_DIRAUTH_SOURCES) diff --git a/src/feature/dirauth/keypin.c b/src/feature/dirauth/keypin.c index edf5ba5833..5072a58573 100644 --- a/src/feature/dirauth/keypin.c +++ b/src/feature/dirauth/keypin.c @@ -118,14 +118,14 @@ return (unsigned) siphash24g(a->ed25519_key, sizeof(a->ed25519_key)); } HT_PROTOTYPE(rsamap, keypin_ent_st, rsamap_node, keypin_ent_hash_rsa, - keypin_ents_eq_rsa) + keypin_ents_eq_rsa); HT_GENERATE2(rsamap, keypin_ent_st, rsamap_node, keypin_ent_hash_rsa, - keypin_ents_eq_rsa, 0.6, tor_reallocarray, tor_free_) + keypin_ents_eq_rsa, 0.6, tor_reallocarray, tor_free_); HT_PROTOTYPE(edmap, keypin_ent_st, edmap_node, keypin_ent_hash_ed, - keypin_ents_eq_ed) + keypin_ents_eq_ed); HT_GENERATE2(edmap, keypin_ent_st, edmap_node, keypin_ent_hash_ed, - keypin_ents_eq_ed, 0.6, tor_reallocarray, tor_free_) + keypin_ents_eq_ed, 0.6, tor_reallocarray, tor_free_); /** * Check whether we already have an entry in the key pinning table for a diff --git a/src/feature/dirauth/shared_random.c b/src/feature/dirauth/shared_random.c index 48e2147ea6..fd55008242 100644 --- a/src/feature/dirauth/shared_random.c +++ b/src/feature/dirauth/shared_random.c @@ -99,7 +99,7 @@ #include "feature/nodelist/dirlist.h" #include "feature/hs_common/shared_random_client.h" #include "feature/dirauth/shared_random_state.h" -#include "feature/dircommon/voting_schedule.h" +#include "feature/dirauth/voting_schedule.h" #include "feature/dirauth/dirvote.h" #include "feature/dirauth/authmode.h" @@ -1261,7 +1261,7 @@ sr_act_post_consensus(const networkstatus_t *consensus) } /* Prepare our state so that it's ready for the next voting period. */ - sr_state_update(voting_schedule_get_next_valid_after_time()); + sr_state_update(dirauth_sched_get_next_valid_after_time()); } /** Initialize shared random subsystem. This MUST be called early in the boot diff --git a/src/feature/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c index cfbfa4ec5b..07bc757506 100644 --- a/src/feature/dirauth/shared_random_state.c +++ b/src/feature/dirauth/shared_random_state.c @@ -20,7 +20,7 @@ #include "feature/dirauth/shared_random.h" #include "feature/hs_common/shared_random_client.h" #include "feature/dirauth/shared_random_state.h" -#include "feature/dircommon/voting_schedule.h" +#include "feature/dirauth/voting_schedule.h" #include "lib/encoding/confline.h" #include "lib/version/torversion.h" @@ -60,6 +60,7 @@ DUMMY_TYPECHECK_INSTANCE(sr_disk_state_t); #define SR_DISK_STATE_MAGIC 0x98AB1254 /** Array of variables that are saved to disk as a persistent state. */ +// clang-format off static const config_var_t state_vars[] = { V(Version, POSINT, "0"), V(TorVersion, STRING, NULL), @@ -73,6 +74,7 @@ static const config_var_t state_vars[] = { VAR("SharedRandCurrentValue", LINELIST_S, SharedRandValues, NULL), END_OF_CONFIG_VARS }; +// clang-format on /** "Extra" variable in the state that receives lines we can't parse. This * lets us preserve options from versions of Tor newer than us. */ @@ -139,7 +141,7 @@ get_state_valid_until_time(time_t now) voting_interval = get_voting_interval(); /* Find the time the current round started. */ - beginning_of_current_round = get_start_time_of_current_round(); + beginning_of_current_round = dirauth_sched_get_cur_valid_after_time(); /* Find how many rounds are left till the end of the protocol run */ current_round = (now / voting_interval) % total_rounds; @@ -1331,7 +1333,7 @@ sr_state_init(int save_to_disk, int read_from_disk) /* We have a state in memory, let's make sure it's updated for the current * and next voting round. */ { - time_t valid_after = voting_schedule_get_next_valid_after_time(); + time_t valid_after = dirauth_sched_get_next_valid_after_time(); sr_state_update(valid_after); } return 0; diff --git a/src/feature/dirauth/voting_schedule.c b/src/feature/dirauth/voting_schedule.c new file mode 100644 index 0000000000..efc4a0b316 --- /dev/null +++ b/src/feature/dirauth/voting_schedule.c @@ -0,0 +1,188 @@ +/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file voting_schedule.c + * \brief Compute information about our voting schedule as a directory + * authority. + **/ + +#include "feature/dirauth/voting_schedule.h" + +#include "core/or/or.h" +#include "app/config/config.h" +#include "feature/nodelist/networkstatus.h" + +#include "feature/nodelist/networkstatus_st.h" + +/* ===== + * Vote scheduling + * ===== */ + +/* Populate and return a new voting_schedule_t that can be used to schedule + * voting. The object is allocated on the heap and it's the responsibility of + * the caller to free it. Can't fail. */ +static voting_schedule_t * +create_voting_schedule(const or_options_t *options, time_t now, int severity) +{ + int interval, vote_delay, dist_delay; + time_t start; + time_t end; + networkstatus_t *consensus; + voting_schedule_t *new_voting_schedule; + + new_voting_schedule = tor_malloc_zero(sizeof(voting_schedule_t)); + + consensus = networkstatus_get_live_consensus(now); + + if (consensus) { + 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; + dist_delay = options->TestingV3AuthInitialDistDelay; + } + + tor_assert(interval > 0); + new_voting_schedule->interval = interval; + + if (vote_delay + dist_delay > interval/2) + vote_delay = dist_delay = interval / 4; + + start = new_voting_schedule->interval_starts = + voting_sched_get_start_of_interval_after(now,interval, + options->TestingV3AuthVotingStartOffset); + end = voting_sched_get_start_of_interval_after(start+1, interval, + options->TestingV3AuthVotingStartOffset); + + tor_assert(end > start); + + new_voting_schedule->fetch_missing_signatures = start - (dist_delay/2); + new_voting_schedule->voting_ends = start - dist_delay; + new_voting_schedule->fetch_missing_votes = + start - dist_delay - (vote_delay/2); + new_voting_schedule->voting_starts = start - dist_delay - vote_delay; + + { + char tbuf[ISO_TIME_LEN+1]; + format_iso_time(tbuf, new_voting_schedule->interval_starts); + tor_log(severity, LD_DIR,"Choosing expected valid-after time as %s: " + "consensus_set=%d, interval=%d", + tbuf, consensus?1:0, interval); + } + + return new_voting_schedule; +} + +#define voting_schedule_free(s) \ + FREE_AND_NULL(voting_schedule_t, voting_schedule_free_, (s)) + +/** Frees a voting_schedule_t. This should be used instead of the generic + * tor_free. */ +static void +voting_schedule_free_(voting_schedule_t *voting_schedule_to_free) +{ + if (!voting_schedule_to_free) + return; + tor_free(voting_schedule_to_free); +} + +voting_schedule_t voting_schedule; + +/** + * Return the current voting schedule, recreating it if necessary. + * + * Dirauth only. + **/ +static const voting_schedule_t * +dirauth_get_voting_schedule(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 (fast_mem_is_zero((const char *) &voting_schedule, + sizeof(voting_schedule))) { + 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) { + dirauth_sched_recalculate_timing(get_options(), approx_time()); + voting_schedule.created_on_demand = 1; + } + + return &voting_schedule; +} + +/** Return the next voting valid-after time. + * + * Dirauth only. */ +time_t +dirauth_sched_get_next_valid_after_time(void) +{ + return dirauth_get_voting_schedule()->interval_starts; +} + +/** + * Return our best idea of what the valid-after time for the _current_ + * consensus, whether we have one or not. + * + * Dirauth only. + **/ +time_t +dirauth_sched_get_cur_valid_after_time(void) +{ + const voting_schedule_t *sched = dirauth_get_voting_schedule(); + time_t next_start = sched->interval_starts; + int interval = sched->interval; + int offset = get_options()->TestingV3AuthVotingStartOffset; + return voting_sched_get_start_of_interval_after(next_start - interval - 1, + interval, + offset); +} + +/** Return the voting interval that we are configured to use. + * + * Dirauth only. */ +int +dirauth_sched_get_configured_interval(void) +{ + return get_options()->V3AuthVotingInterval; +} + +/** Set voting_schedule to hold the timing for the next vote we should be + * doing. All type of tor do that because HS subsystem needs the timing as + * well to function properly. */ +void +dirauth_sched_recalculate_timing(const or_options_t *options, time_t now) +{ + voting_schedule_t *new_voting_schedule; + + /* get the new voting schedule */ + new_voting_schedule = create_voting_schedule(options, now, LOG_INFO); + tor_assert(new_voting_schedule); + + /* Fill in the global static struct now */ + memcpy(&voting_schedule, new_voting_schedule, sizeof(voting_schedule)); + voting_schedule_free(new_voting_schedule); +} diff --git a/src/feature/dirauth/voting_schedule.h b/src/feature/dirauth/voting_schedule.h new file mode 100644 index 0000000000..9e2ac29c75 --- /dev/null +++ b/src/feature/dirauth/voting_schedule.h @@ -0,0 +1,93 @@ +/* Copyright (c) 2018-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file voting_schedule.h + * \brief Header file for voting_schedule.c. + **/ + +#ifndef TOR_VOTING_SCHEDULE_H +#define TOR_VOTING_SCHEDULE_H + +#include "core/or/or.h" + +#ifdef HAVE_MODULE_DIRAUTH + +/** Scheduling information for a voting interval. */ +typedef struct { + /** When do we generate and distribute our vote for this interval? */ + time_t voting_starts; + /** When do we send an HTTP request for any votes that we haven't + * been posted yet?*/ + time_t fetch_missing_votes; + /** When do we give up on getting more votes and generate a consensus? */ + time_t voting_ends; + /** When do we send an HTTP request for any signatures we're expecting to + * see on the consensus? */ + time_t fetch_missing_signatures; + /** When do we publish the consensus? */ + time_t interval_starts; + + /** Our computed dirauth interval */ + int interval; + + /** True iff we have generated and distributed our vote. */ + int have_voted; + /** True iff we've requested missing votes. */ + int have_fetched_missing_votes; + /** True iff we have built a consensus and sent the signatures around. */ + int have_built_consensus; + /** True iff we've fetched missing signatures. */ + int have_fetched_missing_signatures; + /** True iff we have published our consensus. */ + int have_published_consensus; + + /* True iff this voting schedule was set on demand meaning not through the + * normal vote operation of a dirauth or when a consensus is set. This only + * applies to a directory authority that needs to recalculate the voting + * 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. */ + +extern voting_schedule_t voting_schedule; + +void dirauth_sched_recalculate_timing(const or_options_t *options, + time_t now); + +time_t dirauth_sched_get_next_valid_after_time(void); +time_t dirauth_sched_get_cur_valid_after_time(void); +int dirauth_sched_get_configured_interval(void); + +#else /* !defined(HAVE_MODULE_DIRAUTH) */ + +#define dirauth_sched_recalculate_timing(opt,now) \ + ((void)(opt), (void)(now)) + +static inline time_t +dirauth_sched_get_next_valid_after_time(void) +{ + tor_assert_unreached(); + return 0; +} +static inline time_t +dirauth_sched_get_cur_valid_after_time(void) +{ + tor_assert_unreached(); + return 0; +} +static inline int +dirauth_sched_get_configured_interval(void) +{ + tor_assert_unreached(); + return 1; +} +#endif /* defined(HAVE_MODULE_DIRAUTH) */ + +#endif /* !defined(TOR_VOTING_SCHEDULE_H) */ |