diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index 2eb3cd83cf..6c92773a7a 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1552,6 +1552,31 @@ networkstatus_set_current_consensus_from_ns(networkstatus_t *c, } #endif //TOR_UNIT_TESTS +/** Called when we have received a networkstatus c. If there are + * any _required_ protocols we are missing, log an error and exit + * immediately. If there are any _recommended_ protocols we are missing, + * warn. */ +static void +handle_missing_protocol_warning(const networkstatus_t *c, + const or_options_t *options) +{ + char *protocol_warning = NULL; + int should_exit = networkstatus_check_required_protocols(c, + !server_mode(options), + &protocol_warning); + if (protocol_warning) { + tor_log(should_exit ? LOG_ERR : LOG_WARN, + LD_GENERAL, + "%s", protocol_warning); + } + if (should_exit) { + tor_assert_nonfatal(protocol_warning); + } + tor_free(protocol_warning); + if (should_exit) + exit(1); +} + /** Try to replace the current cached v3 networkstatus with the one in * consensus. If we don't have enough certificates to validate it, * store it in consensus_waiting_for_certs and launch a certificate fetch. @@ -1595,6 +1620,7 @@ networkstatus_set_current_consensus(const char *consensus, time_t current_valid_after = 0; int free_consensus = 1; /* Free 'c' at the end of the function */ int old_ewma_enabled; + int checked_protocols_already = 0; if (flav < 0) { /* XXXX we don't handle unrecognized flavors yet. */ @@ -1610,6 +1636,16 @@ networkstatus_set_current_consensus(const char *consensus, goto done; } + if (from_cache && !was_waiting_for_certs) { + /* We previously stored this; check _now_ to make sure that version-kills + * really work. This happens even before we check signatures: we did so + * before when we stored this to disk. This does mean an attacker who can + * write to the datadir can make us not start: such an attacker could + * already harm us by replacing our guards, which would be worse. */ + checked_protocols_already = 1; + handle_missing_protocol_warning(c, options); + } + if ((int)c->flavor != flav) { /* This wasn't the flavor we thought we were getting. */ if (require_flavor) { @@ -1735,6 +1771,10 @@ networkstatus_set_current_consensus(const char *consensus, if (!from_cache && flav == usable_consensus_flavor()) control_event_client_status(LOG_NOTICE, "CONSENSUS_ARRIVED"); + if (!checked_protocols_already) { + handle_missing_protocol_warning(c, options); + } + /* Are we missing any certificates at all? */ if (r != 1 && dl_certs) authority_certs_fetch_missing(c, now, source_dir);