Proposal: Download consensus documents only when it will be trusted

Peter Palfrader peter at palfrader.org
Mon Apr 21 20:24:41 UTC 2008


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.


diff --git a/src/or/directory.c b/src/or/directory.c
index aee76a5..b2fe369 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -2290,7 +2290,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 +2311,52 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
     } else {
       networkstatus_t *v = networkstatus_get_latest_consensus();
       time_t now = time(NULL);
+      /* 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.
+       */
+      #define CONSENSUS_URL_PREFIX "/tor/status-vote/current/consensus/"
+      int signer_list = !strcmpstart(url, CONSENSUS_URL_PREFIX);
+      if (signer_list) {
+        const char *want_url = url + strlen(CONSENSUS_URL_PREFIX);
+        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);
+
+        if (have < need_at_least) {
+          write_http_status_line(conn, 404, "No consensus 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";


Should we keep the list of encoded hexdigests around all the time?  Or
should we not compare the hex encoded strings but instead the binary
representation?

And why is there no function/macro that combines individual items being
freed and then freeing the smartlist?  That seems to be needed quite
often.

Peter



More information about the tor-dev mailing list