dirvote: Move the vote creation code into dirvote.c
This code is only for dirauth so this commit moves it into the module in dirvote.c. No code behavior change. Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
parent
0f3b765b3c
commit
a2ff4975f3
|
@ -13,6 +13,7 @@
|
|||
#include "dirvote_common.h"
|
||||
#include "microdesc.h"
|
||||
#include "networkstatus.h"
|
||||
#include "nodelist.h"
|
||||
#include "parsecommon.h"
|
||||
#include "policies.h"
|
||||
#include "protover.h"
|
||||
|
@ -3966,3 +3967,516 @@ dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items,
|
|||
smartlist_free(fps);
|
||||
}
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
/** Helper for sorting: compares two routerinfos first by address, and then by
|
||||
* descending order of "usefulness". (An authority is more useful than a
|
||||
* non-authority; a running router is more useful than a non-running router;
|
||||
* and a router with more bandwidth is more useful than one with less.)
|
||||
**/
|
||||
static int
|
||||
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_kb_first, bw_kb_second;
|
||||
const node_t *node_first, *node_second;
|
||||
int first_is_running, second_is_running;
|
||||
|
||||
/* we return -1 if first should appear before second... that is,
|
||||
* if first is a better router. */
|
||||
if (first->addr < second->addr)
|
||||
return -1;
|
||||
else if (first->addr > second->addr)
|
||||
return 1;
|
||||
|
||||
/* Potentially, this next bit could cause k n lg n memeq calls. But in
|
||||
* reality, we will almost never get here, since addresses will usually be
|
||||
* different. */
|
||||
|
||||
first_is_auth =
|
||||
router_digest_is_trusted_dir(first->cache_info.identity_digest);
|
||||
second_is_auth =
|
||||
router_digest_is_trusted_dir(second->cache_info.identity_digest);
|
||||
|
||||
if (first_is_auth && !second_is_auth)
|
||||
return -1;
|
||||
else if (!first_is_auth && second_is_auth)
|
||||
return 1;
|
||||
|
||||
node_first = node_get_by_id(first->cache_info.identity_digest);
|
||||
node_second = node_get_by_id(second->cache_info.identity_digest);
|
||||
first_is_running = node_first && node_first->is_running;
|
||||
second_is_running = node_second && node_second->is_running;
|
||||
|
||||
if (first_is_running && !second_is_running)
|
||||
return -1;
|
||||
else if (!first_is_running && second_is_running)
|
||||
return 1;
|
||||
|
||||
bw_kb_first = dirserv_get_bandwidth_for_router_kb(first);
|
||||
bw_kb_second = dirserv_get_bandwidth_for_router_kb(second);
|
||||
|
||||
if (bw_kb_first > bw_kb_second)
|
||||
return -1;
|
||||
else if (bw_kb_first < bw_kb_second)
|
||||
return 1;
|
||||
|
||||
/* They're equal! Compare by identity digest, so there's a
|
||||
* deterministic order and we avoid flapping. */
|
||||
return fast_memcmp(first->cache_info.identity_digest,
|
||||
second->cache_info.identity_digest,
|
||||
DIGEST_LEN);
|
||||
}
|
||||
|
||||
/** Given a list of routerinfo_t in <b>routers</b>, return a new digestmap_t
|
||||
* whose keys are the identity digests of those routers that we're going to
|
||||
* exclude for Sybil-like appearance. */
|
||||
static digestmap_t *
|
||||
get_possible_sybil_list(const smartlist_t *routers)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
digestmap_t *omit_as_sybil;
|
||||
smartlist_t *routers_by_ip = smartlist_new();
|
||||
uint32_t last_addr;
|
||||
int addr_count;
|
||||
/* Allow at most this number of Tor servers on a single IP address, ... */
|
||||
int max_with_same_addr = options->AuthDirMaxServersPerAddr;
|
||||
if (max_with_same_addr <= 0)
|
||||
max_with_same_addr = INT_MAX;
|
||||
|
||||
smartlist_add_all(routers_by_ip, routers);
|
||||
smartlist_sort(routers_by_ip, compare_routerinfo_by_ip_and_bw_);
|
||||
omit_as_sybil = digestmap_new();
|
||||
|
||||
last_addr = 0;
|
||||
addr_count = 0;
|
||||
SMARTLIST_FOREACH_BEGIN(routers_by_ip, routerinfo_t *, ri) {
|
||||
if (last_addr != ri->addr) {
|
||||
last_addr = ri->addr;
|
||||
addr_count = 1;
|
||||
} else if (++addr_count > max_with_same_addr) {
|
||||
digestmap_set(omit_as_sybil, ri->cache_info.identity_digest, ri);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ri);
|
||||
|
||||
smartlist_free(routers_by_ip);
|
||||
return omit_as_sybil;
|
||||
}
|
||||
|
||||
/** Given a platform string as in a routerinfo_t (possibly null), return a
|
||||
* newly allocated version string for a networkstatus document, or NULL if the
|
||||
* platform doesn't give a Tor version. */
|
||||
static char *
|
||||
version_from_platform(const char *platform)
|
||||
{
|
||||
if (platform && !strcmpstart(platform, "Tor ")) {
|
||||
const char *eos = find_whitespace(platform+4);
|
||||
if (eos && !strcmpstart(eos, " (r")) {
|
||||
/* XXXX Unify this logic with the other version extraction
|
||||
* logic in routerparse.c. */
|
||||
eos = find_whitespace(eos+1);
|
||||
}
|
||||
if (eos) {
|
||||
return tor_strndup(platform, eos-platform);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Given a (possibly empty) list of config_line_t, each line of which contains
|
||||
* a list of comma-separated version numbers surrounded by optional space,
|
||||
* allocate and return a new string containing the version numbers, in order,
|
||||
* separated by commas. Used to generate Recommended(Client|Server)?Versions
|
||||
*/
|
||||
static char *
|
||||
format_versions_list(config_line_t *ln)
|
||||
{
|
||||
smartlist_t *versions;
|
||||
char *result;
|
||||
versions = smartlist_new();
|
||||
for ( ; ln; ln = ln->next) {
|
||||
smartlist_split_string(versions, ln->value, ",",
|
||||
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
||||
}
|
||||
sort_version_list(versions, 1);
|
||||
result = smartlist_join_strings(versions,",",0,NULL);
|
||||
SMARTLIST_FOREACH(versions,char *,s,tor_free(s));
|
||||
smartlist_free(versions);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** If there are entries in <b>routers</b> with exactly the same ed25519 keys,
|
||||
* remove the older one. If they are exactly the same age, remove the one
|
||||
* with the greater descriptor digest. May alter the order of the list. */
|
||||
static void
|
||||
routers_make_ed_keys_unique(smartlist_t *routers)
|
||||
{
|
||||
routerinfo_t *ri2;
|
||||
digest256map_t *by_ed_key = digest256map_new();
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
|
||||
ri->omit_from_vote = 0;
|
||||
if (ri->cache_info.signing_key_cert == NULL)
|
||||
continue; /* No ed key */
|
||||
const uint8_t *pk = ri->cache_info.signing_key_cert->signing_key.pubkey;
|
||||
if ((ri2 = digest256map_get(by_ed_key, pk))) {
|
||||
/* Duplicate; must omit one. Set the omit_from_vote flag in whichever
|
||||
* one has the earlier published_on. */
|
||||
const time_t ri_pub = ri->cache_info.published_on;
|
||||
const time_t ri2_pub = ri2->cache_info.published_on;
|
||||
if (ri2_pub < ri_pub ||
|
||||
(ri2_pub == ri_pub &&
|
||||
fast_memcmp(ri->cache_info.signed_descriptor_digest,
|
||||
ri2->cache_info.signed_descriptor_digest,DIGEST_LEN)<0)) {
|
||||
digest256map_set(by_ed_key, pk, ri);
|
||||
ri2->omit_from_vote = 1;
|
||||
} else {
|
||||
ri->omit_from_vote = 1;
|
||||
}
|
||||
} else {
|
||||
/* Add to map */
|
||||
digest256map_set(by_ed_key, pk, ri);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ri);
|
||||
|
||||
digest256map_free(by_ed_key, NULL);
|
||||
|
||||
/* Now remove every router where the omit_from_vote flag got set. */
|
||||
SMARTLIST_FOREACH_BEGIN(routers, const routerinfo_t *, ri) {
|
||||
if (ri->omit_from_vote) {
|
||||
SMARTLIST_DEL_CURRENT(routers, ri);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ri);
|
||||
}
|
||||
|
||||
/** Routerstatus <b>rs</b> is part of a group of routers that are on
|
||||
* too narrow an IP-space. Clear out its flags since we don't want it be used
|
||||
* because of its Sybil-like appearance.
|
||||
*
|
||||
* Leave its BadExit flag alone though, since if we think it's a bad exit,
|
||||
* we want to vote that way in case all the other authorities are voting
|
||||
* Running and Exit.
|
||||
*/
|
||||
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_hs_dir = rs->is_v2_dir = rs->is_possible_guard = 0;
|
||||
/* FFFF we might want some mechanism to check later on if we
|
||||
* missed zeroing any flags: it's easy to add a new flag but
|
||||
* forget to add it to this clause. */
|
||||
}
|
||||
|
||||
/** Return a new networkstatus_t* containing our current opinion. (For v3
|
||||
* authorities) */
|
||||
networkstatus_t *
|
||||
dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
|
||||
authority_cert_t *cert)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
networkstatus_t *v3_out = NULL;
|
||||
uint32_t addr;
|
||||
char *hostname = NULL, *client_versions = NULL, *server_versions = NULL;
|
||||
const char *contact;
|
||||
smartlist_t *routers, *routerstatuses;
|
||||
char identity_digest[DIGEST_LEN];
|
||||
char signing_key_digest[DIGEST_LEN];
|
||||
int listbadexits = options->AuthDirListBadExits;
|
||||
routerlist_t *rl = router_get_routerlist();
|
||||
time_t now = time(NULL);
|
||||
time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
|
||||
networkstatus_voter_info_t *voter = NULL;
|
||||
vote_timing_t timing;
|
||||
digestmap_t *omit_as_sybil = NULL;
|
||||
const int vote_on_reachability = running_long_enough_to_decide_unreachable();
|
||||
smartlist_t *microdescriptors = NULL;
|
||||
|
||||
tor_assert(private_key);
|
||||
tor_assert(cert);
|
||||
|
||||
if (crypto_pk_get_digest(private_key, signing_key_digest)<0) {
|
||||
log_err(LD_BUG, "Error computing signing key digest");
|
||||
return NULL;
|
||||
}
|
||||
if (crypto_pk_get_digest(cert->identity_key, identity_digest)<0) {
|
||||
log_err(LD_BUG, "Error computing identity key digest");
|
||||
return NULL;
|
||||
}
|
||||
if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) {
|
||||
log_warn(LD_NET, "Couldn't resolve my hostname");
|
||||
return NULL;
|
||||
}
|
||||
if (!hostname || !strchr(hostname, '.')) {
|
||||
tor_free(hostname);
|
||||
hostname = tor_dup_ip(addr);
|
||||
}
|
||||
|
||||
if (options->VersioningAuthoritativeDir) {
|
||||
client_versions = format_versions_list(options->RecommendedClientVersions);
|
||||
server_versions = format_versions_list(options->RecommendedServerVersions);
|
||||
}
|
||||
|
||||
contact = get_options()->ContactInfo;
|
||||
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, {
|
||||
dirserv_set_router_is_running(ri, now);
|
||||
});
|
||||
|
||||
routers = smartlist_new();
|
||||
smartlist_add_all(routers, rl->routers);
|
||||
routers_make_ed_keys_unique(routers);
|
||||
/* After this point, don't use rl->routers; use 'routers' instead. */
|
||||
routers_sort_by_identity(routers);
|
||||
omit_as_sybil = get_possible_sybil_list(routers);
|
||||
|
||||
DIGESTMAP_FOREACH(omit_as_sybil, sybil_id, void *, ignore) {
|
||||
(void) ignore;
|
||||
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(routers);
|
||||
|
||||
dirserv_compute_performance_thresholds(omit_as_sybil);
|
||||
|
||||
routerstatuses = smartlist_new();
|
||||
microdescriptors = smartlist_new();
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
|
||||
if (ri->cache_info.published_on >= cutoff) {
|
||||
routerstatus_t *rs;
|
||||
vote_routerstatus_t *vrs;
|
||||
node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest);
|
||||
if (!node)
|
||||
continue;
|
||||
|
||||
vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
|
||||
rs = &vrs->status;
|
||||
set_routerstatus_from_routerinfo(rs, node, ri, now,
|
||||
listbadexits);
|
||||
|
||||
if (ri->cache_info.signing_key_cert) {
|
||||
memcpy(vrs->ed25519_id,
|
||||
ri->cache_info.signing_key_cert->signing_key.pubkey,
|
||||
ED25519_PUBKEY_LEN);
|
||||
}
|
||||
|
||||
if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
|
||||
clear_status_flags_on_sybil(rs);
|
||||
|
||||
if (!vote_on_reachability)
|
||||
rs->is_flagged_running = 0;
|
||||
|
||||
vrs->version = version_from_platform(ri->platform);
|
||||
if (ri->protocol_list) {
|
||||
vrs->protocols = tor_strdup(ri->protocol_list);
|
||||
} else {
|
||||
vrs->protocols = tor_strdup(
|
||||
protover_compute_for_old_tor(vrs->version));
|
||||
}
|
||||
vrs->microdesc = dirvote_format_all_microdesc_vote_lines(ri, now,
|
||||
microdescriptors);
|
||||
|
||||
smartlist_add(routerstatuses, vrs);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ri);
|
||||
|
||||
{
|
||||
smartlist_t *added =
|
||||
microdescs_add_list_to_cache(get_microdesc_cache(),
|
||||
microdescriptors, SAVED_NOWHERE, 0);
|
||||
smartlist_free(added);
|
||||
smartlist_free(microdescriptors);
|
||||
}
|
||||
|
||||
smartlist_free(routers);
|
||||
digestmap_free(omit_as_sybil, NULL);
|
||||
|
||||
/* Apply guardfraction information to routerstatuses. */
|
||||
if (options->GuardfractionFile) {
|
||||
dirserv_read_guardfraction_file(options->GuardfractionFile,
|
||||
routerstatuses);
|
||||
}
|
||||
|
||||
/* 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));
|
||||
|
||||
v3_out->type = NS_TYPE_VOTE;
|
||||
dirvote_get_preferred_voting_intervals(&timing);
|
||||
v3_out->published = now;
|
||||
{
|
||||
char tbuf[ISO_TIME_LEN+1];
|
||||
networkstatus_t *current_consensus =
|
||||
networkstatus_get_live_consensus(now);
|
||||
long last_consensus_interval; /* only used to pick a valid_after */
|
||||
if (current_consensus)
|
||||
last_consensus_interval = current_consensus->fresh_until -
|
||||
current_consensus->valid_after;
|
||||
else
|
||||
last_consensus_interval = options->TestingV3AuthInitialVotingInterval;
|
||||
v3_out->valid_after =
|
||||
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",
|
||||
tbuf, current_consensus?1:0, (int)last_consensus_interval);
|
||||
}
|
||||
v3_out->fresh_until = v3_out->valid_after + timing.vote_interval;
|
||||
v3_out->valid_until = v3_out->valid_after +
|
||||
(timing.vote_interval * timing.n_intervals_valid);
|
||||
v3_out->vote_seconds = timing.vote_delay;
|
||||
v3_out->dist_seconds = timing.dist_delay;
|
||||
tor_assert(v3_out->vote_seconds > 0);
|
||||
tor_assert(v3_out->dist_seconds > 0);
|
||||
tor_assert(timing.n_intervals_valid > 0);
|
||||
|
||||
v3_out->client_versions = client_versions;
|
||||
v3_out->server_versions = server_versions;
|
||||
|
||||
/* These are hardwired, to avoid disaster. */
|
||||
v3_out->recommended_relay_protocols =
|
||||
tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
|
||||
"Link=4 LinkAuth=1 Microdesc=1-2 Relay=2");
|
||||
v3_out->recommended_client_protocols =
|
||||
tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
|
||||
"Link=4 LinkAuth=1 Microdesc=1-2 Relay=2");
|
||||
v3_out->required_client_protocols =
|
||||
tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
|
||||
"Link=4 LinkAuth=1 Microdesc=1-2 Relay=2");
|
||||
v3_out->required_relay_protocols =
|
||||
tor_strdup("Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
|
||||
"Link=3-4 LinkAuth=1 Microdesc=1 Relay=1-2");
|
||||
|
||||
/* We are not allowed to vote to require anything we don't have. */
|
||||
tor_assert(protover_all_supported(v3_out->required_relay_protocols, NULL));
|
||||
tor_assert(protover_all_supported(v3_out->required_client_protocols, NULL));
|
||||
|
||||
/* We should not recommend anything we don't have. */
|
||||
tor_assert_nonfatal(protover_all_supported(
|
||||
v3_out->recommended_relay_protocols, NULL));
|
||||
tor_assert_nonfatal(protover_all_supported(
|
||||
v3_out->recommended_client_protocols, NULL));
|
||||
|
||||
v3_out->package_lines = smartlist_new();
|
||||
{
|
||||
config_line_t *cl;
|
||||
for (cl = get_options()->RecommendedPackages; cl; cl = cl->next) {
|
||||
if (validate_recommended_package_line(cl->value))
|
||||
smartlist_add_strdup(v3_out->package_lines, cl->value);
|
||||
}
|
||||
}
|
||||
|
||||
v3_out->known_flags = smartlist_new();
|
||||
smartlist_split_string(v3_out->known_flags,
|
||||
"Authority Exit Fast Guard Stable V2Dir Valid HSDir",
|
||||
0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
||||
if (vote_on_reachability)
|
||||
smartlist_add_strdup(v3_out->known_flags, "Running");
|
||||
if (listbadexits)
|
||||
smartlist_add_strdup(v3_out->known_flags, "BadExit");
|
||||
smartlist_sort_strings(v3_out->known_flags);
|
||||
|
||||
if (options->ConsensusParams) {
|
||||
v3_out->net_params = smartlist_new();
|
||||
smartlist_split_string(v3_out->net_params,
|
||||
options->ConsensusParams, NULL, 0, 0);
|
||||
smartlist_sort_strings(v3_out->net_params);
|
||||
}
|
||||
|
||||
voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
|
||||
voter->nickname = tor_strdup(options->Nickname);
|
||||
memcpy(voter->identity_digest, identity_digest, DIGEST_LEN);
|
||||
voter->sigs = smartlist_new();
|
||||
voter->address = hostname;
|
||||
voter->addr = addr;
|
||||
voter->dir_port = router_get_advertised_dir_port(options, 0);
|
||||
voter->or_port = router_get_advertised_or_port(options);
|
||||
voter->contact = tor_strdup(contact);
|
||||
if (options->V3AuthUseLegacyKey) {
|
||||
authority_cert_t *c = get_my_v3_legacy_cert();
|
||||
if (c) {
|
||||
if (crypto_pk_get_digest(c->identity_key, voter->legacy_id_digest)) {
|
||||
log_warn(LD_BUG, "Unable to compute digest of legacy v3 identity key");
|
||||
memset(voter->legacy_id_digest, 0, DIGEST_LEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v3_out->voters = smartlist_new();
|
||||
smartlist_add(v3_out->voters, voter);
|
||||
v3_out->cert = dirvote_authority_cert_dup(cert);
|
||||
v3_out->routerstatus_list = routerstatuses;
|
||||
/* Note: networkstatus_digest is unset; it won't get set until we actually
|
||||
* format the vote. */
|
||||
|
||||
return v3_out;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
#include "shared_random.h"
|
||||
#include "config.h"
|
||||
#include "confparse.h"
|
||||
#include "dirvote_common.h"
|
||||
#include "networkstatus.h"
|
||||
#include "routerkeys.h"
|
||||
#include "router.h"
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "shared_random.h"
|
||||
#include "config.h"
|
||||
#include "confparse.h"
|
||||
#include "dirvote_common.h"
|
||||
#include "networkstatus.h"
|
||||
#include "router.h"
|
||||
#include "shared_random_state.h"
|
||||
|
|
571
src/or/dirserv.c
571
src/or/dirserv.c
|
@ -76,7 +76,6 @@
|
|||
static int routers_with_measured_bw = 0;
|
||||
|
||||
static void directory_remove_invalid(void);
|
||||
static char *format_versions_list(config_line_t *ln);
|
||||
struct authdir_config_t;
|
||||
static uint32_t
|
||||
dirserv_get_status_impl(const char *fp, const char *nickname,
|
||||
|
@ -89,7 +88,6 @@ static const signed_descriptor_t *get_signed_descriptor_by_fp(
|
|||
int extrainfo);
|
||||
static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei,
|
||||
const char **msg);
|
||||
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);
|
||||
|
||||
static int spooled_resource_lookup_body(const spooled_resource_t *spooled,
|
||||
|
@ -923,7 +921,7 @@ list_single_server_status(const routerinfo_t *desc, int is_live)
|
|||
}
|
||||
|
||||
/* DOCDOC running_long_enough_to_decide_unreachable */
|
||||
static inline int
|
||||
int
|
||||
running_long_enough_to_decide_unreachable(void)
|
||||
{
|
||||
return time_of_process_start
|
||||
|
@ -1058,28 +1056,6 @@ list_server_status_v1(smartlist_t *routers, char **router_status_out,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** Given a (possibly empty) list of config_line_t, each line of which contains
|
||||
* a list of comma-separated version numbers surrounded by optional space,
|
||||
* allocate and return a new string containing the version numbers, in order,
|
||||
* separated by commas. Used to generate Recommended(Client|Server)?Versions
|
||||
*/
|
||||
static char *
|
||||
format_versions_list(config_line_t *ln)
|
||||
{
|
||||
smartlist_t *versions;
|
||||
char *result;
|
||||
versions = smartlist_new();
|
||||
for ( ; ln; ln = ln->next) {
|
||||
smartlist_split_string(versions, ln->value, ",",
|
||||
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
||||
}
|
||||
sort_version_list(versions, 1);
|
||||
result = smartlist_join_strings(versions,",",0,NULL);
|
||||
SMARTLIST_FOREACH(versions,char *,s,tor_free(s));
|
||||
smartlist_free(versions);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Return 1 if <b>ri</b>'s descriptor is "active" -- running, valid,
|
||||
* not hibernating, having observed bw greater 0, and not too old. Else
|
||||
* return 0.
|
||||
|
@ -1469,6 +1445,24 @@ router_counts_toward_thresholds(const node_t *node, time_t now,
|
|||
(have_mbw || !require_mbw);
|
||||
}
|
||||
|
||||
/** 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. */
|
||||
void
|
||||
dirserv_count_measured_bws(const smartlist_t *routers)
|
||||
{
|
||||
/* Initialize this first */
|
||||
routers_with_measured_bw = 0;
|
||||
|
||||
/* Iterate over the routerlist and count measured bandwidths */
|
||||
SMARTLIST_FOREACH_BEGIN(routers, const 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);
|
||||
}
|
||||
|
||||
/** 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,
|
||||
|
@ -1476,7 +1470,7 @@ router_counts_toward_thresholds(const node_t *node, time_t now,
|
|||
* guard_bandwidth_including_exits, and guard_bandwidth_excluding_exits.
|
||||
*
|
||||
* Also, set the is_exit flag of each router appropriately. */
|
||||
static void
|
||||
void
|
||||
dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil)
|
||||
{
|
||||
int n_active, n_active_nonexit, n_familiar;
|
||||
|
@ -1707,7 +1701,7 @@ dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
|
|||
}
|
||||
|
||||
/** Clear and free the measured bandwidth cache */
|
||||
STATIC void
|
||||
void
|
||||
dirserv_clear_measured_bw_cache(void)
|
||||
{
|
||||
if (mbw_cache) {
|
||||
|
@ -1739,18 +1733,10 @@ dirserv_expire_measured_bw_cache(time_t now)
|
|||
}
|
||||
}
|
||||
|
||||
/** 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
|
||||
int
|
||||
dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out,
|
||||
time_t *as_of_out)
|
||||
{
|
||||
|
@ -1771,61 +1757,18 @@ dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out,
|
|||
}
|
||||
|
||||
/** Predicate wrapper for dirserv_query_measured_bw_cache() */
|
||||
STATIC int
|
||||
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)
|
||||
/** Get the current size of the measured bandwidth cache */
|
||||
int
|
||||
dirserv_get_measured_bw_cache_size(void)
|
||||
{
|
||||
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(const smartlist_t *routers)
|
||||
{
|
||||
/* Initialize this first */
|
||||
routers_with_measured_bw = 0;
|
||||
|
||||
/* Iterate over the routerlist and count measured bandwidths */
|
||||
SMARTLIST_FOREACH_BEGIN(routers, const 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);
|
||||
if (mbw_cache) return digestmap_size(mbw_cache);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
/** Return the bandwidth we believe for assigning flags; prefer measured
|
||||
|
@ -1888,26 +1831,6 @@ dirserv_get_flag_thresholds_line(void)
|
|||
return result;
|
||||
}
|
||||
|
||||
/** Given a platform string as in a routerinfo_t (possibly null), return a
|
||||
* newly allocated version string for a networkstatus document, or NULL if the
|
||||
* platform doesn't give a Tor version. */
|
||||
static char *
|
||||
version_from_platform(const char *platform)
|
||||
{
|
||||
if (platform && !strcmpstart(platform, "Tor ")) {
|
||||
const char *eos = find_whitespace(platform+4);
|
||||
if (eos && !strcmpstart(eos, " (r")) {
|
||||
/* XXXX Unify this logic with the other version extraction
|
||||
* logic in routerparse.c. */
|
||||
eos = find_whitespace(eos+1);
|
||||
}
|
||||
if (eos) {
|
||||
return tor_strndup(platform, eos-platform);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** 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.
|
||||
|
@ -2096,145 +2019,6 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
|
|||
return result;
|
||||
}
|
||||
|
||||
/** Helper for sorting: compares two routerinfos first by address, and then by
|
||||
* descending order of "usefulness". (An authority is more useful than a
|
||||
* non-authority; a running router is more useful than a non-running router;
|
||||
* and a router with more bandwidth is more useful than one with less.)
|
||||
**/
|
||||
static int
|
||||
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_kb_first, bw_kb_second;
|
||||
const node_t *node_first, *node_second;
|
||||
int first_is_running, second_is_running;
|
||||
|
||||
/* we return -1 if first should appear before second... that is,
|
||||
* if first is a better router. */
|
||||
if (first->addr < second->addr)
|
||||
return -1;
|
||||
else if (first->addr > second->addr)
|
||||
return 1;
|
||||
|
||||
/* Potentially, this next bit could cause k n lg n memeq calls. But in
|
||||
* reality, we will almost never get here, since addresses will usually be
|
||||
* different. */
|
||||
|
||||
first_is_auth =
|
||||
router_digest_is_trusted_dir(first->cache_info.identity_digest);
|
||||
second_is_auth =
|
||||
router_digest_is_trusted_dir(second->cache_info.identity_digest);
|
||||
|
||||
if (first_is_auth && !second_is_auth)
|
||||
return -1;
|
||||
else if (!first_is_auth && second_is_auth)
|
||||
return 1;
|
||||
|
||||
node_first = node_get_by_id(first->cache_info.identity_digest);
|
||||
node_second = node_get_by_id(second->cache_info.identity_digest);
|
||||
first_is_running = node_first && node_first->is_running;
|
||||
second_is_running = node_second && node_second->is_running;
|
||||
|
||||
if (first_is_running && !second_is_running)
|
||||
return -1;
|
||||
else if (!first_is_running && second_is_running)
|
||||
return 1;
|
||||
|
||||
bw_kb_first = dirserv_get_bandwidth_for_router_kb(first);
|
||||
bw_kb_second = dirserv_get_bandwidth_for_router_kb(second);
|
||||
|
||||
if (bw_kb_first > bw_kb_second)
|
||||
return -1;
|
||||
else if (bw_kb_first < bw_kb_second)
|
||||
return 1;
|
||||
|
||||
/* They're equal! Compare by identity digest, so there's a
|
||||
* deterministic order and we avoid flapping. */
|
||||
return fast_memcmp(first->cache_info.identity_digest,
|
||||
second->cache_info.identity_digest,
|
||||
DIGEST_LEN);
|
||||
}
|
||||
|
||||
/** Given a list of routerinfo_t in <b>routers</b>, return a new digestmap_t
|
||||
* whose keys are the identity digests of those routers that we're going to
|
||||
* exclude for Sybil-like appearance. */
|
||||
static digestmap_t *
|
||||
get_possible_sybil_list(const smartlist_t *routers)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
digestmap_t *omit_as_sybil;
|
||||
smartlist_t *routers_by_ip = smartlist_new();
|
||||
uint32_t last_addr;
|
||||
int addr_count;
|
||||
/* Allow at most this number of Tor servers on a single IP address, ... */
|
||||
int max_with_same_addr = options->AuthDirMaxServersPerAddr;
|
||||
if (max_with_same_addr <= 0)
|
||||
max_with_same_addr = INT_MAX;
|
||||
|
||||
smartlist_add_all(routers_by_ip, routers);
|
||||
smartlist_sort(routers_by_ip, compare_routerinfo_by_ip_and_bw_);
|
||||
omit_as_sybil = digestmap_new();
|
||||
|
||||
last_addr = 0;
|
||||
addr_count = 0;
|
||||
SMARTLIST_FOREACH_BEGIN(routers_by_ip, routerinfo_t *, ri) {
|
||||
if (last_addr != ri->addr) {
|
||||
last_addr = ri->addr;
|
||||
addr_count = 1;
|
||||
} else if (++addr_count > max_with_same_addr) {
|
||||
digestmap_set(omit_as_sybil, ri->cache_info.identity_digest, ri);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ri);
|
||||
|
||||
smartlist_free(routers_by_ip);
|
||||
return omit_as_sybil;
|
||||
}
|
||||
|
||||
/** If there are entries in <b>routers</b> with exactly the same ed25519 keys,
|
||||
* remove the older one. If they are exactly the same age, remove the one
|
||||
* with the greater descriptor digest. May alter the order of the list. */
|
||||
static void
|
||||
routers_make_ed_keys_unique(smartlist_t *routers)
|
||||
{
|
||||
routerinfo_t *ri2;
|
||||
digest256map_t *by_ed_key = digest256map_new();
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
|
||||
ri->omit_from_vote = 0;
|
||||
if (ri->cache_info.signing_key_cert == NULL)
|
||||
continue; /* No ed key */
|
||||
const uint8_t *pk = ri->cache_info.signing_key_cert->signing_key.pubkey;
|
||||
if ((ri2 = digest256map_get(by_ed_key, pk))) {
|
||||
/* Duplicate; must omit one. Set the omit_from_vote flag in whichever
|
||||
* one has the earlier published_on. */
|
||||
const time_t ri_pub = ri->cache_info.published_on;
|
||||
const time_t ri2_pub = ri2->cache_info.published_on;
|
||||
if (ri2_pub < ri_pub ||
|
||||
(ri2_pub == ri_pub &&
|
||||
fast_memcmp(ri->cache_info.signed_descriptor_digest,
|
||||
ri2->cache_info.signed_descriptor_digest,DIGEST_LEN)<0)) {
|
||||
digest256map_set(by_ed_key, pk, ri);
|
||||
ri2->omit_from_vote = 1;
|
||||
} else {
|
||||
ri->omit_from_vote = 1;
|
||||
}
|
||||
} else {
|
||||
/* Add to map */
|
||||
digest256map_set(by_ed_key, pk, ri);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ri);
|
||||
|
||||
digest256map_free(by_ed_key, NULL);
|
||||
|
||||
/* Now remove every router where the omit_from_vote flag got set. */
|
||||
SMARTLIST_FOREACH_BEGIN(routers, const routerinfo_t *, ri) {
|
||||
if (ri->omit_from_vote) {
|
||||
SMARTLIST_DEL_CURRENT(routers, ri);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ri);
|
||||
}
|
||||
|
||||
/** Extract status information from <b>ri</b> and from other authority
|
||||
* functions and store it in <b>rs</b>. <b>rs</b> is zeroed out before it is
|
||||
* set.
|
||||
|
@ -2347,25 +2131,6 @@ dirserv_set_routerstatus_testing(routerstatus_t *rs)
|
|||
}
|
||||
}
|
||||
|
||||
/** Routerstatus <b>rs</b> is part of a group of routers that are on
|
||||
* too narrow an IP-space. Clear out its flags since we don't want it be used
|
||||
* because of its Sybil-like appearance.
|
||||
*
|
||||
* Leave its BadExit flag alone though, since if we think it's a bad exit,
|
||||
* we want to vote that way in case all the other authorities are voting
|
||||
* Running and Exit.
|
||||
*/
|
||||
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_hs_dir = rs->is_v2_dir = rs->is_possible_guard = 0;
|
||||
/* FFFF we might want some mechanism to check later on if we
|
||||
* missed zeroing any flags: it's easy to add a new flag but
|
||||
* forget to add it to this clause. */
|
||||
}
|
||||
|
||||
/** The guardfraction of the guard with identity fingerprint <b>guard_id</b>
|
||||
* is <b>guardfraction_percentage</b>. See if we have a vote routerstatus for
|
||||
* this guard in <b>vote_routerstatuses</b>, and if we do, register the
|
||||
|
@ -2859,286 +2624,6 @@ dirserv_read_measured_bandwidths(const char *from_file,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** Return a new networkstatus_t* containing our current opinion. (For v3
|
||||
* authorities) */
|
||||
networkstatus_t *
|
||||
dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
|
||||
authority_cert_t *cert)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
networkstatus_t *v3_out = NULL;
|
||||
uint32_t addr;
|
||||
char *hostname = NULL, *client_versions = NULL, *server_versions = NULL;
|
||||
const char *contact;
|
||||
smartlist_t *routers, *routerstatuses;
|
||||
char identity_digest[DIGEST_LEN];
|
||||
char signing_key_digest[DIGEST_LEN];
|
||||
int listbadexits = options->AuthDirListBadExits;
|
||||
routerlist_t *rl = router_get_routerlist();
|
||||
time_t now = time(NULL);
|
||||
time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
|
||||
networkstatus_voter_info_t *voter = NULL;
|
||||
vote_timing_t timing;
|
||||
digestmap_t *omit_as_sybil = NULL;
|
||||
const int vote_on_reachability = running_long_enough_to_decide_unreachable();
|
||||
smartlist_t *microdescriptors = NULL;
|
||||
|
||||
tor_assert(private_key);
|
||||
tor_assert(cert);
|
||||
|
||||
if (crypto_pk_get_digest(private_key, signing_key_digest)<0) {
|
||||
log_err(LD_BUG, "Error computing signing key digest");
|
||||
return NULL;
|
||||
}
|
||||
if (crypto_pk_get_digest(cert->identity_key, identity_digest)<0) {
|
||||
log_err(LD_BUG, "Error computing identity key digest");
|
||||
return NULL;
|
||||
}
|
||||
if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) {
|
||||
log_warn(LD_NET, "Couldn't resolve my hostname");
|
||||
return NULL;
|
||||
}
|
||||
if (!hostname || !strchr(hostname, '.')) {
|
||||
tor_free(hostname);
|
||||
hostname = tor_dup_ip(addr);
|
||||
}
|
||||
|
||||
if (options->VersioningAuthoritativeDir) {
|
||||
client_versions = format_versions_list(options->RecommendedClientVersions);
|
||||
server_versions = format_versions_list(options->RecommendedServerVersions);
|
||||
}
|
||||
|
||||
contact = get_options()->ContactInfo;
|
||||
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, {
|
||||
dirserv_set_router_is_running(ri, now);
|
||||
});
|
||||
|
||||
routers = smartlist_new();
|
||||
smartlist_add_all(routers, rl->routers);
|
||||
routers_make_ed_keys_unique(routers);
|
||||
/* After this point, don't use rl->routers; use 'routers' instead. */
|
||||
routers_sort_by_identity(routers);
|
||||
omit_as_sybil = get_possible_sybil_list(routers);
|
||||
|
||||
DIGESTMAP_FOREACH(omit_as_sybil, sybil_id, void *, ignore) {
|
||||
(void) ignore;
|
||||
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(routers);
|
||||
|
||||
dirserv_compute_performance_thresholds(omit_as_sybil);
|
||||
|
||||
routerstatuses = smartlist_new();
|
||||
microdescriptors = smartlist_new();
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
|
||||
if (ri->cache_info.published_on >= cutoff) {
|
||||
routerstatus_t *rs;
|
||||
vote_routerstatus_t *vrs;
|
||||
node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest);
|
||||
if (!node)
|
||||
continue;
|
||||
|
||||
vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
|
||||
rs = &vrs->status;
|
||||
set_routerstatus_from_routerinfo(rs, node, ri, now,
|
||||
listbadexits);
|
||||
|
||||
if (ri->cache_info.signing_key_cert) {
|
||||
memcpy(vrs->ed25519_id,
|
||||
ri->cache_info.signing_key_cert->signing_key.pubkey,
|
||||
ED25519_PUBKEY_LEN);
|
||||
}
|
||||
|
||||
if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
|
||||
clear_status_flags_on_sybil(rs);
|
||||
|
||||
if (!vote_on_reachability)
|
||||
rs->is_flagged_running = 0;
|
||||
|
||||
vrs->version = version_from_platform(ri->platform);
|
||||
if (ri->protocol_list) {
|
||||
vrs->protocols = tor_strdup(ri->protocol_list);
|
||||
} else {
|
||||
vrs->protocols = tor_strdup(
|
||||
protover_compute_for_old_tor(vrs->version));
|
||||
}
|
||||
vrs->microdesc = dirvote_format_all_microdesc_vote_lines(ri, now,
|
||||
microdescriptors);
|
||||
|
||||
smartlist_add(routerstatuses, vrs);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(ri);
|
||||
|
||||
{
|
||||
smartlist_t *added =
|
||||
microdescs_add_list_to_cache(get_microdesc_cache(),
|
||||
microdescriptors, SAVED_NOWHERE, 0);
|
||||
smartlist_free(added);
|
||||
smartlist_free(microdescriptors);
|
||||
}
|
||||
|
||||
smartlist_free(routers);
|
||||
digestmap_free(omit_as_sybil, NULL);
|
||||
|
||||
/* Apply guardfraction information to routerstatuses. */
|
||||
if (options->GuardfractionFile) {
|
||||
dirserv_read_guardfraction_file(options->GuardfractionFile,
|
||||
routerstatuses);
|
||||
}
|
||||
|
||||
/* 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));
|
||||
|
||||
v3_out->type = NS_TYPE_VOTE;
|
||||
dirvote_get_preferred_voting_intervals(&timing);
|
||||
v3_out->published = now;
|
||||
{
|
||||
char tbuf[ISO_TIME_LEN+1];
|
||||
networkstatus_t *current_consensus =
|
||||
networkstatus_get_live_consensus(now);
|
||||
long last_consensus_interval; /* only used to pick a valid_after */
|
||||
if (current_consensus)
|
||||
last_consensus_interval = current_consensus->fresh_until -
|
||||
current_consensus->valid_after;
|
||||
else
|
||||
last_consensus_interval = options->TestingV3AuthInitialVotingInterval;
|
||||
v3_out->valid_after =
|
||||
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",
|
||||
tbuf, current_consensus?1:0, (int)last_consensus_interval);
|
||||
}
|
||||
v3_out->fresh_until = v3_out->valid_after + timing.vote_interval;
|
||||
v3_out->valid_until = v3_out->valid_after +
|
||||
(timing.vote_interval * timing.n_intervals_valid);
|
||||
v3_out->vote_seconds = timing.vote_delay;
|
||||
v3_out->dist_seconds = timing.dist_delay;
|
||||
tor_assert(v3_out->vote_seconds > 0);
|
||||
tor_assert(v3_out->dist_seconds > 0);
|
||||
tor_assert(timing.n_intervals_valid > 0);
|
||||
|
||||
v3_out->client_versions = client_versions;
|
||||
v3_out->server_versions = server_versions;
|
||||
|
||||
/* These are hardwired, to avoid disaster. */
|
||||
v3_out->recommended_relay_protocols =
|
||||
tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
|
||||
"Link=4 LinkAuth=1 Microdesc=1-2 Relay=2");
|
||||
v3_out->recommended_client_protocols =
|
||||
tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
|
||||
"Link=4 LinkAuth=1 Microdesc=1-2 Relay=2");
|
||||
v3_out->required_client_protocols =
|
||||
tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
|
||||
"Link=4 LinkAuth=1 Microdesc=1-2 Relay=2");
|
||||
v3_out->required_relay_protocols =
|
||||
tor_strdup("Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
|
||||
"Link=3-4 LinkAuth=1 Microdesc=1 Relay=1-2");
|
||||
|
||||
/* We are not allowed to vote to require anything we don't have. */
|
||||
tor_assert(protover_all_supported(v3_out->required_relay_protocols, NULL));
|
||||
tor_assert(protover_all_supported(v3_out->required_client_protocols, NULL));
|
||||
|
||||
/* We should not recommend anything we don't have. */
|
||||
tor_assert_nonfatal(protover_all_supported(
|
||||
v3_out->recommended_relay_protocols, NULL));
|
||||
tor_assert_nonfatal(protover_all_supported(
|
||||
v3_out->recommended_client_protocols, NULL));
|
||||
|
||||
v3_out->package_lines = smartlist_new();
|
||||
{
|
||||
config_line_t *cl;
|
||||
for (cl = get_options()->RecommendedPackages; cl; cl = cl->next) {
|
||||
if (validate_recommended_package_line(cl->value))
|
||||
smartlist_add_strdup(v3_out->package_lines, cl->value);
|
||||
}
|
||||
}
|
||||
|
||||
v3_out->known_flags = smartlist_new();
|
||||
smartlist_split_string(v3_out->known_flags,
|
||||
"Authority Exit Fast Guard Stable V2Dir Valid HSDir",
|
||||
0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
||||
if (vote_on_reachability)
|
||||
smartlist_add_strdup(v3_out->known_flags, "Running");
|
||||
if (listbadexits)
|
||||
smartlist_add_strdup(v3_out->known_flags, "BadExit");
|
||||
smartlist_sort_strings(v3_out->known_flags);
|
||||
|
||||
if (options->ConsensusParams) {
|
||||
v3_out->net_params = smartlist_new();
|
||||
smartlist_split_string(v3_out->net_params,
|
||||
options->ConsensusParams, NULL, 0, 0);
|
||||
smartlist_sort_strings(v3_out->net_params);
|
||||
}
|
||||
|
||||
voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
|
||||
voter->nickname = tor_strdup(options->Nickname);
|
||||
memcpy(voter->identity_digest, identity_digest, DIGEST_LEN);
|
||||
voter->sigs = smartlist_new();
|
||||
voter->address = hostname;
|
||||
voter->addr = addr;
|
||||
voter->dir_port = router_get_advertised_dir_port(options, 0);
|
||||
voter->or_port = router_get_advertised_or_port(options);
|
||||
voter->contact = tor_strdup(contact);
|
||||
if (options->V3AuthUseLegacyKey) {
|
||||
authority_cert_t *c = get_my_v3_legacy_cert();
|
||||
if (c) {
|
||||
if (crypto_pk_get_digest(c->identity_key, voter->legacy_id_digest)) {
|
||||
log_warn(LD_BUG, "Unable to compute digest of legacy v3 identity key");
|
||||
memset(voter->legacy_id_digest, 0, DIGEST_LEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v3_out->voters = smartlist_new();
|
||||
smartlist_add(v3_out->voters, voter);
|
||||
v3_out->cert = dirvote_authority_cert_dup(cert);
|
||||
v3_out->routerstatus_list = routerstatuses;
|
||||
/* Note: networkstatus_digest is unset; it won't get set until we actually
|
||||
* format the vote. */
|
||||
|
||||
return v3_out;
|
||||
}
|
||||
|
||||
/** 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
|
||||
|
|
|
@ -157,6 +157,15 @@ void cached_dir_decref(cached_dir_t *d);
|
|||
cached_dir_t *new_cached_dir(char *s, time_t published);
|
||||
|
||||
int validate_recommended_package_line(const char *line);
|
||||
int dirserv_query_measured_bw_cache_kb(const char *node_id,
|
||||
long *bw_out,
|
||||
time_t *as_of_out);
|
||||
void dirserv_clear_measured_bw_cache(void);
|
||||
int dirserv_has_measured_bw(const char *node_id);
|
||||
int dirserv_get_measured_bw_cache_size(void);
|
||||
void dirserv_count_measured_bws(const smartlist_t *routers);
|
||||
int running_long_enough_to_decide_unreachable(void);
|
||||
void dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil);
|
||||
|
||||
#ifdef DIRSERV_PRIVATE
|
||||
|
||||
|
@ -172,13 +181,7 @@ STATIC int measured_bw_line_apply(measured_bw_line_t *parsed_line,
|
|||
|
||||
STATIC void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
|
||||
time_t as_of);
|
||||
STATIC void dirserv_clear_measured_bw_cache(void);
|
||||
STATIC void dirserv_expire_measured_bw_cache(time_t now);
|
||||
STATIC int dirserv_get_measured_bw_cache_size(void);
|
||||
STATIC int dirserv_query_measured_bw_cache_kb(const char *node_id,
|
||||
long *bw_out,
|
||||
time_t *as_of_out);
|
||||
STATIC int dirserv_has_measured_bw(const char *node_id);
|
||||
|
||||
STATIC int
|
||||
dirserv_read_guardfraction_file_from_str(const char *guardfraction_file_str,
|
||||
|
|
Loading…
Reference in New Issue