diff options
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/circuitbuild.c | 291 | ||||
-rw-r--r-- | src/or/circuitbuild.h | 1 | ||||
-rw-r--r-- | src/or/circuituse.c | 4 | ||||
-rw-r--r-- | src/or/connection_edge.c | 104 | ||||
-rw-r--r-- | src/or/connection_edge.h | 5 | ||||
-rw-r--r-- | src/or/control.c | 4 | ||||
-rw-r--r-- | src/or/main.c | 24 | ||||
-rw-r--r-- | src/or/or.h | 5 | ||||
-rw-r--r-- | src/or/relay.c | 2 | ||||
-rw-r--r-- | src/or/rephist.c | 14 |
10 files changed, 350 insertions, 104 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 3ab72e4b82..fa99a49489 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -156,6 +156,11 @@ circuit_build_times_disabled(void) state_disabled); return 1; } else { + log_debug(LD_BUG, + "CircuitBuildTime learning is not disabled. " + "Consensus=%d, Config=%d, AuthDir=%d, StateFile=%d", + consensus_disabled, config_disabled, dirauth_disabled, + state_disabled); return 0; } } @@ -171,10 +176,21 @@ circuit_build_times_disabled(void) static int32_t circuit_build_times_max_timeouts(void) { - return networkstatus_get_param(NULL, "cbtmaxtimeouts", + int32_t cbt_maxtimeouts; + + cbt_maxtimeouts = networkstatus_get_param(NULL, "cbtmaxtimeouts", CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT, CBT_MIN_MAX_RECENT_TIMEOUT_COUNT, CBT_MAX_MAX_RECENT_TIMEOUT_COUNT); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_max_timeouts() called, cbtmaxtimeouts is" + " %d", + cbt_maxtimeouts); + } + + return cbt_maxtimeouts; } /** @@ -193,6 +209,14 @@ circuit_build_times_default_num_xm_modes(void) CBT_DEFAULT_NUM_XM_MODES, CBT_MIN_NUM_XM_MODES, CBT_MAX_NUM_XM_MODES); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_default_num_xm_modes() called, cbtnummodes" + " is %d", + num); + } + return num; } @@ -209,6 +233,14 @@ circuit_build_times_min_circs_to_observe(void) CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE, CBT_MIN_MIN_CIRCUITS_TO_OBSERVE, CBT_MAX_MIN_CIRCUITS_TO_OBSERVE); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_min_circs_to_observe() called, cbtmincircs" + " is %d", + num); + } + return num; } @@ -233,6 +265,14 @@ circuit_build_times_quantile_cutoff(void) CBT_DEFAULT_QUANTILE_CUTOFF, CBT_MIN_QUANTILE_CUTOFF, CBT_MAX_QUANTILE_CUTOFF); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_quantile_cutoff() called, cbtquantile" + " is %d", + num); + } + return num/100.0; } @@ -263,6 +303,13 @@ circuit_build_times_close_quantile(void) CBT_DEFAULT_CLOSE_QUANTILE, CBT_MIN_CLOSE_QUANTILE, CBT_MAX_CLOSE_QUANTILE); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_close_quantile() called, cbtclosequantile" + " is %d", param); + } + if (param < min) { log_warn(LD_DIR, "Consensus parameter cbtclosequantile is " "too small, raising to %d", min); @@ -285,6 +332,13 @@ circuit_build_times_test_frequency(void) CBT_DEFAULT_TEST_FREQUENCY, CBT_MIN_TEST_FREQUENCY, CBT_MAX_TEST_FREQUENCY); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_test_frequency() called, cbttestfreq is %d", + num); + } + return num; } @@ -302,6 +356,13 @@ circuit_build_times_min_timeout(void) CBT_DEFAULT_TIMEOUT_MIN_VALUE, CBT_MIN_TIMEOUT_MIN_VALUE, CBT_MAX_TIMEOUT_MIN_VALUE); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_min_timeout() called, cbtmintimeout is %d", + num); + } + return num; } @@ -319,6 +380,14 @@ circuit_build_times_initial_timeout(void) CBT_DEFAULT_TIMEOUT_INITIAL_VALUE, CBT_MIN_TIMEOUT_INITIAL_VALUE, CBT_MAX_TIMEOUT_INITIAL_VALUE); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_initial_timeout() called, " + "cbtinitialtimeout is %d", + param); + } + if (param < min) { log_warn(LD_DIR, "Consensus parameter cbtinitialtimeout is too small, " "raising to %d", min); @@ -337,10 +406,20 @@ circuit_build_times_initial_timeout(void) static int32_t circuit_build_times_recent_circuit_count(networkstatus_t *ns) { - return networkstatus_get_param(ns, "cbtrecentcount", - CBT_DEFAULT_RECENT_CIRCUITS, - CBT_MIN_RECENT_CIRCUITS, - CBT_MAX_RECENT_CIRCUITS); + int32_t num; + num = networkstatus_get_param(ns, "cbtrecentcount", + CBT_DEFAULT_RECENT_CIRCUITS, + CBT_MIN_RECENT_CIRCUITS, + CBT_MAX_RECENT_CIRCUITS); + + if (!(get_options()->LearnCircuitBuildTimeout)) { + log_debug(LD_BUG, + "circuit_build_times_recent_circuit_count() called, " + "cbtrecentcount is %d", + num); + } + + return num; } /** @@ -353,41 +432,79 @@ void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, networkstatus_t *ns) { - int32_t num = circuit_build_times_recent_circuit_count(ns); + int32_t num; + + /* + * First check if we're doing adaptive timeouts at all; nothing to + * update if we aren't. + */ - if (num > 0 && num != cbt->liveness.num_recent_circs) { - int8_t *recent_circs; - log_notice(LD_CIRC, "The Tor Directory Consensus has changed how many " - "circuits we must track to detect network failures from %d " - "to %d.", cbt->liveness.num_recent_circs, num); + if (!circuit_build_times_disabled()) { + num = circuit_build_times_recent_circuit_count(ns); - tor_assert(cbt->liveness.timeouts_after_firsthop); + if (num > 0) { + if (num != cbt->liveness.num_recent_circs) { + int8_t *recent_circs; + log_notice(LD_CIRC, "The Tor Directory Consensus has changed how many " + "circuits we must track to detect network failures from %d " + "to %d.", cbt->liveness.num_recent_circs, num); + + tor_assert(cbt->liveness.timeouts_after_firsthop || + cbt->liveness.num_recent_circs == 0); + + /* + * Technically this is a circular array that we are reallocating + * and memcopying. However, since it only consists of either 1s + * or 0s, and is only used in a statistical test to determine when + * we should discard our history after a sufficient number of 1's + * have been reached, it is fine if order is not preserved or + * elements are lost. + * + * cbtrecentcount should only be changing in cases of severe network + * distress anyway, so memory correctness here is paramount over + * doing acrobatics to preserve the array. + */ + recent_circs = tor_malloc_zero(sizeof(int8_t)*num); + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop, + sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs)); + } + + // Adjust the index if it needs it. + if (num < cbt->liveness.num_recent_circs) { + cbt->liveness.after_firsthop_idx = MIN(num-1, + cbt->liveness.after_firsthop_idx); + } + + tor_free(cbt->liveness.timeouts_after_firsthop); + cbt->liveness.timeouts_after_firsthop = recent_circs; + cbt->liveness.num_recent_circs = num; + } + /* else no change, nothing to do */ + } else { /* num == 0 */ + /* + * Weird. This probably shouldn't happen, so log a warning, but try + * to do something sensible anyway. + */ + log_warn(LD_CIRC, + "The cbtrecentcircs consensus parameter came back zero! " + "This disables adaptive timeouts since we can't keep track of " + "any recent circuits."); + + circuit_build_times_free_timeouts(cbt); + } + } else { /* - * Technically this is a circular array that we are reallocating - * and memcopying. However, since it only consists of either 1s - * or 0s, and is only used in a statistical test to determine when - * we should discard our history after a sufficient number of 1's - * have been reached, it is fine if order is not preserved or - * elements are lost. - * - * cbtrecentcount should only be changing in cases of severe network - * distress anyway, so memory correctness here is paramount over - * doing acrobatics to preserve the array. + * Adaptive timeouts are disabled; this might be because of the + * LearnCircuitBuildTimes config parameter, and hence permanent, or + * the cbtdisabled consensus parameter, so it may be a new condition. + * Treat it like getting num == 0 above and free the circuit history + * if we have any. */ - recent_circs = tor_malloc_zero(sizeof(int8_t)*num); - memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop, - sizeof(int8_t)*MIN(num, cbt->liveness.num_recent_circs)); - - // Adjust the index if it needs it. - if (num < cbt->liveness.num_recent_circs) { - cbt->liveness.after_firsthop_idx = MIN(num-1, - cbt->liveness.after_firsthop_idx); - } - tor_free(cbt->liveness.timeouts_after_firsthop); - cbt->liveness.timeouts_after_firsthop = recent_circs; - cbt->liveness.num_recent_circs = num; + circuit_build_times_free_timeouts(cbt); } } @@ -406,16 +523,26 @@ static double circuit_build_times_get_initial_timeout(void) { double timeout; - 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(); + + /* + * 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(); } } else { - timeout = circuit_build_times_initial_timeout(); + timeout = get_options()->CircuitBuildTimeout*1000; } + return timeout; } @@ -444,14 +571,40 @@ void circuit_build_times_init(circuit_build_times_t *cbt) { memset(cbt, 0, sizeof(*cbt)); - cbt->liveness.num_recent_circs = + /* + * Check if we really are using adaptive timeouts, and don't keep + * track of this stuff if not. + */ + if (!circuit_build_times_disabled()) { + cbt->liveness.num_recent_circs = circuit_build_times_recent_circuit_count(NULL); - cbt->liveness.timeouts_after_firsthop = tor_malloc_zero(sizeof(int8_t)* - cbt->liveness.num_recent_circs); + cbt->liveness.timeouts_after_firsthop = + tor_malloc_zero(sizeof(int8_t)*cbt->liveness.num_recent_circs); + } else { + cbt->liveness.num_recent_circs = 0; + cbt->liveness.timeouts_after_firsthop = NULL; + } cbt->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout(); control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET); } +/** + * Free the saved timeouts, if the cbtdisabled consensus parameter got turned + * on or something. + */ + +void +circuit_build_times_free_timeouts(circuit_build_times_t *cbt) +{ + if (!cbt) return; + + if (cbt->liveness.timeouts_after_firsthop) { + tor_free(cbt->liveness.timeouts_after_firsthop); + } + + cbt->liveness.num_recent_circs = 0; +} + #if 0 /** * Rewind our build time history by n positions. @@ -1134,9 +1287,14 @@ circuit_build_times_network_is_live(circuit_build_times_t *cbt) void circuit_build_times_network_circ_success(circuit_build_times_t *cbt) { - cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] = 0; - cbt->liveness.after_firsthop_idx++; - cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; + /* Check for NULLness because we might not be using adaptive timeouts */ + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] + = 0; + cbt->liveness.after_firsthop_idx++; + cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; + } } /** @@ -1151,10 +1309,15 @@ static void circuit_build_times_network_timeout(circuit_build_times_t *cbt, int did_onehop) { - if (did_onehop) { - cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx]=1; - cbt->liveness.after_firsthop_idx++; - cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; + /* Check for NULLness because we might not be using adaptive timeouts */ + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + if (did_onehop) { + cbt->liveness.timeouts_after_firsthop[cbt->liveness.after_firsthop_idx] + = 1; + cbt->liveness.after_firsthop_idx++; + cbt->liveness.after_firsthop_idx %= cbt->liveness.num_recent_circs; + } } } @@ -1240,10 +1403,13 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt) int timeout_count=0; int i; - /* how many of our recent circuits made it to the first hop but then - * timed out? */ - for (i = 0; i < cbt->liveness.num_recent_circs; i++) { - timeout_count += cbt->liveness.timeouts_after_firsthop[i]; + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + /* how many of our recent circuits made it to the first hop but then + * timed out? */ + for (i = 0; i < cbt->liveness.num_recent_circs; i++) { + timeout_count += cbt->liveness.timeouts_after_firsthop[i]; + } } /* If 80% of our recent circuits are timing out after the first hop, @@ -1253,9 +1419,12 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt) } circuit_build_times_reset(cbt); - memset(cbt->liveness.timeouts_after_firsthop, 0, - sizeof(*cbt->liveness.timeouts_after_firsthop)* - cbt->liveness.num_recent_circs); + if (cbt->liveness.timeouts_after_firsthop && + cbt->liveness.num_recent_circs > 0) { + memset(cbt->liveness.timeouts_after_firsthop, 0, + sizeof(*cbt->liveness.timeouts_after_firsthop)* + cbt->liveness.num_recent_circs); + } cbt->liveness.after_firsthop_idx = 0; /* Check to see if this has happened before. If so, double the timeout @@ -1436,6 +1605,12 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt) long prev_timeout = tor_lround(cbt->timeout_ms/1000); double timeout_rate; + /* + * Just return if we aren't using adaptive timeouts + */ + if (circuit_build_times_disabled()) + return; + if (!circuit_build_times_set_timeout_worker(cbt)) return; diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 5b77399030..92811783d3 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -121,6 +121,7 @@ int circuit_build_times_needs_circuits(circuit_build_times_t *cbt); int circuit_build_times_needs_circuits_now(circuit_build_times_t *cbt); void circuit_build_times_init(circuit_build_times_t *cbt); +void circuit_build_times_free_timeouts(circuit_build_times_t *cbt); void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt, networkstatus_t *ns); double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt); diff --git a/src/or/circuituse.c b/src/or/circuituse.c index f43ce19c83..7532c4e923 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -746,6 +746,7 @@ circuit_predict_and_launch_new(void) * want, don't do another -- we want to leave a few slots open so * we can still build circuits preemptively as needed. */ if (num < MAX_UNUSED_OPEN_CIRCUITS-2 && + get_options()->LearnCircuitBuildTimeout && circuit_build_times_needs_circuits_now(&circ_times)) { flags = CIRCLAUNCH_NEED_CAPACITY; log_info(LD_CIRC, @@ -881,7 +882,8 @@ circuit_expire_old_circuits_clientside(void) tor_gettimeofday(&now); cutoff = now; - if (circuit_build_times_needs_circuits(&circ_times)) { + if (get_options()->LearnCircuitBuildTimeout && + circuit_build_times_needs_circuits(&circ_times)) { /* Circuits should be shorter lived if we need more of them * for learning a good build timeout */ cutoff.tv_sec -= IDLE_TIMEOUT_WHILE_LEARNING; diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 63a3213d38..eae19bad47 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -1095,13 +1095,22 @@ addressmap_match_superdomains(char *address) * address changed; false otherwise. Set *<b>expires_out</b> to the * expiry time of the result, or to <b>time_max</b> if the result does * not expire. + * + * If <b>exit_source_out</b> is non-null, we set it as follows. If we the + * address starts out as a non-exit address, and we remap it to an .exit + * address at any point, then set *<b>exit_source_out</b> to the + * address_entry_source_t of the first such rule. Set *<b>exit_source_out</b> + * to ADDRMAPSRC_NONE if there is no such rewrite. + * */ int -addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out) +addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out, + addressmap_entry_source_t *exit_source_out) { addressmap_entry_t *ent; int rewrites; time_t expires = TIME_MAX; + addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE; for (rewrites = 0; rewrites < 16; rewrites++) { int exact_match = 0; @@ -1117,9 +1126,7 @@ addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out) /* This is a rule like *.example.com example.com, and we just got * "example.com" */ tor_free(addr_orig); - if (expires_out) - *expires_out = expires; - return rewrites > 0; + goto done; } exact_match = 1; @@ -1127,9 +1134,7 @@ addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out) if (!ent || !ent->new_address) { tor_free(addr_orig); - if (expires_out) - *expires_out = expires; - return (rewrites > 0); /* done, no rewrite needed */ + goto done; } if (ent->dst_wildcard && !exact_match) { @@ -1139,6 +1144,12 @@ addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out) strlcpy(address, ent->new_address, maxlen); } + if (!strcmpend(address, ".exit") && + strcmpend(addr_orig, ".exit") && + exit_source == ADDRMAPSRC_NONE) { + exit_source = ent->source; + } + log_info(LD_APP, "Addressmap: rewriting %s to %s", addr_orig, escaped_safe_str_client(address)); if (ent->expires > 1 && ent->expires < expires) @@ -1149,9 +1160,13 @@ addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out) "Loop detected: we've rewritten %s 16 times! Using it as-is.", escaped_safe_str_client(address)); /* it's fine to rewrite a rewrite, but don't loop forever */ + + done: + if (exit_source_out) + *exit_source_out = exit_source; if (expires_out) *expires_out = TIME_MAX; - return 1; + return (rewrites > 0); } /** If we have a cached reverse DNS entry for the address stored in the @@ -1782,11 +1797,9 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, int automap = 0; char orig_address[MAX_SOCKS_ADDR_LEN]; time_t map_expires = TIME_MAX; - /* This will be set to true iff the address starts out as a non-.exit - address, and we remap it to one because of an entry in the addressmap. */ - int remapped_to_exit = 0; time_t now = time(NULL); connection_t *base_conn = ENTRY_TO_CONN(conn); + addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE; tor_strlower(socks->address); /* normalize it */ strlcpy(orig_address, socks->address, sizeof(orig_address)); @@ -1794,6 +1807,16 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, safe_str_client(socks->address), socks->port); + if (!strcmpend(socks->address, ".exit") && !options->AllowDotExit) { + log_warn(LD_APP, "The \".exit\" notation is disabled in Tor due to " + "security risks. Set AllowDotExit in your torrc to enable " + "it (at your own risk)."); + control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", + escaped(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + if (! conn->original_dest_address) conn->original_dest_address = tor_strdup(conn->socks_request->address); @@ -1854,16 +1877,11 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, } } } else if (!automap) { - int started_without_chosen_exit = strcasecmpend(socks->address, ".exit"); /* For address map controls, remap the address. */ if (addressmap_rewrite(socks->address, sizeof(socks->address), - &map_expires)) { + &map_expires, &exit_source)) { control_event_stream_status(conn, STREAM_EVENT_REMAP, REMAP_STREAM_SOURCE_CACHE); - if (started_without_chosen_exit && - !strcasecmpend(socks->address, ".exit") && - map_expires < TIME_MAX) - remapped_to_exit = 1; } } @@ -1882,8 +1900,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, /* Parse the address provided by SOCKS. Modify it in-place if it * specifies a hidden-service (.onion) or particular exit node (.exit). */ - addresstype = parse_extended_hostname(socks->address, - remapped_to_exit || options->AllowDotExit); + addresstype = parse_extended_hostname(socks->address); if (addresstype == BAD_HOSTNAME) { control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", @@ -1902,14 +1919,42 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, options->_ExcludeExitNodesUnion : options->ExcludeExitNodes; const node_t *node; + if (exit_source == ADDRMAPSRC_AUTOMAP && !options->AllowDotExit) { + /* Whoops; this one is stale. It must have gotten added earlier, + * when AllowDotExit was on. */ + log_warn(LD_APP,"Stale automapped address for '%s.exit', with " + "AllowDotExit disabled. Refusing.", + safe_str_client(socks->address)); + control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", + escaped(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + + if (exit_source == ADDRMAPSRC_DNS || + (exit_source == ADDRMAPSRC_NONE && !options->AllowDotExit)) { + /* It shouldn't be possible to get a .exit address from any of these + * sources. */ + log_warn(LD_BUG,"Address '%s.exit', with impossible source for the " + ".exit part. Refusing.", + safe_str_client(socks->address)); + control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s", + escaped(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL); + return -1; + } + tor_assert(!automap); if (s) { /* The address was of the form "(stuff).(name).exit */ if (s[1] != '\0') { conn->chosen_exit_name = tor_strdup(s+1); node = node_get_by_nickname(conn->chosen_exit_name, 1); - if (remapped_to_exit) /* 5 tries before it expires the addressmap */ + + if (exit_source == ADDRMAPSRC_TRACKEXIT) { + /* We 5 tries before it expires the addressmap */ conn->chosen_exit_retries = TRACKHOSTEXITS_RETRIES; + } *s = 0; } else { /* Oops, the address was (stuff)..exit. That's not okay. */ @@ -3427,17 +3472,14 @@ connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit) * If address is of the form "y.onion" with a badly-formed handle y: * Return BAD_HOSTNAME and log a message. * - * If address is of the form "y.exit" and <b>allowdotexit</b> is true: + * If address is of the form "y.exit": * Put a NUL after y and return EXIT_HOSTNAME. * - * If address is of the form "y.exit" and <b>allowdotexit</b> is false: - * Return BAD_HOSTNAME and log a message. - * * Otherwise: * Return NORMAL_HOSTNAME and change nothing. */ hostname_type_t -parse_extended_hostname(char *address, int allowdotexit) +parse_extended_hostname(char *address) { char *s; char query[REND_SERVICE_ID_LEN_BASE32+1]; @@ -3446,16 +3488,8 @@ parse_extended_hostname(char *address, int allowdotexit) if (!s) return NORMAL_HOSTNAME; /* no dot, thus normal */ if (!strcmp(s+1,"exit")) { - if (allowdotexit) { - *s = 0; /* NUL-terminate it */ - return EXIT_HOSTNAME; /* .exit */ - } else { - log_warn(LD_APP, "The \".exit\" notation is disabled in Tor due to " - "security risks. Set AllowDotExit in your torrc to enable " - "it."); - /* FFFF send a controller event too to notify Vidalia users */ - return BAD_HOSTNAME; - } + *s = 0; /* NUL-terminate it */ + return EXIT_HOSTNAME; /* .exit */ } if (strcmp(s+1,"onion")) return NORMAL_HOSTNAME; /* neither .exit nor .onion, thus normal */ diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h index 78baf75b68..c320d6ba49 100644 --- a/src/or/connection_edge.h +++ b/src/or/connection_edge.h @@ -74,7 +74,8 @@ void addressmap_clean(time_t now); void addressmap_clear_configured(void); void addressmap_clear_transient(void); void addressmap_free_all(void); -int addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out); +int addressmap_rewrite(char *address, size_t maxlen, time_t *expires_out, + addressmap_entry_source_t *exit_source_out); int addressmap_have_mapping(const char *address, int update_timeout); void addressmap_register(const char *address, char *new_address, @@ -101,7 +102,7 @@ int connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, typedef enum hostname_type_t { NORMAL_HOSTNAME, ONION_HOSTNAME, EXIT_HOSTNAME, BAD_HOSTNAME } hostname_type_t; -hostname_type_t parse_extended_hostname(char *address, int allowdotexit); +hostname_type_t parse_extended_hostname(char *address); #if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H) int get_pf_socket(void); diff --git a/src/or/control.c b/src/or/control.c index dfa7d364c7..9465f895a4 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -4109,11 +4109,13 @@ control_event_buildtimeout_set(const circuit_build_times_t *cbt, buildtimeout_set_event_t type) { const char *type_string = NULL; - double qnt = circuit_build_times_quantile_cutoff(); + double qnt; if (!control_event_is_interesting(EVENT_BUILDTIMEOUT_SET)) return 0; + qnt = circuit_build_times_quantile_cutoff(); + switch (type) { case BUILDTIMEOUT_SET_EVENT_COMPUTED: type_string = "COMPUTED"; diff --git a/src/or/main.c b/src/or/main.c index 163dd5d0fb..3e913d968d 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -848,6 +848,30 @@ conn_close_if_marked(int i) "Holding conn (fd %d) open for more flushing.", (int)conn->s)); conn->timestamp_lastwritten = now; /* reset so we can flush more */ + } else if (sz == 0) { /* retval is also 0 */ + /* Connection must flush before closing, but it's being rate-limited. + Let's remove from Libevent, and mark it as blocked on bandwidth so it + will be re-added on next token bucket refill. Prevents busy Libevent + loops where we keep ending up here and returning 0 until we are no + longer blocked on bandwidth. */ + if (connection_is_writing(conn)) { + conn->write_blocked_on_bw = 1; + connection_stop_writing(conn); + } + if (connection_is_reading(conn)) { +#define MARKED_READING_RATE 180 + static ratelim_t marked_read_lim = RATELIM_INIT(MARKED_READING_RATE); + char *m; + if ((m = rate_limit_log(&marked_read_lim, now))) { + log_warn(LD_BUG, "Marked connection (fd %d, type %s, state %s) " + "is still reading; that shouldn't happen.%s", + (int)conn->s, conn_type_to_string(conn->type), + conn_state_to_string(conn->type, conn->state), m); + tor_free(m); + } + conn->read_blocked_on_bw = 1; + connection_stop_reading(conn); + } } return 0; } diff --git a/src/or/or.h b/src/or/or.h index 9ca9239ce5..7ff628411a 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3855,6 +3855,11 @@ typedef enum { /** We're remapping this address because we got a DNS resolution from a * Tor server that told us what its value was. */ ADDRMAPSRC_DNS, + + /** No remapping has occurred. This isn't a possible value for an + * addrmap_entry_t; it's used as a null value when we need to answer "Why + * did this remapping happen." */ + ADDRMAPSRC_NONE } addressmap_entry_source_t; /********************************* control.c ***************************/ diff --git a/src/or/relay.c b/src/or/relay.c index e22ce47b21..0c99c3497b 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -764,7 +764,7 @@ connection_ap_process_end_not_open( /* rewrite it to an IP if we learned one. */ if (addressmap_rewrite(conn->socks_request->address, sizeof(conn->socks_request->address), - NULL)) { + NULL, NULL)) { control_event_stream_status(conn, STREAM_EVENT_REMAP, 0); } if (conn->chosen_exit_optional || diff --git a/src/or/rephist.c b/src/or/rephist.c index ec5b84692e..341a5a3e98 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -2478,8 +2478,9 @@ char * rep_hist_format_buffer_stats(time_t now) { #define SHARES 10 - int processed_cells[SHARES], circs_in_share[SHARES], - number_of_circuits, i; + uint64_t processed_cells[SHARES]; + uint32_t circs_in_share[SHARES]; + int number_of_circuits, i; double queued_cells[SHARES], time_in_queue[SHARES]; smartlist_t *processed_cells_strings, *queued_cells_strings, *time_in_queue_strings; @@ -2494,8 +2495,8 @@ rep_hist_format_buffer_stats(time_t now) tor_assert(now >= start_of_buffer_stats_interval); /* Calculate deciles if we saw at least one circuit. */ - memset(processed_cells, 0, SHARES * sizeof(int)); - memset(circs_in_share, 0, SHARES * sizeof(int)); + memset(processed_cells, 0, SHARES * sizeof(uint64_t)); + memset(circs_in_share, 0, SHARES * sizeof(uint32_t)); memset(queued_cells, 0, SHARES * sizeof(double)); memset(time_in_queue, 0, SHARES * sizeof(double)); if (!circuits_for_buffer_stats) @@ -2523,8 +2524,9 @@ rep_hist_format_buffer_stats(time_t now) time_in_queue_strings = smartlist_new(); for (i = 0; i < SHARES; i++) { smartlist_add_asprintf(processed_cells_strings, - "%d", !circs_in_share[i] ? 0 : - processed_cells[i] / circs_in_share[i]); + U64_FORMAT, !circs_in_share[i] ? 0 : + U64_PRINTF_ARG(processed_cells[i] / + circs_in_share[i])); } for (i = 0; i < SHARES; i++) { smartlist_add_asprintf(queued_cells_strings, "%.2f", |