tor-commits
Threads by month
- ----- 2026 -----
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
December 2016
- 18 participants
- 2011 discussions
16 Dec '16
commit 404e9e5611eff39866c2e45133a60b40d7492f7e
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Mon Nov 28 07:41:45 2016 -0500
Have multiple guard contexts we can switch between.
Currently, this code doesn't actually have the contexts behave
differently, (except for the legacy context), but it does switch
back and forth between them nicely.
---
src/or/config.c | 7 --
src/or/entrynodes.c | 270 ++++++++++++++++++++++++++++++++++++++++-----
src/or/entrynodes.h | 50 +++++++--
src/or/main.c | 7 +-
src/test/test_entrynodes.c | 59 +++++-----
5 files changed, 321 insertions(+), 72 deletions(-)
diff --git a/src/or/config.c b/src/or/config.c
index b7b5cff..22e5dfd 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -4536,13 +4536,6 @@ options_transition_allowed(const or_options_t *old,
return -1;
}
- if (old->UseDeprecatedGuardAlgorithm !=
- new_val->UseDeprecatedGuardAlgorithm) {
- *msg = tor_strdup("While Tor is running, changing "
- "UseDeprecatedGuardAlgorithm is not allowed.");
- return -1;
- }
-
if (sandbox_is_active()) {
#define SB_NOCHANGE_STR(opt) \
do { \
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 6f6853e..59205a8 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -159,6 +159,10 @@ static void entry_guard_set_filtered_flags(const or_options_t *options,
entry_guard_t *guard);
static void pathbias_check_use_success_count(entry_guard_t *guard);
static void pathbias_check_close_success_count(entry_guard_t *guard);
+static int node_is_possible_guard(guard_selection_t *gs, const node_t *node);
+static int node_passes_guard_filter(const or_options_t *options,
+ guard_selection_t *gs,
+ const node_t *node);
/** Return 0 if we should apply guardfraction information found in the
* consensus. A specific consensus can be specified with the
@@ -186,12 +190,25 @@ should_apply_guardfraction(const networkstatus_t *ns)
* Allocate and return a new guard_selection_t, with the name <b>name</b>.
*/
STATIC guard_selection_t *
-guard_selection_new(const char *name)
+guard_selection_new(const char *name,
+ guard_selection_type_t type)
{
guard_selection_t *gs;
+ if (type == GS_TYPE_INFER) {
+ if (!strcmp(name, "legacy"))
+ type = GS_TYPE_LEGACY;
+ else if (!strcmp(name, "bridges"))
+ type = GS_TYPE_BRIDGE;
+ else if (!strcmp(name, "restricted"))
+ type = GS_TYPE_RESTRICTED;
+ else
+ type = GS_TYPE_NORMAL;
+ }
+
gs = tor_malloc_zero(sizeof(*gs));
gs->name = tor_strdup(name);
+ gs->type = type;
gs->chosen_entry_guards = smartlist_new();
gs->sampled_entry_guards = smartlist_new();
gs->confirmed_entry_guards = smartlist_new();
@@ -206,7 +223,9 @@ guard_selection_new(const char *name)
* is none, and <b>create_if_absent</b> is false, then return NULL.
*/
STATIC guard_selection_t *
-get_guard_selection_by_name(const char *name, int create_if_absent)
+get_guard_selection_by_name(const char *name,
+ guard_selection_type_t type,
+ int create_if_absent)
{
if (!guard_contexts) {
guard_contexts = smartlist_new();
@@ -219,31 +238,42 @@ get_guard_selection_by_name(const char *name, int create_if_absent)
if (! create_if_absent)
return NULL;
- guard_selection_t *new_selection = guard_selection_new(name);
+ log_debug(LD_GUARD, "Creating a guard selection called %s", name);
+ guard_selection_t *new_selection = guard_selection_new(name, type);
smartlist_add(guard_contexts, new_selection);
- const char *default_name = get_options()->UseDeprecatedGuardAlgorithm ?
- "legacy" : "default";
-
- if (!strcmp(name, default_name))
- curr_guard_context = new_selection;
-
return new_selection;
}
-/** Get current default guard_selection_t, creating it if necessary */
-guard_selection_t *
-get_guard_selection_info(void)
+/**
+ * Allocate the first guard context that we're planning to use,
+ * and make it the current context.
+ */
+static void
+create_initial_guard_context(void)
{
+ tor_assert(! curr_guard_context);
if (!guard_contexts) {
guard_contexts = smartlist_new();
}
+ guard_selection_type_t type = GS_TYPE_INFER;
+ const char *name = choose_guard_selection(
+ get_options(),
+ networkstatus_get_live_consensus(approx_time()),
+ NULL,
+ &type);
+ tor_assert(name); // "name" can only be NULL if we had an old name.
+ tor_assert(type != GS_TYPE_INFER);
+ log_notice(LD_GUARD, "Starting with guard context \"%s\"", name);
+ curr_guard_context = get_guard_selection_by_name_and_type(name, type);
+}
+/** Get current default guard_selection_t, creating it if necessary */
+guard_selection_t *
+get_guard_selection_info(void)
+{
if (!curr_guard_context) {
- const char *name = get_options()->UseDeprecatedGuardAlgorithm ?
- "legacy" : "default";
- curr_guard_context = guard_selection_new(name);
- smartlist_add(guard_contexts, curr_guard_context);
+ create_initial_guard_context();
}
return curr_guard_context;
@@ -431,11 +461,185 @@ get_nonprimary_guard_idle_timeout(void)
{
return networkstatus_get_param(NULL,
"guard-nonprimary-guard-idle-timeout",
- (10*60), 1, INT32_MAX);
+ DFLT_NONPRIMARY_GUARD_IDLE_TIMEOUT,
+ 1, INT32_MAX);
+}
+/**
+ * If our configuration retains fewer than this fraction of guards from the
+ * torrc, we are in a restricted setting.
+ */
+STATIC double
+get_meaningful_restriction_threshold(void)
+{
+ int32_t pct = networkstatus_get_param(NULL,
+ "guard-meaningful-restriction-percent",
+ DFLT_MEANINGFUL_RESTRICTION_PERCENT,
+ 1, INT32_MAX);
+ return pct / 100.0;
+}
+/**
+ * If our configuration retains fewer than this fraction of guards from the
+ * torrc, we are in an extremely restricted setting, and should warn.
+ */
+STATIC double
+get_extreme_restriction_threshold(void)
+{
+ int32_t pct = networkstatus_get_param(NULL,
+ "guard-extreme-restriction-percent",
+ DFLT_EXTREME_RESTRICTION_PERCENT,
+ 1, INT32_MAX);
+ return pct / 100.0;
}
/**@}*/
/**
+ * Given our options and our list of nodes, return the name of the
+ * guard selection that we should use. Return NULL for "use the
+ * same selection you were using before.
+ */
+STATIC const char *
+choose_guard_selection(const or_options_t *options,
+ const networkstatus_t *live_ns,
+ const char *old_selection,
+ guard_selection_type_t *type_out)
+{
+ tor_assert(options);
+ tor_assert(type_out);
+ if (options->UseDeprecatedGuardAlgorithm) {
+ *type_out = GS_TYPE_LEGACY;
+ return "legacy";
+ }
+
+ if (options->UseBridges) {
+ *type_out = GS_TYPE_BRIDGE;
+ return "bridges";
+ }
+
+ if (! live_ns) {
+ /* without a networkstatus, we can't tell any more than that. */
+ *type_out = GS_TYPE_NORMAL;
+ return "default";
+ }
+
+ const smartlist_t *nodes = nodelist_get_list();
+ int n_guards = 0, n_passing_filter = 0;
+ SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) {
+ if (node_is_possible_guard(NULL, node)) {
+ ++n_guards;
+ if (node_passes_guard_filter(options, NULL, node)) {
+ ++n_passing_filter;
+ }
+ }
+ } SMARTLIST_FOREACH_END(node);
+
+ /* XXXX prop271 spec deviation -- separate 'high' and 'low' thresholds
+ * to prevent flapping */
+ const int meaningful_threshold_high =
+ (int)(n_guards * get_meaningful_restriction_threshold() * 1.05);
+ const int meaningful_threshold_mid =
+ (int)(n_guards * get_meaningful_restriction_threshold());
+ const int meaningful_threshold_low =
+ (int)(n_guards * get_meaningful_restriction_threshold() * .95);
+ const int extreme_threshold =
+ (int)(n_guards * get_extreme_restriction_threshold());
+
+ /*
+ If we have no previous selection, then we're "restricted" iff we are
+ below the meaningful restriction threshold. That's easy enough.
+
+ But if we _do_ have a previous selection, we make it a little
+ "sticky": we only move from "restricted" to "default" when we find
+ that we're above the threshold plus 5%, and we only move from
+ "default" to "restricted" when we're below the threshold minus 5%.
+ That should prevent us from flapping back and forth if we happen to
+ be hovering very close to the default.
+
+ The extreme threshold is for warning only.
+ */
+
+ static int have_warned_extreme_threshold = 0;
+ if (n_passing_filter < extreme_threshold &&
+ ! have_warned_extreme_threshold) {
+ have_warned_extreme_threshold = 1;
+ const double exclude_frac =
+ (n_guards - n_passing_filter) / (double)n_guards;
+ log_warn(LD_GUARD, "Your configuration excludes %d%% of all possible "
+ "guards. That's likely to make you stand out from the "
+ "rest of the world.", (int)(exclude_frac * 100));
+ }
+
+ /* Easy case: no previous selection */
+ if (old_selection == NULL) {
+ if (n_passing_filter >= meaningful_threshold_mid) {
+ *type_out = GS_TYPE_NORMAL;
+ return "default";
+ } else {
+ *type_out = GS_TYPE_RESTRICTED;
+ return "restricted";
+ }
+ }
+
+ /* Trickier case: we do have a previous selection */
+ if (n_passing_filter >= meaningful_threshold_high) {
+ *type_out = GS_TYPE_NORMAL;
+ return "default";
+ } else if (n_passing_filter < meaningful_threshold_low) {
+ *type_out = GS_TYPE_RESTRICTED;
+ return "restricted";
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * Check whether we should switch from our current guard selection to a
+ * different one. If so, switch and return 1. Return 0 otherwise.
+ *
+ * On a 1 return, the caller should mark all currently live circuits
+ * unusable for new streams.
+ */
+int
+update_guard_selection_choice(const or_options_t *options)
+{
+ if (!curr_guard_context) {
+ create_initial_guard_context();
+ return 1;
+ }
+
+ const char *cur_name = curr_guard_context->name;
+ guard_selection_type_t type = GS_TYPE_INFER;
+ const char *new_name = choose_guard_selection(
+ options,
+ networkstatus_get_live_consensus(approx_time()),
+ cur_name,
+ &type);
+ tor_assert(new_name);
+ tor_assert(type != GS_TYPE_INFER);
+
+ if (! strcmp(cur_name, new_name)) {
+ log_debug(LD_GUARD,
+ "Staying with guard context \"%s\" (no change)", new_name);
+ return 0; // No change
+ }
+
+ log_notice(LD_GUARD, "Switching to guard context \"%s\" (was using \"%s\")",
+ new_name, cur_name);
+ guard_selection_t *new_guard_context;
+ new_guard_context = get_guard_selection_by_name(new_name, type, 1);
+ tor_assert(new_guard_context);
+ tor_assert(new_guard_context != curr_guard_context);
+ curr_guard_context = new_guard_context;
+
+ /*
+ Be sure to call:
+ circuit_mark_all_unused_circs();
+ circuit_mark_all_dirty_circs_as_unusable();
+ */
+
+ return 1;
+}
+
+/**
* Return true iff <b>node</b> has all the flags needed for us to consider it
* a possible guard when sampling guards.
*/
@@ -446,7 +650,7 @@ node_is_possible_guard(guard_selection_t *gs, const node_t *node)
* holds. */
/* XXXX -- prop271 spec deviation. We require node_is_dir() here. */
- (void)gs;
+ (void)gs; /* Remove this argument */
tor_assert(node);
return (node->is_possible_guard &&
node->is_stable &&
@@ -552,7 +756,7 @@ entry_guards_expand_sample(guard_selection_t *gs)
int n_sampled = smartlist_len(gs->sampled_entry_guards);
entry_guard_t *added_guard = NULL;
- smartlist_t *nodes = nodelist_get_list();
+ const smartlist_t *nodes = nodelist_get_list();
/* Construct eligible_guards as GUARDS - SAMPLED_GUARDS */
smartlist_t *eligible_guards = smartlist_new();
int n_guards = 0; // total size of "GUARDS"
@@ -565,13 +769,13 @@ entry_guards_expand_sample(guard_selection_t *gs)
digestset_add(sampled_guard_ids, guard->identity);
} SMARTLIST_FOREACH_END(guard);
- SMARTLIST_FOREACH_BEGIN(nodes, node_t *, node) {
+ SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) {
if (! node_is_possible_guard(gs, node))
continue;
++n_guards;
if (digestset_contains(sampled_guard_ids, node->identity))
continue;
- smartlist_add(eligible_guards, node);
+ smartlist_add(eligible_guards, (node_t*)node);
} SMARTLIST_FOREACH_END(node);
/* Now we can free that bloom filter. */
@@ -817,6 +1021,8 @@ static int
node_passes_guard_filter(const or_options_t *options, guard_selection_t *gs,
const node_t *node)
{
+ /* XXXX prop271 remote the gs option; it is unused, and sometimes NULL. */
+
/* NOTE: Make sure that this function stays in sync with
* options_transition_affects_entry_guards */
@@ -2221,7 +2427,8 @@ entry_guards_load_guards_from_state(or_state_t *state, int set)
if (set) {
guard_selection_t *gs;
- gs = get_guard_selection_by_name(guard->selection_name, 1);
+ gs = get_guard_selection_by_name(guard->selection_name,
+ GS_TYPE_INFER, 1);
tor_assert(gs);
smartlist_add(gs->sampled_entry_guards, guard);
} else {
@@ -3854,7 +4061,7 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
int r1 = entry_guards_load_guards_from_state(state, set);
int r2 = entry_guards_parse_state_for_guard_selection(
- get_guard_selection_by_name("legacy", 1),
+ get_guard_selection_by_name("legacy", GS_TYPE_LEGACY, 1),
state, set, msg);
entry_guards_dirty = 0;
@@ -3926,7 +4133,8 @@ entry_guards_update_state(or_state_t *state)
entry_guards_dirty = 0;
- guard_selection_t *gs = get_guard_selection_by_name("legacy", 0);
+ guard_selection_t *gs;
+ gs = get_guard_selection_by_name("legacy", GS_TYPE_LEGACY, 0);
if (!gs)
return; // nothign to save.
tor_assert(gs->chosen_entry_guards != NULL);
@@ -4212,12 +4420,20 @@ entries_retry_all(const or_options_t *options)
int
guards_update_all(void)
{
- if (get_options()->UseDeprecatedGuardAlgorithm) {
+ int mark_circuits = 0;
+ if (update_guard_selection_choice(get_options()))
+ mark_circuits = 1;
+
+ tor_assert(curr_guard_context);
+
+ if (curr_guard_context->type == GS_TYPE_LEGACY) {
entry_guards_compute_status(get_options(), approx_time());
- return 0;
} else {
- return entry_guards_update_all(get_guard_selection_info());
+ if (entry_guards_update_all(get_guard_selection_info()))
+ mark_circuits = 1;
}
+
+ return mark_circuits;
}
/** Helper: pick a guard for a circuit, with whatever algorithm is
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index a0f4c2e..0164667 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -195,6 +195,26 @@ struct entry_guard_t {
};
/**
+ * Possible rules for a guard selection to follow
+ */
+typedef enum guard_selection_type_t {
+ /** Infer the type of this selection from its name. */
+ GS_TYPE_INFER=0,
+ /** Use the normal guard selection algorithm, taking our sample from the
+ * complete list of guards in the consensus. */
+ GS_TYPE_NORMAL=1,
+ /** Use the normal guard selection algorithm, taking our sample from the
+ * configured bridges, and allowing it to grow as large as all the configured
+ * bridges */
+ GS_TYPE_BRIDGE,
+ /** Use the normal guard selection algorithm, taking our sample from the
+ * set of filtered nodes. */
+ GS_TYPE_RESTRICTED,
+ /** Use the legacy (pre-prop271) guard selection algorithm and fields */
+ GS_TYPE_LEGACY,
+} guard_selection_type_t;
+
+/**
* All of the the context for guard selection on a particular client.
*
* (XXXX prop271 this paragraph below is not actually implemented yet.)
@@ -213,6 +233,11 @@ struct guard_selection_s {
char *name;
/**
+ * What rules does this guard-selection object follow?
+ */
+ guard_selection_type_t type;
+
+ /**
* A value of 1 means that primary_entry_guards is up-to-date; 0
* means we need to recalculate it before using primary_entry_guards
* or the is_primary flag on any guard.
@@ -340,6 +365,8 @@ int entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
int entry_guard_state_should_expire(circuit_guard_state_t *guard_state);
void entry_guards_note_internet_connectivity(guard_selection_t *gs);
+int update_guard_selection_choice(const or_options_t *options);
+
/* Used by bridges.c only. */
void add_bridge_as_entry_guard(guard_selection_t *gs,
const node_t *chosen);
@@ -396,15 +423,17 @@ int num_bridges_usable(void);
* If a circuit has been sitting around in 'waiting for better guard' state
* for at least this long, we'll expire it.
*/
-#define DLFT_NONPRIMARY_GUARD_IDLE_TIMEOUT (10*60)
+#define DFLT_NONPRIMARY_GUARD_IDLE_TIMEOUT (10*60)
/**
- * DOCDOC. not yet used; see prop271.
+ * If our configuration retains fewer than this fraction of guards from the
+ * torrc, we are in a restricted setting.
*/
-#define DFLT_MEANINGFUL_RESTRICTION_FRAC 0.2
+#define DFLT_MEANINGFUL_RESTRICTION_PERCENT 20
/**
- * DOCDOC. not yet used. see prop271.
+ * If our configuration retains fewer than this fraction of guards from the
+ * torrc, we are in an extremely restricted setting, and should warn.
*/
-#define DFLT_EXTREME_RESTRICTION_FRAC 0.01
+#define DFLT_EXTREME_RESTRICTION_PERCENT 1
/**@}*/
STATIC double get_max_sample_threshold(void);
@@ -416,13 +445,20 @@ STATIC int get_n_primary_guards(void);
STATIC int get_internet_likely_down_interval(void);
STATIC int get_nonprimary_guard_connect_timeout(void);
STATIC int get_nonprimary_guard_idle_timeout(void);
+STATIC double get_meaningful_restriction_threshold(void);
+STATIC double get_extreme_restriction_threshold(void);
// ---------- XXXX these functions and definitions are post-prop271.
HANDLE_DECL(entry_guard, entry_guard_t, STATIC)
-STATIC guard_selection_t *guard_selection_new(const char *name);
+STATIC guard_selection_t *guard_selection_new(const char *name,
+ guard_selection_type_t type);
STATIC guard_selection_t *get_guard_selection_by_name(
- const char *name, int create_if_absent);
+ const char *name, guard_selection_type_t type, int create_if_absent);
STATIC void guard_selection_free(guard_selection_t *gs);
+STATIC const char *choose_guard_selection(const or_options_t *options,
+ const networkstatus_t *ns,
+ const char *old_selection,
+ guard_selection_type_t *type_out);
STATIC entry_guard_t *get_sampled_guard_with_id(guard_selection_t *gs,
const uint8_t *rsa_id);
diff --git a/src/or/main.c b/src/or/main.c
index 96ff442..25f8b12 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -980,8 +980,11 @@ directory_info_has_arrived(time_t now, int from_cache, int suppress_logs)
/* if we have enough dir info, then update our guard status with
* whatever we just learned. */
int invalidate_circs = guards_update_all();
- // This shouldn't be able to occur at this point.
- tor_assert_nonfatal(! invalidate_circs);
+
+ if (invalidate_circs) {
+ circuit_mark_all_unused_circs();
+ circuit_mark_all_dirty_circs_as_unusable();
+ }
/* Don't even bother trying to get extrainfo until the rest of our
* directory info is up-to-date */
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index eaaadce..4595e5d 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -1243,30 +1243,30 @@ test_entry_guard_get_guard_selection_by_name(void *arg)
(void)arg;
guard_selection_t *gs1, *gs2, *gs3;
- gs1 = get_guard_selection_by_name("unlikely", 0);
+ gs1 = get_guard_selection_by_name("unlikely", GS_TYPE_NORMAL, 0);
tt_assert(gs1 == NULL);
- gs1 = get_guard_selection_by_name("unlikely", 1);
+ gs1 = get_guard_selection_by_name("unlikely", GS_TYPE_NORMAL, 1);
tt_assert(gs1 != NULL);
- gs2 = get_guard_selection_by_name("unlikely", 1);
+ gs2 = get_guard_selection_by_name("unlikely", GS_TYPE_NORMAL, 1);
tt_assert(gs2 == gs1);
- gs2 = get_guard_selection_by_name("unlikely", 0);
+ gs2 = get_guard_selection_by_name("unlikely", GS_TYPE_NORMAL, 0);
tt_assert(gs2 == gs1);
- gs2 = get_guard_selection_by_name("implausible", 0);
+ gs2 = get_guard_selection_by_name("implausible", GS_TYPE_NORMAL, 0);
tt_assert(gs2 == NULL);
- gs2 = get_guard_selection_by_name("implausible", 1);
+ gs2 = get_guard_selection_by_name("implausible", GS_TYPE_NORMAL, 1);
tt_assert(gs2 != NULL);
tt_assert(gs2 != gs1);
- gs3 = get_guard_selection_by_name("implausible", 0);
+ gs3 = get_guard_selection_by_name("implausible", GS_TYPE_NORMAL, 0);
tt_assert(gs3 == gs2);
- gs3 = get_guard_selection_by_name("default", 0);
+ gs3 = get_guard_selection_by_name("default", GS_TYPE_NORMAL, 0);
tt_assert(gs3 == NULL);
- gs3 = get_guard_selection_by_name("default", 1);
+ gs3 = get_guard_selection_by_name("default", GS_TYPE_NORMAL, 1);
tt_assert(gs3 != NULL);
tt_assert(gs3 != gs2);
tt_assert(gs3 != gs1);
- tt_assert(gs3 == get_guard_selection_info());
+ // XXXX prop271 re-enable this. tt_assert(gs3 == get_guard_selection_info());
#if 0
or_options_t *options = get_options_mutable();
@@ -1287,7 +1287,7 @@ static void
test_entry_guard_add_single_guard(void *arg)
{
(void)arg;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
/* 1: Add a single guard to the sample. */
node_t *n1 = smartlist_get(big_fake_net_nodes, 0);
@@ -1327,7 +1327,7 @@ static void
test_entry_guard_node_filter(void *arg)
{
(void)arg;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
bridge_line_t *bl = NULL;
/* Initialize a bunch of node objects that are all guards. */
@@ -1416,7 +1416,7 @@ static void
test_entry_guard_expand_sample(void *arg)
{
(void)arg;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
digestmap_t *node_by_id = digestmap_new();
entry_guard_t *guard = entry_guards_expand_sample(gs);
@@ -1510,7 +1510,7 @@ static void
test_entry_guard_expand_sample_small_net(void *arg)
{
(void)arg;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
/* Fun corner case: not enough guards to make up our whole sample size. */
SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n, {
@@ -1543,7 +1543,7 @@ test_entry_guard_update_from_consensus_status(void *arg)
(void)arg;
int i;
time_t start = approx_time();
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
networkstatus_t *ns_tmp = NULL;
/* Don't randomly backdate stuff; it will make correctness harder to check.*/
@@ -1648,7 +1648,7 @@ test_entry_guard_update_from_consensus_repair(void *arg)
(void)arg;
int i;
time_t start = approx_time();
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
/* Don't randomly backdate stuff; it will make correctness harder to check.*/
MOCK(randomize_time, mock_randomize_time_no_randomization);
@@ -1711,7 +1711,7 @@ test_entry_guard_update_from_consensus_remove(void *arg)
(void)arg;
//int i;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
smartlist_t *keep_ids = smartlist_new();
smartlist_t *remove_ids = smartlist_new();
@@ -1809,7 +1809,7 @@ test_entry_guard_confirming_guards(void *arg)
(void)arg;
/* Now let's check the logic responsible for manipulating the list
* of confirmed guards */
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
MOCK(randomize_time, mock_randomize_time_no_randomization);
/* Create the sample. */
@@ -1879,7 +1879,7 @@ static void
test_entry_guard_sample_reachable_filtered(void *arg)
{
(void)arg;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
entry_guards_expand_sample(gs);
const int N = 10000;
bitarray_t *selected = NULL;
@@ -1950,7 +1950,7 @@ static void
test_entry_guard_sample_reachable_filtered_empty(void *arg)
{
(void)arg;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
/* What if we try to sample from a set of 0? */
SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n,
n->is_possible_guard = 0);
@@ -1966,7 +1966,7 @@ static void
test_entry_guard_retry_unreachable(void *arg)
{
(void)arg;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
entry_guards_expand_sample(gs);
/* Let's say that we have two guards, and they're down.
@@ -2025,7 +2025,7 @@ static void
test_entry_guard_manage_primary(void *arg)
{
(void)arg;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
smartlist_t *prev_guards = smartlist_new();
/* If no guards are confirmed, we should pick a few reachable guards and
@@ -2146,7 +2146,7 @@ test_entry_guard_select_for_circuit_no_confirmed(void *arg)
{
/* Simpler cases: no gaurds are confirmed yet. */
(void)arg;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
/* simple starting configuration */
entry_guards_update_primary(gs);
@@ -2230,7 +2230,7 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
guards, we use a confirmed guard. */
(void)arg;
int i;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
const int N_CONFIRMED = 10;
/* slightly more complicated simple starting configuration */
@@ -2307,7 +2307,7 @@ test_entry_guard_select_for_circuit_highlevel_primary(void *arg)
/* Play around with selecting primary guards for circuits and markign
* them up and down */
(void)arg;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
time_t start = approx_time();
@@ -2426,7 +2426,7 @@ test_entry_guard_select_for_circuit_highlevel_confirm_other(void *arg)
* primary, and we should get it next time. */
time_t start = approx_time();
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
circuit_guard_state_t *guard = NULL;
int i, r;
const node_t *node = NULL;
@@ -2488,7 +2488,7 @@ test_entry_guard_select_for_circuit_highlevel_primary_retry(void *arg)
* primary, and we should get it next time. */
time_t start = approx_time();
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
circuit_guard_state_t *guard = NULL, *guard2 = NULL;
int i, r;
const node_t *node = NULL;
@@ -2566,7 +2566,7 @@ test_entry_guard_select_and_cancel(void *arg)
int i,r;
const node_t *node = NULL;
circuit_guard_state_t *guard;
- guard_selection_t *gs = guard_selection_new("default");
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
entry_guard_t *g;
/* Once more, we mark all the primary guards down. */
@@ -2624,7 +2624,8 @@ static void *
upgrade_circuits_setup(const struct testcase_t *testcase)
{
upgrade_circuits_data_t *data = tor_malloc_zero(sizeof(*data));
- guard_selection_t *gs = data->gs = guard_selection_new("default");
+ guard_selection_t *gs = data->gs =
+ guard_selection_new("default", GS_TYPE_NORMAL);
circuit_guard_state_t *guard;
const node_t *node;
entry_guard_t *g;
1
0
16 Dec '16
commit 46619ec9143450b181a8510011d3e3fd92542aa4
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Nov 29 11:34:37 2016 -0500
Note some large functions that could be split.
George Kadianakis pointed these out.
---
src/or/entrynodes.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 004081e..af1869f 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -1099,6 +1099,7 @@ entry_guard_is_listed(guard_selection_t *gs, const entry_guard_t *guard)
STATIC void
sampled_guards_update_from_consensus(guard_selection_t *gs)
{
+ /*XXXX prop271 consider splitting this function up. */
tor_assert(gs);
const int REMOVE_UNLISTED_GUARDS_AFTER =
(get_remove_unlisted_guards_after_days() * 86400);
@@ -1503,6 +1504,7 @@ make_guard_confirmed(guard_selection_t *gs, entry_guard_t *guard)
STATIC void
entry_guards_update_primary(guard_selection_t *gs)
{
+ /*XXXX prop271 consider splitting this function up. */
tor_assert(gs);
// prevent recursion. Recursion is potentially very bad here.
@@ -1697,6 +1699,7 @@ entry_guards_note_internet_connectivity(guard_selection_t *gs)
STATIC entry_guard_t *
select_entry_guard_for_circuit(guard_selection_t *gs, unsigned *state_out)
{
+ /*XXXX prop271 consider splitting this function up. */
tor_assert(gs);
tor_assert(state_out);
1
0
[tor/master] More progress on bridge implementation with prop271 guards
by nickm@torproject.org 16 Dec '16
by nickm@torproject.org 16 Dec '16
16 Dec '16
commit 3bcbbea350ccab4bc25b191fcce1dd3fc63775d3
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Nov 29 11:26:55 2016 -0500
More progress on bridge implementation with prop271 guards
Here we handle most (all?) of the remaining tasks, and fix some
bugs, in the prop271 bridge implementation.
* We record bridge identities as we learn them.
* We only call deprecated functions from bridges.c when the
deprecated guard algorithm is in use.
* We update any_bridge_descriptors_known() and
num_bridges_usable() to work correctly with the new backend
code. (Previously, they called into the guard selection logic.
* We update bridge directory fetches to work with the new
guard code.
* We remove some erroneous assertions where we assumed that we'd
never load a guard that wasn't for the current selection.
Also, we fix a couple of typos.
---
src/or/bridges.c | 34 ++++++++++++++++++++++++++--------
src/or/directory.c | 29 +++++++++++++++++++----------
src/or/entrynodes.c | 38 ++++++++++++++++++++++++++------------
3 files changed, 71 insertions(+), 30 deletions(-)
diff --git a/src/or/bridges.c b/src/or/bridges.c
index 8090bae..c480e3f 100644
--- a/src/or/bridges.c
+++ b/src/or/bridges.c
@@ -279,7 +279,8 @@ learned_router_identity(const tor_addr_t *addr, uint16_t port,
hex_str(digest, DIGEST_LEN), fmt_addrport(addr, port),
transport_info ? transport_info : "");
tor_free(transport_info);
- // XXXX prop271 here. we will need to update the guard info too.
+ entry_guard_learned_bridge_identity(&bridge->addrport_configured,
+ (const uint8_t *)digest);
}
}
@@ -741,16 +742,21 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
fmt_and_decorate_addr(&bridge->addr),
(int) bridge->port);
}
- // XXXX prop271 here we will need to update the guard info too.
- add_bridge_as_entry_guard(get_guard_selection_info(), node);
+ if (get_options()->UseDeprecatedGuardAlgorithm) {
+ add_bridge_as_entry_guard(get_guard_selection_info(), node);
+ } else {
+ entry_guard_learned_bridge_identity(&bridge->addrport_configured,
+ (const uint8_t*)ri->cache_info.identity_digest);
+ }
log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname,
from_cache ? "cached" : "fresh", router_describe(ri));
/* set entry->made_contact so if it goes down we don't drop it from
* our entry node list */
- // XXXX prop271 use new interface here when we hit bridges?
- entry_guard_register_connect_status(ri->cache_info.identity_digest,
- 1, 0, now);
+ if (get_options()->UseDeprecatedGuardAlgorithm) {
+ entry_guard_register_connect_status(ri->cache_info.identity_digest,
+ 1, 0, now);
+ }
if (first) {
routerlist_retry_directory_downloads(now);
}
@@ -768,8 +774,20 @@ int
any_bridge_descriptors_known(void)
{
tor_assert(get_options()->UseBridges);
- // XXXX prop271 this needs to get fixed. -- bridges
- return choose_random_entry(NULL) != NULL;
+
+ if (!bridge_list)
+ return 0;
+
+ SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge) {
+ const node_t *node;
+ if (!tor_digest_is_zero(bridge->identity) &&
+ (node = node_get_by_id(bridge->identity)) != NULL &&
+ node->ri) {
+ return 1;
+ }
+ } SMARTLIST_FOREACH_END(bridge);
+
+ return 0;
}
/** Return a smartlist containing all bridge identity digests */
diff --git a/src/or/directory.c b/src/or/directory.c
index 6fc8809..9c039a0 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -560,26 +560,35 @@ MOCK_IMPL(void, directory_get_from_dirserver, (
* sort of dir fetch we'll be doing, so it won't return a bridge
* that can't answer our question.
*/
- // XXXX prop271 update this for bridge support.
- const node_t *node = choose_random_dirguard(type);
+ const node_t *node = guards_choose_dirguard(type,
+ &guard_state);
if (node && node->ri) {
/* every bridge has a routerinfo. */
routerinfo_t *ri = node->ri;
/* clients always make OR connections to bridges */
tor_addr_port_t or_ap;
+ tor_addr_port_t nil_dir_ap;
/* we are willing to use a non-preferred address if we need to */
fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0,
&or_ap);
- directory_initiate_command(&or_ap.addr, or_ap.port,
- NULL, 0, /*no dirport*/
- ri->cache_info.identity_digest,
- dir_purpose,
- router_purpose,
- DIRIND_ONEHOP,
- resource, NULL, 0, if_modified_since);
- } else
+ tor_addr_make_null(&nil_dir_ap.addr, AF_INET);
+ nil_dir_ap.port = 0;
+ directory_initiate_command_rend(&or_ap,
+ &nil_dir_ap,
+ ri->cache_info.identity_digest,
+ dir_purpose,
+ router_purpose,
+ DIRIND_ONEHOP,
+ resource, NULL, 0, if_modified_since,
+ NULL, guard_state);
+ } else {
+ if (guard_state) {
+ entry_guard_cancel(&guard_state);
+ }
log_notice(LD_DIR, "Ignoring directory request, since no bridge "
"nodes are available yet.");
+ }
+
return;
} else {
if (prefer_authority || (type & BRIDGE_DIRINFO)) {
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 6ac3166..004081e 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -271,7 +271,7 @@ create_initial_guard_context(void)
tor_assert(name); // "name" can only be NULL if we had an old name.
tor_assert(type != GS_TYPE_INFER);
log_notice(LD_GUARD, "Starting with guard context \"%s\"", name);
- curr_guard_context = get_guard_selection_by_name_and_type(name, type);
+ curr_guard_context = get_guard_selection_by_name(name, type, 1);
}
/** Get current default guard_selection_t, creating it if necessary */
@@ -1234,13 +1234,10 @@ node_passes_guard_filter(const or_options_t *options, guard_selection_t *gs,
const node_t *node)
{
/* XXXX prop271 remote the gs option; it is unused, and sometimes NULL. */
+ (void)gs;
/* NOTE: Make sure that this function stays in sync with
* options_transition_affects_entry_guards */
-
- tor_assert(! options->UseBridges);
-
- (void)gs;
if (routerset_contains_node(options->ExcludeNodes, node))
return 0;
@@ -1265,7 +1262,6 @@ static int
bridge_passes_guard_filter(const or_options_t *options,
const bridge_info_t *bridge)
{
- tor_assert(options->UseBridges);
tor_assert(bridge);
if (!bridge)
return 0;
@@ -1765,7 +1761,7 @@ select_entry_guard_for_circuit(guard_selection_t *gs, unsigned *state_out)
/**
* Note that we failed to connect to or build circuits through <b>guard</b>.
- * Use with a guard returned by select_entry_guards_for_circuit().
+ * Use with a guard returned by select_entry_guard_for_circuit().
*/
STATIC void
entry_guards_note_guard_failure(guard_selection_t *gs,
@@ -3818,12 +3814,30 @@ choose_random_dirguard(dirinfo_type_t type)
int
num_bridges_usable(void)
{
- tor_assert(get_options()->UseDeprecatedGuardAlgorithm);
-
int n_options = 0;
- tor_assert(get_options()->UseBridges);
- (void) choose_random_entry_impl(get_guard_selection_info(),
- NULL, 0, 0, &n_options);
+
+ if (get_options()->UseDeprecatedGuardAlgorithm) {
+
+ tor_assert(get_options()->UseBridges);
+ (void) choose_random_entry_impl(get_guard_selection_info(),
+ NULL, 0, 0, &n_options);
+ } else {
+ /* XXXX prop271 Is this quite right? */
+ tor_assert(get_options()->UseBridges);
+ guard_selection_t *gs = get_guard_selection_info();
+ tor_assert(gs->type == GS_TYPE_BRIDGE);
+
+ SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) {
+ if (guard->is_reachable == GUARD_REACHABLE_NO)
+ continue;
+ if (tor_digest_is_zero(guard->identity))
+ continue;
+ const node_t *node = node_get_by_id(guard->identity);
+ if (node && node->ri)
+ ++n_options;
+ } SMARTLIST_FOREACH_END(guard);
+ }
+
return n_options;
}
1
0
[tor/master] Re-enable some disabled tests about switching guard_selections
by nickm@torproject.org 16 Dec '16
by nickm@torproject.org 16 Dec '16
16 Dec '16
commit 6c3f555a8c4d33b8f9dcdc55c03bee8170feb65f
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Nov 29 14:28:43 2016 -0500
Re-enable some disabled tests about switching guard_selections
---
src/test/test_entrynodes.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index 6a3048b..e3a9d18 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -1276,18 +1276,18 @@ test_entry_guard_get_guard_selection_by_name(void *arg)
tt_assert(gs3 != NULL);
tt_assert(gs3 != gs2);
tt_assert(gs3 != gs1);
- // XXXX prop271 re-enable this. tt_assert(gs3 == get_guard_selection_info());
+ tt_assert(gs3 == get_guard_selection_info());
-#if 0
or_options_t *options = get_options_mutable();
options->UseDeprecatedGuardAlgorithm = 1;
- gs4 = get_guard_selection_info();
+ update_guard_selection_choice(options);
+ guard_selection_t *gs4 = get_guard_selection_info();
tt_assert(gs4 != gs3);
- tt_assert(gs4 == get_guard_selection_by_name("legacy", 1));
+ tt_assert(gs4 == get_guard_selection_by_name("legacy", GS_TYPE_LEGACY, 1));
options->UseDeprecatedGuardAlgorithm = 0;
+ update_guard_selection_choice(options);
tt_assert(gs3 == get_guard_selection_info());
-#endif
done:
entry_guards_free_all();
1
0
[tor/master] Remove guard_selection argument from status-reporting functions
by nickm@torproject.org 16 Dec '16
by nickm@torproject.org 16 Dec '16
16 Dec '16
commit 89f5f149df984bab00de9868a9305b611c4aa17e
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Mon Nov 28 11:04:28 2016 -0500
Remove guard_selection argument from status-reporting functions
This prevents us from mixing up multiple guard_selections
---
src/or/circuitbuild.c | 3 +--
src/or/circuitlist.c | 2 +-
src/or/circuituse.c | 2 +-
src/or/connection.c | 2 +-
src/or/connection_or.c | 6 ++----
src/or/directory.c | 9 ++++-----
src/or/entrynodes.c | 31 ++++++++++---------------------
src/or/entrynodes.h | 12 ++++--------
src/test/test_entrynodes.c | 26 +++++++++++++-------------
9 files changed, 37 insertions(+), 56 deletions(-)
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 16b53f6..5d0a04f 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -976,8 +976,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
}
r = 1;
} else {
- r = entry_guard_succeeded(get_guard_selection_info(),
- &circ->guard_state);
+ r = entry_guard_succeeded(&circ->guard_state);
}
const int is_usable_for_streams = (r == 1);
if (r == 1) {
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 0afe2f8..b25f817 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -898,7 +898,7 @@ circuit_free(circuit_t *circ)
/* Cancel before freeing, if we haven't already succeeded or failed. */
if (ocirc->guard_state) {
- entry_guard_cancel(get_guard_selection_info(), ô->guard_state);
+ entry_guard_cancel(ô->guard_state);
}
circuit_guard_state_free(ocirc->guard_state);
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index b925729..698b158 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1653,7 +1653,7 @@ circuit_build_failed(origin_circuit_t *circ)
}
if (n_chan_id && !already_marked) {
if (circ->guard_state)
- entry_guard_failed(get_guard_selection_info(), &circ->guard_state);
+ entry_guard_failed(&circ->guard_state);
/* XXXX prop271 -- old API */
entry_guard_register_connect_status(n_chan_id, 0, 1, time(NULL));
/* if there are any one-hop streams waiting on this circuit, fail
diff --git a/src/or/connection.c b/src/or/connection.c
index 25c75ff..87f0f91 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -636,7 +636,7 @@ connection_free_(connection_t *conn)
rend_data_free(dir_conn->rend_data);
if (dir_conn->guard_state) {
/* Cancel before freeing, if it's still there. */
- entry_guard_cancel(get_guard_selection_info(), &dir_conn->guard_state);
+ entry_guard_cancel(&dir_conn->guard_state);
}
circuit_guard_state_free(dir_conn->guard_state);
}
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index fefcc86..14d5979 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -735,8 +735,7 @@ connection_or_about_to_close(or_connection_t *or_conn)
const or_options_t *options = get_options();
connection_or_note_state_when_broken(or_conn);
rep_hist_note_connect_failed(or_conn->identity_digest, now);
- entry_guard_chan_failed(get_guard_selection_info(),
- TLS_CHAN_TO_BASE(or_conn->chan));
+ entry_guard_chan_failed(TLS_CHAN_TO_BASE(or_conn->chan));
/* XXXX prop271 -- old API */
entry_guard_register_connect_status(or_conn->identity_digest,0,
!options->HTTPSProxy, now);
@@ -1676,8 +1675,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
"Tried connecting to router at %s:%d, but identity key was not "
"as expected: wanted %s but got %s.%s",
conn->base_.address, conn->base_.port, expected, seen, extra_log);
- entry_guard_chan_failed(get_guard_selection_info(),
- TLS_CHAN_TO_BASE(conn->chan));
+ entry_guard_chan_failed(TLS_CHAN_TO_BASE(conn->chan));
/* XXXX prop271 old API */
entry_guard_register_connect_status(conn->identity_digest, 0, 1,
time(NULL));
diff --git a/src/or/directory.c b/src/or/directory.c
index 4164672..6fc8809 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -902,7 +902,7 @@ connection_dir_request_failed(dir_connection_t *conn)
if (conn->guard_state) {
/* We haven't seen a success on this guard state, so consider it to have
* failed. */
- entry_guard_failed(get_guard_selection_info(), &conn->guard_state);
+ entry_guard_failed(&conn->guard_state);
}
if (directory_conn_is_self_reachability_test(conn)) {
return; /* this was a test fetch. don't retry. */
@@ -1271,7 +1271,7 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port,
// In this case we should not have picked a directory guard.
if (BUG(guard_state)) {
- entry_guard_cancel(get_guard_selection_info(), &guard_state);
+ entry_guard_cancel(&guard_state);
}
switch (connection_connect(TO_CONN(conn), conn->base_.address, &addr,
@@ -1313,7 +1313,7 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port,
// In this case we should not have a directory guard; we'll
// get a regular guard later when we build the circuit.
if (BUG(anonymized_connection && guard_state)) {
- entry_guard_cancel(get_guard_selection_info(), &guard_state);
+ entry_guard_cancel(&guard_state);
}
conn->guard_state = guard_state;
@@ -2580,8 +2580,7 @@ connection_dir_process_inbuf(dir_connection_t *conn)
*/
/* XXXXprop271 should we count this as only a partial success somehow?
*/
- entry_guard_succeeded(get_guard_selection_info(),
- &conn->guard_state);
+ entry_guard_succeeded(&conn->guard_state);
circuit_guard_state_free(conn->guard_state);
conn->guard_state = NULL;
}
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index e0626cf..0795d19 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -1731,8 +1731,7 @@ entry_guard_pick_for_circuit(guard_selection_t *gs,
* XXXXX prop271 tristates are ugly; reconsider that interface.
*/
int
-entry_guard_succeeded(guard_selection_t *gs,
- circuit_guard_state_t **guard_state_p)
+entry_guard_succeeded(circuit_guard_state_t **guard_state_p)
{
if (get_options()->UseDeprecatedGuardAlgorithm)
return 1;
@@ -1741,13 +1740,12 @@ entry_guard_succeeded(guard_selection_t *gs,
return -1;
entry_guard_t *guard = entry_guard_handle_get((*guard_state_p)->guard);
- if (! guard)
+ if (! guard || BUG(guard->in_selection == NULL))
return -1;
- tor_assert(gs == guard->in_selection); // XXXX prop271 remove argument
-
unsigned newstate =
- entry_guards_note_guard_success(gs, guard, (*guard_state_p)->state);
+ entry_guards_note_guard_success(guard->in_selection, guard,
+ (*guard_state_p)->state);
(*guard_state_p)->state = newstate;
(*guard_state_p)->state_set_at = approx_time();
@@ -1763,10 +1761,8 @@ entry_guard_succeeded(guard_selection_t *gs,
* success or failure. It is safe to call this function if success or
* failure _has_ already been declared. */
void
-entry_guard_cancel(guard_selection_t *gs,
- circuit_guard_state_t **guard_state_p)
+entry_guard_cancel(circuit_guard_state_t **guard_state_p)
{
- (void) gs;
if (get_options()->UseDeprecatedGuardAlgorithm)
return;
if (BUG(*guard_state_p == NULL))
@@ -1775,8 +1771,6 @@ entry_guard_cancel(guard_selection_t *gs,
if (! guard)
return;
- tor_assert(gs == guard->in_selection); // XXXX prop271 remove argument
-
/* XXXX prop271 -- last_tried_to_connect_at will be erroneous here, but this
* function will only get called in "bug" cases anyway. */
guard->is_pending = 0;
@@ -1790,8 +1784,7 @@ entry_guard_cancel(guard_selection_t *gs,
* not working, and advances the state of the guard module.
*/
void
-entry_guard_failed(guard_selection_t *gs,
- circuit_guard_state_t **guard_state_p)
+entry_guard_failed(circuit_guard_state_t **guard_state_p)
{
if (get_options()->UseDeprecatedGuardAlgorithm)
return;
@@ -1800,12 +1793,10 @@ entry_guard_failed(guard_selection_t *gs,
return;
entry_guard_t *guard = entry_guard_handle_get((*guard_state_p)->guard);
- if (! guard)
+ if (! guard || BUG(guard->in_selection == NULL))
return;
- tor_assert(gs == guard->in_selection); // XXXX prop271 remove argument
-
- entry_guards_note_guard_failure(gs, guard);
+ entry_guards_note_guard_failure(guard->in_selection, guard);
(*guard_state_p)->state = GUARD_CIRC_STATE_DEAD;
(*guard_state_p)->state_set_at = approx_time();
@@ -1816,10 +1807,8 @@ entry_guard_failed(guard_selection_t *gs,
* pending on <b>chan</b>.
*/
void
-entry_guard_chan_failed(guard_selection_t *gs,
- channel_t *chan)
+entry_guard_chan_failed(channel_t *chan)
{
- tor_assert(gs);
if (!chan)
return;
if (get_options()->UseDeprecatedGuardAlgorithm)
@@ -1832,7 +1821,7 @@ entry_guard_chan_failed(guard_selection_t *gs,
continue;
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
- entry_guard_failed(gs, &origin_circ->guard_state);
+ entry_guard_failed(&origin_circ->guard_state);
} SMARTLIST_FOREACH_END(circ);
smartlist_free(pending);
}
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index 97cc4d2..0abbea8 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -351,14 +351,10 @@ void circuit_guard_state_free(circuit_guard_state_t *state);
int entry_guard_pick_for_circuit(guard_selection_t *gs,
const node_t **chosen_node_out,
circuit_guard_state_t **guard_state_out);
-int entry_guard_succeeded(guard_selection_t *gs,
- circuit_guard_state_t **guard_state_p);
-void entry_guard_failed(guard_selection_t *gs,
- circuit_guard_state_t **guard_state_p);
-void entry_guard_cancel(guard_selection_t *gs,
- circuit_guard_state_t **guard_state_p);
-void entry_guard_chan_failed(guard_selection_t *gs,
- channel_t *chan);
+int entry_guard_succeeded(circuit_guard_state_t **guard_state_p);
+void entry_guard_failed(circuit_guard_state_t **guard_state_p);
+void entry_guard_cancel(circuit_guard_state_t **guard_state_p);
+void entry_guard_chan_failed(channel_t *chan);
int entry_guards_update_all(guard_selection_t *gs);
int entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
const smartlist_t *all_circuits,
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index 4595e5d..bc0862a 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -2333,7 +2333,7 @@ test_entry_guard_select_for_circuit_highlevel_primary(void *arg)
/* Call that circuit successful. */
update_approx_time(start+15);
- r = entry_guard_succeeded(gs, &guard);
+ r = entry_guard_succeeded(&guard);
tt_int_op(r, OP_EQ, 1); /* We can use it now. */
tt_assert(guard);
tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
@@ -2365,7 +2365,7 @@ test_entry_guard_select_for_circuit_highlevel_primary(void *arg)
/* It's failed! What will happen to our poor guard? */
update_approx_time(start+45);
- entry_guard_failed(gs, &guard);
+ entry_guard_failed(&guard);
tt_assert(guard);
tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_DEAD);
tt_i64_op(guard->state_set_at, OP_EQ, start+45);
@@ -2401,7 +2401,7 @@ test_entry_guard_select_for_circuit_highlevel_primary(void *arg)
/* Call this one up; watch it get confirmed. */
update_approx_time(start+90);
- r = entry_guard_succeeded(gs, &guard);
+ r = entry_guard_succeeded(&guard);
tt_int_op(r, OP_EQ, 1); /* We can use it now. */
tt_assert(guard);
tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
@@ -2441,7 +2441,7 @@ test_entry_guard_select_for_circuit_highlevel_confirm_other(void *arg)
tt_assert(guard);
tt_assert(r == 0);
tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
- entry_guard_failed(gs, &guard);
+ entry_guard_failed(&guard);
circuit_guard_state_free(guard);
guard = NULL;
node = NULL;
@@ -2461,7 +2461,7 @@ test_entry_guard_select_for_circuit_highlevel_confirm_other(void *arg)
tt_int_op(g->is_pending, OP_EQ, 1);
(void)start;
- r = entry_guard_succeeded(gs, &guard);
+ r = entry_guard_succeeded(&guard);
/* We're on the internet (by fiat), so this guard will get called "confirmed"
* and should immediately become primary.
* XXXX prop271 -- I don't like that behavior, but it's what is specified
@@ -2508,7 +2508,7 @@ test_entry_guard_select_for_circuit_highlevel_primary_retry(void *arg)
g = entry_guard_handle_get(guard->guard);
make_guard_confirmed(gs, g);
tt_int_op(g->is_primary, OP_EQ, 1);
- entry_guard_failed(gs, &guard);
+ entry_guard_failed(&guard);
circuit_guard_state_free(guard);
tt_int_op(g->is_reachable, OP_EQ, GUARD_REACHABLE_NO);
guard = NULL;
@@ -2530,7 +2530,7 @@ test_entry_guard_select_for_circuit_highlevel_primary_retry(void *arg)
update_approx_time(start + 3600);
/* Say that guard has succeeded! */
- r = entry_guard_succeeded(gs, &guard);
+ r = entry_guard_succeeded(&guard);
tt_int_op(r, OP_EQ, 0); // can't use it yet.
tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD);
g = entry_guard_handle_get(guard->guard);
@@ -2546,7 +2546,7 @@ test_entry_guard_select_for_circuit_highlevel_primary_retry(void *arg)
r = entry_guard_pick_for_circuit(gs, &node, &guard2);
tt_assert(r == 0);
tt_int_op(guard2->state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
- r = entry_guard_succeeded(gs, &guard2);
+ r = entry_guard_succeeded(&guard2);
tt_assert(r == 1);
tt_int_op(guard2->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
@@ -2578,7 +2578,7 @@ test_entry_guard_select_and_cancel(void *arg)
tt_int_op(g->is_primary, OP_EQ, 1);
tt_int_op(g->is_pending, OP_EQ, 0);
make_guard_confirmed(gs, g);
- entry_guard_failed(gs, &guard);
+ entry_guard_failed(&guard);
circuit_guard_state_free(guard);
guard = NULL;
node = NULL;
@@ -2597,7 +2597,7 @@ test_entry_guard_select_and_cancel(void *arg)
tt_int_op(g->is_pending, OP_EQ, 1);
/* Whoops! We should never have asked for this guard. Cancel the request! */
- entry_guard_cancel(gs, &guard);
+ entry_guard_cancel(&guard);
tt_assert(guard == NULL);
tt_int_op(g->is_primary, OP_EQ, 0);
tt_int_op(g->is_pending, OP_EQ, 0);
@@ -2649,7 +2649,7 @@ upgrade_circuits_setup(const struct testcase_t *testcase)
entry_guard_pick_for_circuit(gs, &node, &guard);
g = entry_guard_handle_get(guard->guard);
make_guard_confirmed(gs, g);
- entry_guard_failed(gs, &guard);
+ entry_guard_failed(&guard);
circuit_guard_state_free(guard);
}
@@ -2682,14 +2682,14 @@ upgrade_circuits_setup(const struct testcase_t *testcase)
int r;
update_approx_time(data->start + 32);
if (make_circ1_succeed) {
- r = entry_guard_succeeded(gs, &data->guard1_state);
+ r = entry_guard_succeeded(&data->guard1_state);
tor_assert(r == 0);
tor_assert(data->guard1_state->state ==
GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD);
}
update_approx_time(data->start + 33);
if (make_circ2_succeed) {
- r = entry_guard_succeeded(gs, &data->guard2_state);
+ r = entry_guard_succeeded(&data->guard2_state);
tor_assert(r == 0);
tor_assert(data->guard2_state->state ==
GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD);
1
0
[tor/master] Add a backpointer from entry_guard_t to guard_selection_t
by nickm@torproject.org 16 Dec '16
by nickm@torproject.org 16 Dec '16
16 Dec '16
commit 6dcbc24a4e9da3d46dc9fa1c225982f7088a6e34
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Mon Nov 28 10:50:36 2016 -0500
Add a backpointer from entry_guard_t to guard_selection_t
This is safe, because no entry_guard_t ever outlives its
guard_selection_t.
I want this because now that multiple guard selections can be active
during one tor session, we should make sure that any information we
register about guards is with respect to the selection that they came
from.
---
src/or/entrynodes.c | 52 +++++++++++++++++++++++++++++++++++++++++-----------
src/or/entrynodes.h | 1 +
2 files changed, 42 insertions(+), 11 deletions(-)
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 59205a8..e0626cf 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -722,6 +722,7 @@ entry_guard_add_to_sample(guard_selection_t *gs,
guard->is_reachable = GUARD_REACHABLE_MAYBE;
smartlist_add(gs->sampled_entry_guards, guard);
+ guard->in_selection = gs;
entry_guard_set_filtered_flags(get_options(), gs, guard);
entry_guards_changed_for_guard_selection(gs);
return guard;
@@ -1743,6 +1744,8 @@ entry_guard_succeeded(guard_selection_t *gs,
if (! guard)
return -1;
+ tor_assert(gs == guard->in_selection); // XXXX prop271 remove argument
+
unsigned newstate =
entry_guards_note_guard_success(gs, guard, (*guard_state_p)->state);
@@ -1772,6 +1775,8 @@ entry_guard_cancel(guard_selection_t *gs,
if (! guard)
return;
+ tor_assert(gs == guard->in_selection); // XXXX prop271 remove argument
+
/* XXXX prop271 -- last_tried_to_connect_at will be erroneous here, but this
* function will only get called in "bug" cases anyway. */
guard->is_pending = 0;
@@ -1798,6 +1803,8 @@ entry_guard_failed(guard_selection_t *gs,
if (! guard)
return;
+ tor_assert(gs == guard->in_selection); // XXXX prop271 remove argument
+
entry_guards_note_guard_failure(gs, guard);
(*guard_state_p)->state = GUARD_CIRC_STATE_DEAD;
@@ -1876,7 +1883,7 @@ circ_state_has_higher_priority(origin_circuit_t *a,
}
/**
- * Look at all of the origin_circuit_t * objects in <b>all_circuits</b>,
+ * Look at all of the origin_circuit_t * objects in <b>all_circuits_in</b>,
* and see if any of them that were previously not ready to use for
* guard-related reasons are now ready to use. Place those circuits
* in <b>newly_complete_out</b>, and mark them COMPLETE.
@@ -1885,11 +1892,11 @@ circ_state_has_higher_priority(origin_circuit_t *a,
*/
int
entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
- const smartlist_t *all_circuits,
+ const smartlist_t *all_circuits_in,
smartlist_t *newly_complete_out)
{
tor_assert(gs);
- tor_assert(all_circuits);
+ tor_assert(all_circuits_in);
tor_assert(newly_complete_out);
if (! entry_guards_all_primary_guards_are_down(gs)) {
@@ -1904,10 +1911,24 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
int n_complete = 0;
origin_circuit_t *best_waiting_circuit = NULL;
origin_circuit_t *best_complete_circuit = NULL;
- SMARTLIST_FOREACH_BEGIN(all_circuits, origin_circuit_t *, circ) {
+ smartlist_t *all_circuits = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(all_circuits_in, origin_circuit_t *, circ) {
+ // We filter out circuits that aren't ours, or which we can't
+ // reason about.
circuit_guard_state_t *state = origin_circuit_get_guard_state(circ);
if (state == NULL)
continue;
+ entry_guard_t *guard = entry_guard_handle_get(state->guard);
+ if (!guard || guard->in_selection != gs)
+ continue;
+
+ smartlist_add(all_circuits, circ);
+ } SMARTLIST_FOREACH_END(circ);
+
+ SMARTLIST_FOREACH_BEGIN(all_circuits, origin_circuit_t *, circ) {
+ circuit_guard_state_t *state = origin_circuit_get_guard_state(circ);
+ if BUG((state == NULL))
+ continue;
if (state->state == GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD) {
++n_waiting;
@@ -1927,7 +1948,7 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
if (! best_waiting_circuit) {
log_debug(LD_GUARD, "Considered upgrading guard-stalled circuits, "
"but didn't find any.");
- return 0;
+ goto no_change;
}
if (best_complete_circuit) {
@@ -1940,8 +1961,7 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
"%d complete and %d guard-stalled. At least one complete "
"circuit had higher priority, so not upgrading.",
n_complete, n_waiting);
-
- return 0;
+ goto no_change;
}
}
@@ -1959,7 +1979,7 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
approx_time() - get_nonprimary_guard_connect_timeout();
SMARTLIST_FOREACH_BEGIN(all_circuits, origin_circuit_t *, circ) {
circuit_guard_state_t *state = origin_circuit_get_guard_state(circ);
- if (state == NULL)
+ if (BUG(state == NULL))
continue;
if (state->state != GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD)
continue;
@@ -1973,7 +1993,7 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
"%d guard-stalled, but %d pending circuit(s) had higher "
"guard priority, so not upgrading.",
n_waiting, n_blockers_found);
- return 0;
+ goto no_change;
}
/* Okay. We have a best waiting circuit, and we aren't waiting for
@@ -1982,7 +2002,7 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
int n_succeeded = 0;
SMARTLIST_FOREACH_BEGIN(all_circuits, origin_circuit_t *, circ) {
circuit_guard_state_t *state = origin_circuit_get_guard_state(circ);
- if (state == NULL)
+ if (BUG(state == NULL))
continue;
if (state->state != GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD)
continue;
@@ -2001,7 +2021,12 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
n_waiting, n_complete, n_succeeded);
tor_assert_nonfatal(n_succeeded >= 1);
+ smartlist_free(all_circuits);
return 1;
+
+ no_change:
+ smartlist_free(all_circuits);
+ return 0;
}
/**
@@ -2431,6 +2456,7 @@ entry_guards_load_guards_from_state(or_state_t *state, int set)
GS_TYPE_INFER, 1);
tor_assert(gs);
smartlist_add(gs->sampled_entry_guards, guard);
+ guard->in_selection = gs;
} else {
entry_guard_free(guard);
}
@@ -2925,6 +2951,7 @@ add_an_entry_guard(guard_selection_t *gs,
smartlist_insert(gs->chosen_entry_guards, 0, entry);
else
smartlist_add(gs->chosen_entry_guards, entry);
+ entry->in_selection = gs;
control_event_guard(entry->nickname, entry->identity, "NEW");
control_event_guard_deferred();
@@ -3127,6 +3154,7 @@ remove_all_entry_guards_for_guard_selection(guard_selection_t *gs)
void
remove_all_entry_guards(void)
{
+ // XXXX prop271 this function shouldn't exist, in the new order.
remove_all_entry_guards_for_guard_selection(get_guard_selection_info());
}
@@ -4037,6 +4065,8 @@ entry_guards_parse_state_for_guard_selection(
smartlist_free(gs->chosen_entry_guards);
}
gs->chosen_entry_guards = new_entry_guards;
+ SMARTLIST_FOREACH(new_entry_guards, entry_guard_t *, e,
+ e->in_selection = gs);
/* XXX hand new_entry_guards to this func, and move it up a
* few lines, so we don't have to re-dirty it */
@@ -4429,7 +4459,7 @@ guards_update_all(void)
if (curr_guard_context->type == GS_TYPE_LEGACY) {
entry_guards_compute_status(get_options(), approx_time());
} else {
- if (entry_guards_update_all(get_guard_selection_info()))
+ if (entry_guards_update_all(curr_guard_context))
mark_circuits = 1;
}
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index 0164667..97cc4d2 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -125,6 +125,7 @@ struct entry_guard_t {
* Which selection does this guard belong to?
*/
char *selection_name;
+ guard_selection_t *in_selection;
/* ==== Non-persistent fields. */
/* == These are used by sampled guards */
1
0
commit eac8b3f758545f02fd7db58c458de19a6442044b
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Nov 29 11:59:48 2016 -0500
Remove a few unused arguments.
---
src/or/entrynodes.c | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index aa90566..3ba0179 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -159,9 +159,8 @@ static void entry_guard_set_filtered_flags(const or_options_t *options,
entry_guard_t *guard);
static void pathbias_check_use_success_count(entry_guard_t *guard);
static void pathbias_check_close_success_count(entry_guard_t *guard);
-static int node_is_possible_guard(guard_selection_t *gs, const node_t *node);
+static int node_is_possible_guard(const node_t *node);
static int node_passes_guard_filter(const or_options_t *options,
- guard_selection_t *gs,
const node_t *node);
static entry_guard_t *entry_guard_add_to_sample_impl(guard_selection_t *gs,
const uint8_t *rsa_id_digest,
@@ -530,9 +529,9 @@ choose_guard_selection(const or_options_t *options,
const smartlist_t *nodes = nodelist_get_list();
int n_guards = 0, n_passing_filter = 0;
SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) {
- if (node_is_possible_guard(NULL, node)) {
+ if (node_is_possible_guard(node)) {
++n_guards;
- if (node_passes_guard_filter(options, NULL, node)) {
+ if (node_passes_guard_filter(options, node)) {
++n_passing_filter;
}
}
@@ -650,13 +649,12 @@ update_guard_selection_choice(const or_options_t *options)
* a possible guard when sampling guards.
*/
static int
-node_is_possible_guard(guard_selection_t *gs, const node_t *node)
+node_is_possible_guard(const node_t *node)
{
/* The "GUARDS" set is all nodes in the nodelist for which this predicate
* holds. */
/* XXXX -- prop271 spec deviation. We require node_is_dir() here. */
- (void)gs; /* Remove this argument */
tor_assert(node);
return (node->is_possible_guard &&
node->is_stable &&
@@ -930,7 +928,7 @@ get_eligible_guards(guard_selection_t *gs,
} SMARTLIST_FOREACH_END(guard);
SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) {
- if (! node_is_possible_guard(gs, node))
+ if (! node_is_possible_guard(node))
continue;
++n_guards;
if (digestset_contains(sampled_guard_ids, node->identity))
@@ -1088,7 +1086,7 @@ entry_guard_is_listed(guard_selection_t *gs, const entry_guard_t *guard)
} else {
const node_t *node = node_get_by_id(guard->identity);
- return node && node_is_possible_guard(gs, node);
+ return node && node_is_possible_guard(node);
}
}
@@ -1231,12 +1229,9 @@ sampled_guards_update_from_consensus(guard_selection_t *gs)
* Return true iff <b>node</b> is a Tor relay that we are configured to
* be able to connect to. */
static int
-node_passes_guard_filter(const or_options_t *options, guard_selection_t *gs,
+node_passes_guard_filter(const or_options_t *options,
const node_t *node)
{
- /* XXXX prop271 remote the gs option; it is unused, and sometimes NULL. */
- (void)gs;
-
/* NOTE: Make sure that this function stays in sync with
* options_transition_affects_entry_guards */
if (routerset_contains_node(options->ExcludeNodes, node))
@@ -1308,7 +1303,7 @@ entry_guard_passes_filter(const or_options_t *options, guard_selection_t *gs,
return 0;
}
- return node_passes_guard_filter(options, gs, node);
+ return node_passes_guard_filter(options, node);
}
}
1
0
[tor/master] Lay down some infrastructure for bridges in the New Guard Order.
by nickm@torproject.org 16 Dec '16
by nickm@torproject.org 16 Dec '16
16 Dec '16
commit 1d52ac4d3f67a6e3fac3602f87d00c14060068ab
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Nov 29 08:04:41 2016 -0500
Lay down some infrastructure for bridges in the New Guard Order.
This includes:
* making bridge_info_t exposed but opaque
* allowing guards where we don't know an identity
* making it possible to learn the identity of a guard
* creating a guard that lacks a node_t
* remembering a guard's address and port.
* Looking up a guard by address and port.
* Only enforcing the rule that we need a live consensus to update
the "listed" status for guards when we are not using bridges.
---
src/common/address.c | 8 +++
src/common/address.h | 2 +
src/or/bridges.c | 44 ++++++++++++-
src/or/bridges.h | 6 ++
src/or/entrynodes.c | 161 +++++++++++++++++++++++++++++++++++++++++----
src/or/entrynodes.h | 18 ++++-
src/test/test_entrynodes.c | 10 +++
7 files changed, 233 insertions(+), 16 deletions(-)
diff --git a/src/common/address.c b/src/common/address.c
index 773e688..1bb0c07 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -2121,3 +2121,11 @@ tor_addr_port_new(const tor_addr_t *addr, uint16_t port)
return ap;
}
+/** Return true iff <a>a</b> and <b>b</b> are the same address and port */
+int
+tor_addr_port_eq(const tor_addr_port_t *a,
+ const tor_addr_port_t *b)
+{
+ return tor_addr_eq(&a->addr, &b->addr) && a->port == b->port;
+}
+
diff --git a/src/common/address.h b/src/common/address.h
index 51db42c..41daf01 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -342,6 +342,8 @@ get_interface_address_list(int severity, int include_internal)
}
tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port);
+int tor_addr_port_eq(const tor_addr_port_t *a,
+ const tor_addr_port_t *b);
#ifdef ADDRESS_PRIVATE
MOCK_DECL(smartlist_t *,get_interface_addresses_raw,(int severity,
diff --git a/src/or/bridges.c b/src/or/bridges.c
index 2170cc6..f16acfa 100644
--- a/src/or/bridges.c
+++ b/src/or/bridges.c
@@ -28,7 +28,9 @@
/** Information about a configured bridge. Currently this just matches the
* ones in the torrc file, but one day we may be able to learn about new
* bridges on our own, and remember them in the state file. */
-typedef struct {
+struct bridge_info_t {
+ /** Address and port of the bridge, as configured by the user.*/
+ tor_addr_port_t addrport_configured;
/** Address of the bridge. */
tor_addr_t addr;
/** TLS port for the bridge. */
@@ -49,7 +51,7 @@ typedef struct {
/** A smartlist of k=v values to be passed to the SOCKS proxy, if
transports are used for this bridge. */
smartlist_t *socks_args;
-} bridge_info_t;
+};
static void bridge_free(bridge_info_t *bridge);
@@ -111,6 +113,40 @@ bridge_free(bridge_info_t *bridge)
tor_free(bridge);
}
+/** Return a list of all the configured bridges, as bridge_info_t pointers. */
+const smartlist_t *
+bridge_list_get(void)
+{
+ if (!bridge_list)
+ bridge_list = smartlist_new();
+ return bridge_list;
+}
+
+/**
+ * Given a <b>bridge</b>, return a pointer to its RSA identity digest, or
+ * NULL if we don't know one for it.
+ */
+const uint8_t *
+bridge_get_rsa_id_digest(const bridge_info_t *bridge)
+{
+ tor_assert(bridge);
+ if (tor_digest_is_zero(bridge->identity))
+ return NULL;
+ else
+ return (const uint8_t *) bridge->identity;
+}
+
+/**
+ * Given a <b>bridge</b>, return a pointer to its configured addr:port
+ * combination.
+ */
+const tor_addr_port_t *
+bridge_get_addr_port(const bridge_info_t *bridge)
+{
+ tor_assert(bridge);
+ return &bridge->addrport_configured;
+}
+
/** If we have a bridge configured whose digest matches <b>digest</b>, or a
* bridge with no known digest whose address matches any of the
* tor_addr_port_t's in <b>orports</b>, return that bridge. Else return
@@ -243,6 +279,7 @@ learned_router_identity(const tor_addr_t *addr, uint16_t port,
hex_str(digest, DIGEST_LEN), fmt_addrport(addr, port),
transport_info ? transport_info : "");
tor_free(transport_info);
+ // XXXX prop271 here. we will need to update the guard info too.
}
}
@@ -361,6 +398,8 @@ bridge_add_from_config(bridge_line_t *bridge_line)
bridge_line->transport_name);
b = tor_malloc_zero(sizeof(bridge_info_t));
+ tor_addr_copy(&b->addrport_configured.addr, &bridge_line->addr);
+ b->addrport_configured.port = bridge_line->port;
tor_addr_copy(&b->addr, &bridge_line->addr);
b->port = bridge_line->port;
memcpy(b->identity, bridge_line->digest, DIGEST_LEN);
@@ -718,6 +757,7 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
fmt_and_decorate_addr(&bridge->addr),
(int) bridge->port);
}
+ // XXXX prop271 here we will need to update the guard info too.
add_bridge_as_entry_guard(get_guard_selection_info(), node);
log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname,
diff --git a/src/or/bridges.h b/src/or/bridges.h
index 738b1a6..d01794f 100644
--- a/src/or/bridges.h
+++ b/src/or/bridges.h
@@ -14,8 +14,14 @@
struct bridge_line_t;
+/* Opaque handle to a configured bridge */
+typedef struct bridge_info_t bridge_info_t;
+
void mark_bridge_list(void);
void sweep_bridge_list(void);
+const smartlist_t *bridge_list_get(void);
+const uint8_t *bridge_get_rsa_id_digest(const bridge_info_t *bridge);
+const tor_addr_port_t * bridge_get_addr_port(const bridge_info_t *bridge);
int addr_is_a_configured_bridge(const tor_addr_t *addr, uint16_t port,
const char *digest);
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 0795d19..e725d4e 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -163,6 +163,10 @@ static int node_is_possible_guard(guard_selection_t *gs, const node_t *node);
static int node_passes_guard_filter(const or_options_t *options,
guard_selection_t *gs,
const node_t *node);
+static entry_guard_t *entry_guard_add_to_sample_impl(guard_selection_t *gs,
+ const uint8_t *rsa_id_digest,
+ const char *nickname,
+ const tor_addr_port_t *bridge_addrport);
/** Return 0 if we should apply guardfraction information found in the
* consensus. A specific consensus can be specified with the
@@ -693,25 +697,47 @@ STATIC entry_guard_t *
entry_guard_add_to_sample(guard_selection_t *gs,
const node_t *node)
{
- const int GUARD_LIFETIME = get_guard_lifetime_days() * 86400;
- tor_assert(gs);
- tor_assert(node);
-
log_info(LD_GUARD, "Adding %s as to the entry guard sample set.",
node_describe(node));
+ return entry_guard_add_to_sample_impl(gs,
+ (const uint8_t*)node->identity,
+ node_get_nickname(node),
+ NULL);
+}
+
+/**
+ * Backend: adds a new sampled guard to <b>gs</b>, with given identity,
+ * nickname, and ORPort. rsa_id_digest and bridge_addrport are
+ * optional, but we need one of them. nickname is optional.
+ */
+static entry_guard_t *
+entry_guard_add_to_sample_impl(guard_selection_t *gs,
+ const uint8_t *rsa_id_digest,
+ const char *nickname,
+ const tor_addr_port_t *bridge_addrport)
+{
+ const int GUARD_LIFETIME = get_guard_lifetime_days() * 86400;
+ tor_assert(gs);
+
// XXXX prop271 take ed25519 identity here too.
/* make sure that the guard is not already sampled. */
- if (BUG(have_sampled_guard_with_id(gs, (uint8_t*)node->identity)))
+ if (rsa_id_digest && BUG(have_sampled_guard_with_id(gs, rsa_id_digest)))
+ return NULL; // LCOV_EXCL_LINE
+ /* Make sure we can actually identify the guard. */
+ if (BUG(!rsa_id_digest && !bridge_addrport))
return NULL; // LCOV_EXCL_LINE
entry_guard_t *guard = tor_malloc_zero(sizeof(entry_guard_t));
/* persistent fields */
+ guard->is_persistent = (rsa_id_digest != NULL);
guard->selection_name = tor_strdup(gs->name);
- memcpy(guard->identity, node->identity, DIGEST_LEN);
- strlcpy(guard->nickname, node_get_nickname(node), sizeof(guard->nickname));
+ if (rsa_id_digest)
+ memcpy(guard->identity, rsa_id_digest, DIGEST_LEN);
+ if (nickname)
+ strlcpy(guard->nickname, nickname, sizeof(guard->nickname));
guard->sampled_on_date = randomize_time(approx_time(), GUARD_LIFETIME/10);
tor_free(guard->sampled_by_version);
guard->sampled_by_version = tor_strdup(VERSION);
@@ -720,6 +746,8 @@ entry_guard_add_to_sample(guard_selection_t *gs,
/* non-persistent fields */
guard->is_reachable = GUARD_REACHABLE_MAYBE;
+ if (bridge_addrport)
+ guard->bridge_addr = tor_memdup(bridge_addrport, sizeof(*bridge_addrport));
smartlist_add(gs->sampled_entry_guards, guard);
guard->in_selection = gs;
@@ -729,6 +757,87 @@ entry_guard_add_to_sample(guard_selection_t *gs,
}
/**
+ * Add an entry guard to the "bridges" guard selection sample, with
+ * information taken from <b>bridge</b>. Return that entry guard.
+ */
+entry_guard_t *
+entry_guard_add_bridge_to_sample(const bridge_info_t *bridge)
+{
+ guard_selection_t *gs = get_guard_selection_by_name("bridges",
+ GS_TYPE_BRIDGE,
+ 1);
+ const uint8_t *id_digest = bridge_get_rsa_id_digest(bridge);
+ const tor_addr_port_t *addrport = bridge_get_addr_port(bridge);
+
+ tor_assert(addrport);
+
+ return entry_guard_add_to_sample_impl(gs, id_digest, NULL, addrport);
+}
+
+/**
+ * Return the entry_guard_t in <b>gs</b> whose address is <b>addrport</b>,
+ * or NULL if none exists.
+*/
+static entry_guard_t *
+entry_guard_get_by_bridge_addr(guard_selection_t *gs,
+ const tor_addr_port_t *addrport)
+{
+ if (! gs)
+ return NULL;
+ if (BUG(!addrport))
+ return NULL;
+ SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, g) {
+ if (g->bridge_addr && tor_addr_port_eq(addrport, g->bridge_addr))
+ return g;
+ } SMARTLIST_FOREACH_END(g);
+ return NULL;
+}
+
+/** Update the guard subsystem's knowledge of the identity of the bridge
+ * at <b>addrport</b>. Idempotent.
+ */
+void
+entry_guard_learned_bridge_identity(const tor_addr_port_t *addrport,
+ const uint8_t *rsa_id_digest)
+{
+ guard_selection_t *gs = get_guard_selection_by_name("bridges",
+ GS_TYPE_BRIDGE,
+ 0);
+ if (!gs)
+ return;
+
+ entry_guard_t *g = entry_guard_get_by_bridge_addr(gs, addrport);
+ if (!g)
+ return;
+
+ int make_persistent = 0;
+
+ if (tor_digest_is_zero(g->identity)) {
+ memcpy(g->identity, rsa_id_digest, DIGEST_LEN);
+ make_persistent = 1;
+ } else if (tor_memeq(g->identity, rsa_id_digest, DIGEST_LEN)) {
+ /* Nothing to see here; we learned something we already knew. */
+ if (BUG(! g->is_persistent))
+ make_persistent = 1;
+ } else {
+ char old_id[HEX_DIGEST_LEN+1];
+ base16_encode(old_id, sizeof(old_id), g->identity, sizeof(g->identity));
+ log_warn(LD_BUG, "We 'learned' an identity %s for a bridge at %s:%d, but "
+ "we already knew a different one (%s). Ignoring the new info as "
+ "possibly bogus.",
+ hex_str((const char *)rsa_id_digest, DIGEST_LEN),
+ fmt_and_decorate_addr(&addrport->addr), addrport->port,
+ old_id);
+ return; // redundant, but let's be clear: we're not making this persistent.
+ }
+
+ if (make_persistent) {
+ g->is_persistent = 1;
+ entry_guards_changed_for_guard_selection(gs);
+ }
+}
+
+/**
* Return the number of sampled guards in <b>gs</b> that are "filtered"
* (that is, we're willing to connect to them) and that are "usable"
* (that is, either "reachable" or "maybe reachable"). */
@@ -892,14 +1001,16 @@ sampled_guards_update_from_consensus(guard_selection_t *gs)
// It's important to use only a live consensus here; we don't want to
// make changes based on anything expired or old.
- networkstatus_t *ns = networkstatus_get_live_consensus(approx_time());
+ if (gs->type != GS_TYPE_BRIDGE) {
+ networkstatus_t *ns = networkstatus_get_live_consensus(approx_time());
- log_info(LD_GUARD, "Updating sampled guard status based on received "
- "consensus.");
+ log_info(LD_GUARD, "Updating sampled guard status based on received "
+ "consensus.");
- if (! ns || ns->valid_until < approx_time()) {
- log_info(LD_GUARD, "Hey, that consensus isn't still valid. Ignoring.");
- return;
+ if (! ns || ns->valid_until < approx_time()) {
+ log_info(LD_GUARD, "Hey, there wasn't a valid consensus. Ignoring");
+ return;
+ }
}
int n_changes = 0;
@@ -2070,6 +2181,11 @@ entry_guard_encode_for_state(entry_guard_t *guard)
smartlist_add_asprintf(result, "in=%s", guard->selection_name);
smartlist_add_asprintf(result, "rsa_id=%s",
hex_str(guard->identity, DIGEST_LEN));
+ if (guard->bridge_addr) {
+ smartlist_add_asprintf(result, "bridge_addr=%s:%d",
+ fmt_and_decorate_addr(&guard->bridge_addr->addr),
+ guard->bridge_addr->port);
+ }
if (strlen(guard->nickname)) {
smartlist_add_asprintf(result, "nickname=%s", guard->nickname);
}
@@ -2152,6 +2268,7 @@ entry_guard_parse_from_state(const char *s)
char *listed = NULL;
char *confirmed_on = NULL;
char *confirmed_idx = NULL;
+ char *bridge_addr = NULL;
// pathbias
char *pb_use_attempts = NULL;
@@ -2180,6 +2297,7 @@ entry_guard_parse_from_state(const char *s)
FIELD(listed);
FIELD(confirmed_on);
FIELD(confirmed_idx);
+ FIELD(bridge_addr);
FIELD(pb_use_attempts);
FIELD(pb_use_successes);
FIELD(pb_circ_attempts);
@@ -2218,6 +2336,7 @@ entry_guard_parse_from_state(const char *s)
}
entry_guard_t *guard = tor_malloc_zero(sizeof(entry_guard_t));
+ guard->is_persistent = 1;
if (in == NULL) {
log_warn(LD_CIRC, "Guard missing 'in' field");
@@ -2247,6 +2366,16 @@ entry_guard_parse_from_state(const char *s)
guard->identity, DIGEST_LEN);
}
+ if (bridge_addr) {
+ tor_addr_port_t res;
+ memset(&res, 0, sizeof(res));
+ int r = tor_addr_port_parse(LOG_WARN, bridge_addr,
+ &res.addr, &res.port, -1);
+ if (r == 0)
+ guard->bridge_addr = tor_memdup(&res, sizeof(res));
+ /* On error, we already warned. */
+ }
+
/* Process the various time fields. */
#define HANDLE_TIME(field) do { \
@@ -2357,6 +2486,7 @@ entry_guard_parse_from_state(const char *s)
tor_free(listed);
tor_free(confirmed_on);
tor_free(confirmed_idx);
+ tor_free(bridge_addr);
tor_free(pb_use_attempts);
tor_free(pb_use_successes);
tor_free(pb_circ_attempts);
@@ -2388,6 +2518,8 @@ entry_guards_update_guards_in_state(or_state_t *state)
if (!strcmp(gs->name, "legacy"))
continue; /* This is encoded differently. */
SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) {
+ if (guard->is_persistent == 0)
+ continue;
*nextline = tor_malloc_zero(sizeof(config_line_t));
(*nextline)->key = tor_strdup("Guard");
(*nextline)->value = entry_guard_encode_for_state(guard);
@@ -2908,6 +3040,7 @@ add_an_entry_guard(guard_selection_t *gs,
return NULL;
}
entry = tor_malloc_zero(sizeof(entry_guard_t));
+ entry->is_persistent = 1;
log_info(LD_CIRC, "Chose %s as new entry guard.",
node_describe(node));
strlcpy(entry->nickname, node_get_nickname(node), sizeof(entry->nickname));
@@ -3020,6 +3153,7 @@ entry_guard_free(entry_guard_t *e)
tor_free(e->sampled_by_version);
tor_free(e->extra_state_fields);
tor_free(e->selection_name);
+ tor_free(e->bridge_addr);
tor_free(e);
}
@@ -3840,6 +3974,7 @@ entry_guards_parse_state_for_guard_selection(
node = tor_malloc_zero(sizeof(entry_guard_t));
/* all entry guards on disk have been contacted */
node->made_contact = 1;
+ node->is_persistent = 1;
smartlist_add(new_entry_guards, node);
smartlist_split_string(args, line->value, " ",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index 0abbea8..cbc3f89 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -125,7 +125,9 @@ struct entry_guard_t {
* Which selection does this guard belong to?
*/
char *selection_name;
- guard_selection_t *in_selection;
+
+ /** Bridges only: address of the bridge. */
+ tor_addr_port_t *bridge_addr;
/* ==== Non-persistent fields. */
/* == These are used by sampled guards */
@@ -140,6 +142,9 @@ struct entry_guard_t {
* to try again until it either succeeds or fails. Primary guards can
* never be pending. */
unsigned is_pending : 1;
+ /** If true, don't write this guard to disk. (Used for bridges with unknown
+ * identities) */
+ unsigned is_persistent : 1;
/** When did we get the earliest connection failure for this guard?
* We clear this field on a successful connect. We do _not_ clear it
* when we mark the guard as "MAYBE" reachable.
@@ -160,6 +165,9 @@ struct entry_guard_t {
/** This string holds any fields that we are maintaining because
* we saw them in the state, even if we don't understand them. */
char *extra_state_fields;
+
+ /** Backpointer to the guard selection that this guard belongs to. */
+ guard_selection_t *in_selection;
/**@}*/
/**
@@ -554,6 +562,14 @@ STATIC int entry_is_time_to_retry(const entry_guard_t *e, time_t now);
void remove_all_entry_guards_for_guard_selection(guard_selection_t *gs);
void remove_all_entry_guards(void);
+struct bridge_info_t;
+// XXXX prop271 should this be a public API?
+entry_guard_t *entry_guard_add_bridge_to_sample(
+ const struct bridge_info_t *bridge);
+
+void entry_guard_learned_bridge_identity(const tor_addr_port_t *addrport,
+ const uint8_t *rsa_id_digest);
+
void entry_guards_compute_status_for_guard_selection(
guard_selection_t *gs, const or_options_t *options, time_t now);
void entry_guards_compute_status(const or_options_t *options, time_t now);
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index bc0862a..32af7ff 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -1055,6 +1055,9 @@ test_entry_guard_encode_for_state_maximal(void *arg)
strlcpy(eg->nickname, "Fred", sizeof(eg->nickname));
eg->selection_name = tor_strdup("default");
memcpy(eg->identity, "plurpyflurpyslurpydo", DIGEST_LEN);
+ eg->bridge_addr = tor_malloc_zero(sizeof(tor_addr_port_t));
+ tor_addr_from_ipv4h(&eg->bridge_addr->addr, 0x08080404);
+ eg->bridge_addr->port = 9999;
eg->sampled_on_date = 1479081600;
eg->sampled_by_version = tor_strdup("1.2.3");
eg->unlisted_since_date = 1479081645;
@@ -1069,6 +1072,7 @@ test_entry_guard_encode_for_state_maximal(void *arg)
tt_str_op(s, OP_EQ,
"in=default "
"rsa_id=706C75727079666C75727079736C75727079646F "
+ "bridge_addr=8.8.4.4:9999 "
"nickname=Fred "
"sampled_on=2016-11-14T00:00:00 "
"sampled_by=1.2.3 "
@@ -1100,6 +1104,7 @@ test_entry_guard_parse_from_state_minimal(void *arg)
test_mem_op_hex(eg->identity, OP_EQ,
"596f75206d6179206e656564206120686f626279");
tt_str_op(eg->nickname, OP_EQ, "$596F75206D6179206E656564206120686F626279");
+ tt_ptr_op(eg->bridge_addr, OP_EQ, NULL);
tt_i64_op(eg->sampled_on_date, OP_GE, t);
tt_i64_op(eg->sampled_on_date, OP_LE, t+86400);
tt_i64_op(eg->unlisted_since_date, OP_EQ, 0);
@@ -1126,6 +1131,7 @@ test_entry_guard_parse_from_state_maximal(void *arg)
eg = entry_guard_parse_from_state(
"in=fred "
"rsa_id=706C75727079666C75727079736C75727079646F "
+ "bridge_addr=[1::3]:9999 "
"nickname=Fred "
"sampled_on=2016-11-14T00:00:00 "
"sampled_by=1.2.3 "
@@ -1139,6 +1145,8 @@ test_entry_guard_parse_from_state_maximal(void *arg)
test_mem_op_hex(eg->identity, OP_EQ,
"706C75727079666C75727079736C75727079646F");
+ tt_str_op(fmt_addr(&eg->bridge_addr->addr), OP_EQ, "1::3");
+ tt_int_op(eg->bridge_addr->port, OP_EQ, 9999);
tt_str_op(eg->nickname, OP_EQ, "Fred");
tt_i64_op(eg->sampled_on_date, OP_EQ, 1479081600);
tt_i64_op(eg->unlisted_since_date, OP_EQ, 1479081645);
@@ -1205,6 +1213,7 @@ test_entry_guard_parse_from_state_partial_failure(void *arg)
eg = entry_guard_parse_from_state(
"in=default "
"rsa_id=706C75727079666C75727079736C75727079646F "
+ "bridge_addr=1.2.3.3.4:5 "
"nickname=FredIsANodeWithAStrangeNicknameThatIsTooLong "
"sampled_on=2016-11-14T00:00:99 "
"sampled_by=1.2.3 stuff in the middle "
@@ -1219,6 +1228,7 @@ test_entry_guard_parse_from_state_partial_failure(void *arg)
test_mem_op_hex(eg->identity, OP_EQ,
"706C75727079666C75727079736C75727079646F");
tt_str_op(eg->nickname, OP_EQ, "FredIsANodeWithAStrangeNicknameThatIsTooL");
+ tt_ptr_op(eg->bridge_addr, OP_EQ, NULL);
tt_i64_op(eg->sampled_on_date, OP_EQ, t);
tt_i64_op(eg->unlisted_since_date, OP_EQ, 0);
tt_str_op(eg->sampled_by_version, OP_EQ, "1.2.3");
1
0
[tor/master] Change return value of entry_guard_succeeded to an enum.
by nickm@torproject.org 16 Dec '16
by nickm@torproject.org 16 Dec '16
16 Dec '16
commit 84bfa895d725338d92f677a31a4dcf6381845e0c
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Nov 29 11:47:12 2016 -0500
Change return value of entry_guard_succeeded to an enum.
George pointed out that (-1,0,1) for (never usable, maybe usable
later, usable right now) was a pretty rotten convention that made
the code harder to read.
---
src/or/circuitbuild.c | 13 +++++++------
src/or/entrynodes.c | 28 +++++++++++++---------------
src/or/entrynodes.h | 7 ++++++-
src/test/test_entrynodes.c | 29 ++++++++++++++++-------------
4 files changed, 42 insertions(+), 35 deletions(-)
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 5d0a04f..c7e116e 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -964,28 +964,29 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
memset(&ec, 0, sizeof(ec));
if (!hop) {
/* done building the circuit. whew. */
- int r;
+ guard_usable_t r;
if (get_options()->UseDeprecatedGuardAlgorithm) {
// The circuit is usable; we already marked the guard as okay.
- r = 1;
+ r = GUARD_USABLE_NOW;
} else if (! circ->guard_state) {
if (circuit_get_cpath_len(circ) != 1) {
log_warn(LD_BUG, "%d-hop circuit %p with purpose %d has no "
"guard state",
circuit_get_cpath_len(circ), circ, circ->base_.purpose);
}
- r = 1;
+ r = GUARD_USABLE_NOW;
} else {
r = entry_guard_succeeded(&circ->guard_state);
}
- const int is_usable_for_streams = (r == 1);
- if (r == 1) {
+ const int is_usable_for_streams = (r == GUARD_USABLE_NOW);
+ if (r == GUARD_USABLE_NOW) {
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
- } else if (r == 0) {
+ } else if (r == GUARD_MAYBE_USABLE_LATER) {
// XXXX prop271 we might want to probe for whether this
// XXXX one is ready even before the next second rolls over.
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_GUARD_WAIT);
} else {
+ tor_assert_nonfatal(r == GUARD_USABLE_NEVER);
return - END_CIRC_REASON_INTERNAL;
}
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index af1869f..aa90566 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -1965,28 +1965,26 @@ entry_guard_pick_for_circuit(guard_selection_t *gs,
}
/**
- * Called by the circuit building module when a circuit has succeeded:
- * informs the guards code that the guard in *<b>guard_state_p</b> is
- * working, and advances the state of the guard module. On a -1 return
- * value, the circuit is broken and should not be used. On a 1 return
- * value, the circuit is ready to use. On a 0 return value, the circuit
- * should not be used until we find out whether preferred guards will
- * work for us.
- *
- * XXXXX prop271 tristates are ugly; reconsider that interface.
+ * Called by the circuit building module when a circuit has succeeded: informs
+ * the guards code that the guard in *<b>guard_state_p</b> is working, and
+ * advances the state of the guard module. On a GUARD_USABLE_NEVER return
+ * value, the circuit is broken and should not be used. On a GUARD_USABLE_NOW
+ * return value, the circuit is ready to use. On a GUARD_MAYBE_USABLE_LATER
+ * return value, the circuit should not be used until we find out whether
+ * preferred guards will work for us.
*/
-int
+guard_usable_t
entry_guard_succeeded(circuit_guard_state_t **guard_state_p)
{
if (get_options()->UseDeprecatedGuardAlgorithm)
- return 1;
+ return GUARD_USABLE_NOW;
if (BUG(*guard_state_p == NULL))
- return -1;
+ return GUARD_USABLE_NEVER;
entry_guard_t *guard = entry_guard_handle_get((*guard_state_p)->guard);
if (! guard || BUG(guard->in_selection == NULL))
- return -1;
+ return GUARD_USABLE_NEVER;
unsigned newstate =
entry_guards_note_guard_success(guard->in_selection, guard,
@@ -1996,9 +1994,9 @@ entry_guard_succeeded(circuit_guard_state_t **guard_state_p)
(*guard_state_p)->state_set_at = approx_time();
if (newstate == GUARD_CIRC_STATE_COMPLETE) {
- return 1;
+ return GUARD_USABLE_NOW;
} else {
- return 0;
+ return GUARD_MAYBE_USABLE_LATER;
}
}
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index 21dab6e..ceccd0f 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -359,7 +359,12 @@ void circuit_guard_state_free(circuit_guard_state_t *state);
int entry_guard_pick_for_circuit(guard_selection_t *gs,
const node_t **chosen_node_out,
circuit_guard_state_t **guard_state_out);
-int entry_guard_succeeded(circuit_guard_state_t **guard_state_p);
+typedef enum {
+ GUARD_USABLE_NEVER = -1,
+ GUARD_MAYBE_USABLE_LATER = 0,
+ GUARD_USABLE_NOW = 1,
+} guard_usable_t;
+guard_usable_t entry_guard_succeeded(circuit_guard_state_t **guard_state_p);
void entry_guard_failed(circuit_guard_state_t **guard_state_p);
void entry_guard_cancel(circuit_guard_state_t **guard_state_p);
void entry_guard_chan_failed(channel_t *chan);
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index 32af7ff..6a3048b 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -2324,6 +2324,7 @@ test_entry_guard_select_for_circuit_highlevel_primary(void *arg)
const node_t *node = NULL;
circuit_guard_state_t *guard = NULL;
entry_guard_t *g;
+ guard_usable_t u;
/*
* Make sure that the pick-for-circuit API basically works. We'll get
* a primary guard, so it'll be usable on completion.
@@ -2343,8 +2344,8 @@ test_entry_guard_select_for_circuit_highlevel_primary(void *arg)
/* Call that circuit successful. */
update_approx_time(start+15);
- r = entry_guard_succeeded(&guard);
- tt_int_op(r, OP_EQ, 1); /* We can use it now. */
+ u = entry_guard_succeeded(&guard);
+ tt_int_op(u, OP_EQ, GUARD_USABLE_NOW); /* We can use it now. */
tt_assert(guard);
tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
g = entry_guard_handle_get(guard->guard);
@@ -2411,8 +2412,8 @@ test_entry_guard_select_for_circuit_highlevel_primary(void *arg)
/* Call this one up; watch it get confirmed. */
update_approx_time(start+90);
- r = entry_guard_succeeded(&guard);
- tt_int_op(r, OP_EQ, 1); /* We can use it now. */
+ u = entry_guard_succeeded(&guard);
+ tt_int_op(u, OP_EQ, GUARD_USABLE_NOW);
tt_assert(guard);
tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
g = entry_guard_handle_get(guard->guard);
@@ -2440,6 +2441,7 @@ test_entry_guard_select_for_circuit_highlevel_confirm_other(void *arg)
circuit_guard_state_t *guard = NULL;
int i, r;
const node_t *node = NULL;
+ guard_usable_t u;
/* Declare that we're on the internet. */
entry_guards_note_internet_connectivity(gs);
@@ -2471,13 +2473,13 @@ test_entry_guard_select_for_circuit_highlevel_confirm_other(void *arg)
tt_int_op(g->is_pending, OP_EQ, 1);
(void)start;
- r = entry_guard_succeeded(&guard);
+ u = entry_guard_succeeded(&guard);
/* We're on the internet (by fiat), so this guard will get called "confirmed"
* and should immediately become primary.
* XXXX prop271 -- I don't like that behavior, but it's what is specified
*/
tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
- tt_assert(r == 1);
+ tt_assert(u == GUARD_USABLE_NOW);
tt_int_op(g->confirmed_idx, OP_EQ, 0);
tt_int_op(g->is_primary, OP_EQ, 1);
tt_int_op(g->is_pending, OP_EQ, 0);
@@ -2503,6 +2505,7 @@ test_entry_guard_select_for_circuit_highlevel_primary_retry(void *arg)
int i, r;
const node_t *node = NULL;
entry_guard_t *g;
+ guard_usable_t u;
/* Declare that we're on the internet. */
entry_guards_note_internet_connectivity(gs);
@@ -2540,8 +2543,8 @@ test_entry_guard_select_for_circuit_highlevel_primary_retry(void *arg)
update_approx_time(start + 3600);
/* Say that guard has succeeded! */
- r = entry_guard_succeeded(&guard);
- tt_int_op(r, OP_EQ, 0); // can't use it yet.
+ u = entry_guard_succeeded(&guard);
+ tt_int_op(u, OP_EQ, GUARD_MAYBE_USABLE_LATER);
tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD);
g = entry_guard_handle_get(guard->guard);
@@ -2556,8 +2559,8 @@ test_entry_guard_select_for_circuit_highlevel_primary_retry(void *arg)
r = entry_guard_pick_for_circuit(gs, &node, &guard2);
tt_assert(r == 0);
tt_int_op(guard2->state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
- r = entry_guard_succeeded(&guard2);
- tt_assert(r == 1);
+ u = entry_guard_succeeded(&guard2);
+ tt_assert(u == GUARD_USABLE_NOW);
tt_int_op(guard2->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
tt_assert(! entry_guards_all_primary_guards_are_down(gs));
@@ -2689,18 +2692,18 @@ upgrade_circuits_setup(const struct testcase_t *testcase)
tor_assert(data->guard2_state->state ==
GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD);
- int r;
+ guard_usable_t r;
update_approx_time(data->start + 32);
if (make_circ1_succeed) {
r = entry_guard_succeeded(&data->guard1_state);
- tor_assert(r == 0);
+ tor_assert(r == GUARD_MAYBE_USABLE_LATER);
tor_assert(data->guard1_state->state ==
GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD);
}
update_approx_time(data->start + 33);
if (make_circ2_succeed) {
r = entry_guard_succeeded(&data->guard2_state);
- tor_assert(r == 0);
+ tor_assert(r == GUARD_MAYBE_USABLE_LATER);
tor_assert(data->guard2_state->state ==
GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD);
}
1
0
[tor/master] Fix for small test networks: don't refuse to have any sampled guards.
by nickm@torproject.org 16 Dec '16
by nickm@torproject.org 16 Dec '16
16 Dec '16
commit 80fa404625b757cbde07be76abf848efadab7c46
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Tue Nov 29 12:48:32 2016 -0500
Fix for small test networks: don't refuse to have any sampled guards.
Don't restrict the sample size if the network size is less than 20
guards. Maybe we'll think of a better rule later on?
---
src/or/entrynodes.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 3ba0179..8380dbf 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -891,6 +891,23 @@ num_reachable_filtered_guards(guard_selection_t *gs)
return n_reachable_filtered_guards;
}
+/** Return the actual maximum size for the sample in <b>gs</b>,
+ * given that we know about <b>n_guards</b> total. */
+static int
+get_max_sample_size(guard_selection_t *gs,
+ int n_guards)
+{
+ const int using_bridges = (gs->type == GS_TYPE_BRIDGE);
+
+ /* XXXX prop271 spec deviation with bridges, max_sample is "all of them" */
+ if (using_bridges)
+ return n_guards;
+ else if (n_guards < 20) // XXXX prop271 spec deviation
+ return n_guards;
+ else
+ return (int)(n_guards * get_max_sample_threshold());
+}
+
/**
* Return a smartlist of the all the guards that are not currently
* members of the sample (GUARDS - SAMPLED_GUARDS). The elements of
@@ -987,11 +1004,7 @@ entry_guards_expand_sample(guard_selection_t *gs)
int n_guards = 0;
smartlist_t *eligible_guards = get_eligible_guards(gs, &n_guards);
- const int using_bridges = (gs->type == GS_TYPE_BRIDGE);
-
- /* XXXX prop271 spec deviation with bridges, max_sample is "all of them" */
- const int max_sample = using_bridges ? n_guards :
- (int)(n_guards * get_max_sample_threshold());
+ const int max_sample = get_max_sample_size(gs, n_guards);
const int min_filtered_sample = get_min_filtered_sample_size();
log_info(LD_GUARD, "Expanding the sample guard set. We have %d guards "
1
0