[tor-commits] [tor/master] Prop140, continued: accept "diff/<HASH>" in URLs, per proposal.

nickm at torproject.org nickm at torproject.org
Mon May 15 22:18:15 UTC 2017


commit eb3c8d376dc240642f784830a9aec3fa95200764
Author: Nick Mathewson <nickm at torproject.org>
Date:   Thu May 4 10:53:22 2017 -0400

    Prop140, continued: accept "diff/<HASH>" in URLs, per proposal.
---
 src/or/directory.c | 86 +++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 69 insertions(+), 17 deletions(-)

diff --git a/src/or/directory.c b/src/or/directory.c
index a5121eb..71ae274 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -3661,6 +3661,27 @@ warn_consensus_is_too_old(const struct consensus_cache_entry_t *consensus,
   }
 }
 
+/**
+ * Parse a single hex-encoded sha3-256 digest from <b>hex</b> into
+ * <b>digest</b>. Return 0 on success.  On failure, report that the hash came
+ * from <b>location</b>, report that we are taking <b>action</b> with it, and
+ * return -1.
+ */
+static int
+parse_one_diff_hash(uint8_t *digest, const char *hex, const char *location,
+                    const char *action)
+{
+  if (base16_decode((char*)digest, DIGEST256_LEN, hex, strlen(hex)) ==
+      DIGEST256_LEN) {
+    return 0;
+  } else {
+    log_fn(LOG_PROTOCOL_WARN, LD_DIR,
+           "%s contained bogus digest %s; %s.",
+           location, escaped(hex), action);
+    return -1;
+  }
+}
+
 /** If there is an X-Or-Diff-From-Consensus header included in <b>headers</b>,
  * set <b>digest_out<b> to a new smartlist containing every 256-bit
  * hex-encoded digest listed in that header and return 0.  Otherwise return
@@ -3678,13 +3699,9 @@ parse_or_diff_from_header(smartlist_t **digests_out, const char *headers)
                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
   SMARTLIST_FOREACH_BEGIN(hex_digests, const char *, hex) {
     uint8_t digest[DIGEST256_LEN];
-    if (base16_decode((char*)digest, sizeof(digest), hex, strlen(hex)) ==
-        DIGEST256_LEN) {
+    if (!parse_one_diff_hash(digest, hex, "X-Or-Diff-From-Consensus header",
+                             "ignoring")) {
       smartlist_add(*digests_out, tor_memdup(digest, sizeof(digest)));
-    } else {
-      log_fn(LOG_PROTOCOL_WARN, LD_DIR,
-             "X-Or-Diff-From-Consensus header contained bogus digest %s; "
-             "ignoring.", escaped(hex));
     }
   } SMARTLIST_FOREACH_END(hex);
   SMARTLIST_FOREACH(hex_digests, char *, cp, tor_free(cp));
@@ -3821,18 +3838,20 @@ handle_get_current_consensus(dir_connection_t *conn,
   long lifetime = NETWORKSTATUS_CACHE_LIFETIME;
 
   time_t now = time(NULL);
-  const char *want_fps = NULL;
+  const char *want_fps = NULL, *after_flavor = NULL;
   char *flavor = NULL;
   int flav = FLAV_NS;
-#define CONSENSUS_URL_PREFIX "/tor/status-vote/current/consensus/"
-#define CONSENSUS_FLAVORED_PREFIX "/tor/status-vote/current/consensus-"
+  const char CONSENSUS_URL_PREFIX[] = "/tor/status-vote/current/consensus/";
+  const char CONSENSUS_FLAVORED_PREFIX[] =
+    "/tor/status-vote/current/consensus-";
+
   /* figure out the flavor if any, and who we wanted to sign the thing */
   if (!strcmpstart(url, CONSENSUS_FLAVORED_PREFIX)) {
     const char *f, *cp;
     f = url + strlen(CONSENSUS_FLAVORED_PREFIX);
     cp = strchr(f, '/');
     if (cp) {
-      want_fps = cp+1;
+      after_flavor = cp+1;
       flavor = tor_strndup(f, cp-f);
     } else {
       flavor = tor_strdup(f);
@@ -3842,19 +3861,53 @@ handle_get_current_consensus(dir_connection_t *conn,
       flav = FLAV_NS;
   } else {
     if (!strcmpstart(url, CONSENSUS_URL_PREFIX))
-      want_fps = url+strlen(CONSENSUS_URL_PREFIX);
+      after_flavor = url+strlen(CONSENSUS_URL_PREFIX);
+  }
+
+  /* see whether we've been asked explicitly for a diff from an older
+   * consensus. (The user might also have said that a diff would be okay,
+   * via X-Or-Diff-From-Consensus */
+  const char DIFF_COMPONENT[] = "diff/";
+  char *diff_hash_in_url = NULL;
+  if (after_flavor && !strcmpstart(after_flavor, DIFF_COMPONENT)) {
+    after_flavor += strlen(DIFF_COMPONENT);
+    const char *cp = strchr(after_flavor, '/');
+    if (cp) {
+      diff_hash_in_url = tor_strndup(after_flavor, cp-after_flavor);
+      want_fps = cp+1;
+    } else {
+      diff_hash_in_url = tor_strdup(after_flavor);
+      want_fps = NULL;
+    }
+  } else {
+    want_fps = after_flavor;
   }
 
   struct consensus_cache_entry_t *cached_consensus = NULL;
   smartlist_t *diff_from_digests = NULL;
   compress_method_t compression_used = NO_METHOD;
-  if (!parse_or_diff_from_header(&diff_from_digests, args->headers)) {
+  if (diff_hash_in_url) {
+    uint8_t diff_from[DIGEST256_LEN];
+    diff_from_digests = smartlist_new();
+    if (!parse_one_diff_hash(diff_from, diff_hash_in_url, "URL",
+                             "rejecting")) {
+      smartlist_add(diff_from_digests, tor_memdup(diff_from, DIGEST256_LEN));
+    }
+  } else if (!parse_or_diff_from_header(&diff_from_digests, args->headers)) {
     tor_assert(diff_from_digests);
+  }
+
+  if (diff_from_digests) {
     cached_consensus = find_best_diff(diff_from_digests, flav,
                                       args->compression_supported,
                                       &compression_used);
-    SMARTLIST_FOREACH(diff_from_digests, uint8_t *, d, tor_free(d));
-    smartlist_free(diff_from_digests);
+  }
+
+  if (diff_hash_in_url && !cached_consensus) {
+    write_http_status_line(conn, 404, "No such diff available");
+    // XXXX warn_consensus_is_too_old(v, flavor, now);
+    geoip_note_ns_response(GEOIP_REJECT_NOT_FOUND);
+    goto done;
   }
 
   if (! cached_consensus) {
@@ -3877,7 +3930,6 @@ handle_get_current_consensus(dir_connection_t *conn,
     write_http_status_line(conn, 404, "Consensus is too old");
     warn_consensus_is_too_old(cached_consensus, flavor, now);
     geoip_note_ns_response(GEOIP_REJECT_NOT_FOUND);
-    tor_free(flavor);
     goto done;
   }
 
@@ -3886,7 +3938,6 @@ handle_get_current_consensus(dir_connection_t *conn,
     write_http_status_line(conn, 404, "Consensus not signed by sufficient "
                            "number of requested authorities");
     geoip_note_ns_response(GEOIP_REJECT_NOT_ENOUGH_SIGS);
-    tor_free(flavor);
     goto done;
   }
 
@@ -3898,7 +3949,6 @@ handle_get_current_consensus(dir_connection_t *conn,
       spooled = spooled_resource_new_from_cache_entry(cached_consensus);
       smartlist_add(conn->spool, spooled);
     }
-    tor_free(flavor);
   }
 
   lifetime = (have_fresh_until && fresh_until > now) ? fresh_until - now : 0;
@@ -3964,6 +4014,8 @@ handle_get_current_consensus(dir_connection_t *conn,
   goto done;
 
  done:
+  tor_free(flavor);
+  tor_free(diff_hash_in_url);
   if (clear_spool) {
     dir_conn_clear_spool(conn);
   }





More information about the tor-commits mailing list