[tor-commits] [tor/master] Implement bridge backends for sampling, filtering guards.

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


commit 82fa71610de1c7d7faed78490a3cb90ce917a3e2
Author: Nick Mathewson <nickm at torproject.org>
Date:   Tue Nov 29 10:19:10 2016 -0500

    Implement bridge backends for sampling, filtering guards.
    
    Still missing is functionality for picking bridges when we don't
    know a descriptor for them yet, and functionality for learning a
    bridge ID.
    
    Everything else remains (basically) the same. Neat!
---
 src/or/entrynodes.c | 185 +++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 139 insertions(+), 46 deletions(-)

diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index dcaab35..6ac3166 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -802,12 +802,10 @@ entry_guard_add_to_sample_impl(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)
+static entry_guard_t *
+entry_guard_add_bridge_to_sample(guard_selection_t *gs,
+                                 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);
 
@@ -896,24 +894,34 @@ num_reachable_filtered_guards(guard_selection_t *gs)
 }
 
 /**
- * Add new guards to the sampled guards in <b>gs</b> until there are
- * enough usable filtered guards, but never grow the sample beyond its
- * maximum size.  Return the last guard added, or NULL if none were
- * added.
+ * Return a smartlist of the all the guards that are not currently
+ * members of the sample (GUARDS - SAMPLED_GUARDS).  The elements of
+ * this list are node_t pointers in the non-bridge case, and
+ * bridge_info_t pointers in the bridge case.  Set *<b>n_guards_out/b>
+ * to the number of guards that we found in GUARDS, including those
+ * that were already sampled.
  */
-STATIC entry_guard_t *
-entry_guards_expand_sample(guard_selection_t *gs)
+static smartlist_t *
+get_eligible_guards(guard_selection_t *gs,
+                    int *n_guards_out)
 {
-  tor_assert(gs);
-  int n_sampled = smartlist_len(gs->sampled_entry_guards);
-  entry_guard_t *added_guard = NULL;
-
-  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"
-  int n_usable_filtered_guards = num_reachable_filtered_guards(gs);
-  {
+
+  if (gs->type == GS_TYPE_BRIDGE) {
+    const smartlist_t *bridges = bridge_list_get();
+    SMARTLIST_FOREACH_BEGIN(bridges, bridge_info_t *, bridge) {
+      ++n_guards;
+      if (NULL != get_sampled_guard_for_bridge(gs, bridge)) {
+        continue;
+      }
+      smartlist_add(eligible_guards, bridge);
+    } SMARTLIST_FOREACH_END(bridge);
+  } else {
+    const smartlist_t *nodes = nodelist_get_list();
+    const int n_sampled = smartlist_len(gs->sampled_entry_guards);
+
     /* Build a bloom filter of our current guards: let's keep this O(N). */
     digestset_t *sampled_guard_ids = digestset_new(n_sampled);
     SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, const entry_guard_t *,
@@ -934,11 +942,58 @@ entry_guards_expand_sample(guard_selection_t *gs)
     digestset_free(sampled_guard_ids);
   }
 
-  /* Is there at least one guard we haven't sampled? */
-  if (! smartlist_len(eligible_guards))
-    goto done;
+  *n_guards_out = n_guards;
+  return eligible_guards;
+}
+
+/** Helper: given a smartlist of either bridge_info_t (if gs->type is
+ * GS_TYPE_BRIDGE) or node_t (otherwise), pick one that can be a guard,
+ * add it as a guard, remove it from the list, and return a new
+ * entry_guard_t.  Return NULL on failure. */
+static entry_guard_t *
+select_and_add_guard_item_for_sample(guard_selection_t *gs,
+                                     smartlist_t *eligible_guards)
+{
+  entry_guard_t *added_guard;
+  if (gs->type == GS_TYPE_BRIDGE) {
+    const bridge_info_t *bridge = smartlist_choose(eligible_guards);
+    if (BUG(!bridge))
+      return NULL; // LCOV_EXCL_LINE
+    smartlist_remove(eligible_guards, bridge);
+    added_guard = entry_guard_add_bridge_to_sample(gs, bridge);
+  } else {
+    const node_t *node =
+      node_sl_choose_by_bandwidth(eligible_guards, WEIGHT_FOR_GUARD);
+    if (BUG(!node))
+      return NULL; // LCOV_EXCL_LINE
+    smartlist_remove(eligible_guards, node);
+    added_guard = entry_guard_add_to_sample(gs, node);
+  }
 
-  const int max_sample = (int)(n_guards * get_max_sample_threshold());
+  return added_guard;
+}
+
+/**
+ * Add new guards to the sampled guards in <b>gs</b> until there are
+ * enough usable filtered guards, but never grow the sample beyond its
+ * maximum size.  Return the last guard added, or NULL if none were
+ * added.
+ */
+STATIC entry_guard_t *
+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_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 min_filtered_sample = get_min_filtered_sample_size();
 
   log_info(LD_GUARD, "Expanding the sample guard set. We have %d guards "
@@ -967,12 +1022,7 @@ entry_guards_expand_sample(guard_selection_t *gs)
     }
 
     /* Otherwise we can add at least one new guard. */
-    const node_t *node =
-      node_sl_choose_by_bandwidth(eligible_guards, WEIGHT_FOR_GUARD);
-    if (BUG(! node))
-      goto done; // LCOV_EXCL_LINE -- should be impossible.
-
-    added_guard = entry_guard_add_to_sample(gs, node);
+    added_guard = select_and_add_guard_item_for_sample(gs, eligible_guards);
     if (!added_guard)
       goto done; // LCOV_EXCL_LINE -- only fails on BUG.
 
@@ -980,8 +1030,6 @@ entry_guards_expand_sample(guard_selection_t *gs)
 
     if (added_guard->is_usable_filtered_guard)
       ++n_usable_filtered_guards;
-
-    smartlist_remove(eligible_guards, node);
   }
 
  done:
@@ -1029,6 +1077,21 @@ remove_guard_from_confirmed_and_primary_lists(guard_selection_t *gs,
   }
 }
 
+/** Return true iff <b>guard</b> is currently "listed" -- that is, it
+ * appears in the consensus, or as a configured bridge (as
+ * appropriate) */
+static int
+entry_guard_is_listed(guard_selection_t *gs, const entry_guard_t *guard)
+{
+  if (gs->type == GS_TYPE_BRIDGE) {
+    return NULL != get_bridge_info_for_guard(guard);
+  } else {
+    const node_t *node = node_get_by_id(guard->identity);
+
+    return node && node_is_possible_guard(gs, node);
+  }
+}
+
 /**
  * Update the status of all sampled guards based on the arrival of a
  * new consensus networkstatus document.  This will include marking
@@ -1059,11 +1122,8 @@ sampled_guards_update_from_consensus(guard_selection_t *gs)
 
   /* First: Update listed/unlisted. */
   SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) {
-    /* XXXX prop271 handle bridges right?  */
     /* XXXX prop271 check ed ID too */
-    const node_t *node = node_get_by_id(guard->identity);
-
-    const unsigned is_listed = node && node_is_possible_guard(gs, node);
+    const int is_listed = entry_guard_is_listed(gs, guard);
 
     if (is_listed && ! guard->currently_listed) {
       ++n_changes;
@@ -1113,8 +1173,6 @@ sampled_guards_update_from_consensus(guard_selection_t *gs)
 
   /* Then: remove the ones that have been junk for too long */
   SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) {
-    /* XXXX prop271 handle bridges right?  */
-
     int remove = 0;
 
     if (guard->currently_listed == 0 &&
@@ -1180,20 +1238,48 @@ node_passes_guard_filter(const or_options_t *options, guard_selection_t *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;
 
   /* XXXX -- prop271 spec deviation -- add entrynodes to spec. */
   if (options->EntryNodes &&
-      !options->UseBridges &&
       !routerset_contains_node(options->EntryNodes, node))
     return 0;
 
   if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0))
     return 0;
 
-  if (bool_neq(options->UseBridges, node_is_a_configured_bridge(node)))
+  if (node_is_a_configured_bridge(node))
+    return 0;
+
+  return 1;
+}
+
+/** Helper: Return true iff <b>bridge</b> passes our configuration
+ * filter-- if it is a relay that we are configured to be able to
+ * connect to. */
+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;
+
+  if (routerset_contains_bridge(options->ExcludeNodes, bridge))
+    return 0;
+
+  /* Ignore entrynodes */
+  const tor_addr_port_t *addrport = bridge_get_addr_port(bridge);
+
+  if (!fascist_firewall_allows_address_addr(&addrport->addr,
+                                            addrport->port,
+                                            FIREWALL_OR_CONNECTION,
+                                            0, 0))
     return 0;
 
   return 1;
@@ -1212,14 +1298,21 @@ entry_guard_passes_filter(const or_options_t *options, guard_selection_t *gs,
   if (guard->pb.path_bias_disabled)
     return 0;
 
-  const node_t *node = node_get_by_id(guard->identity);
-  if (node == NULL) {
-    // This can happen when currently_listed is true, and we're not updating
-    // it because we don't have a live consensus.
-    return 0;
-  }
+  if (gs->type == GS_TYPE_BRIDGE) {
+    const bridge_info_t *bridge = get_bridge_info_for_guard(guard);
+    if (bridge == NULL)
+      return 0;
+    return bridge_passes_guard_filter(options, bridge);
+  } else {
+    const node_t *node = node_get_by_id(guard->identity);
+    if (node == NULL) {
+      // This can happen when currently_listed is true, and we're not updating
+      // it because we don't have a live consensus.
+      return 0;
+    }
 
-  return node_passes_guard_filter(options, gs, node);
+    return node_passes_guard_filter(options, gs, node);
+  }
 }
 
 /**
@@ -3126,7 +3219,7 @@ add_an_entry_guard(guard_selection_t *gs,
 
 /** Entry point for bridges.c to add a bridge as guard.
  *
- * XXXX prop271 refactor.*/
+ * XXXX prop271 refactor, bridge.*/
 void
 add_bridge_as_entry_guard(guard_selection_t *gs,
                           const node_t *chosen)





More information about the tor-commits mailing list