Procházet zdrojové kódy

Merge branch 'bug21242'

Nick Mathewson před 7 roky
rodič
revize
78011bb7ba
5 změnil soubory, kde provedl 88 přidání a 2 odebrání
  1. 10 0
      changes/bug21242
  2. 1 1
      src/or/circuitbuild.c
  3. 63 1
      src/or/entrynodes.c
  4. 6 0
      src/or/entrynodes.h
  5. 8 0
      src/or/nodelist.c

+ 10 - 0
changes/bug21242

@@ -0,0 +1,10 @@
+  o Major bugfixes (entry guards):
+    - Stop trying to build circuits through entry guards for which we
+      have no descriptor yet. Also, stop crashing if we *do* accidentally
+      try to build a circuit in such a state. Fixes bug 21242; bugfix
+      on 0.3.0.1-alpha.
+
+  o Minor features (entry guards):
+    - Do not try to build circuits until we have descriptors for our
+      primary entry guards. Related to fix for bug 21242.
+

+ 1 - 1
src/or/circuitbuild.c

@@ -2369,7 +2369,7 @@ onion_extend_cpath(origin_circuit_t *circ)
       int client = (server_mode(get_options()) == 0);
       info = extend_info_from_node(r, client);
       /* Clients can fail to find an allowed address */
-      tor_assert(info || client);
+      tor_assert_nonfatal(info || client);
     }
   } else {
     const node_t *r =

+ 63 - 1
src/or/entrynodes.c

@@ -185,6 +185,16 @@ should_apply_guardfraction(const networkstatus_t *ns)
   return options->UseGuardFraction;
 }
 
+/** Return true iff we know a descriptor for <b>guard</b> */
+static int
+guard_has_descriptor(const entry_guard_t *guard)
+{
+  const node_t *node = node_get_by_id(guard->identity);
+  if (!node)
+    return 0;
+  return node_has_descriptor(node);
+}
+
 /**
  * Try to determine the correct type for a selection named "name",
  * if <b>type</b> is GS_TYPE_INFER.
@@ -1436,6 +1446,7 @@ sample_reachable_filtered_entry_guards(guard_selection_t *gs,
   const unsigned exclude_primary = flags & SAMPLE_EXCLUDE_PRIMARY;
   const unsigned exclude_pending = flags & SAMPLE_EXCLUDE_PENDING;
   const unsigned no_update_primary = flags & SAMPLE_NO_UPDATE_PRIMARY;
+  const unsigned need_descriptor = flags & SAMPLE_EXCLUDE_NO_DESCRIPTOR;
 
   SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) {
     entry_guard_consider_retry(guard);
@@ -1469,6 +1480,8 @@ sample_reachable_filtered_entry_guards(guard_selection_t *gs,
       continue;
     if (exclude_pending && guard->is_pending)
       continue;
+    if (need_descriptor && !guard_has_descriptor(guard))
+      continue;
     smartlist_add(reachable_filtered_sample, guard);
   } SMARTLIST_FOREACH_END(guard);
 
@@ -1766,6 +1779,7 @@ select_entry_guard_for_circuit(guard_selection_t *gs,
                                const entry_guard_restriction_t *rst,
                                unsigned *state_out)
 {
+  const int need_descriptor = (usage == GUARD_USAGE_TRAFFIC);
   tor_assert(gs);
   tor_assert(state_out);
 
@@ -1782,6 +1796,9 @@ select_entry_guard_for_circuit(guard_selection_t *gs,
     if (! entry_guard_obeys_restriction(guard, rst))
       continue;
     if (guard->is_reachable != GUARD_REACHABLE_NO) {
+      if (need_descriptor && BUG(!guard_has_descriptor(guard))) {
+        continue;
+      }
       *state_out = GUARD_CIRC_STATE_USABLE_ON_COMPLETION;
       guard->last_tried_to_connect = approx_time();
       smartlist_add(usable_primary_guards, guard);
@@ -1810,6 +1827,8 @@ select_entry_guard_for_circuit(guard_selection_t *gs,
       continue;
     entry_guard_consider_retry(guard);
     if (guard->is_usable_filtered_guard && ! guard->is_pending) {
+      if (need_descriptor && !guard_has_descriptor(guard))
+        continue; /* not a bug */
       guard->is_pending = 1;
       guard->last_tried_to_connect = approx_time();
       *state_out = GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD;
@@ -1825,11 +1844,15 @@ select_entry_guard_for_circuit(guard_selection_t *gs,
       random from {USABLE_FILTERED_GUARDS}." */
   {
     entry_guard_t *guard;
+    unsigned flags = 0;
+    if (need_descriptor)
+      flags |= SAMPLE_EXCLUDE_NO_DESCRIPTOR;
     guard = sample_reachable_filtered_entry_guards(gs,
                                                    rst,
                                                    SAMPLE_EXCLUDE_CONFIRMED |
                                                    SAMPLE_EXCLUDE_PRIMARY |
-                                                   SAMPLE_EXCLUDE_PENDING);
+                                                   SAMPLE_EXCLUDE_PENDING |
+                                                   flags);
     if (guard == NULL) {
       log_info(LD_GUARD, "Absolutely no sampled guards were available.");
       return NULL;
@@ -2057,6 +2080,8 @@ entry_guard_pick_for_circuit(guard_selection_t *gs,
   // XXXX prop271 check Ed ID.
   if (! node)
     goto fail;
+  if (BUG(usage != GUARD_USAGE_DIRGUARD && !node_has_descriptor(node)))
+    goto fail;
 
   *chosen_node_out = node;
   *guard_state_out = tor_malloc_zero(sizeof(circuit_guard_state_t));
@@ -3303,6 +3328,43 @@ guards_retry_optimistic(const or_options_t *options)
   return 1;
 }
 
+/**
+ * Return true iff we know enough directory information to construct
+ * circuits through all of the primary guards we'd currently use.
+ */
+int
+guard_selection_have_enough_dir_info_to_build_circuits(guard_selection_t *gs)
+{
+  if (!gs->primary_guards_up_to_date)
+    entry_guards_update_primary(gs);
+
+  const int num_primary = get_n_primary_guards_to_use(GUARD_USAGE_TRAFFIC);
+  int n_missing_descriptors = 0;
+  int n_considered = 0;
+
+  SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards, entry_guard_t *, guard) {
+    entry_guard_consider_retry(guard);
+    if (guard->is_reachable == GUARD_REACHABLE_NO)
+      continue;
+    n_considered++;
+    if (!guard_has_descriptor(guard))
+      n_missing_descriptors++;
+    if (n_considered >= num_primary)
+      break;
+  } SMARTLIST_FOREACH_END(guard);
+
+  return n_missing_descriptors == 0;
+}
+
+/** As guard_selection_have_enough_dir_info_to_build_circuits, but uses
+ * the default guard selection. */
+int
+entry_guards_have_enough_dir_info_to_build_circuits(void)
+{
+  return guard_selection_have_enough_dir_info_to_build_circuits(
+                                        get_guard_selection_info());
+}
+
 /** Free one guard selection context */
 STATIC void
 guard_selection_free(guard_selection_t *gs)

+ 6 - 0
src/or/entrynodes.h

@@ -482,6 +482,7 @@ STATIC entry_guard_t *get_sampled_guard_with_id(guard_selection_t *gs,
                                                 const uint8_t *rsa_id);
 
 MOCK_DECL(STATIC time_t, randomize_time, (time_t now, time_t max_backdate));
+
 STATIC entry_guard_t *entry_guard_add_to_sample(guard_selection_t *gs,
                                                 const node_t *node);
 STATIC entry_guard_t *entry_guards_expand_sample(guard_selection_t *gs);
@@ -498,6 +499,7 @@ STATIC int entry_guards_all_primary_guards_are_down(guard_selection_t *gs);
 #define SAMPLE_EXCLUDE_PRIMARY     (1u<<1)
 #define SAMPLE_EXCLUDE_PENDING     (1u<<2)
 #define SAMPLE_NO_UPDATE_PRIMARY   (1u<<3)
+#define SAMPLE_EXCLUDE_NO_DESCRIPTOR (1u<<4)
 /**@}*/
 STATIC entry_guard_t *sample_reachable_filtered_entry_guards(
                                     guard_selection_t *gs,
@@ -565,6 +567,10 @@ int getinfo_helper_entry_guards(control_connection_t *conn,
 int entries_known_but_down(const or_options_t *options);
 void entries_retry_all(const or_options_t *options);
 
+int guard_selection_have_enough_dir_info_to_build_circuits(
+                                                    guard_selection_t *gs);
+int entry_guards_have_enough_dir_info_to_build_circuits(void);
+
 void entry_guards_free_all(void);
 
 double pathbias_get_close_success_count(entry_guard_t *guard);

+ 8 - 0
src/or/nodelist.c

@@ -43,6 +43,7 @@
 #include "config.h"
 #include "control.h"
 #include "dirserv.h"
+#include "entrynodes.h"
 #include "geoip.h"
 #include "main.h"
 #include "microdesc.h"
@@ -1991,6 +1992,13 @@ update_router_have_minimum_dir_info(void)
 
   using_md = consensus->flavor == FLAV_MICRODESC;
 
+  if (! entry_guards_have_enough_dir_info_to_build_circuits()) {
+    strlcpy(dir_info_status, "We're missing descriptors for some of our "
+            "primary entry guards", sizeof(dir_info_status));
+    res = 0;
+    goto done;
+  }
+
   /* Check fraction of available paths */
   {
     char *status = NULL;