[tor-commits] [tor/master] Implement support for per-circuit guard restrictions.

nickm at torproject.org nickm at torproject.org
Fri Dec 16 16:26:19 UTC 2016


commit 87f9b42179bd23418c3e698938bdeead56da1c43
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Nov 30 08:49:39 2016 -0500

    Implement support for per-circuit guard restrictions.
    
    This is an important thing I hadn't considered when writing prop271:
    sometimes you have to restrict what guard you use for a particular
    circuit.  Most frequently, that would be because you plan to use a
    certain node as your exit, and so you can't choose that for your
    guard.
    
    This change means that the upgrade-waiting-circuits algorithm needs
    a slight tweak too: circuit A cannot block circuit B from upgrading
    if circuit B needs to follow a restriction that circuit A does not
    follow.
---
 src/or/circuitbuild.c      |  15 +++++-
 src/or/circuitbuild.h      |   1 +
 src/or/entrynodes.c        | 122 ++++++++++++++++++++++++++++++++++++++-------
 src/or/entrynodes.h        |  38 +++++++++++++-
 src/test/test_entrynodes.c |  92 +++++++++++++++++-----------------
 5 files changed, 200 insertions(+), 68 deletions(-)

diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index c7e116e..0790309 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -2515,8 +2515,8 @@ extend_info_dup(extend_info_t *info)
   return newinfo;
 }
 
-/** Return the routerinfo_t for the chosen exit router in <b>state</b>.
- * If there is no chosen exit, or if we don't know the routerinfo_t for
+/** Return the node_t for the chosen exit router in <b>state</b>.
+ * If there is no chosen exit, or if we don't know the node_t for
  * the chosen exit, return NULL.
  */
 const node_t *
@@ -2527,6 +2527,17 @@ build_state_get_exit_node(cpath_build_state_t *state)
   return node_get_by_id(state->chosen_exit->identity_digest);
 }
 
+/** Return the RSA ID digest for the chosen exit router in <b>state</b>.
+ * If there is no chosen exit, return NULL.
+ */
+const uint8_t *
+build_state_get_exit_rsa_id(cpath_build_state_t *state)
+{
+  if (!state || !state->chosen_exit)
+    return NULL;
+  return (const uint8_t *) state->chosen_exit->identity_digest;
+}
+
 /** Return the nickname for the chosen exit router in <b>state</b>. If
  * there is no chosen exit, or if we don't know the routerinfo_t for the
  * chosen exit, return NULL.
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index 2c83a16..b85dbec 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -61,6 +61,7 @@ int extend_info_supports_ntor(const extend_info_t* ei);
 int circuit_can_use_tap(const origin_circuit_t *circ);
 int circuit_has_usable_onion_key(const origin_circuit_t *circ);
 int extend_info_has_preferred_onion_key(const extend_info_t* ei);
+const uint8_t *build_state_get_exit_rsa_id(cpath_build_state_t *state);
 const node_t *build_state_get_exit_node(cpath_build_state_t *state);
 const char *build_state_get_exit_nickname(cpath_build_state_t *state);
 
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index dd3a890..9b38641 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -168,6 +168,8 @@ static entry_guard_t *entry_guard_add_to_sample_impl(guard_selection_t *gs,
                                const tor_addr_port_t *bridge_addrport);
 static entry_guard_t *get_sampled_guard_by_bridge_addr(guard_selection_t *gs,
                                               const tor_addr_port_t *addrport);
+static int entry_guard_obeys_restriction(const entry_guard_t *guard,
+                                         const entry_guard_restriction_t *rst);
 
 /** Return 0 if we should apply guardfraction information found in the
  *  consensus. A specific consensus can be specified with the
@@ -878,13 +880,20 @@ entry_guard_learned_bridge_identity(const tor_addr_port_t *addrport,
 /**
  * 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"). */
+ * (that is, either "reachable" or "maybe reachable").
+ *
+ * If a restriction is provided in <b>rst</b>, do not count any guards that
+ * violate it.
+ */
 STATIC int
-num_reachable_filtered_guards(guard_selection_t *gs)
+num_reachable_filtered_guards(guard_selection_t *gs,
+                              const entry_guard_restriction_t *rst)
 {
   int n_reachable_filtered_guards = 0;
   SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) {
     entry_guard_consider_retry(guard);
+    if (! entry_guard_obeys_restriction(guard, rst))
+      continue;
     if (guard->is_usable_filtered_guard)
       ++n_reachable_filtered_guards;
   } SMARTLIST_FOREACH_END(guard);
@@ -1003,7 +1012,7 @@ entry_guards_expand_sample(guard_selection_t *gs)
   tor_assert(gs);
   int n_sampled = smartlist_len(gs->sampled_entry_guards);
   entry_guard_t *added_guard = NULL;
-  int n_usable_filtered_guards = num_reachable_filtered_guards(gs);
+  int n_usable_filtered_guards = num_reachable_filtered_guards(gs, NULL);
   int n_guards = 0;
   smartlist_t *eligible_guards = get_eligible_guards(gs, &n_guards);
 
@@ -1324,6 +1333,22 @@ entry_guard_passes_filter(const or_options_t *options, guard_selection_t *gs,
 }
 
 /**
+ * Return true iff <b>guard</b> obeys the restrictions defined in <b>rst</b>.
+ * (If <b>rst</b> is NULL, there are no restrictions.)
+ */
+static int
+entry_guard_obeys_restriction(const entry_guard_t *guard,
+                              const entry_guard_restriction_t *rst)
+{
+  tor_assert(guard);
+  if (! rst)
+    return 1; // No restriction?  No problem.
+
+  // Only one kind of restriction exists right now
+  return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN);
+}
+
+/**
  * Update the <b>is_filtered_guard</b> and <b>is_usable_filtered_guard</b>
  * flags on <b>guard</b>. */
 void
@@ -1373,9 +1398,13 @@ entry_guards_update_filtered_sets(guard_selection_t *gs)
  *
  * Make sure that the sample is big enough, and that all the filter flags
  * are set correctly, before calling this function.
+ *
+ * If a restriction is provided in <b>rst</b>, do not return any guards that
+ * violate it.
  **/
 STATIC entry_guard_t *
 sample_reachable_filtered_entry_guards(guard_selection_t *gs,
+                                       const entry_guard_restriction_t *rst,
                                        unsigned flags)
 {
   tor_assert(gs);
@@ -1389,7 +1418,7 @@ sample_reachable_filtered_entry_guards(guard_selection_t *gs,
     entry_guard_consider_retry(guard);
   } SMARTLIST_FOREACH_END(guard);
 
-  const int n_reachable_filtered = num_reachable_filtered_guards(gs);
+  const int n_reachable_filtered = num_reachable_filtered_guards(gs, rst);
 
   log_info(LD_GUARD, "Trying to sample a reachable guard: We know of %d "
            "in the USABLE_FILTERED set.", n_reachable_filtered);
@@ -1407,6 +1436,8 @@ sample_reachable_filtered_entry_guards(guard_selection_t *gs,
   smartlist_t *reachable_filtered_sample = smartlist_new();
   SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) {
     entry_guard_consider_retry(guard);// redundant, but cheap.
+    if (! entry_guard_obeys_restriction(guard, rst))
+      continue;
     if (! guard->is_usable_filtered_guard)
       continue;
     if (exclude_confirmed && guard->confirmed_idx >= 0)
@@ -1568,7 +1599,7 @@ entry_guards_update_primary(guard_selection_t *gs)
 
   /* Finally, fill out the list with sampled guards. */
   while (smartlist_len(new_primary_guards) < N_PRIMARY_GUARDS) {
-    entry_guard_t *guard = sample_reachable_filtered_entry_guards(gs,
+    entry_guard_t *guard = sample_reachable_filtered_entry_guards(gs, NULL,
                                             SAMPLE_EXCLUDE_CONFIRMED|
                                             SAMPLE_EXCLUDE_PRIMARY|
                                             SAMPLE_NO_UPDATE_PRIMARY);
@@ -1708,7 +1739,9 @@ entry_guards_note_internet_connectivity(guard_selection_t *gs)
  * of the circuit.
  */
 STATIC entry_guard_t *
-select_entry_guard_for_circuit(guard_selection_t *gs, unsigned *state_out)
+select_entry_guard_for_circuit(guard_selection_t *gs,
+                               const entry_guard_restriction_t *rst,
+                               unsigned *state_out)
 {
   /*XXXX prop271 consider splitting this function up. */
   tor_assert(gs);
@@ -1721,6 +1754,8 @@ select_entry_guard_for_circuit(guard_selection_t *gs, unsigned *state_out)
       <maybe> or <yes>, return the first such guard." */
   SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards, entry_guard_t *, guard) {
     entry_guard_consider_retry(guard);
+    if (! entry_guard_obeys_restriction(guard, rst))
+      continue;
     if (guard->is_reachable != GUARD_REACHABLE_NO) {
       *state_out = GUARD_CIRC_STATE_USABLE_ON_COMPLETION;
       guard->last_tried_to_connect = approx_time();
@@ -1737,6 +1772,8 @@ select_entry_guard_for_circuit(guard_selection_t *gs, unsigned *state_out)
   SMARTLIST_FOREACH_BEGIN(gs->confirmed_entry_guards, entry_guard_t *, guard) {
     if (guard->is_primary)
       continue; /* we already considered this one. */
+    if (! entry_guard_obeys_restriction(guard, rst))
+      continue;
     entry_guard_consider_retry(guard);
     if (guard->is_usable_filtered_guard && ! guard->is_pending) {
       guard->is_pending = 1;
@@ -1755,6 +1792,7 @@ select_entry_guard_for_circuit(guard_selection_t *gs, unsigned *state_out)
   {
     entry_guard_t *guard;
     guard = sample_reachable_filtered_entry_guards(gs,
+                                                   rst,
                                                    SAMPLE_EXCLUDE_CONFIRMED |
                                                    SAMPLE_EXCLUDE_PRIMARY |
                                                    SAMPLE_EXCLUDE_PENDING);
@@ -1925,6 +1963,13 @@ entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b)
   }
 }
 
+/** Release all storage held in <b>restriction</b> */
+static void
+entry_guard_restriction_free(entry_guard_restriction_t *rst)
+{
+  tor_free(rst);
+}
+
 /**
  * Release all storage held in <b>state</b>.
  */
@@ -1933,6 +1978,7 @@ circuit_guard_state_free(circuit_guard_state_t *state)
 {
   if (!state)
     return;
+  entry_guard_restriction_free(state->restrictions);
   entry_guard_handle_free(state->guard);
   tor_free(state);
 }
@@ -1942,9 +1988,14 @@ circuit_guard_state_free(circuit_guard_state_t *state)
  * in *<b>chosen_node_out</b>. Set *<b>guard_state_out</b> to an opaque
  * state object that will record whether the circuit is ready to be used
  * or not. Return 0 on success; on failure, return -1.
+ *
+ * If a restriction is provided in <b>rst</b>, do not return any guards that
+ * violate it, and remember that restriction in <b>guard_state_out</b> for
+ * later use. (Takes ownership of the <b>rst</b> object.)
  */
 int
 entry_guard_pick_for_circuit(guard_selection_t *gs,
+                             entry_guard_restriction_t *rst,
                              const node_t **chosen_node_out,
                              circuit_guard_state_t **guard_state_out)
 {
@@ -1955,23 +2006,27 @@ entry_guard_pick_for_circuit(guard_selection_t *gs,
   *guard_state_out = NULL;
 
   unsigned state = 0;
-  entry_guard_t *guard = select_entry_guard_for_circuit(gs, &state);
+  entry_guard_t *guard = select_entry_guard_for_circuit(gs, rst, &state);
   if (! guard)
-    return -1;
+    goto fail;
   if (BUG(state == 0))
-    return -1;
+    goto fail;
   const node_t *node = node_get_by_id(guard->identity);
   // XXXX prop271 check Ed ID.
   if (! node)
-    return -1;
+    goto fail;
 
   *chosen_node_out = node;
   *guard_state_out = tor_malloc_zero(sizeof(circuit_guard_state_t));
   (*guard_state_out)->guard = entry_guard_handle_new(guard);
   (*guard_state_out)->state = state;
   (*guard_state_out)->state_set_at = approx_time();
+  (*guard_state_out)->restrictions = rst;
 
   return 0;
+ fail:
+  entry_guard_restriction_free(rst);
+  return -1;
 }
 
 /**
@@ -2098,9 +2153,14 @@ entry_guards_all_primary_guards_are_down(guard_selection_t *gs)
 }
 
 /** Wrapper for entry_guard_has_higher_priority that compares the
- * guard-priorities of a pair of circuits. */
+ * guard-priorities of a pair of circuits.
+ *
+ * If a restriction is provided in <b>rst</b>, then do not consider
+ * <b>a</b> to have higher priority if it violates the restriction.
+ */
 static int
 circ_state_has_higher_priority(origin_circuit_t *a,
+                               const entry_guard_restriction_t *rst,
                                origin_circuit_t *b)
 {
   circuit_guard_state_t *state_a = origin_circuit_get_guard_state(a);
@@ -2118,6 +2178,9 @@ circ_state_has_higher_priority(origin_circuit_t *a,
   } else if (! guard_b) {
     /* Known guard -- higher priority than any unknown guard. */
     return 1;
+  } else  if (! entry_guard_obeys_restriction(guard_a, rst)) {
+    /* Restriction violated; guard_a cannot have higher priority. */
+    return 0;
   } else {
     /* Both known -- compare.*/
     return entry_guard_has_higher_priority(guard_a, guard_b);
@@ -2175,13 +2238,13 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
     if (state->state == GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD) {
       ++n_waiting;
       if (! best_waiting_circuit ||
-          circ_state_has_higher_priority(circ, best_waiting_circuit)) {
+          circ_state_has_higher_priority(circ, NULL, best_waiting_circuit)) {
         best_waiting_circuit = circ;
       }
     } else if (state->state == GUARD_CIRC_STATE_COMPLETE) {
       ++n_complete;
       if (! best_complete_circuit ||
-          circ_state_has_higher_priority(circ, best_complete_circuit)) {
+          circ_state_has_higher_priority(circ, NULL, best_complete_circuit)) {
         best_complete_circuit = circ;
       }
     }
@@ -2193,8 +2256,15 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
     goto no_change;
   }
 
+  /* We'll need to keep track of what restrictions were used when picking this
+   * circuit, so that we don't allow any circuit without those restrictions to
+   * block it. */
+  const entry_guard_restriction_t *rst_on_best_waiting =
+    origin_circuit_get_guard_state(best_waiting_circuit)->restrictions;
+
   if (best_complete_circuit) {
     if (circ_state_has_higher_priority(best_complete_circuit,
+                                       rst_on_best_waiting,
                                        best_waiting_circuit)) {
       /* "If any circuit is <complete>, then do not use any
          <waiting_for_better_guard> or <usable_if_no_better_guard> circuits
@@ -2225,8 +2295,10 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
       continue;
     if (state->state != GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD)
       continue;
-    if (state->state_set_at > state_set_at_cutoff &&
-        circ_state_has_higher_priority(circ, best_waiting_circuit))
+    if (state->state_set_at <= state_set_at_cutoff)
+      continue;
+    if (circ_state_has_higher_priority(circ, rst_on_best_waiting,
+                                       best_waiting_circuit))
       ++n_blockers_found;
   } SMARTLIST_FOREACH_END(circ);
 
@@ -2246,9 +2318,14 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
     circuit_guard_state_t *state = origin_circuit_get_guard_state(circ);
     if (BUG(state == NULL))
       continue;
+    if (circ != best_waiting_circuit && rst_on_best_waiting) {
+      /* Can't upgrade other circ with same priority as best; might
+         be blocked. */
+      continue;
+    }
     if (state->state != GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD)
       continue;
-    if (circ_state_has_higher_priority(best_waiting_circuit, circ))
+    if (circ_state_has_higher_priority(best_waiting_circuit, NULL, circ))
       continue;
 
     state->state = GUARD_CIRC_STATE_COMPLETE;
@@ -4759,10 +4836,18 @@ guards_choose_guard(cpath_build_state_t *state,
   if (get_options()->UseDeprecatedGuardAlgorithm) {
     return choose_random_entry(state);
   } else {
-    // XXXX prop271 we need to look at the chosen exit node if any, and
-    // not duplicate it.
     const node_t *r = NULL;
+    const uint8_t *exit_id = NULL;
+    entry_guard_restriction_t *rst = NULL;
+    // XXXX prop271 spec deviation -- use of restriction here.
+    if (state && (exit_id = build_state_get_exit_rsa_id(state))) {
+      /* We're building to a targeted exit node, so that node can't be
+       * chosen as our guard for this circuit. */
+      rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
+      memcpy(rst->exclude_id, exit_id, DIGEST_LEN);
+    }
     if (entry_guard_pick_for_circuit(get_guard_selection_info(),
+                                     rst,
                                      &r,
                                      guard_state_out) < 0) {
       tor_assert(r == NULL);
@@ -4788,6 +4873,7 @@ guards_choose_dirguard(dirinfo_type_t info,
      * microdescriptors. -NM */
     const node_t *r = NULL;
     if (entry_guard_pick_for_circuit(get_guard_selection_info(),
+                                     NULL,
                                      &r,
                                      guard_state_out) < 0) {
       tor_assert(r == NULL);
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index 4ea60e8..753d6f7 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -24,6 +24,10 @@ typedef struct entry_guard_t entry_guard_t;
    private. */
 typedef struct circuit_guard_state_t circuit_guard_state_t;
 
+/* Forward declaration for entry_guard_restriction_t; the real declaration is
+   private. */
+typedef struct entry_guard_restriction_t entry_guard_restriction_t;
+
 /* Information about a guard's pathbias status.
  * These fields are used in circpathbias.c to try to detect entry
  * nodes that are failing circuits at a suspicious frequency.
@@ -311,6 +315,24 @@ struct guard_selection_s {
 struct entry_guard_handle_t;
 
 /**
+ * A restriction to remember which entry guards are off-limits for a given
+ * circuit.
+ *
+ * Right now, we only use restrictions to block a single guard from being
+ * selected; this mechanism is designed to be more extensible in the future,
+ * however.
+ *
+ * Note: This mechanism is NOT for recording which guards are never to be
+ * used: only which guards cannot be used on <em>one particular circuit</em>.
+ */
+struct entry_guard_restriction_t {
+  /**
+   * The guard's RSA identity digest must not equal this.
+   */
+  uint8_t exclude_id[DIGEST_LEN];
+};
+
+/**
  * Per-circuit state to track whether we'll be able to use the circuit.
  */
 struct circuit_guard_state_t {
@@ -320,6 +342,14 @@ struct circuit_guard_state_t {
   time_t state_set_at;
   /** One of GUARD_CIRC_STATE_* */
   uint8_t state;
+
+  /**
+   * A set of restrictions that were placed on this guard when we selected it
+   * for this particular circuit.  We need to remember the restrictions here,
+   * since any guard that breaks these restrictions will not block this
+   * circuit from becoming COMPLETE.
+   */
+  entry_guard_restriction_t *restrictions;
 };
 #endif
 
@@ -356,6 +386,7 @@ guard_pathbias_t *entry_guard_get_pathbias_state(entry_guard_t *guard);
 
 void circuit_guard_state_free(circuit_guard_state_t *state);
 int entry_guard_pick_for_circuit(guard_selection_t *gs,
+                                 entry_guard_restriction_t *rst,
                                  const node_t **chosen_node_out,
                                  circuit_guard_state_t **guard_state_out);
 typedef enum {
@@ -491,12 +522,14 @@ STATIC int entry_guards_all_primary_guards_are_down(guard_selection_t *gs);
 /**@}*/
 STATIC entry_guard_t *sample_reachable_filtered_entry_guards(
                                     guard_selection_t *gs,
+                                    const entry_guard_restriction_t *rst,
                                     unsigned flags);
 STATIC void entry_guard_consider_retry(entry_guard_t *guard);
 STATIC void make_guard_confirmed(guard_selection_t *gs, entry_guard_t *guard);
 STATIC void entry_guards_update_confirmed(guard_selection_t *gs);
 STATIC void entry_guards_update_primary(guard_selection_t *gs);
-STATIC int num_reachable_filtered_guards(guard_selection_t *gs);
+STATIC int num_reachable_filtered_guards(guard_selection_t *gs,
+                                         const entry_guard_restriction_t *rst);
 STATIC void sampled_guards_update_from_consensus(guard_selection_t *gs);
 /**
  * @name Possible guard-states for a circuit.
@@ -522,7 +555,8 @@ STATIC void sampled_guards_update_from_consensus(guard_selection_t *gs);
 STATIC void entry_guards_note_guard_failure(guard_selection_t *gs,
                                             entry_guard_t *guard);
 STATIC entry_guard_t *select_entry_guard_for_circuit(guard_selection_t *gs,
-                                                     unsigned *state_out);
+                                          const entry_guard_restriction_t *rst,
+                                          unsigned *state_out);
 STATIC void mark_primary_guards_maybe_reachable(guard_selection_t *gs);
 STATIC unsigned entry_guards_note_guard_success(guard_selection_t *gs,
                                                 entry_guard_t *guard,
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index e3a9d18..0921e20 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -1353,7 +1353,7 @@ test_entry_guard_node_filter(void *arg)
     tt_assert(g[i]->is_filtered_guard == 1);
     tt_assert(g[i]->is_usable_filtered_guard == 1);
   }
-  tt_int_op(num_reachable_filtered_guards(gs), OP_EQ, NUM);
+  tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, NUM);
 
   /* Make sure refiltering doesn't hurt */
   entry_guards_update_filtered_sets(gs);
@@ -1361,7 +1361,7 @@ test_entry_guard_node_filter(void *arg)
     tt_assert(g[i]->is_filtered_guard == 1);
     tt_assert(g[i]->is_usable_filtered_guard == 1);
   }
-  tt_int_op(num_reachable_filtered_guards(gs), OP_EQ, NUM);
+  tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, NUM);
 
   /* Now start doing things to make the guards get filtered out, 1 by 1. */
 
@@ -1401,7 +1401,7 @@ test_entry_guard_node_filter(void *arg)
     tt_assert(g[i]->is_filtered_guard == (i == 5 || i == 6));
     tt_assert(g[i]->is_usable_filtered_guard == (i == 6));
   }
-  tt_int_op(num_reachable_filtered_guards(gs), OP_EQ, 1);
+  tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, 1);
 
   /* Now make sure we have no live consensus, and no nodes.  Nothing should
    * pass the filter any more. */
@@ -1415,7 +1415,7 @@ test_entry_guard_node_filter(void *arg)
     tt_assert(g[i]->is_filtered_guard == 0);
     tt_assert(g[i]->is_usable_filtered_guard == 0);
   }
-  tt_int_op(num_reachable_filtered_guards(gs), OP_EQ, 0);
+  tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, 0);
 
  done:
   guard_selection_free(gs);
@@ -1434,11 +1434,11 @@ test_entry_guard_expand_sample(void *arg)
 
   // Every sampled guard here should be filtered and reachable for now.
   tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ,
-            num_reachable_filtered_guards(gs));
+            num_reachable_filtered_guards(gs, NULL));
 
   /* Make sure we got the right number. */
   tt_int_op(DFLT_MIN_FILTERED_SAMPLE_SIZE, OP_EQ,
-            num_reachable_filtered_guards(gs));
+            num_reachable_filtered_guards(gs, NULL));
 
   // Make sure everything we got was from our fake node list, and everything
   // was unique.
@@ -1457,7 +1457,7 @@ test_entry_guard_expand_sample(void *arg)
   guard = entry_guards_expand_sample(gs);
   tt_assert(! guard); // no guard was added.
   tt_int_op(DFLT_MIN_FILTERED_SAMPLE_SIZE, OP_EQ,
-            num_reachable_filtered_guards(gs));
+            num_reachable_filtered_guards(gs, NULL));
 
   // Make a few guards unreachable.
   guard = smartlist_get(gs->sampled_entry_guards, 0);
@@ -1467,21 +1467,21 @@ test_entry_guard_expand_sample(void *arg)
   guard = smartlist_get(gs->sampled_entry_guards, 2);
   guard->is_usable_filtered_guard = 0;
   tt_int_op(DFLT_MIN_FILTERED_SAMPLE_SIZE - 3, OP_EQ,
-            num_reachable_filtered_guards(gs));
+            num_reachable_filtered_guards(gs, NULL));
 
   // This time, expanding the sample will add some more guards.
   guard = entry_guards_expand_sample(gs);
   tt_assert(guard); // no guard was added.
   tt_int_op(DFLT_MIN_FILTERED_SAMPLE_SIZE, OP_EQ,
-            num_reachable_filtered_guards(gs));
+            num_reachable_filtered_guards(gs, NULL));
   tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ,
-            num_reachable_filtered_guards(gs)+3);
+            num_reachable_filtered_guards(gs, NULL)+3);
 
   // Still idempotent.
   guard = entry_guards_expand_sample(gs);
   tt_assert(! guard); // no guard was added.
   tt_int_op(DFLT_MIN_FILTERED_SAMPLE_SIZE, OP_EQ,
-            num_reachable_filtered_guards(gs));
+            num_reachable_filtered_guards(gs, NULL));
 
   // Now, do a nasty trick: tell the filter to exclude 31/32 of the guards.
   // This will cause the sample size to get reeeeally huge, while the
@@ -1497,7 +1497,7 @@ test_entry_guard_expand_sample(void *arg)
   entry_guards_update_filtered_sets(gs);
 
   // Surely (p ~ 1-2**-60), one of our guards has been excluded.
-  tt_int_op(num_reachable_filtered_guards(gs), OP_LT,
+  tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_LT,
             DFLT_MIN_FILTERED_SAMPLE_SIZE);
 
   // Try to regenerate the guards.
@@ -1505,7 +1505,7 @@ test_entry_guard_expand_sample(void *arg)
   tt_assert(guard); // no guard was added.
 
   /* this time, it's possible that we didn't add enough sampled guards. */
-  tt_int_op(num_reachable_filtered_guards(gs), OP_LE,
+  tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_LE,
             DFLT_MIN_FILTERED_SAMPLE_SIZE);
   /* but we definitely didn't exceed the sample maximum. */
   tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_LE,
@@ -1538,7 +1538,7 @@ test_entry_guard_expand_sample_small_net(void *arg)
   tt_assert(guard); // the last guard returned -- some guard was added.
   tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_GT, 0);
   tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_LT, 10);
-  tt_int_op(num_reachable_filtered_guards(gs), OP_EQ, 0);
+  tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, 0);
  done:
   guard_selection_free(gs);
 }
@@ -1562,7 +1562,7 @@ test_entry_guard_update_from_consensus_status(void *arg)
   /* First, sample some guards. */
   entry_guards_expand_sample(gs);
   int n_sampled_pre = smartlist_len(gs->sampled_entry_guards);
-  int n_filtered_pre = num_reachable_filtered_guards(gs);
+  int n_filtered_pre = num_reachable_filtered_guards(gs, NULL);
   tt_i64_op(n_sampled_pre, OP_EQ, n_filtered_pre);
   tt_i64_op(n_sampled_pre, OP_GT, 10);
 
@@ -1584,7 +1584,7 @@ test_entry_guard_update_from_consensus_status(void *arg)
     dummy_consensus = NULL;
     sampled_guards_update_from_consensus(gs);
     tt_i64_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_sampled_pre);
-    tt_i64_op(num_reachable_filtered_guards(gs), OP_EQ, n_filtered_pre);
+    tt_i64_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, n_filtered_pre);
     /* put the networkstatus back. */
     dummy_consensus = ns_tmp;
     ns_tmp = NULL;
@@ -1596,7 +1596,7 @@ test_entry_guard_update_from_consensus_status(void *arg)
   sampled_guards_update_from_consensus(gs);
 
   tt_i64_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_sampled_pre);
-  tt_i64_op(num_reachable_filtered_guards(gs), OP_EQ, n_filtered_pre - 5);
+  tt_i64_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, n_filtered_pre-5);
   for (i = 0; i < 5; ++i) {
     entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, i);
     tt_assert(! g->currently_listed);
@@ -1666,7 +1666,7 @@ test_entry_guard_update_from_consensus_repair(void *arg)
   /* First, sample some guards. */
   entry_guards_expand_sample(gs);
   int n_sampled_pre = smartlist_len(gs->sampled_entry_guards);
-  int n_filtered_pre = num_reachable_filtered_guards(gs);
+  int n_filtered_pre = num_reachable_filtered_guards(gs, NULL);
   tt_i64_op(n_sampled_pre, OP_EQ, n_filtered_pre);
   tt_i64_op(n_sampled_pre, OP_GT, 10);
 
@@ -1694,7 +1694,7 @@ test_entry_guard_update_from_consensus_repair(void *arg)
   teardown_capture_of_logs();
 
   tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_sampled_pre);
-  tt_int_op(num_reachable_filtered_guards(gs), OP_EQ, n_filtered_pre - 3);
+  tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, n_filtered_pre-3);
   for (i = 3; i < n_sampled_pre; ++i) {
     /* these will become listed. */
     entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, i);
@@ -1731,7 +1731,7 @@ test_entry_guard_update_from_consensus_remove(void *arg)
   /* First, sample some guards. */
   entry_guards_expand_sample(gs);
   int n_sampled_pre = smartlist_len(gs->sampled_entry_guards);
-  int n_filtered_pre = num_reachable_filtered_guards(gs);
+  int n_filtered_pre = num_reachable_filtered_guards(gs, NULL);
   tt_i64_op(n_sampled_pre, OP_EQ, n_filtered_pre);
   tt_i64_op(n_sampled_pre, OP_GT, 10);
 
@@ -1912,7 +1912,7 @@ test_entry_guard_sample_reachable_filtered(void *arg)
 
   entry_guards_update_filtered_sets(gs);
   gs->primary_guards_up_to_date = 1;
-  tt_int_op(num_reachable_filtered_guards(gs), OP_EQ, n_guards - 1);
+  tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, n_guards - 1);
   tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_guards);
 
   // +1 since the one we made disabled will make  another one get added.
@@ -1934,7 +1934,7 @@ test_entry_guard_sample_reachable_filtered(void *arg)
     const int excluded_flags = tests[j].flag;
     const int excluded_idx = tests[j].idx;
     for (i = 0; i < N; ++i) {
-      g = sample_reachable_filtered_entry_guards(gs, excluded_flags);
+      g = sample_reachable_filtered_entry_guards(gs, NULL, excluded_flags);
       tor_assert(g);
       int pos = smartlist_pos(gs->sampled_entry_guards, g);
       tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_guards);
@@ -1965,7 +1965,7 @@ test_entry_guard_sample_reachable_filtered_empty(void *arg)
   SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n,
                     n->is_possible_guard = 0);
 
-  entry_guard_t *g = sample_reachable_filtered_entry_guards(gs, 0);
+  entry_guard_t *g = sample_reachable_filtered_entry_guards(gs, NULL, 0);
   tt_ptr_op(g, OP_EQ, NULL);
 
  done:
@@ -2162,7 +2162,7 @@ test_entry_guard_select_for_circuit_no_confirmed(void *arg)
   entry_guards_update_primary(gs);
   unsigned state = 9999;
 
-  entry_guard_t *g = select_entry_guard_for_circuit(gs, &state);
+  entry_guard_t *g = select_entry_guard_for_circuit(gs, NULL, &state);
 
   tt_assert(g);
   tt_assert(g->is_primary);
@@ -2172,7 +2172,7 @@ test_entry_guard_select_for_circuit_no_confirmed(void *arg)
   tt_i64_op(g->last_tried_to_connect, OP_EQ, approx_time());
 
   // If we do that again, we should get the same guard.
-  entry_guard_t *g2 = select_entry_guard_for_circuit(gs, &state);
+  entry_guard_t *g2 = select_entry_guard_for_circuit(gs, NULL, &state);
   tt_ptr_op(g2, OP_EQ, g);
 
   // if we mark that guard down, we should get a different primary guard.
@@ -2181,7 +2181,7 @@ test_entry_guard_select_for_circuit_no_confirmed(void *arg)
   g->unreachable_since = approx_time() - 10;
   g->last_tried_to_connect = approx_time() - 10;
   state = 9999;
-  g2 = select_entry_guard_for_circuit(gs, &state);
+  g2 = select_entry_guard_for_circuit(gs, NULL, &state);
   tt_ptr_op(g2, OP_NE, g);
   tt_assert(g2);
   tt_assert(g2->is_primary);
@@ -2195,7 +2195,7 @@ test_entry_guard_select_for_circuit_no_confirmed(void *arg)
   g->unreachable_since = approx_time() - 72*60*60;
   g->last_tried_to_connect = approx_time() - 72*60*60;
   state = 9999;
-  g2 = select_entry_guard_for_circuit(gs, &state);
+  g2 = select_entry_guard_for_circuit(gs, NULL, &state);
   tt_ptr_op(g2, OP_EQ, g);
   tt_assert(g2);
   tt_uint_op(state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
@@ -2210,7 +2210,7 @@ test_entry_guard_select_for_circuit_no_confirmed(void *arg)
     guard->unreachable_since = approx_time() - 30;
   });
   state = 9999;
-  g2 = select_entry_guard_for_circuit(gs, &state);
+  g2 = select_entry_guard_for_circuit(gs, NULL, &state);
   tt_assert(g2);
   tt_assert(!g2->is_primary);
   tt_int_op(g2->confirmed_idx, OP_EQ, -1);
@@ -2254,7 +2254,7 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
   unsigned state = 9999;
 
   // As above, this gives us a primary guard.
-  entry_guard_t *g = select_entry_guard_for_circuit(gs, &state);
+  entry_guard_t *g = select_entry_guard_for_circuit(gs, NULL, &state);
   tt_assert(g);
   tt_assert(g->is_primary);
   tt_int_op(g->confirmed_idx, OP_EQ, 0);
@@ -2271,7 +2271,7 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
 
   // ... we should get a confirmed guard.
   state = 9999;
-  g = select_entry_guard_for_circuit(gs, &state);
+  g = select_entry_guard_for_circuit(gs, NULL, &state);
   tt_assert(g);
   tt_assert(! g->is_primary);
   tt_int_op(g->confirmed_idx, OP_EQ, smartlist_len(gs->primary_entry_guards));
@@ -2282,7 +2282,7 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
   // And if we try again, we should get a different confirmed guard, since
   // that one is pending.
   state = 9999;
-  entry_guard_t *g2 = select_entry_guard_for_circuit(gs, &state);
+  entry_guard_t *g2 = select_entry_guard_for_circuit(gs, NULL, &state);
   tt_assert(g2);
   tt_assert(! g2->is_primary);
   tt_ptr_op(g2, OP_NE, g);
@@ -2297,12 +2297,12 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
   const int n_remaining_confirmed =
     N_CONFIRMED - 2 - smartlist_len(gs->primary_entry_guards);
   for (i = 0; i < n_remaining_confirmed; ++i) {
-    g = select_entry_guard_for_circuit(gs, &state);
+    g = select_entry_guard_for_circuit(gs, NULL, &state);
     tt_int_op(g->confirmed_idx, OP_GE, 0);
     tt_assert(g);
   }
   state = 9999;
-  g = select_entry_guard_for_circuit(gs, &state);
+  g = select_entry_guard_for_circuit(gs, NULL, &state);
   tt_assert(g);
   tt_assert(g->is_pending);
   tt_int_op(g->confirmed_idx, OP_EQ, -1);
@@ -2329,7 +2329,7 @@ test_entry_guard_select_for_circuit_highlevel_primary(void *arg)
    * Make sure that the pick-for-circuit API basically works.  We'll get
    * a primary guard, so it'll be usable on completion.
    */
-  int r = entry_guard_pick_for_circuit(gs, &node, &guard);
+  int r = entry_guard_pick_for_circuit(gs, NULL, &node, &guard);
 
   tt_assert(r == 0);
   tt_assert(node);
@@ -2361,7 +2361,7 @@ test_entry_guard_select_for_circuit_highlevel_primary(void *arg)
   /* Try again. We'll also get a primary guard this time. (The same one,
      in fact.)  But this time, we'll say the connection has failed. */
   update_approx_time(start+35);
-  r = entry_guard_pick_for_circuit(gs, &node, &guard);
+  r = entry_guard_pick_for_circuit(gs, NULL, &node, &guard);
   tt_assert(r == 0);
   tt_assert(node);
   tt_assert(guard);
@@ -2396,7 +2396,7 @@ test_entry_guard_select_for_circuit_highlevel_primary(void *arg)
    * (still primary) guard.
    */
   update_approx_time(start+60);
-  r = entry_guard_pick_for_circuit(gs, &node, &guard);
+  r = entry_guard_pick_for_circuit(gs, NULL, &node, &guard);
   tt_assert(r == 0);
   tt_assert(node);
   tt_assert(guard);
@@ -2448,7 +2448,7 @@ test_entry_guard_select_for_circuit_highlevel_confirm_other(void *arg)
 
   /* Primary guards are down! */
   for (i = 0; i < N_PRIMARY; ++i) {
-    r = entry_guard_pick_for_circuit(gs, &node, &guard);
+    r = entry_guard_pick_for_circuit(gs, NULL, &node, &guard);
     tt_assert(node);
     tt_assert(guard);
     tt_assert(r == 0);
@@ -2461,7 +2461,7 @@ test_entry_guard_select_for_circuit_highlevel_confirm_other(void *arg)
 
   /* Next guard should be non-primary. */
   node = NULL;
-  r = entry_guard_pick_for_circuit(gs, &node, &guard);
+  r = entry_guard_pick_for_circuit(gs, NULL, &node, &guard);
   tt_assert(node);
   tt_assert(guard);
   tt_assert(r == 0);
@@ -2513,7 +2513,7 @@ test_entry_guard_select_for_circuit_highlevel_primary_retry(void *arg)
   /* Make primary guards confirmed (so they won't be superseded by a later
    * guard), then mark them down. */
   for (i = 0; i < N_PRIMARY; ++i) {
-    r = entry_guard_pick_for_circuit(gs, &node, &guard);
+    r = entry_guard_pick_for_circuit(gs, NULL, &node, &guard);
     tt_assert(node);
     tt_assert(guard);
     tt_assert(r == 0);
@@ -2529,7 +2529,7 @@ test_entry_guard_select_for_circuit_highlevel_primary_retry(void *arg)
   }
 
   /* Get another guard that we might try. */
-  r = entry_guard_pick_for_circuit(gs, &node, &guard);
+  r = entry_guard_pick_for_circuit(gs, NULL, &node, &guard);
   tt_assert(node);
   tt_assert(guard);
   tt_assert(r == 0);
@@ -2556,7 +2556,7 @@ test_entry_guard_select_for_circuit_highlevel_primary_retry(void *arg)
   });
 
   /* Have a circuit to a primary guard succeed. */
-  r = entry_guard_pick_for_circuit(gs, &node, &guard2);
+  r = entry_guard_pick_for_circuit(gs, NULL, &node, &guard2);
   tt_assert(r == 0);
   tt_int_op(guard2->state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
   u = entry_guard_succeeded(&guard2);
@@ -2585,7 +2585,7 @@ test_entry_guard_select_and_cancel(void *arg)
   /* Once more, we mark all the primary guards down. */
   entry_guards_note_internet_connectivity(gs);
   for (i = 0; i < N_PRIMARY; ++i) {
-    r = entry_guard_pick_for_circuit(gs, &node, &guard);
+    r = entry_guard_pick_for_circuit(gs, NULL, &node, &guard);
     tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
     g = entry_guard_handle_get(guard->guard);
     tt_int_op(g->is_primary, OP_EQ, 1);
@@ -2600,7 +2600,7 @@ test_entry_guard_select_and_cancel(void *arg)
   tt_assert(entry_guards_all_primary_guards_are_down(gs));
 
   /* Now get another guard we could try... */
-  r = entry_guard_pick_for_circuit(gs, &node, &guard);
+  r = entry_guard_pick_for_circuit(gs, NULL, &node, &guard);
   tt_assert(node);
   tt_assert(guard);
   tt_assert(r == 0);
@@ -2659,7 +2659,7 @@ upgrade_circuits_setup(const struct testcase_t *testcase)
   data->start = approx_time();
   entry_guards_note_internet_connectivity(gs);
   for (i = 0; i < N_PRIMARY; ++i) {
-    entry_guard_pick_for_circuit(gs, &node, &guard);
+    entry_guard_pick_for_circuit(gs, NULL, &node, &guard);
     g = entry_guard_handle_get(guard->guard);
     make_guard_confirmed(gs, g);
     entry_guard_failed(&guard);
@@ -2670,7 +2670,7 @@ upgrade_circuits_setup(const struct testcase_t *testcase)
   data->all_origin_circuits = smartlist_new();
 
   update_approx_time(data->start + 27);
-  entry_guard_pick_for_circuit(gs, &node, &data->guard1_state);
+  entry_guard_pick_for_circuit(gs, NULL, &node, &data->guard1_state);
   origin_circuit_t *circ;
   data->circ1 = circ = origin_circuit_new();
   circ->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL;
@@ -2678,7 +2678,7 @@ upgrade_circuits_setup(const struct testcase_t *testcase)
   smartlist_add(data->all_origin_circuits, circ);
 
   update_approx_time(data->start + 30);
-  entry_guard_pick_for_circuit(gs, &node, &data->guard2_state);
+  entry_guard_pick_for_circuit(gs, NULL, &node, &data->guard2_state);
   data->circ2 = circ = origin_circuit_new();
   circ->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL;
   circ->guard_state = data->guard2_state;





More information about the tor-commits mailing list