summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Palfrader <peter@palfrader.org>2008-08-14 23:01:31 +0000
committerPeter Palfrader <peter@palfrader.org>2008-08-14 23:01:31 +0000
commit8cc3d6e22db28948ceb63f74b8f7d953553ab535 (patch)
treee58a65b70743bbbc08def925f2ba216a82fd9f46
parente27b448c578d279f3f0b2c1a29e17dcdaaff22ee (diff)
downloadtor-8cc3d6e22db28948ceb63f74b8f7d953553ab535.tar.gz
tor-8cc3d6e22db28948ceb63f74b8f7d953553ab535.zip
Add exitpolicy summaries to the consensus
svn:r16554
-rw-r--r--doc/spec/proposals/141-jit-sd-downloads.txt31
-rw-r--r--src/or/dirvote.c91
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. */