diff options
author | Nick Mathewson <nickm@torproject.org> | 2007-09-22 06:06:05 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2007-09-22 06:06:05 +0000 |
commit | 921f9f774d4ce3ed24b48a5921fe7134dccffbb8 (patch) | |
tree | d61d5bf9cd4de80e729b334c5b146357cab81c6f | |
parent | 991ebb42de888661a47512acec02d37f1db12685 (diff) | |
download | tor-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-- | ChangeLog | 5 | ||||
-rw-r--r-- | doc/TODO | 4 | ||||
-rw-r--r-- | src/or/directory.c | 64 | ||||
-rw-r--r-- | src/or/dirserv.c | 2 | ||||
-rw-r--r-- | src/or/dirvote.c | 105 | ||||
-rw-r--r-- | src/or/or.h | 6 | ||||
-rw-r--r-- | src/or/routerlist.c | 6 | ||||
-rw-r--r-- | src/or/routerparse.c | 11 | ||||
-rw-r--r-- | src/or/test.c | 12 |
9 files changed, 186 insertions, 29 deletions
@@ -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 @@ -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); |