r15279@catbus: nickm | 2007-09-22 02:00:06 -0400

V3 authority work: fetch missing votes and/or signatures as needed.


svn:r11575
This commit is contained in:
Nick Mathewson 2007-09-22 06:06:05 +00:00
parent 991ebb42de
commit 921f9f774d
9 changed files with 186 additions and 29 deletions

View File

@ -1,3 +1,8 @@
Changes in version 0.2.0.8-alpha - 2007-??-??
o Major features (directory authorities):
- When an authority is missing votes or signatures, it now tries to fetch
them.
Changes in version 0.2.0.7-alpha - 2007-09-21
o New directory authorities:
- Set up moria1 and tor26 as the first v3 directory authorities. See

View File

@ -59,8 +59,8 @@ Things we'd like to do in 0.2.0.x:
. Code to retry download.
o Code to generate consensus from a list of votes
o Detect whether votes are really all for the same period.
. Push/pull documents as appropriate.
- Pull votes and signatures if we don't get them.
o Push/pull documents as appropriate.
o Pull votes and signatures if we don't get them.
- Cache votes and signatures on disk?
o Code to keep consensus docs in limbo if they don't have
have enough signatures.

View File

@ -297,6 +297,8 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
break;
case DIR_PURPOSE_FETCH_STATUS_VOTE:
case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
type = V3_AUTHORITY;
break;
case DIR_PURPOSE_FETCH_CONSENSUS:
case DIR_PURPOSE_FETCH_CERTIFICATE:
type = V3_AUTHORITY;
@ -377,6 +379,32 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
}
}
/** As directory_get_from_dirserver, but initiates a request to <i>every</i>
* directory authority other than ourself. Only for use by authorities when
* searching for missing information while voting. */
void
directory_get_from_all_authorities(uint8_t dir_purpose,
uint8_t router_purpose,
const char *resource)
{
tor_assert(dir_purpose == DIR_PURPOSE_FETCH_STATUS_VOTE ||
dir_purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES);
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
trusted_dir_server_t *, ds,
{
routerstatus_t *rs;
if (router_digest_is_me(ds->digest))
continue;
if (!(ds->type & V3_AUTHORITY))
continue;
rs = &ds->fake_status.status;
/* XXXX020 should this ever tunnel via tor? */
directory_initiate_command_routerstatus(rs, dir_purpose, router_purpose,
0, resource, NULL, 0);
});
}
/** Launch a new connection to the directory server <b>status</b> to
* upload or download a server or rendezvous
* descriptor. <b>dir_purpose</b> determines what
@ -727,7 +755,7 @@ directory_send_command(dir_connection_t *conn,
httpcommand = "GET";
len = strlen(resource)+32;
url = tor_malloc(len);
tor_snprintf(url, len, "/tor/status-vote/next/%s", resource);
tor_snprintf(url, len, "/tor/status-vote/next/%s.z", resource);
break;
case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
tor_assert(!resource);
@ -1318,7 +1346,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
/*XXXX020*/;
}
if (conn->_base.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
log_info(LD_DIR,"Received aurhority certificatess (size %d) from server "
log_info(LD_DIR,"Received authority certificatess (size %d) from server "
"'%s:%d'",(int) body_len, conn->_base.address, conn->_base.port);
if (status_code != 200) {
log_fn(status_code == 403 ? LOG_INFO : LOG_WARN, LD_DIR,
@ -1336,10 +1364,38 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
}
}
if (conn->_base.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
/*XXXX020*/;
const char *msg;
int st;
log_info(LD_DIR,"Got votes (size %d) from server %s:%d",
(int) body_len, conn->_base.address, conn->_base.port);
if (status_code != 200) {
log_fn(status_code == 403 ? LOG_INFO : LOG_WARN, LD_DIR,
"Received http status code %d (%s) from server "
"'%s:%d' while fetching \"/tor/status-vote/next/%s.z\".",
status_code, escaped(reason), conn->_base.address,
conn->_base.port, conn->requested_resource);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
if (!dirvote_add_vote(body, &msg, &st)) {
log_warn(LD_DIR, "Error adding retrieved vote: %s", msg);
} else {
log_info(LD_DIR, "Added vote(s) successfully.");
}
}
if (conn->_base.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
/*XXXX020*/;
log_info(LD_DIR,"Got detached signatures (size %d) from server %s:%d",
(int) body_len, conn->_base.address, conn->_base.port);
if (status_code != 200) {
log_fn(status_code == 403 ? LOG_INFO : LOG_WARN, LD_DIR,
"Received http status code %d (%s) from server "
"'%s:%d' while fetching \"/tor/status-vote/consensus-signatures.z\".",
status_code, escaped(reason), conn->_base.address,
conn->_base.port);
tor_free(body); tor_free(headers); tor_free(reason);
return -1;
}
dirvote_add_signatures(body);
}
if (conn->_base.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||

View File

@ -2198,7 +2198,7 @@ format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
{
networkstatus_vote_t *v;
if (!(v = networkstatus_parse_vote_from_string(status, 1))) {
if (!(v = networkstatus_parse_vote_from_string(status, NULL, 1))) {
log_err(LD_BUG,"Generated a networkstatus vote we couldn't parse: "
"<<%s>>", status);
goto err;

View File

@ -17,6 +17,10 @@ static int dirvote_add_signatures_to_pending_consensus(
const char *detached_signatures_body,
const char **msg_out);
static char *list_v3_auth_ids(void);
static void dirvote_fetch_missing_votes(void);
static void dirvote_fetch_missing_signatures(void);
/* XXXX020 lots of the functions here could be made static. Do so. */
/* =====
* Voting and consensus generation
@ -641,7 +645,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
{
networkstatus_vote_t *c;
if (!(c = networkstatus_parse_vote_from_string(result, 0))) {
if (!(c = networkstatus_parse_vote_from_string(result, NULL, 0))) {
log_err(LD_BUG,"Generated a networkstatus consensus we couldn't "
"parse.");
tor_free(result);
@ -686,7 +690,8 @@ networkstatus_check_voter_signature(networkstatus_vote_t *consensus,
}
/** Given a v3 networkstatus consensus in <b>consensus</b>, check every
* as-yet-unchecked signature on <b>consensus</b>. Return 0 if there are
* as-yet-unchecked signature on <b>consensus</b>. Return 1 if there is a
* signature from every recognized authority on it, 0 if there are
* enough good signatures from recognized authorities on it, -1 if we might
* get enough good signatures by fetching missing certificates, and -2
* otherwise. Log messages at INFO or WARN: if <b>warn</b> is over 1, warn
@ -701,7 +706,8 @@ networkstatus_check_consensus_signature(networkstatus_vote_t *consensus,
int n_bad = 0;
int n_unknown = 0;
int n_no_signature = 0;
int n_required = get_n_authorities(V3_AUTHORITY)/2 + 1;
int n_v3_authorities = get_n_authorities(V3_AUTHORITY);
int n_required = n_v3_authorities/2 + 1;
smartlist_t *need_certs_from = smartlist_create();
smartlist_t *unrecognized = smartlist_create();
smartlist_t *missing_authorities = smartlist_create();
@ -786,7 +792,9 @@ networkstatus_check_consensus_signature(networkstatus_vote_t *consensus,
smartlist_free(need_certs_from);
smartlist_free(missing_authorities);
if (n_good >= n_required)
if (n_good == n_v3_authorities)
return 1;
else if (n_good >= n_required)
return 0;
else if (n_good + n_missing_key >= n_required)
return -1;
@ -1076,11 +1084,15 @@ static struct {
/* True iff we have generated and distributed our vote. */
int have_voted;
/* DOCDOC */
int have_fetched_missing_votes;
/* True iff we have built a consensus and sent the signatures around. */
int have_built_consensus;
/* DOCDOC */
int have_fetched_missing_signatures;
/* True iff we have published our consensus. */
int have_published_consensus;
} voting_schedule = {0,0,0,0,0,0,0,0,0};
} voting_schedule = {0,0,0,0,0,0,0,0,0,0,0};
/** Set voting_schedule to hold the timing for the next vote we should be
* doing. */
@ -1143,7 +1155,12 @@ dirvote_act(time_t now)
dirvote_perform_vote();
voting_schedule.have_voted = 1;
}
/* XXXX020 after a couple minutes here, start trying to fetch votes. */
if (voting_schedule.fetch_missing_votes < now &&
!voting_schedule.have_fetched_missing_votes) {
log_notice(LD_DIR, "Time to fetch any votes that we're missing.");
dirvote_fetch_missing_votes();
voting_schedule.have_fetched_missing_votes = 1;
}
if (voting_schedule.voting_ends < now &&
!voting_schedule.have_built_consensus) {
log_notice(LD_DIR, "Time to compute a consensus.");
@ -1152,6 +1169,12 @@ dirvote_act(time_t now)
* votes yet. */
voting_schedule.have_built_consensus = 1;
}
if (voting_schedule.fetch_missing_signatures < now &&
!voting_schedule.have_fetched_missing_signatures) {
log_notice(LD_DIR, "Time to fetch any signatures that we're missing.");
dirvote_fetch_missing_signatures();
voting_schedule.have_fetched_missing_signatures = 1;
}
if (voting_schedule.interval_starts < now &&
!voting_schedule.have_published_consensus) {
log_notice(LD_DIR, "Time to publish the consensus.");
@ -1216,6 +1239,53 @@ dirvote_perform_vote(void)
log_notice(LD_DIR, "Vote posted.");
}
/** DOCDOC */
static void
dirvote_fetch_missing_votes(void)
{
smartlist_t *missing_fps = smartlist_create();
char *resource;
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
trusted_dir_server_t *, ds,
{
if ((ds->type & V3_AUTHORITY))
continue;
if (!dirvote_get_vote(ds->v3_identity_digest)) {
char *cp = tor_malloc(HEX_DIGEST_LEN+1);
base16_encode(cp, HEX_DIGEST_LEN+1, ds->v3_identity_digest,
DIGEST_LEN);
smartlist_add(missing_fps, cp);
}
});
if (!smartlist_len(missing_fps)) {
smartlist_free(missing_fps);
return;
}
log_notice(LOG_NOTICE, "We're missing votes from %d authorities. Asking "
"every other authority for a copy.", smartlist_len(missing_fps));
resource = smartlist_join_strings(missing_fps, "+", 0, NULL);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE,
0, resource);
tor_free(resource);
SMARTLIST_FOREACH(missing_fps, char *, cp, tor_free(cp));
smartlist_free(missing_fps);
}
/** DOCDOC */
static void
dirvote_fetch_missing_signatures(void)
{
if (!pending_consensus)
return;
if (networkstatus_check_consensus_signature(pending_consensus, -1) == 1)
return; /* we have a signature from everybody. */
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES,
0, NULL);
}
/** Drop all currently pending votes, consensus, and detached signatures. */
void
dirvote_clear_pending_votes(void)
@ -1271,6 +1341,8 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
networkstatus_voter_info_t *vi;
trusted_dir_server_t *ds;
pending_vote_t *pending_vote = NULL;
const char *end_of_vote = NULL;
int any_failed = 0;
tor_assert(vote_body);
tor_assert(msg_out);
tor_assert(status_out);
@ -1280,7 +1352,8 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
pending_vote_list = smartlist_create();
*msg_out = NULL;
vote = networkstatus_parse_vote_from_string(vote_body, 1);
again:
vote = networkstatus_parse_vote_from_string(vote_body, &end_of_vote, 1);
if (!vote) {
*msg_out = "Unable to parse vote";
goto err;
@ -1325,7 +1398,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
goto err;
}
/* Now see whether we already have a vote from this authority.*/
/* Now see whether we already h<ave a vote from this authority.*/
SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, {
if (! memcmp(v->vote->cert->cache_info.identity_digest,
vote->cert->cache_info.identity_digest,
@ -1359,17 +1432,29 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
vote->published);
pending_vote->vote = vote;
smartlist_add(pending_vote_list, pending_vote);
if (end_of_vote && !strcmpstart(end_of_vote, "network-status-version "))
goto again;
if (any_failed)
goto err;
if (!*status_out)
*status_out = 200;
*msg_out = "ok";
return pending_vote;
err:
any_failed = 1;
if (vote)
networkstatus_vote_free(vote);
if (!*msg_out)
*msg_out = "Error adding vote";
if (!*status_out)
*status_out = 400;
if (end_of_vote && !strcmpstart(end_of_vote, "network-status-version "))
goto again;
return NULL;
}
@ -1414,7 +1499,7 @@ dirvote_compute_consensus(void)
log_warn(LD_DIR, "Couldn't generate a consensus at all!");
goto err;
}
consensus = networkstatus_parse_vote_from_string(consensus_body, 0);
consensus = networkstatus_parse_vote_from_string(consensus_body, NULL, 0);
if (!consensus) {
log_warn(LD_DIR, "Couldn't parse consensus we generated!");
goto err;
@ -1526,7 +1611,7 @@ dirvote_add_signatures_to_pending_consensus(
ns_detached_signatures_t *sigs =
networkstatus_parse_detached_signatures(new_detached, NULL);
networkstatus_vote_t *v = networkstatus_parse_vote_from_string(
pending_consensus_body, 0);
pending_consensus_body, NULL, 0);
tor_assert(sigs);
ns_detached_signatures_free(sigs);
tor_assert(v);

View File

@ -2769,6 +2769,9 @@ void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
void directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
const char *resource,
int retry_if_no_servers);
void directory_get_from_all_authorities(uint8_t dir_purpose,
uint8_t router_purpose,
const char *resource);
void directory_initiate_command_routerstatus(routerstatus_t *status,
uint8_t dir_purpose,
uint8_t router_purpose,
@ -3662,7 +3665,8 @@ void dump_distinct_digest_count(int severity);
networkstatus_t *networkstatus_parse_from_string(const char *s);
networkstatus_vote_t *networkstatus_parse_vote_from_string(const char *s,
int is_vote);
const char **eos_out,
int is_vote);
ns_detached_signatures_t *networkstatus_parse_detached_signatures(
const char *s, const char *eos);

View File

@ -284,8 +284,8 @@ trusted_dirs_load_certs_from_string(const char *contents, int from_store)
trusted_dirs_flush_certs_to_disk();
if (consensus_waiting_for_certs) {
if (!networkstatus_check_consensus_signature(
consensus_waiting_for_certs, 0)) {
if (networkstatus_check_consensus_signature(
consensus_waiting_for_certs, 0)<0) {
if (!networkstatus_set_current_consensus(
consensus_waiting_for_certs_body, 0, 1)) {
tor_free(consensus_waiting_for_certs_body);
@ -4081,7 +4081,7 @@ networkstatus_set_current_consensus(const char *consensus, int from_cache,
networkstatus_vote_t *c;
int r;
/* Make sure it's parseable. */
c = networkstatus_parse_vote_from_string(consensus, 0);
c = networkstatus_parse_vote_from_string(consensus, NULL, 0);
if (!c) {
log_warn(LD_DIR, "Unable to parse networkstatus consensus");
return -1;

View File

@ -1790,7 +1790,8 @@ networkstatus_parse_from_string(const char *s)
* networkstatus consensus (if <b>is_vote</b> is false) from <b>s</b>, and
* return the result. Return NULL on failure. */
networkstatus_vote_t *
networkstatus_parse_vote_from_string(const char *s, int is_vote)
networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
int is_vote)
{
smartlist_t *tokens = smartlist_create();
smartlist_t *rs_tokens = NULL, *footer_tokens = NULL;
@ -2026,7 +2027,10 @@ networkstatus_parse_vote_from_string(const char *s, int is_vote)
/* Parse footer; check signature. */
footer_tokens = smartlist_create();
end_of_footer = s + strlen(s);
if ((end_of_footer = strstr(s, "\nnetwork-status-version ")))
++end_of_footer;
else
end_of_footer = s + strlen(s);
if (tokenize_string(s, end_of_footer, footer_tokens,
networkstatus_vote_footer_token_table)) {
log_warn(LD_DIR, "Error tokenizing network-status vote footer.");
@ -2092,6 +2096,9 @@ networkstatus_parse_vote_from_string(const char *s, int is_vote)
/* XXXX020 check dates for plausibility. ??? */
if (eos_out)
*eos_out = end_of_footer;
goto done;
err:
if (ns)

View File

@ -2520,7 +2520,7 @@ test_v3_networkstatus(void)
/* dump the vote and try to parse it. */
v1_text = format_networkstatus_vote(sign_skey_1, vote);
test_assert(v1_text);
v1 = networkstatus_parse_vote_from_string(v1_text, 1);
v1 = networkstatus_parse_vote_from_string(v1_text, NULL, 1);
test_assert(v1);
/* Make sure the parsed thing was right. */
@ -2604,7 +2604,7 @@ test_v3_networkstatus(void)
/* generate and parse. */
v2_text = format_networkstatus_vote(sign_skey_2, vote);
test_assert(v2_text);
v2 = networkstatus_parse_vote_from_string(v2_text, 1);
v2 = networkstatus_parse_vote_from_string(v2_text, NULL, 1);
test_assert(v2);
/* Check that flags come out right.*/
cp = smartlist_join_strings(v2->known_flags, ":", 0, NULL);
@ -2639,7 +2639,7 @@ test_v3_networkstatus(void)
v3_text = format_networkstatus_vote(sign_skey_3, vote);
test_assert(v3_text);
v3 = networkstatus_parse_vote_from_string(v3_text, 1);
v3 = networkstatus_parse_vote_from_string(v3_text, NULL, 1);
test_assert(v3);
/* Compute a consensus as voter 3. */
@ -2650,7 +2650,7 @@ test_v3_networkstatus(void)
cert3->identity_key,
sign_skey_3);
test_assert(consensus_text);
con = networkstatus_parse_vote_from_string(consensus_text, 0);
con = networkstatus_parse_vote_from_string(consensus_text, NULL, 0);
test_assert(con);
//log_notice(LD_GENERAL, "<<%s>>\n<<%s>>\n<<%s>>\n",
// v1_text, v2_text, v3_text);
@ -2759,8 +2759,8 @@ test_v3_networkstatus(void)
sign_skey_1);
test_assert(consensus_text2);
test_assert(consensus_text3);
con2 = networkstatus_parse_vote_from_string(consensus_text2, 0);
con3 = networkstatus_parse_vote_from_string(consensus_text3, 0);
con2 = networkstatus_parse_vote_from_string(consensus_text2, NULL, 0);
con3 = networkstatus_parse_vote_from_string(consensus_text3, NULL, 0);
test_assert(con2);
test_assert(con3);