[tor-commits] [tor/release-0.3.1] Introduce new guard restriction and use it to skip outdated dirs.

nickm at torproject.org nickm at torproject.org
Mon Dec 11 21:46:21 UTC 2017


commit f61e3090fb2975ad8c2a5e138b87c62428c5f46b
Author: George Kadianakis <desnacked at riseup.net>
Date:   Mon Nov 6 19:38:47 2017 +0200

    Introduce new guard restriction and use it to skip outdated dirs.
---
 changes/bug23817    |  3 ++
 src/or/directory.c  |  4 +--
 src/or/entrynodes.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++-------
 src/or/entrynodes.h | 37 +++++++++++++++------
 4 files changed, 116 insertions(+), 23 deletions(-)

diff --git a/changes/bug23817 b/changes/bug23817
new file mode 100644
index 000000000..474094279
--- /dev/null
+++ b/changes/bug23817
@@ -0,0 +1,3 @@
+  o Minor bugfixes (descriptors):
+    - Don't try fetching microdescriptors from relays that have failed to
+      deliver them in the past. Fixes bug 23817; bugfix on 0.3.0.1-alpha.
diff --git a/src/or/directory.c b/src/or/directory.c
index 129309ae4..aec8ef5bf 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -464,7 +464,7 @@ directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags,
     log_warn(LD_BUG, "Called when we have UseBridges set.");
 
   if (should_use_directory_guards(options)) {
-    const node_t *node = guards_choose_dirguard(guard_state_out);
+    const node_t *node = guards_choose_dirguard(dir_purpose, guard_state_out);
     if (node)
       rs = node->rs;
   } else {
@@ -598,7 +598,7 @@ 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.
        */
-      const node_t *node = guards_choose_dirguard(&guard_state);
+      const node_t *node = guards_choose_dirguard(dir_purpose, &guard_state);
       if (node && node->ri) {
         /* every bridge has a routerinfo. */
         routerinfo_t *ri = node->ri;
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 26f53cbfe..f2ca7aac2 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -1460,6 +1460,70 @@ guard_in_node_family(const entry_guard_t *guard, const node_t *node)
   }
 }
 
+/* Allocate and return a new exit guard restriction (where <b>exit_id</b> is of
+ * size DIGEST_LEN) */
+STATIC entry_guard_restriction_t *
+guard_create_exit_restriction(const uint8_t *exit_id)
+{
+  entry_guard_restriction_t *rst = NULL;
+  rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
+  rst->type = RST_EXIT_NODE;
+  memcpy(rst->exclude_id, exit_id, DIGEST_LEN);
+  return rst;
+}
+
+/** Allocate and return an outdated md guard restriction. */
+STATIC entry_guard_restriction_t *
+guard_create_dirserver_md_restriction(void)
+{
+  entry_guard_restriction_t *rst = NULL;
+
+  rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
+  rst->type = RST_OUTDATED_MD_DIRSERVER;
+
+  return rst;
+}
+
+/* Return True if <b>guard</b> obeys the exit restriction <b>rst</b>. */
+static int
+guard_obeys_exit_restriction(const entry_guard_t *guard,
+                             const entry_guard_restriction_t *rst)
+{
+  tor_assert(rst->type == RST_EXIT_NODE);
+
+  // Exclude the exit ID and all of its family.
+  const node_t *node = node_get_by_id((const char*)rst->exclude_id);
+  if (node && guard_in_node_family(guard, node))
+    return 0;
+
+  return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN);
+}
+
+/** Return True if <b>guard</b> should be used as a dirserver for fetching
+ *  microdescriptors. */
+static int
+guard_obeys_md_dirserver_restriction(const entry_guard_t *guard)
+{
+  /* Don't enforce dirserver restrictions for bridges since we might not have
+   * many of those. Be willing to try them over and over again for now. */
+  /* XXX: Improvement might be possible here */
+  if (guard->bridge_addr) {
+    return 1;
+  }
+
+  /* If this guard is an outdated dirserver, don't use it. */
+  if (microdesc_relay_is_outdated_dirserver(guard->identity)) {
+    log_info(LD_GENERAL, "Skipping %s dirserver: outdated",
+             hex_str(guard->identity, DIGEST_LEN));
+    return 0;
+  }
+
+  log_debug(LD_GENERAL, "%s dirserver obeys md restrictions",
+            hex_str(guard->identity, DIGEST_LEN));
+
+  return 1;
+}
+
 /**
  * Return true iff <b>guard</b> obeys the restrictions defined in <b>rst</b>.
  * (If <b>rst</b> is NULL, there are no restrictions.)
@@ -1472,13 +1536,14 @@ entry_guard_obeys_restriction(const entry_guard_t *guard,
   if (! rst)
     return 1; // No restriction?  No problem.
 
-  // Only one kind of restriction exists right now: excluding an exit
-  // ID and all of its family.
-  const node_t *node = node_get_by_id((const char*)rst->exclude_id);
-  if (node && guard_in_node_family(guard, node))
-    return 0;
+  if (rst->type == RST_EXIT_NODE) {
+    return guard_obeys_exit_restriction(guard, rst);
+  } else if (rst->type == RST_OUTDATED_MD_DIRSERVER) {
+    return guard_obeys_md_dirserver_restriction(guard);
+  }
 
-  return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN);
+  tor_assert_nonfatal_unreached();
+  return 0;
 }
 
 /**
@@ -2105,7 +2170,7 @@ entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b)
 }
 
 /** Release all storage held in <b>restriction</b> */
-static void
+STATIC void
 entry_guard_restriction_free(entry_guard_restriction_t *rst)
 {
   tor_free(rst);
@@ -3358,8 +3423,8 @@ guards_choose_guard(cpath_build_state_t *state,
     /* We're building to a targeted exit node, so that node can't be
      * chosen as our guard for this circuit.  Remember that fact in a
      * restriction. */
-    rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
-    memcpy(rst->exclude_id, exit_id, DIGEST_LEN);
+    rst = guard_create_exit_restriction(exit_id);
+    tor_assert(rst);
   }
   if (entry_guard_pick_for_circuit(get_guard_selection_info(),
                                    GUARD_USAGE_TRAFFIC,
@@ -3411,12 +3476,20 @@ remove_all_entry_guards(void)
 
 /** Helper: pick a directory guard, with whatever algorithm is used. */
 const node_t *
-guards_choose_dirguard(circuit_guard_state_t **guard_state_out)
+guards_choose_dirguard(uint8_t dir_purpose,
+                       circuit_guard_state_t **guard_state_out)
 {
   const node_t *r = NULL;
+  entry_guard_restriction_t *rst = NULL;
+
+  /* If we are fetching microdescs, don't query outdated dirservers. */
+  if (dir_purpose == DIR_PURPOSE_FETCH_MICRODESC) {
+    rst = guard_create_dirserver_md_restriction();
+  }
+
   if (entry_guard_pick_for_circuit(get_guard_selection_info(),
                                    GUARD_USAGE_DIRGUARD,
-                                   NULL,
+                                   rst,
                                    &r,
                                    guard_state_out) < 0) {
     tor_assert(r == NULL);
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index 735c7738b..29de627de 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -272,22 +272,28 @@ struct guard_selection_s {
 
 struct entry_guard_handle_t;
 
+/** Types of restrictions we impose when picking guard nodes */
+typedef enum guard_restriction_type_t {
+  /* Don't pick the same guard node as our exit node (or its family) */
+  RST_EXIT_NODE = 0,
+  /* Don't pick dirguards that have previously shown to be outdated */
+  RST_OUTDATED_MD_DIRSERVER = 1
+} guard_restriction_type_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 and its family
- * 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; and it must not
-   * be in the same family as any node with this digest.
-   */
+  /* What type of restriction are we imposing? */
+  guard_restriction_type_t type;
+
+  /* In case of restriction type RST_EXIT_NODE, the guard's RSA identity
+   * digest must not equal this; and it must not be in the same family as any
+   * node with this digest. */
   uint8_t exclude_id[DIGEST_LEN];
 };
 
@@ -316,7 +322,8 @@ struct circuit_guard_state_t {
 int guards_update_all(void);
 const node_t *guards_choose_guard(cpath_build_state_t *state,
                                   circuit_guard_state_t **guard_state_out);
-const node_t *guards_choose_dirguard(circuit_guard_state_t **guard_state_out);
+const node_t *guards_choose_dirguard(uint8_t dir_purpose,
+                                     circuit_guard_state_t **guard_state_out);
 
 #if 1
 /* XXXX NM I would prefer that all of this stuff be private to
@@ -550,7 +557,17 @@ STATIC unsigned entry_guards_note_guard_success(guard_selection_t *gs,
                                                 unsigned old_state);
 STATIC int entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b);
 STATIC char *getinfo_helper_format_single_entry_guard(const entry_guard_t *e);
-#endif
+
+STATIC entry_guard_restriction_t *
+guard_create_exit_restriction(const uint8_t *exit_id);
+
+STATIC entry_guard_restriction_t *
+guard_create_dirserver_md_restriction(void);
+
+STATIC void
+entry_guard_restriction_free(entry_guard_restriction_t *rst);
+
+#endif /* defined(ENTRYNODES_PRIVATE) */
 
 void remove_all_entry_guards_for_guard_selection(guard_selection_t *gs);
 void remove_all_entry_guards(void);





More information about the tor-commits mailing list