commit eb3c8d376dc240642f784830a9aec3fa95200764 Author: Nick Mathewson nickm@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); }
tor-commits@lists.torproject.org