summaryrefslogtreecommitdiff
path: root/src/or/entrynodes.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/entrynodes.c')
-rw-r--r--src/or/entrynodes.c121
1 files changed, 110 insertions, 11 deletions
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 76a8f591b9..38b9c2c56f 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -1460,6 +1460,96 @@ guard_in_node_family(const entry_guard_t *guard, const node_t *node)
}
}
+/* Allocate and return a new exit guard restriction (where <b>exit_id</b> is of
+ * size DIGEST_LEN) */
+STATIC entry_guard_restriction_t *
+guard_create_exit_restriction(const uint8_t *exit_id)
+{
+ entry_guard_restriction_t *rst = NULL;
+ rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
+ rst->type = RST_EXIT_NODE;
+ memcpy(rst->exclude_id, exit_id, DIGEST_LEN);
+ return rst;
+}
+
+/** If we have fewer than this many possible guards, don't set
+ * MD-availability-based restrictions: we might blacklist all of
+ * them. */
+#define MIN_GUARDS_FOR_MD_RESTRICTION 10
+
+/** Return true if we should set md dirserver restrictions. We might not want
+ * to set those if our network is too restricted, since we don't want to
+ * blacklist all our nodes. */
+static int
+should_set_md_dirserver_restriction(void)
+{
+ const guard_selection_t *gs = get_guard_selection_info();
+
+ /* Compute the number of filtered guards */
+ int n_filtered_guards = 0;
+ SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) {
+ if (guard->is_filtered_guard) {
+ ++n_filtered_guards;
+ }
+ } SMARTLIST_FOREACH_END(guard);
+
+ /* Do we have enough filtered guards that we feel okay about blacklisting
+ * some for MD restriction? */
+ return (n_filtered_guards >= MIN_GUARDS_FOR_MD_RESTRICTION);
+}
+
+/** Allocate and return an outdated md guard restriction. Return NULL if no
+ * such restriction is needed. */
+STATIC entry_guard_restriction_t *
+guard_create_dirserver_md_restriction(void)
+{
+ entry_guard_restriction_t *rst = NULL;
+
+ if (!should_set_md_dirserver_restriction()) {
+ log_debug(LD_GUARD, "Not setting md restriction: too few "
+ "filtered guards.");
+ return NULL;
+ }
+
+ rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
+ rst->type = RST_OUTDATED_MD_DIRSERVER;
+
+ return rst;
+}
+
+/* Return True if <b>guard</b> obeys the exit restriction <b>rst</b>. */
+static int
+guard_obeys_exit_restriction(const entry_guard_t *guard,
+ const entry_guard_restriction_t *rst)
+{
+ tor_assert(rst->type == RST_EXIT_NODE);
+
+ // Exclude the exit ID and all of its family.
+ const node_t *node = node_get_by_id((const char*)rst->exclude_id);
+ if (node && guard_in_node_family(guard, node))
+ return 0;
+
+ return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN);
+}
+
+/** Return True if <b>guard</b> should be used as a dirserver for fetching
+ * microdescriptors. */
+static int
+guard_obeys_md_dirserver_restriction(const entry_guard_t *guard)
+{
+ /* If this guard is an outdated dirserver, don't use it. */
+ if (microdesc_relay_is_outdated_dirserver(guard->identity)) {
+ log_info(LD_GENERAL, "Skipping %s dirserver: outdated",
+ hex_str(guard->identity, DIGEST_LEN));
+ return 0;
+ }
+
+ log_debug(LD_GENERAL, "%s dirserver obeys md restrictions",
+ hex_str(guard->identity, DIGEST_LEN));
+
+ return 1;
+}
+
/**
* Return true iff <b>guard</b> obeys the restrictions defined in <b>rst</b>.
* (If <b>rst</b> is NULL, there are no restrictions.)
@@ -1472,13 +1562,14 @@ entry_guard_obeys_restriction(const entry_guard_t *guard,
if (! rst)
return 1; // No restriction? No problem.
- // Only one kind of restriction exists right now: excluding an exit
- // ID and all of its family.
- const node_t *node = node_get_by_id((const char*)rst->exclude_id);
- if (node && guard_in_node_family(guard, node))
- return 0;
+ if (rst->type == RST_EXIT_NODE) {
+ return guard_obeys_exit_restriction(guard, rst);
+ } else if (rst->type == RST_OUTDATED_MD_DIRSERVER) {
+ return guard_obeys_md_dirserver_restriction(guard);
+ }
- return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN);
+ tor_assert_nonfatal_unreached();
+ return 0;
}
/**
@@ -2105,7 +2196,7 @@ entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b)
}
/** Release all storage held in <b>restriction</b> */
-static void
+STATIC void
entry_guard_restriction_free(entry_guard_restriction_t *rst)
{
tor_free(rst);
@@ -3358,8 +3449,8 @@ guards_choose_guard(cpath_build_state_t *state,
/* We're building to a targeted exit node, so that node can't be
* chosen as our guard for this circuit. Remember that fact in a
* restriction. */
- rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
- memcpy(rst->exclude_id, exit_id, DIGEST_LEN);
+ rst = guard_create_exit_restriction(exit_id);
+ tor_assert(rst);
}
if (entry_guard_pick_for_circuit(get_guard_selection_info(),
GUARD_USAGE_TRAFFIC,
@@ -3411,12 +3502,20 @@ remove_all_entry_guards(void)
/** Helper: pick a directory guard, with whatever algorithm is used. */
const node_t *
-guards_choose_dirguard(circuit_guard_state_t **guard_state_out)
+guards_choose_dirguard(uint8_t dir_purpose,
+ circuit_guard_state_t **guard_state_out)
{
const node_t *r = NULL;
+ entry_guard_restriction_t *rst = NULL;
+
+ /* If we are fetching microdescs, don't query outdated dirservers. */
+ if (dir_purpose == DIR_PURPOSE_FETCH_MICRODESC) {
+ rst = guard_create_dirserver_md_restriction();
+ }
+
if (entry_guard_pick_for_circuit(get_guard_selection_info(),
GUARD_USAGE_DIRGUARD,
- NULL,
+ rst,
&r,
guard_state_out) < 0) {
tor_assert(r == NULL);