Check if there are exits in the consensus

Add router_have_consensus_path() which reports whether
the consensus has exit paths, internal paths, or whether it
just doesn't know.

Used by #13718 and #13814.
This commit is contained in:
teor 2014-12-26 00:10:40 +11:00 committed by Nick Mathewson
parent d812baf54c
commit 9b2d106e49
3 changed files with 84 additions and 3 deletions

View File

@ -0,0 +1,6 @@
o Minor enhancement:
- Check if there are exits in the consensus.
Add router_have_consensus_path() which reports whether
the consensus has exit paths, internal paths, or whether it
just doesn't know.
Used by #13718 and #13814.

View File

@ -1275,6 +1275,10 @@ 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". */
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. */
@ -1308,6 +1312,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.
@ -1396,7 +1418,11 @@ 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,
@ -1417,7 +1443,13 @@ 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, USABLE_DESCRIPTOR_EXIT_ONLY);
log_debug(LD_NET,
@ -1426,6 +1458,27 @@ compute_frac_paths_available(const networkstatus_t *consensus,
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, USABLE_DESCRIPTOR_EXIT_ONLY);
@ -1620,7 +1673,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;

View File

@ -80,6 +80,28 @@ 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);
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);