summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2007-09-22 06:06:05 +0000
committerNick Mathewson <nickm@torproject.org>2007-09-22 06:06:05 +0000
commit921f9f774d4ce3ed24b48a5921fe7134dccffbb8 (patch)
treed61d5bf9cd4de80e729b334c5b146357cab81c6f
parent991ebb42de888661a47512acec02d37f1db12685 (diff)
downloadtor-921f9f774d4ce3ed24b48a5921fe7134dccffbb8.tar.gz
tor-921f9f774d4ce3ed24b48a5921fe7134dccffbb8.zip
r15279@catbus: nickm | 2007-09-22 02:00:06 -0400
V3 authority work: fetch missing votes and/or signatures as needed. svn:r11575
-rw-r--r--ChangeLog5
-rw-r--r--doc/TODO4
-rw-r--r--src/or/directory.c64
-rw-r--r--src/or/dirserv.c2
-rw-r--r--src/or/dirvote.c105
-rw-r--r--src/or/or.h6
-rw-r--r--src/or/routerlist.c6
-rw-r--r--src/or/routerparse.c11
-rw-r--r--src/or/test.c12
9 files changed, 186 insertions, 29 deletions
diff --git a/ChangeLog b/ChangeLog
index cf7148bc66..f86f0a2a63 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/doc/TODO b/doc/TODO
index 86f34d04db..92718482d8 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -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.
diff --git a/src/or/directory.c b/src/or/directory.c
index ebee15a034..09f3a7c83c 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -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 ||
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 33f00e8fec..b0bc210f12 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -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;
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index f39773dcb5..481c3b9ef5 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -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);
diff --git a/src/or/or.h b/src/or/or.h
index 317439dfff..dd098fa961 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -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);
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index fbb99834e8..02c6c851f2 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -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;
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 032b97f8c3..ef87caee7f 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -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)
diff --git a/src/or/test.c b/src/or/test.c
index 6cdba3b26a..96578d41cb 100644
--- a/src/or/test.c
+++ b/src/or/test.c
@@ -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);