mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
Add exitpolicy summaries to the consensus
svn:r16554
This commit is contained in:
@@ -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 Consensus selection
|
||||
|
||||
3.4.1 Client behaviour
|
||||
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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user