diff --git a/changes/bug22702 b/changes/bug22702 new file mode 100644 index 0000000000..a2044c70bf --- /dev/null +++ b/changes/bug22702 @@ -0,0 +1,5 @@ + o Major bugfixes (directory protocol): + - Ensure that we sent "304 Not modified" as HTTP status code when a + client is attempting to fetch a consensus or consensus diff that + matches the latest consensus we have available. Fixes bug 22702; + bugfix on 0.3.1.1-alpha. diff --git a/src/or/consdiffmgr.c b/src/or/consdiffmgr.c index 2af104733b..4036f665f9 100644 --- a/src/or/consdiffmgr.c +++ b/src/or/consdiffmgr.c @@ -1840,3 +1840,21 @@ consensus_cache_entry_get_valid_until(const consensus_cache_entry_t *ent, return 0; } +/** Read the valid after timestamp from the cached object ent into + * *out and return 0, or return -1 if no such time was recorded. */ +int +consensus_cache_entry_get_valid_after(const consensus_cache_entry_t *ent, + time_t *out) +{ + tor_assert(ent); + tor_assert(out); + + const char *s; + s = consensus_cache_entry_get_value(ent, LABEL_VALID_AFTER); + + if (s == NULL || parse_iso_time_nospace(s, out) < 0) + return -1; + else + return 0; +} + diff --git a/src/or/consdiffmgr.h b/src/or/consdiffmgr.h index fe4f9ee239..079f9fe2d2 100644 --- a/src/or/consdiffmgr.h +++ b/src/or/consdiffmgr.h @@ -44,6 +44,9 @@ int consensus_cache_entry_get_fresh_until( int consensus_cache_entry_get_valid_until( const struct consensus_cache_entry_t *ent, time_t *out); +int consensus_cache_entry_get_valid_after( + const struct consensus_cache_entry_t *ent, + time_t *out); void consdiffmgr_rescan(void); int consdiffmgr_cleanup(void); diff --git a/src/or/directory.c b/src/or/directory.c index 5e8e6638b6..c6963fe00e 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -3883,6 +3883,30 @@ find_best_compression_method(unsigned compression_methods, int stream) return NO_METHOD; } +/** Check if any of the digests in digests matches the latest consensus + * flavor (given in flavor) that we have available. */ +static int +digest_list_contains_best_consensus(consensus_flavor_t flavor, + const smartlist_t *digests) +{ + const networkstatus_t *ns = NULL; + + if (digests == NULL) + return 0; + + ns = networkstatus_get_latest_consensus_by_flavor(flavor); + + if (ns == NULL) + return 0; + + SMARTLIST_FOREACH_BEGIN(digests, const uint8_t *, digest) { + if (tor_memeq(ns->digest_sha3_as_signed, digest, DIGEST256_LEN)) + return 1; + } SMARTLIST_FOREACH_END(digest); + + return 0; +} + /** Check if the given compression method is allowed for a connection that is * supposed to be anonymous. Returns 1 if the compression method is allowed, * otherwise 0. */ @@ -4052,6 +4076,13 @@ handle_get_current_consensus(dir_connection_t *conn, goto done; } + if (digest_list_contains_best_consensus(req.flav, + req.diff_from_digests)) { + write_http_status_line(conn, 304, "Not modified"); + geoip_note_ns_response(GEOIP_REJECT_NOT_MODIFIED); + goto done; + } + struct consensus_cache_entry_t *cached_consensus = NULL; compress_method_t compression_used = NO_METHOD; diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 75af7ff674..75a245e07a 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -14,6 +14,7 @@ #include "connection.h" #include "connection_or.h" #include "conscache.h" +#include "consdiffmgr.h" #include "control.h" #include "directory.h" #include "dirserv.h" @@ -3530,6 +3531,11 @@ spooled_resource_estimate_size(const spooled_resource_t *spooled, } else { cached_dir_t *cached; if (spooled->consensus_cache_entry) { + if (published_out) { + consensus_cache_entry_get_valid_after( + spooled->consensus_cache_entry, published_out); + } + return spooled->cce_len; } if (spooled->cached_dir_ref) {