summaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/buffers.c14
-rw-r--r--src/or/circuitbuild.c222
-rw-r--r--src/or/circuitbuild.h2
-rw-r--r--src/or/circuitlist.c15
-rw-r--r--src/or/circuituse.c97
-rw-r--r--src/or/circuituse.h2
-rw-r--r--src/or/config.c129
-rw-r--r--src/or/connection.c43
-rw-r--r--src/or/connection_edge.c69
-rw-r--r--src/or/connection_edge.h1
-rw-r--r--src/or/connection_or.c19
-rw-r--r--src/or/control.c4
-rw-r--r--src/or/directory.c46
-rw-r--r--src/or/dirserv.c72
-rw-r--r--src/or/dirserv.h14
-rw-r--r--src/or/dirvote.c13
-rw-r--r--src/or/dirvote.h3
-rw-r--r--src/or/dns.c19
-rw-r--r--src/or/dnsserv.c5
-rw-r--r--src/or/eventdns.c4
-rw-r--r--src/or/geoip.c197
-rw-r--r--src/or/geoip.h2
-rw-r--r--src/or/hibernate.c6
-rw-r--r--src/or/main.c24
-rw-r--r--src/or/main.h6
-rw-r--r--src/or/networkstatus.c66
-rw-r--r--src/or/networkstatus.h5
-rw-r--r--src/or/ntmain.c10
-rw-r--r--src/or/onion.c10
-rw-r--r--src/or/or.h98
-rw-r--r--src/or/policies.c14
-rw-r--r--src/or/policies.h1
-rw-r--r--src/or/reasons.c13
-rw-r--r--src/or/relay.c17
-rw-r--r--src/or/relay.h2
-rw-r--r--src/or/rendclient.c11
-rw-r--r--src/or/rendcommon.c2
-rw-r--r--src/or/rendservice.c10
-rw-r--r--src/or/rephist.c452
-rw-r--r--src/or/rephist.h4
-rw-r--r--src/or/router.c39
-rw-r--r--src/or/routerlist.c49
-rw-r--r--src/or/routerparse.c72
-rw-r--r--src/or/routerparse.h4
44 files changed, 1273 insertions, 634 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c
index 2a88382501..db926955b4 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -666,12 +666,12 @@ read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls,
* (because of EOF), set *<b>reached_eof</b> to 1 and return 0. Return -1 on
* error; else return the number of bytes read.
*/
-/* XXXX021 indicate "read blocked" somehow? */
+/* XXXX023 indicate "read blocked" somehow? */
int
read_to_buf(int s, size_t at_most, buf_t *buf, int *reached_eof,
int *socket_error)
{
- /* XXXX021 It's stupid to overload the return values for these functions:
+ /* XXXX023 It's stupid to overload the return values for these functions:
* "error status" and "number of bytes read" are not mutually exclusive.
*/
int r = 0;
@@ -856,7 +856,7 @@ flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk,
int
flush_buf(int s, buf_t *buf, size_t sz, size_t *buf_flushlen)
{
- /* XXXX021 It's stupid to overload the return values for these functions:
+ /* XXXX023 It's stupid to overload the return values for these functions:
* "error status" and "number of bytes flushed" are not mutually exclusive.
*/
int r;
@@ -1336,6 +1336,10 @@ log_unsafe_socks_warning(int socks_protocol, const char *address,
socks_protocol, address, (int)port);
}
+/** Do not attempt to parse socks messages longer than this. This value is
+ * actually significantly higher than the longest possible socks message. */
+#define MAX_SOCKS_MESSAGE_LEN 512
+
/** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one
* of the forms
* - socks4: "socksheader username\\0"
@@ -1377,7 +1381,7 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
if (buf->datalen < 2) /* version and another byte */
return 0;
- buf_pullup(buf, 128, 0);
+ buf_pullup(buf, MAX_SOCKS_MESSAGE_LEN, 0);
tor_assert(buf->head && buf->head->datalen >= 2);
socksver = *buf->head->data;
@@ -1666,7 +1670,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
if (buf->datalen < 2)
return 0;
- buf_pullup(buf, 128, 0);
+ buf_pullup(buf, MAX_SOCKS_MESSAGE_LEN, 0);
tor_assert(buf->head && buf->head->datalen >= 2);
data = (unsigned char *) buf->head->data;
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index b1743847c8..2d4d5c032a 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -42,11 +42,12 @@
/********* START VARIABLES **********/
/** Global list of circuit build times */
-// FIXME: Add this as a member for entry_guard_t instead of global?
+// XXXX023: Add this as a member for entry_guard_t instead of global?
// Then we could do per-guard statistics, as guards are likely to
// vary in their own latency. The downside of this is that guards
// can change frequently, so we'd be building a lot more circuits
// most likely.
+/* XXXX023 Make this static; add accessor functions. */
circuit_build_times_t circ_times;
/** A global list of all circuits at this hop. */
@@ -99,6 +100,15 @@ static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
static void entry_guards_changed(void);
+/**
+ * This function decides if CBT learning should be disabled. It returns
+ * true if one or more of the following four conditions are met:
+ *
+ * 1. If the cbtdisabled consensus parameter is set.
+ * 2. If the torrc option LearnCircuitBuildTimeout is false.
+ * 3. If we are a directory authority
+ * 4. If we fail to write circuit build time history to our state file.
+ */
static int
circuit_build_times_disabled(void)
{
@@ -106,7 +116,7 @@ circuit_build_times_disabled(void)
return 0;
} else {
int consensus_disabled = networkstatus_get_param(NULL, "cbtdisabled",
- 0);
+ 0, 0, 1);
int config_disabled = !get_options()->LearnCircuitBuildTimeout;
int dirauth_disabled = get_options()->AuthoritativeDir;
int state_disabled = (get_or_state()->LastWritten == -1);
@@ -125,27 +135,54 @@ circuit_build_times_disabled(void)
}
}
+/**
+ * Retrieve and bounds-check the cbtmaxtimeouts consensus paramter.
+ *
+ * Effect: When this many timeouts happen in the last 'cbtrecentcount'
+ * circuit attempts, the client should discard all of its history and
+ * begin learning a fresh timeout value.
+ */
static int32_t
circuit_build_times_max_timeouts(void)
{
- int32_t num = networkstatus_get_param(NULL, "cbtmaxtimeouts",
- CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT);
- return num;
+ return networkstatus_get_param(NULL, "cbtmaxtimeouts",
+ CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT,
+ CBT_MIN_MAX_RECENT_TIMEOUT_COUNT,
+ CBT_MAX_MAX_RECENT_TIMEOUT_COUNT);
}
+/**
+ * Retrieve and bounds-check the cbtnummodes consensus paramter.
+ *
+ * Effect: This value governs how many modes to use in the weighted
+ * average calculation of Pareto parameter Xm. A value of 3 introduces
+ * some bias (2-5% of CDF) under ideal conditions, but allows for better
+ * performance in the event that a client chooses guard nodes of radically
+ * different performance characteristics.
+ */
static int32_t
circuit_build_times_default_num_xm_modes(void)
{
int32_t num = networkstatus_get_param(NULL, "cbtnummodes",
- CBT_DEFAULT_NUM_XM_MODES);
+ CBT_DEFAULT_NUM_XM_MODES,
+ CBT_MIN_NUM_XM_MODES,
+ CBT_MAX_NUM_XM_MODES);
return num;
}
+/**
+ * Retrieve and bounds-check the cbtmincircs consensus paramter.
+ *
+ * Effect: This is the minimum number of circuits to build before
+ * computing a timeout.
+ */
static int32_t
circuit_build_times_min_circs_to_observe(void)
{
int32_t num = networkstatus_get_param(NULL, "cbtmincircs",
- CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE);
+ CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE,
+ CBT_MIN_MIN_CIRCUITS_TO_OBSERVE,
+ CBT_MAX_MIN_CIRCUITS_TO_OBSERVE);
return num;
}
@@ -157,53 +194,126 @@ circuit_build_times_enough_to_compute(circuit_build_times_t *cbt)
return cbt->total_build_times >= circuit_build_times_min_circs_to_observe();
}
+/**
+ * Retrieve and bounds-check the cbtquantile consensus paramter.
+ *
+ * Effect: This is the position on the quantile curve to use to set the
+ * timeout value. It is a percent (10-99).
+ */
double
circuit_build_times_quantile_cutoff(void)
{
int32_t num = networkstatus_get_param(NULL, "cbtquantile",
- CBT_DEFAULT_QUANTILE_CUTOFF);
+ CBT_DEFAULT_QUANTILE_CUTOFF,
+ CBT_MIN_QUANTILE_CUTOFF,
+ CBT_MAX_QUANTILE_CUTOFF);
return num/100.0;
}
+int
+circuit_build_times_get_bw_scale(networkstatus_t *ns)
+{
+ return networkstatus_get_param(ns, "bwweightscale",
+ BW_WEIGHT_SCALE,
+ BW_MIN_WEIGHT_SCALE,
+ BW_MAX_WEIGHT_SCALE);
+}
+
+/**
+ * Retrieve and bounds-check the cbtclosequantile consensus paramter.
+ *
+ * Effect: This is the position on the quantile curve to use to set the
+ * timeout value to use to actually close circuits. It is a percent
+ * (0-99).
+ */
static double
circuit_build_times_close_quantile(void)
{
- int32_t num = networkstatus_get_param(NULL, "cbtclosequantile",
- CBT_DEFAULT_CLOSE_QUANTILE);
-
- return num/100.0;
+ int32_t param;
+ /* Cast is safe - circuit_build_times_quantile_cutoff() is capped */
+ int32_t min = (int)tor_lround(100*circuit_build_times_quantile_cutoff());
+ param = networkstatus_get_param(NULL, "cbtclosequantile",
+ CBT_DEFAULT_CLOSE_QUANTILE,
+ CBT_MIN_CLOSE_QUANTILE,
+ CBT_MAX_CLOSE_QUANTILE);
+ if (param < min) {
+ log_warn(LD_DIR, "Consensus parameter cbtclosequantile is "
+ "too small, raising to %d", min);
+ param = min;
+ }
+ return param / 100.0;
}
+/**
+ * Retrieve and bounds-check the cbttestfreq consensus paramter.
+ *
+ * Effect: Describes how often in seconds to build a test circuit to
+ * gather timeout values. Only applies if less than 'cbtmincircs'
+ * have been recorded.
+ */
static int32_t
circuit_build_times_test_frequency(void)
{
int32_t num = networkstatus_get_param(NULL, "cbttestfreq",
- CBT_DEFAULT_TEST_FREQUENCY);
+ CBT_DEFAULT_TEST_FREQUENCY,
+ CBT_MIN_TEST_FREQUENCY,
+ CBT_MAX_TEST_FREQUENCY);
return num;
}
+/**
+ * Retrieve and bounds-check the cbtmintimeout consensus paramter.
+ *
+ * Effect: This is the minimum allowed timeout value in milliseconds.
+ * The minimum is to prevent rounding to 0 (we only check once
+ * per second).
+ */
static int32_t
circuit_build_times_min_timeout(void)
{
int32_t num = networkstatus_get_param(NULL, "cbtmintimeout",
- CBT_DEFAULT_TIMEOUT_MIN_VALUE);
+ CBT_DEFAULT_TIMEOUT_MIN_VALUE,
+ CBT_MIN_TIMEOUT_MIN_VALUE,
+ CBT_MAX_TIMEOUT_MIN_VALUE);
return num;
}
+/**
+ * Retrieve and bounds-check the cbtinitialtimeout consensus paramter.
+ *
+ * Effect: This is the timeout value to use before computing a timeout,
+ * in milliseconds.
+ */
int32_t
circuit_build_times_initial_timeout(void)
{
- int32_t num = networkstatus_get_param(NULL, "cbtinitialtimeout",
- CBT_DEFAULT_TIMEOUT_INITIAL_VALUE);
- return num;
+ int32_t min = circuit_build_times_min_timeout();
+ int32_t param = networkstatus_get_param(NULL, "cbtinitialtimeout",
+ CBT_DEFAULT_TIMEOUT_INITIAL_VALUE,
+ CBT_MIN_TIMEOUT_INITIAL_VALUE,
+ CBT_MAX_TIMEOUT_INITIAL_VALUE);
+ if (param < min) {
+ log_warn(LD_DIR, "Consensus parameter cbtinitialtimeout is too small, "
+ "raising to %d", min);
+ param = min;
+ }
+ return param;
}
+/**
+ * Retrieve and bounds-check the cbtrecentcount consensus paramter.
+ *
+ * Effect: This is the number of circuit build times to keep track of
+ * for deciding if we hit cbtmaxtimeouts and need to reset our state
+ * and learn a new timeout.
+ */
static int32_t
-circuit_build_times_recent_circuit_count(void)
+circuit_build_times_recent_circuit_count(networkstatus_t *ns)
{
- int32_t num = networkstatus_get_param(NULL, "cbtrecentcount",
- CBT_DEFAULT_RECENT_CIRCUITS);
- return num;
+ return networkstatus_get_param(ns, "cbtrecentcount",
+ CBT_DEFAULT_RECENT_CIRCUITS,
+ CBT_MIN_RECENT_CIRCUITS,
+ CBT_MAX_RECENT_CIRCUITS);
}
/**
@@ -216,13 +326,13 @@ void
circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
networkstatus_t *ns)
{
- int32_t num = networkstatus_get_param(ns, "cbtrecentcount",
- CBT_DEFAULT_RECENT_CIRCUITS);
+ int32_t num = circuit_build_times_recent_circuit_count(ns);
if (num > 0 && num != cbt->liveness.num_recent_circs) {
int8_t *recent_circs;
- log_notice(LD_CIRC, "Changing recent timeout size from %d to %d",
- cbt->liveness.num_recent_circs, num);
+ 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);
@@ -307,7 +417,8 @@ void
circuit_build_times_init(circuit_build_times_t *cbt)
{
memset(cbt, 0, sizeof(*cbt));
- cbt->liveness.num_recent_circs = circuit_build_times_recent_circuit_count();
+ 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->close_ms = cbt->timeout_ms = circuit_build_times_get_initial_timeout();
@@ -347,7 +458,7 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
* Add a new build time value <b>time</b> to the set of build times. Time
* units are milliseconds.
*
- * circuit_build_times <b>cbt</a> is a circular array, so loop around when
+ * circuit_build_times <b>cbt</b> is a circular array, so loop around when
* array is full.
*/
int
@@ -545,17 +656,19 @@ circuit_build_times_update_state(circuit_build_times_t *cbt,
/**
* Shuffle the build times array.
*
- * Stolen from http://en.wikipedia.org/wiki/Fisher\u2013Yates_shuffle
+ * Adapted from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
*/
static void
circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
build_time_t *raw_times,
- int num_times)
+ uint32_t num_times)
{
- int n = num_times;
+ uint32_t n = num_times;
if (num_times > CBT_NCIRCUITS_TO_OBSERVE) {
- log_notice(LD_CIRC, "Decreasing circuit_build_times size from %d to %d",
- num_times, CBT_NCIRCUITS_TO_OBSERVE);
+ log_notice(LD_CIRC, "The number of circuit times that this Tor version "
+ "uses to calculate build times is less than the number stored "
+ "in your state file. Decreasing the circuit time history from "
+ "%d to %d.", num_times, CBT_NCIRCUITS_TO_OBSERVE);
}
/* This code can only be run on a compact array */
@@ -1036,7 +1149,7 @@ circuit_build_times_network_close(circuit_build_times_t *cbt,
if (cbt->liveness.nonlive_timeouts == 1) {
log_notice(LD_CIRC,
"Tor has not observed any network activity for the past %d "
- "seconds. Disabling circuit build timeout code.",
+ "seconds. Disabling circuit build timeout recording.",
(int)(now - cbt->liveness.network_last_live));
} else {
log_info(LD_CIRC,
@@ -1120,7 +1233,7 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
log_notice(LD_CIRC,
- "Network connection speed appears to have changed. Resetting "
+ "Your network connection speed appears to have changed. Resetting "
"timeout to %lds after %d timeouts and %d buildtimes.",
tor_lround(cbt->timeout_ms/1000), timeout_count,
total_build_times);
@@ -1258,7 +1371,7 @@ circuit_build_times_set_timeout_worker(circuit_build_times_t *cbt)
}
if (max_time < INT32_MAX/2 && cbt->close_ms > 2*max_time) {
- log_notice(LD_CIRC,
+ log_info(LD_CIRC,
"Circuit build measurement period of %dms is more than twice "
"the maximum build time we have ever observed. Capping it to "
"%dms.", (int)cbt->close_ms, 2*max_time);
@@ -1929,7 +2042,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
struct timeval end;
long timediff;
tor_gettimeofday(&end);
- timediff = tv_mdiff(&circ->_base.highres_created, &end);
+ timediff = tv_mdiff(&circ->_base.timestamp_created, &end);
/*
* If the circuit build time is much greater than we would have cut
@@ -3702,7 +3815,7 @@ entry_guards_compute_status(or_options_t *options, time_t now)
* If <b>mark_relay_status</b>, also call router_set_status() on this
* relay.
*
- * XXX022 change succeeded and mark_relay_status into 'int flags'.
+ * XXX023 change succeeded and mark_relay_status into 'int flags'.
*/
int
entry_guard_register_connect_status(const char *digest, int succeeded,
@@ -3860,7 +3973,7 @@ entry_guards_prepend_from_config(or_options_t *options)
/* Split entry guards into those on the list and those not. */
- /* XXXX022 Now that we allow countries and IP ranges in EntryNodes, this is
+ /* XXXX023 Now that we allow countries and IP ranges in EntryNodes, this is
* potentially an enormous list. For now, we disable such values for
* EntryNodes in options_validate(); really, this wants a better solution.
* Perhaps we should do this calculation once whenever the list of routers
@@ -3951,7 +4064,6 @@ choose_random_entry(cpath_build_state_t *state)
int preferred_min, consider_exit_family = 0;
if (chosen_exit) {
- smartlist_add(exit_family, chosen_exit);
routerlist_add_family(exit_family, chosen_exit);
consider_exit_family = 1;
}
@@ -3974,6 +4086,8 @@ choose_random_entry(cpath_build_state_t *state)
r = entry_is_live(entry, need_uptime, need_capacity, 0, &msg);
if (!r)
continue; /* down, no point */
+ if (r == chosen_exit)
+ continue; /* don't pick the same node for entry and exit */
if (consider_exit_family && smartlist_isin(exit_family, r))
continue; /* avoid relays that are family members of our exit */
if (options->EntryNodes &&
@@ -4191,7 +4305,7 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
}
entry_guards = new_entry_guards;
entry_guards_dirty = 0;
- /* XXX022 hand new_entry_guards to this func, and move it up a
+ /* XXX023 hand new_entry_guards to this func, and move it up a
* few lines, so we don't have to re-dirty it */
if (remove_obsolete_entry_guards(now))
entry_guards_dirty = 1;
@@ -4558,6 +4672,29 @@ fetch_bridge_descriptors(or_options_t *options, time_t now)
SMARTLIST_FOREACH_END(bridge);
}
+/** If our <b>bridge</b> is configured to be a different address than
+ * the bridge gives in its routerinfo <b>ri</b>, rewrite the routerinfo
+ * we received to use the address we meant to use. Now we handle
+ * multihomed bridges better.
+ */
+static void
+rewrite_routerinfo_address_for_bridge(bridge_info_t *bridge, routerinfo_t *ri)
+{
+ tor_addr_t addr;
+ tor_addr_from_ipv4h(&addr, ri->addr);
+
+ if (!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
+ bridge->port == ri->or_port)
+ return; /* they match, so no need to do anything */
+
+ ri->addr = tor_addr_to_ipv4h(&bridge->addr);
+ tor_free(ri->address);
+ ri->address = tor_dup_ip(ri->addr);
+ ri->or_port = bridge->port;
+ log_info(LD_DIR, "Adjusted bridge '%s' to match configured address %s:%d.",
+ ri->nickname, ri->address, ri->or_port);
+}
+
/** We just learned a descriptor for a bridge. See if that
* digest is in our entry guard list, and add it if not. */
void
@@ -4576,6 +4713,8 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
if (!from_cache)
download_status_reset(&bridge->fetch_status);
+ rewrite_routerinfo_address_for_bridge(bridge, ri);
+
add_an_entry_guard(ri, 1);
log_notice(LD_DIR, "new bridge descriptor '%s' (%s)", ri->nickname,
from_cache ? "cached" : "fresh");
@@ -4615,7 +4754,8 @@ any_pending_bridge_descriptor_fetches(void)
conn->purpose == DIR_PURPOSE_FETCH_SERVERDESC &&
TO_DIR_CONN(conn)->router_purpose == ROUTER_PURPOSE_BRIDGE &&
!conn->marked_for_close &&
- conn->linked && !conn->linked_conn->marked_for_close) {
+ conn->linked &&
+ conn->linked_conn && !conn->linked_conn->marked_for_close) {
log_debug(LD_DIR, "found one: %s", conn->address);
return 1;
}
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index 74bbd4f22a..af24931878 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -121,5 +121,7 @@ void circuit_build_times_network_is_live(circuit_build_times_t *cbt);
int circuit_build_times_network_check_live(circuit_build_times_t *cbt);
void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
+int circuit_build_times_get_bw_scale(networkstatus_t *ns);
+
#endif
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 58ff27e5e1..d11b457944 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -384,7 +384,9 @@ circuit_purpose_to_controller_string(uint8_t purpose)
int32_t
circuit_initial_package_window(void)
{
- int32_t num = networkstatus_get_param(NULL, "circwindow", CIRCWINDOW_START);
+ int32_t num = networkstatus_get_param(NULL, "circwindow", CIRCWINDOW_START,
+ CIRCWINDOW_START_MIN,
+ CIRCWINDOW_START_MAX);
/* If the consensus tells us a negative number, we'd assert. */
if (num < 0)
num = CIRCWINDOW_START;
@@ -396,8 +398,7 @@ circuit_initial_package_window(void)
static void
init_circuit_base(circuit_t *circ)
{
- circ->timestamp_created = time(NULL);
- tor_gettimeofday(&circ->highres_created);
+ tor_gettimeofday(&circ->timestamp_created);
circ->package_window = circuit_initial_package_window();
circ->deliver_window = CIRCWINDOW_START;
@@ -607,9 +608,10 @@ circuit_dump_details(int severity, circuit_t *circ, int conn_array_index,
const char *type, int this_circid, int other_circid)
{
log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), "
- "state %d (%s), born %d:",
+ "state %d (%s), born %ld:",
conn_array_index, type, this_circid, other_circid, circ->state,
- circuit_state_to_string(circ->state), (int)circ->timestamp_created);
+ circuit_state_to_string(circ->state),
+ (long)circ->timestamp_created.tv_sec);
if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ));
}
@@ -1021,6 +1023,7 @@ 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.
*/
+/* XXX023 this is a bad name for what this function does */
void
circuit_expire_all_dirty_circs(void)
{
@@ -1031,6 +1034,8 @@ circuit_expire_all_dirty_circs(void)
if (CIRCUIT_IS_ORIGIN(circ) &&
!circ->marked_for_close &&
circ->timestamp_dirty)
+ /* XXXX023 This is a screwed-up way to say "This is too dirty
+ * for new circuits. */
circ->timestamp_dirty -= options->MaxCircuitDirtiness;
}
}
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 8d9d115863..cdf49e3983 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -31,7 +31,7 @@ extern circuit_t *global_circuitlist; /* from circuitlist.c */
/********* END VARIABLES ************/
-static void circuit_expire_old_circuits_clientside(time_t now);
+static void circuit_expire_old_circuits_clientside(void);
static void circuit_increment_failure_count(void);
/** Return 1 if <b>circ</b> could be returned by circuit_get_best().
@@ -162,7 +162,7 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
return 1;
} else {
if (a->timestamp_dirty ||
- a->timestamp_created > b->timestamp_created)
+ timercmp(&a->timestamp_created, &b->timestamp_created, >))
return 1;
if (CIRCUIT_IS_ORIGIN(b) &&
TO_ORIGIN_CIRCUIT(b)->build_state->is_internal)
@@ -204,7 +204,7 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
int need_uptime, int need_internal)
{
circuit_t *circ, *best=NULL;
- time_t now = time(NULL);
+ struct timeval now;
int intro_going_on_but_too_old = 0;
tor_assert(conn);
@@ -213,17 +213,16 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT ||
purpose == CIRCUIT_PURPOSE_C_REND_JOINED);
+ tor_gettimeofday(&now);
+
for (circ=global_circuitlist;circ;circ = circ->next) {
if (!circuit_is_acceptable(circ,conn,must_be_open,purpose,
- need_uptime,need_internal,now))
+ need_uptime,need_internal,now.tv_sec))
continue;
-/* XXX022 make this 15 be a function of circuit finishing times we've
- * seen lately, a la Fallon Chen's GSoC work -RD */
-#define REND_PARALLEL_INTRO_DELAY 15
if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT &&
- !must_be_open && circ->state != CIRCUIT_STATE_OPEN &&
- circ->timestamp_created + REND_PARALLEL_INTRO_DELAY < now) {
+ !must_be_open && circ->state != CIRCUIT_STATE_OPEN &&
+ tv_mdiff(&now, &circ->timestamp_created) > circ_times.timeout_ms) {
intro_going_on_but_too_old = 1;
continue;
}
@@ -275,22 +274,38 @@ circuit_conforms_to_options(const origin_circuit_t *circ,
* at least CircuitBuildTimeout seconds ago.
*/
void
-circuit_expire_building(time_t now)
+circuit_expire_building(void)
{
circuit_t *victim, *next_circ = global_circuitlist;
/* circ_times.timeout_ms and circ_times.close_ms are from
* circuit_build_times_get_initial_timeout() if we haven't computed
* custom timeouts yet */
- time_t general_cutoff = now - tor_lround(circ_times.timeout_ms/1000);
- time_t begindir_cutoff = now - tor_lround(circ_times.timeout_ms/2000);
- time_t fourhop_cutoff = now - tor_lround(4*circ_times.timeout_ms/3000);
- time_t cannibalize_cutoff = now - tor_lround(circ_times.timeout_ms/2000);
- time_t close_cutoff = now - tor_lround(circ_times.close_ms/1000);
- time_t introcirc_cutoff = begindir_cutoff;
+ struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff,
+ cannibalize_cutoff, close_cutoff, extremely_old_cutoff;
+ struct timeval now;
+ struct timeval introcirc_cutoff;
cpath_build_state_t *build_state;
+ tor_gettimeofday(&now);
+#define SET_CUTOFF(target, msec) do { \
+ long ms = tor_lround(msec); \
+ struct timeval diff; \
+ diff.tv_sec = ms / 1000; \
+ diff.tv_usec = (int)((ms % 1000) * 1000); \
+ timersub(&now, &diff, &target); \
+ } while (0)
+
+ SET_CUTOFF(general_cutoff, circ_times.timeout_ms);
+ SET_CUTOFF(begindir_cutoff, circ_times.timeout_ms / 2.0);
+ SET_CUTOFF(fourhop_cutoff, circ_times.timeout_ms * (4/3.0));
+ SET_CUTOFF(cannibalize_cutoff, circ_times.timeout_ms / 2.0);
+ SET_CUTOFF(close_cutoff, circ_times.close_ms);
+ SET_CUTOFF(extremely_old_cutoff, circ_times.close_ms*2 + 1000);
+
+ introcirc_cutoff = begindir_cutoff;
+
while (next_circ) {
- time_t cutoff;
+ struct timeval cutoff;
victim = next_circ;
next_circ = next_circ->next;
if (!CIRCUIT_IS_ORIGIN(victim) || /* didn't originate here */
@@ -312,7 +327,7 @@ circuit_expire_building(time_t now)
else
cutoff = general_cutoff;
- if (victim->timestamp_created > cutoff)
+ if (timercmp(&victim->timestamp_created, &cutoff, >))
continue; /* it's still young, leave it alone */
#if 0
@@ -358,7 +373,7 @@ circuit_expire_building(time_t now)
* because that's set when they switch purposes
*/
if (TO_ORIGIN_CIRCUIT(victim)->rend_data ||
- victim->timestamp_dirty > cutoff)
+ victim->timestamp_dirty > cutoff.tv_sec)
continue;
break;
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
@@ -367,7 +382,7 @@ circuit_expire_building(time_t now)
* make an introduction attempt. so timestamp_dirty
* will reflect the time since the last attempt.
*/
- if (victim->timestamp_dirty > cutoff)
+ if (victim->timestamp_dirty > cutoff.tv_sec)
continue;
break;
}
@@ -407,15 +422,15 @@ circuit_expire_building(time_t now)
* it off at, we probably had a suspend event along this codepath,
* and we should discard the value.
*/
- if (now - victim->timestamp_created > 2*circ_times.close_ms/1000+1) {
+ if (timercmp(&victim->timestamp_created, &extremely_old_cutoff, <)) {
log_notice(LD_CIRC,
"Extremely large value for circuit build timeout: %lds. "
"Assuming clock jump. Purpose %d",
- (long)(now - victim->timestamp_created),
+ (long)(now.tv_sec - victim->timestamp_created.tv_sec),
victim->purpose);
} else if (circuit_build_times_count_close(&circ_times,
first_hop_succeeded,
- victim->timestamp_created)) {
+ victim->timestamp_created.tv_sec)) {
circuit_build_times_set_timeout(&circ_times);
}
}
@@ -636,7 +651,7 @@ circuit_build_needed_circs(time_t now)
time_to_new_circuit = now + options->NewCircuitPeriod;
if (proxy_mode(get_options()))
addressmap_clean(now);
- circuit_expire_old_circuits_clientside(now);
+ circuit_expire_old_circuits_clientside();
#if 0 /* disable for now, until predict-and-launch-new can cull leftovers */
circ = circuit_get_youngest_clean_open(CIRCUIT_PURPOSE_C_GENERAL);
@@ -725,17 +740,20 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
* for too long and has no streams on it: mark it for close.
*/
static void
-circuit_expire_old_circuits_clientside(time_t now)
+circuit_expire_old_circuits_clientside(void)
{
circuit_t *circ;
- time_t cutoff;
+ struct timeval cutoff, now;
+
+ tor_gettimeofday(&now);
+ cutoff = now;
if (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 = now - IDLE_TIMEOUT_WHILE_LEARNING;
+ cutoff.tv_sec -= IDLE_TIMEOUT_WHILE_LEARNING;
} else {
- cutoff = now - get_options()->CircuitIdleTimeout;
+ cutoff.tv_sec -= get_options()->CircuitIdleTimeout;
}
for (circ = global_circuitlist; circ; circ = circ->next) {
@@ -745,15 +763,15 @@ circuit_expire_old_circuits_clientside(time_t now)
* on it, mark it for close.
*/
if (circ->timestamp_dirty &&
- circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now &&
+ circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now.tv_sec &&
!TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) {
- log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %d secs ago, "
+ log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %ld sec ago, "
"purpose %d)",
- circ->n_circ_id, (int)(now - circ->timestamp_dirty),
+ circ->n_circ_id, (long)(now.tv_sec - circ->timestamp_dirty),
circ->purpose);
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
} else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN) {
- if (circ->timestamp_created < cutoff) {
+ if (timercmp(&circ->timestamp_created, &cutoff, <)) {
if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL ||
circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT ||
circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
@@ -762,8 +780,8 @@ circuit_expire_old_circuits_clientside(time_t now)
circ->purpose <= CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) ||
circ->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) {
log_debug(LD_CIRC,
- "Closing circuit that has been unused for %ld seconds.",
- (long)(now - circ->timestamp_created));
+ "Closing circuit that has been unused for %ld msec.",
+ tv_mdiff(&circ->timestamp_created, &now));
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
} else if (!TO_ORIGIN_CIRCUIT(circ)->is_ancient) {
/* Server-side rend joined circuits can end up really old, because
@@ -775,9 +793,9 @@ circuit_expire_old_circuits_clientside(time_t now)
circ->purpose != CIRCUIT_PURPOSE_S_INTRO) {
log_notice(LD_CIRC,
"Ancient non-dirty circuit %d is still around after "
- "%ld seconds. Purpose: %d",
+ "%ld milliseconds. Purpose: %d",
TO_ORIGIN_CIRCUIT(circ)->global_identifier,
- (long)(now - circ->timestamp_created),
+ tv_mdiff(&circ->timestamp_created, &now),
circ->purpose);
/* FFFF implement a new circuit_purpose_to_string() so we don't
* just print out a number for circ->purpose */
@@ -1123,7 +1141,7 @@ circuit_launch_by_extend_info(uint8_t purpose,
/* reset the birth date of this circ, else expire_building
* will see it and think it's been trying to build since it
* began. */
- circ->_base.timestamp_created = time(NULL);
+ tor_gettimeofday(&circ->_base.timestamp_created);
switch (purpose) {
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
@@ -1266,7 +1284,8 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn,
return -1;
}
} else {
- /* XXXX022 Duplicates checks in connection_ap_handshake_attach_circuit */
+ /* XXXX023 Duplicates checks in connection_ap_handshake_attach_circuit:
+ * refactor into a single function? */
routerinfo_t *router = router_get_by_nickname(conn->chosen_exit_name, 1);
int opt = conn->chosen_exit_optional;
if (router && !connection_ap_can_use_exit(conn, router, 0)) {
@@ -1605,7 +1624,7 @@ connection_ap_handshake_attach_circuit(edge_connection_t *conn)
/* find the circuit that we should use, if there is one. */
retval = circuit_get_open_circ_or_launch(
conn, CIRCUIT_PURPOSE_C_GENERAL, &circ);
- if (retval < 1) // XXX021 if we totally fail, this still returns 0 -RD
+ if (retval < 1) // XXX022 if we totally fail, this still returns 0 -RD
return retval;
log_debug(LD_APP|LD_CIRC,
diff --git a/src/or/circuituse.h b/src/or/circuituse.h
index 1a604b415f..a121099aca 100644
--- a/src/or/circuituse.h
+++ b/src/or/circuituse.h
@@ -12,7 +12,7 @@
#ifndef _TOR_CIRCUITUSE_H
#define _TOR_CIRCUITUSE_H
-void circuit_expire_building(time_t now);
+void circuit_expire_building(void);
void circuit_remove_handled_ports(smartlist_t *needed_ports);
int circuit_stream_is_being_handled(edge_connection_t *conn, uint16_t port,
int min);
diff --git a/src/or/config.c b/src/or/config.c
index 17d776e71e..9675c73c99 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -195,6 +195,7 @@ static config_var_t _option_vars[] = {
V(CircuitStreamTimeout, INTERVAL, "0"),
V(CircuitPriorityHalflife, DOUBLE, "-100.0"), /*negative:'Use default'*/
V(ClientDNSRejectInternalAddresses, BOOL,"1"),
+ V(ClientRejectInternalAddresses, BOOL, "1"),
V(ClientOnly, BOOL, "0"),
V(ConsensusParams, STRING, NULL),
V(ConnLimit, UINT, "1000"),
@@ -287,6 +288,7 @@ static config_var_t _option_vars[] = {
OBSOLETE("IgnoreVersion"),
V(KeepalivePeriod, INTERVAL, "5 minutes"),
VAR("Log", LINELIST, Logs, NULL),
+ V(LogMessageDomains, BOOL, "0"),
OBSOLETE("LinkPadding"),
OBSOLETE("LogLevel"),
OBSOLETE("LogFile"),
@@ -391,6 +393,7 @@ static config_var_t _option_vars[] = {
VAR("__HashedControlSessionPassword", LINELIST, HashedControlSessionPassword,
NULL),
V(MinUptimeHidServDirectoryV2, INTERVAL, "24 hours"),
+ V(_UsingTestNetworkDefaults, BOOL, "0"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};
@@ -405,6 +408,7 @@ static config_var_t testing_tor_network_defaults[] = {
V(AuthDirMaxServersPerAddr, UINT, "0"),
V(AuthDirMaxServersPerAuthAddr,UINT, "0"),
V(ClientDNSRejectInternalAddresses, BOOL,"0"),
+ V(ClientRejectInternalAddresses, BOOL, "0"),
V(ExitPolicyRejectPrivate, BOOL, "0"),
V(V3AuthVotingInterval, INTERVAL, "5 minutes"),
V(V3AuthVoteDelay, INTERVAL, "20 seconds"),
@@ -415,6 +419,7 @@ static config_var_t testing_tor_network_defaults[] = {
V(TestingAuthDirTimeToLearnReachability, INTERVAL, "0 minutes"),
V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "0 minutes"),
V(MinUptimeHidServDirectoryV2, INTERVAL, "0 minutes"),
+ V(_UsingTestNetworkDefaults, BOOL, "1"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};
#undef VAR
@@ -443,15 +448,19 @@ static config_var_t _state_vars[] = {
V(BWHistoryReadEnds, ISOTIME, NULL),
V(BWHistoryReadInterval, UINT, "900"),
V(BWHistoryReadValues, CSV, ""),
+ V(BWHistoryReadMaxima, CSV, ""),
V(BWHistoryWriteEnds, ISOTIME, NULL),
V(BWHistoryWriteInterval, UINT, "900"),
V(BWHistoryWriteValues, CSV, ""),
+ V(BWHistoryWriteMaxima, CSV, ""),
V(BWHistoryDirReadEnds, ISOTIME, NULL),
V(BWHistoryDirReadInterval, UINT, "900"),
V(BWHistoryDirReadValues, CSV, ""),
+ V(BWHistoryDirReadMaxima, CSV, ""),
V(BWHistoryDirWriteEnds, ISOTIME, NULL),
V(BWHistoryDirWriteInterval, UINT, "900"),
V(BWHistoryDirWriteValues, CSV, ""),
+ V(BWHistoryDirWriteMaxima, CSV, ""),
V(TorVersion, STRING, NULL),
@@ -1250,7 +1259,6 @@ options_act(or_options_t *old_options)
/* Check for transitions that need action. */
if (old_options) {
-
if ((options->UseEntryGuards && !old_options->UseEntryGuards) ||
(options->ExcludeNodes &&
!routerset_equal(old_options->ExcludeNodes,options->ExcludeNodes)) ||
@@ -1298,11 +1306,12 @@ options_act(or_options_t *old_options)
if (options_transition_affects_workers(old_options, options)) {
log_info(LD_GENERAL,
"Worker-related options changed. Rotating workers.");
+
+ if (init_keys() < 0) {
+ log_warn(LD_BUG,"Error initializing keys; exiting");
+ return -1;
+ }
if (server_mode(options) && !server_mode(old_options)) {
- if (init_keys() < 0) {
- log_warn(LD_BUG,"Error initializing keys; exiting");
- return -1;
- }
ip_address_changed(0);
if (can_complete_circuit || !any_predicted_circuits(time(NULL)))
inform_testing_reachability();
@@ -1329,7 +1338,7 @@ options_act(or_options_t *old_options)
|| !geoip_is_loaded())) {
/* XXXX Don't use this "<default>" junk; make our filename options
* understand prefixes somehow. -NM */
- /* XXXX021 Reload GeoIPFile on SIGHUP. -NM */
+ /* XXXX023 Reload GeoIPFile on SIGHUP. -NM */
char *actual_fname = tor_strdup(options->GeoIPFile);
#ifdef WIN32
if (!strcmp(actual_fname, "<default>")) {
@@ -2474,7 +2483,7 @@ is_local_addr(const tor_addr_t *addr)
if (get_options()->EnforceDistinctSubnets == 0)
return 0;
if (tor_addr_family(addr) == AF_INET) {
- /*XXXX022 IP6 what corresponds to an /24? */
+ /*XXXX023 IP6 what corresponds to an /24? */
uint32_t ip = tor_addr_to_ipv4h(addr);
/* It's possible that this next check will hit before the first time
@@ -2491,54 +2500,6 @@ is_local_addr(const tor_addr_t *addr)
return 0;
}
-/** Called when we don't have a nickname set. Try to guess a good nickname
- * based on the hostname, and return it in a newly allocated string. If we
- * can't, return NULL and let the caller warn if it wants to. */
-static char *
-get_default_nickname(void)
-{
- static const char * const bad_default_nicknames[] = {
- "localhost",
- NULL,
- };
- char localhostname[256];
- char *cp, *out, *outp;
- int i;
-
- if (gethostname(localhostname, sizeof(localhostname)) < 0)
- return NULL;
-
- /* Put it in lowercase; stop at the first dot. */
- if ((cp = strchr(localhostname, '.')))
- *cp = '\0';
- tor_strlower(localhostname);
-
- /* Strip invalid characters. */
- cp = localhostname;
- out = outp = tor_malloc(strlen(localhostname) + 1);
- while (*cp) {
- if (strchr(LEGAL_NICKNAME_CHARACTERS, *cp))
- *outp++ = *cp++;
- else
- cp++;
- }
- *outp = '\0';
-
- /* Enforce length. */
- if (strlen(out) > MAX_NICKNAME_LEN)
- out[MAX_NICKNAME_LEN]='\0';
-
- /* Check for dumb names. */
- for (i = 0; bad_default_nicknames[i]; ++i) {
- if (!strcmp(out, bad_default_nicknames[i])) {
- tor_free(out);
- return NULL;
- }
- }
-
- return out;
-}
-
/** Release storage held by <b>options</b>. */
static void
config_free(config_format_t *fmt, void *options)
@@ -2839,7 +2800,9 @@ compute_publishserverdescriptor(or_options_t *options)
else if (!strcasecmp(string, "bridge"))
*auth |= BRIDGE_AUTHORITY;
else if (!strcasecmp(string, "hidserv"))
- *auth |= HIDSERV_AUTHORITY;
+ log_warn(LD_CONFIG,
+ "PublishServerDescriptor hidserv is invalid. See "
+ "PublishHidServDescriptors.");
else if (!strcasecmp(string, "") || !strcmp(string, "0"))
/* no authority */;
else
@@ -2965,14 +2928,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->Nickname == NULL) {
if (server_mode(options)) {
- if (!(options->Nickname = get_default_nickname())) {
- log_notice(LD_CONFIG, "Couldn't pick a nickname based on "
- "our hostname; using %s instead.", UNNAMED_ROUTER_NICKNAME);
options->Nickname = tor_strdup(UNNAMED_ROUTER_NICKNAME);
- } else {
- log_notice(LD_CONFIG, "Choosing default nickname '%s'",
- options->Nickname);
- }
}
} else {
if (!is_legal_nickname(options->Nickname)) {
@@ -3343,6 +3299,11 @@ options_validate(or_options_t *old_options, or_options_t *options,
"PerConnBWBurst", msg) < 0)
return -1;
+ if (options->RelayBandwidthRate && !options->RelayBandwidthBurst)
+ options->RelayBandwidthBurst = options->RelayBandwidthRate;
+ if (options->RelayBandwidthBurst && !options->RelayBandwidthRate)
+ options->RelayBandwidthRate = options->RelayBandwidthBurst;
+
if (server_mode(options)) {
if (options->BandwidthRate < ROUTER_REQUIRED_MIN_BANDWIDTH) {
tor_asprintf(msg,
@@ -3371,9 +3332,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
}
- if (options->RelayBandwidthRate && !options->RelayBandwidthBurst)
- options->RelayBandwidthBurst = options->RelayBandwidthRate;
-
if (options->RelayBandwidthRate > options->RelayBandwidthBurst)
REJECT("RelayBandwidthBurst must be at least equal "
"to RelayBandwidthRate.");
@@ -3639,12 +3597,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
"ignore you.");
}
- /*XXXX022 checking for defaults manually like this is a bit fragile.*/
+ /*XXXX023 checking for defaults manually like this is a bit fragile.*/
/* Keep changes to hard-coded values synchronous to man page and default
* values table. */
if (options->TestingV3AuthInitialVotingInterval != 30*60 &&
- !options->TestingTorNetwork) {
+ !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
REJECT("TestingV3AuthInitialVotingInterval may only be changed in testing "
"Tor networks!");
} else if (options->TestingV3AuthInitialVotingInterval < MIN_VOTE_INTERVAL) {
@@ -3655,7 +3613,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingV3AuthInitialVoteDelay != 5*60 &&
- !options->TestingTorNetwork) {
+ !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
+
REJECT("TestingV3AuthInitialVoteDelay may only be changed in testing "
"Tor networks!");
} else if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS) {
@@ -3663,7 +3622,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingV3AuthInitialDistDelay != 5*60 &&
- !options->TestingTorNetwork) {
+ !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
REJECT("TestingV3AuthInitialDistDelay may only be changed in testing "
"Tor networks!");
} else if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS) {
@@ -3678,7 +3637,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingAuthDirTimeToLearnReachability != 30*60 &&
- !options->TestingTorNetwork) {
+ !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
REJECT("TestingAuthDirTimeToLearnReachability may only be changed in "
"testing Tor networks!");
} else if (options->TestingAuthDirTimeToLearnReachability < 0) {
@@ -3688,7 +3647,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (options->TestingEstimatedDescriptorPropagationTime != 10*60 &&
- !options->TestingTorNetwork) {
+ !options->TestingTorNetwork && !options->_UsingTestNetworkDefaults) {
REJECT("TestingEstimatedDescriptorPropagationTime may only be changed in "
"testing Tor networks!");
} else if (options->TestingEstimatedDescriptorPropagationTime < 0) {
@@ -3810,7 +3769,9 @@ options_transition_affects_workers(or_options_t *old_options,
new_options->ServerDNSSearchDomains ||
old_options->SafeLogging != new_options->SafeLogging ||
old_options->ClientOnly != new_options->ClientOnly ||
- !config_lines_eq(old_options->Logs, new_options->Logs))
+ public_server_mode(old_options) != public_server_mode(new_options) ||
+ !config_lines_eq(old_options->Logs, new_options->Logs) ||
+ old_options->LogMessageDomains != new_options->LogMessageDomains)
return 1;
/* Check whether log options match. */
@@ -4366,11 +4327,13 @@ options_init_logs(or_options_t *options, int validate_only)
if (smartlist_len(elts) == 2 &&
!strcasecmp(smartlist_get(elts,0), "file")) {
if (!validate_only) {
- if (add_file_log(severity, smartlist_get(elts, 1)) < 0) {
+ char *fname = expand_filename(smartlist_get(elts, 1));
+ if (add_file_log(severity, fname) < 0) {
log_warn(LD_CONFIG, "Couldn't open file for 'Log %s': %s",
opt->value, strerror(errno));
ok = 0;
}
+ tor_free(fname);
}
goto cleanup;
}
@@ -4386,6 +4349,9 @@ options_init_logs(or_options_t *options, int validate_only)
}
smartlist_free(elts);
+ if (ok && !validate_only)
+ logs_set_domain_logging(options->LogMessageDomains);
+
return ok?0:-1;
}
@@ -4751,10 +4717,10 @@ options_save_current(void)
}
/** Mapping from a unit name to a multiplier for converting that unit into a
- * base unit. */
+ * base unit. Used by config_parse_unit. */
struct unit_table_t {
- const char *unit;
- uint64_t multiplier;
+ const char *unit; /**< The name of the unit */
+ uint64_t multiplier; /**< How many of the base unit appear in this unit */
};
/** Table to map the names of memory units to the number of bytes they
@@ -5145,6 +5111,9 @@ or_state_load(void)
return r;
}
+/** If writing the state to disk fails, try again after this many seconds. */
+#define STATE_WRITE_RETRY_INTERVAL 3600
+
/** Write the persistent state to disk. Return 0 for success, <0 on failure. */
int
or_state_save(time_t now)
@@ -5179,10 +5148,14 @@ or_state_save(time_t now)
tor_free(state);
fname = get_datadir_fname("state");
if (write_str_to_file(fname, contents, 0)<0) {
- log_warn(LD_FS, "Unable to write state to file \"%s\"", fname);
+ log_warn(LD_FS, "Unable to write state to file \"%s\"; "
+ "will try again later", fname);
global_state->LastWritten = -1;
tor_free(fname);
tor_free(contents);
+ /* Try again after STATE_WRITE_RETRY_INTERVAL (or sooner, if the state
+ * changes sooner). */
+ global_state->next_write = now + STATE_WRITE_RETRY_INTERVAL;
return -1;
}
diff --git a/src/or/connection.c b/src/or/connection.c
index 8a21d81c58..6e7bbd5bad 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -51,7 +51,7 @@ static int connection_finished_flushing(connection_t *conn);
static int connection_flushed_some(connection_t *conn);
static int connection_finished_connecting(connection_t *conn);
static int connection_reached_eof(connection_t *conn);
-static int connection_read_to_buf(connection_t *conn, int *max_to_read,
+static int connection_read_to_buf(connection_t *conn, ssize_t *max_to_read,
int *socket_error);
static int connection_process_inbuf(connection_t *conn, int package_partial);
static void client_check_address_changed(int sock);
@@ -1178,7 +1178,8 @@ connection_handle_listener_read(connection_t *conn, int new_type)
}
if (connection_init_accepted_conn(newconn, conn->type) < 0) {
- connection_mark_for_close(newconn);
+ if (! newconn->marked_for_close)
+ connection_mark_for_close(newconn);
return 0;
}
return 0;
@@ -1204,9 +1205,11 @@ connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
conn->state = AP_CONN_STATE_SOCKS_WAIT;
break;
case CONN_TYPE_AP_TRANS_LISTENER:
+ TO_EDGE_CONN(conn)->is_transparent_ap = 1;
conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
return connection_ap_process_transparent(TO_EDGE_CONN(conn));
case CONN_TYPE_AP_NATD_LISTENER:
+ TO_EDGE_CONN(conn)->is_transparent_ap = 1;
conn->state = AP_CONN_STATE_NATD_WAIT;
break;
}
@@ -2335,7 +2338,7 @@ connection_bucket_should_increase(int bucket, or_connection_t *conn)
static int
connection_handle_read_impl(connection_t *conn)
{
- int max_to_read=-1, try_to_read;
+ ssize_t max_to_read=-1, try_to_read;
size_t before, n_read = 0;
int socket_error = 0;
@@ -2453,7 +2456,8 @@ connection_handle_read(connection_t *conn)
* Return -1 if we want to break conn, else return 0.
*/
static int
-connection_read_to_buf(connection_t *conn, int *max_to_read, int *socket_error)
+connection_read_to_buf(connection_t *conn, ssize_t *max_to_read,
+ int *socket_error)
{
int result;
ssize_t at_most = *max_to_read;
@@ -2571,15 +2575,19 @@ connection_read_to_buf(connection_t *conn, int *max_to_read, int *socket_error)
n_read = (size_t) result;
}
- if (n_read > 0) { /* change *max_to_read */
- /*XXXX021 check for overflow*/
- *max_to_read = (int)(at_most - n_read);
- }
+ if (n_read > 0) {
+ /* change *max_to_read */
+ *max_to_read = at_most - n_read;
- if (conn->type == CONN_TYPE_AP) {
- edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
- /*XXXX021 check for overflow*/
- edge_conn->n_read += (int)n_read;
+ /* Update edge_conn->n_read */
+ if (conn->type == CONN_TYPE_AP) {
+ edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
+ /* Check for overflow: */
+ if (PREDICT_LIKELY(UINT32_MAX - edge_conn->n_read > n_read))
+ edge_conn->n_read += (int)n_read;
+ else
+ edge_conn->n_read = UINT32_MAX;
+ }
}
connection_buckets_decrement(conn, approx_time(), n_read, n_written);
@@ -2778,10 +2786,13 @@ connection_handle_write_impl(connection_t *conn, int force)
n_written = (size_t) result;
}
- if (conn->type == CONN_TYPE_AP) {
+ if (n_written && conn->type == CONN_TYPE_AP) {
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
- /*XXXX021 check for overflow.*/
- edge_conn->n_written += (int)n_written;
+ /* Check for overflow: */
+ if (PREDICT_LIKELY(UINT32_MAX - edge_conn->n_written > n_written))
+ edge_conn->n_written += (int)n_written;
+ else
+ edge_conn->n_written = UINT32_MAX;
}
connection_buckets_decrement(conn, approx_time(), n_read, n_written);
@@ -3242,6 +3253,8 @@ connection_flushed_some(connection_t *conn)
r = connection_dirserv_flushed_some(TO_DIR_CONN(conn));
} else if (conn->type == CONN_TYPE_OR) {
r = connection_or_flushed_some(TO_OR_CONN(conn));
+ } else if (CONN_IS_EDGE(conn)) {
+ r = connection_edge_flushed_some(TO_EDGE_CONN(conn));
}
conn->in_flushed_some = 0;
return r;
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 73ed9fb5c3..72e2c8a409 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -301,6 +301,23 @@ connection_edge_end_errno(edge_connection_t *conn)
return connection_edge_end(conn, reason);
}
+/** We just wrote some data to <b>conn</b>; act appropriately.
+ *
+ * (That is, if it's open, consider sending a stream-level sendme cell if we
+ * have just flushed enough.)
+ */
+int
+connection_edge_flushed_some(edge_connection_t *conn)
+{
+ switch (conn->_base.state) {
+ case AP_CONN_STATE_OPEN:
+ case EXIT_CONN_STATE_OPEN:
+ connection_edge_consider_sending_sendme(conn);
+ break;
+ }
+ return 0;
+}
+
/** Connection <b>conn</b> has finished writing and has no bytes left on
* its outbuf.
*
@@ -500,6 +517,7 @@ connection_ap_expire_beginning(void)
/* 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 */
+ /* XXXX023 this is a kludgy way to do this. */
tor_assert(circ->timestamp_dirty);
circ->timestamp_dirty -= options->MaxCircuitDirtiness;
/* give our stream another 'cutoff' seconds to try */
@@ -540,7 +558,7 @@ connection_ap_attach_pending(void)
/** Tell any AP streams that are waiting for a one-hop tunnel to
* <b>failed_digest</b> that they are going to fail. */
-/* XXX022 We should get rid of this function, and instead attach
+/* XXX023 We should get rid of this function, and instead attach
* one-hop streams to circ->p_streams so they get marked in
* circuit_mark_for_close like normal p_streams. */
void
@@ -1659,6 +1677,28 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
+ if (options->ClientRejectInternalAddresses &&
+ !conn->use_begindir && !conn->chosen_exit_name && !circ) {
+ tor_addr_t addr;
+ if (tor_addr_from_str(&addr, socks->address) >= 0 &&
+ tor_addr_is_internal(&addr, 0)) {
+ /* If this is an explicit private address with no chosen exit node,
+ * then we really don't want to try to connect to it. That's
+ * probably an error. */
+ if (conn->is_transparent_ap) {
+ log_warn(LD_NET,
+ "Rejecting request for anonymous connection to private "
+ "address %s on a TransPort or NATDPort. Possible loop "
+ "in your NAT rules?", safe_str_client(socks->address));
+ } else {
+ log_warn(LD_NET,
+ "Rejecting SOCKS request for anonymous connection to "
+ "private address %s", safe_str_client(socks->address));
+ }
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_PRIVATE_ADDR);
+ return -1;
+ }
+ }
if (!conn->use_begindir && !conn->chosen_exit_name && !circ) {
/* see if we can find a suitable enclave exit */
@@ -2124,8 +2164,14 @@ connection_ap_handshake_send_begin(edge_connection_t *ap_conn)
ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
if (ap_conn->stream_id==0) {
+ /* XXXX023 Instead of closing this stream, we should make it get
+ * retried on another circuit. */
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
+
+ /* Mark this circuit "unusable for new streams". */
+ /* XXXX023 this is a kludgy way to do this. */
+ tor_assert(circ->_base.timestamp_dirty);
+ circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
return -1;
}
@@ -2183,9 +2229,14 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn)
ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
if (ap_conn->stream_id==0) {
+ /* XXXX023 Instead of closing this stream, we should make it get
+ * retried on another circuit. */
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
- /*XXXX022 _close_ the circuit because it's full? That sounds dumb. */
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
+
+ /* Mark this circuit "unusable for new streams". */
+ /* XXXX023 this is a kludgy way to do this. */
+ tor_assert(circ->_base.timestamp_dirty);
+ circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
return -1;
}
@@ -2343,7 +2394,7 @@ tell_controller_about_resolved_result(edge_connection_t *conn,
* certain errors or for values that didn't come via DNS. <b>expires</b> is
* a time when the answer expires, or -1 or TIME_MAX if there's a good TTL.
**/
-/* XXXX022 the use of the ttl and expires fields is nutty. Let's make this
+/* XXXX023 the use of the ttl and expires fields is nutty. Let's make this
* interface and those that use it less ugly. */
void
connection_ap_handshake_socks_resolved(edge_connection_t *conn,
@@ -2784,13 +2835,13 @@ connection_exit_connect(edge_connection_t *edge_conn)
log_debug(LD_EXIT,"about to try connecting");
switch (connection_connect(conn, conn->address, addr, port, &socket_error)) {
- case -1:
- /* XXX021 use socket_error below rather than trying to piece things
- * together from the current errno, which may have been clobbered. */
- connection_edge_end_errno(edge_conn);
+ case -1: {
+ int reason = errno_to_stream_end_reason(socket_error);
+ connection_edge_end(edge_conn, reason);
circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
connection_free(conn);
return;
+ }
case 0:
conn->state = EXIT_CONN_STATE_CONNECTING;
diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h
index fa5f91cf8d..0b08dd07ca 100644
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@ -23,6 +23,7 @@ int connection_edge_process_inbuf(edge_connection_t *conn,
int connection_edge_destroy(circid_t circ_id, edge_connection_t *conn);
int connection_edge_end(edge_connection_t *conn, uint8_t reason);
int connection_edge_end_errno(edge_connection_t *conn);
+int connection_edge_flushed_some(edge_connection_t *conn);
int connection_edge_finished_flushing(edge_connection_t *conn);
int connection_edge_finished_connecting(edge_connection_t *conn);
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index cf7c09a3cd..4b932ec51e 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -353,6 +353,9 @@ connection_or_digest_is_known_relay(const char *id_digest)
* per-conn limits that are big enough they'll never matter. But if it's
* not a known relay, first check if we set PerConnBwRate/Burst, then
* check if the consensus sets them, else default to 'big enough'.
+ *
+ * If <b>reset</b> is true, set the bucket to be full. Otherwise, just
+ * clip the bucket if it happens to be <em>too</em> full.
*/
static void
connection_or_update_token_buckets_helper(or_connection_t *conn, int reset,
@@ -370,11 +373,11 @@ connection_or_update_token_buckets_helper(or_connection_t *conn, int reset,
* bandwidth parameters in the consensus, but allow local config
* options to override. */
rate = options->PerConnBWRate ? (int)options->PerConnBWRate :
- (int)networkstatus_get_param(NULL, "perconnbwrate",
- (int)options->BandwidthRate);
+ networkstatus_get_param(NULL, "perconnbwrate",
+ (int)options->BandwidthRate, 1, INT32_MAX);
burst = options->PerConnBWBurst ? (int)options->PerConnBWBurst :
- (int)networkstatus_get_param(NULL, "perconnbwburst",
- (int)options->BandwidthBurst);
+ networkstatus_get_param(NULL, "perconnbwburst",
+ (int)options->BandwidthBurst, 1, INT32_MAX);
}
conn->bandwidthrate = rate;
@@ -392,7 +395,8 @@ connection_or_update_token_buckets_helper(or_connection_t *conn, int reset,
}
/** Either our set of relays or our per-conn rate limits have changed.
- * Go through all the OR connections and update their token buckets. */
+ * Go through all the OR connections and update their token buckets to make
+ * sure they don't exceed their maximum values. */
void
connection_or_update_token_buckets(smartlist_t *conns, or_options_t *options)
{
@@ -467,7 +471,7 @@ connection_or_init_conn_from_address(or_connection_t *conn,
* Requires that both input connections are open; not is_bad_for_new_circs,
* and not impossibly non-canonical.
*
- * If </b>forgive_new_connections</b> is true, then we do not call
+ * If <b>forgive_new_connections</b> is true, then we do not call
* <b>a</b>better than <b>b</b> simply because b has no circuits,
* unless b is also relatively old.
*/
@@ -1098,9 +1102,6 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
as_advertised = 0;
}
if (authdir_mode_tests_reachability(options)) {
- /* We initiated this connection to address:port. Drop all routers
- * with the same address:port and a different key.
- */
dirserv_orconn_tls_done(conn->_base.address, conn->_base.port,
digest_rcvd_out, as_advertised);
}
diff --git a/src/or/control.c b/src/or/control.c
index fb9c1aeaf6..8f3af0bda1 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1785,12 +1785,12 @@ getinfo_helper_events(control_connection_t *control_conn,
"information", question);
}
} else if (!strcmp(question, "status/clients-seen")) {
- const char *bridge_stats = geoip_get_bridge_stats_controller(time(NULL));
+ char *bridge_stats = geoip_get_bridge_stats_controller(time(NULL));
if (!bridge_stats) {
*errmsg = "No bridge-client stats available";
return -1;
}
- *answer = tor_strdup(bridge_stats);
+ *answer = bridge_stats;
} else {
return 0;
}
diff --git a/src/or/directory.c b/src/or/directory.c
index 7360a47e46..8f33a608d4 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -372,7 +372,7 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
if (!get_via_tor) {
if (options->UseBridges && type != BRIDGE_AUTHORITY) {
/* want to ask a running bridge for which we have a descriptor. */
- /* XXX022 we assume that all of our bridges can answer any
+ /* XXX023 we assume that all of our bridges can answer any
* possible directory question. This won't be true forever. -RD */
/* It certainly is not true with conditional consensus downloading,
* so, for now, never assume the server supports that. */
@@ -1527,9 +1527,10 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
delta>0 ? "ahead" : "behind", dbuf,
delta>0 ? "behind" : "ahead");
skewed = 1; /* don't check the recommended-versions line */
- control_event_general_status(trusted ? LOG_WARN : LOG_NOTICE,
- "CLOCK_SKEW SKEW=%ld SOURCE=DIRSERV:%s:%d",
- delta, conn->_base.address, conn->_base.port);
+ if (trusted)
+ control_event_general_status(LOG_WARN,
+ "CLOCK_SKEW SKEW=%ld SOURCE=DIRSERV:%s:%d",
+ delta, conn->_base.address, conn->_base.port);
} else {
log_debug(LD_HTTP, "Time on received directory is within tolerance; "
"we are %ld seconds skewed. (That's okay.)", delta);
@@ -1538,26 +1539,19 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
(void) skewed; /* skewed isn't used yet. */
if (status_code == 503) {
- if (body_len < 16) {
- routerstatus_t *rs;
- trusted_dir_server_t *ds;
- log_info(LD_DIR,"Received http status code %d (%s) from server "
- "'%s:%d'. I'll try again soon.",
- status_code, escaped(reason), conn->_base.address,
- conn->_base.port);
- if ((rs = router_get_consensus_status_by_id(conn->identity_digest)))
- rs->last_dir_503_at = now;
- if ((ds = router_get_trusteddirserver_by_digest(conn->identity_digest)))
- ds->fake_status.last_dir_503_at = now;
+ routerstatus_t *rs;
+ trusted_dir_server_t *ds;
+ log_info(LD_DIR,"Received http status code %d (%s) from server "
+ "'%s:%d'. I'll try again soon.",
+ status_code, escaped(reason), conn->_base.address,
+ conn->_base.port);
+ if ((rs = router_get_consensus_status_by_id(conn->identity_digest)))
+ rs->last_dir_503_at = now;
+ if ((ds = router_get_trusteddirserver_by_digest(conn->identity_digest)))
+ ds->fake_status.last_dir_503_at = now;
- tor_free(body); tor_free(headers); tor_free(reason);
- return -1;
- }
- /* XXXX022 Remove this once every server with bug 539 is obsolete. */
- log_info(LD_DIR, "Server at '%s:%d' sent us a 503 response, but included "
- "a body anyway. We'll pretend it gave us a 200.",
- conn->_base.address, conn->_base.port);
- status_code = 200;
+ tor_free(body); tor_free(headers); tor_free(reason);
+ return -1;
}
plausible = body_is_plausible(body, body_len, conn->_base.purpose);
@@ -1875,7 +1869,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
ds->nickname);
/* XXXX use this information; be sure to upload next one
* sooner. -NM */
- /* XXXX021 On further thought, the task above implies that we're
+ /* XXXX023 On further thought, the task above implies that we're
* basing our regenerate-descriptor time on when we uploaded the
* last descriptor, not on the published time of the last
* descriptor. If those are different, that's a bad thing to
@@ -2705,7 +2699,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
ssize_t estimated_len = 0;
smartlist_t *items = smartlist_create();
smartlist_t *dir_items = smartlist_create();
- int lifetime = 60; /* XXXX022 should actually use vote intervals. */
+ int lifetime = 60; /* XXXX023 should actually use vote intervals. */
url += strlen("/tor/status-vote/");
current = !strcmpstart(url, "current/");
url = strchr(url, '/');
@@ -3258,6 +3252,8 @@ directory_handle_command_post(dir_connection_t *conn, const char *headers,
write_http_status_line(conn, status, "Vote stored");
} else {
tor_assert(msg);
+ log_warn(LD_DIRSERV, "Rejected vote from %s (\"%s\").",
+ conn->_base.address, msg);
write_http_status_line(conn, status, msg);
}
goto done;
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 876698a2dc..f65f25811b 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -43,6 +43,8 @@
extern time_t time_of_process_start; /* from main.c */
+extern long stats_n_seconds_working; /* from main.c */
+
/** Do we need to regenerate the v1 directory when someone asks for it? */
static time_t the_directory_is_dirty = 1;
/** Do we need to regenerate the v1 runningrouters document when somebody
@@ -944,7 +946,7 @@ running_long_enough_to_decide_unreachable(void)
void
dirserv_set_router_is_running(routerinfo_t *router, time_t now)
{
- /*XXXX022 This function is a mess. Separate out the part that calculates
+ /*XXXX023 This function is a mess. Separate out the part that calculates
whether it's reachable and the part that tells rephist that the router was
unreachable.
*/
@@ -969,8 +971,18 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
}
if (!answer && running_long_enough_to_decide_unreachable()) {
- /* not considered reachable. tell rephist. */
- rep_hist_note_router_unreachable(router->cache_info.identity_digest, now);
+ /* Not considered reachable. tell rephist about that.
+
+ Because we launch a reachability test for each router every
+ REACHABILITY_TEST_CYCLE_PERIOD seconds, then the router has probably
+ been down since at least that time after we last successfully reached
+ it.
+ */
+ time_t when = now;
+ if (router->last_reachable &&
+ router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now)
+ when = router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD;
+ rep_hist_note_router_unreachable(router->cache_info.identity_digest, when);
}
router->is_running = answer;
@@ -1742,9 +1754,12 @@ dirserv_thinks_router_is_unreliable(time_t now,
{
if (need_uptime) {
if (!enough_mtbf_info) {
- /* XXX022 Once most authorities are on v3, we should change the rule from
+ /* XXX023 Once most authorities are on v3, we should change the rule from
* "use uptime if we don't have mtbf data" to "don't advertise Stable on
- * v3 if we don't have enough mtbf data." */
+ * v3 if we don't have enough mtbf data." Or maybe not, since if we ever
+ * hit a point where we need to reset a lot of authorities at once,
+ * none of them would be in a position to declare Stable.
+ */
long uptime = real_uptime(router, now);
if ((unsigned)uptime < stable_uptime &&
(unsigned)uptime < UPTIME_TO_GUARANTEE_STABLE)
@@ -1775,7 +1790,22 @@ dirserv_thinks_router_is_unreliable(time_t now,
static int
dirserv_thinks_router_is_hs_dir(routerinfo_t *router, time_t now)
{
- long uptime = real_uptime(router, now);
+
+ long uptime;
+
+ /* If we haven't been running for at least
+ * get_options()->MinUptimeHidServDirectoryV2 seconds, we can't
+ * have accurate data telling us a relay has been up for at least
+ * that long. We also want to allow a bit of slack: Reachability
+ * tests aren't instant. If we haven't been running long enough,
+ * trust the relay. */
+
+ if (stats_n_seconds_working >
+ get_options()->MinUptimeHidServDirectoryV2 * 1.1)
+ uptime = MIN(rep_hist_get_uptime(router->cache_info.identity_digest, now),
+ real_uptime(router, now));
+ else
+ uptime = real_uptime(router, now);
/* XXX We shouldn't need to check dir_port, but we do because of
* bug 1693. In the future, once relays set wants_to_be_hs_dir
@@ -2970,6 +3000,8 @@ dirserv_get_routerdesc_fingerprints(smartlist_t *fps_out, const char *key,
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
smartlist_add(fps_out,
tor_memdup(r->cache_info.identity_digest, DIGEST_LEN)));
+ /* Treat "all" requests as if they were unencrypted */
+ for_unencrypted_conn = 1;
} else if (!strcmp(key, "authority")) {
routerinfo_t *ri = router_get_my_routerinfo();
if (ri)
@@ -3114,19 +3146,27 @@ dirserv_orconn_tls_done(const char *address,
tor_assert(address);
tor_assert(digest_rcvd);
- SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, {
+ /* XXX023 Doing a loop like this is stupid. We should just look up the
+ * router by digest_rcvd, and see if address, orport, and as_advertised
+ * match up. -NM */
+ SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) {
if (!strcasecmp(address, ri->address) && or_port == ri->or_port &&
as_advertised &&
!memcmp(ri->cache_info.identity_digest, digest_rcvd, DIGEST_LEN)) {
/* correct digest. mark this router reachable! */
if (!bridge_auth || ri->purpose == ROUTER_PURPOSE_BRIDGE) {
- log_info(LD_DIRSERV, "Found router %s to be reachable. Yay.",
- ri->nickname);
- rep_hist_note_router_reachable(digest_rcvd, now);
+ tor_addr_t addr, *addrp=NULL;
+ log_info(LD_DIRSERV, "Found router %s to be reachable at %s:%d. Yay.",
+ ri->nickname, address, ri->or_port );
+ if (tor_addr_from_str(&addr, ri->address) != -1)
+ addrp = &addr;
+ else
+ log_warn(LD_BUG, "Couldn't parse IP address \"%s\"", ri->address);
+ rep_hist_note_router_reachable(digest_rcvd, addrp, or_port, now);
ri->last_reachable = now;
}
}
- });
+ } SMARTLIST_FOREACH_END(ri);
/* FFFF Maybe we should reinstate the code that dumps routers with the same
* addr/port but with nonmatching keys, but instead of dumping, we should
* skip testing. */
@@ -3177,8 +3217,8 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router)
* try a few connections per call.
*
* The load balancing is such that if we get called once every ten
- * seconds, we will cycle through all the tests in 1280 seconds (a
- * bit over 20 minutes).
+ * seconds, we will cycle through all the tests in
+ * REACHABILITY_TEST_CYCLE_PERIOD seconds (a bit over 20 minutes).
*/
void
dirserv_test_reachability(time_t now)
@@ -3204,11 +3244,11 @@ dirserv_test_reachability(time_t now)
continue; /* bridge authorities only test reachability on bridges */
// if (router->cache_info.published_on > cutoff)
// continue;
- if ((((uint8_t)id_digest[0]) % 128) == ctr) {
+ if ((((uint8_t)id_digest[0]) % REACHABILITY_MODULO_PER_TEST) == ctr) {
dirserv_single_reachability_test(now, router);
}
} SMARTLIST_FOREACH_END(router);
- ctr = (ctr + 1) % 128; /* increment ctr */
+ ctr = (ctr + 1) % REACHABILITY_MODULO_PER_TEST; /* increment ctr */
}
/** Given a fingerprint <b>fp</b> which is either set if we're looking for a
@@ -3223,7 +3263,7 @@ lookup_cached_dir_by_fp(const char *fp)
d = strmap_get(cached_consensuses, "ns");
else if (memchr(fp, '\0', DIGEST_LEN) && cached_consensuses &&
(d = strmap_get(cached_consensuses, fp))) {
- /* this here interface is a nasty hack XXXX022 */;
+ /* this here interface is a nasty hack XXXX023 */;
} else if (router_digest_is_me(fp) && the_v2_networkstatus)
d = the_v2_networkstatus;
else if (cached_v2_networkstatus)
diff --git a/src/or/dirserv.h b/src/or/dirserv.h
index 56ad7a6a56..a8a7060a36 100644
--- a/src/or/dirserv.h
+++ b/src/or/dirserv.h
@@ -12,6 +12,18 @@
#ifndef _TOR_DIRSERV_H
#define _TOR_DIRSERV_H
+/** What fraction (1 over this number) of the relay ID space do we
+ * (as a directory authority) launch connections to at each reachability
+ * test? */
+#define REACHABILITY_MODULO_PER_TEST 128
+
+/** How often (in seconds) do we launch reachability tests? */
+#define REACHABILITY_TEST_INTERVAL 10
+
+/** How many seconds apart are the reachability tests for a given relay? */
+#define REACHABILITY_TEST_CYCLE_PERIOD \
+ (REACHABILITY_TEST_INTERVAL*REACHABILITY_MODULO_PER_TEST)
+
/** Maximum length of an exit policy summary. */
#define MAX_EXITPOLICY_SUMMARY_LEN 1000
@@ -40,7 +52,7 @@
MAX_V_LINE_LEN \
)
-#define UNNAMED_ROUTER_NICKNAME "Unnamed"
+#define UNNAMED_ROUTER_NICKNAME "Unnamed"
int connection_dirserv_flushed_some(dir_connection_t *conn);
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 41985d1485..9273dbc90d 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -50,7 +50,7 @@ static int dirvote_publish_consensus(void);
static char *make_consensus_method_list(int low, int high, const char *sep);
/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 10
+#define MAX_SUPPORTED_CONSENSUS_METHOD 11
/** Lowest consensus method that contains a 'directory-footer' marker */
#define MIN_METHOD_FOR_FOOTER 9
@@ -1693,7 +1693,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
const char *chosen_name = NULL;
int exitsummary_disagreement = 0;
int is_named = 0, is_unnamed = 0, is_running = 0;
- int is_guard = 0, is_exit = 0;
+ int is_guard = 0, is_exit = 0, is_bad_exit = 0;
int naming_conflict = 0;
int n_listing = 0;
int i;
@@ -1819,6 +1819,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
is_guard = 1;
else if (!strcmp(fl, "Running"))
is_running = 1;
+ else if (!strcmp(fl, "BadExit"))
+ is_bad_exit = 1;
}
}
});
@@ -1845,6 +1847,11 @@ networkstatus_compute_consensus(smartlist_t *votes,
rs_out.bandwidth = median_uint32(bandwidths, num_bandwidths);
}
+ /* Fix bug 2203: Do not count BadExit nodes as Exits for bw weights */
+ if (consensus_method >= 11) {
+ is_exit = is_exit && !is_bad_exit;
+ }
+
if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) {
if (rs_out.has_bandwidth) {
T += rs_out.bandwidth;
@@ -3073,7 +3080,7 @@ dirvote_compute_consensuses(void)
n_votes = smartlist_len(pending_vote_list);
if (n_votes <= n_voters/2) {
log_warn(LD_DIR, "We don't have enough votes to generate a consensus: "
- "%d of %d", n_votes, n_voters/2);
+ "%d of %d", n_votes, n_voters/2+1);
goto err;
}
tor_assert(pending_vote_list);
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index cd5fe86bc1..67540a37fb 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -19,9 +19,6 @@
/** Smallest allowable voting interval. */
#define MIN_VOTE_INTERVAL 300
-/** Precision multiplier for the Bw weights */
-#define BW_WEIGHT_SCALE 10000
-
void dirvote_free_all(void);
/* vote manipulation */
diff --git a/src/or/dns.c b/src/or/dns.c
index 5c763011ba..61c8f32c98 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -54,12 +54,19 @@ struct evdns_request;
evdns_config_windows_nameservers()
#define evdns_base_set_option_(base, opt, val) \
evdns_set_option((opt),(val),DNS_OPTIONS_ALL)
+/* Note: our internal eventdns.c, plus Libevent 1.4, used a 1 return to
+ * signify failure to launch a resolve. Libevent 2.0 uses a -1 return to
+ * signify a failure on a resolve, though if we're on Libevent 2.0, we should
+ * have event2/dns.h and never hit these macros. Regardless, 0 is success. */
#define evdns_base_resolve_ipv4(base, addr, options, cb, ptr) \
- ((evdns_resolve_ipv4(addr, options, cb, ptr)<0) ? NULL : ((void*)1))
-#define evdns_base_resolve_reverse(base, addr, options, cb, ptr) \
- ((evdns_resolve_reverse(addr, options, cb, ptr)<0) ? NULL : ((void*)1))
-#define evdns_base_resolve_reverse_ipv6(base, addr, options, cb, ptr) \
- ((evdns_resolve_reverse_ipv6(addr, options, cb, ptr)<0) ? NULL : ((void*)1))
+ ((evdns_resolve_ipv4((addr), (options), (cb), (ptr))!=0) \
+ ? NULL : ((void*)1))
+#define evdns_base_resolve_reverse(base, addr, options, cb, ptr) \
+ ((evdns_resolve_reverse((addr), (options), (cb), (ptr))!=0) \
+ ? NULL : ((void*)1))
+#define evdns_base_resolve_reverse_ipv6(base, addr, options, cb, ptr) \
+ ((evdns_resolve_reverse_ipv6((addr), (options), (cb), (ptr))!=0) \
+ ? NULL : ((void*)1))
#elif defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER < 0x02000303
#define evdns_base_set_option_(base, opt, val) \
@@ -1199,7 +1206,7 @@ configure_nameservers(int force)
struct sockaddr_storage ss;
socklen = tor_addr_to_sockaddr(&addr, 0,
(struct sockaddr *)&ss, sizeof(ss));
- if (socklen < 0) {
+ if (socklen <= 0) {
log_warn(LD_BUG, "Couldn't convert outbound bind address to sockaddr."
" Ignoring.");
} else {
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index 63ecbd2266..243b730cbf 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -19,7 +19,7 @@
#ifdef HAVE_EVENT2_DNS_H
#include <event2/dns.h>
#include <event2/dns_compat.h>
-/* XXXX022 this implies we want an improved evdns */
+/* XXXX023 this implies we want an improved evdns */
#include <event2/dns_struct.h>
#else
#include "eventdns.h"
@@ -282,11 +282,12 @@ dnsserv_resolved(edge_connection_t *conn,
name,
1, answer, ttl);
} else if (answer_type == RESOLVED_TYPE_HOSTNAME &&
+ answer_len < 256 &&
conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR) {
char *ans = tor_strndup(answer, answer_len);
evdns_server_request_add_ptr_reply(req, NULL,
name,
- (char*)answer, ttl);
+ ans, ttl);
tor_free(ans);
} else if (answer_type == RESOLVED_TYPE_ERROR) {
err = DNS_ERR_NOTEXIST;
diff --git a/src/or/eventdns.c b/src/or/eventdns.c
index 04913bf6f7..cf583d0682 100644
--- a/src/or/eventdns.c
+++ b/src/or/eventdns.c
@@ -1904,7 +1904,7 @@ server_request_free(struct server_request *req)
if (req->port) {
if (req->port->pending_replies == req) {
- if (req->next_pending)
+ if (req->next_pending && req->next_pending != req)
req->port->pending_replies = req->next_pending;
else
req->port->pending_replies = NULL;
@@ -1999,7 +1999,7 @@ evdns_request_timeout_callback(int fd, short events, void *arg) {
/* retransmit it */
/* Stop waiting for the timeout. No need to do this in
* request_finished; that one already deletes the timeout event.
- * XXXX021 port this change to libevent. */
+ * XXXX023 port this change to libevent. */
del_timeout_event(req);
evdns_request_transmit(req);
}
diff --git a/src/or/geoip.c b/src/or/geoip.c
index d4e279f538..5bb2410a75 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -214,7 +214,7 @@ geoip_load_file(const char *filename, or_options_t *options)
smartlist_free(geoip_entries);
}
geoip_entries = smartlist_create();
- log_notice(LD_GENERAL, "Parsing GEOIP file.");
+ log_notice(LD_GENERAL, "Parsing GEOIP file %s.", filename);
while (!feof(f)) {
char buf[512];
if (fgets(buf, (int)sizeof(buf), f) == NULL)
@@ -284,11 +284,18 @@ geoip_is_loaded(void)
typedef struct clientmap_entry_t {
HT_ENTRY(clientmap_entry_t) node;
uint32_t ipaddr;
+ /** Time when we last saw this IP address, in MINUTES since the epoch.
+ *
+ * (This will run out of space around 4011 CE. If Tor is still in use around
+ * 4000 CE, please remember to add more bits to last_seen_in_minutes.) */
unsigned int last_seen_in_minutes:30;
unsigned int action:2;
} clientmap_entry_t;
-#define ACTION_MASK 3
+/** Largest allowable value for last_seen_in_minutes. (It's a 30-bit field,
+ * so it can hold up to (1u<<30)-1, or 0x3fffffffu.
+ */
+#define MAX_LAST_SEEN_IN_MINUTES 0X3FFFFFFFu
/** Map from client IP address to last time seen. */
static HT_HEAD(clientmap, clientmap_entry_t) client_history =
@@ -413,15 +420,16 @@ geoip_note_client_seen(geoip_client_action_t action,
lookup.ipaddr = addr;
lookup.action = (int)action;
ent = HT_FIND(clientmap, &client_history, &lookup);
- if (ent) {
- ent->last_seen_in_minutes = now / 60;
- } else {
+ if (! ent) {
ent = tor_malloc_zero(sizeof(clientmap_entry_t));
ent->ipaddr = addr;
- ent->last_seen_in_minutes = now / 60;
ent->action = (int)action;
HT_INSERT(clientmap, &client_history, ent);
}
+ if (now / 60 <= (int)MAX_LAST_SEEN_IN_MINUTES && now >= 0)
+ ent->last_seen_in_minutes = (unsigned)(now/60);
+ else
+ ent->last_seen_in_minutes = 0;
if (action == GEOIP_CLIENT_NETWORKSTATUS ||
action == GEOIP_CLIENT_NETWORKSTATUS_V2) {
@@ -593,8 +601,9 @@ _dirreq_map_put(dirreq_map_entry_t *entry, dirreq_type_t type,
tor_assert(entry->type == type);
tor_assert(entry->dirreq_id == dirreq_id);
- /* XXXX022 once we're sure the bug case never happens, we can switch
- * to HT_INSERT */
+ /* XXXX we could switch this to HT_INSERT some time, since it seems that
+ * this bug doesn't happen. But since this function doesn't seem to be
+ * critical-path, it's sane to leave it alone. */
old_ent = HT_REPLACE(dirreqmap, &dirreq_map, entry);
if (old_ent && old_ent != entry) {
log_warn(LD_BUG, "Error when putting directory request into local "
@@ -1075,14 +1084,14 @@ geoip_bridge_stats_term(void)
start_of_bridge_stats_interval = 0;
}
-/** Parse the bridge statistics as they are written to extra-info
- * descriptors for being returned to controller clients. Return the
- * controller string if successful, or NULL otherwise. */
-static char *
-parse_bridge_stats_controller(const char *stats_str, time_t now)
+/** Validate a bridge statistics string as it would be written to a
+ * current extra-info descriptor. Return 1 if the string is valid and
+ * recent enough, or 0 otherwise. */
+static int
+validate_bridge_stats(const char *stats_str, time_t now)
{
char stats_end_str[ISO_TIME_LEN+1], stats_start_str[ISO_TIME_LEN+1],
- *controller_str, *eos, *eol, *summary;
+ *eos;
const char *BRIDGE_STATS_END = "bridge-stats-end ";
const char *BRIDGE_IPS = "bridge-ips ";
@@ -1096,63 +1105,90 @@ parse_bridge_stats_controller(const char *stats_str, time_t now)
"bridge-stats-end YYYY-MM-DD HH:MM:SS (N s)" */
tmp = find_str_at_start_of_line(stats_str, BRIDGE_STATS_END);
if (!tmp)
- return NULL;
+ return 0;
tmp += strlen(BRIDGE_STATS_END);
if (strlen(tmp) < ISO_TIME_LEN + 6)
- return NULL;
+ return 0;
strlcpy(stats_end_str, tmp, sizeof(stats_end_str));
if (parse_iso_time(stats_end_str, &stats_end_time) < 0)
- return NULL;
+ return 0;
if (stats_end_time < now - (25*60*60) ||
stats_end_time > now + (1*60*60))
- return NULL;
+ return 0;
seconds = (int)strtol(tmp + ISO_TIME_LEN + 2, &eos, 10);
if (!eos || seconds < 23*60*60)
- return NULL;
+ return 0;
format_iso_time(stats_start_str, stats_end_time - seconds);
/* Parse: "bridge-ips CC=N,CC=N,..." */
tmp = find_str_at_start_of_line(stats_str, BRIDGE_IPS);
- if (tmp) {
- tmp += strlen(BRIDGE_IPS);
- tmp = eat_whitespace_no_nl(tmp);
- eol = strchr(tmp, '\n');
- if (eol)
- summary = tor_strndup(tmp, eol-tmp);
- else
- summary = tor_strdup(tmp);
- } else {
+ if (!tmp) {
/* Look if there is an empty "bridge-ips" line */
tmp = find_str_at_start_of_line(stats_str, BRIDGE_IPS_EMPTY_LINE);
if (!tmp)
- return NULL;
- summary = tor_strdup("");
+ return 0;
}
- tor_asprintf(&controller_str,
- "TimeStarted=\"%s\" CountrySummary=%s",
- stats_start_str, summary);
- tor_free(summary);
- return controller_str;
+ return 1;
}
/** Most recent bridge statistics formatted to be written to extra-info
* descriptors. */
static char *bridge_stats_extrainfo = NULL;
-/** Most recent bridge statistics formatted to be returned to controller
- * clients. */
-static char *bridge_stats_controller = NULL;
+/** Return a newly allocated string holding our bridge usage stats by country
+ * in a format suitable for inclusion in an extrainfo document. Return NULL on
+ * failure. */
+static char *
+format_bridge_stats_extrainfo(time_t now)
+{
+ char *out = NULL, *data = NULL;
+ long duration = now - start_of_bridge_stats_interval;
+ char written[ISO_TIME_LEN+1];
+
+ if (duration < 0)
+ return NULL;
+
+ format_iso_time(written, now);
+ data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+
+ tor_asprintf(&out,
+ "bridge-stats-end %s (%ld s)\n"
+ "bridge-ips %s\n",
+ written, duration,
+ data ? data : "");
+ tor_free(data);
+
+ return out;
+}
+
+/** Return a newly allocated string holding our bridge usage stats by country
+ * in a format suitable for the answer to a controller request. Return NULL on
+ * failure. */
+static char *
+format_bridge_stats_controller(time_t now)
+{
+ char *out = NULL, *data = NULL;
+ char started[ISO_TIME_LEN+1];
+ (void) now;
+
+ format_iso_time(started, start_of_bridge_stats_interval);
+ data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+
+ tor_asprintf(&out,
+ "TimeStarted=\"%s\" CountrySummary=%s",
+ started, data ? data : "");
+ tor_free(data);
+ return out;
+}
/** Write bridge statistics to $DATADIR/stats/bridge-stats and return
* when we should next try to write statistics. */
time_t
geoip_bridge_stats_write(time_t now)
{
- char *statsdir = NULL, *filename = NULL, *data = NULL,
- written[ISO_TIME_LEN+1], *out = NULL, *controller_str;
- size_t len;
+ char *filename = NULL, *val = NULL, *statsdir = NULL;
/* Check if 24 hours have passed since starting measurements. */
if (now < start_of_bridge_stats_interval + WRITE_STATS_INTERVAL)
@@ -1161,64 +1197,54 @@ geoip_bridge_stats_write(time_t now)
/* Discard all items in the client history that are too old. */
geoip_remove_old_clients(start_of_bridge_stats_interval);
+ /* Generate formatted string */
+ val = format_bridge_stats_extrainfo(now);
+ if (val == NULL)
+ goto done;
+
+ /* Update the stored value. */
+ tor_free(bridge_stats_extrainfo);
+ bridge_stats_extrainfo = val;
+ start_of_bridge_stats_interval = now;
+
+ /* Write it to disk. */
statsdir = get_datadir_fname("stats");
if (check_private_dir(statsdir, CPD_CREATE) < 0)
goto done;
filename = get_datadir_fname2("stats", "bridge-stats");
- data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
- format_iso_time(written, now);
- len = strlen("bridge-stats-end (999999 s)\nbridge-ips \n") +
- ISO_TIME_LEN + (data ? strlen(data) : 0) + 42;
- out = tor_malloc(len);
- if (tor_snprintf(out, len, "bridge-stats-end %s (%u s)\nbridge-ips %s\n",
- written, (unsigned) (now - start_of_bridge_stats_interval),
- data ? data : "") < 0)
- goto done;
- write_str_to_file(filename, out, 0);
- controller_str = parse_bridge_stats_controller(out, now);
- if (!controller_str)
- goto done;
- start_of_bridge_stats_interval = now;
- tor_free(bridge_stats_extrainfo);
- tor_free(bridge_stats_controller);
- bridge_stats_extrainfo = out;
- out = NULL;
- bridge_stats_controller = controller_str;
- control_event_clients_seen(controller_str);
+
+ write_str_to_file(filename, bridge_stats_extrainfo, 0);
+
+ /* Tell the controller, "hey, there are clients!" */
+ {
+ char *controller_str = format_bridge_stats_controller(now);
+ if (controller_str)
+ control_event_clients_seen(controller_str);
+ tor_free(controller_str);
+ }
done:
tor_free(filename);
tor_free(statsdir);
- tor_free(data);
- tor_free(out);
- return start_of_bridge_stats_interval +
- WRITE_STATS_INTERVAL;
+
+ return start_of_bridge_stats_interval + WRITE_STATS_INTERVAL;
}
/** Try to load the most recent bridge statistics from disk, unless we
- * have finished a measurement interval lately. */
+ * have finished a measurement interval lately, and check whether they
+ * are still recent enough. */
static void
load_bridge_stats(time_t now)
{
- char *statsdir, *fname=NULL, *contents, *controller_str;
+ char *fname, *contents;
if (bridge_stats_extrainfo)
return;
- statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE) < 0)
- goto done;
+
fname = get_datadir_fname2("stats", "bridge-stats");
contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
- if (contents) {
- controller_str = parse_bridge_stats_controller(contents, now);
- if (controller_str) {
- bridge_stats_extrainfo = contents;
- bridge_stats_controller = controller_str;
- } else {
- tor_free(contents);
- }
- }
- done:
+ if (contents && validate_bridge_stats(contents, now))
+ bridge_stats_extrainfo = contents;
+
tor_free(fname);
- tor_free(statsdir);
}
/** Return most recent bridge statistics for inclusion in extra-info
@@ -1230,13 +1256,12 @@ geoip_get_bridge_stats_extrainfo(time_t now)
return bridge_stats_extrainfo;
}
-/** Return most recent bridge statistics to be returned to controller
- * clients, or NULL if we don't have recent bridge statistics. */
-const char *
+/** Return a new string containing the recent bridge statistics to be returned
+ * to controller clients, or NULL if we don't have any bridge statistics. */
+char *
geoip_get_bridge_stats_controller(time_t now)
{
- load_bridge_stats(now);
- return bridge_stats_controller;
+ return format_bridge_stats_controller(now);
}
/** Start time of entry stats or 0 if we're not collecting entry
diff --git a/src/or/geoip.h b/src/or/geoip.h
index bafbeea0f2..24f7c5b931 100644
--- a/src/or/geoip.h
+++ b/src/or/geoip.h
@@ -51,7 +51,7 @@ void geoip_bridge_stats_init(time_t now);
time_t geoip_bridge_stats_write(time_t now);
void geoip_bridge_stats_term(void);
const char *geoip_get_bridge_stats_extrainfo(time_t);
-const char *geoip_get_bridge_stats_controller(time_t);
+char *geoip_get_bridge_stats_controller(time_t);
#endif
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index 48a7ce75ba..1878d5d52d 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -783,7 +783,8 @@ hibernate_begin(hibernate_state_t new_state, time_t now)
/* XXX upload rendezvous service descriptors with no intro points */
if (new_state == HIBERNATE_STATE_EXITING) {
- log_notice(LD_GENERAL,"Interrupt: will shut down in %d seconds. Interrupt "
+ log_notice(LD_GENERAL,"Interrupt: we have stopped accepting new "
+ "connections, and will shut down in %d seconds. Interrupt "
"again to exit now.", options->ShutdownWaitLength);
shutdown_time = time(NULL) + options->ShutdownWaitLength;
} else { /* soft limit reached */
@@ -940,7 +941,8 @@ consider_hibernation(time_t now)
if (hibernate_state == HIBERNATE_STATE_LIVE) {
if (hibernate_soft_limit_reached()) {
log_notice(LD_ACCT,
- "Bandwidth soft limit reached; commencing hibernation.");
+ "Bandwidth soft limit reached; commencing hibernation. "
+ "No new conncetions will be accepted");
hibernate_begin(HIBERNATE_STATE_LOWBANDWIDTH, now);
} else if (accounting_enabled && now < interval_wakeup_time) {
format_local_iso_time(buf,interval_wakeup_time);
diff --git a/src/or/main.c b/src/or/main.c
index 4b512905c3..83d1e1e517 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -872,6 +872,7 @@ run_scheduled_events(time_t now)
static time_t time_to_check_for_expired_networkstatus = 0;
static time_t time_to_write_stats_files = 0;
static time_t time_to_write_bridge_stats = 0;
+ static time_t time_to_launch_reachability_tests = 0;
static int should_init_bridge_stats = 1;
static time_t time_to_retry_dns_init = 0;
or_options_t *options = get_options();
@@ -962,8 +963,10 @@ run_scheduled_events(time_t now)
if (accounting_is_enabled(options))
accounting_run_housekeeping(now);
- if (now % 10 == 0 && (authdir_mode_tests_reachability(options)) &&
- !we_are_hibernating()) {
+ if (time_to_launch_reachability_tests < now &&
+ (authdir_mode_tests_reachability(options)) &&
+ !we_are_hibernating()) {
+ time_to_launch_reachability_tests = now + REACHABILITY_TEST_INTERVAL;
/* try to determine reachability of the other Tor relays */
dirserv_test_reachability(now);
}
@@ -1147,7 +1150,9 @@ run_scheduled_events(time_t now)
* We do this before step 4, so it can try building more if
* it's not comfortable with the number of available circuits.
*/
- circuit_expire_building(now);
+ /* XXXX022 If our circuit build timeout is much lower than a second, maybe
+ we should do this more often? */
+ circuit_expire_building();
/** 3b. Also look at pending streams and prune the ones that 'began'
* a long time ago but haven't gotten a 'connected' yet.
@@ -2194,6 +2199,19 @@ tor_main(int argc, char *argv[])
}
#endif
+#ifdef MS_WINDOWS
+ /* Call SetProcessDEPPolicy to permanently enable DEP.
+ The function will not resolve on earlier versions of Windows,
+ and failure is not dangerous. */
+ HMODULE hMod = GetModuleHandleA("Kernel32.dll");
+ if (hMod) {
+ typedef BOOL (WINAPI *PSETDEP)(DWORD);
+ PSETDEP setdeppolicy = (PSETDEP)GetProcAddress(hMod,
+ "SetProcessDEPPolicy");
+ if (setdeppolicy) setdeppolicy(1); /* PROCESS_DEP_ENABLE */
+ }
+#endif
+
update_approx_time(time(NULL));
tor_threads_init();
init_logging();
diff --git a/src/or/main.h b/src/or/main.h
index d399aaaaf3..ed0fb97703 100644
--- a/src/or/main.h
+++ b/src/or/main.h
@@ -23,9 +23,11 @@ int connection_is_on_closeable_list(connection_t *conn);
smartlist_t *get_connection_array(void);
+/** Bitmask for events that we can turn on and off with
+ * connection_watch_events. */
typedef enum watchable_events {
- READ_EVENT=0x02,
- WRITE_EVENT=0x04
+ READ_EVENT=0x02, /**< We want to know when a connection is readable */
+ WRITE_EVENT=0x04 /**< We want to know when a connection is writable */
} watchable_events_t;
void connection_watch_events(connection_t *conn, watchable_events_t events);
int connection_is_reading(connection_t *conn);
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 94bcb41002..4f6fe15409 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -439,6 +439,7 @@ networkstatus_check_document_signature(const networkstatus_t *consensus,
signed_digest = tor_malloc(signed_digest_len);
if (crypto_pk_public_checksig(cert->signing_key,
signed_digest,
+ signed_digest_len,
sig->signature,
sig->signature_len) < dlen ||
memcmp(signed_digest, consensus->digests.d[sig->alg], dlen)) {
@@ -1605,7 +1606,7 @@ networkstatus_set_current_consensus(const char *consensus,
if (from_cache && !accept_obsolete &&
c->valid_until < now-OLD_ROUTER_DESC_MAX_AGE) {
- /* XXX022 when we try to make fallbackconsensus work again, we should
+ /* XXXX If we try to make fallbackconsensus work again, we should
* consider taking this out. Until then, believing obsolete consensuses
* is causing more harm than good. See also bug 887. */
log_info(LD_DIR, "Loaded an expired consensus. Discarding.");
@@ -1746,7 +1747,8 @@ networkstatus_set_current_consensus(const char *consensus,
routerstatus_list_update_named_server_map();
cell_ewma_set_scale_factor(options, current_consensus);
- /* XXX022 where is the right place to put this call? */
+ /* XXXX023 this call might be unnecessary here: can changing the
+ * current consensus really alter our view of any OR's rate limits? */
connection_or_update_token_buckets(get_connection_array(), options);
circuit_build_times_new_consensus_params(&circ_times, current_consensus);
@@ -1763,7 +1765,11 @@ networkstatus_set_current_consensus(const char *consensus,
write_str_to_file(consensus_fname, consensus, 0);
}
- if (ftime_definitely_before(now, current_consensus->valid_after)) {
+/** If a consensus appears more than this many seconds before its declared
+ * valid-after time, declare that our clock is skewed. */
+#define EARLY_CONSENSUS_NOTICE_SKEW 60
+
+ if (now < current_consensus->valid_after - EARLY_CONSENSUS_NOTICE_SKEW) {
char tbuf[ISO_TIME_LEN+1];
char dbuf[64];
long delta = now - current_consensus->valid_after;
@@ -2124,32 +2130,52 @@ networkstatus_dump_bridge_status_to_file(time_t now)
tor_free(status);
}
-int32_t
+static int32_t
get_net_param_from_list(smartlist_t *net_params, const char *param_name,
- int default_val)
+ int32_t default_val, int32_t min_val, int32_t max_val)
{
+ int32_t res = default_val;
size_t name_len = strlen(param_name);
+ tor_assert(max_val > min_val);
+ tor_assert(min_val <= default_val);
+ tor_assert(max_val >= default_val);
+
SMARTLIST_FOREACH_BEGIN(net_params, const char *, p) {
if (!strcmpstart(p, param_name) && p[name_len] == '=') {
int ok=0;
long v = tor_parse_long(p+name_len+1, 10, INT32_MIN,
INT32_MAX, &ok, NULL);
- if (ok)
- return (int32_t) v;
+ if (ok) {
+ res = (int32_t) v;
+ break;
+ }
}
} SMARTLIST_FOREACH_END(p);
- return default_val;
+ if (res < min_val) {
+ log_warn(LD_DIR, "Consensus parameter %s is too small. Got %d, raising to "
+ "%d.", param_name, res, min_val);
+ res = min_val;
+ } else if (res > max_val) {
+ log_warn(LD_DIR, "Consensus parameter %s is too large. Got %d, capping to "
+ "%d.", param_name, res, max_val);
+ res = max_val;
+ }
+
+ return res;
}
/** Return the value of a integer parameter from the networkstatus <b>ns</b>
* whose name is <b>param_name</b>. If <b>ns</b> is NULL, try loading the
* latest consensus ourselves. Return <b>default_val</b> if no latest
- * consensus, or if it has no parameter called <b>param_name</b>. */
+ * consensus, or if it has no parameter called <b>param_name</b>.
+ * Make sure the value parsed from the consensus is at least
+ * <b>min_val</b> and at most <b>max_val</b> and raise/cap the parsed value
+ * if necessary. */
int32_t
networkstatus_get_param(networkstatus_t *ns, const char *param_name,
- int32_t default_val)
+ int32_t default_val, int32_t min_val, int32_t max_val)
{
if (!ns) /* if they pass in null, go find it ourselves */
ns = networkstatus_get_latest_consensus();
@@ -2157,24 +2183,36 @@ networkstatus_get_param(networkstatus_t *ns, const char *param_name,
if (!ns || !ns->net_params)
return default_val;
- return get_net_param_from_list(ns->net_params, param_name, default_val);
+ return get_net_param_from_list(ns->net_params, param_name,
+ default_val, min_val, max_val);
}
/** Return the value of a integer bw weight parameter from the networkstatus
* <b>ns</b> whose name is <b>weight_name</b>. If <b>ns</b> is NULL, try
* loading the latest consensus ourselves. Return <b>default_val</b> if no
- * latest consensus, or if it has no parameter called <b>param_name</b>. */
+ * latest consensus, or if it has no parameter called <b>weight_name</b>. */
int32_t
networkstatus_get_bw_weight(networkstatus_t *ns, const char *weight_name,
- int32_t default_val)
+ int32_t default_val)
{
+ int32_t param;
+ int max;
if (!ns) /* if they pass in null, go find it ourselves */
ns = networkstatus_get_latest_consensus();
if (!ns || !ns->weight_params)
return default_val;
- return get_net_param_from_list(ns->weight_params, weight_name, default_val);
+ max = circuit_build_times_get_bw_scale(ns);
+ param = get_net_param_from_list(ns->weight_params, weight_name,
+ default_val, -1,
+ BW_MAX_WEIGHT_SCALE);
+ if (param > max) {
+ log_warn(LD_DIR, "Value of consensus weight %s was too large, capping "
+ "to %d", weight_name, max);
+ param = max;
+ }
+ return param;
}
/** Return the name of the consensus flavor <b>flav</b> as used to identify
diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h
index 2f18dc9525..ec2e8f884d 100644
--- a/src/or/networkstatus.h
+++ b/src/or/networkstatus.h
@@ -81,10 +81,9 @@ void signed_descs_update_status_from_consensus_networkstatus(
char *networkstatus_getinfo_helper_single(routerstatus_t *rs);
char *networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now);
void networkstatus_dump_bridge_status_to_file(time_t now);
-int32_t get_net_param_from_list(smartlist_t *net_params, const char *name,
- int default_val);
int32_t networkstatus_get_param(networkstatus_t *ns, const char *param_name,
- int32_t default_val);
+ int32_t default_val, int32_t min_val,
+ int32_t max_val);
int getinfo_helper_networkstatus(control_connection_t *conn,
const char *question, char **answer,
const char **errmsg);
diff --git a/src/or/ntmain.c b/src/or/ntmain.c
index 06ca2df91e..b2fee648cc 100644
--- a/src/or/ntmain.c
+++ b/src/or/ntmain.c
@@ -54,6 +54,11 @@ static int nt_service_cmd_stop(void);
struct service_fns {
int loaded;
+ /** @{ */
+ /** Function pointers for Windows API functions related to service
+ * management. These are NULL, or they point to the . They're set by
+ * calling the LOAD macro below. */
+
BOOL (WINAPI *ChangeServiceConfig2A_fn)(
SC_HANDLE hService,
DWORD dwInfoLevel,
@@ -122,6 +127,7 @@ struct service_fns {
LPTSTR ReferencedDomainName,
LPDWORD cchReferencedDomainName,
PSID_NAME_USE peUse);
+ /** @} */
} service_fns = { 0,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
@@ -144,6 +150,10 @@ nt_service_loadlibrary(void)
goto err;
}
+/* Helper macro: try to load a function named <b>f</b> from "library" into
+ * service_functions.<b>f</b>_fn. On failure, log an error message, and goto
+ * err.
+ */
#define LOAD(f) STMT_BEGIN \
if (!(fn = GetProcAddress(library, #f))) { \
log_err(LD_BUG, \
diff --git a/src/or/onion.c b/src/or/onion.c
index 9db9145c78..e1d10a60bb 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -184,7 +184,7 @@ onion_skin_create(crypto_pk_env_t *dest_router_key,
*handshake_state_out = NULL;
memset(onion_skin_out, 0, ONIONSKIN_CHALLENGE_LEN);
- if (!(dh = crypto_dh_new()))
+ if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT)))
goto err;
dhbytes = crypto_dh_get_bytes(dh);
@@ -199,6 +199,7 @@ onion_skin_create(crypto_pk_env_t *dest_router_key,
/* set meeting point, meeting cookie, etc here. Leave zero for now. */
if (crypto_pk_public_hybrid_encrypt(dest_router_key, onion_skin_out,
+ ONIONSKIN_CHALLENGE_LEN,
challenge, DH_KEY_LEN,
PK_PKCS1_OAEP_PADDING, 1)<0)
goto err;
@@ -241,6 +242,7 @@ onion_skin_server_handshake(const char *onion_skin, /*ONIONSKIN_CHALLENGE_LEN*/
break;
note_crypto_pk_op(DEC_ONIONSKIN);
len = crypto_pk_private_hybrid_decrypt(k, challenge,
+ ONIONSKIN_CHALLENGE_LEN,
onion_skin, ONIONSKIN_CHALLENGE_LEN,
PK_PKCS1_OAEP_PADDING,0);
if (len>0)
@@ -256,7 +258,11 @@ onion_skin_server_handshake(const char *onion_skin, /*ONIONSKIN_CHALLENGE_LEN*/
goto err;
}
- dh = crypto_dh_new();
+ dh = crypto_dh_new(DH_TYPE_CIRCUIT);
+ if (!dh) {
+ log_warn(LD_BUG, "Couldn't allocate DH key");
+ goto err;
+ }
if (crypto_dh_get_public(dh, handshake_reply_out, DH_KEY_LEN)) {
log_info(LD_GENERAL, "crypto_dh_get_public failed.");
goto err;
diff --git a/src/or/or.h b/src/or/or.h
index cb36126d99..1688a08f96 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -583,6 +583,9 @@ typedef enum {
/** This is a connection on the NATD port, and the destination IP:Port was
* either ill-formed or out-of-range. */
#define END_STREAM_REASON_INVALID_NATD_DEST 261
+/** The target address is in a private network (like 127.0.0.1 or 10.0.0.1);
+ * you don't want to do that over a randomly chosen exit */
+#define END_STREAM_REASON_PRIVATE_ADDR 262
/** Bitwise-and this value with endreason to mask out all flags. */
#define END_STREAM_REASON_MASK 511
@@ -765,6 +768,8 @@ typedef enum {
/** Initial value for both sides of a circuit transmission window when the
* circuit is initialized. Measured in cells. */
#define CIRCWINDOW_START 1000
+#define CIRCWINDOW_START_MIN 100
+#define CIRCWINDOW_START_MAX 1000
/** Amount to increment a circuit window when we get a circuit SENDME. */
#define CIRCWINDOW_INCREMENT 100
/** Initial value on both sides of a stream transmission window when the
@@ -843,9 +848,13 @@ typedef struct cell_t {
/** Parsed variable-length onion routing cell. */
typedef struct var_cell_t {
+ /** Type of the cell: CELL_VERSIONS, etc. */
uint8_t command;
+ /** Circuit thich received the cell */
circid_t circ_id;
+ /** Number of bytes actually stored in <b>payload</b> */
uint16_t payload_len;
+ /** Payload of this cell */
uint8_t payload[1];
} var_cell_t;
@@ -997,7 +1006,7 @@ typedef struct connection_t {
/** Unique identifier for this connection on this Tor instance. */
uint64_t global_identifier;
- /* XXXX022 move this field, and all the listener-only fields (just
+ /* XXXX023 move this field, and all the listener-only fields (just
socket_family, I think), into a new listener_connection_t subtype. */
/** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points
* to the evdns_server_port is uses to listen to and answer connections. */
@@ -1168,6 +1177,10 @@ typedef struct edge_connection_t {
* zero, abandon the associated mapaddress. */
unsigned int chosen_exit_retries:3;
+ /** True iff this is an AP connection that came from a transparent or
+ * NATd connection */
+ unsigned int is_transparent_ap:1;
+
/** If this is a DNSPort connection, this field holds the pending DNS
* request that we're going to try to answer. */
struct evdns_server_request *dns_server_request;
@@ -1670,8 +1683,13 @@ typedef struct networkstatus_v2_t {
* sorted by identity_digest. */
} networkstatus_v2_t;
+/** Linked list of microdesc hash lines for a single router in a directory
+ * vote.
+ */
typedef struct vote_microdesc_hash_t {
+ /** Next element in the list, or NULL. */
struct vote_microdesc_hash_t *next;
+ /** The raw contents of the microdesc hash line, excluding the "m". */
char *microdesc_hash_line;
} vote_microdesc_hash_t;
@@ -1683,6 +1701,7 @@ typedef struct vote_routerstatus_t {
* networkstatus_t.known_flags. */
char *version; /**< The version that the authority says this router is
* running. */
+ /** The hash or hashes that the authority claims this microdesc has. */
vote_microdesc_hash_t *microdesc;
} vote_routerstatus_t;
@@ -2107,10 +2126,15 @@ typedef struct circuit_t {
* length ONIONSKIN_CHALLENGE_LEN. */
char *n_conn_onionskin;
- time_t timestamp_created; /**< When was this circuit created? */
- time_t timestamp_dirty; /**< When the circuit was first used, or 0 if the
- * circuit is clean. */
- struct timeval highres_created; /**< When exactly was the circuit created? */
+ struct timeval timestamp_created; /**< When was the circuit created? */
+ /** When the circuit was first used, or 0 if the circuit is clean.
+ *
+ * XXXX023 Note that some code will artifically adjust this value backward
+ * in time in order to indicate that a circuit shouldn't be used for new
+ * streams, but that it can stay alive as long as it has streams on it.
+ * That's a kludge we should fix.
+ */
+ time_t timestamp_dirty;
uint16_t marked_for_close; /**< Should we close this circuit at the end of
* the main loop? (If true, holds the line number
@@ -2336,6 +2360,9 @@ typedef struct {
config_line_t *Logs; /**< New-style list of configuration lines
* for logs */
+ int LogMessageDomains; /**< Boolean: Should we log the domain(s) in which
+ * each log message occurs? */
+
char *DebugLogFile; /**< Where to send verbose log messages. */
char *DataDirectory; /**< OR only: where to store long-term data. */
char *Nickname; /**< OR only: nickname of this onion router. */
@@ -2747,6 +2774,10 @@ typedef struct {
* Helps avoid some cross-site attacks. */
int ClientDNSRejectInternalAddresses;
+ /** If true, do not accept any requests to connect to internal addresses
+ * over randomly chosen exits. */
+ int ClientRejectInternalAddresses;
+
/** The length of time that we think a consensus should be fresh. */
int V3AuthVotingInterval;
/** The length of time we think it will take to distribute votes. */
@@ -2825,6 +2856,11 @@ typedef struct {
*/
double CircuitPriorityHalflife;
+ /** Set to true if the TestingTorNetwork configuration option is set.
+ * This is used so that options_validate() has a chance to realize that
+ * the defaults have changed. */
+ int _UsingTestNetworkDefaults;
+
} or_options_t;
/** Persistent state for an onion router, as saved to disk. */
@@ -2856,19 +2892,25 @@ typedef struct {
* bandwidth usage. The "Interval" fields hold the granularity, in seconds,
* of the entries of Values. The "Values" lists hold decimal string
* representations of the number of bytes read or written in each
- * interval. */
+ * interval. The "Maxima" list holds decimal strings describing the highest
+ * rate achieved during the interval.
+ */
time_t BWHistoryReadEnds;
int BWHistoryReadInterval;
smartlist_t *BWHistoryReadValues;
+ smartlist_t *BWHistoryReadMaxima;
time_t BWHistoryWriteEnds;
int BWHistoryWriteInterval;
smartlist_t *BWHistoryWriteValues;
+ smartlist_t *BWHistoryWriteMaxima;
time_t BWHistoryDirReadEnds;
int BWHistoryDirReadInterval;
smartlist_t *BWHistoryDirReadValues;
+ smartlist_t *BWHistoryDirReadMaxima;
time_t BWHistoryDirWriteEnds;
int BWHistoryDirWriteInterval;
smartlist_t *BWHistoryDirWriteValues;
+ smartlist_t *BWHistoryDirWriteMaxima;
/** Build time histogram */
config_line_t * BuildtimeHistogram;
@@ -2942,6 +2984,11 @@ struct socks_request_t {
/* Circuit Build Timeout "public" structures. */
+/** Precision multiplier for the Bw weights */
+#define BW_WEIGHT_SCALE 10000
+#define BW_MIN_WEIGHT_SCALE 1
+#define BW_MAX_WEIGHT_SCALE INT32_MAX
+
/** Total size of the circuit timeout history to accumulate.
* 1000 is approx 2.5 days worth of continual-use circuits. */
#define CBT_NCIRCUITS_TO_OBSERVE 1000
@@ -2951,6 +2998,8 @@ struct socks_request_t {
/** Number of modes to use in the weighted-avg computation of Xm */
#define CBT_DEFAULT_NUM_XM_MODES 3
+#define CBT_MIN_NUM_XM_MODES 1
+#define CBT_MAX_NUM_XM_MODES 20
/** A build_time_t is milliseconds */
typedef uint32_t build_time_t;
@@ -2972,12 +3021,16 @@ typedef uint32_t build_time_t;
* build in terms of CDF quantile.
*/
#define CBT_DEFAULT_CLOSE_QUANTILE 95
+#define CBT_MIN_CLOSE_QUANTILE CBT_MIN_QUANTILE_CUTOFF
+#define CBT_MAX_CLOSE_QUANTILE CBT_MAX_QUANTILE_CUTOFF
/**
* How many circuits count as recent when considering if the
* connection has gone gimpy or changed.
*/
#define CBT_DEFAULT_RECENT_CIRCUITS 20
+#define CBT_MIN_RECENT_CIRCUITS 3
+#define CBT_MAX_RECENT_CIRCUITS 1000
/**
* Maximum count of timeouts that finish the first hop in the past
@@ -2988,25 +3041,37 @@ typedef uint32_t build_time_t;
* gives us.
*/
#define CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT (CBT_DEFAULT_RECENT_CIRCUITS*9/10)
+#define CBT_MIN_MAX_RECENT_TIMEOUT_COUNT 3
+#define CBT_MAX_MAX_RECENT_TIMEOUT_COUNT 10000
/** Minimum circuits before estimating a timeout */
#define CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE 100
+#define CBT_MIN_MIN_CIRCUITS_TO_OBSERVE 1
+#define CBT_MAX_MIN_CIRCUITS_TO_OBSERVE 10000
/** Cutoff percentile on the CDF for our timeout estimation. */
#define CBT_DEFAULT_QUANTILE_CUTOFF 80
+#define CBT_MIN_QUANTILE_CUTOFF 10
+#define CBT_MAX_QUANTILE_CUTOFF 99
double circuit_build_times_quantile_cutoff(void);
/** How often in seconds should we build a test circuit */
#define CBT_DEFAULT_TEST_FREQUENCY 60
+#define CBT_MIN_TEST_FREQUENCY 1
+#define CBT_MAX_TEST_FREQUENCY INT32_MAX
/** Lowest allowable value for CircuitBuildTimeout in milliseconds */
#define CBT_DEFAULT_TIMEOUT_MIN_VALUE (1500)
+#define CBT_MIN_TIMEOUT_MIN_VALUE 500
+#define CBT_MAX_TIMEOUT_MIN_VALUE INT32_MAX
/** Initial circuit build timeout in milliseconds */
#define CBT_DEFAULT_TIMEOUT_INITIAL_VALUE (60*1000)
+#define CBT_MIN_TIMEOUT_INITIAL_VALUE CBT_MIN_TIMEOUT_MIN_VALUE
+#define CBT_MAX_TIMEOUT_INITIAL_VALUE INT32_MAX
int32_t circuit_build_times_initial_timeout(void);
-#if CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT < 1
+#if CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT < CBT_MIN_MAX_RECENT_TIMEOUT_COUNT
#error "RECENT_CIRCUITS is set too low."
#endif
@@ -3168,8 +3233,19 @@ typedef struct {
} fp_pair_t;
/********************************* dirserv.c ***************************/
+
+/** An enum to describe what format we're generating a routerstatus line in.
+ */
typedef enum {
- NS_V2, NS_V3_CONSENSUS, NS_V3_VOTE, NS_CONTROL_PORT,
+ /** For use in a v2 opinion */
+ NS_V2,
+ /** For use in a consensus networkstatus document (ns flavor) */
+ NS_V3_CONSENSUS,
+ /** For use in a vote networkstatus document */
+ NS_V3_VOTE,
+ /** For passing to the controlport in response to a GETINFO request */
+ NS_CONTROL_PORT,
+ /** For use in a consensus networkstatus document (microdesc flavor) */
NS_V3_CONSENSUS_MICRODESC
} routerstatus_format_type_t;
@@ -3186,9 +3262,14 @@ typedef struct measured_bw_line_t {
/** Describes the schedule by which votes should be generated. */
typedef struct vote_timing_t {
+ /** Length in seconds between one consensus becoming valid and the next
+ * becoming valid. */
int vote_interval;
+ /** For how many intervals is a consensus valid? */
int n_intervals_valid;
+ /** Time in seconds allowed to propagate votes */
int vote_delay;
+ /** Time in seconds allowed to propagate signatures */
int dist_delay;
} vote_timing_t;
@@ -3463,6 +3544,7 @@ typedef enum was_router_added_t {
ROUTER_NOT_IN_CONSENSUS = -3,
ROUTER_NOT_IN_CONSENSUS_OR_NETWORKSTATUS = -4,
ROUTER_AUTHDIR_REJECTS = -5,
+ ROUTER_WAS_NOT_WANTED = -6
} was_router_added_t;
/********************************* routerparse.c ************************/
diff --git a/src/or/policies.c b/src/or/policies.c
index 6947222b2e..e48f42058f 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -858,6 +858,14 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
return 0;
}
+/** Add "reject *:*" to the end of the policy in *<b>dest</b>, allocating
+ * *<b>dest</b> as needed. */
+void
+policies_exit_policy_append_reject_star(smartlist_t **dest)
+{
+ append_exit_policy_string(dest, "reject *:*");
+}
+
/** Replace the exit policy of <b>r</b> with reject *:*. */
void
policies_set_router_exitpolicy_to_reject_all(routerinfo_t *r)
@@ -880,6 +888,8 @@ exit_policy_is_general_exit_helper(smartlist_t *policy, int port)
memset(subnet_status, 0, sizeof(subnet_status));
SMARTLIST_FOREACH(policy, addr_policy_t *, p, {
+ if (tor_addr_family(&p->addr) != AF_INET)
+ continue; /* IPv4 only for now */
if (p->prt_min > port || p->prt_max < port)
continue; /* Doesn't cover our port. */
mask = 0;
@@ -1243,8 +1253,8 @@ policy_summarize(smartlist_t *policy)
accepts_str = smartlist_join_strings(accepts, ",", 0, &accepts_len);
rejects_str = smartlist_join_strings(rejects, ",", 0, &rejects_len);
- if (rejects_len > MAX_EXITPOLICY_SUMMARY_LEN &&
- accepts_len > MAX_EXITPOLICY_SUMMARY_LEN) {
+ if (rejects_len > MAX_EXITPOLICY_SUMMARY_LEN-strlen("reject")-1 &&
+ accepts_len > MAX_EXITPOLICY_SUMMARY_LEN-strlen("accept")-1) {
char *c;
shorter_str = accepts_str;
prefix = "accept";
diff --git a/src/or/policies.h b/src/or/policies.h
index a954ac4f5f..b2947c67e7 100644
--- a/src/or/policies.h
+++ b/src/or/policies.h
@@ -41,6 +41,7 @@ addr_policy_result_t compare_addr_to_addr_policy(uint32_t addr,
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 policies_set_router_exitpolicy_to_reject_all(routerinfo_t *exitrouter);
int exit_policy_is_general_exit(smartlist_t *policy);
int policy_is_reject_star(const smartlist_t *policy);
diff --git a/src/or/reasons.c b/src/or/reasons.c
index 1401552223..319e6c055a 100644
--- a/src/or/reasons.c
+++ b/src/or/reasons.c
@@ -40,6 +40,8 @@ stream_end_reason_to_control_string(int reason)
case END_STREAM_REASON_NET_UNREACHABLE: return "NET_UNREACHABLE";
case END_STREAM_REASON_SOCKSPROTOCOL: return "SOCKS_PROTOCOL";
+ case END_STREAM_REASON_PRIVATE_ADDR: return "PRIVATE_ADDR";
+
default: return NULL;
}
}
@@ -125,6 +127,9 @@ stream_end_reason_to_socks5_response(int reason)
return SOCKS5_NET_UNREACHABLE;
case END_STREAM_REASON_SOCKSPROTOCOL:
return SOCKS5_GENERAL_ERROR;
+ case END_STREAM_REASON_PRIVATE_ADDR:
+ return SOCKS5_GENERAL_ERROR;
+
default:
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Reason for ending (%d) not recognized; "
@@ -169,13 +174,7 @@ errno_to_stream_end_reason(int e)
S_CASE(ENETUNREACH):
return END_STREAM_REASON_INTERNAL;
S_CASE(EHOSTUNREACH):
- /* XXXX022
- * The correct behavior is END_STREAM_REASON_NOROUTE, but older
- * clients don't recognize it. So we're going to continue sending
- * "MISC" until 0.2.1.27 or later is "well established".
- */
- /* return END_STREAM_REASON_NOROUTE; */
- return END_STREAM_REASON_MISC;
+ return END_STREAM_REASON_NOROUTE;
S_CASE(ECONNREFUSED):
return END_STREAM_REASON_CONNECTREFUSED;
S_CASE(ECONNRESET):
diff --git a/src/or/relay.c b/src/or/relay.c
index 32ac96edf4..807cb3d435 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -52,9 +52,9 @@ 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);
+/* XXXX023 move this all to compat_libevent */
/** Cache the current hi-res time; the cache gets reset when libevent
* calls us. */
-
static struct timeval cached_time_hires = {0, 0};
/** Stop reading on edge connections when we have this many cells
@@ -76,7 +76,7 @@ tor_gettimeofday_cached(struct timeval *tv)
void
tor_gettimeofday_cache_clear(void)
{
- cached_time_hires.tv_sec = 0;
+ cached_time_hires.tv_sec = 0;
}
/** Stats: how many relay cells have originated at this hop, or have
@@ -791,6 +791,8 @@ connection_ap_process_end_not_open(
< MAX_RESOLVE_FAILURES) {
/* 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". */
+ /* XXXX023 this is a kludgy way to do this. */
tor_assert(circ->_base.timestamp_dirty);
circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
@@ -1409,8 +1411,9 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
goto repeat_connection_edge_package_raw_inbuf;
}
-/** Called when we've just received a relay data cell, or when
- * we've just finished flushing all bytes to stream <b>conn</b>.
+/** Called when we've just received a relay data cell, when
+ * we've just finished flushing all bytes to stream <b>conn</b>,
+ * or when we've flushed *some* bytes to the stream <b>conn</b>.
*
* If conn->outbuf is not too full, and our deliver window is
* low, send back a suitable number of stream-level sendme cells.
@@ -1999,9 +2002,9 @@ cell_ewma_set_scale_factor(or_options_t *options, networkstatus_t *consensus)
if (options && options->CircuitPriorityHalflife >= -EPSILON) {
halflife = options->CircuitPriorityHalflife;
source = "CircuitPriorityHalflife in configuration";
- } else if (consensus &&
- (halflife_ms = networkstatus_get_param(
- consensus, "CircuitPriorityHalflifeMsec", -1)) >= 0) {
+ } else if (consensus && (halflife_ms = networkstatus_get_param(
+ consensus, "CircuitPriorityHalflifeMsec",
+ -1, -1, INT32_MAX)) >= 0) {
halflife = ((double)halflife_ms)/1000.0;
source = "CircuitPriorityHalflifeMsec in consensus";
} else {
diff --git a/src/or/relay.h b/src/or/relay.h
index dbba09239a..f64752da5d 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -64,5 +64,7 @@ void cell_ewma_set_scale_factor(or_options_t *options,
networkstatus_t *consensus);
void circuit_clear_cell_queue(circuit_t *circ, or_connection_t *orconn);
+void tor_gettimeofday_cache_clear(void);
+
#endif
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 7c626c6a64..8ac909fc80 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -121,7 +121,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
cpath = rendcirc->build_state->pending_final_cpath =
tor_malloc_zero(sizeof(crypt_path_t));
cpath->magic = CRYPT_PATH_MAGIC;
- if (!(cpath->dh_handshake_state = crypto_dh_new())) {
+ if (!(cpath->dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) {
log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
goto err;
}
@@ -184,6 +184,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
/*XXX maybe give crypto_pk_public_hybrid_encrypt a max_len arg,
* to avoid buffer overflows? */
r = crypto_pk_public_hybrid_encrypt(intro_key, payload+DIGEST_LEN,
+ sizeof(payload)-DIGEST_LEN,
tmp,
(int)(dh_offset+DH_KEY_LEN),
PK_PKCS1_OAEP_PADDING, 0);
@@ -402,7 +403,7 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query)
tor_assert(rend_query);
/* Determine responsible dirs. Even if we can't get all we want,
* work with the ones we have. If it's empty, we'll notice below. */
- (int) hid_serv_get_responsible_directories(responsible_dirs, desc_id);
+ hid_serv_get_responsible_directories(responsible_dirs, desc_id);
base32_encode(desc_id_base32, sizeof(desc_id_base32),
desc_id, DIGEST_LEN);
@@ -598,7 +599,7 @@ rend_client_rendezvous_acked(origin_circuit_t *circ, const uint8_t *request,
log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for "
"rendezvous.");
circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY;
- /* XXXX022 This is a pretty brute-force approach. It'd be better to
+ /* XXXX023 This is a pretty brute-force approach. It'd be better to
* attach only the connections that are waiting on this circuit, rather
* than trying to attach them all. See comments bug 743. */
/* If we already have the introduction circuit built, make sure we send
@@ -668,12 +669,14 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request,
onion_append_to_cpath(&circ->cpath, hop);
circ->build_state->pending_final_cpath = NULL; /* prevent double-free */
- /* XXXX022 This is a pretty brute-force approach. It'd be better to
+ /* XXXX023 This is a pretty brute-force approach. It'd be better to
* attach only the connections that are waiting on this circuit, rather
* than trying to attach them all. See comments bug 743. */
connection_ap_attach_pending();
+ memset(keys, 0, sizeof(keys));
return 0;
err:
+ memset(keys, 0, sizeof(keys));
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
return -1;
}
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 290e8f8389..f4c8888c04 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -932,7 +932,7 @@ rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e)
if (!*e)
return 0;
tor_assert((*e)->parsed && (*e)->parsed->intro_nodes);
- /* XXX022 hack for now, to return "not found" if there are no intro
+ /* XXX023 hack for now, to return "not found" if there are no intro
* points remaining. See bug 997. */
if (smartlist_len((*e)->parsed->intro_nodes) == 0)
return 0;
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 44b5a4b4c0..45039822f8 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -928,7 +928,8 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
/* Next N bytes is encrypted with service key */
note_crypto_pk_op(REND_SERVER);
r = crypto_pk_private_hybrid_decrypt(
- intro_key,buf,(char*)(request+DIGEST_LEN),request_len-DIGEST_LEN,
+ intro_key,buf,sizeof(buf),
+ (char*)(request+DIGEST_LEN),request_len-DIGEST_LEN,
PK_PKCS1_OAEP_PADDING,1);
if (r<0) {
log_warn(LD_PROTOCOL, "Couldn't decrypt INTRODUCE2 cell.");
@@ -1099,7 +1100,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
}
/* Try DH handshake... */
- dh = crypto_dh_new();
+ dh = crypto_dh_new(DH_TYPE_REND);
if (!dh || crypto_dh_generate_public(dh)<0) {
log_warn(LD_BUG,"Internal error: couldn't build DH state "
"or generate public key.");
@@ -1164,8 +1165,10 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
memcpy(cpath->handshake_digest, keys, DIGEST_LEN);
if (extend_info) extend_info_free(extend_info);
+ memset(keys, 0, sizeof(keys));
return 0;
err:
+ memset(keys, 0, sizeof(keys));
if (dh) crypto_dh_free(dh);
if (launched)
circuit_mark_for_close(TO_CIRCUIT(launched), reason);
@@ -1365,7 +1368,8 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
goto err;
len += 20;
note_crypto_pk_op(REND_SERVER);
- r = crypto_pk_private_sign_digest(intro_key, buf+len, buf, len);
+ r = crypto_pk_private_sign_digest(intro_key, buf+len, sizeof(buf)-len,
+ buf, len);
if (r<0) {
log_warn(LD_BUG, "Internal error: couldn't sign introduction request.");
reason = END_CIRC_REASON_INTERNAL;
diff --git a/src/or/rephist.c b/src/or/rephist.c
index d85a8b7c3a..5703e3edcd 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -14,6 +14,7 @@
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
+#include "networkstatus.h"
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
@@ -73,6 +74,13 @@ typedef struct or_history_t {
/** If nonzero, we have been unable to connect since this time. */
time_t down_since;
+ /** The address at which we most recently connected to this OR
+ * successfully. */
+ tor_addr_t last_reached_addr;
+
+ /** The port at which we most recently connected to this OR successfully */
+ uint16_t last_reached_port;
+
/* === For MTBF tracking: */
/** Weighted sum total of all times that this router has been online.
*/
@@ -119,6 +127,7 @@ get_or_history(const char* id)
rephist_total_num++;
hist->link_history_map = digestmap_new();
hist->since = hist->changed = time(NULL);
+ tor_addr_make_unspec(&hist->last_reached_addr);
digestmap_set(history_map, id, hist);
}
return hist;
@@ -289,13 +298,20 @@ rep_hist_note_connection_died(const char* id, time_t when)
/** We have just decided that this router with identity digest <b>id</b> is
* reachable, meaning we will give it a "Running" flag for the next while. */
void
-rep_hist_note_router_reachable(const char *id, time_t when)
+rep_hist_note_router_reachable(const char *id, const tor_addr_t *at_addr,
+ const uint16_t at_port, time_t when)
{
or_history_t *hist = get_or_history(id);
int was_in_run = 1;
char tbuf[ISO_TIME_LEN+1];
+ int addr_changed, port_changed;
tor_assert(hist);
+ tor_assert((!at_addr && !at_port) || (at_addr && at_port));
+
+ addr_changed = at_addr &&
+ tor_addr_compare(at_addr, &hist->last_reached_addr, CMP_EXACT) != 0;
+ port_changed = at_port && at_port != hist->last_reached_port;
if (!started_tracking_stability)
started_tracking_stability = time(NULL);
@@ -315,6 +331,27 @@ rep_hist_note_router_reachable(const char *id, time_t when)
down_length = when - hist->start_of_downtime;
hist->total_weighted_time += down_length;
hist->start_of_downtime = 0;
+ } else if (addr_changed || port_changed) {
+ /* If we're reachable, but the address changed, treat this as some
+ * downtime. */
+ int penalty = get_options()->TestingTorNetwork ? 240 : 3600;
+ networkstatus_t *ns;
+
+ if ((ns = networkstatus_get_latest_consensus())) {
+ int fresh_interval = (int)(ns->fresh_until - ns->valid_after);
+ int live_interval = (int)(ns->valid_until - ns->valid_after);
+ /* on average, a descriptor addr change takes .5 intervals to make it
+ * into a consensus, and half a liveness period to make it to
+ * clients. */
+ penalty = (int)(fresh_interval + live_interval) / 2;
+ }
+ format_local_iso_time(tbuf, hist->start_of_run);
+ log_info(LD_HIST,"Router %s still seems Running, but its address appears "
+ "to have changed since the last time it was reachable. I'm "
+ "going to treat it as having been down for %d seconds",
+ hex_str(id, DIGEST_LEN), penalty);
+ rep_hist_note_router_unreachable(id, when-penalty);
+ rep_hist_note_router_reachable(id, NULL, 0, when);
} else {
format_local_iso_time(tbuf, hist->start_of_run);
if (was_in_run)
@@ -324,6 +361,10 @@ rep_hist_note_router_reachable(const char *id, time_t when)
log_info(LD_HIST,"Router %s is now Running; it was previously untracked",
hex_str(id, DIGEST_LEN));
}
+ if (at_addr)
+ tor_addr_copy(&hist->last_reached_addr, at_addr);
+ if (at_port)
+ hist->last_reached_port = at_port;
}
/** We have just decided that this router is unreachable, meaning
@@ -344,12 +385,20 @@ rep_hist_note_router_unreachable(const char *id, time_t when)
long run_length = when - hist->start_of_run;
format_local_iso_time(tbuf, hist->start_of_run);
- hist->weighted_run_length += run_length;
hist->total_run_weights += 1.0;
hist->start_of_run = 0;
- hist->weighted_uptime += run_length;
- hist->total_weighted_time += run_length;
+ if (run_length < 0) {
+ unsigned long penalty = -run_length;
+#define SUBTRACT_CLAMPED(var, penalty) \
+ do { (var) = (var) < (penalty) ? 0 : (var) - (penalty); } while (0)
+ SUBTRACT_CLAMPED(hist->weighted_run_length, penalty);
+ SUBTRACT_CLAMPED(hist->weighted_uptime, penalty);
+ } else {
+ hist->weighted_run_length += run_length;
+ hist->weighted_uptime += run_length;
+ hist->total_weighted_time += run_length;
+ }
was_running = 1;
log_info(LD_HIST, "Router %s is now non-Running: it had previously been "
"Running since %s. Its total weighted uptime is %lu/%lu.",
@@ -422,7 +471,7 @@ rep_hist_downrate_old_runs(time_t now)
static double
get_stability(or_history_t *hist, time_t when)
{
- unsigned long total = hist->weighted_run_length;
+ long total = hist->weighted_run_length;
double total_weights = hist->total_run_weights;
if (hist->start_of_run) {
@@ -458,8 +507,8 @@ get_total_weighted_time(or_history_t *hist, time_t when)
static double
get_weighted_fractional_uptime(or_history_t *hist, time_t when)
{
- unsigned long total = hist->total_weighted_time;
- unsigned long up = hist->weighted_uptime;
+ long total = hist->total_weighted_time;
+ long up = hist->weighted_uptime;
if (hist->start_of_run) {
long run_length = (when - hist->start_of_run);
@@ -479,6 +528,20 @@ get_weighted_fractional_uptime(or_history_t *hist, time_t when)
return ((double) up) / total;
}
+/** Return how long the router whose identity digest is <b>id</b> has
+ * been reachable. Return 0 if the router is unknown or currently deemed
+ * unreachable. */
+long
+rep_hist_get_uptime(const char *id, time_t when)
+{
+ or_history_t *hist = get_or_history(id);
+ if (!hist)
+ return 0;
+ if (!hist->start_of_run || when < hist->start_of_run)
+ return 0;
+ return when - hist->start_of_run;
+}
+
/** Return an estimated MTBF for the router whose identity digest is
* <b>id</b>. Return 0 if the router is unknown. */
double
@@ -524,7 +587,7 @@ rep_hist_get_weighted_time_known(const char *id, time_t when)
int
rep_hist_have_measured_enough_stability(void)
{
- /* XXXX021 This doesn't do so well when we change our opinion
+ /* XXXX022 This doesn't do so well when we change our opinion
* as to whether we're tracking router stability. */
return started_tracking_stability < time(NULL) - 4*60*60;
}
@@ -929,10 +992,10 @@ find_next_with(smartlist_t *sl, int i, const char *prefix)
return -1;
}
-/** How many bad times has parse_possibly_bad_iso_time parsed? */
+/** How many bad times has parse_possibly_bad_iso_time() parsed? */
static int n_bogus_times = 0;
/** Parse the ISO-formatted time in <b>s</b> into *<b>time_out</b>, but
- * rounds any pre-1970 date to Jan 1, 1970. */
+ * round any pre-1970 date to Jan 1, 1970. */
static int
parse_possibly_bad_iso_time(const char *s, time_t *time_out)
{
@@ -1165,6 +1228,8 @@ rep_hist_load_mtbf_data(time_t now)
* totals? */
#define NUM_SECS_ROLLING_MEASURE 10
/** How large are the intervals for which we track and report bandwidth use? */
+/* XXXX Watch out! Before Tor 0.2.2.21-alpha, using any other value here would
+ * generate an unparseable state file. */
#define NUM_SECS_BW_SUM_INTERVAL (15*60)
/** How far in the past do we remember and publish bandwidth use? */
#define NUM_SECS_BW_SUM_IS_VALID (24*60*60)
@@ -1223,7 +1288,7 @@ commit_max(bw_array_t *b)
b->total_in_period = 0;
}
-/** Shift the current observation time of 'b' forward by one second. */
+/** Shift the current observation time of <b>b</b> forward by one second. */
static INLINE void
advance_obs(bw_array_t *b)
{
@@ -1253,14 +1318,18 @@ advance_obs(bw_array_t *b)
static INLINE void
add_obs(bw_array_t *b, time_t when, uint64_t n)
{
- /* Don't record data in the past. */
- if (when<b->cur_obs_time)
- return;
+ if (when < b->cur_obs_time)
+ return; /* Don't record data in the past. */
+
/* If we're currently adding observations for an earlier second than
* 'when', advance b->cur_obs_time and b->cur_obs_idx by an
- * appropriate number of seconds, and do all the other housekeeping */
- while (when>b->cur_obs_time)
+ * appropriate number of seconds, and do all the other housekeeping. */
+ while (when > b->cur_obs_time) {
+ /* Doing this one second at a time is potentially inefficient, if we start
+ with a state file that is very old. Fortunately, it doesn't seem to
+ show up in profiles, so we can just ignore it for now. */
advance_obs(b);
+ }
b->obs[b->cur_obs_idx] += n;
b->total_in_period += n;
@@ -1291,17 +1360,22 @@ static bw_array_t *dir_read_array = NULL;
directory protocol. */
static bw_array_t *dir_write_array = NULL;
-/** Set up [dir-]read_array and [dir-]write_array. */
+/** Set up [dir-]read_array and [dir-]write_array, freeing them if they
+ * already exist. */
static void
bw_arrays_init(void)
{
+ tor_free(read_array);
+ tor_free(write_array);
+ tor_free(dir_read_array);
+ tor_free(dir_write_array);
read_array = bw_array_new();
write_array = bw_array_new();
dir_read_array = bw_array_new();
dir_write_array = bw_array_new();
}
-/** We read <b>num_bytes</b> more bytes in second <b>when</b>.
+/** Remember that we read <b>num_bytes</b> bytes in second <b>when</b>.
*
* Add num_bytes to the current running total for <b>when</b>.
*
@@ -1322,7 +1396,7 @@ rep_hist_note_bytes_written(size_t num_bytes, time_t when)
add_obs(write_array, when, num_bytes);
}
-/** We wrote <b>num_bytes</b> more bytes in second <b>when</b>.
+/** Remember that we wrote <b>num_bytes</b> bytes in second <b>when</b>.
* (like rep_hist_note_bytes_written() above)
*/
void
@@ -1332,8 +1406,8 @@ rep_hist_note_bytes_read(size_t num_bytes, time_t when)
add_obs(read_array, when, num_bytes);
}
-/** We wrote <b>num_bytes</b> more directory bytes in second <b>when</b>.
- * (like rep_hist_note_bytes_written() above)
+/** Remember that we wrote <b>num_bytes</b> directory bytes in second
+ * <b>when</b>. (like rep_hist_note_bytes_written() above)
*/
void
rep_hist_note_dir_bytes_written(size_t num_bytes, time_t when)
@@ -1341,8 +1415,8 @@ rep_hist_note_dir_bytes_written(size_t num_bytes, time_t when)
add_obs(dir_write_array, when, num_bytes);
}
-/** We read <b>num_bytes</b> more directory bytes in second <b>when</b>.
- * (like rep_hist_note_bytes_written() above)
+/** Remember that we read <b>num_bytes</b> directory bytes in second
+ * <b>when</b>. (like rep_hist_note_bytes_written() above)
*/
void
rep_hist_note_dir_bytes_read(size_t num_bytes, time_t when)
@@ -1392,7 +1466,7 @@ rep_hist_bandwidth_assess(void)
* It returns the number of bytes written.
*/
static size_t
-rep_hist_fill_bandwidth_history(char *buf, size_t len, bw_array_t *b)
+rep_hist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b)
{
char *cp = buf;
int i, n;
@@ -1437,7 +1511,8 @@ rep_hist_fill_bandwidth_history(char *buf, size_t len, bw_array_t *b)
}
/** Allocate and return lines for representing this server's bandwidth
- * history in its descriptor.
+ * history in its descriptor. We publish these lines in our extra-info
+ * descriptor.
*/
char *
rep_hist_get_bandwidth_lines(void)
@@ -1484,163 +1559,196 @@ rep_hist_get_bandwidth_lines(void)
return buf;
}
-/** Update <b>state</b> with the newest bandwidth history. */
+/** Write a single bw_array_t into the Values, Ends, Interval, and Maximum
+ * entries of an or_state_t. Done before writing out a new state file. */
+static void
+rep_hist_update_bwhist_state_section(or_state_t *state,
+ const bw_array_t *b,
+ smartlist_t **s_values,
+ smartlist_t **s_maxima,
+ time_t *s_begins,
+ int *s_interval)
+{
+ char *cp;
+ int i,j;
+ uint64_t maxval;
+
+ if (*s_values) {
+ SMARTLIST_FOREACH(*s_values, char *, val, tor_free(val));
+ smartlist_free(*s_values);
+ }
+ if (*s_maxima) {
+ SMARTLIST_FOREACH(*s_maxima, char *, val, tor_free(val));
+ smartlist_free(*s_maxima);
+ }
+ if (! server_mode(get_options())) {
+ /* Clients don't need to store bandwidth history persistently;
+ * force these values to the defaults. */
+ /* FFFF we should pull the default out of config.c's state table,
+ * so we don't have two defaults. */
+ if (*s_begins != 0 || *s_interval != 900) {
+ time_t now = time(NULL);
+ time_t save_at = get_options()->AvoidDiskWrites ? now+3600 : now+600;
+ or_state_mark_dirty(state, save_at);
+ }
+ *s_begins = 0;
+ *s_interval = 900;
+ *s_values = smartlist_create();
+ *s_maxima = smartlist_create();
+ return;
+ }
+ *s_begins = b->next_period;
+ *s_interval = NUM_SECS_BW_SUM_INTERVAL;
+
+ *s_values = smartlist_create();
+ *s_maxima = smartlist_create();
+ /* Set i to first position in circular array */
+ i = (b->num_maxes_set <= b->next_max_idx) ? 0 : b->next_max_idx;
+ for (j=0; j < b->num_maxes_set; ++j,++i) {
+ if (i >= NUM_TOTALS)
+ i = 0;
+ tor_asprintf(&cp, U64_FORMAT, U64_PRINTF_ARG(b->totals[i] & ~0x3ff));
+ smartlist_add(*s_values, cp);
+ maxval = b->maxima[i] / NUM_SECS_ROLLING_MEASURE;
+ tor_asprintf(&cp, U64_FORMAT, U64_PRINTF_ARG(maxval & ~0x3ff));
+ smartlist_add(*s_maxima, cp);
+ }
+ tor_asprintf(&cp, U64_FORMAT, U64_PRINTF_ARG(b->total_in_period & ~0x3ff));
+ smartlist_add(*s_values, cp);
+ maxval = b->max_total / NUM_SECS_ROLLING_MEASURE;
+ tor_asprintf(&cp, U64_FORMAT, U64_PRINTF_ARG(maxval & ~0x3ff));
+ smartlist_add(*s_maxima, cp);
+}
+
+/** Update <b>state</b> with the newest bandwidth history. Done before
+ * writing out a new state file. */
void
rep_hist_update_state(or_state_t *state)
{
- int len, r;
- char *buf, *cp;
- smartlist_t **s_values = NULL;
- time_t *s_begins = NULL;
- int *s_interval = NULL;
- bw_array_t *b = NULL;
+#define UPDATE(arrname,st) \
+ rep_hist_update_bwhist_state_section(state,\
+ (arrname),\
+ &state->BWHistory ## st ## Values, \
+ &state->BWHistory ## st ## Maxima, \
+ &state->BWHistory ## st ## Ends, \
+ &state->BWHistory ## st ## Interval)
- len = 20*NUM_TOTALS+1;
- buf = tor_malloc_zero(len);
+ UPDATE(write_array, Write);
+ UPDATE(read_array, Read);
+ UPDATE(dir_write_array, DirWrite);
+ UPDATE(dir_read_array, DirRead);
- for (r=0;r<4;++r) {
- switch (r) {
- case 0:
- b = write_array;
- s_begins = &state->BWHistoryWriteEnds;
- s_interval = &state->BWHistoryWriteInterval;
- s_values = &state->BWHistoryWriteValues;
- break;
- case 1:
- b = read_array;
- s_begins = &state->BWHistoryReadEnds;
- s_interval = &state->BWHistoryReadInterval;
- s_values = &state->BWHistoryReadValues;
- break;
- case 2:
- b = dir_write_array;
- s_begins = &state->BWHistoryDirWriteEnds;
- s_interval = &state->BWHistoryDirWriteInterval;
- s_values = &state->BWHistoryDirWriteValues;
- break;
- case 3:
- b = dir_read_array;
- s_begins = &state->BWHistoryDirReadEnds;
- s_interval = &state->BWHistoryDirReadInterval;
- s_values = &state->BWHistoryDirReadValues;
- break;
- }
- if (*s_values) {
- SMARTLIST_FOREACH(*s_values, char *, val, tor_free(val));
- smartlist_free(*s_values);
- }
- if (! server_mode(get_options())) {
- /* Clients don't need to store bandwidth history persistently;
- * force these values to the defaults. */
- /* FFFF we should pull the default out of config.c's state table,
- * so we don't have two defaults. */
- if (*s_begins != 0 || *s_interval != 900) {
- time_t now = time(NULL);
- time_t save_at = get_options()->AvoidDiskWrites ? now+3600 : now+600;
- or_state_mark_dirty(state, save_at);
- }
- *s_begins = 0;
- *s_interval = 900;
- *s_values = smartlist_create();
- continue;
- }
- *s_begins = b->next_period;
- *s_interval = NUM_SECS_BW_SUM_INTERVAL;
- cp = buf;
- cp += rep_hist_fill_bandwidth_history(cp, len, b);
- tor_snprintf(cp, len-(cp-buf), cp == buf ? U64_FORMAT : ","U64_FORMAT,
- U64_PRINTF_ARG(b->total_in_period));
- *s_values = smartlist_create();
- if (server_mode(get_options()))
- smartlist_split_string(*s_values, buf, ",", SPLIT_SKIP_SPACE, 0);
- }
- tor_free(buf);
if (server_mode(get_options())) {
- or_state_mark_dirty(get_or_state(), time(NULL)+(2*3600));
+ or_state_mark_dirty(state, time(NULL)+(2*3600));
}
+#undef UPDATE
}
-/** Set bandwidth history from our saved state. */
-int
-rep_hist_load_state(or_state_t *state, char **err)
+/** Load a single bw_array_t from its Values, Ends, Maxima, and Interval
+ * entries in an or_state_t. Done while reading the state file. */
+static int
+rep_hist_load_bwhist_state_section(bw_array_t *b,
+ const smartlist_t *s_values,
+ const smartlist_t *s_maxima,
+ const time_t s_begins,
+ const int s_interval)
{
- time_t s_begins = 0, start;
time_t now = time(NULL);
- uint64_t v;
- int r,i,ok;
- int all_ok = 1;
- int s_interval = 0;
- smartlist_t *s_values = NULL;
- bw_array_t *b = NULL;
-
- /* Assert they already have been malloced */
- tor_assert(read_array && write_array);
+ int retval = 0;
+ time_t start;
- for (r=0;r<4;++r) {
- switch (r) {
- case 0:
- b = write_array;
- s_begins = state->BWHistoryWriteEnds;
- s_interval = state->BWHistoryWriteInterval;
- s_values = state->BWHistoryWriteValues;
- break;
- case 1:
- b = read_array;
- s_begins = state->BWHistoryReadEnds;
- s_interval = state->BWHistoryReadInterval;
- s_values = state->BWHistoryReadValues;
- break;
- case 2:
- b = dir_write_array;
- s_begins = state->BWHistoryDirWriteEnds;
- s_interval = state->BWHistoryDirWriteInterval;
- s_values = state->BWHistoryDirWriteValues;
- break;
- case 3:
- b = dir_read_array;
- s_begins = state->BWHistoryDirReadEnds;
- s_interval = state->BWHistoryDirReadInterval;
- s_values = state->BWHistoryDirReadValues;
- break;
- }
- if (s_values && s_begins >= now - NUM_SECS_BW_SUM_INTERVAL*NUM_TOTALS) {
- start = s_begins - s_interval*(smartlist_len(s_values));
- if (start > now)
- continue;
- b->cur_obs_time = start;
- b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
- SMARTLIST_FOREACH(s_values, char *, cp, {
+ uint64_t v, mv;
+ int i,ok,ok_m;
+ int have_maxima = (smartlist_len(s_values) == smartlist_len(s_maxima));
+
+ if (s_values && s_begins >= now - NUM_SECS_BW_SUM_INTERVAL*NUM_TOTALS) {
+ start = s_begins - s_interval*(smartlist_len(s_values));
+ if (start > now)
+ return 0;
+ b->cur_obs_time = start;
+ b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
+ SMARTLIST_FOREACH_BEGIN(s_values, const char *, cp) {
+ const char *maxstr = NULL;
v = tor_parse_uint64(cp, 10, 0, UINT64_MAX, &ok, NULL);
+ if (have_maxima) {
+ maxstr = smartlist_get(s_maxima, cp_sl_idx);
+ mv = tor_parse_uint64(maxstr, 10, 0, UINT64_MAX, &ok_m, NULL);
+ mv *= NUM_SECS_ROLLING_MEASURE;
+ } else {
+ /* No maxima known; guess average rate to be conservative. */
+ mv = (v / s_interval) * NUM_SECS_ROLLING_MEASURE;
+ }
if (!ok) {
- all_ok=0;
- log_notice(LD_HIST, "Could not parse '%s' into a number.'", cp);
+ retval = -1;
+ log_notice(LD_HIST, "Could not parse value '%s' into a number.'",cp);
}
+ if (maxstr && !ok_m) {
+ retval = -1;
+ log_notice(LD_HIST, "Could not parse maximum '%s' into a number.'",
+ maxstr);
+ }
+
if (start < now) {
- add_obs(b, start, v);
- start += NUM_SECS_BW_SUM_INTERVAL;
+ time_t cur_start = start;
+ time_t actual_interval_len = s_interval;
+ uint64_t cur_val = 0;
+ /* Calculate the average per second. This is the best we can do
+ * because our state file doesn't have per-second resolution. */
+ if (start + s_interval > now)
+ actual_interval_len = now - start;
+ cur_val = v / actual_interval_len;
+ /* This is potentially inefficient, but since we don't do it very
+ * often it should be ok. */
+ while (cur_start < start + actual_interval_len) {
+ add_obs(b, cur_start, cur_val);
+ ++cur_start;
+ }
+ b->max_total = mv;
+ /* This will result in some fairly choppy history if s_interval
+ * is not the same as NUM_SECS_BW_SUM_INTERVAL. XXXX */
+ start += actual_interval_len;
}
- });
- }
+ } SMARTLIST_FOREACH_END(cp);
+ }
- /* Clean up maxima and observed */
- /* Do we really want to zero this for the purpose of max capacity? */
- for (i=0; i<NUM_SECS_ROLLING_MEASURE; ++i) {
- b->obs[i] = 0;
- }
- b->total_obs = 0;
- for (i=0; i<NUM_TOTALS; ++i) {
- b->maxima[i] = 0;
- }
- b->max_total = 0;
+ /* Clean up maxima and observed */
+ for (i=0; i<NUM_SECS_ROLLING_MEASURE; ++i) {
+ b->obs[i] = 0;
}
+ b->total_obs = 0;
+ return retval;
+}
+
+/** Set bandwidth history from the state file we just loaded. */
+int
+rep_hist_load_state(or_state_t *state, char **err)
+{
+ int all_ok = 1;
+
+ /* Assert they already have been malloced */
+ tor_assert(read_array && write_array);
+ tor_assert(dir_read_array && dir_write_array);
+
+#define LOAD(arrname,st) \
+ if (rep_hist_load_bwhist_state_section( \
+ (arrname), \
+ state->BWHistory ## st ## Values, \
+ state->BWHistory ## st ## Maxima, \
+ state->BWHistory ## st ## Ends, \
+ state->BWHistory ## st ## Interval)<0) \
+ all_ok = 0
+
+ LOAD(write_array, Write);
+ LOAD(read_array, Read);
+ LOAD(dir_write_array, DirWrite);
+ LOAD(dir_read_array, DirRead);
+
+#undef LOAD
if (!all_ok) {
*err = tor_strdup("Parsing of bandwidth history values failed");
/* and create fresh arrays */
- tor_free(read_array);
- tor_free(write_array);
- read_array = bw_array_new();
- write_array = bw_array_new();
+ bw_arrays_init();
return -1;
}
return 0;
@@ -1660,7 +1768,7 @@ static smartlist_t *predicted_ports_times=NULL;
static void
add_predicted_port(time_t now, uint16_t port)
{
- /* XXXX we could just use uintptr_t here, I think. */
+ /* XXXX we could just use uintptr_t here, I think. -NM */
uint16_t *tmp_port = tor_malloc(sizeof(uint16_t));
time_t *tmp_time = tor_malloc(sizeof(time_t));
*tmp_port = port;
@@ -2238,15 +2346,19 @@ rep_hist_buffer_stats_init(time_t now)
start_of_buffer_stats_interval = now;
}
+/** Statistics from a single circuit. Collected when the circuit closes, or
+ * when we flush statistics to disk. */
typedef struct circ_buffer_stats_t {
- uint32_t processed_cells;
+ /** Average number of cells in the circuit's queue */
double mean_num_cells_in_queue;
+ /** Average time a cell waits in the queue. */
double mean_time_cells_in_queue;
- uint32_t local_circ_id;
+ /** Total number of cells sent over this circuit */
+ uint32_t processed_cells;
} circ_buffer_stats_t;
-/** Holds stats. */
-smartlist_t *circuits_for_buffer_stats = NULL;
+/** List of circ_buffer_stats_t. */
+static smartlist_t *circuits_for_buffer_stats = NULL;
/** Remember cell statistics for circuit <b>circ</b> at time
* <b>end_of_interval</b> and reset cell counters in case the circuit
@@ -2265,11 +2377,13 @@ rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval)
return;
if (!circuits_for_buffer_stats)
circuits_for_buffer_stats = smartlist_create();
- start_of_interval = circ->timestamp_created >
+ start_of_interval = circ->timestamp_created.tv_sec >
start_of_buffer_stats_interval ?
- circ->timestamp_created :
+ circ->timestamp_created.tv_sec :
start_of_buffer_stats_interval;
interval_length = (int) (end_of_interval - start_of_interval);
+ if (interval_length <= 0)
+ return;
stat = tor_malloc_zero(sizeof(circ_buffer_stats_t));
stat->processed_cells = orcirc->processed_cells;
/* 1000.0 for s -> ms; 2.0 because of app-ward and exit-ward queues */
@@ -2447,5 +2561,11 @@ rep_hist_free_all(void)
tor_free(exit_streams);
built_last_stability_doc_at = 0;
predicted_ports_free();
+ if (circuits_for_buffer_stats) {
+ SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *, s,
+ tor_free(s));
+ smartlist_free(circuits_for_buffer_stats);
+ circuits_for_buffer_stats = NULL;
+ }
}
diff --git a/src/or/rephist.h b/src/or/rephist.h
index 9a39070817..b06a39ed59 100644
--- a/src/or/rephist.h
+++ b/src/or/rephist.h
@@ -33,12 +33,14 @@ void rep_hist_update_state(or_state_t *state);
int rep_hist_load_state(or_state_t *state, char **err);
void rep_history_clean(time_t before);
-void rep_hist_note_router_reachable(const char *id, time_t when);
+void rep_hist_note_router_reachable(const char *id, const tor_addr_t *at_addr,
+ uint16_t at_port, time_t when);
void rep_hist_note_router_unreachable(const char *id, time_t when);
int rep_hist_record_mtbf_data(time_t now, int missing_means_down);
int rep_hist_load_mtbf_data(time_t now);
time_t rep_hist_downrate_old_runs(time_t now);
+long rep_hist_get_uptime(const char *id, time_t when);
double rep_hist_get_stability(const char *id, time_t when);
double rep_hist_get_weighted_fractional_uptime(const char *id, time_t when);
long rep_hist_get_weighted_time_known(const char *id, time_t when);
diff --git a/src/or/router.c b/src/or/router.c
index 3bb37de8cf..c15b9b236e 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -629,7 +629,7 @@ init_keys(void)
/* 4. Build our router descriptor. */
/* Must be called after keys are initialized. */
mydesc = router_get_my_descriptor();
- if (authdir_mode(options)) {
+ if (authdir_mode_handles_descs(options, ROUTER_PURPOSE_GENERAL)) {
const char *m = NULL;
routerinfo_t *ri;
/* We need to add our own fingerprint so it gets recognized. */
@@ -881,19 +881,14 @@ consider_testing_reachability(int test_or, int test_dir)
void
router_orport_found_reachable(void)
{
- if (!can_reach_or_port) {
- routerinfo_t *me = router_get_my_routerinfo();
+ routerinfo_t *me = router_get_my_routerinfo();
+ if (!can_reach_or_port && me) {
log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
"the outside. Excellent.%s",
get_options()->_PublishServerDescriptor != NO_AUTHORITY ?
" Publishing server descriptor." : "");
can_reach_or_port = 1;
mark_my_descriptor_dirty();
- if (!me) { /* should never happen */
- log_warn(LD_BUG, "ORPort found reachable, but I have no routerinfo "
- "yet. Failing to inform controller of success.");
- return;
- }
control_event_server_status(LOG_NOTICE,
"REACHABILITY_SUCCEEDED ORADDRESS=%s:%d",
me->address, me->or_port);
@@ -904,18 +899,13 @@ router_orport_found_reachable(void)
void
router_dirport_found_reachable(void)
{
- if (!can_reach_dir_port) {
- routerinfo_t *me = router_get_my_routerinfo();
+ routerinfo_t *me = router_get_my_routerinfo();
+ if (!can_reach_dir_port && me) {
log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
"from the outside. Excellent.");
can_reach_dir_port = 1;
- if (!me || decide_to_advertise_dirport(get_options(), me->dir_port))
+ if (decide_to_advertise_dirport(get_options(), me->dir_port))
mark_my_descriptor_dirty();
- if (!me) { /* should never happen */
- log_warn(LD_BUG, "DirPort found reachable, but I have no routerinfo "
- "yet. Failing to inform controller of success.");
- return;
- }
control_event_server_status(LOG_NOTICE,
"REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d",
me->address, me->dir_port);
@@ -1068,7 +1058,7 @@ should_refuse_unknown_exits(or_options_t *options)
if (options->RefuseUnknownExits_ != -1) {
return options->RefuseUnknownExits_;
} else {
- return networkstatus_get_param(NULL, "refuseunknownexits", 1);
+ return networkstatus_get_param(NULL, "refuseunknownexits", 1, 0, 1);
}
}
@@ -1410,9 +1400,14 @@ router_rebuild_descriptor(int force)
ri->bandwidthcapacity = hibernating ? 0 : rep_hist_bandwidth_assess();
- policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy,
- options->ExitPolicyRejectPrivate,
- ri->address, !options->BridgeRelay);
+ if (dns_seems_to_be_broken() || has_dns_init_failed()) {
+ /* DNS is screwed up; don't claim to be an exit. */
+ policies_exit_policy_append_reject_star(&ri->exit_policy);
+ } else {
+ policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy,
+ options->ExitPolicyRejectPrivate,
+ ri->address, !options->BridgeRelay);
+ }
ri->policy_is_reject_star =
policy_is_reject_star(ri->exit_policy);
@@ -1866,9 +1861,7 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
}
/* Write the exit policy to the end of 's'. */
- if (dns_seems_to_be_broken() || has_dns_init_failed() ||
- !router->exit_policy || !smartlist_len(router->exit_policy)) {
- /* DNS is screwed up; don't claim to be an exit. */
+ if (!router->exit_policy || !smartlist_len(router->exit_policy)) {
strlcat(s+written, "reject *:*\n", maxlen-written);
written += strlen("reject *:*\n");
tmpe = NULL;
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 253b787217..c02654feef 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -328,7 +328,7 @@ trusted_dirs_remove_old_certs(void)
time_t cert_published;
if (newest == cert)
continue;
- expired = ftime_definitely_after(now, cert->expires);
+ expired = now > cert->expires;
cert_published = cert->cache_info.published_on;
/* Store expired certs for 48 hours after a newer arrives;
*/
@@ -520,7 +520,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
continue;
cl = get_cert_list(ds->v3_identity_digest);
SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert, {
- if (!ftime_definitely_after(now, cert->expires)) {
+ if (now < cert->expires) {
/* It's not expired, and we weren't looking for something to
* verify a consensus with. Call it done. */
download_status_reset(&cl->dl_status);
@@ -531,8 +531,8 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
if (!found &&
download_status_is_ready(&cl->dl_status, now,MAX_CERT_DL_FAILURES) &&
!digestmap_get(pending, ds->v3_identity_digest)) {
- log_notice(LD_DIR, "No current certificate known for authority %s; "
- "launching request.", ds->nickname);
+ log_info(LD_DIR, "No current certificate known for authority %s; "
+ "launching request.", ds->nickname);
smartlist_add(missing_digests, ds->v3_identity_digest);
}
} SMARTLIST_FOREACH_END(ds);
@@ -1650,8 +1650,7 @@ smartlist_choose_by_bandwidth_weights(smartlist_t *sl,
return NULL;
}
- weight_scale = networkstatus_get_param(NULL, "bwweightscale",
- BW_WEIGHT_SCALE);
+ weight_scale = circuit_build_times_get_bw_scale(NULL);
if (rule == WEIGHT_FOR_GUARD) {
Wg = networkstatus_get_bw_weight(NULL, "Wgg", -1);
@@ -1723,7 +1722,7 @@ smartlist_choose_by_bandwidth_weights(smartlist_t *sl,
double weight = 1;
if (statuses) {
routerstatus_t *status = smartlist_get(sl, i);
- is_exit = status->is_exit;
+ is_exit = status->is_exit && !status->is_bad_exit;
is_guard = status->is_possible_guard;
is_dir = (status->dir_port != 0);
if (!status->has_bandwidth) {
@@ -1743,7 +1742,7 @@ smartlist_choose_by_bandwidth_weights(smartlist_t *sl,
routerinfo_t *router = smartlist_get(sl, i);
rs = router_get_consensus_status_by_id(
router->cache_info.identity_digest);
- is_exit = router->is_exit;
+ is_exit = router->is_exit && !router->is_bad_exit;
is_guard = router->is_possible_guard;
is_dir = (router->dir_port != 0);
if (rs && rs->has_bandwidth) {
@@ -1771,7 +1770,7 @@ smartlist_choose_by_bandwidth_weights(smartlist_t *sl,
sl_last_weighted_bw_of_me = weight*this_bw;
}
- /* XXXX022 this is a kludge to expose these values. */
+ /* XXXX023 this is a kludge to expose these values. */
sl_last_total_weighted_bw = weighted_bw;
log_debug(LD_CIRC, "Choosing node for rule %s based on weights "
@@ -1894,7 +1893,7 @@ smartlist_choose_by_bandwidth(smartlist_t *sl, bandwidth_weight_rule_t rule,
if (status->has_bandwidth) {
this_bw = kb_to_bytes(status->bandwidth);
} else { /* guess */
- /* XXX022 once consensuses always list bandwidths, we can take
+ /* XXX023 once consensuses always list bandwidths, we can take
* this guessing business out. -RD */
is_known = 0;
flags = status->is_fast ? 1 : 0;
@@ -1913,7 +1912,7 @@ smartlist_choose_by_bandwidth(smartlist_t *sl, bandwidth_weight_rule_t rule,
if (rs && rs->has_bandwidth) {
this_bw = kb_to_bytes(rs->bandwidth);
} else if (rs) { /* guess; don't trust the descriptor */
- /* XXX022 once consensuses always list bandwidths, we can take
+ /* XXX023 once consensuses always list bandwidths, we can take
* this guessing business out. -RD */
is_known = 0;
flags = router->is_fast ? 1 : 0;
@@ -2029,7 +2028,7 @@ smartlist_choose_by_bandwidth(smartlist_t *sl, bandwidth_weight_rule_t rule,
}
}
- /* XXXX022 this is a kludge to expose these values. */
+ /* XXXX023 this is a kludge to expose these values. */
sl_last_total_weighted_bw = total_bw;
log_debug(LD_CIRC, "Total weighted bw = "U64_FORMAT
@@ -3210,7 +3209,8 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
int from_cache, int from_fetch)
{
const char *id_digest;
- int authdir = authdir_mode_handles_descs(get_options(), router->purpose);
+ or_options_t *options = get_options();
+ int authdir = authdir_mode_handles_descs(options, router->purpose);
int authdir_believes_valid = 0;
routerinfo_t *old_router;
networkstatus_t *consensus = networkstatus_get_latest_consensus();
@@ -3315,6 +3315,20 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
return ROUTER_NOT_IN_CONSENSUS;
}
+ /* If we're reading a bridge descriptor from our cache, and we don't
+ * recognize it as one of our currently configured bridges, drop the
+ * descriptor. Otherwise we could end up using it as one of our entry
+ * guards even if it isn't in our Bridge config lines. */
+ if (router->purpose == ROUTER_PURPOSE_BRIDGE && from_cache &&
+ !authdir_mode_bridge(options) &&
+ !routerinfo_is_a_configured_bridge(router)) {
+ log_info(LD_DIR, "Dropping bridge descriptor for '%s' because we have "
+ "no bridge configured at that address.", router->nickname);
+ *msg = "Router descriptor was not a configured bridge.";
+ routerinfo_free(router);
+ return ROUTER_WAS_NOT_WANTED;
+ }
+
/* If we have a router with the same identity key, choose the newer one. */
if (old_router) {
if (!in_consensus && (router->cache_info.published_on <=
@@ -3381,7 +3395,7 @@ router_add_extrainfo_to_routerlist(extrainfo_t *ei, const char **msg,
int inserted;
(void)from_fetch;
if (msg) *msg = NULL;
- /*XXXX022 Do something with msg */
+ /*XXXX023 Do something with msg */
inserted = extrainfo_insert(router_get_routerlist(), ei);
@@ -4577,7 +4591,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
/** How often should we launch a server/authority request to be sure of getting
* a guess for our IP? */
-/*XXXX021 this info should come from netinfo cells or something, or we should
+/*XXXX023 this info should come from netinfo cells or something, or we should
* do this only when we aren't seeing incoming data. see bug 652. */
#define DUMMY_DOWNLOAD_INTERVAL (20*60)
@@ -4595,7 +4609,7 @@ update_router_descriptor_downloads(time_t now)
update_consensus_router_descriptor_downloads(now, 0,
networkstatus_get_reasonably_live_consensus(now));
- /* XXXX021 we could be smarter here; see notes on bug 652. */
+ /* XXXX023 we could be smarter here; see notes on bug 652. */
/* If we're a server that doesn't have a configured address, we rely on
* directory fetches to learn when our address changes. So if we haven't
* tried to get any routerdescs in a long time, try a dummy fetch now. */
@@ -5016,7 +5030,8 @@ routerinfo_incompatible_with_extrainfo(routerinfo_t *ri, extrainfo_t *ei,
if (ei->pending_sig) {
char signed_digest[128];
- if (crypto_pk_public_checksig(ri->identity_pkey, signed_digest,
+ if (crypto_pk_public_checksig(ri->identity_pkey,
+ signed_digest, sizeof(signed_digest),
ei->pending_sig, ei->pending_sig_len) != DIGEST_LEN ||
memcmp(signed_digest, ei->cache_info.signed_descriptor_digest,
DIGEST_LEN)) {
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 691b9beabc..ba29f056f1 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -11,6 +11,7 @@
#include "or.h"
#include "config.h"
+#include "circuitbuild.h"
#include "dirserv.h"
#include "dirvote.h"
#include "policies.h"
@@ -702,11 +703,13 @@ router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
size_t digest_len, crypto_pk_env_t *private_key)
{
char *signature;
- size_t i;
+ size_t i, keysize;
int siglen;
- signature = tor_malloc(crypto_pk_keysize(private_key));
- siglen = crypto_pk_private_sign(private_key, signature, digest, digest_len);
+ keysize = crypto_pk_keysize(private_key);
+ signature = tor_malloc(keysize);
+ siglen = crypto_pk_private_sign(private_key, signature, keysize,
+ digest, digest_len);
if (siglen < 0) {
log_warn(LD_BUG,"Couldn't sign digest.");
goto err;
@@ -1059,6 +1062,7 @@ check_signature_token(const char *digest,
const char *doctype)
{
char *signed_digest;
+ size_t keysize;
const int check_authority = (flags & CST_CHECK_AUTHORITY);
const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE);
@@ -1080,9 +1084,10 @@ check_signature_token(const char *digest,
}
}
- signed_digest = tor_malloc(tok->object_size);
- if (crypto_pk_public_checksig(pkey, signed_digest, tok->object_body,
- tok->object_size)
+ keysize = crypto_pk_keysize(pkey);
+ signed_digest = tor_malloc(keysize);
+ if (crypto_pk_public_checksig(pkey, signed_digest, keysize,
+ tok->object_body, tok->object_size)
< digest_len) {
log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
tor_free(signed_digest);
@@ -1500,6 +1505,12 @@ router_parse_entry_from_string(const char *s, const char *end,
router->has_old_dnsworkers = 1;
}
+ if (find_opt_by_keyword(tokens, K_REJECT6) ||
+ find_opt_by_keyword(tokens, K_ACCEPT6)) {
+ log_warn(LD_DIR, "Rejecting router with reject6/accept6 line: they crash "
+ "older Tors.");
+ goto err;
+ }
exit_policy_tokens = find_all_exitpolicy(tokens);
if (!smartlist_len(exit_policy_tokens)) {
log_warn(LD_DIR, "No exit policy tokens in descriptor.");
@@ -1715,6 +1726,10 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
authority_cert_t *
authority_cert_parse_from_string(const char *s, const char **end_of_string)
{
+ /** Reject any certificate at least this big; it is probably an overflow, an
+ * attack, a bug, or some other nonsense. */
+#define MAX_CERT_SIZE (128*1024)
+
authority_cert_t *cert = NULL, *old_cert;
smartlist_t *tokens = NULL;
char digest[DIGEST_LEN];
@@ -1742,6 +1757,12 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string)
++eos;
len = eos - s;
+ if (len > MAX_CERT_SIZE) {
+ log_warn(LD_DIR, "Certificate is far too big (at %lu bytes long); "
+ "rejecting", (unsigned long)len);
+ return NULL;
+ }
+
tokens = smartlist_create();
area = memarea_new();
if (tokenize_string(area,s, eos, tokens, dir_key_certificate_table, 0) < 0) {
@@ -1797,7 +1818,7 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string)
struct in_addr in;
char *address = NULL;
tor_assert(tok->n_args);
- /* XXX021 use tor_addr_port_parse() below instead. -RD */
+ /* XXX023 use tor_addr_port_parse() below instead. -RD */
if (parse_addr_port(LOG_WARN, tok->args[0], &address, NULL,
&cert->dir_port)<0 ||
tor_inet_aton(address, &in) == 0) {
@@ -2369,7 +2390,7 @@ networkstatus_verify_bw_weights(networkstatus_t *ns)
const char *casename = NULL;
int valid = 1;
- weight_scale = networkstatus_get_param(ns, "bwweightscale", BW_WEIGHT_SCALE);
+ weight_scale = circuit_build_times_get_bw_scale(ns);
Wgg = networkstatus_get_bw_weight(ns, "Wgg", -1);
Wgm = networkstatus_get_bw_weight(ns, "Wgm", -1);
Wgd = networkstatus_get_bw_weight(ns, "Wgd", -1);
@@ -2801,7 +2822,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
ns->flavor = flav = flavor;
}
if (flav != FLAV_NS && ns_type != NS_TYPE_CONSENSUS) {
- log_warn(LD_DIR, "Flavor found on non-consenus networkstatus.");
+ log_warn(LD_DIR, "Flavor found on non-consensus networkstatus.");
goto err;
}
@@ -3223,7 +3244,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
}
sig->good_signature = 1;
} else {
- if (tok->object_size >= INT_MAX) {
+ if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) {
tor_free(sig);
goto err;
}
@@ -3492,7 +3513,7 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
sig->alg = alg;
memcpy(sig->identity_digest, id_digest, DIGEST_LEN);
memcpy(sig->signing_key_digest, sk_digest, DIGEST_LEN);
- if (tok->object_size >= INT_MAX) {
+ if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) {
tor_free(sig);
goto err;
}
@@ -3810,6 +3831,13 @@ static directory_token_t *
get_next_token(memarea_t *area,
const char **s, const char *eos, token_rule_t *table)
{
+ /** Reject any object at least this big; it is probably an overflow, an
+ * attack, a bug, or some other nonsense. */
+#define MAX_UNPARSED_OBJECT_SIZE (128*1024)
+ /** Reject any line at least this big; it is probably an overflow, an
+ * attack, a bug, or some other nonsense. */
+#define MAX_LINE_LENGTH (128*1024)
+
const char *next, *eol, *obstart;
size_t obname_len;
int i;
@@ -3828,6 +3856,10 @@ get_next_token(memarea_t *area,
eol = memchr(*s, '\n', eos-*s);
if (!eol)
eol = eos;
+ if (eol - *s > MAX_LINE_LENGTH) {
+ RET_ERR("Line far too long");
+ }
+
next = find_whitespace_eos(*s, eol);
if (!strcmp_len(*s, "opt", next-*s)) {
@@ -3894,7 +3926,8 @@ get_next_token(memarea_t *area,
obstart = *s; /* Set obstart to start of object spec */
if (*s+16 >= eol || memchr(*s+11,'\0',eol-*s-16) || /* no short lines, */
- strcmp_len(eol-5, "-----", 5)) { /* nuls or invalid endings */
+ strcmp_len(eol-5, "-----", 5) || /* nuls or invalid endings */
+ (eol-*s) > MAX_UNPARSED_OBJECT_SIZE) { /* name too long */
RET_ERR("Malformed object: bad begin line");
}
tok->object_type = STRNDUP(*s+11, eol-*s-16);
@@ -3919,13 +3952,16 @@ get_next_token(memarea_t *area,
ebuf[sizeof(ebuf)-1] = '\0';
RET_ERR(ebuf);
}
+ if (next - *s > MAX_UNPARSED_OBJECT_SIZE)
+ RET_ERR("Couldn't parse object: missing footer or object much too big.");
+
if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */
tok->key = crypto_new_pk_env();
if (crypto_pk_read_public_key_from_string(tok->key, obstart, eol-obstart))
RET_ERR("Couldn't parse public key.");
} else if (!strcmp(tok->object_type, "RSA PRIVATE KEY")) { /* private key */
tok->key = crypto_new_pk_env();
- if (crypto_pk_read_private_key_from_string(tok->key, obstart))
+ if (crypto_pk_read_private_key_from_string(tok->key, obstart, eol-obstart))
RET_ERR("Couldn't parse private key.");
} else { /* If it's something else, try to base64-decode it */
int r;
@@ -4602,10 +4638,12 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
else
eos = eos + 1;
/* Check length. */
- if (strlen(desc) > REND_DESC_MAX_SIZE) {
- log_warn(LD_REND, "Descriptor length is %i which exceeds "
- "maximum rendezvous descriptor size of %i kilobytes.",
- (int)strlen(desc), REND_DESC_MAX_SIZE);
+ if (eos-desc > REND_DESC_MAX_SIZE) {
+ /* XXX023 If we are parsing this descriptor as a server, this
+ * should be a protocol warning. */
+ log_warn(LD_REND, "Descriptor length is %d which exceeds "
+ "maximum rendezvous descriptor size of %d bytes.",
+ (int)(eos-desc), REND_DESC_MAX_SIZE);
goto err;
}
/* Tokenize descriptor. */
diff --git a/src/or/routerparse.h b/src/or/routerparse.h
index bde7800b7d..8b8cde25f6 100644
--- a/src/or/routerparse.h
+++ b/src/or/routerparse.h
@@ -5,7 +5,7 @@
/* See LICENSE for licensing information */
/**
- * \file routerpase.h
+ * \file routerparse.h
* \brief Header file for routerparse.c.
**/
@@ -82,7 +82,5 @@ int rend_parse_introduction_points(rend_service_descriptor_t *parsed,
size_t intro_points_encoded_size);
int rend_parse_client_keys(strmap_t *parsed_clients, const char *str);
-void tor_gettimeofday_cache_clear(void);
-
#endif