diff options
author | Nick Mathewson <nickm@torproject.org> | 2016-11-18 16:05:09 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2016-11-30 14:42:52 -0500 |
commit | dd6bdab3f6254e7245f8ee76b2c6b4314f0472fa (patch) | |
tree | c8c4c6ebcb908bbc263fec2038eba1ed29aba792 /src/or/entrynodes.c | |
parent | 7bf946965bad88116582dfd3d20e5837eeddd758 (diff) | |
download | tor-dd6bdab3f6254e7245f8ee76b2c6b4314f0472fa.tar.gz tor-dd6bdab3f6254e7245f8ee76b2c6b4314f0472fa.zip |
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.)
Diffstat (limited to 'src/or/entrynodes.c')
-rw-r--r-- | src/or/entrynodes.c | 200 |
1 files changed, 187 insertions, 13 deletions
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); |