diff options
-rw-r--r-- | ChangeLog | 107 | ||||
-rw-r--r-- | changes/bug13667 | 5 | ||||
-rw-r--r-- | changes/bug13808 | 9 | ||||
-rw-r--r-- | changes/bug13811 | 6 | ||||
-rw-r--r-- | changes/bug13823-decrease-consensus-interval | 8 | ||||
-rw-r--r-- | changes/bug13839-fix-TestingMinExitFlagThreshold | 7 | ||||
-rw-r--r-- | changes/bug13913 | 7 | ||||
-rw-r--r-- | changes/bug13963-decrease-if-modified-since-delay | 7 | ||||
-rw-r--r-- | changes/bug14013 | 6 | ||||
-rw-r--r-- | changes/bug14041 | 5 | ||||
-rw-r--r-- | changes/resolvemyaddr-tests | 3 | ||||
-rw-r--r-- | changes/ticket11016 | 6 | ||||
-rw-r--r-- | src/or/circuitbuild.c | 24 | ||||
-rw-r--r-- | src/or/circuituse.c | 98 | ||||
-rw-r--r-- | src/or/config.c | 2 | ||||
-rw-r--r-- | src/or/control.c | 30 | ||||
-rw-r--r-- | src/or/dirserv.c | 2 | ||||
-rw-r--r-- | src/or/nodelist.c | 231 | ||||
-rw-r--r-- | src/or/nodelist.h | 30 |
19 files changed, 442 insertions, 151 deletions
@@ -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); |