aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/circuitbuild.c291
-rw-r--r--src/or/circuitbuild.h1
-rw-r--r--src/or/circuituse.c4
-rw-r--r--src/or/connection_edge.c104
-rw-r--r--src/or/connection_edge.h5
-rw-r--r--src/or/control.c4
-rw-r--r--src/or/main.c24
-rw-r--r--src/or/or.h5
-rw-r--r--src/or/relay.c2
-rw-r--r--src/or/rephist.c14
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",