📄 networkstatus.c
字号:
voter->bad_signature = 1;
} else {
voter->good_signature = 1;
}
tor_free(signed_digest);
return 0;
}
/** Given a v3 networkstatus consensus in <b>consensus</b>, check every
* as-yet-unchecked signature on <b>consensus</b>. Return 1 if there is a
* signature from every recognized authority on it, 0 if there are
* enough good signatures from recognized authorities on it, -1 if we might
* get enough good signatures by fetching missing certificates, and -2
* otherwise. Log messages at INFO or WARN: if <b>warn</b> is over 1, warn
* about every problem; if warn is at least 1, warn only if we can't get
* enough signatures; if warn is negative, log nothing at all. */
int
networkstatus_check_consensus_signature(networkstatus_t *consensus,
int warn)
{
int n_good = 0;
int n_missing_key = 0;
int n_bad = 0;
int n_unknown = 0;
int n_no_signature = 0;
int n_v3_authorities = get_n_authorities(V3_AUTHORITY);
int n_required = n_v3_authorities/2 + 1;
smartlist_t *need_certs_from = smartlist_create();
smartlist_t *unrecognized = smartlist_create();
smartlist_t *missing_authorities = smartlist_create();
int severity;
tor_assert(! consensus->is_vote);
SMARTLIST_FOREACH(consensus->voters, networkstatus_voter_info_t *, voter,
{
if (!voter->good_signature && !voter->bad_signature && voter->signature) {
/* we can try to check the signature. */
authority_cert_t *cert =
authority_cert_get_by_digests(voter->identity_digest,
voter->signing_key_digest);
if (! cert) {
if (!trusteddirserver_get_by_v3_auth_digest(voter->identity_digest)) {
smartlist_add(unrecognized, voter);
++n_unknown;
} else {
smartlist_add(need_certs_from, voter);
++n_missing_key;
}
continue;
}
if (networkstatus_check_voter_signature(consensus, voter, cert) < 0) {
smartlist_add(need_certs_from, voter);
++n_missing_key;
continue;
}
}
if (voter->good_signature)
++n_good;
else if (voter->bad_signature)
++n_bad;
else
++n_no_signature;
});
/* Now see whether we're missing any voters entirely. */
SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
trusted_dir_server_t *, ds,
{
if ((ds->type & V3_AUTHORITY) &&
!networkstatus_get_voter_by_id(consensus, ds->v3_identity_digest))
smartlist_add(missing_authorities, ds);
});
if (warn > 1 || (warn >= 0 && n_good < n_required))
severity = LOG_WARN;
else
severity = LOG_INFO;
if (warn >= 0) {
SMARTLIST_FOREACH(unrecognized, networkstatus_voter_info_t *, voter,
{
log_info(LD_DIR, "Consensus includes unrecognized authority '%s' "
"at %s:%d (contact %s; identity %s)",
voter->nickname, voter->address, (int)voter->dir_port,
voter->contact?voter->contact:"n/a",
hex_str(voter->identity_digest, DIGEST_LEN));
});
SMARTLIST_FOREACH(need_certs_from, networkstatus_voter_info_t *, voter,
{
log_info(LD_DIR, "Looks like we need to download a new certificate "
"from authority '%s' at %s:%d (contact %s; identity %s)",
voter->nickname, voter->address, (int)voter->dir_port,
voter->contact?voter->contact:"n/a",
hex_str(voter->identity_digest, DIGEST_LEN));
});
SMARTLIST_FOREACH(missing_authorities, trusted_dir_server_t *, ds,
{
log_info(LD_DIR, "Consensus does not include configured "
"authority '%s' at %s:%d (identity %s)",
ds->nickname, ds->address, (int)ds->dir_port,
hex_str(ds->v3_identity_digest, DIGEST_LEN));
});
log(severity, LD_DIR,
"%d unknown, %d missing key, %d good, %d bad, %d no signature, "
"%d required", n_unknown, n_missing_key, n_good, n_bad,
n_no_signature, n_required);
}
smartlist_free(unrecognized);
smartlist_free(need_certs_from);
smartlist_free(missing_authorities);
if (n_good == n_v3_authorities)
return 1;
else if (n_good >= n_required)
return 0;
else if (n_good + n_missing_key >= n_required)
return -1;
else
return -2;
}
/** Helper: return a newly allocated string containing the name of the filename
* where we plan to cache the network status with the given identity digest. */
char *
networkstatus_get_cache_filename(const char *identity_digest)
{
char fp[HEX_DIGEST_LEN+1];
base16_encode(fp, HEX_DIGEST_LEN+1, identity_digest, DIGEST_LEN);
return get_datadir_fname2("cached-status", fp);
}
/** Helper for smartlist_sort: Compare two networkstatus objects by
* publication date. */
static int
_compare_networkstatus_v2_published_on(const void **_a, const void **_b)
{
const networkstatus_v2_t *a = *_a, *b = *_b;
if (a->published_on < b->published_on)
return -1;
else if (a->published_on > b->published_on)
return 1;
else
return 0;
}
/** Add the parsed v2 networkstatus in <b>ns</b> (with original document in
* <b>s</b>) to the disk cache (and the in-memory directory server cache) as
* appropriate. */
static int
add_networkstatus_to_cache(const char *s,
networkstatus_source_t source,
networkstatus_v2_t *ns)
{
if (source != NS_FROM_CACHE) {
char *fn = networkstatus_get_cache_filename(ns->identity_digest);
if (write_str_to_file(fn, s, 0)<0) {
log_notice(LD_FS, "Couldn't write cached network status to \"%s\"", fn);
}
tor_free(fn);
}
if (directory_caches_v2_dir_info(get_options()))
dirserv_set_cached_networkstatus_v2(s,
ns->identity_digest,
ns->published_on);
return 0;
}
/** How far in the future do we allow a network-status to get before removing
* it? (seconds) */
#define NETWORKSTATUS_ALLOW_SKEW (24*60*60)
/** Given a string <b>s</b> containing a network status that we received at
* <b>arrived_at</b> from <b>source</b>, try to parse it, see if we want to
* store it, and put it into our cache as necessary.
*
* If <b>source</b> is NS_FROM_DIR or NS_FROM_CACHE, do not replace our
* own networkstatus_t (if we're an authoritative directory server).
*
* If <b>source</b> is NS_FROM_CACHE, do not write our networkstatus_t to the
* cache.
*
* If <b>requested_fingerprints</b> is provided, it must contain a list of
* uppercased identity fingerprints. Do not update any networkstatus whose
* fingerprint is not on the list; after updating a networkstatus, remove its
* fingerprint from the list.
*
* Return 0 on success, -1 on failure.
*
* Callers should make sure that routers_update_all_from_networkstatus() is
* invoked after this function succeeds.
*/
int
router_set_networkstatus_v2(const char *s, time_t arrived_at,
networkstatus_source_t source, smartlist_t *requested_fingerprints)
{
networkstatus_v2_t *ns;
int i, found;
time_t now;
int skewed = 0;
trusted_dir_server_t *trusted_dir = NULL;
const char *source_desc = NULL;
char fp[HEX_DIGEST_LEN+1];
char published[ISO_TIME_LEN+1];
if (!directory_caches_v2_dir_info(get_options()))
return 0; /* Don't bother storing it. */
ns = networkstatus_v2_parse_from_string(s);
if (!ns) {
log_warn(LD_DIR, "Couldn't parse network status.");
return -1;
}
base16_encode(fp, HEX_DIGEST_LEN+1, ns->identity_digest, DIGEST_LEN);
if (!(trusted_dir =
router_get_trusteddirserver_by_digest(ns->identity_digest)) ||
!(trusted_dir->type & V2_AUTHORITY)) {
log_info(LD_DIR, "Network status was signed, but not by an authoritative "
"directory we recognize.");
source_desc = fp;
} else {
source_desc = trusted_dir->description;
}
now = time(NULL);
if (arrived_at > now)
arrived_at = now;
ns->received_on = arrived_at;
format_iso_time(published, ns->published_on);
if (ns->published_on > now + NETWORKSTATUS_ALLOW_SKEW) {
char dbuf[64];
long delta = now - ns->published_on;
format_time_interval(dbuf, sizeof(dbuf), delta);
log_warn(LD_GENERAL, "Network status from %s was published %s in the "
"future (%s GMT). Check your time and date settings! "
"Not caching.",
source_desc, dbuf, published);
control_event_general_status(LOG_WARN,
"CLOCK_SKEW MIN_SKEW=%ld SOURCE=NETWORKSTATUS:%s:%d",
delta, ns->source_address, ns->source_dirport);
skewed = 1;
}
if (!networkstatus_v2_list)
networkstatus_v2_list = smartlist_create();
if ( (source == NS_FROM_DIR_BY_FP || source == NS_FROM_DIR_ALL) &&
router_digest_is_me(ns->identity_digest)) {
/* Don't replace our own networkstatus when we get it from somebody else.*/
networkstatus_v2_free(ns);
return 0;
}
if (requested_fingerprints) {
if (smartlist_string_isin(requested_fingerprints, fp)) {
smartlist_string_remove(requested_fingerprints, fp);
} else {
if (source != NS_FROM_DIR_ALL) {
char *requested =
smartlist_join_strings(requested_fingerprints," ",0,NULL);
log_warn(LD_DIR,
"We received a network status with a fingerprint (%s) that we "
"never requested. (We asked for: %s.) Dropping.",
fp, requested);
tor_free(requested);
return 0;
}
}
}
if (!trusted_dir) {
if (!skewed) {
/* We got a non-trusted networkstatus, and we're a directory cache.
* This means that we asked an authority, and it told us about another
* authority we didn't recognize. */
log_info(LD_DIR,
"We do not recognize authority (%s) but we are willing "
"to cache it.", fp);
add_networkstatus_to_cache(s, source, ns);
networkstatus_v2_free(ns);
}
return 0;
}
found = 0;
for (i=0; i < smartlist_len(networkstatus_v2_list); ++i) {
networkstatus_v2_t *old_ns = smartlist_get(networkstatus_v2_list, i);
if (!memcmp(old_ns->identity_digest, ns->identity_digest, DIGEST_LEN)) {
if (!memcmp(old_ns->networkstatus_digest,
ns->networkstatus_digest, DIGEST_LEN)) {
/* Same one we had before. */
networkstatus_v2_free(ns);
tor_assert(trusted_dir);
log_info(LD_DIR,
"Not replacing network-status from %s (published %s); "
"we already have it.",
trusted_dir->description, published);
if (old_ns->received_on < arrived_at) {
if (source != NS_FROM_CACHE) {
char *fn;
fn = networkstatus_get_cache_filename(old_ns->identity_digest);
/* We use mtime to tell when it arrived, so update that. */
touch_file(fn);
tor_free(fn);
}
old_ns->received_on = arrived_at;
}
download_status_failed(&trusted_dir->v2_ns_dl_status, 0);
return 0;
} else if (old_ns->published_on >= ns->published_on) {
char old_published[ISO_TIME_LEN+1];
format_iso_time(old_published, old_ns->published_on);
tor_assert(trusted_dir);
log_info(LD_DIR,
"Not replacing network-status from %s (published %s);"
" we have a newer one (published %s) for this authority.",
trusted_dir->description, published,
old_published);
networkstatus_v2_free(ns);
download_status_failed(&trusted_dir->v2_ns_dl_status, 0);
return 0;
} else {
networkstatus_v2_free(old_ns);
smartlist_set(networkstatus_v2_list, i, ns);
found = 1;
break;
}
}
}
if (source != NS_FROM_CACHE && trusted_dir) {
download_status_reset(&trusted_dir->v2_ns_dl_status);
}
if (!found)
smartlist_add(networkstatus_v2_list, ns);
/*XXXX021 magic. */
/*DOCDOC */
#define V2_NETWORKSTATUS_LIFETIME (3*60*60)
{
time_t live_until = ns->published_on + V2_NETWORKSTATUS_LIFETIME;
SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
{
signed_descriptor_t *sd =
router_get_by_descriptor_digest(rs->descriptor_digest);
if (sd) {
if (sd->last_listed_as_valid_until < live_until)
sd->last_listed_as_valid_until = live_until;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -