Proposal: Download consensus documents only when it will be trusted
Peter Palfrader
peter at palfrader.org
Tue Apr 22 15:37:33 UTC 2008
On Mon, 21 Apr 2008, Peter Palfrader wrote:
> On Sun, 13 Apr 2008, Nick Mathewson wrote:
>
> > > Servers only provide consensus documents to clients when it is known that
> > > the client will trust it.
>
> Here's a first go at the server side.
Split into its own function.
diff --git a/src/or/directory.c b/src/or/directory.c
index aee76a5..ac5eb04 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -57,6 +57,7 @@ static void dir_routerdesc_download_failed(smartlist_t *failed,
int was_extrainfo,
int was_descriptor_digests);
static void note_request(const char *key, size_t bytes);
+static int client_likes_our_consensus(networkstatus_t *v, const char *want_url);
/********* START VARIABLES **********/
@@ -2163,6 +2164,52 @@ directory_dump_request_log(void)
}
#endif
+/* Decide whether a client would accept the consensus we have
+ *
+ * Clients can say they only want a consensus if it's signed by more
+ * than half the authorities in <list>. They pass this list in
+ * the url as ..consensus/<fpr>+<fpr>+<fpr>
+ * <fpr> may be an abbreviated fingerprint, i.e. only a left substring
+ * of the full authority identity digest.
+ *
+ * Returns 1 more than half of the requested authorities signed
+ * the consensus, 0 otherwise.
+ */
+int
+client_likes_our_consensus(networkstatus_t *v, const char *want_url)
+{
+ smartlist_t *want = smartlist_create();
+ smartlist_t *voterdigests = smartlist_create();
+ int need_at_least = 0;
+ int have = 0;
+
+ SMARTLIST_FOREACH(v->voters, networkstatus_voter_info_t *, vi, {
+ char *d = tor_malloc(HEX_DIGEST_LEN+1);
+ base16_encode(d, HEX_DIGEST_LEN+1, vi->identity_digest, DIGEST_LEN);
+ smartlist_add(voterdigests, d);
+ });
+
+ dir_split_resource_into_fingerprints(want_url, want, NULL, 0, 0);
+ need_at_least = smartlist_len(want)/2+1;
+ SMARTLIST_FOREACH(want, const char *, d, {
+ SMARTLIST_FOREACH(voterdigests, char *, voter, {
+ if (!strcasecmpstart(voter, d)) {
+ have++;
+ tor_free(voter);
+ SMARTLIST_DEL_CURRENT(voterdigests, voter);
+ };
+ });
+ });
+
+ SMARTLIST_FOREACH(voterdigests, char *, d, tor_free(d));
+ smartlist_free(voterdigests);
+
+ SMARTLIST_FOREACH(want, char *, d, tor_free(d));
+ smartlist_free(want);
+
+ return (have >= need_at_least);
+}
+
/** Helper function: called when a dirserver gets a complete HTTP GET
* request. Look for a request for a directory or for a rendezvous
* service descriptor. On finding one, write a response into
@@ -2290,7 +2337,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
}
if (!strcmpstart(url,"/tor/status/")
- || !strcmp(url, "/tor/status-vote/current/consensus")) {
+ || !strcmpstart(url, "/tor/status-vote/current/consensus")) {
/* v2 or v3 network status fetch. */
smartlist_t *dir_fps = smartlist_create();
int is_v3 = !strcmpstart(url, "/tor/status-vote");
@@ -2311,6 +2358,14 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
} else {
networkstatus_t *v = networkstatus_get_latest_consensus();
time_t now = time(NULL);
+ #define CONSENSUS_URL_PREFIX "/tor/status-vote/current/consensus/"
+ if (!strcmpstart(url, CONSENSUS_URL_PREFIX) &&
+ !client_likes_our_consensus(v, url + strlen(CONSENSUS_URL_PREFIX))) {
+ write_http_status_line(conn, 404, "Consensus not signed by sufficient number of requested authorities");
+ smartlist_free(dir_fps);
+ goto done;
+ }
+
smartlist_add(dir_fps, tor_memdup("\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0", 20));
request_type = compressed?"v3.z":"v3";
More information about the tor-dev
mailing list