diff options
-rw-r--r-- | src/or/circuitbuild.c | 7 | ||||
-rw-r--r-- | src/or/circuitbuild.h | 2 | ||||
-rw-r--r-- | src/or/circuitlist.c | 2 | ||||
-rw-r--r-- | src/or/entrynodes.c | 200 | ||||
-rw-r--r-- | src/or/entrynodes.h | 38 | ||||
-rw-r--r-- | src/or/or.h | 5 |
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; |