Fetch certificates from the same directory as the consensus

Resolves ticket 18963; fix on #4483 in 0.2.8.1-alpha.
This commit is contained in:
teor (Tim Wilson-Brown) 2016-05-04 16:38:27 +10:00
parent 797ece042d
commit 730cfeb6bd
No known key found for this signature in database
GPG Key ID: 450CBA7F968F094B
7 changed files with 102 additions and 24 deletions

4
changes/bug18963 Normal file
View File

@ -0,0 +1,4 @@
o Minor bugfix (bootstrap):
- Remember the directory we fetched the consensus from, and use
it to fetch authority certificates as well.
Resolves ticket 18963; fix on #4483 in 0.2.8.1-alpha.

View File

@ -2019,7 +2019,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
}
log_info(LD_DIR,"Received consensus directory (size %d) from server "
"'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
if ((r=networkstatus_set_current_consensus(body, flavname, 0))<0) {
if ((r=networkstatus_set_current_consensus(body, flavname, 0,
conn->identity_digest))<0) {
log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR,
"Unable to load %s consensus directory downloaded from "
"server '%s:%d'. I'll try again soon.",

View File

@ -3373,7 +3373,7 @@ dirvote_publish_consensus(void)
continue;
}
if (networkstatus_set_current_consensus(pending->body, name, 0))
if (networkstatus_set_current_consensus(pending->body, name, 0, NULL))
log_warn(LD_DIR, "Error publishing %s consensus", name);
else
log_notice(LD_DIR, "Published %s consensus", name);

View File

@ -174,7 +174,7 @@ router_reload_consensus_networkstatus(void)
}
s = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
if (s) {
if (networkstatus_set_current_consensus(s, flavor, flags) < -1) {
if (networkstatus_set_current_consensus(s, flavor, flags, NULL) < -1) {
log_warn(LD_FS, "Couldn't load consensus %s networkstatus from \"%s\"",
flavor, filename);
}
@ -192,7 +192,8 @@ router_reload_consensus_networkstatus(void)
s = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
if (s) {
if (networkstatus_set_current_consensus(s, flavor,
flags|NSSET_WAS_WAITING_FOR_CERTS)) {
flags|NSSET_WAS_WAITING_FOR_CERTS,
NULL)) {
log_info(LD_FS, "Couldn't load consensus %s networkstatus from \"%s\"",
flavor, filename);
}
@ -1200,13 +1201,13 @@ update_certificate_downloads(time_t now)
for (i = 0; i < N_CONSENSUS_FLAVORS; ++i) {
if (consensus_waiting_for_certs[i].consensus)
authority_certs_fetch_missing(consensus_waiting_for_certs[i].consensus,
now);
now, NULL);
}
if (current_ns_consensus)
authority_certs_fetch_missing(current_ns_consensus, now);
authority_certs_fetch_missing(current_ns_consensus, now, NULL);
if (current_md_consensus)
authority_certs_fetch_missing(current_md_consensus, now);
authority_certs_fetch_missing(current_md_consensus, now, NULL);
}
/** Return 1 if we have a consensus but we don't have enough certificates
@ -1504,6 +1505,10 @@ networkstatus_set_current_consensus_from_ns(networkstatus_t *c,
* If flags & NSSET_ACCEPT_OBSOLETE, then we should be willing to take this
* consensus, even if it comes from many days in the past.
*
* If source_dir is non-NULL, it's the identity digest for a directory that
* we've just successfully retrieved a consensus from, so try it first to
* fetch any missing certificates.
*
* Return 0 on success, <0 on failure. On failure, caller should increment
* the failure count as appropriate.
*
@ -1513,7 +1518,8 @@ networkstatus_set_current_consensus_from_ns(networkstatus_t *c,
int
networkstatus_set_current_consensus(const char *consensus,
const char *flavor,
unsigned flags)
unsigned flags,
const char *source_dir)
{
networkstatus_t *c=NULL;
int r, result = -1;
@ -1635,7 +1641,7 @@ networkstatus_set_current_consensus(const char *consensus,
write_str_to_file(unverified_fname, consensus, 0);
}
if (dl_certs)
authority_certs_fetch_missing(c, now);
authority_certs_fetch_missing(c, now, source_dir);
/* This case is not a success or a failure until we get the certs
* or fail to get the certs. */
result = 0;
@ -1673,7 +1679,7 @@ networkstatus_set_current_consensus(const char *consensus,
/* Are we missing any certificates at all? */
if (r != 1 && dl_certs)
authority_certs_fetch_missing(c, now);
authority_certs_fetch_missing(c, now, source_dir);
if (flav == usable_consensus_flavor()) {
notify_control_networkstatus_changed(current_consensus, c);
@ -1810,7 +1816,8 @@ networkstatus_note_certs_arrived(void)
if (!networkstatus_set_current_consensus(
waiting_body,
networkstatus_get_flavor_name(i),
NSSET_WAS_WAITING_FOR_CERTS)) {
NSSET_WAS_WAITING_FOR_CERTS,
NULL)) {
tor_free(waiting_body);
}
}

View File

@ -85,7 +85,8 @@ int networkstatus_consensus_is_downloading_usable_flavor(void);
#define NSSET_REQUIRE_FLAVOR 16
int networkstatus_set_current_consensus(const char *consensus,
const char *flavor,
unsigned flags);
unsigned flags,
const char *source_dir);
void networkstatus_note_certs_arrived(void);
void routers_update_all_from_networkstatus(time_t now, int dir_version);
void routers_update_status_from_consensus_networkstatus(smartlist_t *routers,

View File

@ -718,9 +718,14 @@ authority_cert_dl_looks_uncertain(const char *id_digest)
* <b>status</b>. Additionally, try to have a non-expired certificate for
* every V3 authority in trusted_dir_servers. Don't fetch certificates we
* already have.
*
* If dir_hint is non-NULL, it's the identity digest for a directory that
* we've just successfully retrieved a consensus from, so try it first to
* fetch any missing certificates.
**/
void
authority_certs_fetch_missing(networkstatus_t *status, time_t now)
authority_certs_fetch_missing(networkstatus_t *status, time_t now,
const char *dir_hint)
{
/*
* The pending_id digestmap tracks pending certificate downloads by
@ -884,6 +889,37 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
} SMARTLIST_FOREACH_END(voter);
}
/* Look up the routerstatus for the dir_hint */
const routerstatus_t *rs = NULL;
/* If we still need certificates, try the directory that just successfully
* served us a consensus or certificates.
* As soon as the directory fails to provide additional certificates, we try
* another, randomly selected directory. This avoids continual retries.
* (We only ever have one outstanding request per certificate.)
*
* Bridge clients won't find their bridges using this hint, so they will
* fall back to using directory_get_from_dirserver, which selects a bridge.
*/
if (dir_hint) {
/* First try the consensus routerstatus, then the fallback
* routerstatus */
rs = router_get_consensus_status_by_id(dir_hint);
if (!rs) {
/* This will also find authorities */
const dir_server_t *ds = router_get_fallback_dirserver_by_digest(
dir_hint);
if (ds) {
rs = &ds->fake_status;
}
}
if (!rs) {
log_warn(LD_BUG, "Directory %s delivered a consensus, but a "
"routerstatus could not be found for it.", dir_hint);
}
}
/* Do downloads by identity digest */
if (smartlist_len(missing_id_digests) > 0) {
int need_plus = 0;
@ -913,11 +949,25 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
if (smartlist_len(fps) > 1) {
resource = smartlist_join_strings(fps, "", 0, NULL);
/* We want certs from mirrors, because they will almost always succeed.
*/
directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
resource, PDS_RETRY_IF_NO_SERVERS,
DL_WANT_ANY_DIRSERVER);
/* If we've just downloaded a consensus from a directory, re-use that
* directory */
if (rs) {
/* Certificate fetches are one-hop, unless AllDirActionsPrivate is 1 */
int get_via_tor = get_options()->AllDirActionsPrivate;
const dir_indirection_t indirection = get_via_tor ? DIRIND_ANONYMOUS
: DIRIND_ONEHOP;
directory_initiate_command_routerstatus(rs,
DIR_PURPOSE_FETCH_CERTIFICATE,
0, indirection, resource, NULL,
0, 0);
} else {
/* Otherwise, we want certs from a random fallback or directory
* mirror, because they will almost always succeed. */
directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
resource, PDS_RETRY_IF_NO_SERVERS,
DL_WANT_ANY_DIRSERVER);
}
tor_free(resource);
}
/* else we didn't add any: they were all pending */
@ -960,11 +1010,25 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
if (smartlist_len(fp_pairs) > 1) {
resource = smartlist_join_strings(fp_pairs, "", 0, NULL);
/* We want certs from mirrors, because they will almost always succeed.
*/
directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
resource, PDS_RETRY_IF_NO_SERVERS,
DL_WANT_ANY_DIRSERVER);
/* If we've just downloaded a consensus from a directory, re-use that
* directory */
if (rs) {
/* Certificate fetches are one-hop, unless AllDirActionsPrivate is 1 */
int get_via_tor = get_options()->AllDirActionsPrivate;
const dir_indirection_t indirection = get_via_tor ? DIRIND_ANONYMOUS
: DIRIND_ONEHOP;
directory_initiate_command_routerstatus(rs,
DIR_PURPOSE_FETCH_CERTIFICATE,
0, indirection, resource, NULL,
0, 0);
} else {
/* Otherwise, we want certs from a random fallback or directory
* mirror, because they will almost always succeed. */
directory_get_from_dirserver(DIR_PURPOSE_FETCH_CERTIFICATE, 0,
resource, PDS_RETRY_IF_NO_SERVERS,
DL_WANT_ANY_DIRSERVER);
}
tor_free(resource);
}
/* else they were all pending */

View File

@ -38,7 +38,8 @@ authority_cert_t *authority_cert_get_by_digests(const char *id_digest,
void authority_cert_get_all(smartlist_t *certs_out);
void authority_cert_dl_failed(const char *id_digest,
const char *signing_key_digest, int status);
void authority_certs_fetch_missing(networkstatus_t *status, time_t now);
void authority_certs_fetch_missing(networkstatus_t *status, time_t now,
const char *dir_hint);
int router_reload_router_list(void);
int authority_cert_dl_looks_uncertain(const char *id_digest);
const smartlist_t *router_get_trusted_dir_servers(void);