diff options
author | Peter Palfrader <peter@palfrader.org> | 2008-08-14 23:01:31 +0000 |
---|---|---|
committer | Peter Palfrader <peter@palfrader.org> | 2008-08-14 23:01:31 +0000 |
commit | 8cc3d6e22db28948ceb63f74b8f7d953553ab535 (patch) | |
tree | e58a65b70743bbbc08def925f2ba216a82fd9f46 | |
parent | e27b448c578d279f3f0b2c1a29e17dcdaaff22ee (diff) | |
download | tor-8cc3d6e22db28948ceb63f74b8f7d953553ab535.tar.gz tor-8cc3d6e22db28948ceb63f74b8f7d953553ab535.zip |
Add exitpolicy summaries to the consensus
svn:r16554
-rw-r--r-- | doc/spec/proposals/141-jit-sd-downloads.txt | 31 | ||||
-rw-r--r-- | src/or/dirvote.c | 91 |
2 files changed, 117 insertions, 5 deletions
diff --git a/doc/spec/proposals/141-jit-sd-downloads.txt b/doc/spec/proposals/141-jit-sd-downloads.txt index 07dea64591..b0c2b2cbcd 100644 --- a/doc/spec/proposals/141-jit-sd-downloads.txt +++ b/doc/spec/proposals/141-jit-sd-downloads.txt @@ -259,11 +259,32 @@ Status: Draft use an accept-style summary and list as much of the port list as is possible within these 1000 bytes. - Similarly to IP address, ports, and timestamp a consensus should list - the exit policy matching the descriptor digest referenced in the - consensus document (See dir-spec section 3.4). - -3.4.1 Client behaviour +3.4.1 Consensus selection + + When building a consensus, authorities have to agree on a digest of + the server descriptor to list in the router line for each router. + This is documented in dir-spec section 3.4. + + All authorities that listed that agreed upon descriptor digest in + their vote should also list the same exit policy summary - or list + none at all if the authority has not been upgraded to list that + information in their vote. + + If we have votes with matching server descriptor digest of which at + least one of them has an exit policy then we differ between two cases: + a) all authorities agree (or abstained) on the policy summary, and we + use the exit policy summary that they all listed in their vote, + b) something went wrong (or some authority is playing foul) and we + have different policy summaries. In that case we pick the one + that is most commonly listed in votes with the matching + descriptor. We break ties in favour of the lexigraphically larger + vote. + + If none one of the votes with a matching server descriptor digest has + an exit policy summary we use the most commonly listed one in all + votes, breaking ties like in case b above. + +3.4.2 Client behaviour When choosing an exit node for a specific request a Tor client will choose from the list of nodes that exit to the requested port as given diff --git a/src/or/dirvote.c b/src/or/dirvote.c index 626854fa69..88ffa62108 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -688,6 +688,7 @@ networkstatus_compute_consensus(smartlist_t *votes, smartlist_t *matching_descs = smartlist_create(); smartlist_t *chosen_flags = smartlist_create(); smartlist_t *versions = smartlist_create(); + smartlist_t *exitsummaries = smartlist_create(); uint32_t *bandwidths = tor_malloc(sizeof(uint32_t) * smartlist_len(votes)); int num_bandwidths; @@ -799,6 +800,7 @@ networkstatus_compute_consensus(smartlist_t *votes, const char *lowest_id = NULL; const char *chosen_version; const char *chosen_name = NULL; + int exitsummary_disagreement = 0; int is_named = 0, is_unnamed = 0, is_running = 0; int naming_conflict = 0; int n_listing = 0; @@ -935,6 +937,85 @@ networkstatus_compute_consensus(smartlist_t *votes, rs_out.bandwidth = median_uint32(bandwidths, num_bandwidths); } + /* Ok, we already picked a descriptor digest we want to list + * previously. Now we want to use the exit policy summary from + * that descriptor. If everybody plays nice all the voters who + * listed that descriptor will have the same summary. If not then + * something is fishy and we'll use the most common one (breaking + * ties in favor of lexigraphically larger one (only because it + * lets me reuse more existing code. + * + * The other case that can happen is that no authority that voted + * for that descriptor has an exit policy summary. That's + * probably quite unlikely but can happen. In that case we use + * the policy that was most often listed in votes, again breaking + * ties like in the previous case. + */ + if (consensus_method >= 5) { + /* Okay, go through all the votes for this router. We prepared + * that list previously */ + const char *chosen_exitsummary = NULL; + smartlist_clear(exitsummaries); + SMARTLIST_FOREACH(matching_descs, vote_routerstatus_t *, vsr, { + /* Check if the vote where this status comes from had the + * proper descriptor */ + tor_assert(!memcmp(rs_out.identity_digest, vsr->status.identity_digest, DIGEST_LEN)); + if (vsr->status.has_exitsummary && + !memcmp(rs_out.descriptor_digest, vsr->status.descriptor_digest, DIGEST_LEN)) { + tor_assert(vsr->status.exitsummary); + smartlist_add(exitsummaries, vsr->status.exitsummary); + if (!chosen_exitsummary) { + chosen_exitsummary = vsr->status.exitsummary; + } else if (strcmp(chosen_exitsummary, vsr->status.exitsummary)) { + /* Great. There's disagreement among the voters. That + * really shouldn't be */ + exitsummary_disagreement = 1; + } + } + }); + + if (exitsummary_disagreement) { + char id[HEX_DIGEST_LEN+1]; + char dd[HEX_DIGEST_LEN+1]; + base16_encode(id, sizeof(dd), rs_out.identity_digest, DIGEST_LEN); + base16_encode(dd, sizeof(dd), rs_out.descriptor_digest, DIGEST_LEN); + log_warn(LD_DIR, "The voters disgreed on the exit policy summary for" + " router %s with descriptor %s. This really shouldn't" + " have happened.", id, dd); + + smartlist_sort_strings(exitsummaries); + chosen_exitsummary = get_most_frequent_member(exitsummaries); + } else if (!chosen_exitsummary) { + char id[HEX_DIGEST_LEN+1]; + char dd[HEX_DIGEST_LEN+1]; + base16_encode(id, sizeof(dd), rs_out.identity_digest, DIGEST_LEN); + base16_encode(dd, sizeof(dd), rs_out.descriptor_digest, DIGEST_LEN); + log_warn(LD_DIR, "Not one of the voters that made us select" + "descriptor %s for router %s had an exit policy" + "summary", dd, id); + + /* Ok, none of those voting for the digest we chose had an + * exit policy for us. Well, that kinda sucks. + */ + smartlist_clear(exitsummaries); + SMARTLIST_FOREACH(matching_descs, vote_routerstatus_t *, vsr, { + if (vsr->status.has_exitsummary) + smartlist_add(exitsummaries, vsr->status.exitsummary); + }); + smartlist_sort_strings(exitsummaries); + chosen_exitsummary = get_most_frequent_member(exitsummaries); + + if (!chosen_exitsummary) + log_warn(LD_DIR, "Wow, not one of the voters had an exit " + "policy summary for %s. Wow.", id); + } + + if (chosen_exitsummary) { + rs_out.has_exitsummary = 1; + rs_out.exitsummary = (char *)chosen_exitsummary; /* yea, discards the const */ + } + } + /* Okay!! Now we can write the descriptor... */ /* First line goes into "buf". */ routerstatus_format_entry(buf, sizeof(buf), &rs_out, NULL, 1, 0); @@ -957,6 +1038,15 @@ networkstatus_compute_consensus(smartlist_t *votes, } smartlist_add(chunks, tor_strdup(buf)); }; + /* Now the exitpolicy summary line. */ + if (rs_out.has_exitsummary) { + int r = tor_snprintf(buf, sizeof(buf), "p %s\n", rs_out.exitsummary); + if (r<0) { + log_warn(LD_BUG, "Not enough space in buffer for exitpolicy line."); + *buf = '\0'; + } + smartlist_add(chunks, tor_strdup(buf)); + }; /* And the loop is over and we move on to the next router */ } @@ -975,6 +1065,7 @@ networkstatus_compute_consensus(smartlist_t *votes, smartlist_free(matching_descs); smartlist_free(chosen_flags); smartlist_free(versions); + smartlist_free(exitsummaries); } /* Add a signature. */ |