diff options
author | Roger Dingledine <arma@torproject.org> | 2013-04-11 01:29:24 -0400 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2013-04-11 01:29:24 -0400 |
commit | 887eba98950f2974bd2031510e1ece2279a4f106 (patch) | |
tree | 0bda88092333a1aa21925033596f395df4e3d4b1 /src/or | |
parent | fcd9248387249d68619734a73860ffaab12b021b (diff) | |
parent | 6acf0ac2851fb95953edea9c231d82f487f28c3d (diff) | |
download | tor-887eba98950f2974bd2031510e1ece2279a4f106.tar.gz tor-887eba98950f2974bd2031510e1ece2279a4f106.zip |
Merge branch 'maint-0.2.4' into release-0.2.4
Diffstat (limited to 'src/or')
45 files changed, 895 insertions, 332 deletions
diff --git a/src/or/addressmap.c b/src/or/addressmap.c index 826eb301db..79e4b7c5e2 100644 --- a/src/or/addressmap.c +++ b/src/or/addressmap.c @@ -560,7 +560,7 @@ addressmap_register(const char *address, char *new_address, time_t expires, log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'", safe_str_client(address), safe_str_client(ent->new_address)); - control_event_address_mapped(address, ent->new_address, expires, NULL); + control_event_address_mapped(address, ent->new_address, expires, NULL, 1); } /** An attempt to resolve <b>address</b> failed at some OR. diff --git a/src/or/channel.c b/src/or/channel.c index 82db061af9..4e9086f2e6 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -1751,6 +1751,14 @@ channel_write_cell(channel_t *chan, cell_t *cell) tor_assert(chan); tor_assert(cell); + if (chan->state == CHANNEL_STATE_CLOSING) { + log_debug(LD_CHANNEL, "Discarding cell_t %p on closing channel %p with " + "global ID "U64_FORMAT, cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + tor_free(cell); + return; + } + log_debug(LD_CHANNEL, "Writing cell_t %p to channel %p with global ID " U64_FORMAT, @@ -1777,6 +1785,14 @@ channel_write_packed_cell(channel_t *chan, packed_cell_t *packed_cell) tor_assert(chan); tor_assert(packed_cell); + if (chan->state == CHANNEL_STATE_CLOSING) { + log_debug(LD_CHANNEL, "Discarding packed_cell_t %p on closing channel %p " + "with global ID "U64_FORMAT, packed_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + packed_cell_free(packed_cell); + return; + } + log_debug(LD_CHANNEL, "Writing packed_cell_t %p to channel %p with global ID " U64_FORMAT, @@ -1805,6 +1821,14 @@ channel_write_var_cell(channel_t *chan, var_cell_t *var_cell) tor_assert(chan); tor_assert(var_cell); + if (chan->state == CHANNEL_STATE_CLOSING) { + log_debug(LD_CHANNEL, "Discarding var_cell_t %p on closing channel %p " + "with global ID "U64_FORMAT, var_cell, chan, + U64_PRINTF_ARG(chan->global_identifier)); + var_cell_free(var_cell); + return; + } + log_debug(LD_CHANNEL, "Writing var_cell_t %p to channel %p with global ID " U64_FORMAT, diff --git a/src/or/channeltls.c b/src/or/channeltls.c index 1035a14127..60693daeb2 100644 --- a/src/or/channeltls.c +++ b/src/or/channeltls.c @@ -1208,7 +1208,7 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan) tor_assert(chan->conn->handshake_state); end = cell->payload + cell->payload_len; - for (cp = cell->payload; cp+1 < end; ++cp) { + for (cp = cell->payload; cp+1 < end; cp += 2) { uint16_t v = ntohs(get_uint16(cp)); if (is_or_protocol_version_known(v) && v > highest_supported_version) highest_supported_version = v; diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index fbe94a98ba..31242f6c14 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -803,6 +803,10 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_STATUS, 0); } + pathbias_count_build_success(circ); + circuit_rep_hist_note_result(circ); + circuit_has_opened(circ); /* do other actions as necessary */ + if (!can_complete_circuit && !circ->build_state->onehop_tunnel) { const or_options_t *options = get_options(); can_complete_circuit=1; @@ -819,10 +823,6 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) } } - pathbias_count_build_success(circ); - circuit_rep_hist_note_result(circ); - circuit_has_opened(circ); /* do other actions as necessary */ - /* We're done with measurement circuits here. Just close them */ if (circ->base_.purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED); @@ -901,7 +901,7 @@ circuit_note_clock_jumped(int seconds_elapsed) control_event_client_status(severity, "CIRCUIT_NOT_ESTABLISHED REASON=%s", "CLOCK_JUMPED"); circuit_mark_all_unused_circs(); - circuit_expire_all_dirty_circs(); + circuit_mark_all_dirty_circs_as_unusable(); } /** Take the 'extend' <b>cell</b>, pull out addr/port plus the onion @@ -1378,7 +1378,7 @@ pathbias_should_count(origin_circuit_t *circ) if (circ->build_state->desired_path_len != 1 || !circ->build_state->onehop_tunnel) { if ((rate_msg = rate_limit_log(&count_limit, approx_time()))) { - log_notice(LD_BUG, + log_info(LD_BUG, "One-hop circuit has length %d. Path state is %s. " "Circuit is a %s currently %s.%s", circ->build_state->desired_path_len, @@ -1539,7 +1539,7 @@ pathbias_count_build_success(origin_circuit_t *circ) guard->circ_successes++; entry_guards_changed(); - log_info(LD_CIRC, "Got success count %f/%f for guard %s=%s", + log_info(LD_CIRC, "Got success count %f/%f for guard %s ($%s)", guard->circ_successes, guard->circ_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); } else { @@ -1558,7 +1558,7 @@ pathbias_count_build_success(origin_circuit_t *circ) if (guard->circ_attempts < guard->circ_successes) { log_notice(LD_BUG, "Unexpectedly high successes counts (%f/%f) " - "for guard %s=%s", + "for guard %s ($%s)", guard->circ_successes, guard->circ_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); } @@ -1626,7 +1626,7 @@ pathbias_count_use_attempt(origin_circuit_t *circ) entry_guards_changed(); log_debug(LD_CIRC, - "Marked circuit %d (%f/%f) as used for guard %s=%s.", + "Marked circuit %d (%f/%f) as used for guard %s ($%s).", circ->global_identifier, guard->use_successes, guard->use_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); @@ -1734,9 +1734,16 @@ pathbias_count_use_success(origin_circuit_t *circ) guard->use_successes++; entry_guards_changed(); + if (guard->use_attempts < guard->use_successes) { + log_notice(LD_BUG, "Unexpectedly high use successes counts (%f/%f) " + "for guard %s=%s", + guard->use_successes, guard->use_attempts, + guard->nickname, hex_str(guard->identity, DIGEST_LEN)); + } + log_debug(LD_CIRC, "Marked circuit %d (%f/%f) as used successfully for guard " - "%s=%s.", + "%s ($%s).", circ->global_identifier, guard->use_successes, guard->use_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); @@ -2010,6 +2017,9 @@ pathbias_check_close(origin_circuit_t *ocirc, int reason) pathbias_count_use_failed(ocirc); break; + case PATH_STATE_NEW_CIRC: + case PATH_STATE_BUILD_ATTEMPTED: + case PATH_STATE_ALREADY_COUNTED: default: // Other states are uninteresting. No stats to count. break; @@ -2253,7 +2263,7 @@ pathbias_measure_use_rate(entry_guard_t *guard) if (pathbias_get_dropguards(options)) { if (!guard->path_bias_disabled) { log_warn(LD_CIRC, - "Your Guard %s=%s is failing to carry an extremely large " + "Your Guard %s ($%s) is failing to carry an extremely large " "amount of stream on its circuits. " "To avoid potential route manipulation attacks, Tor has " "disabled use of this guard. " @@ -2279,7 +2289,7 @@ pathbias_measure_use_rate(entry_guard_t *guard) } else if (!guard->path_bias_use_extreme) { guard->path_bias_use_extreme = 1; log_warn(LD_CIRC, - "Your Guard %s=%s is failing to carry an extremely large " + "Your Guard %s ($%s) is failing to carry an extremely large " "amount of streams on its circuits. " "This could indicate a route manipulation attack, network " "overload, bad local network connectivity, or a bug. " @@ -2303,7 +2313,7 @@ pathbias_measure_use_rate(entry_guard_t *guard) if (!guard->path_bias_use_noticed) { guard->path_bias_use_noticed = 1; log_notice(LD_CIRC, - "Your Guard %s=%s is failing to carry more streams on its " + "Your Guard %s ($%s) is failing to carry more streams on its " "circuits than usual. " "Most likely this means the Tor network is overloaded " "or your network connection is poor. " @@ -2359,7 +2369,7 @@ pathbias_measure_close_rate(entry_guard_t *guard) if (pathbias_get_dropguards(options)) { if (!guard->path_bias_disabled) { log_warn(LD_CIRC, - "Your Guard %s=%s is failing an extremely large " + "Your Guard %s ($%s) is failing an extremely large " "amount of circuits. " "To avoid potential route manipulation attacks, Tor has " "disabled use of this guard. " @@ -2385,7 +2395,7 @@ pathbias_measure_close_rate(entry_guard_t *guard) } else if (!guard->path_bias_extreme) { guard->path_bias_extreme = 1; log_warn(LD_CIRC, - "Your Guard %s=%s is failing an extremely large " + "Your Guard %s ($%s) is failing an extremely large " "amount of circuits. " "This could indicate a route manipulation attack, " "extreme network overload, or a bug. " @@ -2409,7 +2419,7 @@ pathbias_measure_close_rate(entry_guard_t *guard) if (!guard->path_bias_warned) { guard->path_bias_warned = 1; log_warn(LD_CIRC, - "Your Guard %s=%s is failing a very large " + "Your Guard %s ($%s) is failing a very large " "amount of circuits. " "Most likely this means the Tor network is " "overloaded, but it could also mean an attack against " @@ -2434,7 +2444,7 @@ pathbias_measure_close_rate(entry_guard_t *guard) if (!guard->path_bias_noticed) { guard->path_bias_noticed = 1; log_notice(LD_CIRC, - "Your Guard %s=%s is failing more circuits than " + "Your Guard %s ($%s) is failing more circuits than " "usual. " "Most likely this means the Tor network is overloaded. " "Success counts are %ld/%ld. Use counts are %ld/%ld. " @@ -2478,6 +2488,9 @@ pathbias_scale_close_rates(entry_guard_t *guard) int opened_built = pathbias_count_circs_in_states(guard, PATH_STATE_BUILD_SUCCEEDED, PATH_STATE_USE_FAILED); + /* Verify that the counts are sane before and after scaling */ + int counts_are_sane = (guard->circ_attempts >= guard->circ_successes); + guard->circ_attempts -= opened_attempts; guard->circ_successes -= opened_built; @@ -2495,10 +2508,20 @@ pathbias_scale_close_rates(entry_guard_t *guard) log_info(LD_CIRC, "Scaled pathbias counts to (%f,%f)/%f (%d/%d open) for guard " - "%s=%s", + "%s ($%s)", guard->circ_successes, guard->successful_circuits_closed, guard->circ_attempts, opened_built, opened_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); + + /* Have the counts just become invalid by this scaling attempt? */ + if (counts_are_sane && guard->circ_attempts < guard->circ_successes) { + log_notice(LD_BUG, + "Scaling has mangled pathbias counts to %f/%f (%d/%d open) " + "for guard %s ($%s)", + guard->circ_successes, guard->circ_attempts, opened_built, + opened_attempts, guard->nickname, + hex_str(guard->identity, DIGEST_LEN)); + } } } @@ -2521,6 +2544,9 @@ pathbias_scale_use_rates(entry_guard_t *guard) double scale_ratio = pathbias_get_scale_ratio(options); int opened_attempts = pathbias_count_circs_in_states(guard, PATH_STATE_USE_ATTEMPTED, PATH_STATE_USE_SUCCEEDED); + /* Verify that the counts are sane before and after scaling */ + int counts_are_sane = (guard->use_attempts >= guard->use_successes); + guard->use_attempts -= opened_attempts; guard->use_attempts *= scale_ratio; @@ -2529,9 +2555,20 @@ pathbias_scale_use_rates(entry_guard_t *guard) guard->use_attempts += opened_attempts; log_info(LD_CIRC, - "Scaled pathbias use counts to %f/%f (%d open) for guard %s=%s", - guard->use_successes, guard->use_attempts, opened_attempts, - guard->nickname, hex_str(guard->identity, DIGEST_LEN)); + "Scaled pathbias use counts to %f/%f (%d open) for guard %s ($%s)", + guard->use_successes, guard->use_attempts, opened_attempts, + guard->nickname, hex_str(guard->identity, DIGEST_LEN)); + + /* Have the counts just become invalid by this scaling attempt? */ + if (counts_are_sane && guard->use_attempts < guard->use_successes) { + log_notice(LD_BUG, + "Scaling has mangled pathbias usage counts to %f/%f " + "(%d open) for guard %s ($%s)", + guard->circ_successes, guard->circ_attempts, + opened_attempts, guard->nickname, + hex_str(guard->identity, DIGEST_LEN)); + } + entry_guards_changed(); } } @@ -2554,7 +2591,7 @@ entry_guard_inc_circ_attempt_count(entry_guard_t *guard) pathbias_scale_close_rates(guard); guard->circ_attempts++; - log_info(LD_CIRC, "Got success count %f/%f for guard %s=%s", + log_info(LD_CIRC, "Got success count %f/%f for guard %s ($%s)", guard->circ_successes, guard->circ_attempts, guard->nickname, hex_str(guard->identity, DIGEST_LEN)); return 0; @@ -3398,6 +3435,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state) }); } /* and exclude current entry guards and their families, if applicable */ + /*XXXX025 use the using_as_guard flag to accomplish this.*/ if (options->UseEntryGuards) { SMARTLIST_FOREACH(get_entry_guards(), const entry_guard_t *, entry, { diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 17e18c7603..1903fbe2eb 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -24,6 +24,7 @@ #include "nodelist.h" #include "onion.h" #include "onion_fast.h" +#include "policies.h" #include "relay.h" #include "rendclient.h" #include "rendcommon.h" @@ -531,6 +532,9 @@ circuit_purpose_to_string(uint8_t purpose) case CIRCUIT_PURPOSE_CONTROLLER: return "Circuit made by controller"; + case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: + return "Path-bias testing circuit"; + default: tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); return buf; @@ -653,6 +657,7 @@ circuit_free(circuit_t *circ) memwipe(ocirc->socks_password, 0x06, ocirc->socks_password_len); tor_free(ocirc->socks_password); } + addr_policy_list_free(ocirc->prepend_policy); } else { or_circuit_t *ocirc = TO_OR_CIRCUIT(circ); /* Remember cell statistics for this circuit before deallocating. */ @@ -1204,6 +1209,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, if ((!need_uptime || circ->build_state->need_uptime) && (!need_capacity || circ->build_state->need_capacity) && (internal == circ->build_state->is_internal) && + !circ->unusable_for_new_conns && circ->remaining_relay_early_cells && circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN && !circ->build_state->onehop_tunnel && @@ -1299,20 +1305,17 @@ circuit_mark_all_unused_circs(void) * This is useful for letting the user change pseudonyms, so new * streams will not be linkable to old streams. */ -/* XXX024 this is a bad name for what this function does */ void -circuit_expire_all_dirty_circs(void) +circuit_mark_all_dirty_circs_as_unusable(void) { circuit_t *circ; - const or_options_t *options = get_options(); for (circ=global_circuitlist; circ; circ = circ->next) { if (CIRCUIT_IS_ORIGIN(circ) && !circ->marked_for_close && - circ->timestamp_dirty) - /* XXXX024 This is a screwed-up way to say "This is too dirty - * for new circuits. */ - circ->timestamp_dirty -= options->MaxCircuitDirtiness; + circ->timestamp_dirty) { + mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ)); + } } } diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h index e81c0785fe..d67f80b065 100644 --- a/src/or/circuitlist.h +++ b/src/or/circuitlist.h @@ -46,7 +46,7 @@ or_circuit_t *circuit_get_intro_point(const char *digest); origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, int flags); void circuit_mark_all_unused_circs(void); -void circuit_expire_all_dirty_circs(void); +void circuit_mark_all_dirty_circs_as_unusable(void); void circuit_mark_for_close_(circuit_t *circ, int reason, int line, const char *file); int circuit_get_cpath_len(origin_circuit_t *circ); diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c index 73e34d9ed7..1d7812bf2b 100644 --- a/src/or/circuitstats.c +++ b/src/or/circuitstats.c @@ -417,19 +417,16 @@ circuit_build_times_get_initial_timeout(void) * Check if we have LearnCircuitBuildTimeout, and if we don't, * always use CircuitBuildTimeout, no questions asked. */ - if (get_options()->LearnCircuitBuildTimeout) { - if (!unit_tests && get_options()->CircuitBuildTimeout) { - timeout = get_options()->CircuitBuildTimeout*1000; - if (timeout < circuit_build_times_min_timeout()) { - log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds", - circuit_build_times_min_timeout()/1000); - timeout = circuit_build_times_min_timeout(); - } - } else { - timeout = circuit_build_times_initial_timeout(); + if (!unit_tests && get_options()->CircuitBuildTimeout) { + timeout = get_options()->CircuitBuildTimeout*1000; + if (get_options()->LearnCircuitBuildTimeout && + timeout < circuit_build_times_min_timeout()) { + log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds", + circuit_build_times_min_timeout()/1000); + timeout = circuit_build_times_min_timeout(); } } else { - timeout = get_options()->CircuitBuildTimeout*1000; + timeout = circuit_build_times_initial_timeout(); } return timeout; @@ -1235,11 +1232,11 @@ circuit_build_times_network_close(circuit_build_times_t *cbt, format_local_iso_time(last_live_buf, cbt->liveness.network_last_live); format_local_iso_time(start_time_buf, start_time); format_local_iso_time(now_buf, now); - log_warn(LD_BUG, - "Circuit somehow completed a hop while the network was " - "not live. Network was last live at %s, but circuit launched " - "at %s. It's now %s.", last_live_buf, start_time_buf, - now_buf); + log_notice(LD_CIRC, + "A circuit somehow completed a hop while the network was " + "not live. The network was last live at %s, but the circuit " + "launched at %s. It's now %s. This could mean your clock " + "changed.", last_live_buf, start_time_buf, now_buf); } cbt->liveness.nonlive_timeouts++; if (cbt->liveness.nonlive_timeouts == 1) { diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 51d8716faa..8fb70f5853 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -85,10 +85,14 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, } if (purpose == CIRCUIT_PURPOSE_C_GENERAL || - purpose == CIRCUIT_PURPOSE_C_REND_JOINED) + purpose == CIRCUIT_PURPOSE_C_REND_JOINED) { if (circ->timestamp_dirty && circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now) return 0; + } + + if (origin_circ->unusable_for_new_conns) + return 0; /* decide if this circ is suitable for this conn */ @@ -105,6 +109,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, return 0; if (purpose == CIRCUIT_PURPOSE_C_GENERAL) { + tor_addr_t addr; + const int family = tor_addr_parse(&addr, conn->socks_request->address); if (!exitnode && !build_state->onehop_tunnel) { log_debug(LD_CIRC,"Not considering circuit with unknown router."); return 0; /* this circuit is screwed and doesn't know it yet, @@ -125,9 +131,7 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, return 0; /* this is a circuit to somewhere else */ if (tor_digest_is_zero(digest)) { /* we don't know the digest; have to compare addr:port */ - tor_addr_t addr; - int r = tor_addr_parse(&addr, conn->socks_request->address); - if (r < 0 || + if (family < 0 || !tor_addr_eq(&build_state->chosen_exit->addr, &addr) || build_state->chosen_exit->port != conn->socks_request->port) return 0; @@ -139,6 +143,13 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, return 0; } } + if (origin_circ->prepend_policy && family != -1) { + int r = compare_tor_addr_to_addr_policy(&addr, + conn->socks_request->port, + origin_circ->prepend_policy); + if (r == ADDR_POLICY_REJECTED) + return 0; + } if (exitnode && !connection_ap_can_use_exit(conn, exitnode)) { /* can't exit from this router */ return 0; @@ -518,15 +529,25 @@ circuit_expire_building(void) if (timercmp(&victim->timestamp_began, &cutoff, >)) continue; /* it's still young, leave it alone */ - if (!any_opened_circs) { + /* We need to double-check the opened state here because + * we don't want to consider opened 1-hop dircon circuits for + * deciding when to relax the timeout, but we *do* want to relax + * those circuits too if nothing else is opened *and* they still + * aren't either. */ + if (!any_opened_circs && victim->state != CIRCUIT_STATE_OPEN) { /* It's still young enough that we wouldn't close it, right? */ if (timercmp(&victim->timestamp_began, &close_cutoff, >)) { if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) { int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath->state == CPATH_STATE_OPEN; log_info(LD_CIRC, - "No circuits are opened. Relaxing timeout for " - "a circuit with channel state %s. %d guards are live.", + "No circuits are opened. Relaxing timeout for circuit %d " + "(a %s %d-hop circuit in state %s with channel state %s). " + "%d guards are live.", + TO_ORIGIN_CIRCUIT(victim)->global_identifier, + circuit_purpose_to_string(victim->purpose), + TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len, + circuit_state_to_string(victim->state), channel_state_to_string(victim->n_chan->state), num_live_entry_guards(0)); @@ -541,10 +562,14 @@ circuit_expire_building(void) } else { static ratelim_t relax_timeout_limit = RATELIM_INIT(3600); log_fn_ratelim(&relax_timeout_limit, LOG_NOTICE, LD_CIRC, - "No circuits are opened. Relaxed timeout for " - "a circuit with channel state %s to %ldms. " - "However, it appears the circuit has timed out anyway. " - "%d guards are live.", + "No circuits are opened. Relaxed timeout for circuit %d " + "(a %s %d-hop circuit in state %s with channel state %s) to " + "%ldms. However, it appears the circuit has timed out " + "anyway. %d guards are live.", + TO_ORIGIN_CIRCUIT(victim)->global_identifier, + circuit_purpose_to_string(victim->purpose), + TO_ORIGIN_CIRCUIT(victim)->build_state->desired_path_len, + circuit_state_to_string(victim->state), channel_state_to_string(victim->n_chan->state), (long)circ_times.close_ms, num_live_entry_guards(0)); } @@ -660,7 +685,7 @@ circuit_expire_building(void) circuit_purpose_to_string(victim->purpose)); } else if (circuit_build_times_count_close(&circ_times, first_hop_succeeded, - victim->timestamp_began.tv_sec)) { + victim->timestamp_created.tv_sec)) { circuit_build_times_set_timeout(&circ_times); } } @@ -799,9 +824,12 @@ circuit_stream_is_being_handled(entry_connection_t *conn, circ->purpose == CIRCUIT_PURPOSE_C_GENERAL && (!circ->timestamp_dirty || circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) { - cpath_build_state_t *build_state = TO_ORIGIN_CIRCUIT(circ)->build_state; + origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); + cpath_build_state_t *build_state = origin_circ->build_state; if (build_state->is_internal || build_state->onehop_tunnel) continue; + if (!origin_circ->unusable_for_new_conns) + continue; exitnode = build_state_get_exit_node(build_state); if (exitnode && (!need_uptime || build_state->need_uptime)) { @@ -843,6 +871,7 @@ circuit_predict_and_launch_new(void) /* First, count how many of each type of circuit we have already. */ for (circ=global_circuitlist;circ;circ = circ->next) { cpath_build_state_t *build_state; + origin_circuit_t *origin_circ; if (!CIRCUIT_IS_ORIGIN(circ)) continue; if (circ->marked_for_close) @@ -851,7 +880,10 @@ circuit_predict_and_launch_new(void) continue; /* only count clean circs */ if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL) continue; /* only pay attention to general-purpose circs */ - build_state = TO_ORIGIN_CIRCUIT(circ)->build_state; + origin_circ = TO_ORIGIN_CIRCUIT(circ); + if (origin_circ->unusable_for_new_conns) + continue; + build_state = origin_circ->build_state; if (build_state->onehop_tunnel) continue; num++; @@ -2275,3 +2307,23 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose) } } +/** Mark <b>circ</b> so that no more connections can be attached to it. */ +void +mark_circuit_unusable_for_new_conns(origin_circuit_t *circ) +{ + const or_options_t *options = get_options(); + tor_assert(circ); + + /* XXXX025 This is a kludge; we're only keeping it around in case there's + * something that doesn't check unusable_for_new_conns, and to avoid + * deeper refactoring of our expiration logic. */ + if (! circ->base_.timestamp_dirty) + circ->base_.timestamp_dirty = approx_time(); + if (options->MaxCircuitDirtiness >= circ->base_.timestamp_dirty) + circ->base_.timestamp_dirty = 1; /* prevent underflow */ + else + circ->base_.timestamp_dirty -= options->MaxCircuitDirtiness; + + circ->unusable_for_new_conns = 1; +} + diff --git a/src/or/circuituse.h b/src/or/circuituse.h index d4d68aad92..11e5a64163 100644 --- a/src/or/circuituse.h +++ b/src/or/circuituse.h @@ -55,6 +55,7 @@ void circuit_change_purpose(circuit_t *circ, uint8_t new_purpose); int hostname_in_track_host_exits(const or_options_t *options, const char *address); +void mark_circuit_unusable_for_new_conns(origin_circuit_t *circ); #endif diff --git a/src/or/config.c b/src/or/config.c index 15138f9d7b..ffa984bcda 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2001 Matej Pfajfar. + /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2013, The Tor Project, Inc. */ @@ -255,6 +255,7 @@ static config_var_t option_vars_[] = { #endif OBSOLETE("GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays"), OBSOLETE("Group"), + V(GuardLifetime, INTERVAL, "0 minutes"), V(HardwareAccel, BOOL, "0"), V(HeartbeatPeriod, INTERVAL, "6 hours"), V(AccelName, STRING, NULL), @@ -300,6 +301,7 @@ static config_var_t option_vars_[] = { V(MaxClientCircuitsPending, UINT, "32"), OBSOLETE("MaxOnionsPending"), V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"), + V(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, "500"), OBSOLETE("MonthlyAccountingStart"), V(MyFamily, STRING, NULL), V(NewCircuitPeriod, INTERVAL, "30 seconds"), @@ -339,6 +341,8 @@ static config_var_t option_vars_[] = { V(PerConnBWRate, MEMUNIT, "0"), V(PidFile, STRING, NULL), V(TestingTorNetwork, BOOL, "0"), + V(TestingMinExitFlagThreshold, MEMUNIT, "0"), + V(TestingMinFastFlagThreshold, MEMUNIT, "0"), V(OptimisticData, AUTOBOOL, "auto"), V(PortForwarding, BOOL, "0"), V(PortForwardingHelper, FILENAME, "tor-fw-helper"), @@ -1502,7 +1506,7 @@ options_act(const or_options_t *old_options) "preferred or excluded node lists. " "Abandoning previous circuits."); circuit_mark_all_unused_circs(); - circuit_expire_all_dirty_circs(); + circuit_mark_all_dirty_circs_as_unusable(); revise_trackexithosts = 1; } @@ -2481,7 +2485,7 @@ options_validate(or_options_t *old_options, or_options_t *options, log_warn(LD_CONFIG, "PathsNeededToBuildCircuits is too low. Increasing " "to 0.25"); options->PathsNeededToBuildCircuits = 0.25; - } else if (options->PathsNeededToBuildCircuits < 0.95) { + } else if (options->PathsNeededToBuildCircuits > 0.95) { log_warn(LD_CONFIG, "PathsNeededToBuildCircuits is too high. Decreasing " "to 0.95"); options->PathsNeededToBuildCircuits = 0.95; @@ -2601,9 +2605,9 @@ options_validate(or_options_t *old_options, or_options_t *options, if (options->UseBridges && options->EntryNodes) REJECT("You cannot set both UseBridges and EntryNodes."); - if (options->EntryNodes && !options->UseEntryGuards) - log_warn(LD_CONFIG, "EntryNodes is set, but UseEntryGuards is disabled. " - "EntryNodes will be ignored."); + if (options->EntryNodes && !options->UseEntryGuards) { + REJECT("If EntryNodes is set, UseEntryGuards must be enabled."); + } options->AllowInvalid_ = 0; if (options->AllowInvalidNodes) { @@ -2721,15 +2725,19 @@ options_validate(or_options_t *old_options, or_options_t *options, "http://freehaven.net/anonbib/#hs-attack06 for details."); } - if (!(options->LearnCircuitBuildTimeout) && - options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) { + if (!options->LearnCircuitBuildTimeout && options->CircuitBuildTimeout && + options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) { log_warn(LD_CONFIG, - "CircuitBuildTimeout is shorter (%d seconds) than recommended " - "(%d seconds), and LearnCircuitBuildTimeout is disabled. " + "CircuitBuildTimeout is shorter (%d seconds) than the recommended " + "minimum (%d seconds), and LearnCircuitBuildTimeout is disabled. " "If tor isn't working, raise this value or enable " "LearnCircuitBuildTimeout.", options->CircuitBuildTimeout, RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT ); + } else if (!options->LearnCircuitBuildTimeout && + !options->CircuitBuildTimeout) { + log_notice(LD_CONFIG, "You disabled LearnCircuitBuildTimeout, but didn't " + "a CircuitBuildTimeout. I'll pick a plausible default."); } if (options->PathBiasNoticeRate > 1.0) { diff --git a/src/or/confparse.c b/src/or/confparse.c index 717d4ac2aa..8863d92409 100644 --- a/src/or/confparse.c +++ b/src/or/confparse.c @@ -91,12 +91,15 @@ config_get_lines(const char *string, config_line_t **result, int extended) { config_line_t *list = NULL, **next; char *k, *v; + const char *parse_err; next = &list; do { k = v = NULL; - string = parse_config_line_from_str(string, &k, &v); + string = parse_config_line_from_str_verbose(string, &k, &v, &parse_err); if (!string) { + log_warn(LD_CONFIG, "Error while parsing configuration: %s", + parse_err?parse_err:"<unknown>"); config_free_lines(list); tor_free(k); tor_free(v); @@ -1100,6 +1103,8 @@ static struct unit_table_t time_units[] = { { "days", 24*60*60 }, { "week", 7*24*60*60 }, { "weeks", 7*24*60*60 }, + { "month", 2629728, }, /* about 30.437 days */ + { "months", 2629728, }, { NULL, 0 }, }; diff --git a/src/or/connection.c b/src/or/connection.c index c659e65fe5..2cc3d7486b 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -918,8 +918,11 @@ make_socket_reuseable(tor_socket_t sock) * right after somebody else has let it go. But REUSEADDR on win32 * means you can bind to the port _even when somebody else * already has it bound_. So, don't do that on Win32. */ - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one, - (socklen_t)sizeof(one)); + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one, + (socklen_t)sizeof(one)) == -1) { + log_warn(LD_NET, "Error setting SO_REUSEADDR flag: %s", + tor_socket_strerror(errno)); + } #endif } @@ -1102,7 +1105,10 @@ connection_listener_new(const struct sockaddr *listensockaddr, tor_assert(0); } - set_socket_nonblocking(s); + if (set_socket_nonblocking(s) == -1) { + tor_close_socket(s); + goto err; + } lis_conn = listener_connection_new(type, listensockaddr->sa_family); conn = TO_CONN(lis_conn); @@ -1265,7 +1271,10 @@ connection_handle_listener_read(connection_t *conn, int new_type) (int)news,(int)conn->s); make_socket_reuseable(news); - set_socket_nonblocking(news); + if (set_socket_nonblocking(news) == -1) { + tor_close_socket(news); + return 0; + } if (options->ConstrainedSockets) set_constrained_socket_buffers(news, (int)options->ConstrainedSockSize); @@ -1494,7 +1503,11 @@ connection_connect(connection_t *conn, const char *address, } } - set_socket_nonblocking(s); + if (set_socket_nonblocking(s) == -1) { + *socket_error = tor_socket_errno(s); + tor_close_socket(s); + return -1; + } if (options->ConstrainedSockets) set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize); @@ -3426,6 +3439,10 @@ connection_handle_write_impl(connection_t *conn, int force) if (result < 0) { if (CONN_IS_EDGE(conn)) connection_edge_end_errno(TO_EDGE_CONN(conn)); + if (conn->type == CONN_TYPE_AP) { + /* writing failed; we couldn't send a SOCKS reply if we wanted to */ + TO_ENTRY_CONN(conn)->socks_request->has_finished = 1; + } connection_close_immediate(conn); /* Don't flush; connection is dead. */ connection_mark_for_close(conn); diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 84d556513c..926fcab90c 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -651,7 +651,9 @@ connection_ap_expire_beginning(void) } continue; } - if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL) { + if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL && + circ->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT && + circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) { log_warn(LD_BUG, "circuit->purpose == CIRCUIT_PURPOSE_C_GENERAL failed. " "The purpose on the circuit was %s; it was in state %s, " "path_state %s.", @@ -674,12 +676,10 @@ connection_ap_expire_beginning(void) /* un-mark it as ending, since we're going to reuse it */ conn->edge_has_sent_end = 0; conn->end_reason = 0; - /* kludge to make us not try this circuit again, yet to allow - * current streams on it to survive if they can: make it - * unattractive to use for new streams */ - /* XXXX024 this is a kludgy way to do this. */ - tor_assert(circ->timestamp_dirty); - circ->timestamp_dirty -= options->MaxCircuitDirtiness; + /* make us not try this circuit again, but allow + * current streams on it to survive if they can */ + mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ)); + /* give our stream another 'cutoff' seconds to try */ conn->base_.timestamp_lastread += cutoff; if (entry_conn->num_socks_retries < 250) /* avoid overflow */ @@ -1806,9 +1806,7 @@ connection_ap_handshake_send_begin(entry_connection_t *ap_conn) connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); /* Mark this circuit "unusable for new streams". */ - /* XXXX024 this is a kludgy way to do this. */ - tor_assert(circ->base_.timestamp_dirty); - circ->base_.timestamp_dirty -= get_options()->MaxCircuitDirtiness; + mark_circuit_unusable_for_new_conns(circ); return -1; } @@ -1899,9 +1897,7 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn) connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL); /* Mark this circuit "unusable for new streams". */ - /* XXXX024 this is a kludgy way to do this. */ - tor_assert(circ->base_.timestamp_dirty); - circ->base_.timestamp_dirty -= get_options()->MaxCircuitDirtiness; + mark_circuit_unusable_for_new_conns(circ); return -1; } @@ -1945,13 +1941,14 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn) string_addr, payload_len) < 0) return -1; /* circuit is closed, don't continue */ - tor_free(base_conn->address); /* Maybe already set by dnsserv. */ - base_conn->address = tor_strdup("(Tor_internal)"); + if (!base_conn->address) { + /* This might be unnecessary. XXXX */ + base_conn->address = tor_dup_addr(&base_conn->addr); + } base_conn->state = AP_CONN_STATE_RESOLVE_WAIT; log_info(LD_APP,"Address sent for resolve, ap socket "TOR_SOCKET_T_FORMAT ", n_circ_id %u", base_conn->s, (unsigned)circ->base_.n_circ_id); - control_event_stream_status(ap_conn, STREAM_EVENT_NEW, 0); control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE, 0); return 0; } @@ -2043,25 +2040,21 @@ tell_controller_about_resolved_result(entry_connection_t *conn, int ttl, time_t expires) { - - if (ttl >= 0 && (answer_type == RESOLVED_TYPE_IPV4 || - answer_type == RESOLVED_TYPE_HOSTNAME)) { - return; /* we already told the controller. */ - } else if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) { + expires = time(NULL) + ttl; + if (answer_type == RESOLVED_TYPE_IPV4 && answer_len >= 4) { char *cp = tor_dup_ip(ntohl(get_uint32(answer))); control_event_address_mapped(conn->socks_request->address, - cp, expires, NULL); + cp, expires, NULL, 0); tor_free(cp); } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) { char *cp = tor_strndup(answer, answer_len); control_event_address_mapped(conn->socks_request->address, - cp, expires, NULL); + cp, expires, NULL, 0); tor_free(cp); } else { control_event_address_mapped(conn->socks_request->address, - "<error>", - time(NULL)+ttl, - "error=yes"); + "<error>", time(NULL)+ttl, + "error=yes", 0); } } @@ -2119,8 +2112,9 @@ connection_ap_handshake_socks_resolved(entry_connection_t *conn, conn->socks_request->has_finished = 1; return; } else { - /* This must be a request from the controller. We already sent - * a mapaddress if there's a ttl. */ + /* This must be a request from the controller. Since answers to those + * requests are not cached, they do not generate an ADDRMAP event on + * their own. */ tell_controller_about_resolved_result(conn, answer_type, answer_len, (char*)answer, ttl, expires); conn->socks_request->has_finished = 1; @@ -2201,9 +2195,11 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply, tor_assert(conn->socks_request); /* make sure it's an AP stream */ - control_event_stream_status(conn, - status==SOCKS5_SUCCEEDED ? STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED, - endreason); + if (!SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command)) { + control_event_stream_status(conn, status==SOCKS5_SUCCEEDED ? + STREAM_EVENT_SUCCEEDED : STREAM_EVENT_FAILED, + endreason); + } /* Flag this stream's circuit as having completed a stream successfully * (for path bias) */ diff --git a/src/or/control.c b/src/or/control.c index 03e5d79c8e..f50b87711c 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -2939,7 +2939,7 @@ handle_control_resolve(control_connection_t *conn, uint32_t len, failed = smartlist_new(); SMARTLIST_FOREACH(args, const char *, arg, { if (!is_keyval_pair(arg)) { - if (dnsserv_launch_request(arg, is_reverse)<0) + if (dnsserv_launch_request(arg, is_reverse, conn)<0) smartlist_add(failed, (char*)arg); } }); @@ -2947,7 +2947,7 @@ handle_control_resolve(control_connection_t *conn, uint32_t len, send_control_done(conn); SMARTLIST_FOREACH(failed, const char *, arg, { control_event_address_mapped(arg, arg, time(NULL), - "internal"); + "internal", 0); }); SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); @@ -3742,7 +3742,7 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp, } } - if (tp == STREAM_EVENT_NEW) { + if (tp == STREAM_EVENT_NEW || tp == STREAM_EVENT_NEW_RESOLVE) { tor_snprintf(addrport_buf,sizeof(addrport_buf), " SOURCE_ADDR=%s:%d", ENTRY_TO_CONN(conn)->address, ENTRY_TO_CONN(conn)->port); } else { @@ -3752,11 +3752,7 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp, if (tp == STREAM_EVENT_NEW_RESOLVE) { purpose = " PURPOSE=DNS_REQUEST"; } else if (tp == STREAM_EVENT_NEW) { - if (ENTRY_TO_EDGE_CONN(conn)->is_dns_request || - (conn->socks_request && - SOCKS_COMMAND_IS_RESOLVE(conn->socks_request->command))) - purpose = " PURPOSE=DNS_REQUEST"; - else if (conn->use_begindir) { + if (conn->use_begindir) { connection_t *linked = ENTRY_TO_CONN(conn)->linked_conn; int linked_dir_purpose = -1; if (linked && linked->type == CONN_TYPE_DIR) @@ -4028,15 +4024,17 @@ control_event_descriptors_changed(smartlist_t *routers) */ int control_event_address_mapped(const char *from, const char *to, time_t expires, - const char *error) + const char *error, const int cached) { if (!EVENT_IS_INTERESTING(EVENT_ADDRMAP)) return 0; if (expires < 3 || expires == TIME_MAX) send_control_event(EVENT_ADDRMAP, ALL_FORMATS, - "650 ADDRMAP %s %s NEVER %s\r\n", from, to, - error?error:""); + "650 ADDRMAP %s %s NEVER %s%s" + "CACHED=\"%s\"\r\n", + from, to, error?error:"", error?" ":"", + cached?"YES":"NO"); else { char buf[ISO_TIME_LEN+1]; char buf2[ISO_TIME_LEN+1]; @@ -4044,10 +4042,10 @@ control_event_address_mapped(const char *from, const char *to, time_t expires, format_iso_time(buf2,expires); send_control_event(EVENT_ADDRMAP, ALL_FORMATS, "650 ADDRMAP %s %s \"%s\"" - " %s%sEXPIRES=\"%s\"\r\n", + " %s%sEXPIRES=\"%s\" CACHED=\"%s\"\r\n", from, to, buf, error?error:"", error?" ":"", - buf2); + buf2, cached?"YES":"NO"); } return 0; diff --git a/src/or/control.h b/src/or/control.h index 51ae230b09..0ea7941b13 100644 --- a/src/or/control.h +++ b/src/or/control.h @@ -53,7 +53,8 @@ int control_event_stream_bandwidth_used(void); void control_event_logmsg(int severity, uint32_t domain, const char *msg); int control_event_descriptors_changed(smartlist_t *routers); int control_event_address_mapped(const char *from, const char *to, - time_t expires, const char *error); + time_t expires, const char *error, + const int cached); int control_event_or_authdir_new_descriptor(const char *action, const char *desc, size_t desclen, diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c index 38c6613f08..61f9faa394 100644 --- a/src/or/cpuworker.c +++ b/src/or/cpuworker.c @@ -535,13 +535,16 @@ spawn_cpuworker(void) conn = connection_new(CONN_TYPE_CPUWORKER, AF_UNIX); - set_socket_nonblocking(fd); - /* set up conn so it's got all the data we need to remember */ conn->s = fd; conn->address = tor_strdup("localhost"); tor_addr_make_unspec(&conn->addr); + if (set_socket_nonblocking(fd) == -1) { + connection_free(conn); /* this closes fd */ + return -1; + } + if (connection_add(conn) < 0) { /* no space, forget it */ log_warn(LD_NET,"connection_add for cpuworker failed. Giving up."); connection_free(conn); /* this closes fd */ diff --git a/src/or/dirserv.c b/src/or/dirserv.c index badacd683d..e837e4bed5 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -66,6 +66,13 @@ static cached_dir_t *the_directory = NULL; /** For authoritative directories: the current (v1) network status. */ static cached_dir_t the_runningrouters; +/** Total number of routers with measured bandwidth; this is set by + * dirserv_count_measured_bws() before the loop in + * dirserv_generate_networkstatus_vote_obj() and checked by + * dirserv_get_credible_bandwidth() and + * dirserv_compute_performance_thresholds() */ +static int routers_with_measured_bw = 0; + static void directory_remove_invalid(void); static cached_dir_t *dirserv_regenerate_directory(void); static char *format_versions_list(config_line_t *ln); @@ -85,9 +92,8 @@ static const signed_descriptor_t *get_signed_descriptor_by_fp( time_t publish_cutoff); static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei, const char **msg); - -/************** Measured Bandwidth parsing code ******/ -#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */ +static uint32_t dirserv_get_bandwidth_for_router(const routerinfo_t *ri); +static uint32_t dirserv_get_credible_bandwidth(const routerinfo_t *ri); /************** Fingerprint handling code ************/ @@ -1824,7 +1830,7 @@ dirserv_thinks_router_is_unreliable(time_t now, } } if (need_capacity) { - uint32_t bw = router_get_advertised_bandwidth(router); + uint32_t bw = dirserv_get_bandwidth_for_router(router); if (bw < fast_bandwidth) return 1; } @@ -1876,15 +1882,29 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router, #define ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER 4096 /** Helper for dirserv_compute_performance_thresholds(): Decide whether to - * include a router in our calculations, and return true iff we should. */ + * include a router in our calculations, and return true iff we should; the + * require_mbw parameter is passed in by + * dirserv_compute_performance_thresholds() and controls whether we ever + * count routers with only advertised bandwidths */ static int router_counts_toward_thresholds(const node_t *node, time_t now, - const digestmap_t *omit_as_sybil) + const digestmap_t *omit_as_sybil, + int require_mbw) { + /* Have measured bw? */ + int have_mbw = + dirserv_has_measured_bw(node->ri->cache_info.identity_digest); + uint64_t min_bw = ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER; + const or_options_t *options = get_options(); + + if (options->TestingTorNetwork) { + min_bw = (int64_t)options->TestingMinExitFlagThreshold; + } + return node->ri && router_is_active(node->ri, node, now) && !digestmap_get(omit_as_sybil, node->ri->cache_info.identity_digest) && - (router_get_advertised_bandwidth(node->ri) >= - ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER); + (dirserv_get_credible_bandwidth(node->ri) >= min_bw) && + (have_mbw || !require_mbw); } /** Look through the routerlist, the Mean Time Between Failure history, and @@ -1906,6 +1926,11 @@ dirserv_compute_performance_thresholds(routerlist_t *rl, time_t now = time(NULL); const or_options_t *options = get_options(); + /* Require mbw? */ + int require_mbw = + (routers_with_measured_bw > + options->MinMeasuredBWsForAuthToIgnoreAdvertised) ? 1 : 0; + /* initialize these all here, in case there are no routers */ stable_uptime = 0; stable_mtbf = 0; @@ -1938,7 +1963,8 @@ dirserv_compute_performance_thresholds(routerlist_t *rl, /* Now, fill in the arrays. */ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) { - if (router_counts_toward_thresholds(node, now, omit_as_sybil)) { + if (router_counts_toward_thresholds(node, now, omit_as_sybil, + require_mbw)) { routerinfo_t *ri = node->ri; const char *id = ri->cache_info.identity_digest; uint32_t bw; @@ -1947,7 +1973,7 @@ dirserv_compute_performance_thresholds(routerlist_t *rl, uptimes[n_active] = (uint32_t)real_uptime(ri, now); mtbfs[n_active] = rep_hist_get_stability(id, now); tks [n_active] = rep_hist_get_weighted_time_known(id, now); - bandwidths[n_active] = bw = router_get_advertised_bandwidth(ri); + bandwidths[n_active] = bw = dirserv_get_credible_bandwidth(ri); total_bandwidth += bw; if (node->is_exit && !node->is_bad_exit) { total_exit_bandwidth += bw; @@ -1985,6 +2011,9 @@ dirserv_compute_performance_thresholds(routerlist_t *rl, ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG, ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG, INT32_MAX); + if (options->TestingTorNetwork) { + min_fast = (int32_t)options->TestingMinFastFlagThreshold; + } max_fast = networkstatus_get_param(NULL, "FastFlagMaxThreshold", INT32_MAX, min_fast, INT32_MAX); if (fast_bandwidth < (uint32_t)min_fast) @@ -2003,7 +2032,8 @@ dirserv_compute_performance_thresholds(routerlist_t *rl, n_familiar = 0; SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) { - if (router_counts_toward_thresholds(node, now, omit_as_sybil)) { + if (router_counts_toward_thresholds(node, now, + omit_as_sybil, require_mbw)) { routerinfo_t *ri = node->ri; const char *id = ri->cache_info.identity_digest; long tk = rep_hist_get_weighted_time_known(id, now); @@ -2046,6 +2076,203 @@ dirserv_compute_performance_thresholds(routerlist_t *rl, tor_free(wfus); } +/** Measured bandwidth cache entry */ +typedef struct mbw_cache_entry_s { + long mbw; + time_t as_of; +} mbw_cache_entry_t; + +/** Measured bandwidth cache - keys are identity_digests, values are + * mbw_cache_entry_t *. */ +static digestmap_t *mbw_cache = NULL; + +/** Store a measured bandwidth cache entry when reading the measured + * bandwidths file. */ +void +dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, + time_t as_of) +{ + mbw_cache_entry_t *e = NULL; + + tor_assert(parsed_line); + + /* Allocate a cache if we need */ + if (!mbw_cache) mbw_cache = digestmap_new(); + + /* Check if we have an existing entry */ + e = digestmap_get(mbw_cache, parsed_line->node_id); + /* If we do, we can re-use it */ + if (e) { + /* Check that we really are newer, and update */ + if (as_of > e->as_of) { + e->mbw = parsed_line->bw; + e->as_of = as_of; + } + } else { + /* We'll have to insert a new entry */ + e = tor_malloc(sizeof(*e)); + e->mbw = parsed_line->bw; + e->as_of = as_of; + digestmap_set(mbw_cache, parsed_line->node_id, e); + } +} + +/** Clear and free the measured bandwidth cache */ +void +dirserv_clear_measured_bw_cache(void) +{ + if (mbw_cache) { + /* Free the map and all entries */ + digestmap_free(mbw_cache, tor_free_); + mbw_cache = NULL; + } +} + +/** Scan the measured bandwidth cache and remove expired entries */ +void +dirserv_expire_measured_bw_cache(time_t now) +{ + + if (mbw_cache) { + /* Iterate through the cache and check each entry */ + DIGESTMAP_FOREACH_MODIFY(mbw_cache, k, mbw_cache_entry_t *, e) { + if (now > e->as_of + MAX_MEASUREMENT_AGE) { + tor_free(e); + MAP_DEL_CURRENT(k); + } + } DIGESTMAP_FOREACH_END; + + /* Check if we cleared the whole thing and free if so */ + if (digestmap_size(mbw_cache) == 0) { + digestmap_free(mbw_cache, tor_free_); + mbw_cache = 0; + } + } +} + +/** Get the current size of the measured bandwidth cache */ +int +dirserv_get_measured_bw_cache_size(void) +{ + if (mbw_cache) return digestmap_size(mbw_cache); + else return 0; +} + +/** Query the cache by identity digest, return value indicates whether + * we found it. The bw_out and as_of_out pointers receive the cached + * bandwidth value and the time it was cached if not NULL. */ +int +dirserv_query_measured_bw_cache(const char *node_id, long *bw_out, + time_t *as_of_out) +{ + mbw_cache_entry_t *v = NULL; + int rv = 0; + + if (mbw_cache && node_id) { + v = digestmap_get(mbw_cache, node_id); + if (v) { + /* Found something */ + rv = 1; + if (bw_out) *bw_out = v->mbw; + if (as_of_out) *as_of_out = v->as_of; + } + } + + return rv; +} + +/** Predicate wrapper for dirserv_query_measured_bw_cache() */ +int +dirserv_has_measured_bw(const char *node_id) +{ + return dirserv_query_measured_bw_cache(node_id, NULL, NULL); +} + +/** Get the best estimate of a router's bandwidth for dirauth purposes, + * preferring measured to advertised values if available. */ + +static uint32_t +dirserv_get_bandwidth_for_router(const routerinfo_t *ri) +{ + uint32_t bw = 0; + /* + * Yeah, measured bandwidths in measured_bw_line_t are (implicitly + * signed) longs and the ones router_get_advertised_bandwidth() returns + * are uint32_t. + */ + long mbw = 0; + + if (ri) { + /* + * * First try to see if we have a measured bandwidth; don't bother with + * as_of_out here, on the theory that a stale measured bandwidth is still + * better to trust than an advertised one. + */ + if (dirserv_query_measured_bw_cache(ri->cache_info.identity_digest, + &mbw, NULL)) { + /* Got one! */ + bw = (uint32_t)mbw; + } else { + /* If not, fall back to advertised */ + bw = router_get_advertised_bandwidth(ri); + } + } + + return bw; +} + +/** Look through the routerlist, and using the measured bandwidth cache count + * how many measured bandwidths we know. This is used to decide whether we + * ever trust advertised bandwidths for purposes of assigning flags. */ +static void +dirserv_count_measured_bws(routerlist_t *rl) +{ + /* Initialize this first */ + routers_with_measured_bw = 0; + + tor_assert(rl); + tor_assert(rl->routers); + + /* Iterate over the routerlist and count measured bandwidths */ + SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) { + /* Check if we know a measured bandwidth for this one */ + if (dirserv_has_measured_bw(ri->cache_info.identity_digest)) { + ++routers_with_measured_bw; + } + } SMARTLIST_FOREACH_END(ri); +} + +/** Return the bandwidth we believe for assigning flags; prefer measured + * over advertised, and if we have above a threshold quantity of measured + * bandwidths, we don't want to ever give flags to unmeasured routers, so + * return 0. */ +static uint32_t +dirserv_get_credible_bandwidth(const routerinfo_t *ri) +{ + int threshold; + uint32_t bw = 0; + long mbw; + + tor_assert(ri); + /* Check if we have a measured bandwidth, and check the threshold if not */ + if (!(dirserv_query_measured_bw_cache(ri->cache_info.identity_digest, + &mbw, NULL))) { + threshold = get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised; + if (routers_with_measured_bw > threshold) { + /* Return zero for unmeasured bandwidth if we are above threshold */ + bw = 0; + } else { + /* Return an advertised bandwidth otherwise */ + bw = router_get_advertised_bandwidth(ri); + } + } else { + /* We have the measured bandwidth in mbw */ + bw = (uint32_t)mbw; + } + + return bw; +} + /** Give a statement of our current performance thresholds for inclusion * in a vote document. */ char * @@ -2216,9 +2443,10 @@ routerstatus_format_entry(char *buf, size_t buf_len, return -1; } - /* This assert can fire for the control port, because + /* This assert could fire for the control port, because * it can request NS documents before all descriptors - * have been fetched. */ + * have been fetched. Therefore, we only do this test when + * format != NS_CONTROL_PORT. */ if (tor_memneq(desc->cache_info.signed_descriptor_digest, rs->descriptor_digest, DIGEST_LEN)) { @@ -2327,8 +2555,8 @@ compare_routerinfo_by_ip_and_bw_(const void **a, const void **b) else if (!first_is_running && second_is_running) return 1; - bw_first = router_get_advertised_bandwidth(first); - bw_second = router_get_advertised_bandwidth(second); + bw_first = dirserv_get_bandwidth_for_router(first); + bw_second = dirserv_get_bandwidth_for_router(second); if (bw_first > bw_second) return -1; @@ -2468,7 +2696,7 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, int listbaddirs, int vote_on_hsdirs) { const or_options_t *options = get_options(); - uint32_t routerbw = router_get_advertised_bandwidth(ri); + uint32_t routerbw = dirserv_get_credible_bandwidth(ri); memset(rs, 0, sizeof(routerstatus_t)); @@ -2670,8 +2898,9 @@ dirserv_read_measured_bandwidths(const char *from_file, char line[256]; FILE *fp = tor_fopen_cloexec(from_file, "r"); int applied_lines = 0; - time_t file_time; + time_t file_time, now; int ok; + if (fp == NULL) { log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s", from_file); @@ -2695,7 +2924,8 @@ dirserv_read_measured_bandwidths(const char *from_file, return -1; } - if ((time(NULL) - file_time) > MAX_MEASUREMENT_AGE) { + now = time(NULL); + if ((now - file_time) > MAX_MEASUREMENT_AGE) { log_warn(LD_DIRSERV, "Bandwidth measurement file stale. Age: %u", (unsigned)(time(NULL) - file_time)); fclose(fp); @@ -2709,12 +2939,17 @@ dirserv_read_measured_bandwidths(const char *from_file, measured_bw_line_t parsed_line; if (fgets(line, sizeof(line), fp) && strlen(line)) { if (measured_bw_line_parse(&parsed_line, line) != -1) { + /* Also cache the line for dirserv_get_bandwidth_for_router() */ + dirserv_cache_measured_bw(&parsed_line, file_time); if (measured_bw_line_apply(&parsed_line, routerstatuses) > 0) applied_lines++; } } } + /* Now would be a nice time to clean the cache, too */ + dirserv_expire_measured_bw_cache(now); + fclose(fp); log_info(LD_DIRSERV, "Bandwidth measurement file successfully read. " @@ -2778,6 +3013,22 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, if (!contact) contact = "(none)"; + /* + * Do this so dirserv_compute_performance_thresholds() and + * set_routerstatus_from_routerinfo() see up-to-date bandwidth info. + */ + if (options->V3BandwidthsFile) { + dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL); + } else { + /* + * No bandwidths file; clear the measured bandwidth cache in case we had + * one last time around. + */ + if (dirserv_get_measured_bw_cache_size() > 0) { + dirserv_clear_measured_bw_cache(); + } + } + /* precompute this part, since we need it to decide what "stable" * means. */ SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, { @@ -2794,6 +3045,10 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, rep_hist_make_router_pessimal(sybil_id, now); } DIGESTMAP_FOREACH_END; + /* Count how many have measured bandwidths so we know how to assign flags; + * this must come before dirserv_compute_performance_thresholds() */ + dirserv_count_measured_bws(rl); + dirserv_compute_performance_thresholds(rl, omit_as_sybil); routerstatuses = smartlist_new(); @@ -2838,9 +3093,18 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, smartlist_free(routers); digestmap_free(omit_as_sybil, NULL); + /* This pass through applies the measured bw lines to the routerstatuses */ if (options->V3BandwidthsFile) { dirserv_read_measured_bandwidths(options->V3BandwidthsFile, routerstatuses); + } else { + /* + * No bandwidths file; clear the measured bandwidth cache in case we had + * one last time around. + */ + if (dirserv_get_measured_bw_cache_size() > 0) { + dirserv_clear_measured_bw_cache(); + } } v3_out = tor_malloc_zero(sizeof(networkstatus_t)); @@ -3908,5 +4172,7 @@ dirserv_free_all(void) cached_v2_networkstatus = NULL; strmap_free(cached_consensuses, free_cached_dir_); cached_consensuses = NULL; + + dirserv_clear_measured_bw_cache(); } diff --git a/src/or/dirserv.h b/src/or/dirserv.h index 0caf55f830..a84ae964c9 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -76,7 +76,6 @@ int directory_fetches_from_authorities(const or_options_t *options); int directory_fetches_dir_info_early(const or_options_t *options); int directory_fetches_dir_info_later(const or_options_t *options); int directory_caches_v2_dir_info(const or_options_t *options); -#define directory_caches_v1_dir_info(o) directory_caches_v2_dir_info(o) int directory_caches_unknown_auth_certs(const or_options_t *options); int directory_caches_dir_info(const or_options_t *options); int directory_permits_begindir_requests(const or_options_t *options); @@ -138,10 +137,23 @@ void cached_dir_decref(cached_dir_t *d); cached_dir_t *new_cached_dir(char *s, time_t published); #ifdef DIRSERV_PRIVATE + +/* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */ +#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */ + int measured_bw_line_parse(measured_bw_line_t *out, const char *line); int measured_bw_line_apply(measured_bw_line_t *parsed_line, smartlist_t *routerstatuses); + +void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line, + time_t as_of); +void dirserv_clear_measured_bw_cache(void); +void dirserv_expire_measured_bw_cache(time_t now); +int dirserv_get_measured_bw_cache_size(void); +int dirserv_query_measured_bw_cache(const char *node_id, long *bw_out, + time_t *as_of_out); +int dirserv_has_measured_bw(const char *node_id); #endif int dirserv_read_measured_bandwidths(const char *from_file, diff --git a/src/or/dirvote.c b/src/or/dirvote.c index bcfe2b0698..7043cef245 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -1913,7 +1913,7 @@ networkstatus_compute_consensus(smartlist_t *votes, } /* Fix bug 2203: Do not count BadExit nodes as Exits for bw weights */ - if (consensus_method >= 11) { + if (consensus_method >= MIN_METHOD_TO_CUT_BADEXIT_WEIGHT) { is_exit = is_exit && !is_bad_exit; } @@ -2210,7 +2210,7 @@ networkstatus_compute_consensus(smartlist_t *votes, } // Verify balancing parameters if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS && added_weights) { - networkstatus_verify_bw_weights(c); + networkstatus_verify_bw_weights(c, consensus_method); } networkstatus_vote_free(c); } diff --git a/src/or/dirvote.h b/src/or/dirvote.h index fbb61b652f..8d036d6c14 100644 --- a/src/or/dirvote.h +++ b/src/or/dirvote.h @@ -34,6 +34,9 @@ /** Lowest consensus method that generates microdescriptors */ #define MIN_METHOD_FOR_MICRODESC 8 +/** Lowest consensus method that doesn't count bad exits as exits for weight */ +#define MIN_METHOD_TO_CUT_BADEXIT_WEIGHT 11 + /** Lowest consensus method that ensures a majority of authorities voted * for a param. */ #define MIN_METHOD_FOR_MAJORITY_PARAMS 12 diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c index 7032b58145..a1275cf2b3 100644 --- a/src/or/dnsserv.c +++ b/src/or/dnsserv.c @@ -147,7 +147,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_) return; } - control_event_stream_status(entry_conn, STREAM_EVENT_NEW, 0); + control_event_stream_status(entry_conn, STREAM_EVENT_NEW_RESOLVE, 0); /* Now, unless a controller asked us to leave streams unattached, * throw the connection over to get rewritten (which will @@ -170,7 +170,8 @@ evdns_server_callback(struct evdns_server_request *req, void *data_) * response; -1 if we couldn't launch the request. */ int -dnsserv_launch_request(const char *name, int reverse) +dnsserv_launch_request(const char *name, int reverse, + control_connection_t *control_conn) { entry_connection_t *entry_conn; edge_connection_t *conn; @@ -181,6 +182,10 @@ dnsserv_launch_request(const char *name, int reverse) conn = ENTRY_TO_EDGE_CONN(entry_conn); conn->base_.state = AP_CONN_STATE_RESOLVE_WAIT; + tor_addr_copy(&TO_CONN(conn)->addr, &control_conn->base_.addr); + TO_CONN(conn)->port = control_conn->base_.port; + TO_CONN(conn)->address = tor_dup_addr(&control_conn->base_.addr); + if (reverse) entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; else @@ -203,6 +208,8 @@ dnsserv_launch_request(const char *name, int reverse) return -1; } + control_event_stream_status(entry_conn, STREAM_EVENT_NEW_RESOLVE, 0); + /* Now, unless a controller asked us to leave streams unattached, * throw the connection over to get rewritten (which will * answer it immediately if it's in the cache, or completely bogus, or diff --git a/src/or/dnsserv.h b/src/or/dnsserv.h index 6bdb98de70..687a77e59e 100644 --- a/src/or/dnsserv.h +++ b/src/or/dnsserv.h @@ -20,7 +20,8 @@ void dnsserv_resolved(entry_connection_t *conn, const char *answer, int ttl); void dnsserv_reject_request(entry_connection_t *conn); -int dnsserv_launch_request(const char *name, int is_reverse); +int dnsserv_launch_request(const char *name, int is_reverse, + control_connection_t *control_conn); #endif diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index 5d356b6231..3234f4f3c7 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -24,6 +24,7 @@ #include "entrynodes.h" #include "main.h" #include "microdesc.h" +#include "networkstatus.h" #include "nodelist.h" #include "policies.h" #include "router.h" @@ -332,6 +333,9 @@ control_event_guard_deferred(void) #endif } +/** Largest amount that we'll backdate chosen_on_date */ +#define CHOSEN_ON_DATE_SLOP (30*86400) + /** Add a new (preferably stable and fast) router to our * entry_guards list. Return a pointer to the router if we succeed, * or NULL if we can't find any more suitable entries. @@ -367,13 +371,22 @@ add_an_entry_guard(const node_t *chosen, int reset_status, int prepend, } else { const routerstatus_t *rs; rs = router_pick_directory_server(MICRODESC_DIRINFO|V3_DIRINFO, - PDS_PREFER_TUNNELED_DIR_CONNS_); + PDS_PREFER_TUNNELED_DIR_CONNS_|PDS_FOR_GUARD); if (!rs) return NULL; node = node_get_by_id(rs->identity_digest); if (!node) return NULL; } + if (node->using_as_guard) + return NULL; + if (entry_guard_get_by_id_digest(node->identity) != NULL) { + log_info(LD_CIRC, "I was about to add a duplicate entry guard."); + /* This can happen if we choose a guard, then the node goes away, then + * comes back. */ + ((node_t*) node)->using_as_guard = 1; + return NULL; + } entry = tor_malloc_zero(sizeof(entry_guard_t)); log_info(LD_CIRC, "Chose %s as new entry guard.", node_describe(node)); @@ -391,6 +404,7 @@ add_an_entry_guard(const node_t *chosen, int reset_status, int prepend, * this guard. For details, see the Jan 2010 or-dev thread. */ entry->chosen_on_date = time(NULL) - crypto_rand_int(3600*24*30); entry->chosen_by_version = tor_strdup(VERSION); + ((node_t*)node)->using_as_guard = 1; if (prepend) smartlist_insert(entry_guards, 0, entry); else @@ -435,6 +449,32 @@ entry_guard_free(entry_guard_t *e) tor_free(e); } +/** + * Return the minimum lifetime of working entry guard, in seconds, + * as given in the consensus networkstatus. (Plus CHOSEN_ON_DATE_SLOP, + * so that we can do the chosen_on_date randomization while achieving the + * desired minimum lifetime.) + */ +static int32_t +guards_get_lifetime(void) +{ + const or_options_t *options = get_options(); +#define DFLT_GUARD_LIFETIME (86400 * 60) /* Two months. */ +#define MIN_GUARD_LIFETIME (86400 * 30) /* One months. */ +#define MAX_GUARD_LIFETIME (86400 * 1826) /* Five years. */ + + if (options->GuardLifetime >= 1) { + return CLAMP(MIN_GUARD_LIFETIME, + options->GuardLifetime, + MAX_GUARD_LIFETIME) + CHOSEN_ON_DATE_SLOP; + } + + return networkstatus_get_param(NULL, "GuardLifetime", + DFLT_GUARD_LIFETIME, + MIN_GUARD_LIFETIME, + MAX_GUARD_LIFETIME) + CHOSEN_ON_DATE_SLOP; +} + /** Remove any entry guard which was selected by an unknown version of Tor, * or which was selected by a version of Tor that's known to select * entry guards badly, or which was selected more 2 months ago. */ @@ -444,6 +484,7 @@ static int remove_obsolete_entry_guards(time_t now) { int changed = 0, i; + int32_t guard_lifetime = guards_get_lifetime(); for (i = 0; i < smartlist_len(entry_guards); ++i) { entry_guard_t *entry = smartlist_get(entry_guards, i); @@ -474,8 +515,8 @@ remove_obsolete_entry_guards(time_t now) } tor_free(tor_ver); } - if (!version_is_bad && entry->chosen_on_date + 3600*24*60 < now) { - /* It's been 2 months since the date listed in our state file. */ + if (!version_is_bad && entry->chosen_on_date + guard_lifetime < now) { + /* It's been too long since the date listed in our state file. */ msg = "was selected several months ago"; date_is_bad = 1; } @@ -730,6 +771,21 @@ entry_nodes_should_be_added(void) should_add_entry_nodes = 1; } +/** Update the using_as_guard fields of all the nodes. We do this after we + * remove entry guards from the list: This is the only function that clears + * the using_as_guard field. */ +static void +update_node_guard_status(void) +{ + smartlist_t *nodes = nodelist_get_list(); + SMARTLIST_FOREACH(nodes, node_t *, node, node->using_as_guard = 0); + SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) { + node_t *node = node_get_mutable_by_id(entry->identity); + if (node) + node->using_as_guard = 1; + } SMARTLIST_FOREACH_END(entry); +} + /** Adjust the entry guards list so that it only contains entries from * EntryNodes, adding new entries from EntryNodes to the list as needed. */ static void @@ -814,6 +870,8 @@ entry_guards_set_from_config(const or_options_t *options) SMARTLIST_FOREACH(old_entry_guards_not_on_list, entry_guard_t *, e, entry_guard_free(e)); + update_node_guard_status(); + smartlist_free(entry_nodes); smartlist_free(worse_entry_nodes); smartlist_free(entry_fps); @@ -1153,6 +1211,21 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg) continue; } + if (use_cnt < success_cnt) { + int severity = LOG_INFO; + /* If this state file was written by a Tor that would have + * already fixed it, then the overcounting bug is still there.. */ + if (tor_version_as_new_as(state_version, "0.2.4.12-alpha")) { + severity = LOG_NOTICE; + } + log_fn(severity, LD_BUG, + "State file contains unexpectedly high usage success " + "counts %lf/%lf for Guard %s ($%s)", + success_cnt, use_cnt, + node->nickname, hex_str(node->identity, DIGEST_LEN)); + success_cnt = use_cnt; + } + node->use_attempts = use_cnt; node->use_successes = success_cnt; @@ -1203,6 +1276,21 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg) unusable = 0; } + if (hop_cnt < success_cnt) { + int severity = LOG_INFO; + /* If this state file was written by a Tor that would have + * already fixed it, then the overcounting bug is still there.. */ + if (tor_version_as_new_as(state_version, "0.2.4.12-alpha")) { + severity = LOG_NOTICE; + } + log_fn(severity, LD_BUG, + "State file contains unexpectedly high success counts " + "%lf/%lf for Guard %s ($%s)", + success_cnt, hop_cnt, + node->nickname, hex_str(node->identity, DIGEST_LEN)); + success_cnt = hop_cnt; + } + node->circ_attempts = hop_cnt; node->circ_successes = success_cnt; @@ -1269,6 +1357,8 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg) * few lines, so we don't have to re-dirty it */ if (remove_obsolete_entry_guards(now)) entry_guards_dirty = 1; + + update_node_guard_status(); } digestmap_free(added_by, tor_free_); return *msg ? -1 : 0; diff --git a/src/or/hibernate.c b/src/or/hibernate.c index 36af4d8f83..a412571331 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -506,10 +506,6 @@ accounting_run_housekeeping(time_t now) } } -/** When we have no idea how fast we are, how long do we assume it will take - * us to exhaust our bandwidth? */ -#define GUESS_TIME_TO_USE_BANDWIDTH (24*60*60) - /** Based on our interval and our estimated bandwidth, choose a * deterministic (but random-ish) time to wake up. */ static void diff --git a/src/or/main.c b/src/or/main.c index b5d1e2da34..fd8b6cf674 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -158,10 +158,6 @@ int can_complete_circuit=0; /** How long do we let a directory connection stall before expiring it? */ #define DIR_CONN_MAX_STALL (5*60) -/** How long do we let OR connections handshake before we decide that - * they are obsolete? */ -#define TLS_HANDSHAKE_TIMEOUT (60) - /** Decides our behavior when no logs are configured/before any * logs have been configured. For 0, we log notice to stdout as normal. * For 1, we log warnings only. For 2, we log nothing. @@ -1129,7 +1125,7 @@ signewnym_impl(time_t now) return; } - circuit_expire_all_dirty_circs(); + circuit_mark_all_dirty_circs_as_unusable(); addressmap_clear_transient(); rend_client_purge_state(); time_of_last_signewnym = now; @@ -1848,7 +1844,7 @@ do_hup(void) /* Rotate away from the old dirty circuits. This has to be done * after we've read the new options, but before we start using * circuits for directory fetches. */ - circuit_expire_all_dirty_circs(); + circuit_mark_all_dirty_circs_as_unusable(); /* retry appropriate downloads */ router_reset_status_download_failures(); diff --git a/src/or/microdesc.c b/src/or/microdesc.c index ac48930faf..d9955c7b49 100644 --- a/src/or/microdesc.c +++ b/src/or/microdesc.c @@ -71,7 +71,7 @@ HT_GENERATE(microdesc_map, microdesc_t, node, * *<b>annotation_len_out</b> to the number of bytes written as * annotations. */ static ssize_t -dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out) +dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out) { ssize_t r = 0; size_t written; @@ -81,10 +81,10 @@ dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out) char annotation[ISO_TIME_LEN+32]; format_iso_time(buf, md->last_listed); tor_snprintf(annotation, sizeof(annotation), "@last-listed %s\n", buf); - if (fputs(annotation, f) < 0) { + if (write_all(fd, annotation, strlen(annotation), 0) < 0) { log_warn(LD_DIR, "Couldn't write microdescriptor annotation: %s", - strerror(ferror(f))); + strerror(errno)); return -1; } r += strlen(annotation); @@ -93,13 +93,13 @@ dump_microdescriptor(FILE *f, microdesc_t *md, size_t *annotation_len_out) *annotation_len_out = 0; } - md->off = (off_t) ftell(f); - written = fwrite(md->body, 1, md->bodylen, f); + md->off = tor_fd_getpos(fd); + written = write_all(fd, md->body, md->bodylen, 0); if (written != md->bodylen) { log_warn(LD_DIR, "Couldn't dump microdescriptor (wrote %lu out of %lu): %s", (unsigned long)written, (unsigned long)md->bodylen, - strerror(ferror(f))); + strerror(errno)); return -1; } r += md->bodylen; @@ -198,15 +198,15 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache, { smartlist_t *added; open_file_t *open_file = NULL; - FILE *f = NULL; + int fd = -1; // int n_added = 0; ssize_t size = 0; if (where == SAVED_NOWHERE && !no_save) { - f = start_writing_to_stdio_file(cache->journal_fname, - OPEN_FLAGS_APPEND|O_BINARY, - 0600, &open_file); - if (!f) { + fd = start_writing_to_file(cache->journal_fname, + OPEN_FLAGS_APPEND|O_BINARY, + 0600, &open_file); + if (fd < 0) { log_warn(LD_DIR, "Couldn't append to journal in %s: %s", cache->journal_fname, strerror(errno)); return NULL; @@ -228,9 +228,9 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache, } /* Okay, it's a new one. */ - if (f) { + if (fd >= 0) { size_t annotation_len; - size = dump_microdescriptor(f, md, &annotation_len); + size = dump_microdescriptor(fd, md, &annotation_len); if (size < 0) { /* we already warned in dump_microdescriptor */ abort_writing_to_file(open_file); @@ -252,8 +252,14 @@ microdescs_add_list_to_cache(microdesc_cache_t *cache, cache->total_len_seen += md->bodylen; } SMARTLIST_FOREACH_END(md); - if (f) - finish_writing_to_file(open_file); /*XXX Check me.*/ + if (fd >= 0) { + if (finish_writing_to_file(open_file) < 0) { + log_warn(LD_DIR, "Error appending to microdescriptor file: %s", + strerror(errno)); + smartlist_clear(added); + return added; + } + } { networkstatus_t *ns = networkstatus_get_latest_consensus(); @@ -406,11 +412,11 @@ int microdesc_cache_rebuild(microdesc_cache_t *cache, int force) { open_file_t *open_file; - FILE *f; + int fd = -1; microdesc_t **mdp; smartlist_t *wrote; ssize_t size; - off_t off = 0; + off_t off = 0, off_real; int orig_size, new_size; if (cache == NULL) { @@ -430,10 +436,10 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force) orig_size = (int)(cache->cache_content ? cache->cache_content->size : 0); orig_size += (int)cache->journal_len; - f = start_writing_to_stdio_file(cache->cache_fname, - OPEN_FLAGS_REPLACE|O_BINARY, - 0600, &open_file); - if (!f) + fd = start_writing_to_file(cache->cache_fname, + OPEN_FLAGS_REPLACE|O_BINARY, + 0600, &open_file); + if (fd < 0) return -1; wrote = smartlist_new(); @@ -444,7 +450,7 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force) if (md->no_save) continue; - size = dump_microdescriptor(f, md, &annotation_len); + size = dump_microdescriptor(fd, md, &annotation_len); if (size < 0) { /* XXX handle errors from dump_microdescriptor() */ /* log? return -1? die? coredump the universe? */ @@ -453,6 +459,14 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force) tor_assert(((size_t)size) == annotation_len + md->bodylen); md->off = off + annotation_len; off += size; + off_real = tor_fd_getpos(fd); + if (off_real != off) { + log_warn(LD_BUG, "Discontinuity in position in microdescriptor cache." + "By my count, I'm at "I64_FORMAT + ", but I should be at "I64_FORMAT, + I64_PRINTF_ARG(off), I64_PRINTF_ARG(off_real)); + off = off_real; + } if (md->saved_location != SAVED_IN_CACHE) { tor_free(md->body); md->saved_location = SAVED_IN_CACHE; @@ -460,11 +474,15 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force) smartlist_add(wrote, md); } + if (finish_writing_to_file(open_file) < 0) { + log_warn(LD_DIR, "Error rebuilding microdescriptor cache: %s", + strerror(errno)); + return -1; + } + if (cache->cache_content) tor_munmap_file(cache->cache_content); - finish_writing_to_file(open_file); /*XXX Check me.*/ - cache->cache_content = tor_mmap_file(cache->cache_fname); if (!cache->cache_content && smartlist_len(wrote)) { @@ -532,7 +550,7 @@ microdesc_check_counts(void) /** Deallocate a single microdescriptor. Note: the microdescriptor MUST have * previously been removed from the cache if it had ever been inserted. */ void -microdesc_free(microdesc_t *md) +microdesc_free_(microdesc_t *md, const char *fname, int lineno) { if (!md) return; @@ -543,12 +561,12 @@ microdesc_free(microdesc_t *md) microdesc_cache_t *cache = get_microdesc_cache(); microdesc_t *md2 = HT_FIND(microdesc_map, &cache->map, md); if (md2 == md) { - log_warn(LD_BUG, "microdesc_free() called, but md was still in " - "microdesc_map"); + log_warn(LD_BUG, "microdesc_free() called from %s:%d, but md was still " + "in microdesc_map", fname, lineno); HT_REMOVE(microdesc_map, &cache->map, md); } else { - log_warn(LD_BUG, "microdesc_free() called with held_in_map set, but " - "microdesc was not in the map."); + log_warn(LD_BUG, "microdesc_free() called from %s:%d with held_in_map " + "set, but microdesc was not in the map.", fname, lineno); } tor_fragile_assert(); } @@ -562,11 +580,13 @@ microdesc_free(microdesc_t *md) } }); if (found) { - log_warn(LD_BUG, "microdesc_free() called, but md was still referenced " - "%d node(s); held_by_nodes == %u", found, md->held_by_nodes); + log_warn(LD_BUG, "microdesc_free() called from %s:%d, but md was still " + "referenced %d node(s); held_by_nodes == %u", + fname, lineno, found, md->held_by_nodes); } else { - log_warn(LD_BUG, "microdesc_free() called with held_by_nodes set to %u, " - "but md was not referenced by any nodes", md->held_by_nodes); + log_warn(LD_BUG, "microdesc_free() called from %s:%d with held_by_nodes " + "set to %u, but md was not referenced by any nodes", + fname, lineno, md->held_by_nodes); } tor_fragile_assert(); } diff --git a/src/or/microdesc.h b/src/or/microdesc.h index 4e58aa33f0..7adb8c68af 100644 --- a/src/or/microdesc.h +++ b/src/or/microdesc.h @@ -39,7 +39,9 @@ smartlist_t *microdesc_list_missing_digest256(networkstatus_t *ns, int downloadable_only, digestmap_t *skip); -void microdesc_free(microdesc_t *md); +void microdesc_free_(microdesc_t *md, const char *fname, int line); +#define microdesc_free(md) \ + microdesc_free_((md), __FILE__, __LINE__) void microdesc_free_all(void); void update_microdesc_downloads(time_t now); diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index c63c76fccd..8846cd0634 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1432,18 +1432,6 @@ consensus_is_waiting_for_certs(void) ? 1 : 0; } -/** Return the network status with a given identity digest. */ -networkstatus_v2_t * -networkstatus_v2_get_by_digest(const char *digest) -{ - SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns, - { - if (tor_memeq(ns->identity_digest, digest, DIGEST_LEN)) - return ns; - }); - return NULL; -} - /** Return the most recent consensus that we have downloaded, or NULL if we * don't have one. */ networkstatus_t * diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h index b64e4b8e1a..761f8e7f0e 100644 --- a/src/or/networkstatus.h +++ b/src/or/networkstatus.h @@ -75,7 +75,6 @@ void update_certificate_downloads(time_t now); int consensus_is_waiting_for_certs(void); int client_would_use_router(const routerstatus_t *rs, time_t now, const or_options_t *options); -networkstatus_v2_t *networkstatus_v2_get_by_digest(const char *digest); networkstatus_t *networkstatus_get_latest_consensus(void); networkstatus_t *networkstatus_get_latest_consensus_by_flavor( consensus_flavor_t f); diff --git a/src/or/nodelist.c b/src/or/nodelist.c index ee1bc392e3..178f084b69 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -688,6 +688,24 @@ node_exit_policy_rejects_all(const node_t *node) return 1; } +/** Return true iff the exit policy for <b>node</b> is such that we can treat + * rejecting an address of type <b>family</b> unexpectedly as a sign of that + * node's failure. */ +int +node_exit_policy_is_exact(const node_t *node, sa_family_t family) +{ + if (family == AF_UNSPEC) { + return 1; /* Rejecting an address but not telling us what address + * is a bad sign. */ + } else if (family == AF_INET) { + return node->ri != NULL; + } else if (family == AF_INET6) { + return 0; + } + tor_fragile_assert(); + return 1; +} + /** Return list of tor_addr_port_t with all OR ports (in the sense IP * addr + TCP port) for <b>node</b>. Caller must free all elements * using tor_free() and free the list using smartlist_free(). @@ -1400,7 +1418,7 @@ get_frac_paths_needed_for_circs(const or_options_t *options, const networkstatus_t *ns) { #define DFLT_PCT_USABLE_NEEDED 60 - if (options->PathsNeededToBuildCircuits >= 1.0) { + if (options->PathsNeededToBuildCircuits >= 0.0) { return options->PathsNeededToBuildCircuits; } else { return networkstatus_get_param(ns, "min_paths_for_circs_pct", diff --git a/src/or/nodelist.h b/src/or/nodelist.h index 65cf0d0284..8a4665a8bf 100644 --- a/src/or/nodelist.h +++ b/src/or/nodelist.h @@ -41,6 +41,7 @@ int node_get_purpose(const node_t *node); (node_get_purpose((node)) == ROUTER_PURPOSE_BRIDGE) int node_is_me(const node_t *node); int node_exit_policy_rejects_all(const node_t *node); +int node_exit_policy_is_exact(const node_t *node, sa_family_t family); smartlist_t *node_get_all_orports(const node_t *node); int node_allows_single_hop_exits(const node_t *node); const char *node_get_nickname(const node_t *node); diff --git a/src/or/or.h b/src/or/or.h index c7d259853b..4e19140b4b 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1417,8 +1417,8 @@ typedef struct or_connection_t { unsigned int is_outgoing:1; unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */ unsigned int wide_circ_ids:1; - uint8_t link_proto; /**< What protocol version are we using? 0 for - * "none negotiated yet." */ + uint16_t link_proto; /**< What protocol version are we using? 0 for + * "none negotiated yet." */ or_handshake_state_t *handshake_state; /**< If we are setting this connection * up, state information to do so. */ @@ -2249,6 +2249,9 @@ typedef struct node_t { /** Local info: we treat this node as if it rejects everything */ unsigned int rejects_all:1; + /** Local info: this node is in our list of guards */ + unsigned int using_as_guard:1; + /* Local info: derived. */ /** True if the IPv6 OR port is preferred over the IPv4 OR port. */ @@ -2942,6 +2945,10 @@ typedef struct origin_circuit_t { */ ENUM_BF(path_state_t) path_state : 3; + /* If this flag is set, we should not consider attaching any more + * connections to this circuit. */ + unsigned int unusable_for_new_conns : 1; + /** * Tristate variable to guard against pathbias miscounting * due to circuit purpose transitions changing the decision @@ -3059,6 +3066,10 @@ typedef struct origin_circuit_t { * ISO_STREAM. */ uint64_t associated_isolated_stream_global_id; /**@}*/ + /** A list of addr_policy_t for this circuit in particular. Used by + * adjust_exit_policy_from_exitpolicy_failure. + */ + smartlist_t *prepend_policy; } origin_circuit_t; struct onion_queue_t; @@ -3868,6 +3879,10 @@ typedef struct { * consensus vote on the 'params' line. */ char *ConsensusParams; + /** Authority only: minimum number of measured bandwidths we must see + * before we only beliee measured bandwidths to assign flags. */ + int MinMeasuredBWsForAuthToIgnoreAdvertised; + /** The length of time that we think an initial consensus should be fresh. * Only altered on testing networks. */ int TestingV3AuthInitialVotingInterval; @@ -3895,6 +3910,12 @@ typedef struct { * of certain configuration options. */ int TestingTorNetwork; + /** Minimum value for the Exit flag threshold on testing networks. */ + uint64_t TestingMinExitFlagThreshold; + + /** Minimum value for the Fast flag threshold on testing networks. */ + uint64_t TestingMinFastFlagThreshold; + /** If true, and we have GeoIP data, and we're a bridge, keep a per-country * count of how many client addresses have contacted us so that we can help * the bridge authority guess which countries have blocked access to us. */ @@ -4012,6 +4033,8 @@ typedef struct { * should guess a suitable value. */ int SSLKeyLifetime; + /** How long (seconds) do we keep a guard before picking a new one? */ + int GuardLifetime; } or_options_t; /** Persistent state for an onion router, as saved to disk. */ @@ -4465,15 +4488,6 @@ typedef struct vote_timing_t { /********************************* geoip.c **************************/ -/** Round all GeoIP results to the next multiple of this value, to avoid - * leaking information. */ -#define DIR_RECORD_USAGE_GRANULARITY 8 -/** Time interval: Flush geoip data to disk this often. */ -#define DIR_ENTRY_RECORD_USAGE_RETAIN_IPS (24*60*60) -/** How long do we have to have observed per-country request history before - * we are willing to talk about it? */ -#define DIR_RECORD_USAGE_MIN_OBSERVATION_TIME (12*60*60) - /** Indicates an action that we might be noting geoip statistics on. * Note that if we're noticing CONNECT, we're a bridge, and if we're noticing * the others, we're not. @@ -4793,6 +4807,10 @@ typedef struct dir_server_t { #define PDS_NO_EXISTING_SERVERDESC_FETCH (1<<3) #define PDS_NO_EXISTING_MICRODESC_FETCH (1<<4) +/** This node is to be chosen as a directory guard, so don't choose any + * node that's currently a guard. */ +#define PDS_FOR_GUARD (1<<5) + #define PDS_PREFER_TUNNELED_DIR_CONNS_ (1<<16) /** Possible ways to weight routers when choosing one randomly. See diff --git a/src/or/policies.c b/src/or/policies.c index 9696b8123b..be4da55061 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -837,6 +837,24 @@ append_exit_policy_string(smartlist_t **policy, const char *more) } } +/** Add "reject <b>addr</b>:*" to <b>dest</b>, creating the list as needed. */ +void +addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr) +{ + addr_policy_t p, *add; + memset(&p, 0, sizeof(p)); + p.policy_type = ADDR_POLICY_REJECT; + p.maskbits = tor_addr_family(addr) == AF_INET6 ? 128 : 32; + tor_addr_copy(&p.addr, addr); + p.prt_min = 1; + p.prt_max = 65535; + + add = addr_policy_get_canonical_entry(&p); + if (!*dest) + *dest = smartlist_new(); + smartlist_add(*dest, add); +} + /** Detect and excise "dead code" from the policy *<b>dest</b>. */ static void exit_policy_remove_redundancies(smartlist_t *dest) diff --git a/src/or/policies.h b/src/or/policies.h index da375c4425..c0e7a9efce 100644 --- a/src/or/policies.h +++ b/src/or/policies.h @@ -47,6 +47,8 @@ int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, int rejectprivate, const char *local_address, int add_default_policy); void policies_exit_policy_append_reject_star(smartlist_t **dest); +void addr_policy_append_reject_addr(smartlist_t **dest, + const tor_addr_t *addr); void policies_set_node_exitpolicy_to_reject_all(node_t *exitrouter); int exit_policy_is_general_exit(smartlist_t *policy); int policy_is_reject_star(const smartlist_t *policy, sa_family_t family); diff --git a/src/or/relay.c b/src/or/relay.c index 9ff9e1e1f4..0ca3e56fd5 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -17,6 +17,7 @@ #include "channel.h" #include "circuitbuild.h" #include "circuitlist.h" +#include "circuituse.h" #include "config.h" #include "connection.h" #include "connection_edge.h" @@ -53,6 +54,10 @@ static int circuit_resume_edge_reading_helper(edge_connection_t *conn, static int circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint); static int circuit_queue_streams_are_blocked(circuit_t *circ); +static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ, + entry_connection_t *conn, + node_t *node, + const tor_addr_t *addr); /** Stop reading on edge connections when we have this many cells * waiting on the appropriate queue. */ @@ -710,7 +715,6 @@ connection_ap_process_end_not_open( relay_header_t *rh, cell_t *cell, origin_circuit_t *circ, entry_connection_t *conn, crypt_path_t *layer_hint) { - struct in_addr in; node_t *exitrouter; int reason = *(cell->payload+RELAY_HEADER_SIZE); int control_reason; @@ -753,10 +757,10 @@ connection_ap_process_end_not_open( stream_end_reason_to_string(reason)); exitrouter = node_get_mutable_by_id(chosen_exit_digest); switch (reason) { - case END_STREAM_REASON_EXITPOLICY: + case END_STREAM_REASON_EXITPOLICY: { + tor_addr_t addr; + tor_addr_make_unspec(&addr); if (rh->length >= 5) { - tor_addr_t addr; - int ttl = -1; tor_addr_make_unspec(&addr); if (rh->length == 5 || rh->length == 9) { @@ -808,16 +812,11 @@ connection_ap_process_end_not_open( } } /* check if he *ought* to have allowed it */ - if (exitrouter && - (rh->length < 5 || - (tor_inet_aton(conn->socks_request->address, &in) && - !conn->chosen_exit_name))) { - log_info(LD_APP, - "Exitrouter %s seems to be more restrictive than its exit " - "policy. Not using this router as exit for now.", - node_describe(exitrouter)); - policies_set_node_exitpolicy_to_reject_all(exitrouter); - } + + adjust_exit_policy_from_exitpolicy_failure(circ, + conn, + exitrouter, + &addr); if (conn->chosen_exit_optional || conn->chosen_exit_retries) { @@ -837,6 +836,7 @@ connection_ap_process_end_not_open( return 0; /* else, conn will get closed below */ break; + } case END_STREAM_REASON_CONNECTREFUSED: if (!conn->chosen_exit_optional) break; /* break means it'll close, below */ @@ -851,9 +851,7 @@ connection_ap_process_end_not_open( /* We haven't retried too many times; reattach the connection. */ circuit_log_path(LOG_INFO,LD_APP,circ); /* Mark this circuit "unusable for new streams". */ - /* XXXX024 this is a kludgy way to do this. */ - tor_assert(circ->base_.timestamp_dirty); - circ->base_.timestamp_dirty -= get_options()->MaxCircuitDirtiness; + mark_circuit_unusable_for_new_conns(circ); if (conn->chosen_exit_optional) { /* stop wanting a specific exit */ @@ -901,6 +899,47 @@ connection_ap_process_end_not_open( return 0; } +/** Called when we have gotten an END_REASON_EXITPOLICY failure on <b>circ</b> + * for <b>conn</b>, while attempting to connect via <b>node</b>. If the node + * told us which address it rejected, then <b>addr</b> is that address; + * otherwise it is AF_UNSPEC. + * + * If we are sure the node should have allowed this address, mark the node as + * having a reject *:* exit policy. Otherwise, mark the circuit as unusable + * for this particular address. + **/ +static void +adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ, + entry_connection_t *conn, + node_t *node, + const tor_addr_t *addr) +{ + int make_reject_all = 0; + const sa_family_t family = tor_addr_family(addr); + + if (node) { + tor_addr_t tmp; + int asked_for_family = tor_addr_parse(&tmp, conn->socks_request->address); + if (family == AF_UNSPEC) { + make_reject_all = 1; + } else if (node_exit_policy_is_exact(node, family) && + asked_for_family != -1 && !conn->chosen_exit_name) { + make_reject_all = 1; + } + + if (make_reject_all) { + log_info(LD_APP, + "Exitrouter %s seems to be more restrictive than its exit " + "policy. Not using this router as exit for now.", + node_describe(node)); + policies_set_node_exitpolicy_to_reject_all(node); + } + } + + if (family != AF_UNSPEC) + addr_policy_append_reject_addr(&circ->prepend_policy, addr); +} + /** Helper: change the socks_request->address field on conn to the * dotted-quad representation of <b>new_addr</b>, * and send an appropriate REMAP event. */ @@ -1101,12 +1140,15 @@ connection_edge_process_relay_cell_not_open( 2+answer_len)); else ttl = -1; - if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { - uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+2)); - if (get_options()->ClientDNSRejectInternalAddresses && - is_internal_IP(addr, 0)) { + if (answer_type == RESOLVED_TYPE_IPV4 || + answer_type == RESOLVED_TYPE_IPV6) { + tor_addr_t addr; + if (decode_address_from_payload(&addr, cell->payload+RELAY_HEADER_SIZE, + rh->length) && + tor_addr_is_internal(&addr, 0) && + get_options()->ClientDNSRejectInternalAddresses) { log_info(LD_APP,"Got a resolve with answer %s. Rejecting.", - fmt_addr32(addr)); + fmt_addr(&addr)); connection_ap_handshake_socks_resolved(entry_conn, RESOLVED_TYPE_ERROR_TRANSIENT, 0, NULL, 0, TIME_MAX); @@ -1398,6 +1440,14 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, "'truncate' unsupported at origin. Dropping."); return 0; } + if (circ->n_hop) { + if (circ->n_chan) + log_warn(LD_BUG, "n_chan and n_hop set on the same circuit!"); + extend_info_free(circ->n_hop); + circ->n_hop = NULL; + tor_free(circ->n_chan_create_cell); + circuit_set_state(circ, CIRCUIT_STATE_OPEN); + } if (circ->n_chan) { uint8_t trunc_reason = get_uint8(cell->payload + RELAY_HEADER_SIZE); circuit_clear_cell_queue(circ, circ->n_chan); diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index 79c1a724e4..2cfc364c3b 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -1452,13 +1452,6 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint, command); } -/** Return the number of entries in our rendezvous descriptor cache. */ -int -rend_cache_size(void) -{ - return strmap_size(rend_cache); -} - /** Allocate and return a new rend_data_t with the same * contents as <b>query</b>. */ rend_data_t * diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h index 189891b747..f476593d2b 100644 --- a/src/or/rendcommon.h +++ b/src/or/rendcommon.h @@ -49,7 +49,6 @@ int rend_cache_store(const char *desc, size_t desc_len, int published, int rend_cache_store_v2_desc_as_client(const char *desc, const rend_data_t *rend_query); int rend_cache_store_v2_desc_as_dir(const char *desc); -int rend_cache_size(void); int rend_encode_v2_descriptors(smartlist_t *descs_out, rend_service_descriptor_t *desc, time_t now, uint8_t period, rend_auth_type_t auth_type, diff --git a/src/or/router.c b/src/or/router.c index 422fe5db2e..c8c9ce1a4f 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -2983,23 +2983,6 @@ router_get_verbose_nickname(char *buf, const routerinfo_t *router) strlcpy(buf+1+HEX_DIGEST_LEN+1, router->nickname, MAX_NICKNAME_LEN+1); } -/** Set <b>buf</b> (which must have MAX_VERBOSE_NICKNAME_LEN+1 bytes) to the - * verbose representation of the identity of <b>router</b>. The format is: - * A dollar sign. - * The upper-case hexadecimal encoding of the SHA1 hash of router's identity. - * A "=" if the router is named; a "~" if it is not. - * The router's nickname. - **/ -void -routerstatus_get_verbose_nickname(char *buf, const routerstatus_t *router) -{ - buf[0] = '$'; - base16_encode(buf+1, HEX_DIGEST_LEN+1, router->identity_digest, - DIGEST_LEN); - buf[1+HEX_DIGEST_LEN] = router->is_named ? '=' : '~'; - strlcpy(buf+1+HEX_DIGEST_LEN+1, router->nickname, MAX_NICKNAME_LEN+1); -} - /** Forget that we have issued any router-related warnings, so that we'll * warn again if we see the same errors. */ void diff --git a/src/or/router.h b/src/or/router.h index fd2076af01..96749b53c0 100644 --- a/src/or/router.h +++ b/src/or/router.h @@ -132,8 +132,6 @@ const char *routerstatus_describe(const routerstatus_t *ri); const char *extend_info_describe(const extend_info_t *ei); void router_get_verbose_nickname(char *buf, const routerinfo_t *router); -void routerstatus_get_verbose_nickname(char *buf, - const routerstatus_t *router); void router_reset_warnings(void); void router_reset_reachability(void); void router_free_all(void); diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 2f08167f18..0c978e9d00 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -54,8 +54,6 @@ static const routerstatus_t *router_pick_dirserver_generic( smartlist_t *sourcelist, dirinfo_type_t type, int flags); static void mark_all_dirservers_up(smartlist_t *server_list); -static int router_nickname_matches(const routerinfo_t *router, - const char *nickname); static void dir_server_free(dir_server_t *ds); static int signed_desc_digest_is_recognized(signed_descriptor_t *desc); static const char *signed_descriptor_get_body_impl( @@ -339,7 +337,6 @@ trusted_dirs_remove_old_certs(void) time_t now = time(NULL); #define DEAD_CERT_LIFETIME (2*24*60*60) #define OLD_CERT_LIFETIME (7*24*60*60) -#define CERT_EXPIRY_SKEW (60*60) if (!trusted_dir_certs) return; @@ -1153,6 +1150,7 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags) int requireother = ! (flags & PDS_ALLOW_SELF); int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL); int prefer_tunnel = (flags & PDS_PREFER_TUNNELED_DIR_CONNS_); + int for_guard = (flags & PDS_FOR_GUARD); int try_excluding = 1, n_excluded = 0; if (!consensus) @@ -1192,6 +1190,8 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags) if ((type & MICRODESC_DIRINFO) && !is_trusted && !node->rs->version_supports_microdesc_cache) continue; + if (for_guard && node->using_as_guard) + continue; /* Don't make the same node a guard twice. */ if (try_excluding && routerset_contains_routerstatus(options->ExcludeNodes, status, country)) { @@ -1462,30 +1462,6 @@ routerlist_add_node_and_family(smartlist_t *sl, const routerinfo_t *router) nodelist_add_node_and_family(sl, node); } -/** Return 1 iff any member of the (possibly NULL) comma-separated list - * <b>list</b> is an acceptable nickname or hexdigest for <b>router</b>. Else - * return 0. - */ -int -router_nickname_is_in_list(const routerinfo_t *router, const char *list) -{ - smartlist_t *nickname_list; - int v = 0; - - if (!list) - return 0; /* definitely not */ - tor_assert(router); - - nickname_list = smartlist_new(); - smartlist_split_string(nickname_list, list, ",", - SPLIT_SKIP_SPACE|SPLIT_STRIP_SPACE|SPLIT_IGNORE_BLANK, 0); - SMARTLIST_FOREACH(nickname_list, const char *, cp, - if (router_nickname_matches(router, cp)) {v=1;break;}); - SMARTLIST_FOREACH(nickname_list, char *, cp, tor_free(cp)); - smartlist_free(nickname_list); - return v; -} - /** Add every suitable node from our nodelist to <b>sl</b>, so that * we can pick a node for a circuit. */ @@ -2312,18 +2288,6 @@ router_hex_digest_matches(const routerinfo_t *router, const char *hexdigest) router_is_named(router)); } -/** Return true if <b>router</b>'s nickname matches <b>nickname</b> - * (case-insensitive), or if <b>router's</b> identity key digest - * matches a hexadecimal value stored in <b>nickname</b>. Return - * false otherwise. */ -static int -router_nickname_matches(const routerinfo_t *router, const char *nickname) -{ - if (nickname[0]!='$' && !strcasecmp(router->nickname, nickname)) - return 1; - return router_hex_digest_matches(router, nickname); -} - /** Return true iff <b>digest</b> is the digest of the identity key of a * trusted directory matching at least one bit of <b>type</b>. If <b>type</b> * is zero, any authority is okay. */ @@ -4052,17 +4016,6 @@ clear_dir_servers(void) router_dir_info_changed(); } -/** Return 1 if any trusted dir server supports v1 directories, - * else return 0. */ -int -any_trusted_dir_is_v1_authority(void) -{ - if (trusted_dir_servers) - return get_n_authorities(V1_DIRINFO) > 0; - - return 0; -} - /** For every current directory connection whose purpose is <b>purpose</b>, * and where the resource being downloaded begins with <b>prefix</b>, split * rest of the resource into base16 fingerprints (or base64 fingerprints if diff --git a/src/or/routerlist.h b/src/or/routerlist.h index 1849fff31c..28b2f58935 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -42,7 +42,6 @@ int router_get_my_share_of_directory_requests(double *v2_share_out, double *v3_share_out); void router_reset_status_download_failures(void); int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2); -int router_nickname_is_in_list(const routerinfo_t *router, const char *list); const routerinfo_t *routerlist_find_my_routerinfo(void); uint32_t router_get_advertised_bandwidth(const routerinfo_t *router); uint32_t router_get_advertised_bandwidth_capped(const routerinfo_t *router); @@ -146,7 +145,6 @@ void dir_server_add(dir_server_t *ent); void authority_cert_free(authority_cert_t *cert); void clear_dir_servers(void); -int any_trusted_dir_is_v1_authority(void); void update_consensus_router_descriptor_downloads(time_t now, int is_vote, networkstatus_t *consensus); void update_router_descriptor_downloads(time_t now); diff --git a/src/or/routerparse.c b/src/or/routerparse.c index ce2cd5c513..f8edb8407c 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -1953,7 +1953,7 @@ routerstatus_parse_entry_from_string(memarea_t *area, rs->version_supports_optimistic_data = tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha"); rs->version_supports_extend2_cells = - tor_version_as_new_as(tok->args[0], "0.2.4.7-alpha"); + tor_version_as_new_as(tok->args[0], "0.2.4.8-alpha"); } if (vote_rs) { vote_rs->version = tor_strdup(tok->args[0]); @@ -2030,7 +2030,7 @@ routerstatus_parse_entry_from_string(memarea_t *area, } } else { log_info(LD_BUG, "Found an entry in networkstatus with no " - "microdescriptor digest. (Router %s=%s at %s:%d.)", + "microdescriptor digest. (Router %s ($%s) at %s:%d.)", rs->nickname, hex_str(rs->identity_digest, DIGEST_LEN), fmt_addr32(rs->addr), rs->or_port); } @@ -2257,7 +2257,7 @@ networkstatus_v2_parse_from_string(const char *s) /** Verify the bandwidth weights of a network status document */ int -networkstatus_verify_bw_weights(networkstatus_t *ns) +networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) { int64_t weight_scale; int64_t G=0, M=0, E=0, D=0, T=0; @@ -2343,14 +2343,21 @@ networkstatus_verify_bw_weights(networkstatus_t *ns) // Then, gather G, M, E, D, T to determine case SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { + int is_exit = 0; + if (consensus_method >= MIN_METHOD_TO_CUT_BADEXIT_WEIGHT) { + /* Bug #2203: Don't count bad exits as exits for balancing */ + is_exit = rs->is_exit && !rs->is_bad_exit; + } else { + is_exit = rs->is_exit; + } if (rs->has_bandwidth) { T += rs->bandwidth; - if (rs->is_exit && rs->is_possible_guard) { + if (is_exit && rs->is_possible_guard) { D += rs->bandwidth; Gtotal += Wgd*rs->bandwidth; Mtotal += Wmd*rs->bandwidth; Etotal += Wed*rs->bandwidth; - } else if (rs->is_exit) { + } else if (is_exit) { E += rs->bandwidth; Mtotal += Wme*rs->bandwidth; Etotal += Wee*rs->bandwidth; diff --git a/src/or/routerparse.h b/src/or/routerparse.h index 859a691e2a..7bf7d79073 100644 --- a/src/or/routerparse.h +++ b/src/or/routerparse.h @@ -54,7 +54,7 @@ void dump_distinct_digest_count(int severity); int compare_routerstatus_entries(const void **_a, const void **_b); int compare_vote_routerstatus_entries(const void **_a, const void **_b); networkstatus_v2_t *networkstatus_v2_parse_from_string(const char *s); -int networkstatus_verify_bw_weights(networkstatus_t *ns); +int networkstatus_verify_bw_weights(networkstatus_t *ns, int); networkstatus_t *networkstatus_parse_vote_from_string(const char *s, const char **eos_out, networkstatus_type_t ns_type); diff --git a/src/or/status.c b/src/or/status.c index 126167dcb9..e44de635cb 100644 --- a/src/or/status.c +++ b/src/or/status.c @@ -85,6 +85,7 @@ log_heartbeat(time_t now) char *bw_rcvd = NULL; char *uptime = NULL; const routerinfo_t *me; + double r = tls_get_write_overhead_ratio(); const or_options_t *options = get_options(); (void)now; @@ -112,6 +113,11 @@ log_heartbeat(time_t now) 100*(U64_TO_DBL(stats_n_data_bytes_packaged) / U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) ); + if (r > 1.0) { + double overhead = ( r - 1.0 ) * 100.0; + log_notice(LD_HEARTBEAT, "TLS write overhead: %.f%%", overhead); + } + tor_free(uptime); tor_free(bw_sent); tor_free(bw_rcvd); diff --git a/src/or/transports.c b/src/or/transports.c index 945d422f34..b5a00c90ec 100644 --- a/src/or/transports.c +++ b/src/or/transports.c @@ -124,10 +124,6 @@ static INLINE void free_execve_args(char **arg); #define PROTO_CMETHODS_DONE "CMETHODS DONE" #define PROTO_SMETHODS_DONE "SMETHODS DONE" -/** Number of environment variables for managed proxy clients/servers. */ -#define ENVIRON_SIZE_CLIENT 3 -#define ENVIRON_SIZE_SERVER 7 /* XXX known to be too high, but that's ok */ - /** The first and only supported - at the moment - configuration protocol version. */ #define PROTO_VERSION_ONE 1 |