diff options
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/buffers.c | 11 | ||||
-rw-r--r-- | src/or/channelpadding.c | 16 | ||||
-rw-r--r-- | src/or/connection_or.c | 4 | ||||
-rw-r--r-- | src/or/consdiffmgr.c | 24 | ||||
-rw-r--r-- | src/or/consdiffmgr.h | 3 | ||||
-rw-r--r-- | src/or/control.c | 2 | ||||
-rw-r--r-- | src/or/cpuworker.c | 2 | ||||
-rw-r--r-- | src/or/directory.c | 56 | ||||
-rw-r--r-- | src/or/dirserv.c | 6 | ||||
-rw-r--r-- | src/or/entrynodes.c | 36 | ||||
-rw-r--r-- | src/or/main.c | 4 |
11 files changed, 140 insertions, 24 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c index 3692ed4d08..12a6c0239b 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -2092,7 +2092,7 @@ fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len) int write_to_buf_compress(buf_t *buf, tor_compress_state_t *state, const char *data, size_t data_len, - int done) + const int done) { char *next; size_t old_avail, avail; @@ -2114,8 +2114,10 @@ write_to_buf_compress(buf_t *buf, tor_compress_state_t *state, case TOR_COMPRESS_ERROR: return -1; case TOR_COMPRESS_OK: - if (data_len == 0) + if (data_len == 0) { + tor_assert_nonfatal(!done); over = 1; + } break; case TOR_COMPRESS_BUFFER_FULL: if (avail) { @@ -2124,6 +2126,11 @@ write_to_buf_compress(buf_t *buf, tor_compress_state_t *state, * whether were going to or not. */ need_new_chunk = 1; } + if (data_len == 0 && !done) { + /* We've consumed all the input data, though, so there's no + * point in forging ahead right now. */ + over = 1; + } break; } buf->datalen += old_avail - avail; diff --git a/src/or/channelpadding.c b/src/or/channelpadding.c index f5248e8960..bed2489837 100644 --- a/src/or/channelpadding.c +++ b/src/or/channelpadding.c @@ -530,10 +530,20 @@ channelpadding_compute_time_until_pad_for_netflow(channel_t *chan) >= chan->next_padding_time_ms) { int64_t ms_until_pad_for_netflow = chan->next_padding_time_ms - long_now; + /* If the padding time is in the past, that means that libevent delayed + * calling the once-per-second callback due to other work taking too long. + * See https://bugs.torproject.org/22212 and + * https://bugs.torproject.org/16585. This is a systemic problem + * with being single-threaded, but let's emit a notice if this + * is long enough in the past that we might have missed a netflow window, + * and allowed a router to emit a netflow frame, just so we don't forget + * about it entirely.. */ +#define NETFLOW_MISSED_WINDOW (150000 - DFLT_NETFLOW_INACTIVE_KEEPALIVE_HIGH) if (ms_until_pad_for_netflow < 0) { - log_warn(LD_BUG, - "Channel padding timeout scheduled "I64_FORMAT"ms in the past. " - "Did the monotonic clock just jump?", + int severity = (ms_until_pad_for_netflow < -NETFLOW_MISSED_WINDOW) + ? LOG_NOTICE : LOG_INFO; + log_fn(severity, LD_OR, + "Channel padding timeout scheduled "I64_FORMAT"ms in the past. ", I64_PRINTF_ARG(-ms_until_pad_for_netflow)); return 0; /* Clock jumped: Send padding now */ } diff --git a/src/or/connection_or.c b/src/or/connection_or.c index ab0f411cc5..753148291c 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -420,9 +420,11 @@ cell_pack(packed_cell_t *dst, const cell_t *src, int wide_circ_ids) set_uint32(dest, htonl(src->circ_id)); dest += 4; } else { + /* Clear the last two bytes of dest, in case we can accidentally + * send them to the network somehow. */ + memset(dest+CELL_MAX_NETWORK_SIZE-2, 0, 2); set_uint16(dest, htons(src->circ_id)); dest += 2; - memset(dest+CELL_MAX_NETWORK_SIZE-2, 0, 2); /*make sure it's clear */ } set_uint8(dest, src->command); memcpy(dest+1, src->payload, CELL_PAYLOAD_SIZE); diff --git a/src/or/consdiffmgr.c b/src/or/consdiffmgr.c index 2af104733b..638fcd6794 100644 --- a/src/or/consdiffmgr.c +++ b/src/or/consdiffmgr.c @@ -325,7 +325,8 @@ cdm_diff_ht_purge(consensus_flavor_t flav, if ((*diff)->cdm_diff_status == CDM_DIFF_PRESENT && flav == (*diff)->flavor) { - if (consensus_cache_entry_handle_get((*diff)->entry) == NULL) { + if (BUG((*diff)->entry == NULL) || + consensus_cache_entry_handle_get((*diff)->entry) == NULL) { /* the underlying entry has gone away; drop this. */ next = HT_NEXT_RMV(cdm_diff_ht, &cdm_diff_ht, diff); cdm_diff_free(this); @@ -622,6 +623,9 @@ consdiffmgr_find_diff_from(consensus_cache_entry_t **entry_out, return CONSDIFF_IN_PROGRESS; } + if (BUG(ent->entry == NULL)) { + return CONSDIFF_NOT_FOUND; + } *entry_out = consensus_cache_entry_handle_get(ent->entry); return (*entry_out) ? CONSDIFF_AVAILABLE : CONSDIFF_NOT_FOUND; @@ -1840,3 +1844,21 @@ consensus_cache_entry_get_valid_until(const consensus_cache_entry_t *ent, return 0; } +/** Read the valid after timestamp from the cached object <b>ent</b> into + * *<b>out</b> 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/control.c b/src/or/control.c index 9454a7ab67..9bcf1ee364 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -6506,7 +6506,7 @@ monitor_owning_controller_process(const char *process_spec) msg); owning_controller_process_spec = NULL; tor_cleanup(); - exit(0); + exit(1); } } diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c index af79fafaa6..1013fa555e 100644 --- a/src/or/cpuworker.c +++ b/src/or/cpuworker.c @@ -475,7 +475,7 @@ queue_pending_tasks(void) return; if (assign_onionskin_to_cpuworker(circ, onionskin)) - log_warn(LD_OR,"assign_to_cpuworker failed. Ignoring."); + log_info(LD_OR,"assign_to_cpuworker failed. Ignoring."); } } diff --git a/src/or/directory.c b/src/or/directory.c index ac40e54ceb..45fbd1dd33 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -3920,6 +3920,30 @@ find_best_compression_method(unsigned compression_methods, int stream) return NO_METHOD; } +/** Check if any of the digests in <b>digests</b> matches the latest consensus + * flavor (given in <b>flavor</b>) 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. */ @@ -4089,6 +4113,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; @@ -4227,13 +4258,14 @@ static int handle_get_status_vote(dir_connection_t *conn, const get_handler_args_t *args) { const char *url = args->url; - const compress_method_t compress_method = - find_best_compression_method(args->compression_supported, 1); { int current; ssize_t body_len = 0; ssize_t estimated_len = 0; + /* This smartlist holds strings that we can compress on the fly. */ smartlist_t *items = smartlist_new(); + /* This smartlist holds cached_dir_t objects that have a precompressed + * deflated version. */ smartlist_t *dir_items = smartlist_new(); int lifetime = 60; /* XXXX?? should actually use vote intervals. */ url += strlen("/tor/status-vote/"); @@ -4284,6 +4316,26 @@ handle_get_status_vote(dir_connection_t *conn, const get_handler_args_t *args) write_http_status_line(conn, 404, "Not found"); goto vote_done; } + + /* We're sending items from at most one kind of source */ + tor_assert_nonfatal(smartlist_len(items) == 0 || + smartlist_len(dir_items) == 0); + + int streaming; + unsigned mask; + if (smartlist_len(items)) { + /* We're taking strings and compressing them on the fly. */ + streaming = 1; + mask = ~0u; + } else { + /* We're taking cached_dir_t objects. We only have them uncompressed + * or deflated. */ + streaming = 0; + mask = (1u<<NO_METHOD) | (1u<<ZLIB_METHOD); + } + const compress_method_t compress_method = find_best_compression_method( + args->compression_supported&mask, streaming); + SMARTLIST_FOREACH(dir_items, cached_dir_t *, d, body_len += compress_method != NO_METHOD ? d->dir_compressed_len : d->dir_len); diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 408f58b22b..4954471c6a 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" @@ -3518,6 +3519,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) { diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index dc2cab28f7..be9f85a89f 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -1093,6 +1093,18 @@ select_and_add_guard_item_for_sample(guard_selection_t *gs, return added_guard; } +/** Return true iff we need a consensus to maintain our */ +static int +live_consensus_is_missing(const guard_selection_t *gs) +{ + tor_assert(gs); + if (gs->type == GS_TYPE_BRIDGE) { + /* We don't update bridges from the consensus; they aren't there. */ + return 0; + } + return networkstatus_get_live_consensus(approx_time()) == NULL; +} + /** * Add new guards to the sampled guards in <b>gs</b> until there are * enough usable filtered guards, but never grow the sample beyond its @@ -1104,6 +1116,13 @@ entry_guards_expand_sample(guard_selection_t *gs) { tor_assert(gs); const or_options_t *options = get_options(); + + if (live_consensus_is_missing(gs)) { + log_info(LD_GUARD, "Not expanding the sample guard set; we have " + "no live consensus."); + return NULL; + } + int n_sampled = smartlist_len(gs->sampled_entry_guards); entry_guard_t *added_guard = NULL; int n_usable_filtered_guards = num_reachable_filtered_guards(gs, NULL); @@ -1212,18 +1231,13 @@ sampled_guards_update_from_consensus(guard_selection_t *gs) // It's important to use only a live consensus here; we don't want to // make changes based on anything expired or old. - if (gs->type != GS_TYPE_BRIDGE) { - networkstatus_t *ns = networkstatus_get_live_consensus(approx_time()); - - if (! ns) { - log_info(LD_GUARD, "No live consensus; can't update " - "sampled entry guards."); - return; - } else { - log_info(LD_GUARD, "Updating sampled guard status based on received " - "consensus."); - } + if (live_consensus_is_missing(gs)) { + log_info(LD_GUARD, "Not updating the sample guard set; we have " + "no live consensus."); + return; } + log_info(LD_GUARD, "Updating sampled guard status based on received " + "consensus."); int n_changes = 0; diff --git a/src/or/main.c b/src/or/main.c index 9699c8d381..cb24fd18c8 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1556,7 +1556,7 @@ check_ed_keys_callback(time_t now, const or_options_t *options) generate_ed_link_cert(options, now, new_signing_key > 0)) { log_err(LD_OR, "Unable to update Ed25519 keys! Exiting."); tor_cleanup(); - exit(0); + exit(1); } } return 30; @@ -3168,7 +3168,7 @@ try_locking(const or_options_t *options, int err_if_locked) r = try_locking(options, 0); if (r<0) { log_err(LD_GENERAL, "No, it's still there. Exiting."); - exit(0); + exit(1); } return r; } |