📄 networkstatus.c
字号:
/* This can never be signed enough: Kill it. */
if (!was_waiting_for_certs) {
log_warn(LD_DIR, "Not enough good signatures on networkstatus "
"consensus");
result = -2;
}
if (was_waiting_for_certs && (r < -1) && from_cache)
unlink(unverified_fname);
goto done;
}
}
/* Are we missing any certificates at all? */
if (r != 1 && dl_certs)
authority_certs_fetch_missing(c, now);
if (control_event_is_interesting(EVENT_NS))
notify_control_networkstatus_changed(current_consensus, c);
if (current_consensus) {
networkstatus_copy_old_consensus_info(c, current_consensus);
networkstatus_vote_free(current_consensus);
}
if (consensus_waiting_for_certs &&
consensus_waiting_for_certs->valid_after <= c->valid_after) {
networkstatus_vote_free(consensus_waiting_for_certs);
consensus_waiting_for_certs = NULL;
if (consensus != consensus_waiting_for_certs_body)
tor_free(consensus_waiting_for_certs_body);
else
consensus_waiting_for_certs_body = NULL;
consensus_waiting_for_certs_set_at = 0;
consensus_waiting_for_certs_dl_failed = 0;
unlink(unverified_fname);
}
/* Reset the failure count only if this consensus is actually valid. */
if (c->valid_after <= now && now <= c->valid_until) {
download_status_reset(&consensus_dl_status);
} else {
if (!from_cache)
download_status_failed(&consensus_dl_status, 0);
}
current_consensus = c;
c = NULL; /* Prevent free. */
update_consensus_networkstatus_fetch_time(now);
dirvote_recalculate_timing(get_options(), now);
routerstatus_list_update_named_server_map();
if (!from_cache) {
write_str_to_file(consensus_fname, consensus, 0);
}
if (directory_caches_dir_info(get_options()))
dirserv_set_cached_networkstatus_v3(consensus,
current_consensus->valid_after);
if (ftime_definitely_before(now, current_consensus->valid_after)) {
char tbuf[ISO_TIME_LEN+1];
char dbuf[64];
long delta = now - current_consensus->valid_after;
format_iso_time(tbuf, current_consensus->valid_after);
format_time_interval(dbuf, sizeof(dbuf), delta);
log_warn(LD_GENERAL, "Our clock is %s behind the time published in the "
"consensus network status document (%s GMT). Tor needs an "
"accurate clock to work correctly. Please check your time and "
"date settings!", dbuf, tbuf);
control_event_general_status(LOG_WARN,
"CLOCK_SKEW MIN_SKEW=%ld SOURCE=CONSENSUS", delta);
}
router_dir_info_changed();
result = 0;
done:
if (c)
networkstatus_vote_free(c);
tor_free(consensus_fname);
tor_free(unverified_fname);
return result;
}
/** Called when we have gotten more certificates: see whether we can
* now verify a pending consensus. */
void
networkstatus_note_certs_arrived(void)
{
if (consensus_waiting_for_certs) {
if (networkstatus_check_consensus_signature(
consensus_waiting_for_certs, 0)>=0) {
if (!networkstatus_set_current_consensus(
consensus_waiting_for_certs_body,
NSSET_WAS_WAITING_FOR_CERTS)) {
tor_free(consensus_waiting_for_certs_body);
}
}
}
}
/** If the network-status list has changed since the last time we called this
* function, update the status of every routerinfo from the network-status
* list. If <b>dir_version</b> is 2, it's a v2 networkstatus that changed.
* If <b>dir_version</b> is 3, it's a v3 consensus that changed.
*/
void
routers_update_all_from_networkstatus(time_t now, int dir_version)
{
routerinfo_t *me;
routerlist_t *rl = router_get_routerlist();
networkstatus_t *consensus = networkstatus_get_live_consensus(now);
or_options_t *options = get_options();
if (networkstatus_v2_list_has_changed)
download_status_map_update_from_v2_networkstatus();
if (!consensus || dir_version < 3) /* nothing more we should do */
return;
/* More routers may be up or down now: we need to recalc whether there's
* enough directory info. */
router_dir_info_changed();
routers_update_status_from_consensus_networkstatus(rl->routers, 0);
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri,
ri->cache_info.routerlist_index = ri_sl_idx);
if (rl->old_routers)
signed_descs_update_status_from_consensus_networkstatus(rl->old_routers);
/* XXX020 these warnings don't help anymore; we should disable them -RD */
me = router_get_my_routerinfo();
if (me && !have_warned_about_invalid_status) {
routerstatus_t *rs = networkstatus_vote_find_entry(consensus,
me->cache_info.identity_digest);
if (!rs) {
log_info(LD_GENERAL, "The latest consensus does not list us."
"Are you misconfigured?");
have_warned_about_invalid_status = 1;
} else if (rs->is_unnamed) {
/* Maybe upgrade this to notice? XXXX020 */
log_info(LD_GENERAL, "The directory have assigned the nickname "
"you're using (%s) to a different identity; you may want to "
"choose a different nickname.", options->Nickname);
have_warned_about_invalid_status = 1;
} else if (!rs->is_named) {
log_debug(LD_GENERAL, "The directory authorities do not currently "
"recognize your nickname.");
have_warned_about_invalid_status = 1;
}
}
if (!have_warned_about_old_version) {
int is_server = server_mode(get_options());
version_status_t status;
const char *recommended = is_server ?
consensus->server_versions : consensus->client_versions;
status = tor_version_is_obsolete(VERSION, recommended);
if (status == VS_RECOMMENDED) {
log_info(LD_GENERAL, "The directory authorities say my version is ok.");
} else if (status == VS_EMPTY) {
log_info(LD_GENERAL,
"The directory authorities don't recommend any versions.");
} else if (status == VS_NEW || status == VS_NEW_IN_SERIES) {
if (!have_warned_about_new_version) {
log_notice(LD_GENERAL, "This version of Tor (%s) is newer than any "
"recommended version%s, according to the directory "
"authorities. Recommended versions are: %s",
VERSION,
status == VS_NEW_IN_SERIES ? " in its series" : "",
recommended);
have_warned_about_new_version = 1;
control_event_general_status(LOG_WARN, "DANGEROUS_VERSION "
"CURRENT=%s REASON=%s RECOMMENDED=\"%s\"",
VERSION, "NEW", recommended);
}
} else {
log_warn(LD_GENERAL, "Please upgrade! "
"This version of Tor (%s) is %s, according to the directory "
"authorities. Recommended versions are: %s",
VERSION,
status == VS_OLD ? "obsolete" : "not recommended",
recommended);
have_warned_about_old_version = 1;
control_event_general_status(LOG_WARN, "DANGEROUS_VERSION "
"CURRENT=%s REASON=%s RECOMMENDED=\"%s\"",
VERSION, status == VS_OLD ? "OBSOLETE" : "UNRECOMMENDED",
recommended);
}
}
}
/** Update v2_download_status_map to contain an entry for every router
* descriptor listed in the v2 networkstatuses. */
static void
download_status_map_update_from_v2_networkstatus(void)
{
digestmap_t *dl_status;
if (!networkstatus_v2_list)
return;
if (!v2_download_status_map)
v2_download_status_map = digestmap_new();
dl_status = digestmap_new();
SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns,
{
SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
{
const char *d = rs->descriptor_digest;
download_status_t *s;
if (digestmap_get(dl_status, d))
continue;
if (!(s = digestmap_remove(v2_download_status_map, d))) {
s = tor_malloc_zero(sizeof(download_status_t));
}
digestmap_set(dl_status, d, s);
});
});
digestmap_free(v2_download_status_map, _tor_free);
v2_download_status_map = dl_status;
networkstatus_v2_list_has_changed = 0;
}
/** Update our view of the list of named servers from the most recently
* retrieved networkstatus consensus. */
static void
routerstatus_list_update_named_server_map(void)
{
if (!current_consensus)
return;
if (named_server_map)
strmap_free(named_server_map, _tor_free);
named_server_map = strmap_new();
if (unnamed_server_map)
strmap_free(unnamed_server_map, NULL);
unnamed_server_map = strmap_new();
SMARTLIST_FOREACH(current_consensus->routerstatus_list, routerstatus_t *, rs,
{
if (rs->is_named) {
strmap_set_lc(named_server_map, rs->nickname,
tor_memdup(rs->identity_digest, DIGEST_LEN));
}
if (rs->is_unnamed) {
strmap_set_lc(unnamed_server_map, rs->nickname, (void*)1);
}
});
}
/** Given a list <b>routers</b> of routerinfo_t *, update each status field
* according to our current consensus networkstatus. May re-order
* <b>routers</b>. */
void
routers_update_status_from_consensus_networkstatus(smartlist_t *routers,
int reset_failures)
{
trusted_dir_server_t *ds;
or_options_t *options = get_options();
int authdir = authdir_mode_v2(options) || authdir_mode_v3(options);
int namingdir = authdir && options->NamingAuthoritativeDir;
networkstatus_t *ns = current_consensus;
if (!ns || !smartlist_len(ns->routerstatus_list))
return;
if (!networkstatus_v2_list)
networkstatus_v2_list = smartlist_create();
routers_sort_by_identity(routers);
SMARTLIST_FOREACH_JOIN(ns->routerstatus_list, routerstatus_t *, rs,
routers, routerinfo_t *, router,
memcmp(rs->identity_digest,
router->cache_info.identity_digest, DIGEST_LEN),
{
/* We have no routerstatus for this router. Clear flags and skip it. */
if (!namingdir)
router->is_named = 0;
if (!authdir) {
if (router->purpose == ROUTER_PURPOSE_GENERAL)
router_clear_status_flags(router);
}
}) {
/* We have a routerstatus for this router. */
const char *digest = router->cache_info.identity_digest;
ds = router_get_trusteddirserver_by_digest(digest);
if (!namingdir) {
if (rs->is_named && !strcasecmp(router->nickname, rs->nickname))
router->is_named = 1;
else
router->is_named = 0;
}
/* Is it the same descriptor, or only the same identity? */
if (!memcmp(router->cache_info.signed_descriptor_digest,
rs->descriptor_digest, DIGEST_LEN)) {
if (ns->valid_until > router->cache_info.last_listed_as_valid_until)
router->cache_info.last_listed_as_valid_until = ns->valid_until;
}
if (!authdir) {
/* If we're not an authdir, believe others. */
router->is_valid = rs->is_valid;
router->is_running = rs->is_running;
router->is_fast = rs->is_fast;
router->is_stable = rs->is_stable;
router->is_possible_guard = rs->is_possible_guard;
router->is_exit = rs->is_exit;
router->is_bad_directory = rs->is_bad_directory;
router->is_bad_exit = rs->is_bad_exit;
router->is_hs_dir = rs->is_hs_dir;
}
if (router->is_running && ds) {
download_status_reset(&ds->v2_ns_dl_status);
}
if (reset_failures) {
download_status_reset(&rs->dl_status);
}
} SMARTLIST_FOREACH_JOIN_END(rs, router);
/* Now update last_listed_as_valid_until from v2 networkstatuses. */
/* XXXX021 If this is slow, we need to rethink the code. */
SMARTLIST_FOREACH(networkstatus_v2_list, networkstatus_v2_t *, ns, {
time_t live_until = ns->published_on + V2_NETWORKSTATUS_LIFETIME;
SMARTLIST_FOREACH_JOIN(ns->entries, routerstatus_t *, rs,
routers, routerinfo_t *, ri,
memcmp(rs->identity_digest,
ri->cache_info.identity_digest, DIGEST_LEN),
STMT_NIL) {
if (!memcmp(ri->cache_info.signed_descriptor_digest,
rs->descriptor_digest, DIGEST_LEN)) {
if (live_until > ri->cache_info.last_listed_as_valid_until)
ri->cache_info.last_listed_as_valid_until = live_until;
}
} SMARTLIST_FOREACH_JOIN_END(rs, ri);
});
router_dir_info_changed();
}
/** Given a list of signed_descriptor_t, update their fields (mainly, when
* they were last listed) from the most recent consensus. */
void
signed_descs_update_status_from_consensus_networkstatus(smartlist_t *descs)
{
networkstatus_t *ns = current_consensus;
if (!ns)
return;
if (!ns->desc_digest_map) {
char dummy[DIGEST_LEN];
/* instantiates the digest map. */
memset(dummy, 0, sizeof(dummy));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -