Don't (usually) return any guards that are missing descriptors.

Actually, it's _fine_ to use a descriptorless guard for fetching
directory info -- we just shouldn't use it when building circuits.
Fortunately, we already have a "usage" flag that we can use here.

Partial fix for bug 21242.
This commit is contained in:
Nick Mathewson 2017-01-31 12:30:33 -05:00
parent 26957a127a
commit 02da24f8e5
2 changed files with 25 additions and 1 deletions

View File

@ -185,6 +185,16 @@ should_apply_guardfraction(const networkstatus_t *ns)
return options->UseGuardFraction; return options->UseGuardFraction;
} }
/** Return true iff we know a descriptor for <b>guard</b> */
static int
guard_has_descriptor(const entry_guard_t *guard)
{
const node_t *node = node_get_by_id(guard->identity);
if (!node)
return 0;
return node_has_descriptor(node);
}
/** /**
* Try to determine the correct type for a selection named "name", * Try to determine the correct type for a selection named "name",
* if <b>type</b> is GS_TYPE_INFER. * if <b>type</b> is GS_TYPE_INFER.
@ -1447,6 +1457,7 @@ sample_reachable_filtered_entry_guards(guard_selection_t *gs,
const unsigned exclude_primary = flags & SAMPLE_EXCLUDE_PRIMARY; const unsigned exclude_primary = flags & SAMPLE_EXCLUDE_PRIMARY;
const unsigned exclude_pending = flags & SAMPLE_EXCLUDE_PENDING; const unsigned exclude_pending = flags & SAMPLE_EXCLUDE_PENDING;
const unsigned no_update_primary = flags & SAMPLE_NO_UPDATE_PRIMARY; const unsigned no_update_primary = flags & SAMPLE_NO_UPDATE_PRIMARY;
const unsigned need_descriptor = flags & SAMPLE_EXCLUDE_NO_DESCRIPTOR;
SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) { SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) {
entry_guard_consider_retry(guard); entry_guard_consider_retry(guard);
@ -1480,6 +1491,8 @@ sample_reachable_filtered_entry_guards(guard_selection_t *gs,
continue; continue;
if (exclude_pending && guard->is_pending) if (exclude_pending && guard->is_pending)
continue; continue;
if (need_descriptor && !guard_has_descriptor(guard))
continue;
smartlist_add(reachable_filtered_sample, guard); smartlist_add(reachable_filtered_sample, guard);
} SMARTLIST_FOREACH_END(guard); } SMARTLIST_FOREACH_END(guard);
@ -1777,6 +1790,7 @@ select_entry_guard_for_circuit(guard_selection_t *gs,
const entry_guard_restriction_t *rst, const entry_guard_restriction_t *rst,
unsigned *state_out) unsigned *state_out)
{ {
const int need_descriptor = (usage == GUARD_USAGE_TRAFFIC);
tor_assert(gs); tor_assert(gs);
tor_assert(state_out); tor_assert(state_out);
@ -1793,6 +1807,9 @@ select_entry_guard_for_circuit(guard_selection_t *gs,
if (! entry_guard_obeys_restriction(guard, rst)) if (! entry_guard_obeys_restriction(guard, rst))
continue; continue;
if (guard->is_reachable != GUARD_REACHABLE_NO) { if (guard->is_reachable != GUARD_REACHABLE_NO) {
if (need_descriptor && BUG(!guard_has_descriptor(guard))) {
continue;
}
*state_out = GUARD_CIRC_STATE_USABLE_ON_COMPLETION; *state_out = GUARD_CIRC_STATE_USABLE_ON_COMPLETION;
guard->last_tried_to_connect = approx_time(); guard->last_tried_to_connect = approx_time();
smartlist_add(usable_primary_guards, guard); smartlist_add(usable_primary_guards, guard);
@ -1821,6 +1838,8 @@ select_entry_guard_for_circuit(guard_selection_t *gs,
continue; continue;
entry_guard_consider_retry(guard); entry_guard_consider_retry(guard);
if (guard->is_usable_filtered_guard && ! guard->is_pending) { if (guard->is_usable_filtered_guard && ! guard->is_pending) {
if (need_descriptor && !guard_has_descriptor(guard))
continue; /* not a bug */
guard->is_pending = 1; guard->is_pending = 1;
guard->last_tried_to_connect = approx_time(); guard->last_tried_to_connect = approx_time();
*state_out = GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD; *state_out = GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD;
@ -1836,11 +1855,15 @@ select_entry_guard_for_circuit(guard_selection_t *gs,
random from {USABLE_FILTERED_GUARDS}." */ random from {USABLE_FILTERED_GUARDS}." */
{ {
entry_guard_t *guard; entry_guard_t *guard;
unsigned flags = 0;
if (need_descriptor)
flags |= SAMPLE_EXCLUDE_NO_DESCRIPTOR;
guard = sample_reachable_filtered_entry_guards(gs, guard = sample_reachable_filtered_entry_guards(gs,
rst, rst,
SAMPLE_EXCLUDE_CONFIRMED | SAMPLE_EXCLUDE_CONFIRMED |
SAMPLE_EXCLUDE_PRIMARY | SAMPLE_EXCLUDE_PRIMARY |
SAMPLE_EXCLUDE_PENDING); SAMPLE_EXCLUDE_PENDING |
flags);
if (guard == NULL) { if (guard == NULL) {
log_info(LD_GUARD, "Absolutely no sampled guards were available."); log_info(LD_GUARD, "Absolutely no sampled guards were available.");
return NULL; return NULL;

View File

@ -498,6 +498,7 @@ STATIC int entry_guards_all_primary_guards_are_down(guard_selection_t *gs);
#define SAMPLE_EXCLUDE_PRIMARY (1u<<1) #define SAMPLE_EXCLUDE_PRIMARY (1u<<1)
#define SAMPLE_EXCLUDE_PENDING (1u<<2) #define SAMPLE_EXCLUDE_PENDING (1u<<2)
#define SAMPLE_NO_UPDATE_PRIMARY (1u<<3) #define SAMPLE_NO_UPDATE_PRIMARY (1u<<3)
#define SAMPLE_EXCLUDE_NO_DESCRIPTOR (1u<<4)
/**@}*/ /**@}*/
STATIC entry_guard_t *sample_reachable_filtered_entry_guards( STATIC entry_guard_t *sample_reachable_filtered_entry_guards(
guard_selection_t *gs, guard_selection_t *gs,