Kaynağa Gözat

Write the easy parts of the public entryguard interface.

Here we add a little bit of state to origin circuits, and set up
the necessary functions for the circuit code to call in order to
find guards, use guards, and decide when circuits can be used.

There's also an incomplete function for the hard part of the
circuit-maintenance code, where we figure out whether any waiting
guards are ready to become usable.

(This patch finally uses the handle.c code to make safe handles to
entry_guard_t objects, so that we are allowed to free an
entry_guard_t without checking whether any origin_circuit_t is
holding a reference to it.)
Nick Mathewson 8 yıl önce
ebeveyn
işleme
dd6bdab3f6
6 değiştirilmiş dosya ile 241 ekleme ve 13 silme
  1. 7 0
      src/or/circuitbuild.c
  2. 2 0
      src/or/circuitbuild.h
  3. 2 0
      src/or/circuitlist.c
  4. 187 13
      src/or/entrynodes.c
  5. 38 0
      src/or/entrynodes.h
  6. 5 0
      src/or/or.h

+ 7 - 0
src/or/circuitbuild.c

@@ -519,6 +519,13 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *exit_ei, int flags)
   return circ;
 }
 
+/** Return the guard state associated with <b>circ</b>, which may be NULL. */
+circuit_guard_state_t *
+origin_circuit_get_guard_state(origin_circuit_t *circ)
+{
+  return circ->guard_state;
+}
+
 /** Start establishing the first hop of our circuit. Figure out what
  * OR we should connect to, and if necessary start the connection to
  * it. If we're already connected, then send the 'create' cell.

+ 2 - 0
src/or/circuitbuild.h

@@ -21,6 +21,8 @@ origin_circuit_t *origin_circuit_init(uint8_t purpose, int flags);
 origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
                                             extend_info_t *exit,
                                             int flags);
+struct circuit_guard_state_t *origin_circuit_get_guard_state(
+                                            origin_circuit_t *circ);
 int circuit_handle_first_hop(origin_circuit_t *circ);
 void circuit_n_chan_done(channel_t *chan, int status,
                          int close_origin_circuits);

+ 2 - 0
src/or/circuitlist.c

@@ -63,6 +63,7 @@
 #include "connection_edge.h"
 #include "connection_or.h"
 #include "control.h"
+#include "entrynodes.h"
 #include "main.h"
 #include "hs_common.h"
 #include "networkstatus.h"
@@ -834,6 +835,7 @@ circuit_free(circuit_t *circ)
         cpath_ref_decref(ocirc->build_state->service_pending_final_cpath_ref);
     }
     tor_free(ocirc->build_state);
+    circuit_guard_state_free(ocirc->guard_state);
 
     circuit_clear_cpath(ocirc);
 

+ 187 - 13
src/or/entrynodes.c

@@ -263,6 +263,8 @@ entry_guard_get_pathbias_state(entry_guard_t *guard)
   return &guard->pb;
 }
 
+HANDLE_IMPL(entry_guard, entry_guard_t, ATTR_UNUSED STATIC)
+
 /** Return an interval betweeen 'now' and 'max_backdate' seconds in the past,
  * chosen uniformly at random.  We use this before recording persistent
  * dates, so that we aren't leaking exactly when we recorded it.
@@ -1248,6 +1250,186 @@ entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b)
   }
 }
 
+/**
+ * Release all storage held in <b>state</b>.
+ */
+void
+circuit_guard_state_free(circuit_guard_state_t *state)
+{
+  /* XXXX prop271 -- do we want to inline this structure? */
+  if (!state)
+    return;
+  entry_guard_handle_free(state->guard);
+  tor_free(state);
+}
+
+/**
+ * Pick a suitable entry guard for a circuit in, and place that guard
+ * 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.
+ */
+int
+entry_guard_pick_for_circuit(guard_selection_t *gs,
+                             const node_t **chosen_node_out,
+                             circuit_guard_state_t **guard_state_out)
+{
+  tor_assert(gs);
+  tor_assert(chosen_node_out);
+  tor_assert(guard_state_out);
+  *chosen_node_out = NULL;
+  *guard_state_out = NULL;
+
+  unsigned state = 0;
+  entry_guard_t *guard = select_entry_guard_for_circuit(gs, &state);
+  if (! guard)
+    return -1;
+  if (BUG(state == 0))
+    return -1;
+  const node_t *node = node_get_by_id(guard->identity);
+  // XXXX prop271 check Ed ID.
+  if (! node)
+    return -1;
+
+  *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();
+
+  return 0;
+}
+
+/**
+ * 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.
+ */
+int
+entry_guard_succeeded(guard_selection_t *gs,
+                      circuit_guard_state_t **guard_state_p)
+{
+  if (BUG(*guard_state_p == NULL))
+    return -1;
+
+  entry_guard_t *guard = entry_guard_handle_get((*guard_state_p)->guard);
+  if (! guard)
+    return -1;
+
+  unsigned newstate =
+    entry_guards_note_guard_success(gs, guard, (*guard_state_p)->state);
+
+  (*guard_state_p)->state = newstate;
+  (*guard_state_p)->state_set_at = approx_time();
+
+  if (newstate == GUARD_CIRC_STATE_COMPLETE) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+/**
+ * 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
+ * not working, and advances the state of the guard module. Return -1 on
+ * bug or inconsistency; 0 on success.
+ */
+int
+entry_guard_failed(guard_selection_t *gs,
+                   circuit_guard_state_t **guard_state_p)
+{
+  if (BUG(*guard_state_p == NULL))
+    return -1;
+
+  entry_guard_t *guard = entry_guard_handle_get((*guard_state_p)->guard);
+  if (! guard)
+    return -1;
+
+  entry_guards_note_guard_failure(gs, guard);
+
+  (*guard_state_p)->state = GUARD_CIRC_STATE_DEAD;
+  (*guard_state_p)->state_set_at = approx_time();
+
+  return 0;
+}
+
+/**
+ * Return true iff every primary guard in <b>gs</b> is believed to
+ * be unreachable.
+ */
+static int
+entry_guards_all_primary_guards_are_down(guard_selection_t *gs)
+{
+  /* XXXXX prop271 do we have to call entry_guards_update_primary() ?? */
+  tor_assert(gs);
+  SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards, entry_guard_t *, guard) {
+    entry_guard_consider_retry(guard);
+    if (guard->is_reachable != GUARD_REACHABLE_NO)
+      return 0;
+  } SMARTLIST_FOREACH_END(guard);
+  return 1;
+}
+
+/**
+ * Look at all of the origin_circuit_t * objects in <b>all_circuits</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.
+ *
+ * Return 1 if we upgraded any circuits, and 0 otherwise.
+ */
+int
+entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
+                                      smartlist_t *all_circuits,
+                                      smartlist_t *newly_complete_out)
+{
+  tor_assert(gs);
+  tor_assert(all_circuits);
+  tor_assert(newly_complete_out);
+
+  if (! entry_guards_all_primary_guards_are_down(gs)) {
+    /* We only upgrade a waiting circuit if the primary guards are all
+     * down. */
+    return 0;
+  }
+
+  /* XXXX finish implementing. prop271 */
+
+  /* "If any circuit is <waiting_for_better_guard>, and every currently
+      {is_pending} circuit whose guard has higher priority has been
+      in state <usable_if_no_better_guard> for at least
+      {NONPRIMARY_GUARD_CONNECT_TIMEOUT} seconds, and all primary
+      guards have reachable status of <no>, then call that circuit
+      <complete>."
+  */
+
+  /* "If any circuit is <complete>, then do not use any
+      <waiting_for_better_guard> or <usable_if_no_better_guard> circuits
+      circuits whose guards have lower priority.  (Time them out
+      after a {NONPRIMARY_GUARD_IDLE_TIMEOUT} seconds.)"
+  */
+  return 0;
+}
+
+/**
+ * Update all derived pieces of the guard selection state in <b>gs</b>.
+ */
+void
+entry_guards_update_all(guard_selection_t *gs)
+{
+  sampled_guards_update_from_consensus(gs);
+  entry_guards_update_filtered_sets(gs);
+  entry_guards_update_confirmed(gs);
+  entry_guards_update_primary(gs);
+}
+
 /**
  * Return a newly allocated string for encoding the persistent parts of
  * <b>guard</b> to the state file.
@@ -1487,19 +1669,10 @@ __attribute__((noreturn)) void
 entry_guards_DUMMY_ENTRY_POINT(void)
 {
   // prop271 XXXXX kludge; remove this
-  sampled_guards_update_from_consensus(NULL);
-  sample_reachable_filtered_entry_guards(NULL, 0);
-  entry_guards_update_confirmed(NULL);
-  entry_guards_update_primary(NULL);
-  select_entry_guard_for_circuit(NULL, NULL);
-  entry_guards_note_guard_failure(NULL, NULL);
-  entry_guards_note_guard_success(NULL, NULL, 0);
-  entry_guard_has_higher_priority(NULL, NULL);
-  entry_guard_encode_for_state(NULL);
-  entry_guard_parse_from_state(NULL);
-  compare_guards_by_confirmed_idx(NULL, NULL);
-  entry_guards_update_filtered_sets(NULL);
-  tor_assert(0);
+   entry_guard_has_higher_priority(NULL, NULL);
+   entry_guard_encode_for_state(NULL);
+   entry_guard_parse_from_state(NULL);
+   tor_assert(0);
 }
 
 /* XXXXX ----------------------------------------------- */
@@ -2050,6 +2223,7 @@ entry_guard_free(entry_guard_t *e)
 {
   if (!e)
     return;
+  entry_guard_handles_clear(e);
   tor_free(e->chosen_by_version);
   tor_free(e->sampled_by_version);
   tor_free(e->extra_state_fields);

+ 38 - 0
src/or/entrynodes.h

@@ -12,12 +12,18 @@
 #ifndef TOR_ENTRYNODES_H
 #define TOR_ENTRYNODES_H
 
+#include "handles.h"
+
 /* Forward declare for guard_selection_t; entrynodes.c has the real struct */
 typedef struct guard_selection_s guard_selection_t;
 
 /* Forward declare for entry_guard_t; the real declaration is private. */
 typedef struct entry_guard_t entry_guard_t;
 
+/* Forward declaration for circuit_guard_state_t; the real declaration is
+   private. */
+typedef struct circuit_guard_state_t circuit_guard_state_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.
@@ -70,6 +76,8 @@ typedef struct guard_pathbias_t {
  * use a node_t, since we want to remember these even when we
  * don't have any directory info. */
 struct entry_guard_t {
+  HANDLE_ENTRY(entry_guard, entry_guard_t);
+
   char nickname[MAX_HEX_NICKNAME_LEN+1];
   char identity[DIGEST_LEN];
   ed25519_public_key_t ed_id;
@@ -259,6 +267,20 @@ struct guard_selection_s {
    */
   int should_add_entry_nodes;
 };
+
+struct entry_guard_handle_t;
+
+/**
+ * Per-circuit state to track whether we'll be able to use the circuit.
+ */
+struct circuit_guard_state_t {
+  /** Handle to the entry guard object for this circuit. */
+  struct entry_guard_handle_t *guard;
+  /** The time at which <b>state</b> last changed. */
+  time_t state_set_at;
+  /** One of GUARD_CIRC_STATE_* */
+  uint8_t state;
+};
 #endif
 
 #if 1
@@ -285,6 +307,19 @@ const char *entry_guard_get_rsa_id_digest(const entry_guard_t *guard);
 const char *entry_guard_describe(const entry_guard_t *guard);
 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,
+                                 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);
+int entry_guard_failed(guard_selection_t *gs,
+                       circuit_guard_state_t **guard_state_p);
+void entry_guards_update_all(guard_selection_t *gs);
+int entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
+                                          smartlist_t *all_circuits,
+                                          smartlist_t *newly_complete_out);
+
 /* Used by bridges.c only. */
 void add_bridge_as_entry_guard(guard_selection_t *gs,
                                const node_t *chosen);
@@ -350,6 +385,7 @@ int num_bridges_usable(void);
 /**@}*/
 
 // ---------- XXXX these functions and definitions are post-prop271.
+HANDLE_DECL(entry_guard, entry_guard_t, STATIC)
 STATIC guard_selection_t *guard_selection_new(void);
 STATIC void guard_selection_free(guard_selection_t *gs);
 STATIC entry_guard_t *get_sampled_guard_with_id(guard_selection_t *gs,
@@ -398,6 +434,8 @@ STATIC void sampled_guards_update_from_consensus(guard_selection_t *gs);
 /** State for a circuit that can (so far as the guard subsystem is
  * concerned) be used for actual traffic. */
 #define GUARD_CIRC_STATE_COMPLETE 4
+/** State for a circuit that is unusable, and will not become usable. */
+#define GUARD_CIRC_STATE_DEAD 5
 /**@}*/
 STATIC void entry_guards_note_guard_failure(guard_selection_t *gs,
                                             entry_guard_t *guard);

+ 5 - 0
src/or/or.h

@@ -3148,6 +3148,11 @@ typedef struct origin_circuit_t {
   /** Holds all rendezvous data on either client or service side. */
   rend_data_t *rend_data;
 
+  /** Holds the data that the entry guard system uses to track the
+   * status of the guard this circuit is using, and thereby to determine
+   * whether this circuit can be used. */
+  struct circuit_guard_state_t *guard_state;
+
   /** How many more relay_early cells can we send on this circuit, according
    * to the specification? */
   unsigned int remaining_relay_early_cells : 4;