aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2007-10-22 17:31:26 +0000
committerNick Mathewson <nickm@torproject.org>2007-10-22 17:31:26 +0000
commit09bce19884d9b07a83979a6b6f0abb1789a3b9b3 (patch)
treee9d316e6aef1f6a95f0d98326aa32bcc88915c1d /src/or
parent4bab46d5d797c9a2f88fbf5dfb9ea0d91d384ee7 (diff)
downloadtor-09bce19884d9b07a83979a6b6f0abb1789a3b9b3.tar
tor-09bce19884d9b07a83979a6b6f0abb1789a3b9b3.tar.gz
r16042@catbus: nickm | 2007-10-22 13:30:49 -0400
Move functions into and out of dirvote.c so that it contains all the v3 authority functionality, and no non-authority functionality. svn:r12107
Diffstat (limited to 'src/or')
-rw-r--r--src/or/dirserv.c239
-rw-r--r--src/or/dirvote.c420
-rw-r--r--src/or/networkstatus.c208
-rw-r--r--src/or/or.h34
-rw-r--r--src/or/routerlist.c16
5 files changed, 442 insertions, 475 deletions
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 420bf08d1..7c702fa2d 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1457,10 +1457,6 @@ dirserv_get_consensus(void)
/** For authoritative directories: the current (v2) network status. */
static cached_dir_t *the_v2_networkstatus = NULL;
-/** For authoritative directories: out most recent vote for the (v3) network
- * status */
-static cached_dir_t *the_v3_networkstatus_vote = 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
@@ -1870,10 +1866,9 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
/** Return a new networkstatus_vote_t* containing our current opinion. (For v3
* authorities */
-/* XXXX020 possibly rename and relocate to dirvote.c? */
-static networkstatus_vote_t *
-generate_networkstatus_vote_obj(crypto_pk_env_t *private_key,
- authority_cert_t *cert)
+networkstatus_vote_t *
+dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key,
+ authority_cert_t *cert)
{
or_options_t *options = get_options();
networkstatus_vote_t *v3_out = NULL;
@@ -2029,224 +2024,11 @@ generate_networkstatus_vote_obj(crypto_pk_env_t *private_key,
return v3_out;
}
-/** Return a new string containing teh string representation of the vote in
- * <b>v3_ns</b>, signed with our v3 signing key <b>private_signing_key</b>.
- * For v3 authorities. */
-char *
-format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
- networkstatus_vote_t *v3_ns)
-{
-/** Longest status flag name that we generate. */
-#define LONGEST_STATUS_FLAG_NAME_LEN 9
-/** Maximum number of status flags we'll apply to one router. */
-#define N_STATUS_FLAGS 10
-/** Amount of space to allocate for each entry. (r line and s line.) */
-#define RS_ENTRY_LEN \
- ( /* first line */ \
- MAX_NICKNAME_LEN+BASE64_DIGEST_LEN*2+ISO_TIME_LEN+INET_NTOA_BUF_LEN+ \
- 5*2 /* ports */ + 10 /* punctuation */ + \
- /* second line */ \
- (LONGEST_STATUS_FLAG_NAME_LEN+1)*N_STATUS_FLAGS + 2)
-
- size_t len;
- char *status = NULL;
- const char *client_versions = NULL, *server_versions = NULL;
- char *outp, *endp;
- char fingerprint[FINGERPRINT_LEN+1];
- char ipaddr[INET_NTOA_BUF_LEN];
- char digest[DIGEST_LEN];
- struct in_addr in;
- uint32_t addr;
- routerlist_t *rl = router_get_routerlist();
- char *version_lines = NULL;
- networkstatus_voter_info_t *voter;
-
- tor_assert(private_signing_key);
-
- voter = smartlist_get(v3_ns->voters, 0);
-
- addr = voter->addr;
- in.s_addr = htonl(addr);
- tor_inet_ntoa(&in, ipaddr, sizeof(ipaddr));
-
- base16_encode(fingerprint, sizeof(fingerprint),
- v3_ns->cert->cache_info.identity_digest, DIGEST_LEN);
- client_versions = v3_ns->client_versions;
- server_versions = v3_ns->server_versions;
-
- if (client_versions || server_versions) {
- size_t v_len = 64;
- char *cp;
- if (client_versions)
- v_len += strlen(client_versions);
- if (client_versions)
- v_len += strlen(server_versions);
- version_lines = tor_malloc(v_len);
- cp = version_lines;
- if (client_versions) {
- tor_snprintf(cp, v_len-(cp-version_lines),
- "client-versions %s\n", client_versions);
- cp += strlen(cp);
- }
- if (server_versions)
- tor_snprintf(cp, v_len-(cp-version_lines),
- "server-versions %s\n", server_versions);
- } else {
- version_lines = tor_strdup("");
- }
-
- len = 8192;
- len += strlen(version_lines);
- len += (RS_ENTRY_LEN)*smartlist_len(rl->routers);
- len += v3_ns->cert->cache_info.signed_descriptor_len;
-
- status = tor_malloc(len);
- {
- char published[ISO_TIME_LEN+1];
- char va[ISO_TIME_LEN+1];
- char fu[ISO_TIME_LEN+1];
- char vu[ISO_TIME_LEN+1];
- char *flags = smartlist_join_strings(v3_ns->known_flags, " ", 0, NULL);
- authority_cert_t *cert = v3_ns->cert;
- format_iso_time(published, v3_ns->published);
- format_iso_time(va, v3_ns->valid_after);
- format_iso_time(fu, v3_ns->fresh_until);
- format_iso_time(vu, v3_ns->valid_until);
-
- tor_assert(cert);
- tor_snprintf(status, len,
- "network-status-version 3\n"
- "vote-status vote\n"
- "consensus-methods 1\n"
- "published %s\n"
- "valid-after %s\n"
- "fresh-until %s\n"
- "valid-until %s\n"
- "voting-delay %d %d\n"
- "%s" /* versions */
- "known-flags %s\n"
- "dir-source %s %s %s %s %d %d\n"
- "contact %s\n",
- published, va, fu, vu,
- v3_ns->vote_seconds, v3_ns->dist_seconds,
- version_lines,
- flags,
- voter->nickname, fingerprint, voter->address,
- ipaddr, voter->dir_port, voter->or_port, voter->contact);
-
- tor_free(flags);
- outp = status + strlen(status);
- endp = status + len;
- tor_assert(outp + cert->cache_info.signed_descriptor_len < endp);
- memcpy(outp, cert->cache_info.signed_descriptor_body,
- cert->cache_info.signed_descriptor_len);
-
- outp += cert->cache_info.signed_descriptor_len;
- }
-
- SMARTLIST_FOREACH(v3_ns->routerstatus_list, vote_routerstatus_t *, vrs,
- {
- if (routerstatus_format_entry(outp, endp-outp, &vrs->status,
- vrs->version, 0) < 0) {
- log_warn(LD_BUG, "Unable to print router status.");
- goto err;
- }
- outp += strlen(outp);
- });
-
- {
- char signing_key_fingerprint[FINGERPRINT_LEN+1];
- if (tor_snprintf(outp, endp-outp, "directory-signature ")<0) {
- log_warn(LD_BUG, "Unable to start signature line.");
- goto err;
- }
- outp += strlen(outp);
-
- if (crypto_pk_get_fingerprint(private_signing_key,
- signing_key_fingerprint, 0)<0) {
- log_warn(LD_BUG, "Unable to get fingerprint for signing key");
- goto err;
- }
- if (tor_snprintf(outp, endp-outp, "%s %s\n", fingerprint,
- signing_key_fingerprint)<0) {
- log_warn(LD_BUG, "Unable to end signature line.");
- goto err;
- }
- outp += strlen(outp);
- }
-
- if (router_get_networkstatus_v3_hash(status, digest)<0)
- goto err;
- note_crypto_pk_op(SIGN_DIR);
- if (router_append_dirobj_signature(outp,endp-outp,digest,
- private_signing_key)<0) {
- log_warn(LD_BUG, "Unable to sign networkstatus vote.");
- goto err;
- }
-
- {
- networkstatus_vote_t *v;
- if (!(v = networkstatus_parse_vote_from_string(status, NULL, 1))) {
- log_err(LD_BUG,"Generated a networkstatus vote we couldn't parse: "
- "<<%s>>", status);
- goto err;
- }
- networkstatus_vote_free(v);
- }
-
- goto done;
-
- err:
- tor_free(status);
- done:
- tor_free(version_lines);
- return status;
-}
-
-/** Replace the value of <b>the_v3_networkstatus_vote</b> with a
- * new vote, and return that value. Returns NULL on failure. */
-/* XXXX020 possibly rename and relocate to dirvote.c? */
-cached_dir_t *
-generate_v3_networkstatus(void)
-{
- crypto_pk_env_t *key = get_my_v3_authority_signing_key();
- authority_cert_t *cert = get_my_v3_authority_cert();
- networkstatus_vote_t *ns;
- char *status;
- time_t now = time(NULL);
-
- if (!cert || !key) {
- log_warn(LD_NET, "Didn't find key/certificate to generate v3 vote");
- return NULL;
- }
-
- if (!(ns = generate_networkstatus_vote_obj(key, cert)))
- return NULL;
-
- status = format_networkstatus_vote(key, ns);
- networkstatus_vote_free(ns);
- if (!status)
- return NULL;
-
- {
- cached_dir_t **ns_ptr =
- &the_v3_networkstatus_vote;
- if (*ns_ptr)
- cached_dir_decref(*ns_ptr);
- *ns_ptr = new_cached_dir(status, now);
- status = NULL; /* So it doesn't get double-freed. */
- }
-
- return the_v3_networkstatus_vote;
-}
-
-/** For v2 and v3 authoritative directories only: If <b>v2</b> is set, replace
- * the contents of <b>the_v2_networkstatus</b> with a newly generated network
- * status object. If <b>v2</b> is zero, replace the contents of
- * <b>the_v3_networkstatus_vote</b> with a newly generated consensus vote
- * object. */
+/** 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_networkstatus_opinion(int v2)
+generate_v2_networkstatus_opinion(void)
{
/** Longest status flag name that we generate. */
#define LONGEST_STATUS_FLAG_NAME_LEN 9
@@ -2285,9 +2067,6 @@ generate_networkstatus_opinion(int v2)
smartlist_t *routers = NULL;
digestmap_t *omit_as_sybil = NULL;
- if (!v2)
- return generate_v3_networkstatus();
-
private_key = get_identity_key();
if (resolve_my_address(LOG_WARN, options, &addr, &hostname)<0) {
@@ -2460,7 +2239,7 @@ dirserv_get_networkstatus_v2_fingerprints(smartlist_t *result,
cached_v2_networkstatus = digestmap_new();
if (should_generate_v2_networkstatus())
- generate_networkstatus_opinion(1);
+ generate_v2_networkstatus_opinion();
if (!strcmp(key,"authority")) {
if (authdir_mode_v2(get_options())) {
@@ -2515,7 +2294,7 @@ dirserv_get_networkstatus_v2(smartlist_t *result,
SMARTLIST_FOREACH(fingerprints, const char *, fp,
{
if (router_digest_is_me(fp) && should_generate_v2_networkstatus())
- generate_networkstatus_opinion(1);
+ generate_v2_networkstatus_opinion();
cached = digestmap_get(cached_v2_networkstatus, fp);
if (cached) {
smartlist_add(result, cached);
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 0a3088230..81b046f65 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -19,78 +19,193 @@ static int dirvote_add_signatures_to_pending_consensus(
static char *list_v3_auth_ids(void);
static void dirvote_fetch_missing_votes(void);
static void dirvote_fetch_missing_signatures(void);
-static void dirvote_perform_vote(void);
+static int dirvote_perform_vote(void);
static void dirvote_clear_votes(int all_votes);
static int dirvote_compute_consensus(void);
static int dirvote_publish_consensus(void);
/* =====
- * Voting and consensus generation
- * ===== */
+ * Voting
+ * =====*/
-/*XXXX020 move to networkstaus.c */
-/** Clear all storage held in <b>ns</b>. */
-void
-networkstatus_vote_free(networkstatus_vote_t *ns)
+/** Return a new string containing teh string representation of the vote in
+ * <b>v3_ns</b>, signed with our v3 signing key <b>private_signing_key</b>.
+ * For v3 authorities. */
+char *
+format_networkstatus_vote(crypto_pk_env_t *private_signing_key,
+ networkstatus_vote_t *v3_ns)
{
- if (!ns)
- return;
-
- tor_free(ns->client_versions);
- tor_free(ns->server_versions);
- if (ns->known_flags) {
- SMARTLIST_FOREACH(ns->known_flags, char *, c, tor_free(c));
- smartlist_free(ns->known_flags);
+/** Longest status flag name that we generate. */
+#define LONGEST_STATUS_FLAG_NAME_LEN 9
+/** Maximum number of status flags we'll apply to one router. */
+#define N_STATUS_FLAGS 10
+/** Amount of space to allocate for each entry. (r line and s line.) */
+#define RS_ENTRY_LEN \
+ ( /* first line */ \
+ MAX_NICKNAME_LEN+BASE64_DIGEST_LEN*2+ISO_TIME_LEN+INET_NTOA_BUF_LEN+ \
+ 5*2 /* ports */ + 10 /* punctuation */ + \
+ /* second line */ \
+ (LONGEST_STATUS_FLAG_NAME_LEN+1)*N_STATUS_FLAGS + 2)
+
+ size_t len;
+ char *status = NULL;
+ const char *client_versions = NULL, *server_versions = NULL;
+ char *outp, *endp;
+ char fingerprint[FINGERPRINT_LEN+1];
+ char ipaddr[INET_NTOA_BUF_LEN];
+ char digest[DIGEST_LEN];
+ struct in_addr in;
+ uint32_t addr;
+ routerlist_t *rl = router_get_routerlist();
+ char *version_lines = NULL;
+ networkstatus_voter_info_t *voter;
+
+ tor_assert(private_signing_key);
+
+ voter = smartlist_get(v3_ns->voters, 0);
+
+ addr = voter->addr;
+ in.s_addr = htonl(addr);
+ tor_inet_ntoa(&in, ipaddr, sizeof(ipaddr));
+
+ base16_encode(fingerprint, sizeof(fingerprint),
+ v3_ns->cert->cache_info.identity_digest, DIGEST_LEN);
+ client_versions = v3_ns->client_versions;
+ server_versions = v3_ns->server_versions;
+
+ if (client_versions || server_versions) {
+ size_t v_len = 64;
+ char *cp;
+ if (client_versions)
+ v_len += strlen(client_versions);
+ if (client_versions)
+ v_len += strlen(server_versions);
+ version_lines = tor_malloc(v_len);
+ cp = version_lines;
+ if (client_versions) {
+ tor_snprintf(cp, v_len-(cp-version_lines),
+ "client-versions %s\n", client_versions);
+ cp += strlen(cp);
+ }
+ if (server_versions)
+ tor_snprintf(cp, v_len-(cp-version_lines),
+ "server-versions %s\n", server_versions);
+ } else {
+ version_lines = tor_strdup("");
}
- if (ns->voters) {
- SMARTLIST_FOREACH(ns->voters, networkstatus_voter_info_t *, voter,
- {
- tor_free(voter->nickname);
- tor_free(voter->address);
- tor_free(voter->contact);
- });
- smartlist_free(ns->voters);
+
+ len = 8192;
+ len += strlen(version_lines);
+ len += (RS_ENTRY_LEN)*smartlist_len(rl->routers);
+ len += v3_ns->cert->cache_info.signed_descriptor_len;
+
+ status = tor_malloc(len);
+ {
+ char published[ISO_TIME_LEN+1];
+ char va[ISO_TIME_LEN+1];
+ char fu[ISO_TIME_LEN+1];
+ char vu[ISO_TIME_LEN+1];
+ char *flags = smartlist_join_strings(v3_ns->known_flags, " ", 0, NULL);
+ authority_cert_t *cert = v3_ns->cert;
+ format_iso_time(published, v3_ns->published);
+ format_iso_time(va, v3_ns->valid_after);
+ format_iso_time(fu, v3_ns->fresh_until);
+ format_iso_time(vu, v3_ns->valid_until);
+
+ tor_assert(cert);
+ tor_snprintf(status, len,
+ "network-status-version 3\n"
+ "vote-status vote\n"
+ "consensus-methods 1\n"
+ "published %s\n"
+ "valid-after %s\n"
+ "fresh-until %s\n"
+ "valid-until %s\n"
+ "voting-delay %d %d\n"
+ "%s" /* versions */
+ "known-flags %s\n"
+ "dir-source %s %s %s %s %d %d\n"
+ "contact %s\n",
+ published, va, fu, vu,
+ v3_ns->vote_seconds, v3_ns->dist_seconds,
+ version_lines,
+ flags,
+ voter->nickname, fingerprint, voter->address,
+ ipaddr, voter->dir_port, voter->or_port, voter->contact);
+
+ tor_free(flags);
+ outp = status + strlen(status);
+ endp = status + len;
+ tor_assert(outp + cert->cache_info.signed_descriptor_len < endp);
+ memcpy(outp, cert->cache_info.signed_descriptor_body,
+ cert->cache_info.signed_descriptor_len);
+
+ outp += cert->cache_info.signed_descriptor_len;
}
- if (ns->cert)
- authority_cert_free(ns->cert);
- if (ns->routerstatus_list) {
- if (ns->is_vote) {
- SMARTLIST_FOREACH(ns->routerstatus_list, vote_routerstatus_t *, rs,
- {
- tor_free(rs->version);
- tor_free(rs);
- });
- } else {
- SMARTLIST_FOREACH(ns->routerstatus_list, routerstatus_t *, rs,
- tor_free(rs));
+ SMARTLIST_FOREACH(v3_ns->routerstatus_list, vote_routerstatus_t *, vrs,
+ {
+ if (routerstatus_format_entry(outp, endp-outp, &vrs->status,
+ vrs->version, 0) < 0) {
+ log_warn(LD_BUG, "Unable to print router status.");
+ goto err;
}
+ outp += strlen(outp);
+ });
+
+ {
+ char signing_key_fingerprint[FINGERPRINT_LEN+1];
+ if (tor_snprintf(outp, endp-outp, "directory-signature ")<0) {
+ log_warn(LD_BUG, "Unable to start signature line.");
+ goto err;
+ }
+ outp += strlen(outp);
- smartlist_free(ns->routerstatus_list);
+ if (crypto_pk_get_fingerprint(private_signing_key,
+ signing_key_fingerprint, 0)<0) {
+ log_warn(LD_BUG, "Unable to get fingerprint for signing key");
+ goto err;
+ }
+ if (tor_snprintf(outp, endp-outp, "%s %s\n", fingerprint,
+ signing_key_fingerprint)<0) {
+ log_warn(LD_BUG, "Unable to end signature line.");
+ goto err;
+ }
+ outp += strlen(outp);
}
- if (ns->desc_digest_map)
- digestmap_free(ns->desc_digest_map, NULL);
- memset(ns, 11, sizeof(*ns));
- tor_free(ns);
-}
+ if (router_get_networkstatus_v3_hash(status, digest)<0)
+ goto err;
+ note_crypto_pk_op(SIGN_DIR);
+ if (router_append_dirobj_signature(outp,endp-outp,digest,
+ private_signing_key)<0) {
+ log_warn(LD_BUG, "Unable to sign networkstatus vote.");
+ goto err;
+ }
-/*XXXX020 move to networkstaus.c */
-/** Return the voter info from <b>vote</b> for the voter whose identity digest
- * is <b>identity</b>, or NULL if no such voter is associated with
- * <b>vote</b>. */
-networkstatus_voter_info_t *
-networkstatus_get_voter_by_id(networkstatus_vote_t *vote,
- const char *identity)
-{
- if (!vote || !vote->voters)
- return NULL;
- SMARTLIST_FOREACH(vote->voters, networkstatus_voter_info_t *, voter,
- if (!memcmp(voter->identity_digest, identity, DIGEST_LEN))
- return voter);
- return NULL;
+ {
+ networkstatus_vote_t *v;
+ if (!(v = networkstatus_parse_vote_from_string(status, NULL, 1))) {
+ log_err(LD_BUG,"Generated a networkstatus vote we couldn't parse: "
+ "<<%s>>", status);
+ goto err;
+ }
+ networkstatus_vote_free(v);
+ }
+
+ goto done;
+
+ err:
+ tor_free(status);
+ done:
+ tor_free(version_lines);
+ return status;
}
+/* =====
+ * Consensus generation
+ * ===== */
+
/** Given a vote <b>vote</b> (not a consensus!), return its associated
* networkstatus_voter_info_t.*/
static networkstatus_voter_info_t *
@@ -818,155 +933,6 @@ networkstatus_compute_consensus(smartlist_t *votes,
return result;
}
-/*XXXX020 move to networkstatus.c ? */
-/** Check whether the signature on <b>voter</b> is correctly signed by
- * the signing key of <b>cert</b>. Return -1 if <b>cert</b> doesn't match the
- * signing key; otherwise set the good_signature or bad_signature flag on
- * <b>voter</b>, and return 0. */
-/* (private; exposed for testing.) */
-int
-networkstatus_check_voter_signature(networkstatus_vote_t *consensus,
- networkstatus_voter_info_t *voter,
- authority_cert_t *cert)
-{
- char d[DIGEST_LEN];
- char *signed_digest;
- size_t signed_digest_len;
- if (crypto_pk_get_digest(cert->signing_key, d)<0)
- return -1;
- if (memcmp(voter->signing_key_digest, d, DIGEST_LEN))
- return -1;
- signed_digest_len = crypto_pk_keysize(cert->signing_key);
- signed_digest = tor_malloc(signed_digest_len);
- if (crypto_pk_public_checksig(cert->signing_key,
- signed_digest,
- voter->signature,
- voter->signature_len) != DIGEST_LEN ||
- memcmp(signed_digest, consensus->networkstatus_digest, DIGEST_LEN)) {
- log_warn(LD_DIR, "Got a bad signature on a networkstatus vote");
- voter->bad_signature = 1;
- } else {
- voter->good_signature = 1;
- }
- return 0;
-}
-
-/*XXXX020 move to networkstatus.c ? */
-/** 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_vote_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(severity, 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(severity, 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;
-}
-
/** Given a consensus vote <b>target</b> and a set of detached signatures in
* <b>sigs</b> that correspond to the same consensus, check whether there are
* any new signatures in <b>src_voter_list</b> that should be added to
@@ -1127,23 +1093,7 @@ ns_detached_signatures_free(ns_detached_signatures_t *s)
* Certificate functions
* ===== */
-/*XXXX020 move to routerlist.c ? */
-/** Free storage held in <b>cert</b>. */
-void
-authority_cert_free(authority_cert_t *cert)
-{
- if (!cert)
- return;
-
- tor_free(cert->cache_info.signed_descriptor_body);
- if (cert->signing_key)
- crypto_free_pk_env(cert->signing_key);
- if (cert->identity_key)
- crypto_free_pk_env(cert->identity_key);
-
- tor_free(cert);
-}
-
+/*XXXX020 make this static? */
/** Allocate and return a new authority_cert_t with the same contents as
* <b>cert</b>. */
authority_cert_t *
@@ -1376,21 +1326,36 @@ static smartlist_t *pending_consensus_signature_list = NULL;
/** Generate a networkstatus vote and post it to all the v3 authorities.
* (V3 Authority only) */
-static void
+static int
dirvote_perform_vote(void)
{
- cached_dir_t *new_vote = generate_v3_networkstatus();
+ crypto_pk_env_t *key = get_my_v3_authority_signing_key();
+ authority_cert_t *cert = get_my_v3_authority_cert();
+ networkstatus_vote_t *ns;
+ char *contents;
pending_vote_t *pending_vote;
+
int status;
const char *msg = "";
- if (!new_vote)
- return;
+ if (!cert || !key) {
+ log_warn(LD_NET, "Didn't find key/certificate to generate v3 vote");
+ return -1;
+ }
+ if (!(ns = dirserv_generate_networkstatus_vote_obj(key, cert)))
+ return -1;
+
+ contents = format_networkstatus_vote(key, ns);
+ networkstatus_vote_free(ns);
+ if (!contents)
+ return -1;
- if (!(pending_vote = dirvote_add_vote(new_vote->dir, &msg, &status))) {
+ pending_vote = dirvote_add_vote(contents, &msg, &status);
+ tor_free(contents);
+ if (!pending_vote) {
log_warn(LD_DIR, "Couldn't store my own vote! (I told myself, '%s'.)",
msg);
- return;
+ return -1;
}
directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_VOTE,
@@ -1399,6 +1364,7 @@ dirvote_perform_vote(void)
pending_vote->vote_body->dir,
pending_vote->vote_body->dir_len, 0);
log_notice(LD_DIR, "Vote posted.");
+ return 0;
}
/** Send an HTTP request to every other v3 authority, for the votes of every
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index a9efd8d92..657895915 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -210,6 +210,214 @@ networkstatus_v2_free(networkstatus_v2_t *ns)
tor_free(ns);
}
+/** Clear all storage held in <b>ns</b>. */
+void
+networkstatus_vote_free(networkstatus_vote_t *ns)
+{
+ if (!ns)
+ return;
+
+ tor_free(ns->client_versions);
+ tor_free(ns->server_versions);
+ if (ns->known_flags) {
+ SMARTLIST_FOREACH(ns->known_flags, char *, c, tor_free(c));
+ smartlist_free(ns->known_flags);
+ }
+ if (ns->voters) {
+ SMARTLIST_FOREACH(ns->voters, networkstatus_voter_info_t *, voter,
+ {
+ tor_free(voter->nickname);
+ tor_free(voter->address);
+ tor_free(voter->contact);
+ });
+ smartlist_free(ns->voters);
+ }
+ if (ns->cert)
+ authority_cert_free(ns->cert);
+
+ if (ns->routerstatus_list) {
+ if (ns->is_vote) {
+ SMARTLIST_FOREACH(ns->routerstatus_list, vote_routerstatus_t *, rs,
+ {
+ tor_free(rs->version);
+ tor_free(rs);
+ });
+ } else {
+ SMARTLIST_FOREACH(ns->routerstatus_list, routerstatus_t *, rs,
+ tor_free(rs));
+ }
+
+ smartlist_free(ns->routerstatus_list);
+ }
+ if (ns->desc_digest_map)
+ digestmap_free(ns->desc_digest_map, NULL);
+
+ memset(ns, 11, sizeof(*ns));
+ tor_free(ns);
+}
+
+/** Return the voter info from <b>vote</b> for the voter whose identity digest
+ * is <b>identity</b>, or NULL if no such voter is associated with
+ * <b>vote</b>. */
+networkstatus_voter_info_t *
+networkstatus_get_voter_by_id(networkstatus_vote_t *vote,
+ const char *identity)
+{
+ if (!vote || !vote->voters)
+ return NULL;
+ SMARTLIST_FOREACH(vote->voters, networkstatus_voter_info_t *, voter,
+ if (!memcmp(voter->identity_digest, identity, DIGEST_LEN))
+ return voter);
+ return NULL;
+}
+
+/** Check whether the signature on <b>voter</b> is correctly signed by
+ * the signing key of <b>cert</b>. Return -1 if <b>cert</b> doesn't match the
+ * signing key; otherwise set the good_signature or bad_signature flag on
+ * <b>voter</b>, and return 0. */
+/* (private; exposed for testing.) */
+int
+networkstatus_check_voter_signature(networkstatus_vote_t *consensus,
+ networkstatus_voter_info_t *voter,
+ authority_cert_t *cert)
+{
+ char d[DIGEST_LEN];
+ char *signed_digest;
+ size_t signed_digest_len;
+ if (crypto_pk_get_digest(cert->signing_key, d)<0)
+ return -1;
+ if (memcmp(voter->signing_key_digest, d, DIGEST_LEN))
+ return -1;
+ signed_digest_len = crypto_pk_keysize(cert->signing_key);
+ signed_digest = tor_malloc(signed_digest_len);
+ if (crypto_pk_public_checksig(cert->signing_key,
+ signed_digest,
+ voter->signature,
+ voter->signature_len) != DIGEST_LEN ||
+ memcmp(signed_digest, consensus->networkstatus_digest, DIGEST_LEN)) {
+ log_warn(LD_DIR, "Got a bad signature on a networkstatus vote");
+ voter->bad_signature = 1;
+ } else {
+ voter->good_signature = 1;
+ }
+ 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_vote_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(severity, 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(severity, 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 *
diff --git a/src/or/or.h b/src/or/or.h
index 677c30a39..d50e78c1a 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2898,14 +2898,6 @@ void dirserv_free_all(void);
void cached_dir_decref(cached_dir_t *d);
cached_dir_t *new_cached_dir(char *s, time_t published);
-cached_dir_t *generate_v3_networkstatus(void);
-
-#ifdef DIRSERV_PRIVATE
-char *
-format_networkstatus_vote(crypto_pk_env_t *private_key,
- networkstatus_vote_t *v3_ns);
-#endif
-
/********************************* dirvote.c ************************/
/** Lowest allowable value for VoteSeconds. */
@@ -2918,16 +2910,10 @@ format_networkstatus_vote(crypto_pk_env_t *private_key,
void dirvote_free_all(void);
/* vote manipulation */
-void networkstatus_vote_free(networkstatus_vote_t *ns);
char *networkstatus_compute_consensus(smartlist_t *votes,
int total_authorities,
crypto_pk_env_t *identity_key,
crypto_pk_env_t *signing_key);
-networkstatus_voter_info_t *networkstatus_get_voter_by_id(
- networkstatus_vote_t *vote,
- const char *identity);
-int networkstatus_check_consensus_signature(networkstatus_vote_t *consensus,
- int warn);
int networkstatus_add_detached_signatures(networkstatus_vote_t *target,
ns_detached_signatures_t *sigs,
const char **msg_out);
@@ -2935,7 +2921,6 @@ char *networkstatus_get_detached_signatures(networkstatus_vote_t *consensus);
void ns_detached_signatures_free(ns_detached_signatures_t *s);
/* cert manipulation */
-void authority_cert_free(authority_cert_t *cert);
authority_cert_t *authority_cert_dup(authority_cert_t *cert);
/** Describes the schedule by which votes should be generated. */
@@ -2965,11 +2950,14 @@ const char *dirvote_get_pending_detached_signatures(void);
#define DGV_INCLUDE_PENDING 2
#define DGV_INCLUDE_PREVIOUS 4
const cached_dir_t *dirvote_get_vote(const char *fp, int flags);
+networkstatus_vote_t *
+dirserv_generate_networkstatus_vote_obj(crypto_pk_env_t *private_key,
+ authority_cert_t *cert);
#ifdef DIRVOTE_PRIVATE
-int networkstatus_check_voter_signature(networkstatus_vote_t *consensus,
- networkstatus_voter_info_t *voter,
- authority_cert_t *cert);
+char *
+format_networkstatus_vote(crypto_pk_env_t *private_key,
+ networkstatus_vote_t *v3_ns);
#endif
/********************************* dns.c ***************************/
@@ -3084,6 +3072,15 @@ int router_reload_v2_networkstatus(void);
int router_reload_consensus_networkstatus(void);
void routerstatus_free(routerstatus_t *rs);
void networkstatus_v2_free(networkstatus_v2_t *ns);
+void networkstatus_vote_free(networkstatus_vote_t *ns);
+networkstatus_voter_info_t *networkstatus_get_voter_by_id(
+ networkstatus_vote_t *vote,
+ const char *identity);
+int networkstatus_check_consensus_signature(networkstatus_vote_t *consensus,
+ int warn);
+int networkstatus_check_voter_signature(networkstatus_vote_t *consensus,
+ networkstatus_voter_info_t *voter,
+ authority_cert_t *cert);
char *networkstatus_get_cache_filename(const char *identity_digest);
int router_set_networkstatus_v2(const char *s, time_t arrived_at,
networkstatus_source_t source,
@@ -3639,6 +3636,7 @@ void add_trusted_dir_server(const char *nickname, const char *address,
uint16_t dir_port, uint16_t or_port,
const char *digest, const char *v3_auth_digest,
authority_type_t type);
+void authority_cert_free(authority_cert_t *cert);
void clear_trusted_dir_servers(void);
int any_trusted_dir_is_v1_authority(void);
void update_router_descriptor_downloads(time_t now);
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index b62a48f04..95e63df3a 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -3300,6 +3300,22 @@ add_trusted_dir_server(const char *nickname, const char *address,
router_dir_info_changed();
}
+/** Free storage held in <b>cert</b>. */
+void
+authority_cert_free(authority_cert_t *cert)
+{
+ if (!cert)
+ return;
+
+ tor_free(cert->cache_info.signed_descriptor_body);
+ if (cert->signing_key)
+ crypto_free_pk_env(cert->signing_key);
+ if (cert->identity_key)
+ crypto_free_pk_env(cert->identity_key);
+
+ tor_free(cert);
+}
+
/** Free storage held in <b>ds</b>. */
static void
trusted_dir_server_free(trusted_dir_server_t *ds)