summaryrefslogtreecommitdiff
path: root/src/feature/dirauth
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature/dirauth')
-rw-r--r--src/feature/dirauth/dirauth_config.c5
-rw-r--r--src/feature/dirauth/dirauth_options.inc2
-rw-r--r--src/feature/dirauth/dirauth_stub.c1
-rw-r--r--src/feature/dirauth/dirauth_sys.c1
-rw-r--r--src/feature/dirauth/dircollate.c5
-rw-r--r--src/feature/dirauth/dirvote.c194
-rw-r--r--src/feature/dirauth/dirvote.h65
-rw-r--r--src/feature/dirauth/guardfraction.c2
-rw-r--r--src/feature/dirauth/include.am6
-rw-r--r--src/feature/dirauth/keypin.c8
-rw-r--r--src/feature/dirauth/shared_random.c4
-rw-r--r--src/feature/dirauth/shared_random_state.c8
-rw-r--r--src/feature/dirauth/voting_schedule.c188
-rw-r--r--src/feature/dirauth/voting_schedule.h93
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) */