aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog107
-rw-r--r--changes/bug136675
-rw-r--r--changes/bug138089
-rw-r--r--changes/bug138116
-rw-r--r--changes/bug13823-decrease-consensus-interval8
-rw-r--r--changes/bug13839-fix-TestingMinExitFlagThreshold7
-rw-r--r--changes/bug139137
-rw-r--r--changes/bug13963-decrease-if-modified-since-delay7
-rw-r--r--changes/bug140136
-rw-r--r--changes/bug140415
-rw-r--r--changes/resolvemyaddr-tests3
-rw-r--r--changes/ticket110166
-rw-r--r--src/or/circuitbuild.c24
-rw-r--r--src/or/circuituse.c98
-rw-r--r--src/or/config.c2
-rw-r--r--src/or/control.c30
-rw-r--r--src/or/dirserv.c2
-rw-r--r--src/or/nodelist.c231
-rw-r--r--src/or/nodelist.h30
19 files changed, 442 insertions, 151 deletions
diff --git a/ChangeLog b/ChangeLog
index d7c9430f8d..4b7f35f546 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -18,6 +18,10 @@ Changes in version 0.2.6.2-alpha - 2014-12-??
implements ticket 9262.
o Major features (hidden services):
+ - Make HS port scanning more difficult by sending back REASON_DONE
+ if the exit policy didn't match. Furthermore, immediately close
+ the circuit to slow down port scanning attempts. Closes
+ ticket 13667.
- Add a HiddenServiceStatistics option that allows Tor relays to
gather and publish statistics the overall size and volume of
hidden service usage. Specifically, when this option is turned on,
@@ -30,6 +34,14 @@ Changes in version 0.2.6.2-alpha - 2014-12-??
proposal 238, "Better hidden service stats from Tor relays". This
feature is currently disabled by default. Implements feature 13192.
+ o Major bugfixes (client, automap):
+ - Repair automapping with IPv6 addresses; this automapping should
+ have worked previously, but one piece of debugging code that we
+ inserted to detect a regression actually caused the regression to
+ manifest itself again. Fixes bug 13811 and bug 12831; bugfix on
+ 0.2.4.7-alpha. Diagnosed and fixed by Francisco Blas
+ Izquierdo Riera.
+
o Major bugfixes (hidden services):
- When closing an introduction circuit that was opened in parallel
with others, don't mark the introduction point as unreachable.
@@ -37,6 +49,12 @@ Changes in version 0.2.6.2-alpha - 2014-12-??
point would make the other introduction points get marked as
having timed out. Fixes bug 13698; bugfix on 0.0.6rc2.
+ o Major removed features:
+ - Tor clients no longer support connecting to hidden services
+ running on Tor 0.2.2.x and earlier; the Support022HiddenServices
+ option has been removed. (There shouldn't be any hidden services
+ running these versions on the network.) Closes ticket 7803.
+
o Minor features (client):
- Validate hostnames in SOCKS5 requests more strictly. If SafeSocks
is enabled, reject requests with IP addresses as hostnames.
@@ -63,9 +81,29 @@ Changes in version 0.2.6.2-alpha - 2014-12-??
directories and hostname files to be created group-readable. Patch
from "anon", David Stainton, and "meejah". Closes ticket 11291.
- o Minor features (transparent firewall):
+ o Minor features (systemd):
+ - Where supported, when running with systemd, report successful
+ startup to systemd. Part of ticket 11016. Patch by Michael Scherer.
+ - When running with systemd, support systemd watchdog messages. Part
+ of ticket 11016. Patch by Michael Scherer.
+
+ o Minor features (transparent proxy):
- Update the transparent proxy option checks to allow for both ipfw
and pf on OS X. Closes ticket 14002.
+ - Use the correct option when using IPv6 with transparent proxy
+ support on Linux. Resolves 13808. Patch by Francisco Blas
+ Izquierdo Riera.
+
+ o Minor bugfixes (preventative security, C safety):
+ - When reading a hexadecimal, base-32, or base-64 encoded value from
+ a string, always overwrite the complete output buffer. This
+ prevents some bugs where we would look at (but fortunately, not
+ reveal) uninitialized memory on the stack. Fixes bug 14013; bugfix
+ on all versions of Tor.
+ - Clear all memory targetted by tor_addr_{to,from}_sockaddr(), not
+ just the part that's used. This makes it harder for data leak bugs
+ to occur in the event of other programming failures. Resolves
+ ticket 14041.
o Minor bugfixes (client, micordescriptors):
- Use a full 256 bits of the SHA256 digest of a microdescriptor when
@@ -103,6 +141,11 @@ Changes in version 0.2.6.2-alpha - 2014-12-??
directories. Fixes bug 13214; bugfix on 0.2.1.6-alpha. Reported
by "special".
+ o Minor bugfixes (Linux seccomp2 sandbox):
+ - Make transparent proxy support work along with the seccomp2
+ sandbox. Fixes part of bug 13808; bugfix on 0.2.5.1-alpha. Patch
+ by Francisco Blas Izquierdo Riera.
+
o Minor bugfixes (logging):
- Downgrade warnings about RSA signature failures to info log level.
Emit a warning when extra info document is found incompatible with
@@ -118,6 +161,56 @@ Changes in version 0.2.6.2-alpha - 2014-12-??
our address-range parsing code. Fixes bug 7484; bugfix
on 0.0.2pre14.
+ o Minor bugfixes (testing networks):
+ - Allow Tor to build circuits using a consensus with no exits. If
+ the consensus has no exits (typical of a bootstrapping test
+ network), allow Tor to build circuits once enough descriptors have
+ been downloaded. This assists in bootstrapping a testing Tor
+ network. Fixes bug 13718; bugfix on 0.2.4.10-alpha. Patch
+ by "teor".
+ - When V3AuthVotingInterval is low, give a lower If-Modified-Since
+ header to directory servers. This allows us to obtain consensuses
+ promptly when the consensus interval is very short. This assists
+ in bootstrapping a testing Tor network. Fixes parts of bugs 13718
+ and 13963; bugfix on 0.2.0.3-alpha. Patch by "teor".
+ - Stop assuming that private addresses are local when checking
+ reachability in a TestingTorNetwork. Instead, when testing, assume
+ all OR connections are remote. (This is necessary due to many test
+ scenarios running all nodes on localhost.) This assists in
+ bootstrapping a testing Tor network. Fixes bug 13924; bugfix on
+ 0.1.0.1-rc. Patch by "teor".
+ - Avoid building exit circuits from a consensus with no exits. Now
+ thanks to our fix for 13718, we accept a no-exit network as not
+ wholly lost, but we need to remember not to try to build exit
+ circuits on it. Closes ticket 13814; patch by "teor".
+ - Stop requiring exits to have non-zero bandwithcapacity in a
+ TestingTorNetwork. Instead, when TestingMinExitFlagThreshold is 0,
+ ignore exit bandwidthcapacity. This assists in bootstrapping a
+ testing Tor network. Fixes parts of bugs 13718 and 13839; bugfix
+ on 0.2.0.3-alpha. Patch by "teor".
+ - Add "internal" to some bootstrap statuses when no exits are
+ available. If the consensus does not contain Exits, Tor will only
+ build internal circuits. In this case, relevant statuses will
+ contain the word "internal" as indicated in the Tor control-
+ spec.txt. When bootstrap completes, Tor will be ready to handle an
+ application requesting an internal circuit to hidden services at
+ ".onion" addresses. If a future consensus contains Exits, exit
+ circuits may become available. Fixes part of bug 13718; bugfix on
+ 0.2.4.10-alpha. Patch by "teor".
+ - Decrease minimum consensus interval to 10 seconds when
+ TestingTorNetwork is set, or 5 seconds for the first consensus.
+ Fix assumptions throughout the code that assume larger interval
+ values. This assists in quickly bootstrapping a testing Tor
+ network. Fixes bugs 13718 and 13823; bugfix on 0.2.0.3-alpha.
+ Patch by "teor".
+ - Avoid excluding guards from path building in minimal test
+ networks, when we're in a test network, and excluding guards would
+ exclude all nodes. This typically occurs in incredibly small tor
+ networks, and those using TestingAuthVoteGuard * This fix only
+ applies to minimal, testing tor networks, so it's no less secure.
+ Fixes part of bug 13718; bugfix on 0.1.1.11-alpha. Patch
+ by "teor".
+
o Code simplification and refactoring:
- Stop using can_complete_circuits as a global variable; access it
with a function instead.
@@ -153,12 +246,10 @@ Changes in version 0.2.6.2-alpha - 2014-12-??
good idea. Also, properly cross-reference how to specify nodes in
all parts of the manual for options that take a list of nodes.
Closes ticket 13381.
-
- o Major removed features:
- - Tor clients no longer support connecting to hidden services
- running on Tor 0.2.2.x and earlier; the Support022HiddenServices
- option has been removed. (There shouldn't be any hidden services
- running these versions on the network.) Closes ticket 7803.
+ - Clarify HiddenServiceDir option description in manpage to make it
+ clear that relative paths are taken with respect to the current
+ working directory of Tor instance. Also clarify that this behavior
+ is not guaranteed to remain indefinitely. Fixes issue 13913.
o Testing:
- New tests for many parts of channel, relay, and circuit mux
@@ -168,6 +259,8 @@ Changes in version 0.2.6.2-alpha - 2014-12-??
test temporary directory to the current user, so that the sticky
bit doesn't interfere with tests that check directory groups.
Closes 13678.
+ - Add unit tests for resolve_my_addr(). Part of ticket 12376; patch
+ by 'rl1987'.
Changes in version 0.2.6.1-alpha - 2014-10-30
diff --git a/changes/bug13667 b/changes/bug13667
deleted file mode 100644
index 3714753df4..0000000000
--- a/changes/bug13667
+++ /dev/null
@@ -1,5 +0,0 @@
- o Major bugfixes:
- - Make HS port scanning more difficult by sending back REASON_DONE if the
- exit policy didn't match. Furthermore, immediately close the circuit to
- avoid other connection attempts on it from the possible attacker trying
- multiple ports on that same circuit.
diff --git a/changes/bug13808 b/changes/bug13808
deleted file mode 100644
index b24a01c17b..0000000000
--- a/changes/bug13808
+++ /dev/null
@@ -1,9 +0,0 @@
- o Minor features (transparent proxy):
- - Use the correct option when using IPv6 with transparent proxy
- support on Linux. Resolves 13808. Patch by Francisco Blas
- Izquierdo Riera.
-
- o Minor bugfixes (sandbox):
- - Make transparent proxy support work along with the seccomp2
- sandbox. Fixes part of bug 13808; bugfix on 0.2.5.1-alpha.
- Patch by Francisco Blas Izquierdo Riera.
diff --git a/changes/bug13811 b/changes/bug13811
deleted file mode 100644
index 1b9bd9c68d..0000000000
--- a/changes/bug13811
+++ /dev/null
@@ -1,6 +0,0 @@
- o Major bugfixes (client, automap):
- - Repair automapping with IPv6 addresses; this automapping should
- have worked previously, but one piece of debugging code that we
- inserted to detect a regression actually caused the regression
- to manifest itself again. Fixes bug 13811; bugfix on
- 0.2.4.7-alpha. Diagnosed and fixed by Francisco Blas Izquierdo Riera. \ No newline at end of file
diff --git a/changes/bug13823-decrease-consensus-interval b/changes/bug13823-decrease-consensus-interval
deleted file mode 100644
index 1d99bd73cb..0000000000
--- a/changes/bug13823-decrease-consensus-interval
+++ /dev/null
@@ -1,8 +0,0 @@
- o Minor bugfixes:
- - Decrease minimum consensus interval to 10 seconds
- when TestingTorNetwork is set. (Or 5 seconds for
- the first consensus.)
- Fix code that assumes larger interval values.
- This assists in quickly bootstrapping a testing
- Tor network.
- Fixes bugs 13718 & 13823.
diff --git a/changes/bug13839-fix-TestingMinExitFlagThreshold b/changes/bug13839-fix-TestingMinExitFlagThreshold
deleted file mode 100644
index 947614f550..0000000000
--- a/changes/bug13839-fix-TestingMinExitFlagThreshold
+++ /dev/null
@@ -1,7 +0,0 @@
- o Minor bugfixes:
- - Stop requiring exits to have non-zero bandwithcapacity in a
- TestingTorNetwork. Instead, when TestingMinExitFlagThreshold is 0,
- ignore exit bandwidthcapacity.
- This assists in bootstrapping a testing Tor network.
- Fixes bugs 13718 & 13839.
- Makes bug 13161's TestingDirAuthVoteExit non-essential.
diff --git a/changes/bug13913 b/changes/bug13913
deleted file mode 100644
index 9a23180eb3..0000000000
--- a/changes/bug13913
+++ /dev/null
@@ -1,7 +0,0 @@
- o Documentation:
- - Clarify HiddenServiceDir option description in manpage to make it
- clear that relative paths are taken with respect to the current
- working
- directory of Tor instance. Also clarify that this behavior is
- not guaranteed to remain indefinitely. Fixes
- issue 13913.
diff --git a/changes/bug13963-decrease-if-modified-since-delay b/changes/bug13963-decrease-if-modified-since-delay
deleted file mode 100644
index 62371444c4..0000000000
--- a/changes/bug13963-decrease-if-modified-since-delay
+++ /dev/null
@@ -1,7 +0,0 @@
- o Minor bugfixes:
- - When V3AuthVotingInterval is low, decrease the delay on the
- If-Modified-Since header passed to directory servers.
- This allows us to obtain consensuses promptly when the consensus
- interval is very short.
- This assists in bootstrapping a testing Tor network.
- Fixes bugs 13718 & 13963.
diff --git a/changes/bug14013 b/changes/bug14013
deleted file mode 100644
index 640cf859f5..0000000000
--- a/changes/bug14013
+++ /dev/null
@@ -1,6 +0,0 @@
- o Major bugfixes:
- - When reading a hexadecimal, base-32, or base-64 encoded value
- from a string, always overwrite the complete output buffer. This
- prevents some bugs where we would look at (but fortunately, not
- reveal) uninitialized memory on the stack. Fixes bug 14013;
- bugfix on all versions of Tor.
diff --git a/changes/bug14041 b/changes/bug14041
deleted file mode 100644
index d3d6538483..0000000000
--- a/changes/bug14041
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor features (security):
- - Clear all memory targetted by tor_addr_{to,from}_sockaddr(),
- not just the part that's used. This makes it harder for data leak
- bugs to occur in the event of other programming failures.
- Resolves ticket 14041.
diff --git a/changes/resolvemyaddr-tests b/changes/resolvemyaddr-tests
deleted file mode 100644
index c019bb831e..0000000000
--- a/changes/resolvemyaddr-tests
+++ /dev/null
@@ -1,3 +0,0 @@
- o Testing:
- - Add unit tests for resolve_my_addr(). Part of ticket 12376;
- patch by 'rl1987'.
diff --git a/changes/ticket11016 b/changes/ticket11016
deleted file mode 100644
index 98d5d49697..0000000000
--- a/changes/ticket11016
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor features (systemd):
- - Where supported, when running with systemd, report successful
- startup to systemd. Part of ticket 11016. Patch by Michael
- Scherer.
- - When running with systemd, support systemd watchdog messages.
- Part of ticket 11016. Patch by Michael Scherer.
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index faddc08e03..7061ab0e0b 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -1378,8 +1378,10 @@ onionskin_answer(or_circuit_t *circ,
log_debug(LD_CIRC,"Finished sending '%s' cell.",
circ->is_first_hop ? "created_fast" : "created");
- if (!channel_is_local(circ->p_chan) &&
- !channel_is_outgoing(circ->p_chan)) {
+ /* Ignore the local bit when testing - many test networks run on local
+ * addresses */
+ if ((!channel_is_local(circ->p_chan) || get_options()->TestingTorNetwork)
+ && !channel_is_outgoing(circ->p_chan)) {
/* record that we could process create cells from a non-local conn
* that we didn't initiate; presumably this means that create cells
* can reach us too. */
@@ -1863,7 +1865,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
choose_good_exit_server(circ->base_.purpose, state->need_uptime,
state->need_capacity, state->is_internal);
if (!node) {
- log_warn(LD_CIRC,"failed to choose an exit server");
+ log_warn(LD_CIRC,"Failed to choose an exit server");
return -1;
}
exit = extend_info_from_node(node, 0);
@@ -1990,7 +1992,8 @@ choose_good_middle_server(uint8_t purpose,
tor_assert(CIRCUIT_PURPOSE_MIN_ <= purpose &&
purpose <= CIRCUIT_PURPOSE_MAX_);
- log_debug(LD_CIRC, "Contemplating intermediate hop: random choice.");
+ log_debug(LD_CIRC, "Contemplating intermediate hop %d: random choice.",
+ cur_len);
excluded = smartlist_new();
if ((r = build_state_get_exit_node(state))) {
nodelist_add_node_and_family(excluded, r);
@@ -2052,9 +2055,18 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
smartlist_add(excluded, (void*)node);
});
}
- /* and exclude current entry guards and their families, if applicable */
+ /* and exclude current entry guards and their families,
+ * unless we're in a test network, and excluding guards
+ * would exclude all nodes (i.e. we're in an incredibly small tor network,
+ * or we're using TestingAuthVoteGuard *).
+ * This is an incomplete fix, but is no worse than the previous behaviour,
+ * and only applies to minimal, testing tor networks
+ * (so it's no less secure) */
/*XXXX025 use the using_as_guard flag to accomplish this.*/
- if (options->UseEntryGuards) {
+ if (options->UseEntryGuards
+ && (!options->TestingTorNetwork ||
+ smartlist_len(nodelist_get_list()) > smartlist_len(get_entry_guards())
+ )) {
SMARTLIST_FOREACH(get_entry_guards(), const entry_guard_t *, entry,
{
if ((node = node_get_by_id(entry->identity))) {
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 90571360de..3322d31e2f 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1024,9 +1024,11 @@ circuit_predict_and_launch_new(void)
/* Second, see if we need any more exit circuits. */
/* check if we know of a port that's been requested recently
- * and no circuit is currently available that can handle it. */
+ * and no circuit is currently available that can handle it.
+ * Exits (obviously) require an exit circuit. */
if (!circuit_all_predicted_ports_handled(now, &port_needs_uptime,
- &port_needs_capacity)) {
+ &port_needs_capacity)
+ && router_have_consensus_path() == CONSENSUS_PATH_EXIT) {
if (port_needs_uptime)
flags |= CIRCLAUNCH_NEED_UPTIME;
if (port_needs_capacity)
@@ -1038,8 +1040,10 @@ circuit_predict_and_launch_new(void)
return;
}
- /* Third, see if we need any more hidden service (server) circuits. */
- if (num_rend_services() && num_uptime_internal < 3) {
+ /* Third, see if we need any more hidden service (server) circuits.
+ * HS servers only need an internal circuit. */
+ if (num_rend_services() && num_uptime_internal < 3
+ && router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
flags = (CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_NEED_UPTIME |
CIRCLAUNCH_IS_INTERNAL);
log_info(LD_CIRC,
@@ -1050,11 +1054,13 @@ circuit_predict_and_launch_new(void)
return;
}
- /* Fourth, see if we need any more hidden service (client) circuits. */
+ /* Fourth, see if we need any more hidden service (client) circuits.
+ * HS clients only need an internal circuit. */
if (rep_hist_get_predicted_internal(now, &hidserv_needs_uptime,
&hidserv_needs_capacity) &&
((num_uptime_internal<2 && hidserv_needs_uptime) ||
- num_internal<2)) {
+ num_internal<2)
+ && router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
if (hidserv_needs_uptime)
flags |= CIRCLAUNCH_NEED_UPTIME;
if (hidserv_needs_capacity)
@@ -1071,15 +1077,23 @@ circuit_predict_and_launch_new(void)
/* Finally, check to see if we still need more circuits to learn
* a good build timeout. But if we're close to our max number we
* want, don't do another -- we want to leave a few slots open so
- * we can still build circuits preemptively as needed. */
- if (num < MAX_UNUSED_OPEN_CIRCUITS-2 &&
- ! circuit_build_times_disabled() &&
- circuit_build_times_needs_circuits_now(get_circuit_build_times())) {
- flags = CIRCLAUNCH_NEED_CAPACITY;
- log_info(LD_CIRC,
- "Have %d clean circs need another buildtime test circ.", num);
- circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
- return;
+ * we can still build circuits preemptively as needed.
+ * XXXX make the assumption that build timeout streams should be
+ * created whenever we can build internal circuits. */
+ if (router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
+ if (num < MAX_UNUSED_OPEN_CIRCUITS-2 &&
+ ! circuit_build_times_disabled() &&
+ circuit_build_times_needs_circuits_now(get_circuit_build_times())) {
+ flags = CIRCLAUNCH_NEED_CAPACITY;
+ /* if there are no exits in the consensus, make timeout
+ * circuits internal */
+ if (router_have_consensus_path() == CONSENSUS_PATH_INTERNAL)
+ flags |= CIRCLAUNCH_IS_INTERNAL;
+ log_info(LD_CIRC,
+ "Have %d clean circs need another buildtime test circ.", num);
+ circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
+ return;
+ }
}
}
@@ -1096,11 +1110,17 @@ circuit_build_needed_circs(time_t now)
{
const or_options_t *options = get_options();
- /* launch a new circ for any pending streams that need one */
- connection_ap_attach_pending();
+ /* launch a new circ for any pending streams that need one
+ * XXXX make the assumption that (some) AP streams (i.e. HS clients)
+ * don't require an exit circuit, review in #13814.
+ * This allows HSs to function in a consensus without exits. */
+ if (router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN)
+ connection_ap_attach_pending();
- /* make sure any hidden services have enough intro points */
- rend_services_introduce();
+ /* make sure any hidden services have enough intro points
+ * HS intro point streams only require an internal circuit */
+ if (router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN)
+ rend_services_introduce();
circuit_expire_old_circs_as_needed(now);
@@ -1632,6 +1652,16 @@ circuit_launch(uint8_t purpose, int flags)
return circuit_launch_by_extend_info(purpose, NULL, flags);
}
+/** DOCDOC */
+static int
+have_enough_path_info(int need_exit)
+{
+ if (need_exit)
+ return router_have_consensus_path() == CONSENSUS_PATH_EXIT;
+ else
+ return router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN;
+}
+
/** Launch a new circuit with purpose <b>purpose</b> and exit node
* <b>extend_info</b> (or NULL to select a random exit node). If flags
* contains CIRCLAUNCH_NEED_UPTIME, choose among routers with high uptime. If
@@ -1646,10 +1676,14 @@ circuit_launch_by_extend_info(uint8_t purpose,
{
origin_circuit_t *circ;
int onehop_tunnel = (flags & CIRCLAUNCH_ONEHOP_TUNNEL) != 0;
-
- if (!onehop_tunnel && !router_have_minimum_dir_info()) {
- log_debug(LD_CIRC,"Haven't fetched enough directory info yet; canceling "
- "circuit launch.");
+ int have_path = have_enough_path_info(! (flags & CIRCLAUNCH_IS_INTERNAL) );
+
+ if (!onehop_tunnel && (!router_have_minimum_dir_info() || !have_path)) {
+ log_debug(LD_CIRC,"Haven't %s yet; canceling "
+ "circuit launch.",
+ !router_have_minimum_dir_info() ?
+ "fetched enough directory info" :
+ "received a consensus with exits");
return NULL;
}
@@ -1806,7 +1840,9 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
return 1; /* we're happy */
}
- if (!want_onehop && !router_have_minimum_dir_info()) {
+ int have_path = have_enough_path_info(!need_internal);
+
+ if (!want_onehop && (!router_have_minimum_dir_info() || !have_path)) {
if (!connection_get_by_type(CONN_TYPE_DIR)) {
int severity = LOG_NOTICE;
/* FFFF if this is a tunneled directory fetch, don't yell
@@ -1814,14 +1850,20 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
if (entry_list_is_constrained(options) &&
entries_known_but_down(options)) {
log_fn(severity, LD_APP|LD_DIR,
- "Application request when we haven't used client functionality "
- "lately. Optimistically trying known %s again.",
+ "Application request when we haven't %s. "
+ "Optimistically trying known %s again.",
+ !router_have_minimum_dir_info() ?
+ "used client functionality lately" :
+ "received a consensus with exits",
options->UseBridges ? "bridges" : "entrynodes");
entries_retry_all(options);
} else if (!options->UseBridges || any_bridge_descriptors_known()) {
log_fn(severity, LD_APP|LD_DIR,
- "Application request when we haven't used client functionality "
- "lately. Optimistically trying directory fetches again.");
+ "Application request when we haven't %s. "
+ "Optimistically trying directory fetches again.",
+ !router_have_minimum_dir_info() ?
+ "used client functionality lately" :
+ "received a consensus with exits");
routerlist_retry_directory_downloads(time(NULL));
}
}
diff --git a/src/or/config.c b/src/or/config.c
index ae4b0892d6..9f5bd3b957 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -1833,7 +1833,7 @@ options_act(const or_options_t *old_options)
directory_fetches_dir_info_early(old_options)) ||
!bool_eq(directory_fetches_dir_info_later(options),
directory_fetches_dir_info_later(old_options))) {
- /* Make sure update_router_have_min_dir_info gets called. */
+ /* Make sure update_router_have_minimum_dir_info() gets called. */
router_dir_info_changed();
/* We might need to download a new consensus status later or sooner than
* we had expected. */
diff --git a/src/or/control.c b/src/or/control.c
index dc67588d6a..7214559136 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -4807,23 +4807,43 @@ bootstrap_status_to_string(bootstrap_status_t s, const char **tag,
break;
case BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS:
*tag = "requesting_descriptors";
- *summary = "Asking for relay descriptors";
+ /* XXXX this appears to incorrectly report internal on most loads */
+ *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ?
+ "Asking for relay descriptors for internal paths" :
+ "Asking for relay descriptors";
break;
+ /* If we're sure there are no exits in the consensus,
+ * inform the controller by adding "internal"
+ * to the status summaries.
+ * (We only check this while loading descriptors,
+ * so we may not know in the earlier stages.)
+ * But if there are exits, we can't be sure whether
+ * we're creating internal or exit paths/circuits.
+ * XXXX Or should be use different tags or statuses
+ * for internal and exit/all? */
case BOOTSTRAP_STATUS_LOADING_DESCRIPTORS:
*tag = "loading_descriptors";
- *summary = "Loading relay descriptors";
+ *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ?
+ "Loading relay descriptors for internal paths" :
+ "Loading relay descriptors";
break;
case BOOTSTRAP_STATUS_CONN_OR:
*tag = "conn_or";
- *summary = "Connecting to the Tor network";
+ *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ?
+ "Connecting to the Tor network internally" :
+ "Connecting to the Tor network";
break;
case BOOTSTRAP_STATUS_HANDSHAKE_OR:
*tag = "handshake_or";
- *summary = "Finishing handshake with first hop";
+ *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ?
+ "Finishing handshake with first hop of internal circuit" :
+ "Finishing handshake with first hop";
break;
case BOOTSTRAP_STATUS_CIRCUIT_CREATE:
*tag = "circuit_create";
- *summary = "Establishing a Tor circuit";
+ *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ?
+ "Establishing an internal Tor circuit" :
+ "Establishing a Tor circuit";
break;
case BOOTSTRAP_STATUS_DONE:
*tag = "done";
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index a1d22b041f..45d12ed3b1 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -733,7 +733,7 @@ running_long_enough_to_decide_unreachable(void)
}
/** Each server needs to have passed a reachability test no more
- * than this number of seconds ago, or he is listed as down in
+ * than this number of seconds ago, or it is listed as down in
* the directory. */
#define REACHABLE_TIMEOUT (45*60)
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index e0e01ec190..34d1d5f4d7 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -24,6 +24,23 @@
static void nodelist_drop_node(node_t *node, int remove_from_ht);
static void node_free(node_t *node);
+
+/** count_usable_descriptors counts descriptors with these flag(s)
+ */
+typedef enum {
+ /* All descriptors regardless of flags */
+ USABLE_DESCRIPTOR_ALL = 0,
+ /* Only descriptors with the Exit flag */
+ USABLE_DESCRIPTOR_EXIT_ONLY = 1
+} usable_descriptor_t;
+static void count_usable_descriptors(int *num_present,
+ int *num_usable,
+ smartlist_t *descs_out,
+ const networkstatus_t *consensus,
+ const or_options_t *options,
+ time_t now,
+ routerset_t *in_set,
+ usable_descriptor_t exit_only);
static void update_router_have_minimum_dir_info(void);
static double get_frac_paths_needed_for_circs(const or_options_t *options,
const networkstatus_t *ns);
@@ -1256,20 +1273,28 @@ router_set_status(const char *digest, int up)
}
/** True iff, the last time we checked whether we had enough directory info
- * to build circuits, the answer was "yes". */
+ * to build circuits, the answer was "yes". If there are no exits in the
+ * consensus, we act as if we have 100% of the exit directory info. */
static int have_min_dir_info = 0;
+
+/** Does the consensus contain nodes that can exit? */
+static consensus_path_type_t have_consensus_path = CONSENSUS_PATH_UNKNOWN;
+
/** True iff enough has changed since the last time we checked whether we had
* enough directory info to build circuits that our old answer can no longer
* be trusted. */
static int need_to_update_have_min_dir_info = 1;
/** String describing what we're missing before we have enough directory
* info. */
-static char dir_info_status[256] = "";
-
-/** Return true iff we have enough networkstatus and router information to
- * start building circuits. Right now, this means "more than half the
- * networkstatus documents, and at least 1/4 of expected routers." */
-//XXX should consider whether we have enough exiting nodes here.
+static char dir_info_status[512] = "";
+
+/** Return true iff we have enough consensus information to
+ * start building circuits. Right now, this means "a consensus that's
+ * less than a day old, and at least 60% of router descriptors (configurable),
+ * weighted by bandwidth. Treat the exit fraction as 100% if there are
+ * no exits in the consensus."
+ * To obtain the final weighted bandwidth, we multiply the
+ * weighted bandwidth fraction for each position (guard, middle, exit). */
int
router_have_minimum_dir_info(void)
{
@@ -1291,6 +1316,24 @@ router_have_minimum_dir_info(void)
return have_min_dir_info;
}
+/** Set to CONSENSUS_PATH_EXIT if there is at least one exit node
+ * in the consensus. We update this flag in compute_frac_paths_available if
+ * there is at least one relay that has an Exit flag in the consensus.
+ * Used to avoid building exit circuits when they will almost certainly fail.
+ * Set to CONSENSUS_PATH_INTERNAL if there are no exits in the consensus.
+ * (This situation typically occurs during bootstrap of a test network.)
+ * Set to CONSENSUS_PATH_UNKNOWN if we have never checked, or have
+ * reason to believe our last known value was invalid or has expired.
+ * If we're in a network with TestingDirAuthVoteExit set,
+ * this can cause router_have_consensus_path() to be set to
+ * CONSENSUS_PATH_EXIT, even if there are no nodes with accept exit policies.
+ */
+consensus_path_type_t
+router_have_consensus_path(void)
+{
+ return have_consensus_path;
+}
+
/** Called when our internal view of the directory has changed. This can be
* when the authorities change, networkstatuses change, the list of routerdescs
* changes, or number of running routers changes.
@@ -1313,20 +1356,23 @@ get_dir_info_status_string(void)
/** Iterate over the servers listed in <b>consensus</b>, and count how many of
* them seem like ones we'd use, and how many of <em>those</em> we have
* descriptors for. Store the former in *<b>num_usable</b> and the latter in
- * *<b>num_present</b>. If <b>in_set</b> is non-NULL, only consider those
- * routers in <b>in_set</b>. If <b>exit_only</b> is true, only consider nodes
- * with the Exit flag. If *descs_out is present, add a node_t for each
- * usable descriptor to it.
+ * *<b>num_present</b>.
+ * If <b>in_set</b> is non-NULL, only consider those routers in <b>in_set</b>.
+ * If <b>exit_only</b> is USABLE_DESCRIPTOR_EXIT_ONLY, only consider nodes
+ * with the Exit flag.
+ * If *<b>descs_out</b> is present, add a node_t for each usable descriptor
+ * to it.
*/
static void
count_usable_descriptors(int *num_present, int *num_usable,
smartlist_t *descs_out,
const networkstatus_t *consensus,
const or_options_t *options, time_t now,
- routerset_t *in_set, int exit_only)
+ routerset_t *in_set,
+ usable_descriptor_t exit_only)
{
const int md = (consensus->flavor == FLAV_MICRODESC);
- *num_present = 0, *num_usable=0;
+ *num_present = 0, *num_usable = 0;
SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs)
{
@@ -1334,7 +1380,7 @@ count_usable_descriptors(int *num_present, int *num_usable,
if (!node)
continue; /* This would be a bug: every entry in the consensus is
* supposed to have a node. */
- if (exit_only && ! rs->is_exit)
+ if (exit_only == USABLE_DESCRIPTOR_EXIT_ONLY && ! rs->is_exit)
continue;
if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1))
continue;
@@ -1358,11 +1404,21 @@ count_usable_descriptors(int *num_present, int *num_usable,
log_debug(LD_DIR, "%d usable, %d present (%s%s).",
*num_usable, *num_present,
- md ? "microdesc" : "desc", exit_only ? " exits" : "s");
+ md ? "microdesc" : "desc",
+ exit_only == USABLE_DESCRIPTOR_EXIT_ONLY ? " exits" : "s");
}
/** Return an estimate of which fraction of usable paths through the Tor
- * network we have available for use. */
+ * network we have available for use.
+ * Count how many routers seem like ones we'd use, and how many of
+ * <em>those</em> we have descriptors for. Store the former in
+ * *<b>num_usable_out</b> and the latter in *<b>num_present_out</b>.
+ * If **<b>status_out</b> is present, allocate a new string and print the
+ * available percentages of guard, middle, and exit nodes to it, noting
+ * whether there are exits in the consensus.
+ * If there are no guards in the consensus,
+ * we treat the exit fraction as 100%.
+ */
static double
compute_frac_paths_available(const networkstatus_t *consensus,
const or_options_t *options, time_t now,
@@ -1375,14 +1431,19 @@ compute_frac_paths_available(const networkstatus_t *consensus,
smartlist_t *myexits= smartlist_new();
smartlist_t *myexits_unflagged = smartlist_new();
double f_guard, f_mid, f_exit, f_myexit, f_myexit_unflagged;
- int np, nu; /* Ignored */
+ double f_path = 0.0;
+ /* Used to determine whether there are any exits in the consensus */
+ int np = 0;
+ /* Used to determine whether there are any exits with descriptors */
+ int nu = 0;
const int authdir = authdir_mode_v3(options);
count_usable_descriptors(num_present_out, num_usable_out,
- mid, consensus, options, now, NULL, 0);
+ mid, consensus, options, now, NULL,
+ USABLE_DESCRIPTOR_ALL);
if (options->EntryNodes) {
count_usable_descriptors(&np, &nu, guards, consensus, options, now,
- options->EntryNodes, 0);
+ options->EntryNodes, USABLE_DESCRIPTOR_ALL);
} else {
SMARTLIST_FOREACH(mid, const node_t *, node, {
if (authdir) {
@@ -1395,22 +1456,78 @@ compute_frac_paths_available(const networkstatus_t *consensus,
});
}
- /* All nodes with exit flag */
+ /* All nodes with exit flag
+ * If we're in a network with TestingDirAuthVoteExit set,
+ * this can cause false positives on have_consensus_path,
+ * incorrectly setting it to CONSENSUS_PATH_EXIT. This is
+ * an unavoidable feature of forcing authorities to declare
+ * certain nodes as exits.
+ */
count_usable_descriptors(&np, &nu, exits, consensus, options, now,
- NULL, 1);
+ NULL, USABLE_DESCRIPTOR_EXIT_ONLY);
+ log_debug(LD_NET,
+ "%s: %d present, %d usable",
+ "exits",
+ np,
+ nu);
+
+ /* We need at least 1 exit present in the consensus to consider
+ * building exit paths */
+ /* Update our understanding of whether the consensus has exits */
+ consensus_path_type_t old_have_consensus_path = have_consensus_path;
+ have_consensus_path = ((np > 0) ?
+ CONSENSUS_PATH_EXIT :
+ CONSENSUS_PATH_INTERNAL);
+
+ if (have_consensus_path == CONSENSUS_PATH_INTERNAL
+ && old_have_consensus_path != have_consensus_path) {
+ log_notice(LD_NET,
+ "The current consensus has no exit nodes. "
+ "Tor can only build internal paths, "
+ "such as paths to hidden services.");
+
+ /* However, exit nodes can reachability self-test using this consensus,
+ * join the network, and appear in a later consensus. This will allow
+ * the network to build exit paths, such as paths for world wide web
+ * browsing (as distinct from hidden service web browsing). */
+ }
+
/* All nodes with exit flag in ExitNodes option */
count_usable_descriptors(&np, &nu, myexits, consensus, options, now,
- options->ExitNodes, 1);
+ options->ExitNodes, USABLE_DESCRIPTOR_EXIT_ONLY);
+ log_debug(LD_NET,
+ "%s: %d present, %d usable",
+ "myexits",
+ np,
+ nu);
+
/* Now compute the nodes in the ExitNodes option where which we don't know
* what their exit policy is, or we know it permits something. */
count_usable_descriptors(&np, &nu, myexits_unflagged,
consensus, options, now,
- options->ExitNodes, 0);
+ options->ExitNodes, USABLE_DESCRIPTOR_ALL);
+ log_debug(LD_NET,
+ "%s: %d present, %d usable",
+ "myexits_unflagged (initial)",
+ np,
+ nu);
+
SMARTLIST_FOREACH_BEGIN(myexits_unflagged, const node_t *, node) {
- if (node_has_descriptor(node) && node_exit_policy_rejects_all(node))
+ if (node_has_descriptor(node) && node_exit_policy_rejects_all(node)) {
SMARTLIST_DEL_CURRENT(myexits_unflagged, node);
+ /* this node is not actually an exit */
+ np--;
+ /* this node is unusable as an exit */
+ nu--;
+ }
} SMARTLIST_FOREACH_END(node);
+ log_debug(LD_NET,
+ "%s: %d present, %d usable",
+ "myexits_unflagged (final)",
+ np,
+ nu);
+
f_guard = frac_nodes_with_descriptors(guards, WEIGHT_FOR_GUARD);
f_mid = frac_nodes_with_descriptors(mid, WEIGHT_FOR_MID);
f_exit = frac_nodes_with_descriptors(exits, WEIGHT_FOR_EXIT);
@@ -1418,6 +1535,12 @@ compute_frac_paths_available(const networkstatus_t *consensus,
f_myexit_unflagged=
frac_nodes_with_descriptors(myexits_unflagged,WEIGHT_FOR_EXIT);
+ log_debug(LD_NET,
+ "f_exit: %.2f, f_myexit: %.2f, f_myexit_unflagged: %.2f",
+ f_exit,
+ f_myexit,
+ f_myexit_unflagged);
+
/* If our ExitNodes list has eliminated every possible Exit node, and there
* were some possible Exit nodes, then instead consider nodes that permit
* exiting to some ports. */
@@ -1439,16 +1562,28 @@ compute_frac_paths_available(const networkstatus_t *consensus,
if (f_myexit < f_exit)
f_exit = f_myexit;
+ /* if the consensus has no exits, treat the exit fraction as 100% */
+ if (router_have_consensus_path() != CONSENSUS_PATH_EXIT) {
+ f_exit = 1.0;
+ }
+
+ f_path = f_guard * f_mid * f_exit;
+
if (status_out)
tor_asprintf(status_out,
"%d%% of guards bw, "
"%d%% of midpoint bw, and "
- "%d%% of exit bw",
+ "%d%% of exit bw%s = "
+ "%d%% of path bw",
(int)(f_guard*100),
(int)(f_mid*100),
- (int)(f_exit*100));
+ (int)(f_exit*100),
+ (router_have_consensus_path() == CONSENSUS_PATH_EXIT ?
+ "" :
+ " (no exits in consensus)"),
+ (int)(f_path*100));
- return f_guard * f_mid * f_exit;
+ return f_path;
}
/** We just fetched a new set of descriptors. Compute how far through
@@ -1521,6 +1656,9 @@ update_router_have_minimum_dir_info(void)
using_md = consensus->flavor == FLAV_MICRODESC;
+#define NOTICE_DIR_INFO_STATUS_INTERVAL (60)
+
+ /* Check fraction of available paths */
{
char *status = NULL;
int num_present=0, num_usable=0;
@@ -1529,16 +1667,37 @@ update_router_have_minimum_dir_info(void)
&status);
if (paths < get_frac_paths_needed_for_circs(options,consensus)) {
- tor_snprintf(dir_info_status, sizeof(dir_info_status),
- "We need more %sdescriptors: we have %d/%d, and "
- "can only build %d%% of likely paths. (We have %s.)",
- using_md?"micro":"", num_present, num_usable,
- (int)(paths*100), status);
- /* log_notice(LD_NET, "%s", dir_info_status); */
+ /* these messages can be excessive in testing networks */
+ static ratelim_t last_warned =
+ RATELIM_INIT(NOTICE_DIR_INFO_STATUS_INTERVAL);
+ char *suppression_msg = NULL;
+ if ((suppression_msg = rate_limit_log(&last_warned, time(NULL)))) {
+ tor_snprintf(dir_info_status, sizeof(dir_info_status),
+ "We need more %sdescriptors: we have %d/%d, and "
+ "can only build %d%% of likely paths. (We have %s.)",
+ using_md?"micro":"", num_present, num_usable,
+ (int)(paths*100), status);
+ log_warn(LD_NET, "%s%s", dir_info_status, suppression_msg);
+ tor_free(suppression_msg);
+ }
tor_free(status);
res = 0;
control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
goto done;
+ } else {
+ /* these messages can be excessive in testing networks */
+ static ratelim_t last_warned =
+ RATELIM_INIT(NOTICE_DIR_INFO_STATUS_INTERVAL);
+ char *suppression_msg = NULL;
+ if ((suppression_msg = rate_limit_log(&last_warned, time(NULL)))) {
+ tor_snprintf(dir_info_status, sizeof(dir_info_status),
+ "We have enough %sdescriptors: we have %d/%d, and "
+ "can build %d%% of likely paths. (We have %s.)",
+ using_md?"micro":"", num_present, num_usable,
+ (int)(paths*100), status);
+ log_info(LD_NET, "%s%s", dir_info_status, suppression_msg);
+ tor_free(suppression_msg);
+ }
}
tor_free(status);
@@ -1546,12 +1705,16 @@ update_router_have_minimum_dir_info(void)
}
done:
+
+ /* If paths have just become available in this update. */
if (res && !have_min_dir_info) {
log_notice(LD_DIR,
"We now have enough directory information to build circuits.");
control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO");
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0);
}
+
+ /* If paths have just become unavailable in this update. */
if (!res && have_min_dir_info) {
int quiet = directory_too_idle_to_fetch_descriptors(options, now);
tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
@@ -1563,7 +1726,7 @@ update_router_have_minimum_dir_info(void)
* should only do while circuits are working, like reachability tests
* and fetching bridge descriptors only over circuits. */
note_that_we_maybe_cant_complete_circuits();
-
+ have_consensus_path = CONSENSUS_PATH_UNKNOWN;
control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO");
}
have_min_dir_info = res;
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index 48b0e94be0..2e59da673e 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -79,7 +79,37 @@ int node_is_unreliable(const node_t *router, int need_uptime,
int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
int need_uptime);
void router_set_status(const char *digest, int up);
+
+/** router_have_minimum_dir_info tests to see if we have enough
+ * descriptor information to create circuits.
+ * If there are exits in the consensus, we wait until we have enough
+ * info to create exit paths before creating any circuits. If there are
+ * no exits in the consensus, we wait for enough info to create internal
+ * paths, and should avoid creating exit paths, as they will simply fail.
+ * We make sure we create all available circuit types at the same time. */
int router_have_minimum_dir_info(void);
+
+/** Set to CONSENSUS_PATH_EXIT if there is at least one exit node
+ * in the consensus. We update this flag in compute_frac_paths_available if
+ * there is at least one relay that has an Exit flag in the consensus.
+ * Used to avoid building exit circuits when they will almost certainly fail.
+ * Set to CONSENSUS_PATH_INTERNAL if there are no exits in the consensus.
+ * (This situation typically occurs during bootstrap of a test network.)
+ * Set to CONSENSUS_PATH_UNKNOWN if we have never checked, or have
+ * reason to believe our last known value was invalid or has expired.
+ */
+typedef enum {
+ /* we haven't checked yet, or we have invalidated our previous check */
+ CONSENSUS_PATH_UNKNOWN = -1,
+ /* The consensus only has internal relays, and we should only
+ * create internal paths, circuits, streams, ... */
+ CONSENSUS_PATH_INTERNAL = 0,
+ /* The consensus has at least one exit, and can therefore (potentially)
+ * create exit and internal paths, circuits, streams, ... */
+ CONSENSUS_PATH_EXIT = 1
+} consensus_path_type_t;
+consensus_path_type_t router_have_consensus_path(void);
+
void router_dir_info_changed(void);
const char *get_dir_info_status_string(void);
int count_loading_descriptors_progress(void);