aboutsummaryrefslogtreecommitdiff
path: root/src/or/dirserv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/dirserv.c')
-rw-r--r--src/or/dirserv.c1039
1 files changed, 429 insertions, 610 deletions
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index b18d0a5951..984b47d2f5 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -26,6 +26,7 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "routerset.h"
/**
* \file dirserv.c
@@ -55,9 +56,6 @@ static time_t the_directory_is_dirty = 1;
/** Do we need to regenerate the v1 runningrouters document when somebody
* asks for it? */
static time_t runningrouters_is_dirty = 1;
-/** Do we need to regenerate our v2 networkstatus document when somebody asks
- * for it? */
-static time_t the_v2_networkstatus_is_dirty = 1;
/** Most recently generated encoded signed v1 directory. (v1 auth dirservers
* only.) */
@@ -66,18 +64,12 @@ static cached_dir_t *the_directory = NULL;
/** For authoritative directories: the current (v1) network status. */
static cached_dir_t the_runningrouters;
-/** Array of start and end of consensus methods used for supported
- microdescriptor formats. */
-static const struct consensus_method_range_t {
- int low;
- int high;
-} microdesc_consensus_methods[] = {
- {MIN_METHOD_FOR_MICRODESC, MIN_METHOD_FOR_A_LINES - 1},
- {MIN_METHOD_FOR_A_LINES, MIN_METHOD_FOR_P6_LINES - 1},
- {MIN_METHOD_FOR_P6_LINES, MIN_METHOD_FOR_NTOR_KEY - 1},
- {MIN_METHOD_FOR_NTOR_KEY, MAX_SUPPORTED_CONSENSUS_METHOD},
- {-1, -1}
-};
+/** Total number of routers with measured bandwidth; this is set by
+ * dirserv_count_measured_bws() before the loop in
+ * dirserv_generate_networkstatus_vote_obj() and checked by
+ * dirserv_get_credible_bandwidth() and
+ * dirserv_compute_performance_thresholds() */
+static int routers_with_measured_bw = 0;
static void directory_remove_invalid(void);
static cached_dir_t *dirserv_regenerate_directory(void);
@@ -97,9 +89,8 @@ static const signed_descriptor_t *get_signed_descriptor_by_fp(
time_t publish_cutoff);
static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei,
const char **msg);
-
-/************** Measured Bandwidth parsing code ******/
-#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */
+static uint32_t dirserv_get_bandwidth_for_router_kb(const routerinfo_t *ri);
+static uint32_t dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri);
/************** Fingerprint handling code ************/
@@ -922,8 +913,6 @@ directory_set_dirty(void)
if (!runningrouters_is_dirty)
runningrouters_is_dirty = now;
}
- if (!the_v2_networkstatus_is_dirty)
- the_v2_networkstatus_is_dirty = now;
}
/**
@@ -1265,14 +1254,6 @@ directory_fetches_dir_info_later(const or_options_t *options)
return options->UseBridges != 0;
}
-/** Return 1 if we want to cache v2 dir info (each status file).
- */
-int
-directory_caches_v2_dir_info(const or_options_t *options)
-{
- return options->DirPort_set;
-}
-
/** Return true iff we want to fetch and keep certificates for authorities
* that we don't acknowledge as aurthorities ourself.
*/
@@ -1307,15 +1288,6 @@ directory_permits_begindir_requests(const or_options_t *options)
return options->BridgeRelay != 0 || options->DirPort_set;
}
-/** Return 1 if we want to allow controllers to ask us directory
- * requests via the controller interface, which doesn't require
- * having any separate port open. */
-int
-directory_permits_controller_requests(const or_options_t *options)
-{
- return options->DirPort_set;
-}
-
/** Return 1 if we have no need to fetch new descriptors. This generally
* happens when we're not a dir cache and we haven't built any circuits
* lately.
@@ -1341,10 +1313,6 @@ static cached_dir_t *cached_directory = NULL;
* if requested. */
static cached_dir_t cached_runningrouters;
-/** Used for other dirservers' v2 network statuses. Map from hexdigest to
- * cached_dir_t. */
-static digestmap_t *cached_v2_networkstatus = NULL;
-
/** Map from flavor name to the cached_dir_t for the v3 consensuses that we're
* currently serving. */
static strmap_t *cached_consensuses = NULL;
@@ -1445,70 +1413,6 @@ dirserv_set_cached_directory(const char *directory, time_t published)
cached_directory = new_cached_dir(tor_strdup(directory), published);
}
-/** If <b>networkstatus</b> is non-NULL, we've just received a v2
- * network-status for an authoritative directory with identity digest
- * <b>identity</b> published at <b>published</b> -- store it so we can
- * serve it to others.
- *
- * If <b>networkstatus</b> is NULL, remove the entry with the given
- * identity fingerprint from the v2 cache.
- */
-void
-dirserv_set_cached_networkstatus_v2(const char *networkstatus,
- const char *identity,
- time_t published)
-{
- cached_dir_t *d, *old_d;
- if (!cached_v2_networkstatus)
- cached_v2_networkstatus = digestmap_new();
-
- old_d = digestmap_get(cached_v2_networkstatus, identity);
- if (!old_d && !networkstatus)
- return;
-
- if (networkstatus) {
- if (!old_d || published > old_d->published) {
- d = new_cached_dir(tor_strdup(networkstatus), published);
- digestmap_set(cached_v2_networkstatus, identity, d);
- if (old_d)
- cached_dir_decref(old_d);
- }
- } else {
- if (old_d) {
- digestmap_remove(cached_v2_networkstatus, identity);
- cached_dir_decref(old_d);
- }
- }
-
- /* Now purge old entries. */
-
- if (digestmap_size(cached_v2_networkstatus) >
- get_n_authorities(V2_DIRINFO) + MAX_UNTRUSTED_NETWORKSTATUSES) {
- /* We need to remove the oldest untrusted networkstatus. */
- const char *oldest = NULL;
- time_t oldest_published = TIME_MAX;
- digestmap_iter_t *iter;
-
- for (iter = digestmap_iter_init(cached_v2_networkstatus);
- !digestmap_iter_done(iter);
- iter = digestmap_iter_next(cached_v2_networkstatus, iter)) {
- const char *ident;
- void *val;
- digestmap_iter_get(iter, &ident, &val);
- d = val;
- if (d->published < oldest_published &&
- !router_digest_is_trusted_dir(ident)) {
- oldest = ident;
- oldest_published = d->published;
- }
- }
- tor_assert(oldest);
- d = digestmap_remove(cached_v2_networkstatus, oldest);
- if (d)
- cached_dir_decref(d);
- }
-}
-
/** Replace the v3 consensus networkstatus of type <b>flavor_name</b> that
* we're serving with <b>networkstatus</b>, published at <b>published</b>. No
* validation is performed. */
@@ -1531,46 +1435,7 @@ dirserv_set_cached_consensus_networkstatus(const char *networkstatus,
cached_dir_decref(old_networkstatus);
}
-/** Remove any v2 networkstatus from the directory cache that was published
- * before <b>cutoff</b>. */
-void
-dirserv_clear_old_networkstatuses(time_t cutoff)
-{
- if (!cached_v2_networkstatus)
- return;
-
- DIGESTMAP_FOREACH_MODIFY(cached_v2_networkstatus, id, cached_dir_t *, dir) {
- if (dir->published < cutoff) {
- char *fname;
- fname = networkstatus_get_cache_filename(id);
- if (file_status(fname) == FN_FILE) {
- log_info(LD_DIR, "Removing too-old untrusted networkstatus in %s",
- fname);
- unlink(fname);
- }
- tor_free(fname);
- cached_dir_decref(dir);
- MAP_DEL_CURRENT(id);
- }
- } DIGESTMAP_FOREACH_END
-}
-
-/** Remove any v1 info from the directory cache that was published
- * too long ago. */
-void
-dirserv_clear_old_v1_info(time_t now)
-{
- if (cached_directory &&
- cached_directory->published < (now - MAX_V1_DIRECTORY_AGE)) {
- cached_dir_decref(cached_directory);
- cached_directory = NULL;
- }
- if (cached_runningrouters.published < (now - MAX_V1_RR_AGE)) {
- clear_cached_dir(&cached_runningrouters);
- }
-}
-
-/** Helper: If we're an authority for the right directory version (v1 or v2)
+/** Helper: If we're an authority for the right directory version (v1)
* (based on <b>auth_type</b>), try to regenerate
* auth_src as appropriate and return it, falling back to cache_src on
* failure. If we're a cache, simply return cache_src.
@@ -1583,8 +1448,7 @@ dirserv_pick_cached_dir_obj(cached_dir_t *cache_src,
dirinfo_type_t auth_type)
{
const or_options_t *options = get_options();
- int authority = (auth_type == V1_DIRINFO && authdir_mode_v1(options)) ||
- (auth_type == V2_DIRINFO && authdir_mode_v2(options));
+ int authority = (auth_type == V1_DIRINFO && authdir_mode_v1(options));
if (!authority || authdir_mode_bridge(options)) {
return cache_src;
@@ -1721,19 +1585,6 @@ dirserv_get_consensus(const char *flavor_name)
return strmap_get(cached_consensuses, flavor_name);
}
-/** For authoritative directories: the current (v2) network status. */
-static cached_dir_t *the_v2_networkstatus = NULL;
-
-/** Return true iff our opinion of the routers has been stale for long
- * enough that we should generate a new v2 network status doc. */
-static int
-should_generate_v2_networkstatus(void)
-{
- return authdir_mode_v2(get_options()) &&
- the_v2_networkstatus_is_dirty &&
- the_v2_networkstatus_is_dirty + DIR_REGEN_SLACK_TIME < time(NULL);
-}
-
/** If a router's uptime is at least this value, then it is always
* considered stable, regardless of the rest of the network. This
* way we resist attacks where an attacker doubles the size of the
@@ -1770,17 +1621,13 @@ static double guard_wfu = 0.0;
* many seconds. */
static long guard_tk = 0;
/** Any router with a bandwidth at least this high is "Fast" */
-static uint32_t fast_bandwidth = 0;
+static uint32_t fast_bandwidth_kb = 0;
/** If exits can be guards, then all guards must have a bandwidth this
* high. */
-static uint32_t guard_bandwidth_including_exits = 0;
+static uint32_t guard_bandwidth_including_exits_kb = 0;
/** If exits can't be guards, then all guards must have a bandwidth this
* high. */
-static uint32_t guard_bandwidth_excluding_exits = 0;
-/** Total bandwidth of all the routers we're considering. */
-static uint64_t total_bandwidth = 0;
-/** Total bandwidth of all the exit routers we're considering. */
-static uint64_t total_exit_bandwidth = 0;
+static uint32_t guard_bandwidth_excluding_exits_kb = 0;
/** Helper: estimate the uptime of a router given its stated uptime and the
* amount of time since it last stated its stated uptime. */
@@ -1824,8 +1671,8 @@ dirserv_thinks_router_is_unreliable(time_t now,
}
}
if (need_capacity) {
- uint32_t bw = router_get_advertised_bandwidth(router);
- if (bw < fast_bandwidth)
+ uint32_t bw_kb = dirserv_get_credible_bandwidth_kb(router);
+ if (bw_kb < fast_bandwidth_kb)
return 1;
}
return 0;
@@ -1873,26 +1720,39 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router,
/** Don't consider routers with less bandwidth than this when computing
* thresholds. */
-#define ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER 4096
+#define ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER_KB 4
/** Helper for dirserv_compute_performance_thresholds(): Decide whether to
- * include a router in our calculations, and return true iff we should. */
+ * include a router in our calculations, and return true iff we should; the
+ * require_mbw parameter is passed in by
+ * dirserv_compute_performance_thresholds() and controls whether we ever
+ * count routers with only advertised bandwidths */
static int
router_counts_toward_thresholds(const node_t *node, time_t now,
- const digestmap_t *omit_as_sybil)
+ const digestmap_t *omit_as_sybil,
+ int require_mbw)
{
+ /* Have measured bw? */
+ int have_mbw =
+ dirserv_has_measured_bw(node->identity);
+ uint64_t min_bw_kb = ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER_KB;
+ const or_options_t *options = get_options();
+
+ if (options->TestingTorNetwork) {
+ min_bw_kb = (int64_t)options->TestingMinExitFlagThreshold / 1000;
+ }
+
return node->ri && router_is_active(node->ri, node, now) &&
- !digestmap_get(omit_as_sybil, node->ri->cache_info.identity_digest) &&
- (router_get_advertised_bandwidth(node->ri) >=
- ABSOLUTE_MIN_BW_VALUE_TO_CONSIDER);
+ !digestmap_get(omit_as_sybil, node->identity) &&
+ (dirserv_get_credible_bandwidth_kb(node->ri) >= min_bw_kb) &&
+ (have_mbw || !require_mbw);
}
/** Look through the routerlist, the Mean Time Between Failure history, and
* the Weighted Fractional Uptime history, and use them to set thresholds for
* the Stable, Fast, and Guard flags. Update the fields stable_uptime,
* stable_mtbf, enough_mtbf_info, guard_wfu, guard_tk, fast_bandwidth,
- * guard_bandwidh_including_exits, guard_bandwidth_excluding_exits,
- * total_bandwidth, and total_exit_bandwidth.
+ * guard_bandwidth_including_exits, and guard_bandwidth_excluding_exits.
*
* Also, set the is_exit flag of each router appropriately. */
static void
@@ -1900,22 +1760,25 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
digestmap_t *omit_as_sybil)
{
int n_active, n_active_nonexit, n_familiar;
- uint32_t *uptimes, *bandwidths, *bandwidths_excluding_exits;
+ uint32_t *uptimes, *bandwidths_kb, *bandwidths_excluding_exits_kb;
long *tks;
double *mtbfs, *wfus;
time_t now = time(NULL);
const or_options_t *options = get_options();
+ /* Require mbw? */
+ int require_mbw =
+ (routers_with_measured_bw >
+ options->MinMeasuredBWsForAuthToIgnoreAdvertised) ? 1 : 0;
+
/* initialize these all here, in case there are no routers */
stable_uptime = 0;
stable_mtbf = 0;
- fast_bandwidth = 0;
- guard_bandwidth_including_exits = 0;
- guard_bandwidth_excluding_exits = 0;
+ fast_bandwidth_kb = 0;
+ guard_bandwidth_including_exits_kb = 0;
+ guard_bandwidth_excluding_exits_kb = 0;
guard_tk = 0;
guard_wfu = 0;
- total_bandwidth = 0;
- total_exit_bandwidth = 0;
/* Initialize arrays that will hold values for each router. We'll
* sort them and use that to compute thresholds. */
@@ -1923,9 +1786,9 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
/* Uptime for every active router. */
uptimes = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
/* Bandwidth for every active router. */
- bandwidths = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
+ bandwidths_kb = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
/* Bandwidth for every active non-exit router. */
- bandwidths_excluding_exits =
+ bandwidths_excluding_exits_kb =
tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
/* Weighted mean time between failure for each active router. */
mtbfs = tor_malloc(sizeof(double)*smartlist_len(rl->routers));
@@ -1938,21 +1801,23 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
/* Now, fill in the arrays. */
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) {
- if (router_counts_toward_thresholds(node, now, omit_as_sybil)) {
+ if (options->BridgeAuthoritativeDir &&
+ node->ri &&
+ node->ri->purpose != ROUTER_PURPOSE_BRIDGE)
+ continue;
+ if (router_counts_toward_thresholds(node, now, omit_as_sybil,
+ require_mbw)) {
routerinfo_t *ri = node->ri;
- const char *id = ri->cache_info.identity_digest;
- uint32_t bw;
+ const char *id = node->identity;
+ uint32_t bw_kb;
node->is_exit = (!router_exit_policy_rejects_all(ri) &&
exit_policy_is_general_exit(ri->exit_policy));
uptimes[n_active] = (uint32_t)real_uptime(ri, now);
mtbfs[n_active] = rep_hist_get_stability(id, now);
tks [n_active] = rep_hist_get_weighted_time_known(id, now);
- bandwidths[n_active] = bw = router_get_advertised_bandwidth(ri);
- total_bandwidth += bw;
- if (node->is_exit && !node->is_bad_exit) {
- total_exit_bandwidth += bw;
- } else {
- bandwidths_excluding_exits[n_active_nonexit] = bw;
+ bandwidths_kb[n_active] = bw_kb = dirserv_get_credible_bandwidth_kb(ri);
+ if (!node->is_exit || node->is_bad_exit) {
+ bandwidths_excluding_exits_kb[n_active_nonexit] = bw_kb;
++n_active_nonexit;
}
++n_active;
@@ -1966,11 +1831,11 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
/* The median mtbf is stable, if we have enough mtbf info */
stable_mtbf = median_double(mtbfs, n_active);
/* The 12.5th percentile bandwidth is fast. */
- fast_bandwidth = find_nth_uint32(bandwidths, n_active, n_active/8);
+ fast_bandwidth_kb = find_nth_uint32(bandwidths_kb, n_active, n_active/8);
/* (Now bandwidths is sorted.) */
- if (fast_bandwidth < ROUTER_REQUIRED_MIN_BANDWIDTH/2)
- fast_bandwidth = bandwidths[n_active/4];
- guard_bandwidth_including_exits = bandwidths[(n_active-1)/2];
+ if (fast_bandwidth_kb < ROUTER_REQUIRED_MIN_BANDWIDTH/(2 * 1000))
+ fast_bandwidth_kb = bandwidths_kb[n_active/4];
+ guard_bandwidth_including_exits_kb = bandwidths_kb[(n_active-1)/2];
guard_tk = find_nth_long(tks, n_active, n_active/8);
}
@@ -1979,31 +1844,38 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
{
/* We can vote on a parameter for the minimum and maximum. */
-#define ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG 4096
- int32_t min_fast, max_fast;
+#define ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG 4
+ int32_t min_fast_kb, max_fast_kb, min_fast, max_fast;
min_fast = networkstatus_get_param(NULL, "FastFlagMinThreshold",
ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG,
ABSOLUTE_MIN_VALUE_FOR_FAST_FLAG,
INT32_MAX);
+ if (options->TestingTorNetwork) {
+ min_fast = (int32_t)options->TestingMinFastFlagThreshold;
+ }
max_fast = networkstatus_get_param(NULL, "FastFlagMaxThreshold",
INT32_MAX, min_fast, INT32_MAX);
- if (fast_bandwidth < (uint32_t)min_fast)
- fast_bandwidth = min_fast;
- if (fast_bandwidth > (uint32_t)max_fast)
- fast_bandwidth = max_fast;
+ min_fast_kb = min_fast / 1000;
+ max_fast_kb = max_fast / 1000;
+
+ if (fast_bandwidth_kb < (uint32_t)min_fast_kb)
+ fast_bandwidth_kb = min_fast_kb;
+ if (fast_bandwidth_kb > (uint32_t)max_fast_kb)
+ fast_bandwidth_kb = max_fast_kb;
}
/* Protect sufficiently fast nodes from being pushed out of the set
* of Fast nodes. */
if (options->AuthDirFastGuarantee &&
- fast_bandwidth > options->AuthDirFastGuarantee)
- fast_bandwidth = (uint32_t)options->AuthDirFastGuarantee;
+ fast_bandwidth_kb > options->AuthDirFastGuarantee/1000)
+ fast_bandwidth_kb = (uint32_t)options->AuthDirFastGuarantee/1000;
/* Now that we have a time-known that 7/8 routers are known longer than,
* fill wfus with the wfu of every such "familiar" router. */
n_familiar = 0;
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) {
- if (router_counts_toward_thresholds(node, now, omit_as_sybil)) {
+ if (router_counts_toward_thresholds(node, now,
+ omit_as_sybil, require_mbw)) {
routerinfo_t *ri = node->ri;
const char *id = ri->cache_info.identity_digest;
long tk = rep_hist_get_weighted_time_known(id, now);
@@ -2020,52 +1892,270 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
enough_mtbf_info = rep_hist_have_measured_enough_stability();
if (n_active_nonexit) {
- guard_bandwidth_excluding_exits =
- median_uint32(bandwidths_excluding_exits, n_active_nonexit);
+ guard_bandwidth_excluding_exits_kb =
+ median_uint32(bandwidths_excluding_exits_kb, n_active_nonexit);
}
log_info(LD_DIRSERV,
"Cutoffs: For Stable, %lu sec uptime, %lu sec MTBF. "
- "For Fast: %lu bytes/sec. "
+ "For Fast: %lu kilobytes/sec. "
"For Guard: WFU %.03f%%, time-known %lu sec, "
- "and bandwidth %lu or %lu bytes/sec. We%s have enough stability data.",
+ "and bandwidth %lu or %lu kilobytes/sec. "
+ "We%s have enough stability data.",
(unsigned long)stable_uptime,
(unsigned long)stable_mtbf,
- (unsigned long)fast_bandwidth,
+ (unsigned long)fast_bandwidth_kb,
guard_wfu*100,
(unsigned long)guard_tk,
- (unsigned long)guard_bandwidth_including_exits,
- (unsigned long)guard_bandwidth_excluding_exits,
+ (unsigned long)guard_bandwidth_including_exits_kb,
+ (unsigned long)guard_bandwidth_excluding_exits_kb,
enough_mtbf_info ? "" : " don't ");
tor_free(uptimes);
tor_free(mtbfs);
- tor_free(bandwidths);
- tor_free(bandwidths_excluding_exits);
+ tor_free(bandwidths_kb);
+ tor_free(bandwidths_excluding_exits_kb);
tor_free(tks);
tor_free(wfus);
}
+/* Use dirserv_compute_performance_thresholds() to compute the thresholds
+ * for the status flags, specifically for bridges.
+ *
+ * This is only called by a Bridge Authority from
+ * networkstatus_getinfo_by_purpose().
+ */
+void
+dirserv_compute_bridge_flag_thresholds(routerlist_t *rl)
+{
+
+ digestmap_t *omit_as_sybil = digestmap_new();
+ dirserv_compute_performance_thresholds(rl, omit_as_sybil);
+ digestmap_free(omit_as_sybil, NULL);
+}
+
+/** Measured bandwidth cache entry */
+typedef struct mbw_cache_entry_s {
+ long mbw_kb;
+ time_t as_of;
+} mbw_cache_entry_t;
+
+/** Measured bandwidth cache - keys are identity_digests, values are
+ * mbw_cache_entry_t *. */
+static digestmap_t *mbw_cache = NULL;
+
+/** Store a measured bandwidth cache entry when reading the measured
+ * bandwidths file. */
+STATIC void
+dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
+ time_t as_of)
+{
+ mbw_cache_entry_t *e = NULL;
+
+ tor_assert(parsed_line);
+
+ /* Allocate a cache if we need */
+ if (!mbw_cache) mbw_cache = digestmap_new();
+
+ /* Check if we have an existing entry */
+ e = digestmap_get(mbw_cache, parsed_line->node_id);
+ /* If we do, we can re-use it */
+ if (e) {
+ /* Check that we really are newer, and update */
+ if (as_of > e->as_of) {
+ e->mbw_kb = parsed_line->bw_kb;
+ e->as_of = as_of;
+ }
+ } else {
+ /* We'll have to insert a new entry */
+ e = tor_malloc(sizeof(*e));
+ e->mbw_kb = parsed_line->bw_kb;
+ e->as_of = as_of;
+ digestmap_set(mbw_cache, parsed_line->node_id, e);
+ }
+}
+
+/** Clear and free the measured bandwidth cache */
+STATIC void
+dirserv_clear_measured_bw_cache(void)
+{
+ if (mbw_cache) {
+ /* Free the map and all entries */
+ digestmap_free(mbw_cache, tor_free_);
+ mbw_cache = NULL;
+ }
+}
+
+/** Scan the measured bandwidth cache and remove expired entries */
+STATIC void
+dirserv_expire_measured_bw_cache(time_t now)
+{
+
+ if (mbw_cache) {
+ /* Iterate through the cache and check each entry */
+ DIGESTMAP_FOREACH_MODIFY(mbw_cache, k, mbw_cache_entry_t *, e) {
+ if (now > e->as_of + MAX_MEASUREMENT_AGE) {
+ tor_free(e);
+ MAP_DEL_CURRENT(k);
+ }
+ } DIGESTMAP_FOREACH_END;
+
+ /* Check if we cleared the whole thing and free if so */
+ if (digestmap_size(mbw_cache) == 0) {
+ digestmap_free(mbw_cache, tor_free_);
+ mbw_cache = 0;
+ }
+ }
+}
+
+/** Get the current size of the measured bandwidth cache */
+STATIC int
+dirserv_get_measured_bw_cache_size(void)
+{
+ if (mbw_cache) return digestmap_size(mbw_cache);
+ else return 0;
+}
+
+/** Query the cache by identity digest, return value indicates whether
+ * we found it. The bw_out and as_of_out pointers receive the cached
+ * bandwidth value and the time it was cached if not NULL. */
+STATIC int
+dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out,
+ time_t *as_of_out)
+{
+ mbw_cache_entry_t *v = NULL;
+ int rv = 0;
+
+ if (mbw_cache && node_id) {
+ v = digestmap_get(mbw_cache, node_id);
+ if (v) {
+ /* Found something */
+ rv = 1;
+ if (bw_kb_out) *bw_kb_out = v->mbw_kb;
+ if (as_of_out) *as_of_out = v->as_of;
+ }
+ }
+
+ return rv;
+}
+
+/** Predicate wrapper for dirserv_query_measured_bw_cache() */
+STATIC int
+dirserv_has_measured_bw(const char *node_id)
+{
+ return dirserv_query_measured_bw_cache_kb(node_id, NULL, NULL);
+}
+
+/** Get the best estimate of a router's bandwidth for dirauth purposes,
+ * preferring measured to advertised values if available. */
+
+static uint32_t
+dirserv_get_bandwidth_for_router_kb(const routerinfo_t *ri)
+{
+ uint32_t bw_kb = 0;
+ /*
+ * Yeah, measured bandwidths in measured_bw_line_t are (implicitly
+ * signed) longs and the ones router_get_advertised_bandwidth() returns
+ * are uint32_t.
+ */
+ long mbw_kb = 0;
+
+ if (ri) {
+ /*
+ * * First try to see if we have a measured bandwidth; don't bother with
+ * as_of_out here, on the theory that a stale measured bandwidth is still
+ * better to trust than an advertised one.
+ */
+ if (dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest,
+ &mbw_kb, NULL)) {
+ /* Got one! */
+ bw_kb = (uint32_t)mbw_kb;
+ } else {
+ /* If not, fall back to advertised */
+ bw_kb = router_get_advertised_bandwidth(ri) / 1000;
+ }
+ }
+
+ return bw_kb;
+}
+
+/** Look through the routerlist, and using the measured bandwidth cache count
+ * how many measured bandwidths we know. This is used to decide whether we
+ * ever trust advertised bandwidths for purposes of assigning flags. */
+static void
+dirserv_count_measured_bws(routerlist_t *rl)
+{
+ /* Initialize this first */
+ routers_with_measured_bw = 0;
+
+ tor_assert(rl);
+ tor_assert(rl->routers);
+
+ /* Iterate over the routerlist and count measured bandwidths */
+ SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) {
+ /* Check if we know a measured bandwidth for this one */
+ if (dirserv_has_measured_bw(ri->cache_info.identity_digest)) {
+ ++routers_with_measured_bw;
+ }
+ } SMARTLIST_FOREACH_END(ri);
+}
+
+/** Return the bandwidth we believe for assigning flags; prefer measured
+ * over advertised, and if we have above a threshold quantity of measured
+ * bandwidths, we don't want to ever give flags to unmeasured routers, so
+ * return 0. */
+static uint32_t
+dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri)
+{
+ int threshold;
+ uint32_t bw_kb = 0;
+ long mbw_kb;
+
+ tor_assert(ri);
+ /* Check if we have a measured bandwidth, and check the threshold if not */
+ if (!(dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest,
+ &mbw_kb, NULL))) {
+ threshold = get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised;
+ if (routers_with_measured_bw > threshold) {
+ /* Return zero for unmeasured bandwidth if we are above threshold */
+ bw_kb = 0;
+ } else {
+ /* Return an advertised bandwidth otherwise */
+ bw_kb = router_get_advertised_bandwidth_capped(ri) / 1000;
+ }
+ } else {
+ /* We have the measured bandwidth in mbw */
+ bw_kb = (uint32_t)mbw_kb;
+ }
+
+ return bw_kb;
+}
+
/** Give a statement of our current performance thresholds for inclusion
* in a vote document. */
char *
dirserv_get_flag_thresholds_line(void)
{
char *result=NULL;
+ const int measured_threshold =
+ get_options()->MinMeasuredBWsForAuthToIgnoreAdvertised;
+ const int enough_measured_bw = routers_with_measured_bw > measured_threshold;
+
tor_asprintf(&result,
"stable-uptime=%lu stable-mtbf=%lu "
"fast-speed=%lu "
"guard-wfu=%.03f%% guard-tk=%lu "
"guard-bw-inc-exits=%lu guard-bw-exc-exits=%lu "
- "enough-mtbf=%d",
+ "enough-mtbf=%d ignoring-advertised-bws=%d",
(unsigned long)stable_uptime,
(unsigned long)stable_mtbf,
- (unsigned long)fast_bandwidth,
+ (unsigned long)fast_bandwidth_kb*1000,
guard_wfu*100,
(unsigned long)guard_tk,
- (unsigned long)guard_bandwidth_including_exits,
- (unsigned long)guard_bandwidth_excluding_exits,
- enough_mtbf_info ? 1 : 0);
+ (unsigned long)guard_bandwidth_including_exits_kb*1000,
+ (unsigned long)guard_bandwidth_excluding_exits_kb*1000,
+ enough_mtbf_info ? 1 : 0,
+ enough_measured_bw ? 1 : 0);
return result;
}
@@ -2090,38 +2180,39 @@ version_from_platform(const char *platform)
return NULL;
}
-/** Helper: write the router-status information in <b>rs</b> into <b>buf</b>,
- * which has at least <b>buf_len</b> free characters. Do NUL-termination.
- * Use the same format as in network-status documents. If <b>version</b> is
- * non-NULL, add a "v" line for the platform. Return 0 on success, -1 on
- * failure.
+/** Helper: write the router-status information in <b>rs</b> into a newly
+ * allocated character buffer. Use the same format as in network-status
+ * documents. If <b>version</b> is non-NULL, add a "v" line for the platform.
+ * Return 0 on success, -1 on failure.
*
* The format argument has one of the following values:
* NS_V2 - Output an entry suitable for a V2 NS opinion document
* NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
* NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc
* consensus entry.
- * NS_V3_VOTE - Output a complete V3 NS vote
+ * NS_V3_VOTE - Output a complete V3 NS vote. If <b>vrs</b> is present,
+ * it contains additional information for the vote.
* NS_CONTROL_PORT - Output a NS document for the control port
*/
-int
-routerstatus_format_entry(char *buf, size_t buf_len,
- const routerstatus_t *rs, const char *version,
- routerstatus_format_type_t format)
+char *
+routerstatus_format_entry(const routerstatus_t *rs, const char *version,
+ routerstatus_format_type_t format,
+ const vote_routerstatus_t *vrs)
{
- int r;
- char *cp;
char *summary;
+ char *result = NULL;
char published[ISO_TIME_LEN+1];
char identity64[BASE64_DIGEST_LEN+1];
char digest64[BASE64_DIGEST_LEN+1];
+ smartlist_t *chunks = NULL;
format_iso_time(published, rs->published_on);
digest_to_base64(identity64, rs->identity_digest);
digest_to_base64(digest64, rs->descriptor_digest);
- r = tor_snprintf(buf, buf_len,
+ chunks = smartlist_new();
+ smartlist_add_asprintf(chunks,
"r %s %s %s%s%s %s %d %d\n",
rs->nickname,
identity64,
@@ -2131,11 +2222,6 @@ routerstatus_format_entry(char *buf, size_t buf_len,
fmt_addr32(rs->addr),
(int)rs->or_port,
(int)rs->dir_port);
- if (r<0) {
- log_warn(LD_BUG, "Not enough space in buffer.");
- return -1;
- }
- cp = buf + strlen(buf);
/* TODO: Maybe we want to pass in what we need to build the rest of
* this here, instead of in the caller. Then we could use the
@@ -2144,25 +2230,18 @@ routerstatus_format_entry(char *buf, size_t buf_len,
/* V3 microdesc consensuses don't have "a" lines. */
if (format == NS_V3_CONSENSUS_MICRODESC)
- return 0;
+ goto done;
/* Possible "a" line. At most one for now. */
if (!tor_addr_is_null(&rs->ipv6_addr)) {
- r = tor_snprintf(cp, buf_len - (cp-buf),
- "a %s\n",
- fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
- if (r<0) {
- log_warn(LD_BUG, "Not enough space in buffer.");
- return -1;
- }
- cp += strlen(cp);
+ smartlist_add_asprintf(chunks, "a %s\n",
+ fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
}
if (format == NS_V3_CONSENSUS)
- return 0;
+ goto done;
- /* NOTE: Whenever this list expands, be sure to increase MAX_FLAG_LINE_LEN*/
- r = tor_snprintf(cp, buf_len - (cp-buf),
+ smartlist_add_asprintf(chunks,
"s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
/* These must stay in alphabetical order. */
rs->is_authority?" Authority":"",
@@ -2176,27 +2255,18 @@ routerstatus_format_entry(char *buf, size_t buf_len,
rs->is_flagged_running?" Running":"",
rs->is_stable?" Stable":"",
rs->is_unnamed?" Unnamed":"",
- rs->is_v2_dir?" V2Dir":"",
+ (rs->dir_port!=0)?" V2Dir":"",
rs->is_valid?" Valid":"");
- if (r<0) {
- log_warn(LD_BUG, "Not enough space in buffer.");
- return -1;
- }
- cp += strlen(cp);
/* length of "opt v \n" */
#define V_LINE_OVERHEAD 7
if (version && strlen(version) < MAX_V_LINE_LEN - V_LINE_OVERHEAD) {
- if (tor_snprintf(cp, buf_len - (cp-buf), "v %s\n", version)<0) {
- log_warn(LD_BUG, "Unable to print router version.");
- return -1;
- }
- cp += strlen(cp);
+ smartlist_add_asprintf(chunks, "v %s\n", version);
}
if (format != NS_V2) {
const routerinfo_t* desc = router_get_by_id_digest(rs->identity_digest);
- uint32_t bw;
+ uint32_t bw_kb;
if (format != NS_CONTROL_PORT) {
/* Blow up more or less nicely if we didn't get anything or not the
@@ -2211,12 +2281,13 @@ routerstatus_format_entry(char *buf, size_t buf_len,
log_warn(LD_BUG, "Cannot get any descriptor for %s "
"(wanted descriptor %s).",
id, dd);
- return -1;
+ goto err;
}
- /* This assert can fire for the control port, because
+ /* This assert could fire for the control port, because
* it can request NS documents before all descriptors
- * have been fetched. */
+ * have been fetched. Therefore, we only do this test when
+ * format != NS_CONTROL_PORT. */
if (tor_memneq(desc->cache_info.signed_descriptor_digest,
rs->descriptor_digest,
DIGEST_LEN)) {
@@ -2240,44 +2311,37 @@ routerstatus_format_entry(char *buf, size_t buf_len,
}
if (format == NS_CONTROL_PORT && rs->has_bandwidth) {
- bw = rs->bandwidth;
+ bw_kb = rs->bandwidth_kb;
} else {
tor_assert(desc);
- bw = router_get_advertised_bandwidth_capped(desc) / 1000;
+ bw_kb = router_get_advertised_bandwidth_capped(desc) / 1000;
}
- r = tor_snprintf(cp, buf_len - (cp-buf),
- "w Bandwidth=%d\n", bw);
+ smartlist_add_asprintf(chunks,
+ "w Bandwidth=%d", bw_kb);
- if (r<0) {
- log_warn(LD_BUG, "Not enough space in buffer.");
- return -1;
- }
- cp += strlen(cp);
- if (format == NS_V3_VOTE && rs->has_measured_bw) {
- *--cp = '\0'; /* Kill "\n" */
- r = tor_snprintf(cp, buf_len - (cp-buf),
- " Measured=%d\n", rs->measured_bw);
- if (r<0) {
- log_warn(LD_BUG, "Not enough space in buffer for weight line.");
- return -1;
- }
- cp += strlen(cp);
+ if (format == NS_V3_VOTE && vrs && vrs->has_measured_bw) {
+ smartlist_add_asprintf(chunks,
+ " Measured=%d", vrs->measured_bw_kb);
}
+ smartlist_add(chunks, tor_strdup("\n"));
if (desc) {
summary = policy_summarize(desc->exit_policy, AF_INET);
- r = tor_snprintf(cp, buf_len - (cp-buf), "p %s\n", summary);
- if (r<0) {
- log_warn(LD_BUG, "Not enough space in buffer.");
- tor_free(summary);
- return -1;
- }
- cp += strlen(cp);
+ smartlist_add_asprintf(chunks, "p %s\n", summary);
tor_free(summary);
}
}
- return 0;
+ done:
+ result = smartlist_join_strings(chunks, "", 0, NULL);
+
+ err:
+ if (chunks) {
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
+ }
+
+ return result;
}
/** Helper for sorting: compares two routerinfos first by address, and then by
@@ -2290,7 +2354,7 @@ compare_routerinfo_by_ip_and_bw_(const void **a, const void **b)
{
routerinfo_t *first = *(routerinfo_t **)a, *second = *(routerinfo_t **)b;
int first_is_auth, second_is_auth;
- uint32_t bw_first, bw_second;
+ uint32_t bw_kb_first, bw_kb_second;
const node_t *node_first, *node_second;
int first_is_running, second_is_running;
@@ -2325,12 +2389,12 @@ compare_routerinfo_by_ip_and_bw_(const void **a, const void **b)
else if (!first_is_running && second_is_running)
return 1;
- bw_first = router_get_advertised_bandwidth(first);
- bw_second = router_get_advertised_bandwidth(second);
+ bw_kb_first = dirserv_get_bandwidth_for_router_kb(first);
+ bw_kb_second = dirserv_get_bandwidth_for_router_kb(second);
- if (bw_first > bw_second)
+ if (bw_kb_first > bw_kb_second)
return -1;
- else if (bw_first < bw_second)
+ else if (bw_kb_first < bw_kb_second)
return 1;
/* They're equal! Compare by identity digest, so there's a
@@ -2466,7 +2530,7 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
int listbaddirs, int vote_on_hsdirs)
{
const or_options_t *options = get_options();
- uint32_t routerbw = router_get_advertised_bandwidth(ri);
+ uint32_t routerbw_kb = dirserv_get_credible_bandwidth_kb(ri);
memset(rs, 0, sizeof(routerstatus_t));
@@ -2493,9 +2557,9 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
if (node->is_fast &&
((options->AuthDirGuardBWGuarantee &&
- routerbw >= options->AuthDirGuardBWGuarantee) ||
- routerbw >= MIN(guard_bandwidth_including_exits,
- guard_bandwidth_excluding_exits)) &&
+ routerbw_kb >= options->AuthDirGuardBWGuarantee/1000) ||
+ routerbw_kb >= MIN(guard_bandwidth_including_exits_kb,
+ guard_bandwidth_excluding_exits_kb)) &&
is_router_version_good_for_possible_guard(ri->platform)) {
long tk = rep_hist_get_weighted_time_known(
node->identity, now);
@@ -2505,12 +2569,16 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
} else {
rs->is_possible_guard = 0;
}
+ if (options->TestingTorNetwork &&
+ routerset_contains_routerstatus(options->TestingDirAuthVoteGuard,
+ rs, 0)) {
+ rs->is_possible_guard = 1;
+ }
rs->is_bad_directory = listbaddirs && node->is_bad_directory;
rs->is_bad_exit = listbadexits && node->is_bad_exit;
node->is_hs_dir = dirserv_thinks_router_is_hs_dir(ri, node, now);
rs->is_hs_dir = vote_on_hsdirs && node->is_hs_dir;
- rs->is_v2_dir = ri->dir_port != 0;
if (!strcasecmp(ri->nickname, UNNAMED_ROUTER_NICKNAME))
rs->is_named = rs->is_unnamed = 0;
@@ -2541,7 +2609,7 @@ static void
clear_status_flags_on_sybil(routerstatus_t *rs)
{
rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
- rs->is_flagged_running = rs->is_named = rs->is_valid = rs->is_v2_dir =
+ rs->is_flagged_running = rs->is_named = rs->is_valid =
rs->is_hs_dir = rs->is_possible_guard = rs->is_bad_exit =
rs->is_bad_directory = 0;
/* FFFF we might want some mechanism to check later on if we
@@ -2554,7 +2622,7 @@ clear_status_flags_on_sybil(routerstatus_t *rs)
* into a measured_bw_line_t output structure. Returns -1 on failure
* or 0 on success.
*/
-int
+STATIC int
measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line)
{
char *line = tor_strdup(orig_line);
@@ -2590,7 +2658,7 @@ measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line)
}
cp+=strlen("bw=");
- out->bw = tor_parse_long(cp, 0, 0, LONG_MAX, &parse_ok, &endptr);
+ out->bw_kb = tor_parse_long(cp, 0, 0, LONG_MAX, &parse_ok, &endptr);
if (!parse_ok || (*endptr && !TOR_ISSPACE(*endptr))) {
log_warn(LD_DIRSERV, "Invalid bandwidth in bandwidth file line: %s",
escaped(orig_line));
@@ -2635,20 +2703,20 @@ measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line)
* of bandwidth statuses. Returns true if a line is found,
* false otherwise.
*/
-int
+STATIC int
measured_bw_line_apply(measured_bw_line_t *parsed_line,
smartlist_t *routerstatuses)
{
- routerstatus_t *rs = NULL;
+ vote_routerstatus_t *rs = NULL;
if (!routerstatuses)
return 0;
rs = smartlist_bsearch(routerstatuses, parsed_line->node_id,
- compare_digest_to_routerstatus_entry);
+ compare_digest_to_vote_routerstatus_entry);
if (rs) {
rs->has_measured_bw = 1;
- rs->measured_bw = (uint32_t)parsed_line->bw;
+ rs->measured_bw_kb = (uint32_t)parsed_line->bw_kb;
} else {
log_info(LD_DIRSERV, "Node ID %s not found in routerstatus list",
parsed_line->node_hex);
@@ -2659,7 +2727,7 @@ measured_bw_line_apply(measured_bw_line_t *parsed_line,
/**
* Read the measured bandwidth file and apply it to the list of
- * routerstatuses. Returns -1 on error, 0 otherwise.
+ * vote_routerstatus_t. Returns -1 on error, 0 otherwise.
*/
int
dirserv_read_measured_bandwidths(const char *from_file,
@@ -2668,8 +2736,9 @@ dirserv_read_measured_bandwidths(const char *from_file,
char line[256];
FILE *fp = tor_fopen_cloexec(from_file, "r");
int applied_lines = 0;
- time_t file_time;
+ time_t file_time, now;
int ok;
+
if (fp == NULL) {
log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s",
from_file);
@@ -2693,7 +2762,8 @@ dirserv_read_measured_bandwidths(const char *from_file,
return -1;
}
- if ((time(NULL) - file_time) > MAX_MEASUREMENT_AGE) {
+ now = time(NULL);
+ if ((now - file_time) > MAX_MEASUREMENT_AGE) {
log_warn(LD_DIRSERV, "Bandwidth measurement file stale. Age: %u",
(unsigned)(time(NULL) - file_time));
fclose(fp);
@@ -2701,18 +2771,23 @@ dirserv_read_measured_bandwidths(const char *from_file,
}
if (routerstatuses)
- smartlist_sort(routerstatuses, compare_routerstatus_entries);
+ smartlist_sort(routerstatuses, compare_vote_routerstatus_entries);
while (!feof(fp)) {
measured_bw_line_t parsed_line;
if (fgets(line, sizeof(line), fp) && strlen(line)) {
if (measured_bw_line_parse(&parsed_line, line) != -1) {
+ /* Also cache the line for dirserv_get_bandwidth_for_router() */
+ dirserv_cache_measured_bw(&parsed_line, file_time);
if (measured_bw_line_apply(&parsed_line, routerstatuses) > 0)
applied_lines++;
}
}
}
+ /* Now would be a nice time to clean the cache, too */
+ dirserv_expire_measured_bw_cache(now);
+
fclose(fp);
log_info(LD_DIRSERV,
"Bandwidth measurement file successfully read. "
@@ -2750,11 +2825,11 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
tor_assert(private_key);
tor_assert(cert);
- if (resolve_my_address(LOG_WARN, options, &addr, &hostname)<0) {
+ if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) {
log_warn(LD_NET, "Couldn't resolve my hostname");
return NULL;
}
- if (!strchr(hostname, '.')) {
+ if (!hostname || !strchr(hostname, '.')) {
tor_free(hostname);
hostname = tor_dup_ip(addr);
}
@@ -2776,6 +2851,22 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
if (!contact)
contact = "(none)";
+ /*
+ * Do this so dirserv_compute_performance_thresholds() and
+ * set_routerstatus_from_routerinfo() see up-to-date bandwidth info.
+ */
+ if (options->V3BandwidthsFile) {
+ dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL);
+ } else {
+ /*
+ * No bandwidths file; clear the measured bandwidth cache in case we had
+ * one last time around.
+ */
+ if (dirserv_get_measured_bw_cache_size() > 0) {
+ dirserv_clear_measured_bw_cache();
+ }
+ }
+
/* precompute this part, since we need it to decide what "stable"
* means. */
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, {
@@ -2792,17 +2883,19 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
rep_hist_make_router_pessimal(sybil_id, now);
} DIGESTMAP_FOREACH_END;
+ /* Count how many have measured bandwidths so we know how to assign flags;
+ * this must come before dirserv_compute_performance_thresholds() */
+ dirserv_count_measured_bws(rl);
+
dirserv_compute_performance_thresholds(rl, omit_as_sybil);
routerstatuses = smartlist_new();
microdescriptors = smartlist_new();
SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
- const struct consensus_method_range_t *cmr = NULL;
if (ri->cache_info.published_on >= cutoff) {
routerstatus_t *rs;
vote_routerstatus_t *vrs;
- microdesc_t *md;
node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest);
if (!node)
continue;
@@ -2820,23 +2913,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
rs->is_flagged_running = 0;
vrs->version = version_from_platform(ri->platform);
- for (cmr = microdesc_consensus_methods;
- cmr->low != -1 && cmr->high != -1;
- cmr++) {
- md = dirvote_create_microdescriptor(ri, cmr->low);
- if (md) {
- char buf[128];
- vote_microdesc_hash_t *h;
- dirvote_format_microdesc_vote_line(buf, sizeof(buf), md,
- cmr->low, cmr->high);
- h = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
- h->microdesc_hash_line = tor_strdup(buf);
- h->next = vrs->microdesc;
- vrs->microdesc = h;
- md->last_listed = now;
- smartlist_add(microdescriptors, md);
- }
- }
+ vrs->microdesc = dirvote_format_all_microdesc_vote_lines(ri, now,
+ microdescriptors);
smartlist_add(routerstatuses, vrs);
}
@@ -2853,9 +2931,18 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
smartlist_free(routers);
digestmap_free(omit_as_sybil, NULL);
+ /* This pass through applies the measured bw lines to the routerstatuses */
if (options->V3BandwidthsFile) {
dirserv_read_measured_bandwidths(options->V3BandwidthsFile,
routerstatuses);
+ } else {
+ /*
+ * No bandwidths file; clear the measured bandwidth cache in case we had
+ * one last time around.
+ */
+ if (dirserv_get_measured_bw_cache_size() > 0) {
+ dirserv_clear_measured_bw_cache();
+ }
}
v3_out = tor_malloc_zero(sizeof(networkstatus_t));
@@ -2874,7 +2961,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
else
last_consensus_interval = options->TestingV3AuthInitialVotingInterval;
v3_out->valid_after =
- dirvote_get_start_of_next_interval(now, (int)last_consensus_interval);
+ dirvote_get_start_of_next_interval(now, (int)last_consensus_interval,
+ options->TestingV3AuthVotingStartOffset);
format_iso_time(tbuf, v3_out->valid_after);
log_notice(LD_DIR,"Choosing valid-after time in vote as %s: "
"consensus_set=%d, last_interval=%d",
@@ -2945,271 +3033,6 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
return v3_out;
}
-/** For v2 authoritative directories only: Replace the contents of
- * <b>the_v2_networkstatus</b> with a newly generated network status
- * object. */
-static cached_dir_t *
-generate_v2_networkstatus_opinion(void)
-{
- cached_dir_t *r = NULL;
- size_t len, identity_pkey_len;
- char *status = NULL, *client_versions = NULL, *server_versions = NULL,
- *identity_pkey = NULL, *hostname = NULL;
- char *outp, *endp;
- const or_options_t *options = get_options();
- char fingerprint[FINGERPRINT_LEN+1];
- char published[ISO_TIME_LEN+1];
- char digest[DIGEST_LEN];
- uint32_t addr;
- crypto_pk_t *private_key;
- routerlist_t *rl = router_get_routerlist();
- time_t now = time(NULL);
- time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
- int naming = options->NamingAuthoritativeDir;
- int versioning = options->VersioningAuthoritativeDir;
- int listbaddirs = options->AuthDirListBadDirs;
- int listbadexits = options->AuthDirListBadExits;
- int vote_on_hsdirs = options->VoteOnHidServDirectoriesV2;
- const char *contact;
- char *version_lines = NULL;
- smartlist_t *routers = NULL;
- digestmap_t *omit_as_sybil = NULL;
-
- private_key = get_server_identity_key();
-
- if (resolve_my_address(LOG_WARN, options, &addr, &hostname)<0) {
- log_warn(LD_NET, "Couldn't resolve my hostname");
- goto done;
- }
-
- format_iso_time(published, now);
-
- client_versions = format_versions_list(options->RecommendedClientVersions);
- server_versions = format_versions_list(options->RecommendedServerVersions);
-
- if (crypto_pk_write_public_key_to_string(private_key, &identity_pkey,
- &identity_pkey_len)<0) {
- log_warn(LD_BUG,"Writing public key to string failed.");
- goto done;
- }
-
- if (crypto_pk_get_fingerprint(private_key, fingerprint, 0)<0) {
- log_err(LD_BUG, "Error computing fingerprint");
- goto done;
- }
-
- contact = options->ContactInfo;
- if (!contact)
- contact = "(none)";
-
- if (versioning) {
- tor_asprintf(&version_lines,
- "client-versions %s\nserver-versions %s\n",
- client_versions, server_versions);
- } else {
- version_lines = tor_strdup("");
- }
-
- len = 4096+strlen(client_versions)+strlen(server_versions);
- len += identity_pkey_len*2;
- len += (RS_ENTRY_LEN)*smartlist_len(rl->routers);
-
- status = tor_malloc(len);
- tor_snprintf(status, len,
- "network-status-version 2\n"
- "dir-source %s %s %d\n"
- "fingerprint %s\n"
- "contact %s\n"
- "published %s\n"
- "dir-options%s%s%s%s\n"
- "%s" /* client version line, server version line. */
- "dir-signing-key\n%s",
- hostname, fmt_addr32(addr),
- (int)router_get_advertised_dir_port(options, 0),
- fingerprint,
- contact,
- published,
- naming ? " Names" : "",
- listbaddirs ? " BadDirectories" : "",
- listbadexits ? " BadExits" : "",
- versioning ? " Versions" : "",
- version_lines,
- identity_pkey);
- outp = status + strlen(status);
- endp = status + len;
-
- /* precompute this part, since we need it to decide what "stable"
- * means. */
- SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, {
- dirserv_set_router_is_running(ri, now);
- });
-
- routers = smartlist_new();
- smartlist_add_all(routers, rl->routers);
- routers_sort_by_identity(routers);
- omit_as_sybil = get_possible_sybil_list(routers);
-
- dirserv_compute_performance_thresholds(rl, omit_as_sybil);
-
- SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
- if (ri->cache_info.published_on >= cutoff) {
- routerstatus_t rs;
- char *version = version_from_platform(ri->platform);
- node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest);
- if (!node) {
- tor_free(version);
- continue;
- }
- set_routerstatus_from_routerinfo(&rs, node, ri, now,
- naming, listbadexits, listbaddirs,
- vote_on_hsdirs);
-
- if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
- clear_status_flags_on_sybil(&rs);
-
- if (routerstatus_format_entry(outp, endp-outp, &rs, version, NS_V2)) {
- log_warn(LD_BUG, "Unable to print router status.");
- tor_free(version);
- goto done;
- }
- tor_free(version);
- outp += strlen(outp);
- }
- } SMARTLIST_FOREACH_END(ri);
-
- if (tor_snprintf(outp, endp-outp, "directory-signature %s\n",
- options->Nickname)<0) {
- log_warn(LD_BUG, "Unable to write signature line.");
- goto done;
- }
- if (router_get_networkstatus_v2_hash(status, digest)<0) {
- log_warn(LD_BUG, "Unable to hash network status");
- goto done;
- }
- outp += strlen(outp);
-
- note_crypto_pk_op(SIGN_DIR);
- if (router_append_dirobj_signature(outp,endp-outp,digest,DIGEST_LEN,
- private_key)<0) {
- log_warn(LD_BUG, "Unable to sign router status.");
- goto done;
- }
-
- {
- networkstatus_v2_t *ns;
- if (!(ns = networkstatus_v2_parse_from_string(status))) {
- log_err(LD_BUG,"Generated a networkstatus we couldn't parse.");
- goto done;
- }
- networkstatus_v2_free(ns);
- }
-
- {
- cached_dir_t **ns_ptr = &the_v2_networkstatus;
- if (*ns_ptr)
- cached_dir_decref(*ns_ptr);
- *ns_ptr = new_cached_dir(status, now);
- status = NULL; /* So it doesn't get double-freed. */
- the_v2_networkstatus_is_dirty = 0;
- router_set_networkstatus_v2((*ns_ptr)->dir, now, NS_GENERATED, NULL);
- r = *ns_ptr;
- }
-
- done:
- tor_free(client_versions);
- tor_free(server_versions);
- tor_free(version_lines);
- tor_free(status);
- tor_free(hostname);
- tor_free(identity_pkey);
- smartlist_free(routers);
- digestmap_free(omit_as_sybil, NULL);
- return r;
-}
-
-/** Given the portion of a networkstatus request URL after "tor/status/" in
- * <b>key</b>, append to <b>result</b> the digests of the identity keys of the
- * networkstatus objects that the client has requested. */
-void
-dirserv_get_networkstatus_v2_fingerprints(smartlist_t *result,
- const char *key)
-{
- tor_assert(result);
-
- if (!cached_v2_networkstatus)
- cached_v2_networkstatus = digestmap_new();
-
- if (should_generate_v2_networkstatus())
- generate_v2_networkstatus_opinion();
-
- if (!strcmp(key,"authority")) {
- if (authdir_mode_v2(get_options())) {
- const routerinfo_t *me = router_get_my_routerinfo();
- if (me)
- smartlist_add(result,
- tor_memdup(me->cache_info.identity_digest, DIGEST_LEN));
- }
- } else if (!strcmp(key, "all")) {
- if (digestmap_size(cached_v2_networkstatus)) {
- digestmap_iter_t *iter;
- iter = digestmap_iter_init(cached_v2_networkstatus);
- while (!digestmap_iter_done(iter)) {
- const char *ident;
- void *val;
- digestmap_iter_get(iter, &ident, &val);
- smartlist_add(result, tor_memdup(ident, DIGEST_LEN));
- iter = digestmap_iter_next(cached_v2_networkstatus, iter);
- }
- } else {
- SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
- dir_server_t *, ds,
- if (ds->type & V2_DIRINFO)
- smartlist_add(result, tor_memdup(ds->digest, DIGEST_LEN)));
- }
- smartlist_sort_digests(result);
- if (smartlist_len(result) == 0)
- log_info(LD_DIRSERV,
- "Client requested 'all' network status objects; we have none.");
- } else if (!strcmpstart(key, "fp/")) {
- dir_split_resource_into_fingerprints(key+3, result, NULL,
- DSR_HEX|DSR_SORT_UNIQ);
- }
-}
-
-/** Look for a network status object as specified by <b>key</b>, which should
- * be either "authority" (to find a network status generated by us), a hex
- * identity digest (to find a network status generated by given directory), or
- * "all" (to return all the v2 network status objects we have).
- */
-void
-dirserv_get_networkstatus_v2(smartlist_t *result,
- const char *key)
-{
- cached_dir_t *cached;
- smartlist_t *fingerprints = smartlist_new();
- tor_assert(result);
-
- if (!cached_v2_networkstatus)
- cached_v2_networkstatus = digestmap_new();
-
- dirserv_get_networkstatus_v2_fingerprints(fingerprints, key);
- SMARTLIST_FOREACH_BEGIN(fingerprints, const char *, fp) {
- if (router_digest_is_me(fp) && should_generate_v2_networkstatus())
- generate_v2_networkstatus_opinion();
- cached = digestmap_get(cached_v2_networkstatus, fp);
- if (cached) {
- smartlist_add(result, cached);
- } else {
- char hexbuf[HEX_DIGEST_LEN+1];
- base16_encode(hexbuf, sizeof(hexbuf), fp, DIGEST_LEN);
- log_info(LD_DIRSERV, "Don't know about any network status with "
- "fingerprint '%s'", hexbuf);
- }
- } SMARTLIST_FOREACH_END(fp);
- SMARTLIST_FOREACH(fingerprints, char *, cp, tor_free(cp));
- smartlist_free(fingerprints);
-}
-
/** As dirserv_get_routerdescs(), but instead of getting signed_descriptor_t
* pointers, adds copies of digests to fps_out, and doesn't use the
* /tor/server/ prefix. For a /d/ request, adds descriptor digests; for other
@@ -3509,15 +3332,12 @@ static cached_dir_t *
lookup_cached_dir_by_fp(const char *fp)
{
cached_dir_t *d = NULL;
- if (tor_digest_is_zero(fp) && cached_consensuses)
+ if (tor_digest_is_zero(fp) && cached_consensuses) {
d = strmap_get(cached_consensuses, "ns");
- else if (memchr(fp, '\0', DIGEST_LEN) && cached_consensuses &&
+ } else if (memchr(fp, '\0', DIGEST_LEN) && cached_consensuses &&
(d = strmap_get(cached_consensuses, fp))) {
/* this here interface is a nasty hack XXXX024 */;
- } else if (router_digest_is_me(fp) && the_v2_networkstatus)
- d = the_v2_networkstatus;
- else if (cached_v2_networkstatus)
- d = digestmap_get(cached_v2_networkstatus, fp);
+ }
return d;
}
@@ -3763,7 +3583,7 @@ connection_dirserv_add_microdescs_to_outbuf(dir_connection_t *conn)
char *fp256 = smartlist_pop_last(conn->fingerprint_stack);
microdesc_t *md = microdesc_cache_lookup_by_digest256(cache, fp256);
tor_free(fp256);
- if (!md)
+ if (!md || !md->body)
continue;
if (conn->zlib_state) {
/* XXXX024 This 'last' business should actually happen on the last
@@ -3912,13 +3732,12 @@ dirserv_free_all(void)
cached_dir_decref(the_directory);
clear_cached_dir(&the_runningrouters);
- cached_dir_decref(the_v2_networkstatus);
cached_dir_decref(cached_directory);
clear_cached_dir(&cached_runningrouters);
- digestmap_free(cached_v2_networkstatus, free_cached_dir_);
- cached_v2_networkstatus = NULL;
strmap_free(cached_consensuses, free_cached_dir_);
cached_consensuses = NULL;
+
+ dirserv_clear_measured_bw_cache();
}