mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-24 22:58:50 +01:00
Merge branch 'vanguards-lite-dev-rebased'
This commit is contained in:
commit
4f68fe3e6c
12 changed files with 383 additions and 53 deletions
9
changes/ticket40363
Normal file
9
changes/ticket40363
Normal file
|
@ -0,0 +1,9 @@
|
|||
o Major features (Proposal 332, onion services, guard selection algorithm):
|
||||
- Clients and onion services now choose four long-lived "layer 2" guard
|
||||
relays for use as the middle hop in all onion circuits. These relays are
|
||||
kept in place for a randomized duration averaging 1 week each. This
|
||||
mitigates guard discovery attacks against clients and short-lived onion
|
||||
services such as OnionShare. Long-lived onion services that need high
|
||||
security should still use the Vanguards addon
|
||||
(https://github.com/mikeperry-tor/vanguards). Closes ticket 40363;
|
||||
implements proposal 333.
|
|
@ -1749,6 +1749,13 @@ The following options are useful only for clients (that is, if
|
|||
the guard-n-primary-guards consensus parameter, and default to 3 if the
|
||||
consensus parameter isn't set. (Default: 0)
|
||||
|
||||
[[VanguardsLiteEnabled]] **VanguardsLiteEnabled** **0**|**1**|**auto**::
|
||||
This option specifies whether clients should use the vanguards-lite
|
||||
subsystem to protect against guard discovery attacks. If it's set to
|
||||
'auto', clients will do what the vanguards-lite-enabled consensus parameter
|
||||
tells them to do, and will default to enable the subsystem if the consensus
|
||||
parameter isn't set. (Default: auto)
|
||||
|
||||
[[UseMicrodescriptors]] **UseMicrodescriptors** **0**|**1**|**auto**::
|
||||
Microdescriptors are a smaller version of the information that Tor needs
|
||||
in order to build its circuits. Using microdescriptors makes Tor clients
|
||||
|
|
|
@ -669,6 +669,7 @@ static const config_var_t option_vars_[] = {
|
|||
VAR("UseEntryGuards", BOOL, UseEntryGuards_option, "1"),
|
||||
OBSOLETE("UseEntryGuardsAsDirGuards"),
|
||||
V(UseGuardFraction, AUTOBOOL, "auto"),
|
||||
V(VanguardsLiteEnabled, AUTOBOOL, "auto"),
|
||||
V(UseMicrodescriptors, AUTOBOOL, "auto"),
|
||||
OBSOLETE("UseNTorHandshake"),
|
||||
V_IMMUTABLE(User, STRING, NULL),
|
||||
|
|
|
@ -594,6 +594,9 @@ struct or_options_t {
|
|||
* If 0, use value from NumEntryGuards. */
|
||||
int NumPrimaryGuards; /**< How many primary guards do we want? */
|
||||
|
||||
/** Boolean: Switch to toggle the vanguards-lite subsystem */
|
||||
int VanguardsLiteEnabled;
|
||||
|
||||
int RephistTrackTime; /**< How many seconds do we keep rephist info? */
|
||||
/** Should we always fetch our dir info on the mirror schedule (which
|
||||
* means directly from the authorities) no matter our other config? */
|
||||
|
|
|
@ -1293,6 +1293,7 @@ signewnym_impl(time_t now)
|
|||
circuit_mark_all_dirty_circs_as_unusable();
|
||||
addressmap_clear_transient();
|
||||
hs_client_purge_state();
|
||||
purge_vanguards_lite();
|
||||
time_of_last_signewnym = now;
|
||||
signewnym_is_pending = 0;
|
||||
|
||||
|
@ -1370,6 +1371,7 @@ CALLBACK(save_state);
|
|||
CALLBACK(write_stats_file);
|
||||
CALLBACK(control_per_second_events);
|
||||
CALLBACK(second_elapsed);
|
||||
CALLBACK(manage_vglite);
|
||||
|
||||
#undef CALLBACK
|
||||
|
||||
|
@ -1392,6 +1394,9 @@ STATIC periodic_event_item_t mainloop_periodic_events[] = {
|
|||
CALLBACK(second_elapsed, NET_PARTICIPANT,
|
||||
FL(RUN_ON_DISABLE)),
|
||||
|
||||
/* Update vanguards-lite once per hour, if we have networking */
|
||||
CALLBACK(manage_vglite, NET_PARTICIPANT, FL(NEED_NET)),
|
||||
|
||||
/* XXXX Do we have a reason to do this on a callback? Does it do any good at
|
||||
* all? For now, if we're dormant, we can let our listeners decay. */
|
||||
CALLBACK(retry_listeners, NET_PARTICIPANT, FL(NEED_NET)),
|
||||
|
@ -1662,6 +1667,21 @@ mainloop_schedule_shutdown(int delay_sec)
|
|||
mainloop_event_schedule(scheduled_shutdown_ev, &delay_tv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update vanguards-lite layer2 nodes, once every 15 minutes
|
||||
*/
|
||||
static int
|
||||
manage_vglite_callback(time_t now, const or_options_t *options)
|
||||
{
|
||||
(void)now;
|
||||
(void)options;
|
||||
#define VANGUARDS_LITE_INTERVAL (15*60)
|
||||
|
||||
maintain_layer2_guards();
|
||||
|
||||
return VANGUARDS_LITE_INTERVAL;
|
||||
}
|
||||
|
||||
/** Perform regular maintenance tasks. This function gets run once per
|
||||
* second.
|
||||
*/
|
||||
|
|
|
@ -1359,7 +1359,9 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei)
|
|||
int routelen = DEFAULT_ROUTE_LEN;
|
||||
int known_purpose = 0;
|
||||
|
||||
if (circuit_should_use_vanguards(purpose)) {
|
||||
/* If we're using L3 vanguards, we need longer paths for onion services */
|
||||
if (circuit_purpose_is_hidden_service(purpose) &&
|
||||
get_options()->HSLayer3Nodes) {
|
||||
/* Clients want an extra hop for rends to avoid linkability.
|
||||
* Services want it for intro points to avoid publishing their
|
||||
* layer3 guards. They want it for hsdir posts to use
|
||||
|
@ -1374,14 +1376,6 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei)
|
|||
purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)
|
||||
return routelen+1;
|
||||
|
||||
/* If we only have Layer2 vanguards, then we do not need
|
||||
* the extra hop for linkabilty reasons (see below).
|
||||
* This means all hops can be of the form:
|
||||
* S/C - G - L2 - M - R/HSDir/I
|
||||
*/
|
||||
if (get_options()->HSLayer2Nodes && !get_options()->HSLayer3Nodes)
|
||||
return routelen+1;
|
||||
|
||||
/* For connections to hsdirs, clients want two extra hops
|
||||
* when using layer3 guards, to avoid linkability.
|
||||
* Same goes for intro points. Note that the route len
|
||||
|
@ -1400,16 +1394,14 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei)
|
|||
return routelen;
|
||||
|
||||
switch (purpose) {
|
||||
/* These two purposes connect to a router that we chose, so
|
||||
* DEFAULT_ROUTE_LEN is safe. */
|
||||
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
|
||||
/* hidden service connecting to introduction point */
|
||||
/* These purposes connect to a router that we chose, so DEFAULT_ROUTE_LEN
|
||||
* is safe: */
|
||||
case CIRCUIT_PURPOSE_TESTING:
|
||||
/* router reachability testing */
|
||||
known_purpose = 1;
|
||||
break;
|
||||
|
||||
/* These three purposes connect to a router that someone else
|
||||
/* These purposes connect to a router that someone else
|
||||
* might have chosen, so add an extra hop to protect anonymity. */
|
||||
case CIRCUIT_PURPOSE_C_GENERAL:
|
||||
case CIRCUIT_PURPOSE_C_HSDIR_GET:
|
||||
|
@ -1419,6 +1411,9 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei)
|
|||
/* client connecting to introduction point */
|
||||
case CIRCUIT_PURPOSE_S_CONNECT_REND:
|
||||
/* hidden service connecting to rendezvous point */
|
||||
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
|
||||
/* hidden service connecting to intro point. In this case we want an extra
|
||||
hop to avoid linkability attacks by the introduction point. */
|
||||
known_purpose = 1;
|
||||
routelen++;
|
||||
break;
|
||||
|
@ -2259,8 +2254,14 @@ middle_node_must_be_vanguard(const or_options_t *options,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* If we have sticky L2 nodes, and this is an L2 pick, use vanguards */
|
||||
if (options->HSLayer2Nodes && cur_len == 1) {
|
||||
/* Don't even bother if the feature is disabled */
|
||||
if (!vanguards_lite_is_enabled()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we are a hidden service circuit, always use either vanguards-lite
|
||||
* or HSLayer2Nodes for 2nd hop. */
|
||||
if (cur_len == 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -2284,7 +2285,8 @@ pick_vanguard_middle_node(const or_options_t *options,
|
|||
|
||||
/* Pick the right routerset based on the current hop */
|
||||
if (cur_len == 1) {
|
||||
vanguard_routerset = options->HSLayer2Nodes;
|
||||
vanguard_routerset = options->HSLayer2Nodes ?
|
||||
options->HSLayer2Nodes : get_layer2_guards();
|
||||
} else if (cur_len == 2) {
|
||||
vanguard_routerset = options->HSLayer3Nodes;
|
||||
} else {
|
||||
|
@ -2293,6 +2295,10 @@ pick_vanguard_middle_node(const or_options_t *options,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (BUG(!vanguard_routerset)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = pick_restricted_middle_node(flags, vanguard_routerset,
|
||||
options->ExcludeNodes, excluded,
|
||||
cur_len+1);
|
||||
|
|
|
@ -1204,25 +1204,6 @@ needs_circuits_for_build(int num)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the appropriate type of predicted circuit for hidden
|
||||
* services, depending on our options.
|
||||
*/
|
||||
static void
|
||||
circuit_launch_predicted_hs_circ(int flags)
|
||||
{
|
||||
/* K.I.S.S. implementation of bug #23101: If we are using
|
||||
* vanguards or pinned middles, pre-build a specific purpose
|
||||
* for HS circs. */
|
||||
if (circuit_should_use_vanguards(CIRCUIT_PURPOSE_HS_VANGUARDS)) {
|
||||
circuit_launch(CIRCUIT_PURPOSE_HS_VANGUARDS, flags);
|
||||
} else {
|
||||
/* If no vanguards, then no HS-specific prebuilt circuits are needed.
|
||||
* Normal GENERAL circs are fine */
|
||||
circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/** Determine how many circuits we have open that are clean,
|
||||
* Make sure it's enough for all the upcoming behaviors we predict we'll have.
|
||||
* But put an upper bound on the total number of circuits.
|
||||
|
@ -1276,7 +1257,7 @@ circuit_predict_and_launch_new(void)
|
|||
"Have %d clean circs (%d internal), need another internal "
|
||||
"circ for my hidden service.",
|
||||
num, num_internal);
|
||||
circuit_launch_predicted_hs_circ(flags);
|
||||
circuit_launch(CIRCUIT_PURPOSE_HS_VANGUARDS, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1295,7 +1276,10 @@ circuit_predict_and_launch_new(void)
|
|||
" another hidden service circ.",
|
||||
num, num_uptime_internal, num_internal);
|
||||
|
||||
circuit_launch_predicted_hs_circ(flags);
|
||||
/* Always launch vanguards purpose circuits for HS clients,
|
||||
* for vanguards-lite. This prevents us from cannibalizing
|
||||
* to build these circuits (and thus not use vanguards). */
|
||||
circuit_launch(CIRCUIT_PURPOSE_HS_VANGUARDS, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2022,16 +2006,12 @@ circuit_is_hs_v3(const circuit_t *circ)
|
|||
int
|
||||
circuit_should_use_vanguards(uint8_t purpose)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
/* Only hidden service circuits use vanguards */
|
||||
if (!circuit_purpose_is_hidden_service(purpose))
|
||||
return 0;
|
||||
|
||||
/* Pinned middles are effectively vanguards */
|
||||
if (options->HSLayer2Nodes || options->HSLayer3Nodes)
|
||||
/* All hidden service circuits use either vanguards or
|
||||
* vanguards-lite. */
|
||||
if (circuit_purpose_is_hidden_service(purpose))
|
||||
return 1;
|
||||
|
||||
/* Everything else is a normal circuit */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2069,13 +2049,11 @@ circuit_should_cannibalize_to_build(uint8_t purpose_to_build,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* For vanguards, the server-side intro circ is not cannibalized
|
||||
* because we pre-build 4 hop HS circuits, and it only needs a 3 hop
|
||||
* circuit. It is also long-lived, so it is more important that
|
||||
* it have lower latency than get built fast.
|
||||
/* The server-side intro circ is not cannibalized because it only
|
||||
* needs a 3 hop circuit. It is also long-lived, so it is more
|
||||
* important that it have lower latency than get built fast.
|
||||
*/
|
||||
if (circuit_should_use_vanguards(purpose_to_build) &&
|
||||
purpose_to_build == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
|
||||
if (purpose_to_build == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -3930,6 +3930,253 @@ guard_selection_free_(guard_selection_t *gs)
|
|||
tor_free(gs);
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/** Layer2 guard subsystem (vanguards-lite) used for onion service circuits */
|
||||
|
||||
/** A simple representation of a layer2 guard. We just need its identity so
|
||||
* that we feed it into a routerset, and a sampled timestamp to do expiration
|
||||
* checks. */
|
||||
typedef struct layer2_guard_t {
|
||||
/** Identity of the guard */
|
||||
char identity[DIGEST_LEN];
|
||||
/** When does this guard expire? (randomized timestamp) */
|
||||
time_t expire_on_date;
|
||||
} layer2_guard_t;
|
||||
|
||||
#define layer2_guard_free(val) \
|
||||
FREE_AND_NULL(layer2_guard_t, layer2_guard_free_, (val))
|
||||
|
||||
/** Return true if the vanguards-lite subsystem is enabled */
|
||||
bool
|
||||
vanguards_lite_is_enabled(void)
|
||||
{
|
||||
/* First check torrc option and then maybe also the consensus parameter. */
|
||||
const or_options_t *options = get_options();
|
||||
|
||||
/* If the option is explicitly disabled, that's the final word here */
|
||||
if (options->VanguardsLiteEnabled == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the option is set to auto, then check the consensus parameter */
|
||||
if (options->VanguardsLiteEnabled == -1) {
|
||||
return networkstatus_get_param(NULL, "vanguards-lite-enabled",
|
||||
1, /* default to "on" */
|
||||
0, 1);
|
||||
}
|
||||
|
||||
/* else it's enabled */
|
||||
tor_assert_nonfatal(options->VanguardsLiteEnabled == 1);
|
||||
return options->VanguardsLiteEnabled;
|
||||
}
|
||||
|
||||
static void
|
||||
layer2_guard_free_(layer2_guard_t *l2)
|
||||
{
|
||||
if (!l2) {
|
||||
return;
|
||||
}
|
||||
|
||||
tor_free(l2);
|
||||
}
|
||||
|
||||
/** Global list and routerset of L2 guards. They are both synced and they get
|
||||
* updated periodically. We need both the list and the routerset: we use the
|
||||
* smartlist to keep track of expiration times and the routerset is what we
|
||||
* return to the users of this subsystem. */
|
||||
static smartlist_t *layer2_guards = NULL;
|
||||
static routerset_t *layer2_routerset = NULL;
|
||||
|
||||
/** Number of L2 guards */
|
||||
#define NUMBER_SECOND_GUARDS 4
|
||||
/** Make sure that the number of L2 guards is less than the number of
|
||||
* MAX_SANE_RESTRICTED_NODES */
|
||||
CTASSERT(NUMBER_SECOND_GUARDS < 20);
|
||||
|
||||
/** Lifetime of L2 guards:
|
||||
* 1 to 12 days, for an average of a week using the max(x,x) distribution */
|
||||
#define MIN_SECOND_GUARD_LIFETIME (3600*24)
|
||||
#define MAX_SECOND_GUARD_LIFETIME (3600*24*12)
|
||||
|
||||
/** Return the number of guards our L2 guardset should have */
|
||||
static int
|
||||
get_number_of_layer2_hs_guards(void)
|
||||
{
|
||||
return (int) networkstatus_get_param(NULL,
|
||||
"guard-hs-l2-number",
|
||||
NUMBER_SECOND_GUARDS,
|
||||
1, 19);
|
||||
}
|
||||
|
||||
/** Return the minimum lifetime of L2 guards */
|
||||
static int
|
||||
get_min_lifetime_of_layer2_hs_guards(void)
|
||||
{
|
||||
return (int) networkstatus_get_param(NULL,
|
||||
"guard-hs-l2-lifetime-min",
|
||||
MIN_SECOND_GUARD_LIFETIME,
|
||||
1, INT32_MAX);
|
||||
}
|
||||
|
||||
/** Return the maximum lifetime of L2 guards */
|
||||
static int
|
||||
get_max_lifetime_of_layer2_hs_guards(void)
|
||||
{
|
||||
return (int) networkstatus_get_param(NULL,
|
||||
"guard-hs-l2-lifetime-max",
|
||||
MAX_SECOND_GUARD_LIFETIME,
|
||||
1, INT32_MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample and return a lifetime for an L2 guard.
|
||||
*
|
||||
* Lifetime randomized uniformly between min and max consensus params.
|
||||
*/
|
||||
static int
|
||||
get_layer2_hs_guard_lifetime(void)
|
||||
{
|
||||
int min = get_min_lifetime_of_layer2_hs_guards();
|
||||
int max = get_max_lifetime_of_layer2_hs_guards();
|
||||
|
||||
if (BUG(min >= max)) {
|
||||
return min;
|
||||
}
|
||||
|
||||
return crypto_rand_int_range(min, max);
|
||||
}
|
||||
|
||||
/** Maintain the L2 guard list. Make sure the list contains enough guards, do
|
||||
* expirations as necessary, and keep all the data structures of this
|
||||
* subsystem synchronized */
|
||||
void
|
||||
maintain_layer2_guards(void)
|
||||
{
|
||||
if (!router_have_minimum_dir_info()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create the list if it doesn't exist */
|
||||
if (!layer2_guards) {
|
||||
layer2_guards = smartlist_new();
|
||||
}
|
||||
|
||||
/* Go through the list and perform any needed expirations */
|
||||
SMARTLIST_FOREACH_BEGIN(layer2_guards, layer2_guard_t *, g) {
|
||||
/* Expire based on expiration date */
|
||||
if (g->expire_on_date <= approx_time()) {
|
||||
log_info(LD_GENERAL, "Removing expired Layer2 guard %s",
|
||||
safe_str_client(hex_str(g->identity, DIGEST_LEN)));
|
||||
// Nickname may be gone from consensus and doesn't matter anyway
|
||||
control_event_guard("None", g->identity, "BAD_L2");
|
||||
layer2_guard_free(g);
|
||||
SMARTLIST_DEL_CURRENT_KEEPORDER(layer2_guards, g);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Expire if relay has left consensus */
|
||||
if (router_get_consensus_status_by_id(g->identity) == NULL) {
|
||||
log_info(LD_GENERAL, "Removing missing Layer2 guard %s",
|
||||
safe_str_client(hex_str(g->identity, DIGEST_LEN)));
|
||||
// Nickname may be gone from consensus and doesn't matter anyway
|
||||
control_event_guard("None", g->identity, "BAD_L2");
|
||||
layer2_guard_free(g);
|
||||
SMARTLIST_DEL_CURRENT_KEEPORDER(layer2_guards, g);
|
||||
continue;
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(g);
|
||||
|
||||
/* Find out how many guards we need to add */
|
||||
int new_guards_needed_n =
|
||||
get_number_of_layer2_hs_guards() - smartlist_len(layer2_guards);
|
||||
if (new_guards_needed_n <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_info(LD_GENERAL, "Adding %d guards to Layer2 routerset",
|
||||
new_guards_needed_n);
|
||||
|
||||
/* Add required guards to the list */
|
||||
smartlist_t *excluded = smartlist_new();
|
||||
for (int i = 0; i < new_guards_needed_n; i++) {
|
||||
const node_t *choice = NULL;
|
||||
const or_options_t *options = get_options();
|
||||
/* Pick Stable nodes */
|
||||
router_crn_flags_t flags = CRN_NEED_DESC|CRN_NEED_UPTIME;
|
||||
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
|
||||
if (!choice) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* We found our node: create an L2 guard out of it */
|
||||
layer2_guard_t *layer2_guard = tor_malloc_zero(sizeof(layer2_guard_t));
|
||||
memcpy(layer2_guard->identity, choice->identity, DIGEST_LEN);
|
||||
layer2_guard->expire_on_date = approx_time() +
|
||||
get_layer2_hs_guard_lifetime();
|
||||
smartlist_add(layer2_guards, layer2_guard);
|
||||
log_info(LD_GENERAL, "Adding Layer2 guard %s",
|
||||
safe_str_client(hex_str(layer2_guard->identity, DIGEST_LEN)));
|
||||
// Nickname can also be None here because it is looked up later
|
||||
control_event_guard("None", layer2_guard->identity,
|
||||
"GOOD_L2");
|
||||
/* Exclude this node and its family so that we don't double-pick. */
|
||||
nodelist_add_node_and_family(excluded, choice);
|
||||
}
|
||||
|
||||
/* Some cleanup */
|
||||
smartlist_free(excluded);
|
||||
|
||||
/* Now that the list is up to date, synchronize the routerset */
|
||||
routerset_free(layer2_routerset);
|
||||
layer2_routerset = routerset_new();
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN (layer2_guards, layer2_guard_t *, g) {
|
||||
routerset_parse(layer2_routerset,
|
||||
hex_str(g->identity, DIGEST_LEN),
|
||||
"l2 guards");
|
||||
} SMARTLIST_FOREACH_END(g);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset vanguards-lite list(s).
|
||||
*
|
||||
* Used for SIGNAL NEWNYM.
|
||||
*/
|
||||
void
|
||||
purge_vanguards_lite(void)
|
||||
{
|
||||
if (!layer2_guards)
|
||||
return;
|
||||
|
||||
/* Go through the list and perform any needed expirations */
|
||||
SMARTLIST_FOREACH_BEGIN(layer2_guards, layer2_guard_t *, g) {
|
||||
layer2_guard_free(g);
|
||||
} SMARTLIST_FOREACH_END(g);
|
||||
|
||||
smartlist_clear(layer2_guards);
|
||||
|
||||
/* Pick new l2 guards */
|
||||
maintain_layer2_guards();
|
||||
}
|
||||
|
||||
/** Return a routerset containing the L2 guards or NULL if it's not yet
|
||||
* initialized. Callers must not free the routerset. Designed for use in
|
||||
* pick_vanguard_middle_node() and should not be used anywhere else. Do not
|
||||
* store this pointer -- any future calls to maintain_layer2_guards() and
|
||||
* purge_vanguards_lite() can invalidate it. */
|
||||
const routerset_t *
|
||||
get_layer2_guards(void)
|
||||
{
|
||||
if (!layer2_guards) {
|
||||
maintain_layer2_guards();
|
||||
}
|
||||
|
||||
return layer2_routerset;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Release all storage held by the list of entry guards and related
|
||||
* memory structs. */
|
||||
void
|
||||
|
@ -3946,4 +4193,15 @@ entry_guards_free_all(void)
|
|||
guard_contexts = NULL;
|
||||
}
|
||||
circuit_build_times_free_timeouts(get_circuit_build_times_mutable());
|
||||
|
||||
if (!layer2_guards) {
|
||||
return;
|
||||
}
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(layer2_guards, layer2_guard_t *, g) {
|
||||
layer2_guard_free(g);
|
||||
} SMARTLIST_FOREACH_END(g);
|
||||
|
||||
smartlist_free(layer2_guards);
|
||||
routerset_free(layer2_routerset);
|
||||
}
|
||||
|
|
|
@ -651,4 +651,9 @@ guard_get_guardfraction_bandwidth(guardfraction_bandwidth_t *guardfraction_bw,
|
|||
int orig_bandwidth,
|
||||
uint32_t guardfraction_percentage);
|
||||
|
||||
bool vanguards_lite_is_enabled(void);
|
||||
const routerset_t *get_layer2_guards(void);
|
||||
void maintain_layer2_guards(void);
|
||||
void purge_vanguards_lite(void);
|
||||
|
||||
#endif /* !defined(TOR_ENTRYNODES_H) */
|
||||
|
|
|
@ -1699,6 +1699,9 @@ notify_after_networkstatus_changes(void)
|
|||
channelpadding_new_consensus_params(c);
|
||||
circpad_new_consensus_params(c);
|
||||
router_new_consensus_params(c);
|
||||
|
||||
/* Maintenance of our L2 guard list */
|
||||
maintain_layer2_guards();
|
||||
}
|
||||
|
||||
/** Copy all the ancillary information (like router download status and so on)
|
||||
|
|
|
@ -113,7 +113,7 @@ test_new_route_len_safe_exit(void *arg)
|
|||
/* hidden service connecting to introduction point */
|
||||
r = new_route_len(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, &dummy_ei,
|
||||
&dummy_nodes);
|
||||
tt_int_op(DEFAULT_ROUTE_LEN, OP_EQ, r);
|
||||
tt_int_op(DEFAULT_ROUTE_LEN+1, OP_EQ, r);
|
||||
|
||||
/* router testing its own reachability */
|
||||
r = new_route_len(CIRCUIT_PURPOSE_TESTING, &dummy_ei, &dummy_nodes);
|
||||
|
|
|
@ -92,6 +92,12 @@ bfn_mock_node_get_by_id(const char *id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
mock_router_have_minimum_dir_info(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Helper function to free a test node. */
|
||||
static void
|
||||
test_node_free(node_t *n)
|
||||
|
@ -3087,6 +3093,38 @@ test_entry_guard_vanguard_path_selection(void *arg)
|
|||
circuit_free_(circ);
|
||||
}
|
||||
|
||||
static void
|
||||
test_entry_guard_layer2_guards(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
MOCK(router_have_minimum_dir_info, mock_router_have_minimum_dir_info);
|
||||
|
||||
/* First check the enable/disable switch */
|
||||
get_options_mutable()->VanguardsLiteEnabled = 0;
|
||||
tt_int_op(vanguards_lite_is_enabled(), OP_EQ, 0);
|
||||
|
||||
get_options_mutable()->VanguardsLiteEnabled = 1;
|
||||
tt_int_op(vanguards_lite_is_enabled(), OP_EQ, 1);
|
||||
|
||||
get_options_mutable()->VanguardsLiteEnabled = -1;
|
||||
tt_int_op(vanguards_lite_is_enabled(), OP_EQ, 1);
|
||||
|
||||
/* OK now let's move to actual testing */
|
||||
|
||||
/* Remove restrictions to route around Big Fake Network restrictions */
|
||||
get_options_mutable()->EnforceDistinctSubnets = 0;
|
||||
|
||||
/* Create the L2 guardset */
|
||||
maintain_layer2_guards();
|
||||
|
||||
const routerset_t *l2_guards = get_layer2_guards();
|
||||
tt_assert(l2_guards);
|
||||
tt_int_op(routerset_len(l2_guards), OP_EQ, 4);
|
||||
|
||||
done:
|
||||
UNMOCK(router_have_minimum_dir_info);
|
||||
}
|
||||
|
||||
static const struct testcase_setup_t big_fake_network = {
|
||||
big_fake_network_setup, big_fake_network_cleanup
|
||||
};
|
||||
|
@ -3152,6 +3190,8 @@ struct testcase_t entrynodes_tests[] = {
|
|||
BFN_TEST(manage_primary),
|
||||
BFN_TEST(correct_cascading_order),
|
||||
|
||||
BFN_TEST(layer2_guards),
|
||||
|
||||
EN_TEST_FORK(guard_preferred),
|
||||
|
||||
BFN_TEST(select_for_circuit_no_confirmed),
|
||||
|
|
Loading…
Add table
Reference in a new issue