summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/or/circuitbuild.c7
-rw-r--r--src/or/circuitbuild.h2
-rw-r--r--src/or/circuitlist.c2
-rw-r--r--src/or/entrynodes.c200
-rw-r--r--src/or/entrynodes.h38
-rw-r--r--src/or/or.h5
6 files changed, 241 insertions, 13 deletions
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index b482e7818d..a33c2ca654 100644
--- a/src/or/circuitbuild.c
+++ b/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.
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index 1244601f71..56f66a19d6 100644
--- a/src/or/circuitbuild.h
+++ b/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);
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index dee103e36a..f13126d76b 100644
--- a/src/or/circuitlist.c
+++ b/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);
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 958aba47da..260b3d6e82 100644
--- a/src/or/entrynodes.c
+++ b/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.
@@ -1249,6 +1251,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);
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index 5501e624eb..5b3aa66a26 100644
--- a/src/or/entrynodes.h
+++ b/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);
diff --git a/src/or/or.h b/src/or/or.h
index eb94f63d5e..4bc806619c 100644
--- a/src/or/or.h
+++ b/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;