LCOV - code coverage report
Current view: top level - feature/dirauth - dirvote.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 1636 2376 68.9 %
Date: 2021-11-24 03:28:48 Functions: 59 72 81.9 %

          Line data    Source code
       1             : /* Copyright (c) 2001-2004, Roger Dingledine.
       2             :  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
       3             :  * Copyright (c) 2007-2021, The Tor Project, Inc. */
       4             : /* See LICENSE for licensing information */
       5             : 
       6             : #define DIRVOTE_PRIVATE
       7             : 
       8             : #include "core/or/or.h"
       9             : #include "app/config/config.h"
      10             : #include "app/config/resolve_addr.h"
      11             : #include "core/or/policies.h"
      12             : #include "core/or/protover.h"
      13             : #include "core/or/tor_version_st.h"
      14             : #include "core/or/versions.h"
      15             : #include "feature/dirauth/bwauth.h"
      16             : #include "feature/dirauth/dircollate.h"
      17             : #include "feature/dirauth/dsigs_parse.h"
      18             : #include "feature/dirauth/guardfraction.h"
      19             : #include "feature/dirauth/recommend_pkg.h"
      20             : #include "feature/dirauth/voteflags.h"
      21             : #include "feature/dircache/dirserv.h"
      22             : #include "feature/dirclient/dirclient.h"
      23             : #include "feature/dircommon/directory.h"
      24             : #include "feature/dirparse/microdesc_parse.h"
      25             : #include "feature/dirparse/ns_parse.h"
      26             : #include "feature/dirparse/parsecommon.h"
      27             : #include "feature/dirparse/signing.h"
      28             : #include "feature/nodelist/authcert.h"
      29             : #include "feature/nodelist/dirlist.h"
      30             : #include "feature/nodelist/fmt_routerstatus.h"
      31             : #include "feature/nodelist/microdesc.h"
      32             : #include "feature/nodelist/networkstatus.h"
      33             : #include "feature/nodelist/nodefamily.h"
      34             : #include "feature/nodelist/nodelist.h"
      35             : #include "feature/nodelist/routerlist.h"
      36             : #include "feature/relay/router.h"
      37             : #include "feature/relay/routerkeys.h"
      38             : #include "feature/stats/rephist.h"
      39             : #include "feature/client/entrynodes.h" /* needed for guardfraction methods */
      40             : #include "feature/nodelist/torcert.h"
      41             : #include "feature/dirauth/voting_schedule.h"
      42             : 
      43             : #include "feature/dirauth/dirvote.h"
      44             : #include "feature/dirauth/authmode.h"
      45             : #include "feature/dirauth/shared_random_state.h"
      46             : #include "feature/dirauth/dirauth_sys.h"
      47             : 
      48             : #include "feature/nodelist/authority_cert_st.h"
      49             : #include "feature/dircache/cached_dir_st.h"
      50             : #include "feature/dirclient/dir_server_st.h"
      51             : #include "feature/dirauth/dirauth_options_st.h"
      52             : #include "feature/nodelist/document_signature_st.h"
      53             : #include "feature/nodelist/microdesc_st.h"
      54             : #include "feature/nodelist/networkstatus_st.h"
      55             : #include "feature/nodelist/networkstatus_voter_info_st.h"
      56             : #include "feature/nodelist/node_st.h"
      57             : #include "feature/dirauth/ns_detached_signatures_st.h"
      58             : #include "feature/nodelist/routerinfo_st.h"
      59             : #include "feature/nodelist/routerlist_st.h"
      60             : #include "feature/dirauth/vote_microdesc_hash_st.h"
      61             : #include "feature/nodelist/vote_routerstatus_st.h"
      62             : #include "feature/dircommon/vote_timing_st.h"
      63             : 
      64             : #include "lib/container/order.h"
      65             : #include "lib/encoding/confline.h"
      66             : #include "lib/crypt_ops/crypto_format.h"
      67             : 
      68             : /* Algorithm to use for the bandwidth file digest. */
      69             : #define DIGEST_ALG_BW_FILE DIGEST_SHA256
      70             : 
      71             : /**
      72             :  * \file dirvote.c
      73             :  * \brief Functions to compute directory consensus, and schedule voting.
      74             :  *
      75             :  * This module is the center of the consensus-voting based directory
      76             :  * authority system.  With this system, a set of authorities first
      77             :  * publish vote based on their opinions of the network, and then compute
      78             :  * a consensus from those votes.  Each authority signs the consensus,
      79             :  * and clients trust the consensus if enough known authorities have
      80             :  * signed it.
      81             :  *
      82             :  * The code in this module is only invoked on directory authorities.  It's
      83             :  * responsible for:
      84             :  *
      85             :  * <ul>
      86             :  *   <li>Generating this authority's vote networkstatus, based on the
      87             :  *       authority's view of the network as represented in dirserv.c
      88             :  *   <li>Formatting the vote networkstatus objects.
      89             :  *   <li>Generating the microdescriptors that correspond to our own
      90             :  *       vote.
      91             :  *   <li>Sending votes to all the other authorities.
      92             :  *   <li>Trying to fetch missing votes from other authorities.
      93             :  *   <li>Computing the consensus from a set of votes, as well as
      94             :  *       a "detached signature" object for other authorities to fetch.
      95             :  *   <li>Collecting other authorities' signatures on the same consensus,
      96             :  *       until there are enough.
      97             :  *   <li>Publishing the consensus to the reset of the directory system.
      98             :  *   <li>Scheduling all of the above operations.
      99             :  * </ul>
     100             :  *
     101             :  * The main entry points are in dirvote_act(), which handles scheduled
     102             :  * actions; and dirvote_add_vote() and dirvote_add_signatures(), which
     103             :  * handle uploaded and downloaded votes and signatures.
     104             :  *
     105             :  * (See dir-spec.txt from torspec.git for a complete specification of
     106             :  * the directory protocol and voting algorithms.)
     107             :  **/
     108             : 
     109             : /** A consensus that we have built and are appending signatures to.  Once it's
     110             :  * time to publish it, it will become an active consensus if it accumulates
     111             :  * enough signatures. */
     112             : typedef struct pending_consensus_t {
     113             :   /** The body of the consensus that we're currently building.  Once we
     114             :    * have it built, it goes into dirserv.c */
     115             :   char *body;
     116             :   /** The parsed in-progress consensus document. */
     117             :   networkstatus_t *consensus;
     118             : } pending_consensus_t;
     119             : 
     120             : /* DOCDOC dirvote_add_signatures_to_all_pending_consensuses */
     121             : static int dirvote_add_signatures_to_all_pending_consensuses(
     122             :                        const char *detached_signatures_body,
     123             :                        const char *source,
     124             :                        const char **msg_out);
     125             : static int dirvote_add_signatures_to_pending_consensus(
     126             :                        pending_consensus_t *pc,
     127             :                        ns_detached_signatures_t *sigs,
     128             :                        const char *source,
     129             :                        int severity,
     130             :                        const char **msg_out);
     131             : static char *list_v3_auth_ids(void);
     132             : static void dirvote_fetch_missing_votes(void);
     133             : static void dirvote_fetch_missing_signatures(void);
     134             : static int dirvote_perform_vote(void);
     135             : static void dirvote_clear_votes(int all_votes);
     136             : static int dirvote_compute_consensuses(void);
     137             : static int dirvote_publish_consensus(void);
     138             : 
     139             : /* =====
     140             :  * Certificate functions
     141             :  * ===== */
     142             : 
     143             : /** Allocate and return a new authority_cert_t with the same contents as
     144             :  * <b>cert</b>. */
     145             : STATIC authority_cert_t *
     146          27 : authority_cert_dup(authority_cert_t *cert)
     147             : {
     148          27 :   authority_cert_t *out = tor_malloc(sizeof(authority_cert_t));
     149          27 :   tor_assert(cert);
     150             : 
     151          27 :   memcpy(out, cert, sizeof(authority_cert_t));
     152             :   /* Now copy pointed-to things. */
     153          54 :   out->cache_info.signed_descriptor_body =
     154          27 :     tor_strndup(cert->cache_info.signed_descriptor_body,
     155             :                 cert->cache_info.signed_descriptor_len);
     156          27 :   out->cache_info.saved_location = SAVED_NOWHERE;
     157          27 :   out->identity_key = crypto_pk_dup_key(cert->identity_key);
     158          27 :   out->signing_key = crypto_pk_dup_key(cert->signing_key);
     159             : 
     160          27 :   return out;
     161             : }
     162             : 
     163             : /* =====
     164             :  * Voting
     165             :  * =====*/
     166             : 
     167             : /* If <b>opt_value</b> is non-NULL, return "keyword opt_value\n" in a new
     168             :  * string. Otherwise return a new empty string. */
     169             : static char *
     170         162 : format_line_if_present(const char *keyword, const char *opt_value)
     171             : {
     172         162 :   if (opt_value) {
     173          36 :     char *result = NULL;
     174          36 :     tor_asprintf(&result, "%s %s\n", keyword, opt_value);
     175          36 :     return result;
     176             :   } else {
     177         126 :     return tor_strdup("");
     178             :   }
     179             : }
     180             : 
     181             : /** Format the recommended/required-relay-client protocols lines for a vote in
     182             :  * a newly allocated string, and return that string. */
     183             : static char *
     184          27 : format_protocols_lines_for_vote(const networkstatus_t *v3_ns)
     185             : {
     186          27 :   char *recommended_relay_protocols_line = NULL;
     187          27 :   char *recommended_client_protocols_line = NULL;
     188          27 :   char *required_relay_protocols_line = NULL;
     189          27 :   char *required_client_protocols_line = NULL;
     190             : 
     191          54 :   recommended_relay_protocols_line =
     192          27 :     format_line_if_present("recommended-relay-protocols",
     193          27 :                            v3_ns->recommended_relay_protocols);
     194          54 :   recommended_client_protocols_line =
     195          27 :     format_line_if_present("recommended-client-protocols",
     196          27 :                            v3_ns->recommended_client_protocols);
     197          54 :   required_relay_protocols_line =
     198          27 :     format_line_if_present("required-relay-protocols",
     199          27 :                            v3_ns->required_relay_protocols);
     200          54 :   required_client_protocols_line =
     201          27 :     format_line_if_present("required-client-protocols",
     202          27 :                            v3_ns->required_client_protocols);
     203             : 
     204          27 :   char *result = NULL;
     205          27 :   tor_asprintf(&result, "%s%s%s%s",
     206             :                recommended_relay_protocols_line,
     207             :                recommended_client_protocols_line,
     208             :                required_relay_protocols_line,
     209             :                required_client_protocols_line);
     210             : 
     211          27 :   tor_free(recommended_relay_protocols_line);
     212          27 :   tor_free(recommended_client_protocols_line);
     213          27 :   tor_free(required_relay_protocols_line);
     214          27 :   tor_free(required_client_protocols_line);
     215             : 
     216          27 :   return result;
     217             : }
     218             : 
     219             : /** Return a new string containing the string representation of the vote in
     220             :  * <b>v3_ns</b>, signed with our v3 signing key <b>private_signing_key</b>.
     221             :  * For v3 authorities. */
     222             : STATIC char *
     223          27 : format_networkstatus_vote(crypto_pk_t *private_signing_key,
     224             :                           networkstatus_t *v3_ns)
     225             : {
     226          27 :   smartlist_t *chunks = smartlist_new();
     227          27 :   char fingerprint[FINGERPRINT_LEN+1];
     228          27 :   char digest[DIGEST_LEN];
     229          27 :   char *protocols_lines = NULL;
     230          27 :   char *client_versions_line = NULL, *server_versions_line = NULL;
     231          27 :   char *shared_random_vote_str = NULL;
     232          27 :   networkstatus_voter_info_t *voter;
     233          27 :   char *status = NULL;
     234             : 
     235          27 :   tor_assert(private_signing_key);
     236          27 :   tor_assert(v3_ns->type == NS_TYPE_VOTE || v3_ns->type == NS_TYPE_OPINION);
     237             : 
     238          27 :   voter = smartlist_get(v3_ns->voters, 0);
     239             : 
     240          27 :   base16_encode(fingerprint, sizeof(fingerprint),
     241          27 :                 v3_ns->cert->cache_info.identity_digest, DIGEST_LEN);
     242             : 
     243          54 :   client_versions_line = format_line_if_present("client-versions",
     244          27 :                                                 v3_ns->client_versions);
     245          54 :   server_versions_line = format_line_if_present("server-versions",
     246          27 :                                                 v3_ns->server_versions);
     247          27 :   protocols_lines = format_protocols_lines_for_vote(v3_ns);
     248             : 
     249             :     /* Get shared random commitments/reveals line(s). */
     250          27 :   shared_random_vote_str = sr_get_string_for_vote();
     251             : 
     252             :   {
     253          27 :     char published[ISO_TIME_LEN+1];
     254          27 :     char va[ISO_TIME_LEN+1];
     255          27 :     char fu[ISO_TIME_LEN+1];
     256          27 :     char vu[ISO_TIME_LEN+1];
     257          27 :     char *flags = smartlist_join_strings(v3_ns->known_flags, " ", 0, NULL);
     258             :     /* XXXX Abstraction violation: should be pulling a field out of v3_ns.*/
     259          27 :     char *flag_thresholds = dirserv_get_flag_thresholds_line();
     260          27 :     char *params;
     261          27 :     char *bw_headers_line = NULL;
     262          27 :     char *bw_file_digest = NULL;
     263          27 :     authority_cert_t *cert = v3_ns->cert;
     264          54 :     char *methods =
     265          27 :       make_consensus_method_list(MIN_SUPPORTED_CONSENSUS_METHOD,
     266             :                                  MAX_SUPPORTED_CONSENSUS_METHOD, " ");
     267          27 :     format_iso_time(published, v3_ns->published);
     268          27 :     format_iso_time(va, v3_ns->valid_after);
     269          27 :     format_iso_time(fu, v3_ns->fresh_until);
     270          27 :     format_iso_time(vu, v3_ns->valid_until);
     271             : 
     272          27 :     if (v3_ns->net_params)
     273          27 :       params = smartlist_join_strings(v3_ns->net_params, " ", 0, NULL);
     274             :     else
     275           0 :       params = tor_strdup("");
     276          27 :     tor_assert(cert);
     277             : 
     278             :     /* v3_ns->bw_file_headers is only set when V3BandwidthsFile is
     279             :      * configured */
     280          27 :     if (v3_ns->bw_file_headers) {
     281           0 :       char *bw_file_headers = NULL;
     282             :       /* If there are too many headers, leave the header string NULL */
     283           0 :       if (! BUG(smartlist_len(v3_ns->bw_file_headers)
     284             :                 > MAX_BW_FILE_HEADER_COUNT_IN_VOTE)) {
     285           0 :         bw_file_headers = smartlist_join_strings(v3_ns->bw_file_headers, " ",
     286             :                                                  0, NULL);
     287           0 :         if (BUG(strlen(bw_file_headers) > MAX_BW_FILE_HEADERS_LINE_LEN)) {
     288             :           /* Free and set to NULL, because the line was too long */
     289           0 :           tor_free(bw_file_headers);
     290             :         }
     291             :       }
     292           0 :       if (!bw_file_headers) {
     293             :           /* If parsing failed, add a bandwidth header line with no entries */
     294           0 :           bw_file_headers = tor_strdup("");
     295             :       }
     296             :       /* At this point, the line will always be present */
     297           0 :       bw_headers_line = format_line_if_present("bandwidth-file-headers",
     298             :                                                bw_file_headers);
     299           0 :       tor_free(bw_file_headers);
     300             :     }
     301             : 
     302             :     /* Create bandwidth-file-digest if applicable.
     303             :      * v3_ns->b64_digest_bw_file will contain the digest when V3BandwidthsFile
     304             :      * is configured and the bandwidth file could be read, even if it was not
     305             :      * parseable.
     306             :      */
     307          27 :     if (!tor_digest256_is_zero((const char *)v3_ns->bw_file_digest256)) {
     308             :       /* Encode the digest. */
     309           0 :       char b64_digest_bw_file[BASE64_DIGEST256_LEN+1] = {0};
     310           0 :       digest256_to_base64(b64_digest_bw_file,
     311             :                           (const char *)v3_ns->bw_file_digest256);
     312             :       /* "bandwidth-file-digest" 1*(SP algorithm "=" digest) NL */
     313           0 :       char *digest_algo_b64_digest_bw_file = NULL;
     314           0 :       tor_asprintf(&digest_algo_b64_digest_bw_file, "%s=%s",
     315             :                    crypto_digest_algorithm_get_name(DIGEST_ALG_BW_FILE),
     316             :                    b64_digest_bw_file);
     317             :       /* No need for tor_strdup(""), format_line_if_present does it. */
     318           0 :       bw_file_digest = format_line_if_present(
     319             :           "bandwidth-file-digest", digest_algo_b64_digest_bw_file);
     320           0 :       tor_free(digest_algo_b64_digest_bw_file);
     321             :     }
     322             : 
     323          27 :     const char *ip_str = fmt_addr(&voter->ipv4_addr);
     324             : 
     325          27 :     if (ip_str[0]) {
     326          81 :       smartlist_add_asprintf(chunks,
     327             :                    "network-status-version 3\n"
     328             :                    "vote-status %s\n"
     329             :                    "consensus-methods %s\n"
     330             :                    "published %s\n"
     331             :                    "valid-after %s\n"
     332             :                    "fresh-until %s\n"
     333             :                    "valid-until %s\n"
     334             :                    "voting-delay %d %d\n"
     335             :                    "%s%s" /* versions */
     336             :                    "%s" /* protocols */
     337             :                    "known-flags %s\n"
     338             :                    "flag-thresholds %s\n"
     339             :                    "params %s\n"
     340             :                    "%s" /* bandwidth file headers */
     341             :                    "%s" /* bandwidth file digest */
     342             :                    "dir-source %s %s %s %s %d %d\n"
     343             :                    "contact %s\n"
     344             :                    "%s" /* shared randomness information */
     345             :                    ,
     346          27 :                    v3_ns->type == NS_TYPE_VOTE ? "vote" : "opinion",
     347             :                    methods,
     348             :                    published, va, fu, vu,
     349             :                    v3_ns->vote_seconds, v3_ns->dist_seconds,
     350             :                    client_versions_line,
     351             :                    server_versions_line,
     352             :                    protocols_lines,
     353             :                    flags,
     354             :                    flag_thresholds,
     355             :                    params,
     356             :                    bw_headers_line ? bw_headers_line : "",
     357             :                    bw_file_digest ? bw_file_digest: "",
     358             :                    voter->nickname, fingerprint, voter->address,
     359          27 :                    ip_str, voter->ipv4_dirport, voter->ipv4_orport,
     360             :                    voter->contact,
     361             :                    shared_random_vote_str ?
     362             :                              shared_random_vote_str : "");
     363             :     }
     364             : 
     365          27 :     tor_free(params);
     366          27 :     tor_free(flags);
     367          27 :     tor_free(flag_thresholds);
     368          27 :     tor_free(methods);
     369          27 :     tor_free(shared_random_vote_str);
     370          27 :     tor_free(bw_headers_line);
     371          27 :     tor_free(bw_file_digest);
     372             : 
     373          27 :     if (ip_str[0] == '\0')
     374           0 :       goto err;
     375             : 
     376          27 :     if (!tor_digest_is_zero(voter->legacy_id_digest)) {
     377           9 :       char fpbuf[HEX_DIGEST_LEN+1];
     378           9 :       base16_encode(fpbuf, sizeof(fpbuf), voter->legacy_id_digest, DIGEST_LEN);
     379           9 :       smartlist_add_asprintf(chunks, "legacy-dir-key %s\n", fpbuf);
     380             :     }
     381             : 
     382          27 :     smartlist_add(chunks, tor_strndup(cert->cache_info.signed_descriptor_body,
     383             :                                       cert->cache_info.signed_descriptor_len));
     384             :   }
     385             : 
     386         135 :   SMARTLIST_FOREACH_BEGIN(v3_ns->routerstatus_list, vote_routerstatus_t *,
     387             :                           vrs) {
     388         108 :     char *rsf;
     389         108 :     vote_microdesc_hash_t *h;
     390         216 :     rsf = routerstatus_format_entry(&vrs->status,
     391         108 :                                     vrs->version, vrs->protocols,
     392             :                                     NS_V3_VOTE,
     393             :                                     vrs);
     394         108 :     if (rsf)
     395         108 :       smartlist_add(chunks, rsf);
     396             : 
     397         216 :     for (h = vrs->microdesc; h; h = h->next) {
     398         108 :       smartlist_add_strdup(chunks, h->microdesc_hash_line);
     399             :     }
     400         108 :   } SMARTLIST_FOREACH_END(vrs);
     401             : 
     402          27 :   smartlist_add_strdup(chunks, "directory-footer\n");
     403             : 
     404             :   /* The digest includes everything up through the space after
     405             :    * directory-signature.  (Yuck.) */
     406          27 :   crypto_digest_smartlist(digest, DIGEST_LEN, chunks,
     407             :                           "directory-signature ", DIGEST_SHA1);
     408             : 
     409             :   {
     410          27 :     char signing_key_fingerprint[FINGERPRINT_LEN+1];
     411          27 :     if (crypto_pk_get_fingerprint(private_signing_key,
     412             :                                   signing_key_fingerprint, 0)<0) {
     413           0 :       log_warn(LD_BUG, "Unable to get fingerprint for signing key");
     414           0 :       goto err;
     415             :     }
     416             : 
     417          27 :     smartlist_add_asprintf(chunks, "directory-signature %s %s\n", fingerprint,
     418             :                            signing_key_fingerprint);
     419             :   }
     420             : 
     421             :   {
     422          27 :     char *sig = router_get_dirobj_signature(digest, DIGEST_LEN,
     423             :                                             private_signing_key);
     424          27 :     if (!sig) {
     425           0 :       log_warn(LD_BUG, "Unable to sign networkstatus vote.");
     426           0 :       goto err;
     427             :     }
     428          27 :     smartlist_add(chunks, sig);
     429             :   }
     430             : 
     431          27 :   status = smartlist_join_strings(chunks, "", 0, NULL);
     432             : 
     433             :   {
     434          27 :     networkstatus_t *v;
     435          27 :     if (!(v = networkstatus_parse_vote_from_string(status, strlen(status),
     436             :                                                    NULL,
     437             :                                                    v3_ns->type))) {
     438           0 :       log_err(LD_BUG,"Generated a networkstatus %s we couldn't parse: "
     439             :               "<<%s>>",
     440             :               v3_ns->type == NS_TYPE_VOTE ? "vote" : "opinion", status);
     441           0 :       goto err;
     442             :     }
     443          27 :     networkstatus_vote_free(v);
     444             :   }
     445             : 
     446          27 :   goto done;
     447             : 
     448           0 :  err:
     449           0 :   tor_free(status);
     450          27 :  done:
     451          27 :   tor_free(client_versions_line);
     452          27 :   tor_free(server_versions_line);
     453          27 :   tor_free(protocols_lines);
     454             : 
     455         387 :   SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
     456          27 :   smartlist_free(chunks);
     457          27 :   return status;
     458             : }
     459             : 
     460             : /** Set *<b>timing_out</b> to the intervals at which we would like to vote.
     461             :  * Note that these aren't the intervals we'll use to vote; they're the ones
     462             :  * that we'll vote to use. */
     463             : static void
     464           0 : dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out)
     465             : {
     466           0 :   const or_options_t *options = get_options();
     467             : 
     468           0 :   tor_assert(timing_out);
     469             : 
     470           0 :   timing_out->vote_interval = options->V3AuthVotingInterval;
     471           0 :   timing_out->n_intervals_valid = options->V3AuthNIntervalsValid;
     472           0 :   timing_out->vote_delay = options->V3AuthVoteDelay;
     473           0 :   timing_out->dist_delay = options->V3AuthDistDelay;
     474           0 : }
     475             : 
     476             : /* =====
     477             :  * Consensus generation
     478             :  * ===== */
     479             : 
     480             : /** If <b>vrs</b> has a hash made for the consensus method <b>method</b> with
     481             :  * the digest algorithm <b>alg</b>, decode it and copy it into
     482             :  * <b>digest256_out</b> and return 0.  Otherwise return -1. */
     483             : static int
     484         258 : vote_routerstatus_find_microdesc_hash(char *digest256_out,
     485             :                                       const vote_routerstatus_t *vrs,
     486             :                                       int method,
     487             :                                       digest_algorithm_t alg)
     488             : {
     489             :   /* XXXX only returns the sha256 method. */
     490         258 :   const vote_microdesc_hash_t *h;
     491         258 :   char mstr[64];
     492         258 :   size_t mlen;
     493         258 :   char dstr[64];
     494             : 
     495         258 :   tor_snprintf(mstr, sizeof(mstr), "%d", method);
     496         258 :   mlen = strlen(mstr);
     497         258 :   tor_snprintf(dstr, sizeof(dstr), " %s=",
     498             :                crypto_digest_algorithm_get_name(alg));
     499             : 
     500         258 :   for (h = vrs->microdesc; h; h = h->next) {
     501         258 :     const char *cp = h->microdesc_hash_line;
     502        1032 :     size_t num_len;
     503             :     /* cp looks like \d+(,\d+)* (digesttype=val )+ .  Let's hunt for mstr in
     504             :      * the first part. */
     505        1806 :     while (1) {
     506        1806 :       num_len = strspn(cp, "1234567890");
     507        1032 :       if (num_len == mlen && fast_memeq(mstr, cp, mlen)) {
     508             :         /* This is the line. */
     509         258 :         char buf[BASE64_DIGEST256_LEN+1];
     510             :         /* XXXX ignores extraneous stuff if the digest is too long.  This
     511             :          * seems harmless enough, right? */
     512         258 :         cp = strstr(cp, dstr);
     513         258 :         if (!cp)
     514             :           return -1;
     515         258 :         cp += strlen(dstr);
     516         258 :         strlcpy(buf, cp, sizeof(buf));
     517         258 :         return digest256_from_base64(digest256_out, buf);
     518             :       }
     519         774 :       if (num_len == 0 || cp[num_len] != ',')
     520             :         break;
     521         774 :       cp += num_len + 1;
     522             :     }
     523             :   }
     524             :   return -1;
     525             : }
     526             : 
     527             : /** Given a vote <b>vote</b> (not a consensus!), return its associated
     528             :  * networkstatus_voter_info_t. */
     529             : static networkstatus_voter_info_t *
     530         678 : get_voter(const networkstatus_t *vote)
     531             : {
     532         678 :   tor_assert(vote);
     533         678 :   tor_assert(vote->type == NS_TYPE_VOTE);
     534         678 :   tor_assert(vote->voters);
     535         678 :   tor_assert(smartlist_len(vote->voters) == 1);
     536         678 :   return smartlist_get(vote->voters, 0);
     537             : }
     538             : 
     539             : /** Temporary structure used in constructing a list of dir-source entries
     540             :  * for a consensus.  One of these is generated for every vote, and one more
     541             :  * for every legacy key in each vote. */
     542             : typedef struct dir_src_ent_t {
     543             :   networkstatus_t *v;
     544             :   const char *digest;
     545             :   int is_legacy;
     546             : } dir_src_ent_t;
     547             : 
     548             : /** Helper for sorting networkstatus_t votes (not consensuses) by the
     549             :  * hash of their voters' identity digests. */
     550             : static int
     551          62 : compare_votes_by_authority_id_(const void **_a, const void **_b)
     552             : {
     553          62 :   const networkstatus_t *a = *_a, *b = *_b;
     554          62 :   return fast_memcmp(get_voter(a)->identity_digest,
     555             :                 get_voter(b)->identity_digest, DIGEST_LEN);
     556             : }
     557             : 
     558             : /** Helper: Compare the dir_src_ent_ts in *<b>_a</b> and *<b>_b</b> by
     559             :  * their identity digests, and return -1, 0, or 1 depending on their
     560             :  * ordering */
     561             : static int
     562         120 : compare_dir_src_ents_by_authority_id_(const void **_a, const void **_b)
     563             : {
     564         120 :   const dir_src_ent_t *a = *_a, *b = *_b;
     565         120 :   const networkstatus_voter_info_t *a_v = get_voter(a->v),
     566         120 :     *b_v = get_voter(b->v);
     567         120 :   const char *a_id, *b_id;
     568         120 :   a_id = a->is_legacy ? a_v->legacy_id_digest : a_v->identity_digest;
     569         120 :   b_id = b->is_legacy ? b_v->legacy_id_digest : b_v->identity_digest;
     570             : 
     571         120 :   return fast_memcmp(a_id, b_id, DIGEST_LEN);
     572             : }
     573             : 
     574             : /** Given a sorted list of strings <b>in</b>, add every member to <b>out</b>
     575             :  * that occurs more than <b>min</b> times. */
     576             : static void
     577          72 : get_frequent_members(smartlist_t *out, smartlist_t *in, int min)
     578             : {
     579          72 :   char *cur = NULL;
     580          72 :   int count = 0;
     581         600 :   SMARTLIST_FOREACH_BEGIN(in, char *, cp) {
     582         528 :     if (cur && !strcmp(cp, cur)) {
     583         264 :       ++count;
     584             :     } else {
     585         264 :       if (count > min)
     586         120 :         smartlist_add(out, cur);
     587             :       cur = cp;
     588             :       count = 1;
     589             :     }
     590         528 :   } SMARTLIST_FOREACH_END(cp);
     591          72 :   if (count > min)
     592          48 :     smartlist_add(out, cur);
     593          72 : }
     594             : 
     595             : /** Given a sorted list of strings <b>lst</b>, return the member that appears
     596             :  * most.  Break ties in favor of later-occurring members. */
     597             : #define get_most_frequent_member(lst)           \
     598             :   smartlist_get_most_frequent_string(lst)
     599             : 
     600             : /** Return 0 if and only if <b>a</b> and <b>b</b> are routerstatuses
     601             :  * that come from the same routerinfo, with the same derived elements.
     602             :  */
     603             : static int
     604         876 : compare_vote_rs(const vote_routerstatus_t *a, const vote_routerstatus_t *b)
     605             : {
     606         876 :   int r;
     607         876 :   tor_assert(a);
     608         876 :   tor_assert(b);
     609             : 
     610         876 :   if ((r = fast_memcmp(a->status.identity_digest, b->status.identity_digest,
     611             :                   DIGEST_LEN)))
     612             :     return r;
     613         876 :   if ((r = fast_memcmp(a->status.descriptor_digest,
     614             :                        b->status.descriptor_digest,
     615             :                        DIGEST_LEN)))
     616             :     return r;
     617             :   /* If we actually reached this point, then the identities and
     618             :    * the descriptor digests matched, so somebody is making SHA1 collisions.
     619             :    */
     620             : #define CMP_FIELD(utype, itype, field) do {                             \
     621             :     utype aval = (utype) (itype) a->status.field;                       \
     622             :     utype bval = (utype) (itype) b->status.field;                       \
     623             :     utype u = bval - aval;                                              \
     624             :     itype r2 = (itype) u;                                               \
     625             :     if (r2 < 0) {                                                       \
     626             :       return -1;                                                        \
     627             :     } else if (r2 > 0) {                                                \
     628             :       return 1;                                                         \
     629             :     }                                                                   \
     630             :   } while (0)
     631             : 
     632         852 :   CMP_FIELD(uint64_t, int64_t, published_on);
     633             : 
     634         852 :   if ((r = strcmp(b->status.nickname, a->status.nickname)))
     635             :     return r;
     636             : 
     637         852 :   if ((r = tor_addr_compare(&a->status.ipv4_addr, &b->status.ipv4_addr,
     638             :                             CMP_EXACT))) {
     639             :     return r;
     640             :   }
     641         852 :   CMP_FIELD(unsigned, int, ipv4_orport);
     642         852 :   CMP_FIELD(unsigned, int, ipv4_dirport);
     643             : 
     644             :   return 0;
     645             : }
     646             : 
     647             : /** Helper for sorting routerlists based on compare_vote_rs. */
     648             : static int
     649         174 : compare_vote_rs_(const void **_a, const void **_b)
     650             : {
     651         174 :   const vote_routerstatus_t *a = *_a, *b = *_b;
     652         174 :   return compare_vote_rs(a,b);
     653             : }
     654             : 
     655             : /** Helper for sorting OR ports. */
     656             : static int
     657          84 : compare_orports_(const void **_a, const void **_b)
     658             : {
     659          84 :   const tor_addr_port_t *a = *_a, *b = *_b;
     660          84 :   int r;
     661             : 
     662          84 :   if ((r = tor_addr_compare(&a->addr, &b->addr, CMP_EXACT)))
     663             :     return r;
     664          84 :   if ((r = (((int) b->port) - ((int) a->port))))
     665           0 :     return r;
     666             : 
     667             :   return 0;
     668             : }
     669             : 
     670             : /** Given a list of vote_routerstatus_t, all for the same router identity,
     671             :  * return whichever is most frequent, breaking ties in favor of more
     672             :  * recently published vote_routerstatus_t and in case of ties there,
     673             :  * in favor of smaller descriptor digest.
     674             :  */
     675             : static vote_routerstatus_t *
     676          90 : compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
     677             :                                char *microdesc_digest256_out,
     678             :                                tor_addr_port_t *best_alt_orport_out)
     679             : {
     680          90 :   vote_routerstatus_t *most = NULL, *cur = NULL;
     681          90 :   int most_n = 0, cur_n = 0;
     682          90 :   time_t most_published = 0;
     683             : 
     684             :   /* compare_vote_rs_() sorts the items by identity digest (all the same),
     685             :    * then by SD digest.  That way, if we have a tie that the published_on
     686             :    * date cannot break, we use the descriptor with the smaller digest.
     687             :    */
     688          90 :   smartlist_sort(votes, compare_vote_rs_);
     689         354 :   SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) {
     690         264 :     if (cur && !compare_vote_rs(cur, rs)) {
     691         168 :       ++cur_n;
     692             :     } else {
     693          96 :       if (cur && (cur_n > most_n ||
     694           0 :                   (cur_n == most_n &&
     695           0 :                    cur->status.published_on > most_published))) {
     696           6 :         most = cur;
     697           6 :         most_n = cur_n;
     698           6 :         most_published = cur->status.published_on;
     699             :       }
     700             :       cur_n = 1;
     701             :       cur = rs;
     702             :     }
     703         264 :   } SMARTLIST_FOREACH_END(rs);
     704             : 
     705          90 :   if (cur_n > most_n ||
     706           6 :       (cur && cur_n == most_n && cur->status.published_on > most_published)) {
     707          84 :     most = cur;
     708             :     // most_n = cur_n; // unused after this point.
     709             :     // most_published = cur->status.published_on; // unused after this point.
     710             :   }
     711             : 
     712          90 :   tor_assert(most);
     713             : 
     714             :   /* Vote on potential alternative (sets of) OR port(s) in the winning
     715             :    * routerstatuses.
     716             :    *
     717             :    * XXX prop186 There's at most one alternative OR port (_the_ IPv6
     718             :    * port) for now. */
     719          90 :   if (best_alt_orport_out) {
     720          90 :     smartlist_t *alt_orports = smartlist_new();
     721          90 :     const tor_addr_port_t *most_alt_orport = NULL;
     722             : 
     723         354 :     SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) {
     724         264 :       tor_assert(rs);
     725         522 :       if (compare_vote_rs(most, rs) == 0 &&
     726         258 :           !tor_addr_is_null(&rs->status.ipv6_addr)
     727          66 :           && rs->status.ipv6_orport) {
     728          66 :         smartlist_add(alt_orports, tor_addr_port_new(&rs->status.ipv6_addr,
     729             :                                                      rs->status.ipv6_orport));
     730             :       }
     731         264 :     } SMARTLIST_FOREACH_END(rs);
     732             : 
     733          90 :     smartlist_sort(alt_orports, compare_orports_);
     734          90 :     most_alt_orport = smartlist_get_most_frequent(alt_orports,
     735             :                                                   compare_orports_);
     736          90 :     if (most_alt_orport) {
     737          24 :       memcpy(best_alt_orport_out, most_alt_orport, sizeof(tor_addr_port_t));
     738          24 :       log_debug(LD_DIR, "\"a\" line winner for %s is %s",
     739             :                 most->status.nickname,
     740             :                 fmt_addrport(&most_alt_orport->addr, most_alt_orport->port));
     741             :     }
     742             : 
     743         156 :     SMARTLIST_FOREACH(alt_orports, tor_addr_port_t *, ap, tor_free(ap));
     744          90 :     smartlist_free(alt_orports);
     745             :   }
     746             : 
     747          90 :   if (microdesc_digest256_out) {
     748          90 :     smartlist_t *digests = smartlist_new();
     749          90 :     const uint8_t *best_microdesc_digest;
     750         354 :     SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) {
     751         264 :         char d[DIGEST256_LEN];
     752         264 :         if (compare_vote_rs(rs, most))
     753           6 :           continue;
     754         258 :         if (!vote_routerstatus_find_microdesc_hash(d, rs, consensus_method,
     755             :                                                    DIGEST_SHA256))
     756         258 :           smartlist_add(digests, tor_memdup(d, sizeof(d)));
     757         264 :     } SMARTLIST_FOREACH_END(rs);
     758          90 :     smartlist_sort_digests256(digests);
     759          90 :     best_microdesc_digest = smartlist_get_most_frequent_digest256(digests);
     760          90 :     if (best_microdesc_digest)
     761          90 :       memcpy(microdesc_digest256_out, best_microdesc_digest, DIGEST256_LEN);
     762         348 :     SMARTLIST_FOREACH(digests, char *, cp, tor_free(cp));
     763          90 :     smartlist_free(digests);
     764             :   }
     765             : 
     766          90 :   return most;
     767             : }
     768             : 
     769             : /** Sorting helper: compare two strings based on their values as base-ten
     770             :  * positive integers. (Non-integers are treated as prior to all integers, and
     771             :  * compared lexically.) */
     772             : static int
     773        1224 : cmp_int_strings_(const void **_a, const void **_b)
     774             : {
     775        1224 :   const char *a = *_a, *b = *_b;
     776        1224 :   int ai = (int)tor_parse_long(a, 10, 1, INT_MAX, NULL, NULL);
     777        1224 :   int bi = (int)tor_parse_long(b, 10, 1, INT_MAX, NULL, NULL);
     778        1224 :   if (ai<bi) {
     779             :     return -1;
     780         528 :   } else if (ai==bi) {
     781         240 :     if (ai == 0) /* Parsing failed. */
     782           0 :       return strcmp(a, b);
     783             :     return 0;
     784             :   } else {
     785             :     return 1;
     786             :   }
     787             : }
     788             : 
     789             : /** Given a list of networkstatus_t votes, determine and return the number of
     790             :  * the highest consensus method that is supported by 2/3 of the voters. */
     791             : static int
     792          24 : compute_consensus_method(smartlist_t *votes)
     793             : {
     794          24 :   smartlist_t *all_methods = smartlist_new();
     795          24 :   smartlist_t *acceptable_methods = smartlist_new();
     796          24 :   smartlist_t *tmp = smartlist_new();
     797          24 :   int min = (smartlist_len(votes) * 2) / 3;
     798          24 :   int n_ok;
     799          24 :   int result;
     800          96 :   SMARTLIST_FOREACH(votes, networkstatus_t *, vote,
     801             :   {
     802             :     tor_assert(vote->supported_methods);
     803             :     smartlist_add_all(tmp, vote->supported_methods);
     804             :     smartlist_sort(tmp, cmp_int_strings_);
     805             :     smartlist_uniq(tmp, cmp_int_strings_, NULL);
     806             :     smartlist_add_all(all_methods, tmp);
     807             :     smartlist_clear(tmp);
     808             :   });
     809             : 
     810          24 :   smartlist_sort(all_methods, cmp_int_strings_);
     811          24 :   get_frequent_members(acceptable_methods, all_methods, min);
     812          24 :   n_ok = smartlist_len(acceptable_methods);
     813          24 :   if (n_ok) {
     814          24 :     const char *best = smartlist_get(acceptable_methods, n_ok-1);
     815          24 :     result = (int)tor_parse_long(best, 10, 1, INT_MAX, NULL, NULL);
     816             :   } else {
     817             :     result = 1;
     818             :   }
     819          24 :   smartlist_free(tmp);
     820          24 :   smartlist_free(all_methods);
     821          24 :   smartlist_free(acceptable_methods);
     822          24 :   return result;
     823             : }
     824             : 
     825             : /** Return true iff <b>method</b> is a consensus method that we support. */
     826             : static int
     827         468 : consensus_method_is_supported(int method)
     828             : {
     829         468 :   return (method >= MIN_SUPPORTED_CONSENSUS_METHOD) &&
     830             :     (method <= MAX_SUPPORTED_CONSENSUS_METHOD);
     831             : }
     832             : 
     833             : /** Return a newly allocated string holding the numbers between low and high
     834             :  * (inclusive) that are supported consensus methods. */
     835             : STATIC char *
     836         111 : make_consensus_method_list(int low, int high, const char *separator)
     837             : {
     838         111 :   char *list;
     839             : 
     840         111 :   int i;
     841         111 :   smartlist_t *lst;
     842         111 :   lst = smartlist_new();
     843         666 :   for (i = low; i <= high; ++i) {
     844         444 :     if (!consensus_method_is_supported(i))
     845           0 :       continue;
     846         444 :     smartlist_add_asprintf(lst, "%d", i);
     847             :   }
     848         111 :   list = smartlist_join_strings(lst, separator, 0, NULL);
     849         111 :   tor_assert(list);
     850         555 :   SMARTLIST_FOREACH(lst, char *, cp, tor_free(cp));
     851         111 :   smartlist_free(lst);
     852         111 :   return list;
     853             : }
     854             : 
     855             : /** Helper: given <b>lst</b>, a list of version strings such that every
     856             :  * version appears once for every versioning voter who recommends it, return a
     857             :  * newly allocated string holding the resulting client-versions or
     858             :  * server-versions list. May change contents of <b>lst</b> */
     859             : static char *
     860          48 : compute_consensus_versions_list(smartlist_t *lst, int n_versioning)
     861             : {
     862          48 :   int min = n_versioning / 2;
     863          48 :   smartlist_t *good = smartlist_new();
     864          48 :   char *result;
     865         288 :   SMARTLIST_FOREACH_BEGIN(lst, const char *, v) {
     866         240 :     if (strchr(v, ' ')) {
     867           0 :       log_warn(LD_DIR, "At least one authority has voted for a version %s "
     868             :                "that contains a space. This probably wasn't intentional, and "
     869             :                "is likely to cause trouble. Please tell them to stop it.",
     870             :                escaped(v));
     871             :     }
     872         240 :   } SMARTLIST_FOREACH_END(v);
     873          48 :   sort_version_list(lst, 0);
     874          48 :   get_frequent_members(good, lst, min);
     875          48 :   result = smartlist_join_strings(good, ",", 0, NULL);
     876          48 :   smartlist_free(good);
     877          48 :   return result;
     878             : }
     879             : 
     880             : /** Given a list of K=V values, return the int32_t value corresponding to
     881             :  * KEYWORD=, or default_val if no such value exists, or if the value is
     882             :  * corrupt.
     883             :  */
     884             : STATIC int32_t
     885          56 : dirvote_get_intermediate_param_value(const smartlist_t *param_list,
     886             :                                      const char *keyword,
     887             :                                      int32_t default_val)
     888             : {
     889          56 :   unsigned int n_found = 0;
     890          56 :   int32_t value = default_val;
     891             : 
     892         218 :   SMARTLIST_FOREACH_BEGIN(param_list, const char *, k_v_pair) {
     893         165 :     if (!strcmpstart(k_v_pair, keyword) && k_v_pair[strlen(keyword)] == '=') {
     894           7 :       const char *integer_str = &k_v_pair[strlen(keyword)+1];
     895           7 :       int ok;
     896          14 :       value = (int32_t)
     897           7 :         tor_parse_long(integer_str, 10, INT32_MIN, INT32_MAX, &ok, NULL);
     898           7 :       if (BUG(!ok))
     899           3 :         return default_val;
     900           4 :       ++n_found;
     901             :     }
     902         162 :   } SMARTLIST_FOREACH_END(k_v_pair);
     903             : 
     904          53 :   if (n_found == 1) {
     905             :     return value;
     906             :   } else {
     907          51 :     tor_assert_nonfatal(n_found == 0);
     908          51 :     return default_val;
     909             :   }
     910             : }
     911             : 
     912             : /** Minimum number of directory authorities voting for a parameter to
     913             :  * include it in the consensus, if consensus method 12 or later is to be
     914             :  * used. See proposal 178 for details. */
     915             : #define MIN_VOTES_FOR_PARAM 3
     916             : 
     917             : /** Helper: given a list of valid networkstatus_t, return a new smartlist
     918             :  * containing the contents of the consensus network parameter set.
     919             :  */
     920             : STATIC smartlist_t *
     921          36 : dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
     922             : {
     923          36 :   int i;
     924          36 :   int32_t *vals;
     925             : 
     926          36 :   int cur_param_len;
     927          36 :   const char *cur_param;
     928          36 :   const char *eq;
     929             : 
     930          36 :   const int n_votes = smartlist_len(votes);
     931          36 :   smartlist_t *output;
     932          36 :   smartlist_t *param_list = smartlist_new();
     933          36 :   (void) method;
     934             : 
     935             :   /* We require that the parameter lists in the votes are well-formed: that
     936             :      is, that their keywords are unique and sorted, and that their values are
     937             :      between INT32_MIN and INT32_MAX inclusive.  This should be guaranteed by
     938             :      the parsing code. */
     939             : 
     940          36 :   vals = tor_calloc(n_votes, sizeof(int));
     941             : 
     942         141 :   SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
     943         105 :     if (!v->net_params)
     944           0 :       continue;
     945         105 :     smartlist_add_all(param_list, v->net_params);
     946         105 :   } SMARTLIST_FOREACH_END(v);
     947             : 
     948          36 :   if (smartlist_len(param_list) == 0) {
     949           0 :     tor_free(vals);
     950           0 :     return param_list;
     951             :   }
     952             : 
     953          36 :   smartlist_sort_strings(param_list);
     954          36 :   i = 0;
     955          36 :   cur_param = smartlist_get(param_list, 0);
     956          36 :   eq = strchr(cur_param, '=');
     957          36 :   tor_assert(eq);
     958          36 :   cur_param_len = (int)(eq+1 - cur_param);
     959             : 
     960          36 :   output = smartlist_new();
     961             : 
     962         331 :   SMARTLIST_FOREACH_BEGIN(param_list, const char *, param) {
     963             :     /* resolve spurious clang shallow analysis null pointer errors */
     964         295 :     tor_assert(param);
     965             : 
     966         295 :     const char *next_param;
     967         295 :     int ok=0;
     968         295 :     eq = strchr(param, '=');
     969         295 :     tor_assert(i<n_votes); /* Make sure we prevented vote-stuffing. */
     970         590 :     vals[i++] = (int32_t)
     971         295 :       tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
     972         295 :     tor_assert(ok); /* Already checked these when parsing. */
     973             : 
     974         295 :     if (param_sl_idx+1 == smartlist_len(param_list))
     975             :       next_param = NULL;
     976             :     else
     977         259 :       next_param = smartlist_get(param_list, param_sl_idx+1);
     978             : 
     979         259 :     if (!next_param || strncmp(next_param, param, cur_param_len)) {
     980             :       /* We've reached the end of a series. */
     981             :       /* Make sure enough authorities voted on this param, unless the
     982             :        * the consensus method we use is too old for that. */
     983         140 :       if (i > total_authorities/2 ||
     984             :           i >= MIN_VOTES_FOR_PARAM) {
     985          88 :         int32_t median = median_int32(vals, i);
     986          88 :         char *out_string = tor_malloc(64+cur_param_len);
     987          88 :         memcpy(out_string, param, cur_param_len);
     988          88 :         tor_snprintf(out_string+cur_param_len,64, "%ld", (long)median);
     989          88 :         smartlist_add(output, out_string);
     990             :       }
     991             : 
     992         140 :       i = 0;
     993         140 :       if (next_param) {
     994         104 :         eq = strchr(next_param, '=');
     995         104 :         cur_param_len = (int)(eq+1 - next_param);
     996             :       }
     997             :     }
     998         295 :   } SMARTLIST_FOREACH_END(param);
     999             : 
    1000          36 :   smartlist_free(param_list);
    1001          36 :   tor_free(vals);
    1002          36 :   return output;
    1003             : }
    1004             : 
    1005             : #define RANGE_CHECK(a,b,c,d,e,f,g,mx) \
    1006             :        ((a) >= 0 && (a) <= (mx) && (b) >= 0 && (b) <= (mx) && \
    1007             :         (c) >= 0 && (c) <= (mx) && (d) >= 0 && (d) <= (mx) && \
    1008             :         (e) >= 0 && (e) <= (mx) && (f) >= 0 && (f) <= (mx) && \
    1009             :         (g) >= 0 && (g) <= (mx))
    1010             : 
    1011             : #define CHECK_EQ(a, b, margin) \
    1012             :      ((a)-(b) >= 0 ? (a)-(b) <= (margin) : (b)-(a) <= (margin))
    1013             : 
    1014             : typedef enum {
    1015             :  BW_WEIGHTS_NO_ERROR = 0,
    1016             :  BW_WEIGHTS_RANGE_ERROR = 1,
    1017             :  BW_WEIGHTS_SUMG_ERROR = 2,
    1018             :  BW_WEIGHTS_SUME_ERROR = 3,
    1019             :  BW_WEIGHTS_SUMD_ERROR = 4,
    1020             :  BW_WEIGHTS_BALANCE_MID_ERROR = 5,
    1021             :  BW_WEIGHTS_BALANCE_EG_ERROR = 6
    1022             : } bw_weights_error_t;
    1023             : 
    1024             : /**
    1025             :  * Verify that any weightings satisfy the balanced formulas.
    1026             :  */
    1027             : static bw_weights_error_t
    1028          47 : networkstatus_check_weights(int64_t Wgg, int64_t Wgd, int64_t Wmg,
    1029             :                             int64_t Wme, int64_t Wmd, int64_t Wee,
    1030             :                             int64_t Wed, int64_t scale, int64_t G,
    1031             :                             int64_t M, int64_t E, int64_t D, int64_t T,
    1032             :                             int64_t margin, int do_balance) {
    1033          47 :   bw_weights_error_t berr = BW_WEIGHTS_NO_ERROR;
    1034             : 
    1035             :   // Wed + Wmd + Wgd == 1
    1036          47 :   if (!CHECK_EQ(Wed + Wmd + Wgd, scale, margin)) {
    1037           0 :     berr = BW_WEIGHTS_SUMD_ERROR;
    1038           0 :     goto out;
    1039             :   }
    1040             : 
    1041             :   // Wmg + Wgg == 1
    1042          47 :   if (!CHECK_EQ(Wmg + Wgg, scale, margin)) {
    1043           0 :     berr = BW_WEIGHTS_SUMG_ERROR;
    1044           0 :     goto out;
    1045             :   }
    1046             : 
    1047             :   // Wme + Wee == 1
    1048          47 :   if (!CHECK_EQ(Wme + Wee, scale, margin)) {
    1049           0 :     berr = BW_WEIGHTS_SUME_ERROR;
    1050           0 :     goto out;
    1051             :   }
    1052             : 
    1053             :   // Verify weights within range 0->1
    1054          47 :   if (!RANGE_CHECK(Wgg, Wgd, Wmg, Wme, Wmd, Wed, Wee, scale)) {
    1055          14 :     berr = BW_WEIGHTS_RANGE_ERROR;
    1056          14 :     goto out;
    1057             :   }
    1058             : 
    1059          33 :   if (do_balance) {
    1060             :     // Wgg*G + Wgd*D == Wee*E + Wed*D, already scaled
    1061          33 :     if (!CHECK_EQ(Wgg*G + Wgd*D, Wee*E + Wed*D, (margin*T)/3)) {
    1062           1 :       berr = BW_WEIGHTS_BALANCE_EG_ERROR;
    1063           1 :       goto out;
    1064             :     }
    1065             : 
    1066             :     // Wgg*G + Wgd*D == M*scale + Wmd*D + Wme*E + Wmg*G, already scaled
    1067          32 :     if (!CHECK_EQ(Wgg*G + Wgd*D, M*scale + Wmd*D + Wme*E + Wmg*G,
    1068             :                 (margin*T)/3)) {
    1069           0 :       berr = BW_WEIGHTS_BALANCE_MID_ERROR;
    1070           0 :       goto out;
    1071             :     }
    1072             :   }
    1073             : 
    1074          32 :  out:
    1075          15 :   if (berr) {
    1076          15 :     log_info(LD_DIR,
    1077             :              "Bw weight mismatch %d. G=%"PRId64" M=%"PRId64
    1078             :              " E=%"PRId64" D=%"PRId64" T=%"PRId64
    1079             :              " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d"
    1080             :              " Wgd=%d Wgg=%d Wme=%d Wmg=%d",
    1081             :              berr,
    1082             :              (G), (M), (E),
    1083             :              (D), (T),
    1084             :              (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee,
    1085             :              (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg);
    1086             :   }
    1087             : 
    1088          47 :   return berr;
    1089             : }
    1090             : 
    1091             : /**
    1092             :  * This function computes the bandwidth weights for consensus method 10.
    1093             :  *
    1094             :  * It returns true if weights could be computed, false otherwise.
    1095             :  */
    1096             : int
    1097          39 : networkstatus_compute_bw_weights_v10(smartlist_t *chunks, int64_t G,
    1098             :                                      int64_t M, int64_t E, int64_t D,
    1099             :                                      int64_t T, int64_t weight_scale)
    1100             : {
    1101          39 :   bw_weights_error_t berr = 0;
    1102          39 :   int64_t Wgg = -1, Wgd = -1;
    1103          39 :   int64_t Wmg = -1, Wme = -1, Wmd = -1;
    1104          39 :   int64_t Wed = -1, Wee = -1;
    1105          39 :   const char *casename;
    1106             : 
    1107          39 :   if (G <= 0 || M <= 0 || E <= 0 || D <= 0) {
    1108           1 :     log_warn(LD_DIR, "Consensus with empty bandwidth: "
    1109             :                      "G=%"PRId64" M=%"PRId64" E=%"PRId64
    1110             :                      " D=%"PRId64" T=%"PRId64,
    1111             :              (G), (M), (E),
    1112             :              (D), (T));
    1113           1 :     return 0;
    1114             :   }
    1115             : 
    1116             :   /*
    1117             :    * Computed from cases in 3.8.3 of dir-spec.txt
    1118             :    *
    1119             :    * 1. Neither are scarce
    1120             :    * 2. Both Guard and Exit are scarce
    1121             :    *    a. R+D <= S
    1122             :    *    b. R+D > S
    1123             :    * 3. One of Guard or Exit is scarce
    1124             :    *    a. S+D < T/3
    1125             :    *    b. S+D >= T/3
    1126             :    */
    1127          38 :   if (3*E >= T && 3*G >= T) { // E >= T/3 && G >= T/3
    1128             :     /* Case 1: Neither are scarce.  */
    1129           1 :     casename = "Case 1 (Wgd=Wmd=Wed)";
    1130           1 :     Wgd = weight_scale/3;
    1131           1 :     Wed = weight_scale/3;
    1132           1 :     Wmd = weight_scale/3;
    1133           1 :     Wee = (weight_scale*(E+G+M))/(3*E);
    1134           1 :     Wme = weight_scale - Wee;
    1135           1 :     Wmg = (weight_scale*(2*G-E-M))/(3*G);
    1136           1 :     Wgg = weight_scale - Wmg;
    1137             : 
    1138           1 :     berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed,
    1139             :                                        weight_scale, G, M, E, D, T, 10, 1);
    1140             : 
    1141           1 :     if (berr) {
    1142           0 :       log_warn(LD_DIR,
    1143             :              "Bw Weights error %d for %s v10. G=%"PRId64" M=%"PRId64
    1144             :              " E=%"PRId64" D=%"PRId64" T=%"PRId64
    1145             :              " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d"
    1146             :              " Wgd=%d Wgg=%d Wme=%d Wmg=%d weight_scale=%d",
    1147             :              berr, casename,
    1148             :              (G), (M), (E),
    1149             :              (D), (T),
    1150             :              (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee,
    1151             :              (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg, (int)weight_scale);
    1152           0 :       return 0;
    1153             :     }
    1154          37 :   } else if (3*E < T && 3*G < T) { // E < T/3 && G < T/3
    1155          31 :     int64_t R = MIN(E, G);
    1156          31 :     int64_t S = MAX(E, G);
    1157             :     /*
    1158             :      * Case 2: Both Guards and Exits are scarce
    1159             :      * Balance D between E and G, depending upon
    1160             :      * D capacity and scarcity.
    1161             :      */
    1162          31 :     if (R+D < S) { // Subcase a
    1163           2 :       Wgg = weight_scale;
    1164           2 :       Wee = weight_scale;
    1165           2 :       Wmg = 0;
    1166           2 :       Wme = 0;
    1167           2 :       Wmd = 0;
    1168           2 :       if (E < G) {
    1169             :         casename = "Case 2a (E scarce)";
    1170             :         Wed = weight_scale;
    1171             :         Wgd = 0;
    1172             :       } else { /* E >= G */
    1173           1 :         casename = "Case 2a (G scarce)";
    1174           1 :         Wed = 0;
    1175           1 :         Wgd = weight_scale;
    1176             :       }
    1177             :     } else { // Subcase b: R+D >= S
    1178          29 :       casename = "Case 2b1 (Wgg=weight_scale, Wmd=Wgd)";
    1179          29 :       Wee = (weight_scale*(E - G + M))/E;
    1180          29 :       Wed = (weight_scale*(D - 2*E + 4*G - 2*M))/(3*D);
    1181          29 :       Wme = (weight_scale*(G-M))/E;
    1182          29 :       Wmg = 0;
    1183          29 :       Wgg = weight_scale;
    1184          29 :       Wmd = (weight_scale - Wed)/2;
    1185          29 :       Wgd = (weight_scale - Wed)/2;
    1186             : 
    1187          29 :       berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed,
    1188             :                                        weight_scale, G, M, E, D, T, 10, 1);
    1189             : 
    1190          29 :       if (berr) {
    1191          14 :         casename = "Case 2b2 (Wgg=weight_scale, Wee=weight_scale)";
    1192          14 :         Wgg = weight_scale;
    1193          14 :         Wee = weight_scale;
    1194          14 :         Wed = (weight_scale*(D - 2*E + G + M))/(3*D);
    1195          14 :         Wmd = (weight_scale*(D - 2*M + G + E))/(3*D);
    1196          14 :         Wme = 0;
    1197          14 :         Wmg = 0;
    1198             : 
    1199          14 :         if (Wmd < 0) { // Can happen if M > T/3
    1200           1 :           casename = "Case 2b3 (Wmd=0)";
    1201           1 :           Wmd = 0;
    1202           1 :           log_warn(LD_DIR,
    1203             :                    "Too much Middle bandwidth on the network to calculate "
    1204             :                    "balanced bandwidth-weights. Consider increasing the "
    1205             :                    "number of Guard nodes by lowering the requirements.");
    1206             :         }
    1207          14 :         Wgd = weight_scale - Wed - Wmd;
    1208          14 :         berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee,
    1209             :                   Wed, weight_scale, G, M, E, D, T, 10, 1);
    1210             :       }
    1211          29 :       if (berr != BW_WEIGHTS_NO_ERROR &&
    1212          29 :               berr != BW_WEIGHTS_BALANCE_MID_ERROR) {
    1213           1 :         log_warn(LD_DIR,
    1214             :              "Bw Weights error %d for %s v10. G=%"PRId64" M=%"PRId64
    1215             :              " E=%"PRId64" D=%"PRId64" T=%"PRId64
    1216             :              " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d"
    1217             :              " Wgd=%d Wgg=%d Wme=%d Wmg=%d weight_scale=%d",
    1218             :              berr, casename,
    1219             :              (G), (M), (E),
    1220             :              (D), (T),
    1221             :              (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee,
    1222             :              (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg, (int)weight_scale);
    1223           1 :         return 0;
    1224             :       }
    1225             :     }
    1226             :   } else { // if (E < T/3 || G < T/3) {
    1227           6 :     int64_t S = MIN(E, G);
    1228             :     // Case 3: Exactly one of Guard or Exit is scarce
    1229           6 :     if (!(3*E < T || 3*G < T) || !(3*G >= T || 3*E >= T)) {
    1230           0 :       log_warn(LD_BUG,
    1231             :            "Bw-Weights Case 3 v10 but with G=%"PRId64" M="
    1232             :            "%"PRId64" E=%"PRId64" D=%"PRId64" T=%"PRId64,
    1233             :                (G), (M), (E),
    1234             :                (D), (T));
    1235             :     }
    1236             : 
    1237           6 :     if (3*(S+D) < T) { // Subcase a: S+D < T/3
    1238           3 :       if (G < E) {
    1239           1 :         casename = "Case 3a (G scarce)";
    1240           1 :         Wgg = Wgd = weight_scale;
    1241           1 :         Wmd = Wed = Wmg = 0;
    1242             :         // Minor subcase, if E is more scarce than M,
    1243             :         // keep its bandwidth in place.
    1244           1 :         if (E < M) Wme = 0;
    1245           1 :         else Wme = (weight_scale*(E-M))/(2*E);
    1246           1 :         Wee = weight_scale-Wme;
    1247             :       } else { // G >= E
    1248           2 :         casename = "Case 3a (E scarce)";
    1249           2 :         Wee = Wed = weight_scale;
    1250           2 :         Wmd = Wgd = Wme = 0;
    1251             :         // Minor subcase, if G is more scarce than M,
    1252             :         // keep its bandwidth in place.
    1253           2 :         if (G < M) Wmg = 0;
    1254           2 :         else Wmg = (weight_scale*(G-M))/(2*G);
    1255           2 :         Wgg = weight_scale-Wmg;
    1256             :       }
    1257             :     } else { // Subcase b: S+D >= T/3
    1258             :       // D != 0 because S+D >= T/3
    1259           3 :       if (G < E) {
    1260           1 :         casename = "Case 3bg (G scarce, Wgg=weight_scale, Wmd == Wed)";
    1261           1 :         Wgg = weight_scale;
    1262           1 :         Wgd = (weight_scale*(D - 2*G + E + M))/(3*D);
    1263           1 :         Wmg = 0;
    1264           1 :         Wee = (weight_scale*(E+M))/(2*E);
    1265           1 :         Wme = weight_scale - Wee;
    1266           1 :         Wmd = (weight_scale - Wgd)/2;
    1267           1 :         Wed = (weight_scale - Wgd)/2;
    1268             : 
    1269           1 :         berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee,
    1270             :                     Wed, weight_scale, G, M, E, D, T, 10, 1);
    1271             :       } else { // G >= E
    1272           2 :         casename = "Case 3be (E scarce, Wee=weight_scale, Wmd == Wgd)";
    1273           2 :         Wee = weight_scale;
    1274           2 :         Wed = (weight_scale*(D - 2*E + G + M))/(3*D);
    1275           2 :         Wme = 0;
    1276           2 :         Wgg = (weight_scale*(G+M))/(2*G);
    1277           2 :         Wmg = weight_scale - Wgg;
    1278           2 :         Wmd = (weight_scale - Wed)/2;
    1279           2 :         Wgd = (weight_scale - Wed)/2;
    1280             : 
    1281           2 :         berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee,
    1282             :                       Wed, weight_scale, G, M, E, D, T, 10, 1);
    1283             :       }
    1284           3 :       if (berr) {
    1285           0 :         log_warn(LD_DIR,
    1286             :              "Bw Weights error %d for %s v10. G=%"PRId64" M=%"PRId64
    1287             :              " E=%"PRId64" D=%"PRId64" T=%"PRId64
    1288             :              " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d"
    1289             :              " Wgd=%d Wgg=%d Wme=%d Wmg=%d weight_scale=%d",
    1290             :              berr, casename,
    1291             :              (G), (M), (E),
    1292             :              (D), (T),
    1293             :              (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee,
    1294             :              (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg, (int)weight_scale);
    1295           0 :         return 0;
    1296             :       }
    1297             :     }
    1298             :   }
    1299             : 
    1300             :   /* We cast down the weights to 32 bit ints on the assumption that
    1301             :    * weight_scale is ~= 10000. We need to ensure a rogue authority
    1302             :    * doesn't break this assumption to rig our weights */
    1303          37 :   tor_assert(0 < weight_scale && weight_scale <= INT32_MAX);
    1304             : 
    1305             :   /*
    1306             :    * Provide Wgm=Wgg, Wmm=weight_scale, Wem=Wee, Weg=Wed. May later determine
    1307             :    * that middle nodes need different bandwidth weights for dirport traffic,
    1308             :    * or that weird exit policies need special weight, or that bridges
    1309             :    * need special weight.
    1310             :    *
    1311             :    * NOTE: This list is sorted.
    1312             :    */
    1313          37 :   smartlist_add_asprintf(chunks,
    1314             :      "bandwidth-weights Wbd=%d Wbe=%d Wbg=%d Wbm=%d "
    1315             :      "Wdb=%d "
    1316             :      "Web=%d Wed=%d Wee=%d Weg=%d Wem=%d "
    1317             :      "Wgb=%d Wgd=%d Wgg=%d Wgm=%d "
    1318             :      "Wmb=%d Wmd=%d Wme=%d Wmg=%d Wmm=%d\n",
    1319             :      (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale,
    1320             :      (int)weight_scale,
    1321             :      (int)weight_scale, (int)Wed, (int)Wee, (int)Wed, (int)Wee,
    1322             :      (int)weight_scale, (int)Wgd, (int)Wgg, (int)Wgg,
    1323             :      (int)weight_scale, (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale);
    1324             : 
    1325          37 :   log_notice(LD_CIRC, "Computed bandwidth weights for %s with v10: "
    1326             :              "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
    1327             :              " T=%"PRId64,
    1328             :              casename,
    1329             :              (G), (M), (E),
    1330             :              (D), (T));
    1331          37 :   return 1;
    1332             : }
    1333             : 
    1334             : /** Update total bandwidth weights (G/M/E/D/T) with the bandwidth of
    1335             :  *  the router in <b>rs</b>. */
    1336             : static void
    1337          78 : update_total_bandwidth_weights(const routerstatus_t *rs,
    1338             :                                int is_exit, int is_guard,
    1339             :                                int64_t *G, int64_t *M, int64_t *E, int64_t *D,
    1340             :                                int64_t *T)
    1341             : {
    1342          78 :   int default_bandwidth = rs->bandwidth_kb;
    1343          78 :   int guardfraction_bandwidth = 0;
    1344             : 
    1345          78 :   if (!rs->has_bandwidth) {
    1346           0 :     log_info(LD_BUG, "Missing consensus bandwidth for router %s",
    1347             :              rs->nickname);
    1348           0 :     return;
    1349             :   }
    1350             : 
    1351             :   /* If this routerstatus represents a guard that we have
    1352             :    * guardfraction information on, use it to calculate its actual
    1353             :    * bandwidth. From proposal236:
    1354             :    *
    1355             :    *    Similarly, when calculating the bandwidth-weights line as in
    1356             :    *    section 3.8.3 of dir-spec.txt, directory authorities should treat N
    1357             :    *    as if fraction F of its bandwidth has the guard flag and (1-F) does
    1358             :    *    not.  So when computing the totals G,M,E,D, each relay N with guard
    1359             :    *    visibility fraction F and bandwidth B should be added as follows:
    1360             :    *
    1361             :    *    G' = G + F*B, if N does not have the exit flag
    1362             :    *    M' = M + (1-F)*B, if N does not have the exit flag
    1363             :    *
    1364             :    *    or
    1365             :    *
    1366             :    *    D' = D + F*B, if N has the exit flag
    1367             :    *    E' = E + (1-F)*B, if N has the exit flag
    1368             :    *
    1369             :    * In this block of code, we prepare the bandwidth values by setting
    1370             :    * the default_bandwidth to F*B and guardfraction_bandwidth to (1-F)*B.
    1371             :    */
    1372          78 :   if (rs->has_guardfraction) {
    1373           0 :     guardfraction_bandwidth_t guardfraction_bw;
    1374             : 
    1375           0 :     tor_assert(is_guard);
    1376             : 
    1377           0 :     guard_get_guardfraction_bandwidth(&guardfraction_bw,
    1378             :                                       rs->bandwidth_kb,
    1379           0 :                                       rs->guardfraction_percentage);
    1380             : 
    1381           0 :     default_bandwidth = guardfraction_bw.guard_bw;
    1382           0 :     guardfraction_bandwidth = guardfraction_bw.non_guard_bw;
    1383             :   }
    1384             : 
    1385             :   /* Now calculate the total bandwidth weights with or without
    1386             :    * guardfraction. Depending on the flags of the relay, add its
    1387             :    * bandwidth to the appropriate weight pool. If it's a guard and
    1388             :    * guardfraction is enabled, add its bandwidth to both pools as
    1389             :    * indicated by the previous comment.
    1390             :    */
    1391          78 :   *T += default_bandwidth;
    1392          78 :   if (is_exit && is_guard) {
    1393             : 
    1394          42 :     *D += default_bandwidth;
    1395          42 :     if (rs->has_guardfraction) {
    1396           0 :       *E += guardfraction_bandwidth;
    1397             :     }
    1398             : 
    1399          36 :   } else if (is_exit) {
    1400             : 
    1401           0 :     *E += default_bandwidth;
    1402             : 
    1403          36 :   } else if (is_guard) {
    1404             : 
    1405           0 :     *G += default_bandwidth;
    1406           0 :     if (rs->has_guardfraction) {
    1407           0 :       *M += guardfraction_bandwidth;
    1408             :     }
    1409             : 
    1410             :   } else {
    1411             : 
    1412          36 :     *M += default_bandwidth;
    1413             :   }
    1414             : }
    1415             : 
    1416             : /** Considering the different recommended/required protocols sets as a
    1417             :  * 4-element array, return the element from <b>vote</b> for that protocol
    1418             :  * set.
    1419             :  */
    1420             : static const char *
    1421         288 : get_nth_protocol_set_vote(int n, const networkstatus_t *vote)
    1422             : {
    1423         288 :   switch (n) {
    1424          72 :     case 0: return vote->recommended_client_protocols;
    1425          72 :     case 1: return vote->recommended_relay_protocols;
    1426          72 :     case 2: return vote->required_client_protocols;
    1427          72 :     case 3: return vote->required_relay_protocols;
    1428           0 :     default:
    1429           0 :       tor_assert_unreached();
    1430             :       return NULL;
    1431             :   }
    1432             : }
    1433             : 
    1434             : /** Considering the different recommended/required protocols sets as a
    1435             :  * 4-element array, return a newly allocated string for the consensus value
    1436             :  * for the n'th set.
    1437             :  */
    1438             : static char *
    1439          96 : compute_nth_protocol_set(int n, int n_voters, const smartlist_t *votes)
    1440             : {
    1441          96 :   const char *keyword;
    1442          96 :   smartlist_t *proto_votes = smartlist_new();
    1443          96 :   int threshold;
    1444          96 :   switch (n) {
    1445          24 :     case 0:
    1446          24 :       keyword = "recommended-client-protocols";
    1447          24 :       threshold = CEIL_DIV(n_voters, 2);
    1448          24 :       break;
    1449          24 :     case 1:
    1450          24 :       keyword = "recommended-relay-protocols";
    1451          24 :       threshold = CEIL_DIV(n_voters, 2);
    1452          24 :       break;
    1453          24 :     case 2:
    1454          24 :       keyword = "required-client-protocols";
    1455          24 :       threshold = CEIL_DIV(n_voters * 2, 3);
    1456          24 :       break;
    1457          24 :     case 3:
    1458          24 :       keyword = "required-relay-protocols";
    1459          24 :       threshold = CEIL_DIV(n_voters * 2, 3);
    1460          24 :       break;
    1461           0 :     default:
    1462           0 :       tor_assert_unreached();
    1463             :       return NULL;
    1464             :   }
    1465             : 
    1466         384 :   SMARTLIST_FOREACH_BEGIN(votes, const networkstatus_t *, ns) {
    1467         288 :     const char *v = get_nth_protocol_set_vote(n, ns);
    1468         288 :     if (v)
    1469           0 :       smartlist_add(proto_votes, (void*)v);
    1470         288 :   } SMARTLIST_FOREACH_END(ns);
    1471             : 
    1472          96 :   char *protocols = protover_compute_vote(proto_votes, threshold);
    1473          96 :   smartlist_free(proto_votes);
    1474             : 
    1475          96 :   char *result = NULL;
    1476          96 :   tor_asprintf(&result, "%s %s\n", keyword, protocols);
    1477          96 :   tor_free(protocols);
    1478             : 
    1479          96 :   return result;
    1480             : }
    1481             : 
    1482             : /** Given a list of vote networkstatus_t in <b>votes</b>, our public
    1483             :  * authority <b>identity_key</b>, our private authority <b>signing_key</b>,
    1484             :  * and the number of <b>total_authorities</b> that we believe exist in our
    1485             :  * voting quorum, generate the text of a new v3 consensus or microdescriptor
    1486             :  * consensus (depending on <b>flavor</b>), and return the value in a newly
    1487             :  * allocated string.
    1488             :  *
    1489             :  * Note: this function DOES NOT check whether the votes are from
    1490             :  * recognized authorities.   (dirvote_add_vote does that.)
    1491             :  *
    1492             :  * <strong>WATCH OUT</strong>: You need to think before you change the
    1493             :  * behavior of this function, or of the functions it calls! If some
    1494             :  * authorities compute the consensus with a different algorithm than
    1495             :  * others, they will not reach the same result, and they will not all
    1496             :  * sign the same thing!  If you really need to change the algorithm
    1497             :  * here, you should allocate a new "consensus_method" for the new
    1498             :  * behavior, and make the new behavior conditional on a new-enough
    1499             :  * consensus_method.
    1500             :  **/
    1501             : STATIC char *
    1502          24 : networkstatus_compute_consensus(smartlist_t *votes,
    1503             :                                 int total_authorities,
    1504             :                                 crypto_pk_t *identity_key,
    1505             :                                 crypto_pk_t *signing_key,
    1506             :                                 const char *legacy_id_key_digest,
    1507             :                                 crypto_pk_t *legacy_signing_key,
    1508             :                                 consensus_flavor_t flavor)
    1509             : {
    1510          24 :   smartlist_t *chunks;
    1511          24 :   char *result = NULL;
    1512          24 :   int consensus_method;
    1513          24 :   time_t valid_after, fresh_until, valid_until;
    1514          24 :   int vote_seconds, dist_seconds;
    1515          24 :   char *client_versions = NULL, *server_versions = NULL;
    1516          24 :   smartlist_t *flags;
    1517          24 :   const char *flavor_name;
    1518          24 :   uint32_t max_unmeasured_bw_kb = DEFAULT_MAX_UNMEASURED_BW_KB;
    1519          24 :   int64_t G, M, E, D, T; /* For bandwidth weights */
    1520          48 :   const routerstatus_format_type_t rs_format =
    1521          24 :     flavor == FLAV_NS ? NS_V3_CONSENSUS : NS_V3_CONSENSUS_MICRODESC;
    1522          24 :   char *params = NULL;
    1523          24 :   char *packages = NULL;
    1524          24 :   int added_weights = 0;
    1525          24 :   dircollator_t *collator = NULL;
    1526          24 :   smartlist_t *param_list = NULL;
    1527             : 
    1528          24 :   tor_assert(flavor == FLAV_NS || flavor == FLAV_MICRODESC);
    1529          24 :   tor_assert(total_authorities >= smartlist_len(votes));
    1530          24 :   tor_assert(total_authorities > 0);
    1531             : 
    1532          24 :   flavor_name = networkstatus_get_flavor_name(flavor);
    1533             : 
    1534          24 :   if (!smartlist_len(votes)) {
    1535           0 :     log_warn(LD_DIR, "Can't compute a consensus from no votes.");
    1536           0 :     return NULL;
    1537             :   }
    1538          24 :   flags = smartlist_new();
    1539             : 
    1540          24 :   consensus_method = compute_consensus_method(votes);
    1541          24 :   if (consensus_method_is_supported(consensus_method)) {
    1542          24 :     log_info(LD_DIR, "Generating consensus using method %d.",
    1543             :              consensus_method);
    1544             :   } else {
    1545           0 :     log_warn(LD_DIR, "The other authorities will use consensus method %d, "
    1546             :              "which I don't support.  Maybe I should upgrade!",
    1547             :              consensus_method);
    1548           0 :     consensus_method = MAX_SUPPORTED_CONSENSUS_METHOD;
    1549             :   }
    1550             : 
    1551             :   {
    1552             :     /* It's smarter to initialize these weights to 1, so that later on,
    1553             :      * we can't accidentally divide by zero. */
    1554          24 :     G = M = E = D = 1;
    1555          24 :     T = 4;
    1556             :   }
    1557             : 
    1558             :   /* Compute medians of time-related things, and figure out how many
    1559             :    * routers we might need to talk about. */
    1560             :   {
    1561          24 :     int n_votes = smartlist_len(votes);
    1562          24 :     time_t *va_times = tor_calloc(n_votes, sizeof(time_t));
    1563          24 :     time_t *fu_times = tor_calloc(n_votes, sizeof(time_t));
    1564          24 :     time_t *vu_times = tor_calloc(n_votes, sizeof(time_t));
    1565          24 :     int *votesec_list = tor_calloc(n_votes, sizeof(int));
    1566          24 :     int *distsec_list = tor_calloc(n_votes, sizeof(int));
    1567          24 :     int n_versioning_clients = 0, n_versioning_servers = 0;
    1568          24 :     smartlist_t *combined_client_versions = smartlist_new();
    1569          24 :     smartlist_t *combined_server_versions = smartlist_new();
    1570             : 
    1571          96 :     SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
    1572          72 :       tor_assert(v->type == NS_TYPE_VOTE);
    1573          72 :       va_times[v_sl_idx] = v->valid_after;
    1574          72 :       fu_times[v_sl_idx] = v->fresh_until;
    1575          72 :       vu_times[v_sl_idx] = v->valid_until;
    1576          72 :       votesec_list[v_sl_idx] = v->vote_seconds;
    1577          72 :       distsec_list[v_sl_idx] = v->dist_seconds;
    1578          72 :       if (v->client_versions) {
    1579          48 :         smartlist_t *cv = smartlist_new();
    1580          48 :         ++n_versioning_clients;
    1581          48 :         smartlist_split_string(cv, v->client_versions, ",",
    1582             :                                SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    1583          48 :         sort_version_list(cv, 1);
    1584          48 :         smartlist_add_all(combined_client_versions, cv);
    1585          48 :         smartlist_free(cv); /* elements get freed later. */
    1586             :       }
    1587          72 :       if (v->server_versions) {
    1588          48 :         smartlist_t *sv = smartlist_new();
    1589          48 :         ++n_versioning_servers;
    1590          48 :         smartlist_split_string(sv, v->server_versions, ",",
    1591             :                                SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    1592          48 :         sort_version_list(sv, 1);
    1593          48 :         smartlist_add_all(combined_server_versions, sv);
    1594          48 :         smartlist_free(sv); /* elements get freed later. */
    1595             :       }
    1596         696 :       SMARTLIST_FOREACH(v->known_flags, const char *, cp,
    1597             :                         smartlist_add_strdup(flags, cp));
    1598          72 :     } SMARTLIST_FOREACH_END(v);
    1599          24 :     valid_after = median_time(va_times, n_votes);
    1600          24 :     fresh_until = median_time(fu_times, n_votes);
    1601          24 :     valid_until = median_time(vu_times, n_votes);
    1602          24 :     vote_seconds = median_int(votesec_list, n_votes);
    1603          24 :     dist_seconds = median_int(distsec_list, n_votes);
    1604             : 
    1605          48 :     tor_assert(valid_after +
    1606             :                (get_options()->TestingTorNetwork ?
    1607             :                 MIN_VOTE_INTERVAL_TESTING : MIN_VOTE_INTERVAL) <= fresh_until);
    1608          48 :     tor_assert(fresh_until +
    1609             :                (get_options()->TestingTorNetwork ?
    1610             :                 MIN_VOTE_INTERVAL_TESTING : MIN_VOTE_INTERVAL) <= valid_until);
    1611          24 :     tor_assert(vote_seconds >= MIN_VOTE_SECONDS);
    1612          24 :     tor_assert(dist_seconds >= MIN_DIST_SECONDS);
    1613             : 
    1614          24 :     server_versions = compute_consensus_versions_list(combined_server_versions,
    1615             :                                                       n_versioning_servers);
    1616          24 :     client_versions = compute_consensus_versions_list(combined_client_versions,
    1617             :                                                       n_versioning_clients);
    1618          24 :     packages = compute_consensus_package_lines(votes);
    1619             : 
    1620         168 :     SMARTLIST_FOREACH(combined_server_versions, char *, cp, tor_free(cp));
    1621         120 :     SMARTLIST_FOREACH(combined_client_versions, char *, cp, tor_free(cp));
    1622          24 :     smartlist_free(combined_server_versions);
    1623          24 :     smartlist_free(combined_client_versions);
    1624             : 
    1625          24 :     smartlist_add_strdup(flags, "NoEdConsensus");
    1626             : 
    1627          24 :     smartlist_sort_strings(flags);
    1628          24 :     smartlist_uniq_strings(flags);
    1629             : 
    1630          24 :     tor_free(va_times);
    1631          24 :     tor_free(fu_times);
    1632          24 :     tor_free(vu_times);
    1633          24 :     tor_free(votesec_list);
    1634          24 :     tor_free(distsec_list);
    1635             :   }
    1636             : 
    1637          24 :   chunks = smartlist_new();
    1638             : 
    1639             :   {
    1640          24 :     char va_buf[ISO_TIME_LEN+1], fu_buf[ISO_TIME_LEN+1],
    1641             :       vu_buf[ISO_TIME_LEN+1];
    1642          24 :     char *flaglist;
    1643          24 :     format_iso_time(va_buf, valid_after);
    1644          24 :     format_iso_time(fu_buf, fresh_until);
    1645          24 :     format_iso_time(vu_buf, valid_until);
    1646          24 :     flaglist = smartlist_join_strings(flags, " ", 0, NULL);
    1647             : 
    1648          48 :     smartlist_add_asprintf(chunks, "network-status-version 3%s%s\n"
    1649             :                  "vote-status consensus\n",
    1650             :                  flavor == FLAV_NS ? "" : " ",
    1651             :                  flavor == FLAV_NS ? "" : flavor_name);
    1652             : 
    1653          24 :     smartlist_add_asprintf(chunks, "consensus-method %d\n",
    1654             :                            consensus_method);
    1655             : 
    1656          24 :     smartlist_add_asprintf(chunks,
    1657             :                  "valid-after %s\n"
    1658             :                  "fresh-until %s\n"
    1659             :                  "valid-until %s\n"
    1660             :                  "voting-delay %d %d\n"
    1661             :                  "client-versions %s\n"
    1662             :                  "server-versions %s\n"
    1663             :                  "%s" /* packages */
    1664             :                  "known-flags %s\n",
    1665             :                  va_buf, fu_buf, vu_buf,
    1666             :                  vote_seconds, dist_seconds,
    1667             :                  client_versions, server_versions,
    1668             :                  packages,
    1669             :                  flaglist);
    1670             : 
    1671          24 :     tor_free(flaglist);
    1672             :   }
    1673             : 
    1674             :   {
    1675          24 :     int num_dirauth = get_n_authorities(V3_DIRINFO);
    1676          24 :     int idx;
    1677         144 :     for (idx = 0; idx < 4; ++idx) {
    1678          96 :       char *proto_line = compute_nth_protocol_set(idx, num_dirauth, votes);
    1679          96 :       if (BUG(!proto_line))
    1680           0 :         continue;
    1681          96 :       smartlist_add(chunks, proto_line);
    1682             :     }
    1683             :   }
    1684             : 
    1685          24 :   param_list = dirvote_compute_params(votes, consensus_method,
    1686             :                                       total_authorities);
    1687          24 :   if (smartlist_len(param_list)) {
    1688          24 :     params = smartlist_join_strings(param_list, " ", 0, NULL);
    1689          24 :     smartlist_add_strdup(chunks, "params ");
    1690          24 :     smartlist_add(chunks, params);
    1691          24 :     smartlist_add_strdup(chunks, "\n");
    1692             :   }
    1693             : 
    1694             :   {
    1695          24 :     int num_dirauth = get_n_authorities(V3_DIRINFO);
    1696             :     /* Default value of this is 2/3 of the total number of authorities. For
    1697             :      * instance, if we have 9 dirauth, the default value is 6. The following
    1698             :      * calculation will round it down. */
    1699          24 :     int32_t num_srv_agreements =
    1700          48 :       dirvote_get_intermediate_param_value(param_list,
    1701             :                                            "AuthDirNumSRVAgreements",
    1702          24 :                                            (num_dirauth * 2) / 3);
    1703             :     /* Add the shared random value. */
    1704          24 :     char *srv_lines = sr_get_string_for_consensus(votes, num_srv_agreements);
    1705          24 :     if (srv_lines != NULL) {
    1706           0 :       smartlist_add(chunks, srv_lines);
    1707             :     }
    1708             :   }
    1709             : 
    1710             :   /* Sort the votes. */
    1711          24 :   smartlist_sort(votes, compare_votes_by_authority_id_);
    1712             :   /* Add the authority sections. */
    1713             :   {
    1714          24 :     smartlist_t *dir_sources = smartlist_new();
    1715          96 :     SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
    1716          72 :       dir_src_ent_t *e = tor_malloc_zero(sizeof(dir_src_ent_t));
    1717          72 :       e->v = v;
    1718          72 :       e->digest = get_voter(v)->identity_digest;
    1719          72 :       e->is_legacy = 0;
    1720          72 :       smartlist_add(dir_sources, e);
    1721          72 :       if (!tor_digest_is_zero(get_voter(v)->legacy_id_digest)) {
    1722          24 :         dir_src_ent_t *e_legacy = tor_malloc_zero(sizeof(dir_src_ent_t));
    1723          24 :         e_legacy->v = v;
    1724          24 :         e_legacy->digest = get_voter(v)->legacy_id_digest;
    1725          24 :         e_legacy->is_legacy = 1;
    1726          24 :         smartlist_add(dir_sources, e_legacy);
    1727             :       }
    1728          72 :     } SMARTLIST_FOREACH_END(v);
    1729          24 :     smartlist_sort(dir_sources, compare_dir_src_ents_by_authority_id_);
    1730             : 
    1731         120 :     SMARTLIST_FOREACH_BEGIN(dir_sources, const dir_src_ent_t *, e) {
    1732          96 :       char fingerprint[HEX_DIGEST_LEN+1];
    1733          96 :       char votedigest[HEX_DIGEST_LEN+1];
    1734          96 :       networkstatus_t *v = e->v;
    1735          96 :       networkstatus_voter_info_t *voter = get_voter(v);
    1736             : 
    1737          96 :       base16_encode(fingerprint, sizeof(fingerprint), e->digest, DIGEST_LEN);
    1738          96 :       base16_encode(votedigest, sizeof(votedigest), voter->vote_digest,
    1739             :                     DIGEST_LEN);
    1740             : 
    1741          96 :       smartlist_add_asprintf(chunks,
    1742             :                    "dir-source %s%s %s %s %s %d %d\n",
    1743          96 :                    voter->nickname, e->is_legacy ? "-legacy" : "",
    1744          96 :                    fingerprint, voter->address, fmt_addr(&voter->ipv4_addr),
    1745          96 :                    voter->ipv4_dirport,
    1746          96 :                    voter->ipv4_orport);
    1747          96 :       if (! e->is_legacy) {
    1748          72 :         smartlist_add_asprintf(chunks,
    1749             :                      "contact %s\n"
    1750             :                      "vote-digest %s\n",
    1751             :                      voter->contact,
    1752             :                      votedigest);
    1753             :       }
    1754          96 :     } SMARTLIST_FOREACH_END(e);
    1755         120 :     SMARTLIST_FOREACH(dir_sources, dir_src_ent_t *, e, tor_free(e));
    1756          24 :     smartlist_free(dir_sources);
    1757             :   }
    1758             : 
    1759             :   {
    1760          24 :     if (consensus_method < MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE) {
    1761          12 :       max_unmeasured_bw_kb = (int32_t) extract_param_buggy(
    1762             :                   params, "maxunmeasuredbw", DEFAULT_MAX_UNMEASURED_BW_KB);
    1763             :     } else {
    1764          12 :       max_unmeasured_bw_kb = dirvote_get_intermediate_param_value(
    1765             :                   param_list, "maxunmeasurdbw", DEFAULT_MAX_UNMEASURED_BW_KB);
    1766          12 :       if (max_unmeasured_bw_kb < 1)
    1767             :         max_unmeasured_bw_kb = 1;
    1768             :     }
    1769             :   }
    1770             : 
    1771             :   /* Add the actual router entries. */
    1772             :   {
    1773          24 :     int *size; /* size[j] is the number of routerstatuses in votes[j]. */
    1774          24 :     int *flag_counts; /* The number of voters that list flag[j] for the
    1775             :                        * currently considered router. */
    1776          24 :     int i;
    1777          24 :     smartlist_t *matching_descs = smartlist_new();
    1778          24 :     smartlist_t *chosen_flags = smartlist_new();
    1779          24 :     smartlist_t *versions = smartlist_new();
    1780          24 :     smartlist_t *protocols = smartlist_new();
    1781          24 :     smartlist_t *exitsummaries = smartlist_new();
    1782          24 :     uint32_t *bandwidths_kb = tor_calloc(smartlist_len(votes),
    1783             :                                          sizeof(uint32_t));
    1784          24 :     uint32_t *measured_bws_kb = tor_calloc(smartlist_len(votes),
    1785             :                                            sizeof(uint32_t));
    1786          24 :     uint32_t *measured_guardfraction = tor_calloc(smartlist_len(votes),
    1787             :                                                   sizeof(uint32_t));
    1788          24 :     int num_bandwidths;
    1789          24 :     int num_mbws;
    1790          24 :     int num_guardfraction_inputs;
    1791             : 
    1792          24 :     int *n_voter_flags; /* n_voter_flags[j] is the number of flags that
    1793             :                          * votes[j] knows about. */
    1794          24 :     int *n_flag_voters; /* n_flag_voters[f] is the number of votes that care
    1795             :                          * about flags[f]. */
    1796          24 :     int **flag_map; /* flag_map[j][b] is an index f such that flag_map[f]
    1797             :                      * is the same flag as votes[j]->known_flags[b]. */
    1798          24 :     int *named_flag; /* Index of the flag "Named" for votes[j] */
    1799          24 :     int *unnamed_flag; /* Index of the flag "Unnamed" for votes[j] */
    1800          24 :     int n_authorities_measuring_bandwidth;
    1801             : 
    1802          24 :     strmap_t *name_to_id_map = strmap_new();
    1803          24 :     char conflict[DIGEST_LEN];
    1804          24 :     char unknown[DIGEST_LEN];
    1805          24 :     memset(conflict, 0, sizeof(conflict));
    1806          24 :     memset(unknown, 0xff, sizeof(conflict));
    1807             : 
    1808          24 :     size = tor_calloc(smartlist_len(votes), sizeof(int));
    1809          24 :     n_voter_flags = tor_calloc(smartlist_len(votes), sizeof(int));
    1810          24 :     n_flag_voters = tor_calloc(smartlist_len(flags), sizeof(int));
    1811          24 :     flag_map = tor_calloc(smartlist_len(votes), sizeof(int *));
    1812          24 :     named_flag = tor_calloc(smartlist_len(votes), sizeof(int));
    1813          24 :     unnamed_flag = tor_calloc(smartlist_len(votes), sizeof(int));
    1814         120 :     for (i = 0; i < smartlist_len(votes); ++i)
    1815          72 :       unnamed_flag[i] = named_flag[i] = -1;
    1816             : 
    1817             :     /* Build the flag indexes. Note that no vote can have more than 64 members
    1818             :      * for known_flags, so no value will be greater than 63, so it's safe to
    1819             :      * do UINT64_C(1) << index on these values.  But note also that
    1820             :      * named_flag and unnamed_flag are initialized to -1, so we need to check
    1821             :      * that they're actually set before doing UINT64_C(1) << index with
    1822             :      * them.*/
    1823          96 :     SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
    1824          72 :       flag_map[v_sl_idx] = tor_calloc(smartlist_len(v->known_flags),
    1825             :                                       sizeof(int));
    1826          72 :       if (smartlist_len(v->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) {
    1827           0 :         log_warn(LD_BUG, "Somehow, a vote has %d entries in known_flags",
    1828             :                  smartlist_len(v->known_flags));
    1829             :       }
    1830         696 :       SMARTLIST_FOREACH_BEGIN(v->known_flags, const char *, fl) {
    1831         624 :         int p = smartlist_string_pos(flags, fl);
    1832         624 :         tor_assert(p >= 0);
    1833         624 :         flag_map[v_sl_idx][fl_sl_idx] = p;
    1834         624 :         ++n_flag_voters[p];
    1835         624 :         if (!strcmp(fl, "Named"))
    1836           0 :           named_flag[v_sl_idx] = fl_sl_idx;
    1837         624 :         if (!strcmp(fl, "Unnamed"))
    1838           0 :           unnamed_flag[v_sl_idx] = fl_sl_idx;
    1839         624 :       } SMARTLIST_FOREACH_END(fl);
    1840          72 :       n_voter_flags[v_sl_idx] = smartlist_len(v->known_flags);
    1841          72 :       size[v_sl_idx] = smartlist_len(v->routerstatus_list);
    1842          72 :     } SMARTLIST_FOREACH_END(v);
    1843             : 
    1844             :     /* Named and Unnamed get treated specially */
    1845             :     {
    1846          96 :       SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
    1847          72 :         uint64_t nf;
    1848          72 :         if (named_flag[v_sl_idx]<0)
    1849          72 :           continue;
    1850           0 :         nf = UINT64_C(1) << named_flag[v_sl_idx];
    1851           0 :         SMARTLIST_FOREACH_BEGIN(v->routerstatus_list,
    1852             :                                 vote_routerstatus_t *, rs) {
    1853             : 
    1854           0 :           if ((rs->flags & nf) != 0) {
    1855           0 :             const char *d = strmap_get_lc(name_to_id_map, rs->status.nickname);
    1856           0 :             if (!d) {
    1857             :               /* We have no name officially mapped to this digest. */
    1858           0 :               strmap_set_lc(name_to_id_map, rs->status.nickname,
    1859           0 :                             rs->status.identity_digest);
    1860           0 :             } else if (d != conflict &&
    1861           0 :                 fast_memcmp(d, rs->status.identity_digest, DIGEST_LEN)) {
    1862             :               /* Authorities disagree about this nickname. */
    1863           0 :               strmap_set_lc(name_to_id_map, rs->status.nickname, conflict);
    1864             :             } else {
    1865             :               /* It's already a conflict, or it's already this ID. */
    1866           0 :             }
    1867             :           }
    1868           0 :         } SMARTLIST_FOREACH_END(rs);
    1869          72 :       } SMARTLIST_FOREACH_END(v);
    1870             : 
    1871          96 :       SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
    1872          72 :         uint64_t uf;
    1873          72 :         if (unnamed_flag[v_sl_idx]<0)
    1874          72 :           continue;
    1875           0 :         uf = UINT64_C(1) << unnamed_flag[v_sl_idx];
    1876           0 :         SMARTLIST_FOREACH_BEGIN(v->routerstatus_list,
    1877             :                                 vote_routerstatus_t *, rs) {
    1878           0 :           if ((rs->flags & uf) != 0) {
    1879           0 :             const char *d = strmap_get_lc(name_to_id_map, rs->status.nickname);
    1880           0 :             if (d == conflict || d == unknown) {
    1881             :               /* Leave it alone; we know what it is. */
    1882           0 :             } else if (!d) {
    1883             :               /* We have no name officially mapped to this digest. */
    1884           0 :               strmap_set_lc(name_to_id_map, rs->status.nickname, unknown);
    1885           0 :             } else if (fast_memeq(d, rs->status.identity_digest, DIGEST_LEN)) {
    1886             :               /* Authorities disagree about this nickname. */
    1887           0 :               strmap_set_lc(name_to_id_map, rs->status.nickname, conflict);
    1888             :             } else {
    1889             :               /* It's mapped to a different name. */
    1890           0 :             }
    1891             :           }
    1892           0 :         } SMARTLIST_FOREACH_END(rs);
    1893          72 :       } SMARTLIST_FOREACH_END(v);
    1894             :     }
    1895             : 
    1896             :     /* We need to know how many votes measure bandwidth. */
    1897          24 :     n_authorities_measuring_bandwidth = 0;
    1898          96 :     SMARTLIST_FOREACH(votes, const networkstatus_t *, v,
    1899             :        if (v->has_measured_bws) {
    1900             :          ++n_authorities_measuring_bandwidth;
    1901             :        }
    1902             :     );
    1903             : 
    1904             :     /* Populate the collator */
    1905          24 :     collator = dircollator_new(smartlist_len(votes), total_authorities);
    1906          96 :     SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
    1907          72 :       dircollator_add_vote(collator, v);
    1908          72 :     } SMARTLIST_FOREACH_END(v);
    1909             : 
    1910          24 :     dircollator_collate(collator, consensus_method);
    1911             : 
    1912             :     /* Now go through all the votes */
    1913          24 :     flag_counts = tor_calloc(smartlist_len(flags), sizeof(int));
    1914          24 :     const int num_routers = dircollator_n_routers(collator);
    1915         138 :     for (i = 0; i < num_routers; ++i) {
    1916          90 :       vote_routerstatus_t **vrs_lst =
    1917          90 :         dircollator_get_votes_for_router(collator, i);
    1918             : 
    1919          90 :       vote_routerstatus_t *rs;
    1920          90 :       routerstatus_t rs_out;
    1921          90 :       const char *current_rsa_id = NULL;
    1922          90 :       const char *chosen_version;
    1923          90 :       const char *chosen_protocol_list;
    1924          90 :       const char *chosen_name = NULL;
    1925          90 :       int exitsummary_disagreement = 0;
    1926          90 :       int is_named = 0, is_unnamed = 0, is_running = 0, is_valid = 0;
    1927          90 :       int is_guard = 0, is_exit = 0, is_bad_exit = 0;
    1928          90 :       int naming_conflict = 0;
    1929          90 :       int n_listing = 0;
    1930          90 :       char microdesc_digest[DIGEST256_LEN];
    1931          90 :       tor_addr_port_t alt_orport = {TOR_ADDR_NULL, 0};
    1932             : 
    1933          90 :       memset(flag_counts, 0, sizeof(int)*smartlist_len(flags));
    1934          90 :       smartlist_clear(matching_descs);
    1935          90 :       smartlist_clear(chosen_flags);
    1936          90 :       smartlist_clear(versions);
    1937          90 :       smartlist_clear(protocols);
    1938          90 :       num_bandwidths = 0;
    1939          90 :       num_mbws = 0;
    1940          90 :       num_guardfraction_inputs = 0;
    1941          90 :       int ed_consensus = 0;
    1942          90 :       const uint8_t *ed_consensus_val = NULL;
    1943             : 
    1944             :       /* Okay, go through all the entries for this digest. */
    1945         360 :       for (int voter_idx = 0; voter_idx < smartlist_len(votes); ++voter_idx) {
    1946         270 :         if (vrs_lst[voter_idx] == NULL)
    1947           6 :           continue; /* This voter had nothing to say about this entry. */
    1948         264 :         rs = vrs_lst[voter_idx];
    1949         264 :         ++n_listing;
    1950             : 
    1951         264 :         current_rsa_id = rs->status.identity_digest;
    1952             : 
    1953         264 :         smartlist_add(matching_descs, rs);
    1954         264 :         if (rs->version && rs->version[0])
    1955         264 :           smartlist_add(versions, rs->version);
    1956             : 
    1957         264 :         if (rs->protocols) {
    1958             :           /* We include this one even if it's empty: voting for an
    1959             :            * empty protocol list actually is meaningful. */
    1960         264 :           smartlist_add(protocols, rs->protocols);
    1961             :         }
    1962             : 
    1963             :         /* Tally up all the flags. */
    1964        2556 :         for (int flag = 0; flag < n_voter_flags[voter_idx]; ++flag) {
    1965        2292 :           if (rs->flags & (UINT64_C(1) << flag))
    1966        1134 :             ++flag_counts[flag_map[voter_idx][flag]];
    1967             :         }
    1968         264 :         if (named_flag[voter_idx] >= 0 &&
    1969           0 :             (rs->flags & (UINT64_C(1) << named_flag[voter_idx]))) {
    1970           0 :           if (chosen_name && strcmp(chosen_name, rs->status.nickname)) {
    1971           0 :             log_notice(LD_DIR, "Conflict on naming for router: %s vs %s",
    1972             :                        chosen_name, rs->status.nickname);
    1973           0 :             naming_conflict = 1;
    1974             :           }
    1975           0 :           chosen_name = rs->status.nickname;
    1976             :         }
    1977             : 
    1978             :         /* Count guardfraction votes and note down the values. */
    1979         264 :         if (rs->status.has_guardfraction) {
    1980           0 :           measured_guardfraction[num_guardfraction_inputs++] =
    1981           0 :             rs->status.guardfraction_percentage;
    1982             :         }
    1983             : 
    1984             :         /* count bandwidths */
    1985         264 :         if (rs->has_measured_bw)
    1986          72 :           measured_bws_kb[num_mbws++] = rs->measured_bw_kb;
    1987             : 
    1988         264 :         if (rs->status.has_bandwidth)
    1989         264 :           bandwidths_kb[num_bandwidths++] = rs->status.bandwidth_kb;
    1990             : 
    1991             :         /* Count number for which ed25519 is canonical. */
    1992         264 :         if (rs->ed25519_reflects_consensus) {
    1993         264 :           ++ed_consensus;
    1994         264 :           if (ed_consensus_val) {
    1995         174 :             tor_assert(fast_memeq(ed_consensus_val, rs->ed25519_id,
    1996             :                                   ED25519_PUBKEY_LEN));
    1997             :           } else {
    1998          90 :             ed_consensus_val = rs->ed25519_id;
    1999             :           }
    2000             :         }
    2001             :       }
    2002             : 
    2003             :       /* We don't include this router at all unless more than half of
    2004             :        * the authorities we believe in list it. */
    2005          90 :       if (n_listing <= total_authorities/2)
    2006          12 :         continue;
    2007             : 
    2008          90 :       if (ed_consensus > 0) {
    2009          90 :         if (ed_consensus <= total_authorities / 2) {
    2010           0 :           log_warn(LD_BUG, "Not enough entries had ed_consensus set; how "
    2011             :                    "can we have a consensus of %d?", ed_consensus);
    2012             :         }
    2013             :       }
    2014             : 
    2015             :       /* The clangalyzer can't figure out that this will never be NULL
    2016             :        * if n_listing is at least 1 */
    2017          90 :       tor_assert(current_rsa_id);
    2018             : 
    2019             :       /* Figure out the most popular opinion of what the most recent
    2020             :        * routerinfo and its contents are. */
    2021          90 :       memset(microdesc_digest, 0, sizeof(microdesc_digest));
    2022          90 :       rs = compute_routerstatus_consensus(matching_descs, consensus_method,
    2023             :                                           microdesc_digest, &alt_orport);
    2024             :       /* Copy bits of that into rs_out. */
    2025          90 :       memset(&rs_out, 0, sizeof(rs_out));
    2026          90 :       tor_assert(fast_memeq(current_rsa_id,
    2027             :                             rs->status.identity_digest,DIGEST_LEN));
    2028          90 :       memcpy(rs_out.identity_digest, current_rsa_id, DIGEST_LEN);
    2029          90 :       memcpy(rs_out.descriptor_digest, rs->status.descriptor_digest,
    2030             :              DIGEST_LEN);
    2031          90 :       tor_addr_copy(&rs_out.ipv4_addr, &rs->status.ipv4_addr);
    2032          90 :       rs_out.published_on = rs->status.published_on;
    2033          90 :       rs_out.ipv4_dirport = rs->status.ipv4_dirport;
    2034          90 :       rs_out.ipv4_orport = rs->status.ipv4_orport;
    2035          90 :       tor_addr_copy(&rs_out.ipv6_addr, &alt_orport.addr);
    2036          90 :       rs_out.ipv6_orport = alt_orport.port;
    2037          90 :       rs_out.has_bandwidth = 0;
    2038          90 :       rs_out.has_exitsummary = 0;
    2039             : 
    2040          90 :       if (chosen_name && !naming_conflict) {
    2041           0 :         strlcpy(rs_out.nickname, chosen_name, sizeof(rs_out.nickname));
    2042             :       } else {
    2043          90 :         strlcpy(rs_out.nickname, rs->status.nickname, sizeof(rs_out.nickname));
    2044             :       }
    2045             : 
    2046             :       {
    2047          90 :         const char *d = strmap_get_lc(name_to_id_map, rs_out.nickname);
    2048          90 :         if (!d) {
    2049             :           is_named = is_unnamed = 0;
    2050           0 :         } else if (fast_memeq(d, current_rsa_id, DIGEST_LEN)) {
    2051             :           is_named = 1; is_unnamed = 0;
    2052             :         } else {
    2053           0 :           is_named = 0; is_unnamed = 1;
    2054             :         }
    2055             :       }
    2056             : 
    2057             :       /* Set the flags. */
    2058          90 :       smartlist_add(chosen_flags, (char*)"s"); /* for the start of the line. */
    2059        1080 :       SMARTLIST_FOREACH_BEGIN(flags, const char *, fl) {
    2060         990 :         if (!strcmp(fl, "Named")) {
    2061           0 :           if (is_named)
    2062           0 :             smartlist_add(chosen_flags, (char*)fl);
    2063         990 :         } else if (!strcmp(fl, "Unnamed")) {
    2064           0 :           if (is_unnamed)
    2065           0 :             smartlist_add(chosen_flags, (char*)fl);
    2066         990 :         } else if (!strcmp(fl, "NoEdConsensus")) {
    2067          90 :           if (ed_consensus <= total_authorities/2)
    2068           0 :             smartlist_add(chosen_flags, (char*)fl);
    2069             :         } else {
    2070         900 :           if (flag_counts[fl_sl_idx] > n_flag_voters[fl_sl_idx]/2) {
    2071         384 :             smartlist_add(chosen_flags, (char*)fl);
    2072         384 :             if (!strcmp(fl, "Exit"))
    2073             :               is_exit = 1;
    2074         342 :             else if (!strcmp(fl, "Guard"))
    2075             :               is_guard = 1;
    2076         300 :             else if (!strcmp(fl, "Running"))
    2077             :               is_running = 1;
    2078         222 :             else if (!strcmp(fl, "BadExit"))
    2079             :               is_bad_exit = 1;
    2080         222 :             else if (!strcmp(fl, "Valid"))
    2081          78 :               is_valid = 1;
    2082             :           }
    2083             :         }
    2084         990 :       } SMARTLIST_FOREACH_END(fl);
    2085             : 
    2086             :       /* Starting with consensus method 4 we do not list servers
    2087             :        * that are not running in a consensus.  See Proposal 138 */
    2088          90 :       if (!is_running)
    2089          12 :         continue;
    2090             : 
    2091             :       /* Starting with consensus method 24, we don't list servers
    2092             :        * that are not valid in a consensus.  See Proposal 272 */
    2093          78 :       if (!is_valid)
    2094           0 :         continue;
    2095             : 
    2096             :       /* Pick the version. */
    2097          78 :       if (smartlist_len(versions)) {
    2098          78 :         sort_version_list(versions, 0);
    2099          78 :         chosen_version = get_most_frequent_member(versions);
    2100             :       } else {
    2101             :         chosen_version = NULL;
    2102             :       }
    2103             : 
    2104             :       /* Pick the protocol list */
    2105          78 :       if (smartlist_len(protocols)) {
    2106          78 :         smartlist_sort_strings(protocols);
    2107          78 :         chosen_protocol_list = get_most_frequent_member(protocols);
    2108             :       } else {
    2109             :         chosen_protocol_list = NULL;
    2110             :       }
    2111             : 
    2112             :       /* If it's a guard and we have enough guardfraction votes,
    2113             :          calculate its consensus guardfraction value. */
    2114          78 :       if (is_guard && num_guardfraction_inputs > 2) {
    2115           0 :         rs_out.has_guardfraction = 1;
    2116           0 :         rs_out.guardfraction_percentage = median_uint32(measured_guardfraction,
    2117             :                                                      num_guardfraction_inputs);
    2118             :         /* final value should be an integer percentage! */
    2119           0 :         tor_assert(rs_out.guardfraction_percentage <= 100);
    2120             :       }
    2121             : 
    2122             :       /* Pick a bandwidth */
    2123          78 :       if (num_mbws > 2) {
    2124          24 :         rs_out.has_bandwidth = 1;
    2125          24 :         rs_out.bw_is_unmeasured = 0;
    2126          24 :         rs_out.bandwidth_kb = median_uint32(measured_bws_kb, num_mbws);
    2127          54 :       } else if (num_bandwidths > 0) {
    2128          54 :         rs_out.has_bandwidth = 1;
    2129          54 :         rs_out.bw_is_unmeasured = 1;
    2130          54 :         rs_out.bandwidth_kb = median_uint32(bandwidths_kb, num_bandwidths);
    2131          54 :         if (n_authorities_measuring_bandwidth > 2) {
    2132             :           /* Cap non-measured bandwidths. */
    2133          24 :           if (rs_out.bandwidth_kb > max_unmeasured_bw_kb) {
    2134          12 :             rs_out.bandwidth_kb = max_unmeasured_bw_kb;
    2135             :           }
    2136             :         }
    2137             :       }
    2138             : 
    2139             :       /* Fix bug 2203: Do not count BadExit nodes as Exits for bw weights */
    2140          78 :       is_exit = is_exit && !is_bad_exit;
    2141             : 
    2142             :       /* Update total bandwidth weights with the bandwidths of this router. */
    2143             :       {
    2144          78 :         update_total_bandwidth_weights(&rs_out,
    2145             :                                        is_exit, is_guard,
    2146             :                                        &G, &M, &E, &D, &T);
    2147             :       }
    2148             : 
    2149             :       /* Ok, we already picked a descriptor digest we want to list
    2150             :        * previously.  Now we want to use the exit policy summary from
    2151             :        * that descriptor.  If everybody plays nice all the voters who
    2152             :        * listed that descriptor will have the same summary.  If not then
    2153             :        * something is fishy and we'll use the most common one (breaking
    2154             :        * ties in favor of lexicographically larger one (only because it
    2155             :        * lets me reuse more existing code)).
    2156             :        *
    2157             :        * The other case that can happen is that no authority that voted
    2158             :        * for that descriptor has an exit policy summary.  That's
    2159             :        * probably quite unlikely but can happen.  In that case we use
    2160             :        * the policy that was most often listed in votes, again breaking
    2161             :        * ties like in the previous case.
    2162             :        */
    2163             :       {
    2164             :         /* Okay, go through all the votes for this router.  We prepared
    2165             :          * that list previously */
    2166          78 :         const char *chosen_exitsummary = NULL;
    2167          78 :         smartlist_clear(exitsummaries);
    2168         306 :         SMARTLIST_FOREACH_BEGIN(matching_descs, vote_routerstatus_t *, vsr) {
    2169             :           /* Check if the vote where this status comes from had the
    2170             :            * proper descriptor */
    2171         228 :           tor_assert(fast_memeq(rs_out.identity_digest,
    2172             :                              vsr->status.identity_digest,
    2173             :                              DIGEST_LEN));
    2174         228 :           if (vsr->status.has_exitsummary &&
    2175         228 :                fast_memeq(rs_out.descriptor_digest,
    2176             :                        vsr->status.descriptor_digest,
    2177             :                        DIGEST_LEN)) {
    2178         222 :             tor_assert(vsr->status.exitsummary);
    2179         222 :             smartlist_add(exitsummaries, vsr->status.exitsummary);
    2180         222 :             if (!chosen_exitsummary) {
    2181          78 :               chosen_exitsummary = vsr->status.exitsummary;
    2182         144 :             } else if (strcmp(chosen_exitsummary, vsr->status.exitsummary)) {
    2183             :               /* Great.  There's disagreement among the voters.  That
    2184             :                * really shouldn't be */
    2185           0 :               exitsummary_disagreement = 1;
    2186             :             }
    2187             :           }
    2188         228 :         } SMARTLIST_FOREACH_END(vsr);
    2189             : 
    2190          78 :         if (exitsummary_disagreement) {
    2191           0 :           char id[HEX_DIGEST_LEN+1];
    2192           0 :           char dd[HEX_DIGEST_LEN+1];
    2193           0 :           base16_encode(id, sizeof(dd), rs_out.identity_digest, DIGEST_LEN);
    2194           0 :           base16_encode(dd, sizeof(dd), rs_out.descriptor_digest, DIGEST_LEN);
    2195           0 :           log_warn(LD_DIR, "The voters disagreed on the exit policy summary "
    2196             :                    " for router %s with descriptor %s.  This really shouldn't"
    2197             :                    " have happened.", id, dd);
    2198             : 
    2199           0 :           smartlist_sort_strings(exitsummaries);
    2200           0 :           chosen_exitsummary = get_most_frequent_member(exitsummaries);
    2201          78 :         } else if (!chosen_exitsummary) {
    2202           0 :           char id[HEX_DIGEST_LEN+1];
    2203           0 :           char dd[HEX_DIGEST_LEN+1];
    2204           0 :           base16_encode(id, sizeof(dd), rs_out.identity_digest, DIGEST_LEN);
    2205           0 :           base16_encode(dd, sizeof(dd), rs_out.descriptor_digest, DIGEST_LEN);
    2206           0 :           log_warn(LD_DIR, "Not one of the voters that made us select"
    2207             :                    "descriptor %s for router %s had an exit policy"
    2208             :                    "summary", dd, id);
    2209             : 
    2210             :           /* Ok, none of those voting for the digest we chose had an
    2211             :            * exit policy for us.  Well, that kinda sucks.
    2212             :            */
    2213           0 :           smartlist_clear(exitsummaries);
    2214           0 :           SMARTLIST_FOREACH(matching_descs, vote_routerstatus_t *, vsr, {
    2215             :             if (vsr->status.has_exitsummary)
    2216             :               smartlist_add(exitsummaries, vsr->status.exitsummary);
    2217             :           });
    2218           0 :           smartlist_sort_strings(exitsummaries);
    2219           0 :           chosen_exitsummary = get_most_frequent_member(exitsummaries);
    2220             : 
    2221           0 :           if (!chosen_exitsummary)
    2222           0 :             log_warn(LD_DIR, "Wow, not one of the voters had an exit "
    2223             :                      "policy summary for %s.  Wow.", id);
    2224             :         }
    2225             : 
    2226          78 :         if (chosen_exitsummary) {
    2227          78 :           rs_out.has_exitsummary = 1;
    2228             :           /* yea, discards the const */
    2229          78 :           rs_out.exitsummary = (char *)chosen_exitsummary;
    2230             :         }
    2231             :       }
    2232             : 
    2233         126 :       if (flavor == FLAV_MICRODESC &&
    2234          48 :           tor_digest256_is_zero(microdesc_digest)) {
    2235             :         /* With no microdescriptor digest, we omit the entry entirely. */
    2236           0 :         continue;
    2237             :       }
    2238             : 
    2239             :       {
    2240          78 :         char *buf;
    2241             :         /* Okay!! Now we can write the descriptor... */
    2242             :         /*     First line goes into "buf". */
    2243          78 :         buf = routerstatus_format_entry(&rs_out, NULL, NULL,
    2244             :                                         rs_format, NULL);
    2245          78 :         if (buf)
    2246          78 :           smartlist_add(chunks, buf);
    2247             :       }
    2248             :       /*     Now an m line, if applicable. */
    2249         126 :       if (flavor == FLAV_MICRODESC &&
    2250          48 :           !tor_digest256_is_zero(microdesc_digest)) {
    2251          48 :         char m[BASE64_DIGEST256_LEN+1];
    2252          48 :         digest256_to_base64(m, microdesc_digest);
    2253          48 :         smartlist_add_asprintf(chunks, "m %s\n", m);
    2254             :       }
    2255             :       /*     Next line is all flags.  The "\n" is missing. */
    2256          78 :       smartlist_add(chunks,
    2257          78 :                     smartlist_join_strings(chosen_flags, " ", 0, NULL));
    2258             :       /*     Now the version line. */
    2259          78 :       if (chosen_version) {
    2260          78 :         smartlist_add_strdup(chunks, "\nv ");
    2261          78 :         smartlist_add_strdup(chunks, chosen_version);
    2262             :       }
    2263          78 :       smartlist_add_strdup(chunks, "\n");
    2264          78 :       if (chosen_protocol_list) {
    2265          78 :         smartlist_add_asprintf(chunks, "pr %s\n", chosen_protocol_list);
    2266             :       }
    2267             :       /*     Now the weight line. */
    2268          78 :       if (rs_out.has_bandwidth) {
    2269          78 :         char *guardfraction_str = NULL;
    2270          78 :         int unmeasured = rs_out.bw_is_unmeasured;
    2271             : 
    2272             :         /* If we have guardfraction info, include it in the 'w' line. */
    2273          78 :         if (rs_out.has_guardfraction) {
    2274           0 :           tor_asprintf(&guardfraction_str,
    2275             :                        " GuardFraction=%u", rs_out.guardfraction_percentage);
    2276             :         }
    2277         102 :         smartlist_add_asprintf(chunks, "w Bandwidth=%d%s%s\n",
    2278             :                                rs_out.bandwidth_kb,
    2279             :                                unmeasured?" Unmeasured=1":"",
    2280          78 :                                guardfraction_str ? guardfraction_str : "");
    2281             : 
    2282          78 :         tor_free(guardfraction_str);
    2283             :       }
    2284             : 
    2285             :       /*     Now the exitpolicy summary line. */
    2286          78 :       if (rs_out.has_exitsummary && flavor == FLAV_NS) {
    2287          30 :         smartlist_add_asprintf(chunks, "p %s\n", rs_out.exitsummary);
    2288             :       }
    2289             : 
    2290             :       /* And the loop is over and we move on to the next router */
    2291             :     }
    2292             : 
    2293          24 :     tor_free(size);
    2294          24 :     tor_free(n_voter_flags);
    2295          24 :     tor_free(n_flag_voters);
    2296          96 :     for (i = 0; i < smartlist_len(votes); ++i)
    2297          72 :       tor_free(flag_map[i]);
    2298          24 :     tor_free(flag_map);
    2299          24 :     tor_free(flag_counts);
    2300          24 :     tor_free(named_flag);
    2301          24 :     tor_free(unnamed_flag);
    2302          24 :     strmap_free(name_to_id_map, NULL);
    2303          24 :     smartlist_free(matching_descs);
    2304          24 :     smartlist_free(chosen_flags);
    2305          24 :     smartlist_free(versions);
    2306          24 :     smartlist_free(protocols);
    2307          24 :     smartlist_free(exitsummaries);
    2308          24 :     tor_free(bandwidths_kb);
    2309          24 :     tor_free(measured_bws_kb);
    2310          24 :     tor_free(measured_guardfraction);
    2311             :   }
    2312             : 
    2313             :   /* Mark the directory footer region */
    2314          24 :   smartlist_add_strdup(chunks, "directory-footer\n");
    2315             : 
    2316             :   {
    2317          24 :     int64_t weight_scale;
    2318          24 :     if (consensus_method < MIN_METHOD_FOR_CORRECT_BWWEIGHTSCALE) {
    2319          12 :       weight_scale = extract_param_buggy(params, "bwweightscale",
    2320             :                                          BW_WEIGHT_SCALE);
    2321             :     } else {
    2322          12 :       weight_scale = dirvote_get_intermediate_param_value(
    2323             :                        param_list, "bwweightscale", BW_WEIGHT_SCALE);
    2324          12 :       if (weight_scale < 1)
    2325             :         weight_scale = 1;
    2326             :     }
    2327          24 :     added_weights = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D,
    2328             :                                                          T, weight_scale);
    2329             :   }
    2330             : 
    2331             :   /* Add a signature. */
    2332             :   {
    2333          24 :     char digest[DIGEST256_LEN];
    2334          24 :     char fingerprint[HEX_DIGEST_LEN+1];
    2335          24 :     char signing_key_fingerprint[HEX_DIGEST_LEN+1];
    2336          24 :     digest_algorithm_t digest_alg =
    2337          24 :       flavor == FLAV_NS ? DIGEST_SHA1 : DIGEST_SHA256;
    2338          48 :     size_t digest_len =
    2339          24 :       flavor == FLAV_NS ? DIGEST_LEN : DIGEST256_LEN;
    2340          24 :     const char *algname = crypto_digest_algorithm_get_name(digest_alg);
    2341          24 :     char *signature;
    2342             : 
    2343          24 :     smartlist_add_strdup(chunks, "directory-signature ");
    2344             : 
    2345             :     /* Compute the hash of the chunks. */
    2346          24 :     crypto_digest_smartlist(digest, digest_len, chunks, "", digest_alg);
    2347             : 
    2348             :     /* Get the fingerprints */
    2349          24 :     crypto_pk_get_fingerprint(identity_key, fingerprint, 0);
    2350          24 :     crypto_pk_get_fingerprint(signing_key, signing_key_fingerprint, 0);
    2351             : 
    2352             :     /* add the junk that will go at the end of the line. */
    2353          24 :     if (flavor == FLAV_NS) {
    2354           9 :       smartlist_add_asprintf(chunks, "%s %s\n", fingerprint,
    2355             :                    signing_key_fingerprint);
    2356             :     } else {
    2357          15 :       smartlist_add_asprintf(chunks, "%s %s %s\n",
    2358             :                    algname, fingerprint,
    2359             :                    signing_key_fingerprint);
    2360             :     }
    2361             :     /* And the signature. */
    2362          24 :     if (!(signature = router_get_dirobj_signature(digest, digest_len,
    2363             :                                                   signing_key))) {
    2364           0 :       log_warn(LD_BUG, "Couldn't sign consensus networkstatus.");
    2365           0 :       goto done;
    2366             :     }
    2367          24 :     smartlist_add(chunks, signature);
    2368             : 
    2369          24 :     if (legacy_id_key_digest && legacy_signing_key) {
    2370          12 :       smartlist_add_strdup(chunks, "directory-signature ");
    2371          12 :       base16_encode(fingerprint, sizeof(fingerprint),
    2372             :                     legacy_id_key_digest, DIGEST_LEN);
    2373          12 :       crypto_pk_get_fingerprint(legacy_signing_key,
    2374             :                                 signing_key_fingerprint, 0);
    2375          12 :       if (flavor == FLAV_NS) {
    2376           3 :         smartlist_add_asprintf(chunks, "%s %s\n", fingerprint,
    2377             :                      signing_key_fingerprint);
    2378             :       } else {
    2379           9 :         smartlist_add_asprintf(chunks, "%s %s %s\n",
    2380             :                      algname, fingerprint,
    2381             :                      signing_key_fingerprint);
    2382             :       }
    2383             : 
    2384          12 :       if (!(signature = router_get_dirobj_signature(digest, digest_len,
    2385             :                                                     legacy_signing_key))) {
    2386           0 :         log_warn(LD_BUG, "Couldn't sign consensus networkstatus.");
    2387           0 :         goto done;
    2388             :       }
    2389          12 :       smartlist_add(chunks, signature);
    2390             :     }
    2391             :   }
    2392             : 
    2393          24 :   result = smartlist_join_strings(chunks, "", 0, NULL);
    2394             : 
    2395             :   {
    2396          24 :     networkstatus_t *c;
    2397          24 :     if (!(c = networkstatus_parse_vote_from_string(result, strlen(result),
    2398             :                                                    NULL,
    2399             :                                                    NS_TYPE_CONSENSUS))) {
    2400           0 :       log_err(LD_BUG, "Generated a networkstatus consensus we couldn't "
    2401             :               "parse.");
    2402           0 :       tor_free(result);
    2403           0 :       goto done;
    2404             :     }
    2405             :     // Verify balancing parameters
    2406          24 :     if (added_weights) {
    2407          24 :       networkstatus_verify_bw_weights(c, consensus_method);
    2408             :     }
    2409          24 :     networkstatus_vote_free(c);
    2410             :   }
    2411             : 
    2412          24 :  done:
    2413             : 
    2414          24 :   dircollator_free(collator);
    2415          24 :   tor_free(client_versions);
    2416          24 :   tor_free(server_versions);
    2417          24 :   tor_free(packages);
    2418         288 :   SMARTLIST_FOREACH(flags, char *, cp, tor_free(cp));
    2419          24 :   smartlist_free(flags);
    2420        1212 :   SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
    2421          24 :   smartlist_free(chunks);
    2422          78 :   SMARTLIST_FOREACH(param_list, char *, cp, tor_free(cp));
    2423          24 :   smartlist_free(param_list);
    2424             : 
    2425          24 :   return result;
    2426             : }
    2427             : 
    2428             : /** Extract the value of a parameter from a string encoding a list of
    2429             :  * parameters, badly.
    2430             :  *
    2431             :  * This is a deliberately buggy implementation, for backward compatibility
    2432             :  * with versions of Tor affected by #19011.  Once all authorities have
    2433             :  * upgraded to consensus method 31 or later, then we can throw away this
    2434             :  * function.  */
    2435             : STATIC int64_t
    2436          29 : extract_param_buggy(const char *params,
    2437             :                     const char *param_name,
    2438             :                     int64_t default_value)
    2439             : {
    2440          29 :   int64_t value = default_value;
    2441          29 :   const char *param_str = NULL;
    2442             : 
    2443          29 :   if (params) {
    2444          29 :     char *prefix1 = NULL, *prefix2=NULL;
    2445          29 :     tor_asprintf(&prefix1, "%s=", param_name);
    2446          29 :     tor_asprintf(&prefix2, " %s=", param_name);
    2447          29 :     if (strcmpstart(params, prefix1) == 0)
    2448             :       param_str = params;
    2449             :     else
    2450          27 :       param_str = strstr(params, prefix2);
    2451          29 :     tor_free(prefix1);
    2452          29 :     tor_free(prefix2);
    2453             :   }
    2454             : 
    2455          29 :   if (param_str) {
    2456          10 :     int ok=0;
    2457          10 :     char *eq = strchr(param_str, '=');
    2458          10 :     if (eq) {
    2459          10 :       value = tor_parse_long(eq+1, 10, 1, INT32_MAX, &ok, NULL);
    2460          10 :       if (!ok) {
    2461           2 :         log_warn(LD_DIR, "Bad element '%s' in %s",
    2462             :                  escaped(param_str), param_name);
    2463           2 :         value = default_value;
    2464             :       }
    2465             :     } else {
    2466           0 :       log_warn(LD_DIR, "Bad element '%s' in %s",
    2467             :                escaped(param_str), param_name);
    2468           0 :       value = default_value;
    2469             :     }
    2470             :   }
    2471             : 
    2472          29 :   return value;
    2473             : }
    2474             : 
    2475             : /** Given a list of networkstatus_t for each vote, return a newly allocated
    2476             :  * string containing the "package" lines for the vote. */
    2477             : STATIC char *
    2478          25 : compute_consensus_package_lines(smartlist_t *votes)
    2479             : {
    2480          25 :   const int n_votes = smartlist_len(votes);
    2481             : 
    2482             :   /* This will be a map from "packagename version" strings to arrays
    2483             :    * of const char *, with the i'th member of the array corresponding to the
    2484             :    * package line from the i'th vote.
    2485             :    */
    2486          25 :   strmap_t *package_status = strmap_new();
    2487             : 
    2488         103 :   SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
    2489          78 :     if (! v->package_lines)
    2490           0 :       continue;
    2491         130 :     SMARTLIST_FOREACH_BEGIN(v->package_lines, const char *, line) {
    2492          52 :       if (! validate_recommended_package_line(line))
    2493           5 :         continue;
    2494             : 
    2495             :       /* Skip 'cp' to the second space in the line. */
    2496          47 :       const char *cp = strchr(line, ' ');
    2497          47 :       if (!cp) continue;
    2498          47 :       ++cp;
    2499          47 :       cp = strchr(cp, ' ');
    2500          47 :       if (!cp) continue;
    2501             : 
    2502          47 :       char *key = tor_strndup(line, cp - line);
    2503             : 
    2504          47 :       const char **status = strmap_get(package_status, key);
    2505          47 :       if (!status) {
    2506           9 :         status = tor_calloc(n_votes, sizeof(const char *));
    2507           9 :         strmap_set(package_status, key, status);
    2508             :       }
    2509          47 :       status[v_sl_idx] = line; /* overwrite old value */
    2510          47 :       tor_free(key);
    2511          52 :     } SMARTLIST_FOREACH_END(line);
    2512          78 :   } SMARTLIST_FOREACH_END(v);
    2513             : 
    2514          25 :   smartlist_t *entries = smartlist_new(); /* temporary */
    2515          25 :   smartlist_t *result_list = smartlist_new(); /* output */
    2516          34 :   STRMAP_FOREACH(package_status, key, const char **, values) {
    2517           9 :     int i, count=-1;
    2518          63 :     for (i = 0; i < n_votes; ++i) {
    2519          54 :       if (values[i])
    2520          37 :         smartlist_add(entries, (void*) values[i]);
    2521             :     }
    2522           9 :     smartlist_sort_strings(entries);
    2523           9 :     int n_voting_for_entry = smartlist_len(entries);
    2524           9 :     const char *most_frequent =
    2525           9 :       smartlist_get_most_frequent_string_(entries, &count);
    2526             : 
    2527           9 :     if (n_voting_for_entry >= 3 && count > n_voting_for_entry / 2) {
    2528           5 :       smartlist_add_asprintf(result_list, "package %s\n", most_frequent);
    2529             :     }
    2530             : 
    2531           9 :     smartlist_clear(entries);
    2532             : 
    2533          25 :   } STRMAP_FOREACH_END;
    2534             : 
    2535          25 :   smartlist_sort_strings(result_list);
    2536             : 
    2537          25 :   char *result = smartlist_join_strings(result_list, "", 0, NULL);
    2538             : 
    2539          30 :   SMARTLIST_FOREACH(result_list, char *, cp, tor_free(cp));
    2540          25 :   smartlist_free(result_list);
    2541          25 :   smartlist_free(entries);
    2542          25 :   strmap_free(package_status, tor_free_);
    2543             : 
    2544          25 :   return result;
    2545             : }
    2546             : 
    2547             : /** Given a consensus vote <b>target</b> and a set of detached signatures in
    2548             :  * <b>sigs</b> that correspond to the same consensus, check whether there are
    2549             :  * any new signatures in <b>src_voter_list</b> that should be added to
    2550             :  * <b>target</b>. (A signature should be added if we have no signature for that
    2551             :  * voter in <b>target</b> yet, or if we have no verifiable signature and the
    2552             :  * new signature is verifiable.)
    2553             :  *
    2554             :  * Return the number of signatures added or changed, or -1 if the document
    2555             :  * signatures are invalid. Sets *<b>msg_out</b> to a string constant
    2556             :  * describing the signature status.
    2557             :  */
    2558             : STATIC int
    2559          12 : networkstatus_add_detached_signatures(networkstatus_t *target,
    2560             :                                       ns_detached_signatures_t *sigs,
    2561             :                                       const char *source,
    2562             :                                       int severity,
    2563             :                                       const char **msg_out)
    2564             : {
    2565          12 :   int r = 0;
    2566          12 :   const char *flavor;
    2567          12 :   smartlist_t *siglist;
    2568          12 :   tor_assert(sigs);
    2569          12 :   tor_assert(target);
    2570          12 :   tor_assert(target->type == NS_TYPE_CONSENSUS);
    2571             : 
    2572          12 :   flavor = networkstatus_get_flavor_name(target->flavor);
    2573             : 
    2574             :   /* Do the times seem right? */
    2575          12 :   if (target->valid_after != sigs->valid_after) {
    2576           0 :     *msg_out = "Valid-After times do not match "
    2577             :       "when adding detached signatures to consensus";
    2578           0 :     return -1;
    2579             :   }
    2580          12 :   if (target->fresh_until != sigs->fresh_until) {
    2581           0 :     *msg_out = "Fresh-until times do not match "
    2582             :       "when adding detached signatures to consensus";
    2583           0 :     return -1;
    2584             :   }
    2585          12 :   if (target->valid_until != sigs->valid_until) {
    2586           0 :     *msg_out = "Valid-until times do not match "
    2587             :       "when adding detached signatures to consensus";
    2588           0 :     return -1;
    2589             :   }
    2590          12 :   siglist = strmap_get(sigs->signatures, flavor);
    2591          12 :   if (!siglist) {
    2592           0 :     *msg_out = "No signatures for given consensus flavor";
    2593           0 :     return -1;
    2594             :   }
    2595             : 
    2596             :   /** Make sure all the digests we know match, and at least one matches. */
    2597             :   {
    2598          12 :     common_digests_t *digests = strmap_get(sigs->digests, flavor);
    2599          12 :     int n_matches = 0;
    2600          12 :     int alg;
    2601          12 :     if (!digests) {
    2602           0 :       *msg_out = "No digests for given consensus flavor";
    2603           0 :       return -1;
    2604             :     }
    2605          36 :     for (alg = DIGEST_SHA1; alg < N_COMMON_DIGEST_ALGORITHMS; ++alg) {
    2606          24 :       if (!fast_mem_is_zero(digests->d[alg], DIGEST256_LEN)) {
    2607          12 :         if (fast_memeq(target->digests.d[alg], digests->d[alg],
    2608             :                        DIGEST256_LEN)) {
    2609          12 :           ++n_matches;
    2610             :         } else {
    2611           0 :           *msg_out = "Mismatched digest.";
    2612           0 :           return -1;
    2613             :         }
    2614             :       }
    2615             :     }
    2616          12 :     if (!n_matches) {
    2617           0 :       *msg_out = "No recognized digests for given consensus flavor";
    2618             :     }
    2619             :   }
    2620             : 
    2621             :   /* For each voter in src... */
    2622          27 :   SMARTLIST_FOREACH_BEGIN(siglist, document_signature_t *, sig) {
    2623          15 :     char voter_identity[HEX_DIGEST_LEN+1];
    2624          15 :     networkstatus_voter_info_t *target_voter =
    2625          15 :       networkstatus_get_voter_by_id(target, sig->identity_digest);
    2626          15 :     authority_cert_t *cert = NULL;
    2627          15 :     const char *algorithm;
    2628          15 :     document_signature_t *old_sig = NULL;
    2629             : 
    2630          15 :     algorithm = crypto_digest_algorithm_get_name(sig->alg);
    2631             : 
    2632          15 :     base16_encode(voter_identity, sizeof(voter_identity),
    2633             :                   sig->identity_digest, DIGEST_LEN);
    2634          15 :     log_info(LD_DIR, "Looking at signature from %s using %s", voter_identity,
    2635             :              algorithm);
    2636             :     /* If the target doesn't know about this voter, then forget it. */
    2637          15 :     if (!target_voter) {
    2638           0 :       log_info(LD_DIR, "We do not know any voter with ID %s", voter_identity);
    2639           0 :       continue;
    2640             :     }
    2641             : 
    2642          15 :     old_sig = networkstatus_get_voter_sig_by_alg(target_voter, sig->alg);
    2643             : 
    2644             :     /* If the target already has a good signature from this voter, then skip
    2645             :      * this one. */
    2646          15 :     if (old_sig && old_sig->good_signature) {
    2647           0 :       log_info(LD_DIR, "We already have a good signature from %s using %s",
    2648             :                voter_identity, algorithm);
    2649           0 :       continue;
    2650             :     }
    2651             : 
    2652             :     /* Try checking the signature if we haven't already. */
    2653          15 :     if (!sig->good_signature && !sig->bad_signature) {
    2654          30 :       cert = authority_cert_get_by_digests(sig->identity_digest,
    2655          15 :                                            sig->signing_key_digest);
    2656          15 :       if (cert) {
    2657             :         /* Not checking the return value here, since we are going to look
    2658             :          * at the status of sig->good_signature in a moment. */
    2659           0 :         (void) networkstatus_check_document_signature(target, sig, cert);
    2660             :       }
    2661             :     }
    2662             : 
    2663             :     /* If this signature is good, or we don't have any signature yet,
    2664             :      * then maybe add it. */
    2665          15 :     if (sig->good_signature || !old_sig || old_sig->bad_signature) {
    2666          12 :       log_info(LD_DIR, "Adding signature from %s with %s", voter_identity,
    2667             :                algorithm);
    2668          12 :       tor_log(severity, LD_DIR, "Added a signature for %s from %s.",
    2669             :           target_voter->nickname, source);
    2670          12 :       ++r;
    2671          12 :       if (old_sig) {
    2672           0 :         smartlist_remove(target_voter->sigs, old_sig);
    2673           0 :         document_signature_free(old_sig);
    2674             :       }
    2675          12 :       smartlist_add(target_voter->sigs, document_signature_dup(sig));
    2676             :     } else {
    2677           3 :       log_info(LD_DIR, "Not adding signature from %s", voter_identity);
    2678             :     }
    2679          15 :   } SMARTLIST_FOREACH_END(sig);
    2680             : 
    2681             :   return r;
    2682             : }
    2683             : 
    2684             : /** Return a newly allocated string containing all the signatures on
    2685             :  * <b>consensus</b> by all voters. If <b>for_detached_signatures</b> is true,
    2686             :  * then the signatures will be put in a detached signatures document, so
    2687             :  * prefix any non-NS-flavored signatures with "additional-signature" rather
    2688             :  * than "directory-signature". */
    2689             : static char *
    2690          18 : networkstatus_format_signatures(networkstatus_t *consensus,
    2691             :                                 int for_detached_signatures)
    2692             : {
    2693          18 :   smartlist_t *elements;
    2694          18 :   char buf[4096];
    2695          18 :   char *result = NULL;
    2696          18 :   int n_sigs = 0;
    2697          18 :   const consensus_flavor_t flavor = consensus->flavor;
    2698          18 :   const char *flavor_name = networkstatus_get_flavor_name(flavor);
    2699          18 :   const char *keyword;
    2700             : 
    2701          18 :   if (for_detached_signatures && flavor != FLAV_NS)
    2702             :     keyword = "additional-signature";
    2703             :   else
    2704           9 :     keyword = "directory-signature";
    2705             : 
    2706          18 :   elements = smartlist_new();
    2707             : 
    2708          90 :   SMARTLIST_FOREACH_BEGIN(consensus->voters, networkstatus_voter_info_t *, v) {
    2709          96 :     SMARTLIST_FOREACH_BEGIN(v->sigs, document_signature_t *, sig) {
    2710          24 :       char sk[HEX_DIGEST_LEN+1];
    2711          24 :       char id[HEX_DIGEST_LEN+1];
    2712          24 :       if (!sig->signature || sig->bad_signature)
    2713           0 :         continue;
    2714          24 :       ++n_sigs;
    2715          24 :       base16_encode(sk, sizeof(sk), sig->signing_key_digest, DIGEST_LEN);
    2716          24 :       base16_encode(id, sizeof(id), sig->identity_digest, DIGEST_LEN);
    2717          24 :       if (flavor == FLAV_NS) {
    2718          12 :         smartlist_add_asprintf(elements,
    2719             :                      "%s %s %s\n-----BEGIN SIGNATURE-----\n",
    2720             :                      keyword, id, sk);
    2721             :       } else {
    2722          12 :         const char *digest_name =
    2723          12 :           crypto_digest_algorithm_get_name(sig->alg);
    2724          12 :         smartlist_add_asprintf(elements,
    2725             :                      "%s%s%s %s %s %s\n-----BEGIN SIGNATURE-----\n",
    2726             :                      keyword,
    2727             :                      for_detached_signatures ? " " : "",
    2728             :                      for_detached_signatures ? flavor_name : "",
    2729             :                      digest_name, id, sk);
    2730             :       }
    2731          24 :       base64_encode(buf, sizeof(buf), sig->signature, sig->signature_len,
    2732             :                     BASE64_ENCODE_MULTILINE);
    2733          24 :       strlcat(buf, "-----END SIGNATURE-----\n", sizeof(buf));
    2734          24 :       smartlist_add_strdup(elements, buf);
    2735          24 :     } SMARTLIST_FOREACH_END(sig);
    2736          72 :   } SMARTLIST_FOREACH_END(v);
    2737             : 
    2738          18 :   result = smartlist_join_strings(elements, "", 0, NULL);
    2739          66 :   SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
    2740          18 :   smartlist_free(elements);
    2741          18 :   if (!n_sigs)
    2742           0 :     tor_free(result);
    2743          18 :   return result;
    2744             : }
    2745             : 
    2746             : /** Return a newly allocated string holding the detached-signatures document
    2747             :  * corresponding to the signatures on <b>consensuses</b>, which must contain
    2748             :  * exactly one FLAV_NS consensus, and no more than one consensus for each
    2749             :  * other flavor. */
    2750             : STATIC char *
    2751           9 : networkstatus_get_detached_signatures(smartlist_t *consensuses)
    2752             : {
    2753           9 :   smartlist_t *elements;
    2754           9 :   char *result = NULL, *sigs = NULL;
    2755           9 :   networkstatus_t *consensus_ns = NULL;
    2756           9 :   tor_assert(consensuses);
    2757             : 
    2758          27 :   SMARTLIST_FOREACH(consensuses, networkstatus_t *, ns, {
    2759             :       tor_assert(ns);
    2760             :       tor_assert(ns->type == NS_TYPE_CONSENSUS);
    2761             :       if (ns && ns->flavor == FLAV_NS)
    2762             :         consensus_ns = ns;
    2763             :   });
    2764           9 :   if (!consensus_ns) {
    2765           0 :     log_warn(LD_BUG, "No NS consensus given.");
    2766           0 :     return NULL;
    2767             :   }
    2768             : 
    2769           9 :   elements = smartlist_new();
    2770             : 
    2771             :   {
    2772           9 :     char va_buf[ISO_TIME_LEN+1], fu_buf[ISO_TIME_LEN+1],
    2773             :       vu_buf[ISO_TIME_LEN+1];
    2774           9 :     char d[HEX_DIGEST_LEN+1];
    2775             : 
    2776           9 :     base16_encode(d, sizeof(d),
    2777           9 :                   consensus_ns->digests.d[DIGEST_SHA1], DIGEST_LEN);
    2778           9 :     format_iso_time(va_buf, consensus_ns->valid_after);
    2779           9 :     format_iso_time(fu_buf, consensus_ns->fresh_until);
    2780           9 :     format_iso_time(vu_buf, consensus_ns->valid_until);
    2781             : 
    2782           9 :     smartlist_add_asprintf(elements,
    2783             :                  "consensus-digest %s\n"
    2784             :                  "valid-after %s\n"
    2785             :                  "fresh-until %s\n"
    2786             :                  "valid-until %s\n", d, va_buf, fu_buf, vu_buf);
    2787             :   }
    2788             : 
    2789             :   /* Get all the digests for the non-FLAV_NS consensuses */
    2790          27 :   SMARTLIST_FOREACH_BEGIN(consensuses, networkstatus_t *, ns) {
    2791          18 :     const char *flavor_name = networkstatus_get_flavor_name(ns->flavor);
    2792          18 :     int alg;
    2793          18 :     if (ns->flavor == FLAV_NS)
    2794           9 :       continue;
    2795             : 
    2796             :     /* start with SHA256; we don't include SHA1 for anything but the basic
    2797             :      * consensus. */
    2798          18 :     for (alg = DIGEST_SHA256; alg < N_COMMON_DIGEST_ALGORITHMS; ++alg) {
    2799           9 :       char d[HEX_DIGEST256_LEN+1];
    2800           9 :       const char *alg_name =
    2801           9 :         crypto_digest_algorithm_get_name(alg);
    2802           9 :       if (fast_mem_is_zero(ns->digests.d[alg], DIGEST256_LEN))
    2803           0 :         continue;
    2804           9 :       base16_encode(d, sizeof(d), ns->digests.d[alg], DIGEST256_LEN);
    2805           9 :       smartlist_add_asprintf(elements, "additional-digest %s %s %s\n",
    2806             :                    flavor_name, alg_name, d);
    2807             :     }
    2808          18 :   } SMARTLIST_FOREACH_END(ns);
    2809             : 
    2810             :   /* Now get all the sigs for non-FLAV_NS consensuses */
    2811          27 :   SMARTLIST_FOREACH_BEGIN(consensuses, networkstatus_t *, ns) {
    2812          18 :     char *sigs_on_this_consensus;
    2813          18 :     if (ns->flavor == FLAV_NS)
    2814           9 :       continue;
    2815           9 :     sigs_on_this_consensus = networkstatus_format_signatures(ns, 1);
    2816           9 :     if (!sigs_on_this_consensus) {
    2817           0 :       log_warn(LD_DIR, "Couldn't format signatures");
    2818           0 :       goto err;
    2819             :     }
    2820           9 :     smartlist_add(elements, sigs_on_this_consensus);
    2821          18 :   } SMARTLIST_FOREACH_END(ns);
    2822             : 
    2823             :   /* Now add the FLAV_NS consensus signatrures. */
    2824           9 :   sigs = networkstatus_format_signatures(consensus_ns, 1);
    2825           9 :   if (!sigs)
    2826           0 :     goto err;
    2827           9 :   smartlist_add(elements, sigs);
    2828             : 
    2829           9 :   result = smartlist_join_strings(elements, "", 0, NULL);
    2830           9 :  err:
    2831          45 :   SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
    2832           9 :   smartlist_free(elements);
    2833           9 :   return result;
    2834             : }
    2835             : 
    2836             : /** Return a newly allocated string holding a detached-signatures document for
    2837             :  * all of the in-progress consensuses in the <b>n_flavors</b>-element array at
    2838             :  * <b>pending</b>. */
    2839             : static char *
    2840           0 : get_detached_signatures_from_pending_consensuses(pending_consensus_t *pending,
    2841             :                                                  int n_flavors)
    2842             : {
    2843           0 :   int flav;
    2844           0 :   char *signatures;
    2845           0 :   smartlist_t *c = smartlist_new();
    2846           0 :   for (flav = 0; flav < n_flavors; ++flav) {
    2847           0 :     if (pending[flav].consensus)
    2848           0 :       smartlist_add(c, pending[flav].consensus);
    2849             :   }
    2850           0 :   signatures = networkstatus_get_detached_signatures(c);
    2851           0 :   smartlist_free(c);
    2852           0 :   return signatures;
    2853             : }
    2854             : 
    2855             : /**
    2856             :  * Entry point: Take whatever voting actions are pending as of <b>now</b>.
    2857             :  *
    2858             :  * Return the time at which the next action should be taken.
    2859             :  */
    2860             : time_t
    2861          17 : dirvote_act(const or_options_t *options, time_t now)
    2862             : {
    2863          17 :   if (!authdir_mode_v3(options))
    2864             :     return TIME_MAX;
    2865          17 :   tor_assert_nonfatal(voting_schedule.voting_starts);
    2866             :   /* If we haven't initialized this object through this codeflow, we need to
    2867             :    * recalculate the timings to match our vote. The reason to do that is if we
    2868             :    * have a voting schedule initialized 1 minute ago, the voting timings might
    2869             :    * not be aligned to what we should expect with "now". This is especially
    2870             :    * true for TestingTorNetwork using smaller timings.  */
    2871          17 :   if (voting_schedule.created_on_demand) {
    2872           0 :     char *keys = list_v3_auth_ids();
    2873           0 :     authority_cert_t *c = get_my_v3_authority_cert();
    2874           0 :     log_notice(LD_DIR, "Scheduling voting.  Known authority IDs are %s. "
    2875             :                "Mine is %s.",
    2876             :                keys, hex_str(c->cache_info.identity_digest, DIGEST_LEN));
    2877           0 :     tor_free(keys);
    2878           0 :     dirauth_sched_recalculate_timing(options, now);
    2879             :   }
    2880             : 
    2881             : #define IF_TIME_FOR_NEXT_ACTION(when_field, done_field) \
    2882             :   if (! voting_schedule.done_field) {                   \
    2883             :     if (voting_schedule.when_field > now) {             \
    2884             :       return voting_schedule.when_field;                \
    2885             :     } else {
    2886             : #define ENDIF \
    2887             :     }           \
    2888             :   }
    2889             : 
    2890          17 :   IF_TIME_FOR_NEXT_ACTION(voting_starts, have_voted) {
    2891          17 :     log_notice(LD_DIR, "Time to vote.");
    2892          17 :     dirvote_perform_vote();
    2893          17 :     voting_schedule.have_voted = 1;
    2894             :   } ENDIF
    2895          17 :   IF_TIME_FOR_NEXT_ACTION(fetch_missing_votes, have_fetched_missing_votes) {
    2896          17 :     log_notice(LD_DIR, "Time to fetch any votes that we're missing.");
    2897          17 :     dirvote_fetch_missing_votes();
    2898          17 :     voting_schedule.have_fetched_missing_votes = 1;
    2899             :   } ENDIF
    2900          17 :   IF_TIME_FOR_NEXT_ACTION(voting_ends, have_built_consensus) {
    2901          17 :     log_notice(LD_DIR, "Time to compute a consensus.");
    2902          17 :     dirvote_compute_consensuses();
    2903             :     /* XXXX We will want to try again later if we haven't got enough
    2904             :      * votes yet.  Implement this if it turns out to ever happen. */
    2905          17 :     voting_schedule.have_built_consensus = 1;
    2906             :   } ENDIF
    2907          17 :   IF_TIME_FOR_NEXT_ACTION(fetch_missing_signatures,
    2908             :                           have_fetched_missing_signatures) {
    2909          17 :     log_notice(LD_DIR, "Time to fetch any signatures that we're missing.");
    2910          17 :     dirvote_fetch_missing_signatures();
    2911          17 :     voting_schedule.have_fetched_missing_signatures = 1;
    2912             :   } ENDIF
    2913          17 :   IF_TIME_FOR_NEXT_ACTION(interval_starts,
    2914             :                           have_published_consensus) {
    2915          17 :     log_notice(LD_DIR, "Time to publish the consensus and discard old votes");
    2916          17 :     dirvote_publish_consensus();
    2917          17 :     dirvote_clear_votes(0);
    2918          17 :     voting_schedule.have_published_consensus = 1;
    2919             :     /* Update our shared random state with the consensus just published. */
    2920          17 :     sr_act_post_consensus(
    2921          17 :                 networkstatus_get_latest_consensus_by_flavor(FLAV_NS));
    2922             :     /* XXXX We will want to try again later if we haven't got enough
    2923             :      * signatures yet.  Implement this if it turns out to ever happen. */
    2924          17 :     dirauth_sched_recalculate_timing(options, now);
    2925          17 :     return voting_schedule.voting_starts;
    2926             :   } ENDIF
    2927             : 
    2928           0 :   tor_assert_nonfatal_unreached();
    2929           0 :   return now + 1;
    2930             : 
    2931             : #undef ENDIF
    2932             : #undef IF_TIME_FOR_NEXT_ACTION
    2933             : }
    2934             : 
    2935             : /** A vote networkstatus_t and its unparsed body: held around so we can
    2936             :  * use it to generate a consensus (at voting_ends) and so we can serve it to
    2937             :  * other authorities that might want it. */
    2938             : typedef struct pending_vote_t {
    2939             :   cached_dir_t *vote_body;
    2940             :   networkstatus_t *vote;
    2941             : } pending_vote_t;
    2942             : 
    2943             : /** List of pending_vote_t for the current vote.  Before we've used them to
    2944             :  * build a consensus, the votes go here. */
    2945             : static smartlist_t *pending_vote_list = NULL;
    2946             : /** List of pending_vote_t for the previous vote.  After we've used them to
    2947             :  * build a consensus, the votes go here for the next period. */
    2948             : static smartlist_t *previous_vote_list = NULL;
    2949             : 
    2950             : /* DOCDOC pending_consensuses */
    2951             : static pending_consensus_t pending_consensuses[N_CONSENSUS_FLAVORS];
    2952             : 
    2953             : /** The detached signatures for the consensus that we're currently
    2954             :  * building. */
    2955             : static char *pending_consensus_signatures = NULL;
    2956             : 
    2957             : /** List of ns_detached_signatures_t: hold signatures that get posted to us
    2958             :  * before we have generated the consensus on our own. */
    2959             : static smartlist_t *pending_consensus_signature_list = NULL;
    2960             : 
    2961             : /** Generate a networkstatus vote and post it to all the v3 authorities.
    2962             :  * (V3 Authority only) */
    2963             : static int
    2964          17 : dirvote_perform_vote(void)
    2965             : {
    2966          17 :   crypto_pk_t *key = get_my_v3_authority_signing_key();
    2967          17 :   authority_cert_t *cert = get_my_v3_authority_cert();
    2968          17 :   networkstatus_t *ns;
    2969          17 :   char *contents;
    2970          17 :   pending_vote_t *pending_vote;
    2971          17 :   time_t now = time(NULL);
    2972             : 
    2973          17 :   int status;
    2974          17 :   const char *msg = "";
    2975             : 
    2976          17 :   if (!cert || !key) {
    2977          17 :     log_warn(LD_NET, "Didn't find key/certificate to generate v3 vote");
    2978          17 :     return -1;
    2979           0 :   } else if (cert->expires < now) {
    2980           0 :     log_warn(LD_NET, "Can't generate v3 vote with expired certificate");
    2981           0 :     return -1;
    2982             :   }
    2983           0 :   if (!(ns = dirserv_generate_networkstatus_vote_obj(key, cert)))
    2984             :     return -1;
    2985             : 
    2986           0 :   contents = format_networkstatus_vote(key, ns);
    2987           0 :   networkstatus_vote_free(ns);
    2988           0 :   if (!contents)
    2989             :     return -1;
    2990             : 
    2991           0 :   pending_vote = dirvote_add_vote(contents, 0, "self", &msg, &status);
    2992           0 :   tor_free(contents);
    2993           0 :   if (!pending_vote) {
    2994           0 :     log_warn(LD_DIR, "Couldn't store my own vote! (I told myself, '%s'.)",
    2995             :              msg);
    2996           0 :     return -1;
    2997             :   }
    2998             : 
    2999           0 :   directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_VOTE,
    3000             :                                ROUTER_PURPOSE_GENERAL,
    3001             :                                V3_DIRINFO,
    3002           0 :                                pending_vote->vote_body->dir,
    3003           0 :                                pending_vote->vote_body->dir_len, 0);
    3004           0 :   log_notice(LD_DIR, "Vote posted.");
    3005           0 :   return 0;
    3006             : }
    3007             : 
    3008             : /** Send an HTTP request to every other v3 authority, for the votes of every
    3009             :  * authority for which we haven't received a vote yet in this period. (V3
    3010             :  * authority only) */
    3011             : static void
    3012          17 : dirvote_fetch_missing_votes(void)
    3013             : {
    3014          17 :   smartlist_t *missing_fps = smartlist_new();
    3015          17 :   char *resource;
    3016             : 
    3017          34 :   SMARTLIST_FOREACH_BEGIN(router_get_trusted_dir_servers(),
    3018             :                           dir_server_t *, ds) {
    3019          17 :       if (!(ds->type & V3_DIRINFO))
    3020           0 :         continue;
    3021          17 :       if (!dirvote_get_vote(ds->v3_identity_digest,
    3022             :                             DGV_BY_ID|DGV_INCLUDE_PENDING)) {
    3023           0 :         char *cp = tor_malloc(HEX_DIGEST_LEN+1);
    3024           0 :         base16_encode(cp, HEX_DIGEST_LEN+1, ds->v3_identity_digest,
    3025             :                       DIGEST_LEN);
    3026           0 :         smartlist_add(missing_fps, cp);
    3027             :       }
    3028          17 :   } SMARTLIST_FOREACH_END(ds);
    3029             : 
    3030          17 :   if (!smartlist_len(missing_fps)) {
    3031          17 :     smartlist_free(missing_fps);
    3032          17 :     return;
    3033             :   }
    3034             :   {
    3035           0 :     char *tmp = smartlist_join_strings(missing_fps, " ", 0, NULL);
    3036           0 :     log_notice(LOG_NOTICE, "We're missing votes from %d authorities (%s). "
    3037             :                "Asking every other authority for a copy.",
    3038             :                smartlist_len(missing_fps), tmp);
    3039           0 :     tor_free(tmp);
    3040             :   }
    3041           0 :   resource = smartlist_join_strings(missing_fps, "+", 0, NULL);
    3042           0 :   directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE,
    3043             :                                      0, resource);
    3044           0 :   tor_free(resource);
    3045           0 :   SMARTLIST_FOREACH(missing_fps, char *, cp, tor_free(cp));
    3046           0 :   smartlist_free(missing_fps);
    3047             : }
    3048             : 
    3049             : /** Send a request to every other authority for its detached signatures,
    3050             :  * unless we have signatures from all other v3 authorities already. */
    3051             : static void
    3052          17 : dirvote_fetch_missing_signatures(void)
    3053             : {
    3054          17 :   int need_any = 0;
    3055          17 :   int i;
    3056          51 :   for (i=0; i < N_CONSENSUS_FLAVORS; ++i) {
    3057          34 :     networkstatus_t *consensus = pending_consensuses[i].consensus;
    3058          34 :     if (!consensus ||
    3059           0 :         networkstatus_check_consensus_signature(consensus, -1) == 1) {
    3060             :       /* We have no consensus, or we have one that's signed by everybody. */
    3061          34 :       continue;
    3062             :     }
    3063             :     need_any = 1;
    3064             :   }
    3065          17 :   if (!need_any)
    3066             :     return;
    3067             : 
    3068           0 :   directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES,
    3069             :                                      0, NULL);
    3070             : }
    3071             : 
    3072             : /** Release all storage held by pending consensuses (those waiting for
    3073             :  * signatures). */
    3074             : static void
    3075         515 : dirvote_clear_pending_consensuses(void)
    3076             : {
    3077         515 :   int i;
    3078        1545 :   for (i = 0; i < N_CONSENSUS_FLAVORS; ++i) {
    3079        1030 :     pending_consensus_t *pc = &pending_consensuses[i];
    3080        1030 :     tor_free(pc->body);
    3081             : 
    3082        1030 :     networkstatus_vote_free(pc->consensus);
    3083        1030 :     pc->consensus = NULL;
    3084             :   }
    3085         515 : }
    3086             : 
    3087             : /** Drop all currently pending votes, consensus, and detached signatures. */
    3088             : static void
    3089         266 : dirvote_clear_votes(int all_votes)
    3090             : {
    3091         266 :   if (!previous_vote_list)
    3092         249 :     previous_vote_list = smartlist_new();
    3093         266 :   if (!pending_vote_list)
    3094         242 :     pending_vote_list = smartlist_new();
    3095             : 
    3096             :   /* All "previous" votes are now junk. */
    3097         283 :   SMARTLIST_FOREACH(previous_vote_list, pending_vote_t *, v, {
    3098             :       cached_dir_decref(v->vote_body);
    3099             :       v->vote_body = NULL;
    3100             :       networkstatus_vote_free(v->vote);
    3101             :       tor_free(v);
    3102             :     });
    3103         266 :   smartlist_clear(previous_vote_list);
    3104             : 
    3105         266 :   if (all_votes) {
    3106             :     /* If we're dumping all the votes, we delete the pending ones. */
    3107         251 :     SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, {
    3108             :         cached_dir_decref(v->vote_body);
    3109             :         v->vote_body = NULL;
    3110             :         networkstatus_vote_free(v->vote);
    3111             :         tor_free(v);
    3112             :       });
    3113             :   } else {
    3114             :     /* Otherwise, we move them into "previous". */
    3115          17 :     smartlist_add_all(previous_vote_list, pending_vote_list);
    3116             :   }
    3117         266 :   smartlist_clear(pending_vote_list);
    3118             : 
    3119         266 :   if (pending_consensus_signature_list) {
    3120           0 :     SMARTLIST_FOREACH(pending_consensus_signature_list, char *, cp,
    3121             :                       tor_free(cp));
    3122           0 :     smartlist_clear(pending_consensus_signature_list);
    3123             :   }
    3124         266 :   tor_free(pending_consensus_signatures);
    3125         266 :   dirvote_clear_pending_consensuses();
    3126         266 : }
    3127             : 
    3128             : /** Return a newly allocated string containing the hex-encoded v3 authority
    3129             :     identity digest of every recognized v3 authority. */
    3130             : static char *
    3131           0 : list_v3_auth_ids(void)
    3132             : {
    3133           0 :   smartlist_t *known_v3_keys = smartlist_new();
    3134           0 :   char *keys;
    3135           0 :   SMARTLIST_FOREACH(router_get_trusted_dir_servers(),
    3136             :                     dir_server_t *, ds,
    3137             :     if ((ds->type & V3_DIRINFO) &&
    3138             :         !tor_digest_is_zero(ds->v3_identity_digest))
    3139             :       smartlist_add(known_v3_keys,
    3140             :                     tor_strdup(hex_str(ds->v3_identity_digest, DIGEST_LEN))));
    3141           0 :   keys = smartlist_join_strings(known_v3_keys, ", ", 0, NULL);
    3142           0 :   SMARTLIST_FOREACH(known_v3_keys, char *, cp, tor_free(cp));
    3143           0 :   smartlist_free(known_v3_keys);
    3144           0 :   return keys;
    3145             : }
    3146             : 
    3147             : /* Check the voter information <b>vi</b>, and  assert that at least one
    3148             :  * signature is good. Asserts on failure. */
    3149             : static void
    3150          27 : assert_any_sig_good(const networkstatus_voter_info_t *vi)
    3151             : {
    3152          27 :   int any_sig_good = 0;
    3153          54 :   SMARTLIST_FOREACH(vi->sigs, document_signature_t *, sig,
    3154             :                     if (sig->good_signature)
    3155             :                       any_sig_good = 1);
    3156          27 :   tor_assert(any_sig_good);
    3157          27 : }
    3158             : 
    3159             : /* Add <b>cert</b> to our list of known authority certificates. */
    3160             : static void
    3161          27 : add_new_cert_if_needed(const struct authority_cert_t *cert)
    3162             : {
    3163          27 :   tor_assert(cert);
    3164          27 :   if (!authority_cert_get_by_digests(cert->cache_info.identity_digest,
    3165          27 :                                      cert->signing_key_digest)) {
    3166             :     /* Hey, it's a new cert! */
    3167           1 :     trusted_dirs_load_certs_from_string(
    3168           1 :                                cert->cache_info.signed_descriptor_body,
    3169             :                                TRUSTED_DIRS_CERTS_SRC_FROM_VOTE, 1 /*flush*/,
    3170             :                                NULL);
    3171           1 :     if (!authority_cert_get_by_digests(cert->cache_info.identity_digest,
    3172             :                                        cert->signing_key_digest)) {
    3173           0 :       log_warn(LD_BUG, "We added a cert, but still couldn't find it.");
    3174             :     }
    3175             :   }
    3176          27 : }
    3177             : 
    3178             : /** Called when we have received a networkstatus vote in <b>vote_body</b>.
    3179             :  * Parse and validate it, and on success store it as a pending vote (which we
    3180             :  * then return).  Return NULL on failure.  Sets *<b>msg_out</b> and
    3181             :  * *<b>status_out</b> to an HTTP response and status code.  (V3 authority
    3182             :  * only) */
    3183             : pending_vote_t *
    3184          27 : dirvote_add_vote(const char *vote_body, time_t time_posted,
    3185             :                  const char *where_from,
    3186             :                  const char **msg_out, int *status_out)
    3187             : {
    3188          27 :   networkstatus_t *vote;
    3189          27 :   networkstatus_voter_info_t *vi;
    3190          27 :   dir_server_t *ds;
    3191          27 :   pending_vote_t *pending_vote = NULL;
    3192          27 :   const char *end_of_vote = NULL;
    3193          27 :   int any_failed = 0;
    3194          27 :   tor_assert(vote_body);
    3195          27 :   tor_assert(msg_out);
    3196          27 :   tor_assert(status_out);
    3197             : 
    3198          27 :   if (!pending_vote_list)
    3199           7 :     pending_vote_list = smartlist_new();
    3200          27 :   *status_out = 0;
    3201          27 :   *msg_out = NULL;
    3202             : 
    3203             :  again:
    3204          27 :   vote = networkstatus_parse_vote_from_string(vote_body, strlen(vote_body),
    3205             :                                               &end_of_vote,
    3206             :                                               NS_TYPE_VOTE);
    3207          27 :   if (!end_of_vote)
    3208           0 :     end_of_vote = vote_body + strlen(vote_body);
    3209          27 :   if (!vote) {
    3210           0 :     log_warn(LD_DIR, "Couldn't parse vote: length was %d",
    3211             :              (int)strlen(vote_body));
    3212           0 :     *msg_out = "Unable to parse vote";
    3213           0 :     goto err;
    3214             :   }
    3215          27 :   tor_assert(smartlist_len(vote->voters) == 1);
    3216          27 :   vi = get_voter(vote);
    3217          27 :   assert_any_sig_good(vi);
    3218          27 :   ds = trusteddirserver_get_by_v3_auth_digest(vi->identity_digest);
    3219          27 :   if (!ds) {
    3220           0 :     char *keys = list_v3_auth_ids();
    3221           0 :     log_warn(LD_DIR, "Got a vote from an authority (nickname %s, address %s) "
    3222             :              "with authority key ID %s. "
    3223             :              "This key ID is not recognized.  Known v3 key IDs are: %s",
    3224             :              vi->nickname, vi->address,
    3225             :              hex_str(vi->identity_digest, DIGEST_LEN), keys);
    3226           0 :     tor_free(keys);
    3227           0 :     *msg_out = "Vote not from a recognized v3 authority";
    3228           0 :     goto err;
    3229             :   }
    3230          27 :   add_new_cert_if_needed(vote->cert);
    3231             : 
    3232             :   /* Is it for the right period? */
    3233          27 :   if (vote->valid_after != voting_schedule.interval_starts) {
    3234           0 :     char tbuf1[ISO_TIME_LEN+1], tbuf2[ISO_TIME_LEN+1];
    3235           0 :     format_iso_time(tbuf1, vote->valid_after);
    3236           0 :     format_iso_time(tbuf2, voting_schedule.interval_starts);
    3237           0 :     log_warn(LD_DIR, "Rejecting vote from %s with valid-after time of %s; "
    3238             :              "we were expecting %s", vi->address, tbuf1, tbuf2);
    3239           0 :     *msg_out = "Bad valid-after time";
    3240           0 :     goto err;
    3241             :   }
    3242             : 
    3243          27 :   if (time_posted) { /* they sent it to me via a POST */
    3244          24 :     log_notice(LD_DIR, "%s posted a vote to me from %s.",
    3245             :                vi->nickname, where_from);
    3246             :   } else { /* I imported this one myself */
    3247           3 :     log_notice(LD_DIR, "Retrieved %s's vote from %s.",
    3248             :                vi->nickname, where_from);
    3249             :   }
    3250             : 
    3251             :   /* Check if we received it, as a post, after the cutoff when we
    3252             :    * start asking other dir auths for it. If we do, the best plan
    3253             :    * is to discard it, because using it greatly increases the chances
    3254             :    * of a split vote for this round (some dir auths got it in time,
    3255             :    * some didn't). */
    3256          27 :   if (time_posted && time_posted > voting_schedule.fetch_missing_votes) {
    3257           8 :     char tbuf1[ISO_TIME_LEN+1], tbuf2[ISO_TIME_LEN+1];
    3258           8 :     format_iso_time(tbuf1, time_posted);
    3259           8 :     format_iso_time(tbuf2, voting_schedule.fetch_missing_votes);
    3260           8 :     log_warn(LD_DIR, "Rejecting %s's posted vote from %s received at %s; "
    3261             :              "our cutoff for received votes is %s. Check your clock, "
    3262             :              "CPU load, and network load. Also check the authority that "
    3263             :              "posted the vote.", vi->nickname, vi->address, tbuf1, tbuf2);
    3264           8 :     *msg_out = "Posted vote received too late, would be dangerous to count it";
    3265           8 :     goto err;
    3266             :   }
    3267             : 
    3268             :   /* Fetch any new router descriptors we just learned about */
    3269          19 :   update_consensus_router_descriptor_downloads(time(NULL), 1, vote);
    3270             : 
    3271             :   /* Now see whether we already have a vote from this authority. */
    3272          19 :   SMARTLIST_FOREACH_BEGIN(pending_vote_list, pending_vote_t *, v) {
    3273           0 :       if (fast_memeq(v->vote->cert->cache_info.identity_digest,
    3274             :                    vote->cert->cache_info.identity_digest,
    3275             :                    DIGEST_LEN)) {
    3276           0 :         networkstatus_voter_info_t *vi_old = get_voter(v->vote);
    3277           0 :         if (fast_memeq(vi_old->vote_digest, vi->vote_digest, DIGEST_LEN)) {
    3278             :           /* Ah, it's the same vote. Not a problem. */
    3279           0 :           log_notice(LD_DIR, "Discarding a vote we already have (from %s).",
    3280             :                      vi->address);
    3281           0 :           if (*status_out < 200)
    3282           0 :             *status_out = 200;
    3283           0 :           goto discard;
    3284           0 :         } else if (v->vote->published < vote->published) {
    3285           0 :           log_notice(LD_DIR, "Replacing an older pending vote from this "
    3286             :                      "directory (%s)", vi->address);
    3287           0 :           cached_dir_decref(v->vote_body);
    3288           0 :           networkstatus_vote_free(v->vote);
    3289           0 :           v->vote_body = new_cached_dir(tor_strndup(vote_body,
    3290             :                                                     end_of_vote-vote_body),
    3291             :                                         vote->published);
    3292           0 :           v->vote = vote;
    3293           0 :           if (end_of_vote &&
    3294           0 :               !strcmpstart(end_of_vote, "network-status-version"))
    3295           0 :             goto again;
    3296             : 
    3297           0 :           if (*status_out < 200)
    3298           0 :             *status_out = 200;
    3299           0 :           if (!*msg_out)
    3300           0 :             *msg_out = "OK";
    3301           0 :           return v;
    3302             :         } else {
    3303           0 :           log_notice(LD_DIR, "Discarding vote from %s because we have "
    3304             :                      "a newer one already.", vi->address);
    3305           0 :           *msg_out = "Already have a newer pending vote";
    3306           0 :           goto err;
    3307             :         }
    3308             :       }
    3309           0 :   } SMARTLIST_FOREACH_END(v);
    3310             : 
    3311             :   /* This a valid vote, update our shared random state. */
    3312          19 :   sr_handle_received_commits(vote->sr_info.commits,
    3313          19 :                              vote->cert->identity_key);
    3314             : 
    3315          19 :   pending_vote = tor_malloc_zero(sizeof(pending_vote_t));
    3316          19 :   pending_vote->vote_body = new_cached_dir(tor_strndup(vote_body,
    3317             :                                                        end_of_vote-vote_body),
    3318             :                                            vote->published);
    3319          19 :   pending_vote->vote = vote;
    3320          19 :   smartlist_add(pending_vote_list, pending_vote);
    3321             : 
    3322          19 :   if (!strcmpstart(end_of_vote, "network-status-version ")) {
    3323           0 :     vote_body = end_of_vote;
    3324           0 :     goto again;
    3325             :   }
    3326             : 
    3327          19 :   goto done;
    3328             : 
    3329           8 :  err:
    3330           8 :   any_failed = 1;
    3331           8 :   if (!*msg_out)
    3332           0 :     *msg_out = "Error adding vote";
    3333           8 :   if (*status_out < 400)
    3334           8 :     *status_out = 400;
    3335             : 
    3336           0 :  discard:
    3337           8 :   networkstatus_vote_free(vote);
    3338             : 
    3339           8 :   if (end_of_vote && !strcmpstart(end_of_vote, "network-status-version ")) {
    3340           0 :     vote_body = end_of_vote;
    3341           0 :     goto again;
    3342             :   }
    3343             : 
    3344           8 :  done:
    3345             : 
    3346          27 :   if (*status_out < 200)
    3347          19 :     *status_out = 200;
    3348          27 :   if (!*msg_out) {
    3349          19 :     if (!any_failed && !pending_vote) {
    3350           0 :       *msg_out = "Duplicate discarded";
    3351             :     } else {
    3352          19 :       *msg_out = "ok";
    3353             :     }
    3354             :   }
    3355             : 
    3356          27 :   return any_failed ? NULL : pending_vote;
    3357             : }
    3358             : 
    3359             : /* Write the votes in <b>pending_vote_list</b> to disk. */
    3360             : static void
    3361          17 : write_v3_votes_to_disk(const smartlist_t *pending_votes)
    3362             : {
    3363          17 :   smartlist_t *votestrings = smartlist_new();
    3364          17 :   char *votefile = NULL;
    3365             : 
    3366          34 :   SMARTLIST_FOREACH(pending_votes, pending_vote_t *, v,
    3367             :     {
    3368             :       sized_chunk_t *c = tor_malloc(sizeof(sized_chunk_t));
    3369             :       c->bytes = v->vote_body->dir;
    3370             :       c->len = v->vote_body->dir_len;
    3371             :       smartlist_add(votestrings, c); /* collect strings to write to disk */
    3372             :     });
    3373             : 
    3374          17 :   votefile = get_datadir_fname("v3-status-votes");
    3375          17 :   write_chunks_to_file(votefile, votestrings, 0, 0);
    3376          17 :   log_debug(LD_DIR, "Wrote votes to disk (%s)!", votefile);
    3377             : 
    3378          17 :   tor_free(votefile);
    3379          34 :   SMARTLIST_FOREACH(votestrings, sized_chunk_t *, c, tor_free(c));
    3380          17 :   smartlist_free(votestrings);
    3381          17 : }
    3382             : 
    3383             : /** Try to compute a v3 networkstatus consensus from the currently pending
    3384             :  * votes.  Return 0 on success, -1 on failure.  Store the consensus in
    3385             :  * pending_consensus: it won't be ready to be published until we have
    3386             :  * everybody else's signatures collected too. (V3 Authority only) */
    3387             : static int
    3388          17 : dirvote_compute_consensuses(void)
    3389             : {
    3390             :   /* Have we got enough votes to try? */
    3391          17 :   int n_votes, n_voters, n_vote_running = 0;
    3392          17 :   smartlist_t *votes = NULL;
    3393          17 :   char *consensus_body = NULL, *signatures = NULL;
    3394          17 :   networkstatus_t *consensus = NULL;
    3395          17 :   authority_cert_t *my_cert;
    3396          17 :   pending_consensus_t pending[N_CONSENSUS_FLAVORS];
    3397          17 :   int flav;
    3398             : 
    3399          17 :   memset(pending, 0, sizeof(pending));
    3400             : 
    3401          17 :   if (!pending_vote_list)
    3402           0 :     pending_vote_list = smartlist_new();
    3403             : 
    3404             :   /* Write votes to disk */
    3405          17 :   write_v3_votes_to_disk(pending_vote_list);
    3406             : 
    3407             :   /* Setup votes smartlist */
    3408          17 :   votes = smartlist_new();
    3409          34 :   SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v,
    3410             :     {
    3411             :       smartlist_add(votes, v->vote); /* collect votes to compute consensus */
    3412             :     });
    3413             : 
    3414             :   /* See if consensus managed to achieve majority */
    3415          17 :   n_voters = get_n_authorities(V3_DIRINFO);
    3416          17 :   n_votes = smartlist_len(pending_vote_list);
    3417          17 :   if (n_votes <= n_voters/2) {
    3418           0 :     log_warn(LD_DIR, "We don't have enough votes to generate a consensus: "
    3419             :              "%d of %d", n_votes, n_voters/2+1);
    3420           0 :     goto err;
    3421             :   }
    3422             :   tor_assert(pending_vote_list);
    3423          34 :   SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, v, {
    3424             :     if (smartlist_contains_string(v->vote->known_flags, "Running"))
    3425             :       n_vote_running++;
    3426             :   });
    3427          17 :   if (!n_vote_running) {
    3428             :     /* See task 1066. */
    3429           0 :     log_warn(LD_DIR, "Nobody has voted on the Running flag. Generating "
    3430             :                      "and publishing a consensus without Running nodes "
    3431             :                      "would make many clients stop working. Not "
    3432             :                      "generating a consensus!");
    3433           0 :     goto err;
    3434             :   }
    3435             : 
    3436          17 :   if (!(my_cert = get_my_v3_authority_cert())) {
    3437          17 :     log_warn(LD_DIR, "Can't generate consensus without a certificate.");
    3438          17 :     goto err;
    3439             :   }
    3440             : 
    3441             :   {
    3442           0 :     char legacy_dbuf[DIGEST_LEN];
    3443           0 :     crypto_pk_t *legacy_sign=NULL;
    3444           0 :     char *legacy_id_digest = NULL;
    3445           0 :     int n_generated = 0;
    3446           0 :     if (get_options()->V3AuthUseLegacyKey) {
    3447           0 :       authority_cert_t *cert = get_my_v3_legacy_cert();
    3448           0 :       legacy_sign = get_my_v3_legacy_signing_key();
    3449           0 :       if (cert) {
    3450           0 :         if (crypto_pk_get_digest(cert->identity_key, legacy_dbuf)) {
    3451           0 :           log_warn(LD_BUG,
    3452             :                    "Unable to compute digest of legacy v3 identity key");
    3453             :         } else {
    3454             :           legacy_id_digest = legacy_dbuf;
    3455             :         }
    3456             :       }
    3457             :     }
    3458             : 
    3459           0 :     for (flav = 0; flav < N_CONSENSUS_FLAVORS; ++flav) {
    3460           0 :       const char *flavor_name = networkstatus_get_flavor_name(flav);
    3461           0 :       consensus_body = networkstatus_compute_consensus(
    3462             :         votes, n_voters,
    3463             :         my_cert->identity_key,
    3464             :         get_my_v3_authority_signing_key(), legacy_id_digest, legacy_sign,
    3465             :         flav);
    3466             : 
    3467           0 :       if (!consensus_body) {
    3468           0 :         log_warn(LD_DIR, "Couldn't generate a %s consensus at all!",
    3469             :                  flavor_name);
    3470           0 :         continue;
    3471             :       }
    3472           0 :       consensus = networkstatus_parse_vote_from_string(consensus_body,
    3473             :                                                        strlen(consensus_body),
    3474             :                                                        NULL,
    3475             :                                                        NS_TYPE_CONSENSUS);
    3476           0 :       if (!consensus) {
    3477           0 :         log_warn(LD_DIR, "Couldn't parse %s consensus we generated!",
    3478             :                  flavor_name);
    3479           0 :         tor_free(consensus_body);
    3480           0 :         continue;
    3481             :       }
    3482             : 
    3483             :       /* 'Check' our own signature, to mark it valid. */
    3484           0 :       networkstatus_check_consensus_signature(consensus, -1);
    3485             : 
    3486           0 :       pending[flav].body = consensus_body;
    3487           0 :       pending[flav].consensus = consensus;
    3488           0 :       n_generated++;
    3489             : 
    3490             :       /* Write it out to disk too, for dir auth debugging purposes */
    3491             :       {
    3492           0 :         char *filename;
    3493           0 :         tor_asprintf(&filename, "my-consensus-%s", flavor_name);
    3494           0 :         write_str_to_file(get_datadir_fname(filename), consensus_body, 0);
    3495           0 :         tor_free(filename);
    3496             :       }
    3497             : 
    3498           0 :       consensus_body = NULL;
    3499           0 :       consensus = NULL;
    3500             :     }
    3501           0 :     if (!n_generated) {
    3502           0 :       log_warn(LD_DIR, "Couldn't generate any consensus flavors at all.");
    3503           0 :       goto err;
    3504             :     }
    3505             :   }
    3506             : 
    3507           0 :   signatures = get_detached_signatures_from_pending_consensuses(
    3508             :        pending, N_CONSENSUS_FLAVORS);
    3509             : 
    3510           0 :   if (!signatures) {
    3511           0 :     log_warn(LD_DIR, "Couldn't extract signatures.");
    3512           0 :     goto err;
    3513             :   }
    3514             : 
    3515           0 :   dirvote_clear_pending_consensuses();
    3516           0 :   memcpy(pending_consensuses, pending, sizeof(pending));
    3517             : 
    3518           0 :   tor_free(pending_consensus_signatures);
    3519           0 :   pending_consensus_signatures = signatures;
    3520             : 
    3521           0 :   if (pending_consensus_signature_list) {
    3522           0 :     int n_sigs = 0;
    3523             :     /* we may have gotten signatures for this consensus before we built
    3524             :      * it ourself.  Add them now. */
    3525           0 :     SMARTLIST_FOREACH_BEGIN(pending_consensus_signature_list, char *, sig) {
    3526           0 :         const char *msg = NULL;
    3527           0 :         int r = dirvote_add_signatures_to_all_pending_consensuses(sig,
    3528             :                                                      "pending", &msg);
    3529           0 :         if (r >= 0)
    3530           0 :           n_sigs += r;
    3531             :         else
    3532           0 :           log_warn(LD_DIR,
    3533             :                    "Could not add queued signature to new consensus: %s",
    3534             :                    msg);
    3535           0 :         tor_free(sig);
    3536           0 :     } SMARTLIST_FOREACH_END(sig);
    3537           0 :     if (n_sigs)
    3538           0 :       log_notice(LD_DIR, "Added %d pending signatures while building "
    3539             :                  "consensus.", n_sigs);
    3540           0 :     smartlist_clear(pending_consensus_signature_list);
    3541             :   }
    3542             : 
    3543           0 :   log_notice(LD_DIR, "Consensus computed; uploading signature(s)");
    3544             : 
    3545           0 :   directory_post_to_dirservers(DIR_PURPOSE_UPLOAD_SIGNATURES,
    3546             :                                ROUTER_PURPOSE_GENERAL,
    3547             :                                V3_DIRINFO,
    3548             :                                pending_consensus_signatures,
    3549             :                                strlen(pending_consensus_signatures), 0);
    3550           0 :   log_notice(LD_DIR, "Signature(s) posted.");
    3551             : 
    3552           0 :   smartlist_free(votes);
    3553           0 :   return 0;
    3554          17 :  err:
    3555          17 :   smartlist_free(votes);
    3556          17 :   tor_free(consensus_body);
    3557          17 :   tor_free(signatures);
    3558          17 :   networkstatus_vote_free(consensus);
    3559             : 
    3560          17 :   return -1;
    3561             : }
    3562             : 
    3563             : /** Helper: we just got the <b>detached_signatures_body</b> sent to us as
    3564             :  * signatures on the currently pending consensus.  Add them to <b>pc</b>
    3565             :  * as appropriate.  Return the number of signatures added. (?) */
    3566             : static int
    3567           0 : dirvote_add_signatures_to_pending_consensus(
    3568             :                        pending_consensus_t *pc,
    3569             :                        ns_detached_signatures_t *sigs,
    3570             :                        const char *source,
    3571             :                        int severity,
    3572             :                        const char **msg_out)
    3573             : {
    3574           0 :   const char *flavor_name;
    3575           0 :   int r = -1;
    3576             : 
    3577             :   /* Only call if we have a pending consensus right now. */
    3578           0 :   tor_assert(pc->consensus);
    3579           0 :   tor_assert(pc->body);
    3580           0 :   tor_assert(pending_consensus_signatures);
    3581             : 
    3582           0 :   flavor_name = networkstatus_get_flavor_name(pc->consensus->flavor);
    3583           0 :   *msg_out = NULL;
    3584             : 
    3585             :   {
    3586           0 :     smartlist_t *sig_list = strmap_get(sigs->signatures, flavor_name);
    3587           0 :     log_info(LD_DIR, "Have %d signatures for adding to %s consensus.",
    3588             :              sig_list ? smartlist_len(sig_list) : 0, flavor_name);
    3589             :   }
    3590           0 :   r = networkstatus_add_detached_signatures(pc->consensus, sigs,
    3591             :                                             source, severity, msg_out);
    3592           0 :   if (r >= 0) {
    3593           0 :     log_info(LD_DIR,"Added %d signatures to consensus.", r);
    3594             :   } else {
    3595           0 :     log_fn(LOG_PROTOCOL_WARN, LD_DIR,
    3596             :            "Unable to add signatures to consensus: %s",
    3597             :            *msg_out ? *msg_out : "(unknown)");
    3598             :   }
    3599             : 
    3600           0 :   if (r >= 1) {
    3601           0 :     char *new_signatures =
    3602           0 :       networkstatus_format_signatures(pc->consensus, 0);
    3603           0 :     char *dst, *dst_end;
    3604           0 :     size_t new_consensus_len;
    3605           0 :     if (!new_signatures) {
    3606           0 :       *msg_out = "No signatures to add";
    3607           0 :       goto err;
    3608             :     }
    3609           0 :     new_consensus_len =
    3610           0 :       strlen(pc->body) + strlen(new_signatures) + 1;
    3611           0 :     pc->body = tor_realloc(pc->body, new_consensus_len);
    3612           0 :     dst_end = pc->body + new_consensus_len;
    3613           0 :     dst = (char *) find_str_at_start_of_line(pc->body, "directory-signature ");
    3614           0 :     tor_assert(dst);
    3615           0 :     strlcpy(dst, new_signatures, dst_end-dst);
    3616             : 
    3617             :     /* We remove this block once it has failed to crash for a while.  But
    3618             :      * unless it shows up in profiles, we're probably better leaving it in,
    3619             :      * just in case we break detached signature processing at some point. */
    3620             :     {
    3621           0 :       networkstatus_t *v = networkstatus_parse_vote_from_string(
    3622           0 :                                              pc->body, strlen(pc->body), NULL,
    3623             :                                              NS_TYPE_CONSENSUS);
    3624           0 :       tor_assert(v);
    3625           0 :       networkstatus_vote_free(v);
    3626             :     }
    3627           0 :     *msg_out = "Signatures added";
    3628           0 :     tor_free(new_signatures);
    3629           0 :   } else if (r == 0) {
    3630           0 :     *msg_out = "Signatures ignored";
    3631             :   } else {
    3632           0 :     goto err;
    3633             :   }
    3634             : 
    3635           0 :   goto done;
    3636           0 :  err:
    3637           0 :   if (!*msg_out)
    3638           0 :     *msg_out = "Unrecognized error while adding detached signatures.";
    3639           0 :  done:
    3640           0 :   return r;
    3641             : }
    3642             : 
    3643             : /** Helper: we just got the <b>detached_signatures_body</b> sent to us as
    3644             :  * signatures on the currently pending consensus.  Add them to the pending
    3645             :  * consensus (if we have one).
    3646             :  *
    3647             :  * Set *<b>msg</b> to a string constant describing the status, regardless of
    3648             :  * success or failure.
    3649             :  *
    3650             :  * Return negative on failure, nonnegative on success. */
    3651             : static int
    3652           0 : dirvote_add_signatures_to_all_pending_consensuses(
    3653             :                        const char *detached_signatures_body,
    3654             :                        const char *source,
    3655             :                        const char **msg_out)
    3656             : {
    3657           0 :   int r=0, i, n_added = 0, errors = 0;
    3658           0 :   ns_detached_signatures_t *sigs;
    3659           0 :   tor_assert(detached_signatures_body);
    3660           0 :   tor_assert(msg_out);
    3661           0 :   tor_assert(pending_consensus_signatures);
    3662             : 
    3663           0 :   if (!(sigs = networkstatus_parse_detached_signatures(
    3664             :                                detached_signatures_body, NULL))) {
    3665           0 :     *msg_out = "Couldn't parse detached signatures.";
    3666           0 :     goto err;
    3667             :   }
    3668             : 
    3669           0 :   for (i = 0; i < N_CONSENSUS_FLAVORS; ++i) {
    3670           0 :     int res;
    3671           0 :     int severity = i == FLAV_NS ? LOG_NOTICE : LOG_INFO;
    3672           0 :     pending_consensus_t *pc = &pending_consensuses[i];
    3673           0 :     if (!pc->consensus)
    3674           0 :       continue;
    3675           0 :     res = dirvote_add_signatures_to_pending_consensus(pc, sigs, source,
    3676             :                                                       severity, msg_out);
    3677           0 :     if (res < 0)
    3678           0 :       errors++;
    3679             :     else
    3680           0 :       n_added += res;
    3681             :   }
    3682             : 
    3683           0 :   if (errors && !n_added) {
    3684           0 :     r = -1;
    3685           0 :     goto err;
    3686             :   }
    3687             : 
    3688           0 :   if (n_added && pending_consensuses[FLAV_NS].consensus) {
    3689           0 :     char *new_detached =
    3690           0 :       get_detached_signatures_from_pending_consensuses(
    3691             :                       pending_consensuses, N_CONSENSUS_FLAVORS);
    3692           0 :     if (new_detached) {
    3693           0 :       tor_free(pending_consensus_signatures);
    3694           0 :       pending_consensus_signatures = new_detached;
    3695             :     }
    3696             :   }
    3697             : 
    3698           0 :   r = n_added;
    3699           0 :   goto done;
    3700           0 :  err:
    3701           0 :   if (!*msg_out)
    3702           0 :     *msg_out = "Unrecognized error while adding detached signatures.";
    3703           0 :  done:
    3704           0 :   ns_detached_signatures_free(sigs);
    3705             :   /* XXXX NM Check how return is used.  We can now have an error *and*
    3706             :      signatures added. */
    3707           0 :   return r;
    3708             : }
    3709             : 
    3710             : /** Helper: we just got the <b>detached_signatures_body</b> sent to us as
    3711             :  * signatures on the currently pending consensus.  Add them to the pending
    3712             :  * consensus (if we have one); otherwise queue them until we have a
    3713             :  * consensus.
    3714             :  *
    3715             :  * Set *<b>msg</b> to a string constant describing the status, regardless of
    3716             :  * success or failure.
    3717             :  *
    3718             :  * Return negative on failure, nonnegative on success. */
    3719             : int
    3720           0 : dirvote_add_signatures(const char *detached_signatures_body,
    3721             :                        const char *source,
    3722             :                        const char **msg)
    3723             : {
    3724           0 :   if (pending_consensuses[FLAV_NS].consensus) {
    3725           0 :     log_notice(LD_DIR, "Got a signature from %s. "
    3726             :                        "Adding it to the pending consensus.", source);
    3727           0 :     return dirvote_add_signatures_to_all_pending_consensuses(
    3728             :                                      detached_signatures_body, source, msg);
    3729             :   } else {
    3730           0 :     log_notice(LD_DIR, "Got a signature from %s. "
    3731             :                        "Queuing it for the next consensus.", source);
    3732           0 :     if (!pending_consensus_signature_list)
    3733           0 :       pending_consensus_signature_list = smartlist_new();
    3734           0 :     smartlist_add_strdup(pending_consensus_signature_list,
    3735             :                   detached_signatures_body);
    3736           0 :     *msg = "Signature queued";
    3737           0 :     return 0;
    3738             :   }
    3739             : }
    3740             : 
    3741             : /** Replace the consensus that we're currently serving with the one that we've
    3742             :  * been building. (V3 Authority only) */
    3743             : static int
    3744          17 : dirvote_publish_consensus(void)
    3745             : {
    3746          17 :   int i;
    3747             : 
    3748             :   /* Now remember all the other consensuses as if we were a directory cache. */
    3749          51 :   for (i = 0; i < N_CONSENSUS_FLAVORS; ++i) {
    3750          34 :     pending_consensus_t *pending = &pending_consensuses[i];
    3751          34 :     const char *name;
    3752          34 :     name = networkstatus_get_flavor_name(i);
    3753          34 :     tor_assert(name);
    3754          34 :     if (!pending->consensus ||
    3755           0 :       networkstatus_check_consensus_signature(pending->consensus, 1)<0) {
    3756          34 :       log_warn(LD_DIR, "Not enough info to publish pending %s consensus",name);
    3757          34 :       continue;
    3758             :     }
    3759             : 
    3760           0 :     if (networkstatus_set_current_consensus(pending->body,
    3761           0 :                                             strlen(pending->body),
    3762             :                                             name, 0, NULL))
    3763           0 :       log_warn(LD_DIR, "Error publishing %s consensus", name);
    3764             :     else
    3765           0 :       log_notice(LD_DIR, "Published %s consensus", name);
    3766             :   }
    3767             : 
    3768          17 :   return 0;
    3769             : }
    3770             : 
    3771             : /** Release all static storage held in dirvote.c */
    3772             : void
    3773         249 : dirvote_free_all(void)
    3774             : {
    3775         249 :   dirvote_clear_votes(1);
    3776             :   /* now empty as a result of dirvote_clear_votes(). */
    3777         249 :   smartlist_free(pending_vote_list);
    3778         249 :   pending_vote_list = NULL;
    3779         249 :   smartlist_free(previous_vote_list);
    3780         249 :   previous_vote_list = NULL;
    3781             : 
    3782         249 :   dirvote_clear_pending_consensuses();
    3783         249 :   tor_free(pending_consensus_signatures);
    3784         249 :   if (pending_consensus_signature_list) {
    3785             :     /* now empty as a result of dirvote_clear_votes(). */
    3786           0 :     smartlist_free(pending_consensus_signature_list);
    3787           0 :     pending_consensus_signature_list = NULL;
    3788             :   }
    3789         249 : }
    3790             : 
    3791             : /* ====
    3792             :  * Access to pending items.
    3793             :  * ==== */
    3794             : 
    3795             : /** Return the body of the consensus that we're currently trying to build. */
    3796           1 : MOCK_IMPL(const char *,
    3797             : dirvote_get_pending_consensus, (consensus_flavor_t flav))
    3798             : {
    3799           1 :   tor_assert(((int)flav) >= 0 && (int)flav < N_CONSENSUS_FLAVORS);
    3800           1 :   return pending_consensuses[flav].body;
    3801             : }
    3802             : 
    3803             : /** Return the signatures that we know for the consensus that we're currently
    3804             :  * trying to build. */
    3805           1 : MOCK_IMPL(const char *,
    3806             : dirvote_get_pending_detached_signatures, (void))
    3807             : {
    3808           1 :   return pending_consensus_signatures;
    3809             : }
    3810             : 
    3811             : /** Return a given vote specified by <b>fp</b>.  If <b>by_id</b>, return the
    3812             :  * vote for the authority with the v3 authority identity key digest <b>fp</b>;
    3813             :  * if <b>by_id</b> is false, return the vote whose digest is <b>fp</b>.  If
    3814             :  * <b>fp</b> is NULL, return our own vote.  If <b>include_previous</b> is
    3815             :  * false, do not consider any votes for a consensus that's already been built.
    3816             :  * If <b>include_pending</b> is false, do not consider any votes for the
    3817             :  * consensus that's in progress.  May return NULL if we have no vote for the
    3818             :  * authority in question. */
    3819             : const cached_dir_t *
    3820          31 : dirvote_get_vote(const char *fp, int flags)
    3821             : {
    3822          31 :   int by_id = flags & DGV_BY_ID;
    3823          31 :   const int include_pending = flags & DGV_INCLUDE_PENDING;
    3824          31 :   const int include_previous = flags & DGV_INCLUDE_PREVIOUS;
    3825             : 
    3826          31 :   if (!pending_vote_list && !previous_vote_list)
    3827             :     return NULL;
    3828          25 :   if (fp == NULL) {
    3829           6 :     authority_cert_t *c = get_my_v3_authority_cert();
    3830           6 :     if (c) {
    3831           6 :       fp = c->cache_info.identity_digest;
    3832           6 :       by_id = 1;
    3833             :     } else
    3834             :       return NULL;
    3835             :   }
    3836          25 :   if (by_id) {
    3837          23 :     if (pending_vote_list && include_pending) {
    3838          18 :       SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, pv,
    3839             :         if (fast_memeq(get_voter(pv->vote)->identity_digest, fp, DIGEST_LEN))
    3840             :           return pv->vote_body);
    3841             :     }
    3842           5 :     if (previous_vote_list && include_previous) {
    3843           5 :       SMARTLIST_FOREACH(previous_vote_list, pending_vote_t *, pv,
    3844             :         if (fast_memeq(get_voter(pv->vote)->identity_digest, fp, DIGEST_LEN))
    3845             :           return pv->vote_body);
    3846             :     }
    3847             :   } else {
    3848           2 :     if (pending_vote_list && include_pending) {
    3849           2 :       SMARTLIST_FOREACH(pending_vote_list, pending_vote_t *, pv,
    3850             :         if (fast_memeq(pv->vote->digests.d[DIGEST_SHA1], fp, DIGEST_LEN))
    3851             :           return pv->vote_body);
    3852             :     }
    3853           0 :     if (previous_vote_list && include_previous) {
    3854           0 :       SMARTLIST_FOREACH(previous_vote_list, pending_vote_t *, pv,
    3855             :         if (fast_memeq(pv->vote->digests.d[DIGEST_SHA1], fp, DIGEST_LEN))
    3856             :           return pv->vote_body);
    3857             :     }
    3858             :   }
    3859             :   return NULL;
    3860             : }
    3861             : 
    3862             : /** Construct and return a new microdescriptor from a routerinfo <b>ri</b>
    3863             :  * according to <b>consensus_method</b>.
    3864             :  **/
    3865             : STATIC microdesc_t *
    3866           3 : dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
    3867             : {
    3868           3 :   microdesc_t *result = NULL;
    3869           3 :   char *key = NULL, *summary = NULL, *family = NULL;
    3870           3 :   size_t keylen;
    3871           3 :   smartlist_t *chunks = smartlist_new();
    3872           3 :   char *output = NULL;
    3873           6 :   crypto_pk_t *rsa_pubkey = router_get_rsa_onion_pkey(ri->onion_pkey,
    3874           3 :                                                       ri->onion_pkey_len);
    3875             : 
    3876           3 :   if (crypto_pk_write_public_key_to_string(rsa_pubkey, &key, &keylen)<0)
    3877           0 :     goto done;
    3878           3 :   summary = policy_summarize(ri->exit_policy, AF_INET);
    3879           3 :   if (ri->declared_family)
    3880           2 :     family = smartlist_join_strings(ri->declared_family, " ", 0, NULL);
    3881             : 
    3882           3 :   smartlist_add_asprintf(chunks, "onion-key\n%s", key);
    3883             : 
    3884           3 :   if (ri->onion_curve25519_pkey) {
    3885           3 :     char kbuf[CURVE25519_BASE64_PADDED_LEN + 1];
    3886           3 :     bool add_padding = (consensus_method < MIN_METHOD_FOR_UNPADDED_NTOR_KEY);
    3887           3 :     curve25519_public_to_base64(kbuf, ri->onion_curve25519_pkey, add_padding);
    3888           3 :     smartlist_add_asprintf(chunks, "ntor-onion-key %s\n", kbuf);
    3889             :   }
    3890             : 
    3891           3 :   if (family) {
    3892           2 :     if (consensus_method < MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS) {
    3893           1 :       smartlist_add_asprintf(chunks, "family %s\n", family);
    3894             :     } else {
    3895           1 :       const uint8_t *id = (const uint8_t *)ri->cache_info.identity_digest;
    3896           1 :       char *canonical_family = nodefamily_canonicalize(family, id, 0);
    3897           1 :       smartlist_add_asprintf(chunks, "family %s\n", canonical_family);
    3898           1 :       tor_free(canonical_family);
    3899             :     }
    3900             :   }
    3901             : 
    3902           3 :   if (summary && strcmp(summary, "reject 1-65535"))
    3903           3 :     smartlist_add_asprintf(chunks, "p %s\n", summary);
    3904             : 
    3905           3 :   if (ri->ipv6_exit_policy) {
    3906             :     /* XXXX+++ This doesn't match proposal 208, which says these should
    3907             :      * be taken unchanged from the routerinfo.  That's bogosity, IMO:
    3908             :      * the proposal should have said to do this instead.*/
    3909           0 :     char *p6 = write_short_policy(ri->ipv6_exit_policy);
    3910           0 :     if (p6 && strcmp(p6, "reject 1-65535"))
    3911           0 :       smartlist_add_asprintf(chunks, "p6 %s\n", p6);
    3912           0 :     tor_free(p6);
    3913             :   }
    3914             : 
    3915             :   {
    3916           3 :     char idbuf[ED25519_BASE64_LEN+1];
    3917           3 :     const char *keytype;
    3918           3 :     if (ri->cache_info.signing_key_cert &&
    3919             :         ri->cache_info.signing_key_cert->signing_key_included) {
    3920           3 :       keytype = "ed25519";
    3921           3 :       ed25519_public_to_base64(idbuf,
    3922           3 :                                &ri->cache_info.signing_key_cert->signing_key);
    3923             :     } else {
    3924           0 :       keytype = "rsa1024";
    3925           0 :       digest_to_base64(idbuf, ri->cache_info.identity_digest);
    3926             :     }
    3927           3 :     smartlist_add_asprintf(chunks, "id %s %s\n", keytype, idbuf);
    3928             :   }
    3929             : 
    3930           3 :   output = smartlist_join_strings(chunks, "", 0, NULL);
    3931             : 
    3932             :   {
    3933           6 :     smartlist_t *lst = microdescs_parse_from_string(output,
    3934           3 :                                                     output+strlen(output), 0,
    3935             :                                                     SAVED_NOWHERE, NULL);
    3936           3 :     if (smartlist_len(lst) != 1) {
    3937           0 :       log_warn(LD_DIR, "We generated a microdescriptor we couldn't parse.");
    3938           0 :       SMARTLIST_FOREACH(lst, microdesc_t *, md, microdesc_free(md));
    3939           0 :       smartlist_free(lst);
    3940           0 :       goto done;
    3941             :     }
    3942           3 :     result = smartlist_get(lst, 0);
    3943           3 :     smartlist_free(lst);
    3944             :   }
    3945             : 
    3946           3 :  done:
    3947           3 :   crypto_pk_free(rsa_pubkey);
    3948           3 :   tor_free(output);
    3949           3 :   tor_free(key);
    3950           3 :   tor_free(summary);
    3951           3 :   tor_free(family);
    3952           3 :   if (chunks) {
    3953          17 :     SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
    3954           3 :     smartlist_free(chunks);
    3955             :   }
    3956           3 :   return result;
    3957             : }
    3958             : 
    3959             : /** Format the appropriate vote line to describe the microdescriptor <b>md</b>
    3960             :  * in a consensus vote document.  Write it into the <b>out_len</b>-byte buffer
    3961             :  * in <b>out</b>.  Return -1 on failure and the number of characters written
    3962             :  * on success. */
    3963             : static ssize_t
    3964           0 : dirvote_format_microdesc_vote_line(char *out_buf, size_t out_buf_len,
    3965             :                                    const microdesc_t *md,
    3966             :                                    int consensus_method_low,
    3967             :                                    int consensus_method_high)
    3968             : {
    3969           0 :   ssize_t ret = -1;
    3970           0 :   char d64[BASE64_DIGEST256_LEN+1];
    3971           0 :   char *microdesc_consensus_methods =
    3972           0 :     make_consensus_method_list(consensus_method_low,
    3973             :                                consensus_method_high,
    3974             :                                ",");
    3975           0 :   tor_assert(microdesc_consensus_methods);
    3976             : 
    3977           0 :   digest256_to_base64(d64, md->digest);
    3978             : 
    3979           0 :   if (tor_snprintf(out_buf, out_buf_len, "m %s sha256=%s\n",
    3980             :                    microdesc_consensus_methods, d64)<0)
    3981           0 :     goto out;
    3982             : 
    3983           0 :   ret = strlen(out_buf);
    3984             : 
    3985           0 :  out:
    3986           0 :   tor_free(microdesc_consensus_methods);
    3987           0 :   return ret;
    3988             : }
    3989             : 
    3990             : /** Array of start and end of consensus methods used for supported
    3991             :     microdescriptor formats. */
    3992             : static const struct consensus_method_range_t {
    3993             :   int low;
    3994             :   int high;
    3995             : } microdesc_consensus_methods[] = {
    3996             :   {MIN_SUPPORTED_CONSENSUS_METHOD,
    3997             :    MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS - 1},
    3998             :   {MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS,
    3999             :    MIN_METHOD_FOR_UNPADDED_NTOR_KEY - 1},
    4000             :   {MIN_METHOD_FOR_UNPADDED_NTOR_KEY,
    4001             :    MAX_SUPPORTED_CONSENSUS_METHOD},
    4002             :   {-1, -1}
    4003             : };
    4004             : 
    4005             : /** Helper type used when generating the microdescriptor lines in a directory
    4006             :  * vote. */
    4007             : typedef struct microdesc_vote_line_t {
    4008             :   int low;
    4009             :   int high;
    4010             :   microdesc_t *md;
    4011             :   struct microdesc_vote_line_t *next;
    4012             : } microdesc_vote_line_t;
    4013             : 
    4014             : /** Generate and return a linked list of all the lines that should appear to
    4015             :  * describe a router's microdescriptor versions in a directory vote.
    4016             :  * Add the generated microdescriptors to <b>microdescriptors_out</b>. */
    4017             : vote_microdesc_hash_t *
    4018           0 : dirvote_format_all_microdesc_vote_lines(const routerinfo_t *ri, time_t now,
    4019             :                                         smartlist_t *microdescriptors_out)
    4020             : {
    4021           0 :   const struct consensus_method_range_t *cmr;
    4022           0 :   microdesc_vote_line_t *entries = NULL, *ep;
    4023           0 :   vote_microdesc_hash_t *result = NULL;
    4024             : 
    4025             :   /* Generate the microdescriptors. */
    4026           0 :   for (cmr = microdesc_consensus_methods;
    4027           0 :        cmr->low != -1 && cmr->high != -1;
    4028           0 :        cmr++) {
    4029           0 :     microdesc_t *md = dirvote_create_microdescriptor(ri, cmr->low);
    4030           0 :     if (md) {
    4031           0 :       microdesc_vote_line_t *e =
    4032           0 :         tor_malloc_zero(sizeof(microdesc_vote_line_t));
    4033           0 :       e->md = md;
    4034           0 :       e->low = cmr->low;
    4035           0 :       e->high = cmr->high;
    4036           0 :       e->next = entries;
    4037           0 :       entries = e;
    4038             :     }
    4039             :   }
    4040             : 
    4041             :   /* Compress adjacent identical ones */
    4042           0 :   for (ep = entries; ep; ep = ep->next) {
    4043           0 :     while (ep->next &&
    4044           0 :            fast_memeq(ep->md->digest, ep->next->md->digest, DIGEST256_LEN) &&
    4045           0 :            ep->low == ep->next->high + 1) {
    4046           0 :       microdesc_vote_line_t *next = ep->next;
    4047           0 :       ep->low = next->low;
    4048           0 :       microdesc_free(next->md);
    4049           0 :       ep->next = next->next;
    4050           0 :       tor_free(next);
    4051             :     }
    4052             :   }
    4053             : 
    4054             :   /* Format them into vote_microdesc_hash_t, and add to microdescriptors_out.*/
    4055           0 :   while ((ep = entries)) {
    4056           0 :     char buf[128];
    4057           0 :     vote_microdesc_hash_t *h;
    4058           0 :     if (dirvote_format_microdesc_vote_line(buf, sizeof(buf), ep->md,
    4059             :                                            ep->low, ep->high) >= 0) {
    4060           0 :       h = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
    4061           0 :       h->microdesc_hash_line = tor_strdup(buf);
    4062           0 :       h->next = result;
    4063           0 :       result = h;
    4064           0 :       ep->md->last_listed = now;
    4065           0 :       smartlist_add(microdescriptors_out, ep->md);
    4066             :     }
    4067           0 :     entries = ep->next;
    4068           0 :     tor_free(ep);
    4069             :   }
    4070             : 
    4071           0 :   return result;
    4072             : }
    4073             : 
    4074             : /** Parse and extract all SR commits from <b>tokens</b> and place them in
    4075             :  *  <b>ns</b>. */
    4076             : static void
    4077         158 : extract_shared_random_commits(networkstatus_t *ns, const smartlist_t *tokens)
    4078             : {
    4079         158 :   smartlist_t *chunks = NULL;
    4080             : 
    4081         158 :   tor_assert(ns);
    4082         158 :   tor_assert(tokens);
    4083             :   /* Commits are only present in a vote. */
    4084         158 :   tor_assert(ns->type == NS_TYPE_VOTE);
    4085             : 
    4086         158 :   ns->sr_info.commits = smartlist_new();
    4087             : 
    4088         158 :   smartlist_t *commits = find_all_by_keyword(tokens, K_COMMIT);
    4089             :   /* It's normal that a vote might contain no commits even if it participates
    4090             :    * in the SR protocol. Don't treat it as an error. */
    4091         158 :   if (commits == NULL) {
    4092          14 :     goto end;
    4093             :   }
    4094             : 
    4095             :   /* Parse the commit. We do NO validation of number of arguments or ordering
    4096             :    * for forward compatibility, it's the parse commit job to inform us if it's
    4097             :    * supported or not. */
    4098         144 :   chunks = smartlist_new();
    4099        4821 :   SMARTLIST_FOREACH_BEGIN(commits, directory_token_t *, tok) {
    4100             :     /* Extract all arguments and put them in the chunks list. */
    4101       27941 :     for (int i = 0; i < tok->n_args; i++) {
    4102       23264 :       smartlist_add(chunks, tok->args[i]);
    4103             :     }
    4104        4677 :     sr_commit_t *commit = sr_parse_commit(chunks);
    4105        4677 :     smartlist_clear(chunks);
    4106        4677 :     if (commit == NULL) {
    4107             :       /* Get voter identity so we can warn that this dirauth vote contains
    4108             :        * commit we can't parse. */
    4109        4191 :       networkstatus_voter_info_t *voter = smartlist_get(ns->voters, 0);
    4110        4191 :       tor_assert(voter);
    4111        4191 :       log_warn(LD_DIR, "SR: Unable to parse commit %s from vote of voter %s.",
    4112             :                escaped(tok->object_body),
    4113             :                hex_str(voter->identity_digest,
    4114             :                        sizeof(voter->identity_digest)));
    4115             :       /* Commitment couldn't be parsed. Continue onto the next commit because
    4116             :        * this one could be unsupported for instance. */
    4117        4191 :       continue;
    4118             :     }
    4119             :     /* Add newly created commit object to the vote. */
    4120         486 :     smartlist_add(ns->sr_info.commits, commit);
    4121        4677 :   } SMARTLIST_FOREACH_END(tok);
    4122             : 
    4123         144 :  end:
    4124         158 :   smartlist_free(chunks);
    4125         158 :   smartlist_free(commits);
    4126         158 : }
    4127             : 
    4128             : /* Using the given directory tokens in tokens, parse the shared random commits
    4129             :  * and put them in the given vote document ns.
    4130             :  *
    4131             :  * This also sets the SR participation flag if present in the vote. */
    4132             : void
    4133         320 : dirvote_parse_sr_commits(networkstatus_t *ns, const smartlist_t *tokens)
    4134             : {
    4135             :   /* Does this authority participates in the SR protocol? */
    4136         320 :   directory_token_t *tok = find_opt_by_keyword(tokens, K_SR_FLAG);
    4137         320 :   if (tok) {
    4138         158 :     ns->sr_info.participate = 1;
    4139             :     /* Get the SR commitments and reveals from the vote. */
    4140         158 :     extract_shared_random_commits(ns, tokens);
    4141             :   }
    4142         320 : }
    4143             : 
    4144             : /* For the given vote, free the shared random commits if any. */
    4145             : void
    4146         158 : dirvote_clear_commits(networkstatus_t *ns)
    4147             : {
    4148         158 :   tor_assert(ns->type == NS_TYPE_VOTE);
    4149             : 
    4150         158 :   if (ns->sr_info.commits) {
    4151         644 :     SMARTLIST_FOREACH(ns->sr_info.commits, sr_commit_t *, c,
    4152             :                       sr_commit_free(c));
    4153         158 :     smartlist_free(ns->sr_info.commits);
    4154             :   }
    4155         158 : }
    4156             : 
    4157             : /* The given url is the /tor/status-vote GET directory request. Populates the
    4158             :  * items list with strings that we can compress on the fly and dir_items with
    4159             :  * cached_dir_t objects that have a precompressed deflated version. */
    4160             : void
    4161          21 : dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items,
    4162             :                                smartlist_t *dir_items)
    4163             : {
    4164          21 :   int current;
    4165             : 
    4166          21 :   url += strlen("/tor/status-vote/");
    4167          21 :   current = !strcmpstart(url, "current/");
    4168          21 :   url = strchr(url, '/');
    4169          21 :   tor_assert(url);
    4170          21 :   ++url;
    4171          21 :   if (!strcmp(url, "consensus")) {
    4172           3 :     const char *item;
    4173           3 :     tor_assert(!current); /* we handle current consensus specially above,
    4174             :                            * since it wants to be spooled. */
    4175           3 :     if ((item = dirvote_get_pending_consensus(FLAV_NS)))
    4176           2 :       smartlist_add(items, (char*)item);
    4177          18 :   } else if (!current && !strcmp(url, "consensus-signatures")) {
    4178             :     /* XXXX the spec says that we should implement
    4179             :      * current/consensus-signatures too.  It doesn't seem to be needed,
    4180             :      * though. */
    4181           3 :     const char *item;
    4182           3 :     if ((item=dirvote_get_pending_detached_signatures()))
    4183           2 :       smartlist_add(items, (char*)item);
    4184          15 :   } else if (!strcmp(url, "authority")) {
    4185           8 :     const cached_dir_t *d;
    4186           8 :     int flags = DGV_BY_ID |
    4187             :       (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING);
    4188           8 :     if ((d=dirvote_get_vote(NULL, flags)))
    4189           6 :       smartlist_add(dir_items, (cached_dir_t*)d);
    4190             :   } else {
    4191           7 :     const cached_dir_t *d;
    4192           7 :     smartlist_t *fps = smartlist_new();
    4193           7 :     int flags;
    4194           7 :     if (!strcmpstart(url, "d/")) {
    4195           4 :       url += 2;
    4196           4 :       flags = DGV_INCLUDE_PENDING | DGV_INCLUDE_PREVIOUS;
    4197             :     } else {
    4198           3 :       flags = DGV_BY_ID |
    4199             :         (current ? DGV_INCLUDE_PREVIOUS : DGV_INCLUDE_PENDING);
    4200             :     }
    4201           7 :     dir_split_resource_into_fingerprints(url, fps, NULL,
    4202             :                                          DSR_HEX|DSR_SORT_UNIQ);
    4203          13 :     SMARTLIST_FOREACH(fps, char *, fp, {
    4204             :                       if ((d = dirvote_get_vote(fp, flags)))
    4205             :                       smartlist_add(dir_items, (cached_dir_t*)d);
    4206             :                       tor_free(fp);
    4207             :                       });
    4208           7 :     smartlist_free(fps);
    4209             :   }
    4210          21 : }
    4211             : 
    4212             : /** Get the best estimate of a router's bandwidth for dirauth purposes,
    4213             :  * preferring measured to advertised values if available. */
    4214           0 : MOCK_IMPL(uint32_t,dirserv_get_bandwidth_for_router_kb,
    4215             :         (const routerinfo_t *ri))
    4216             : {
    4217           0 :   uint32_t bw_kb = 0;
    4218             :   /*
    4219             :    * Yeah, measured bandwidths in measured_bw_line_t are (implicitly
    4220             :    * signed) longs and the ones router_get_advertised_bandwidth() returns
    4221             :    * are uint32_t.
    4222             :    */
    4223           0 :   long mbw_kb = 0;
    4224             : 
    4225           0 :   if (ri) {
    4226             :     /*
    4227             :      * * First try to see if we have a measured bandwidth; don't bother with
    4228             :      * as_of_out here, on the theory that a stale measured bandwidth is still
    4229             :      * better to trust than an advertised one.
    4230             :      */
    4231           0 :     if (dirserv_query_measured_bw_cache_kb(ri->cache_info.identity_digest,
    4232             :                                            &mbw_kb, NULL)) {
    4233             :       /* Got one! */
    4234           0 :       bw_kb = (uint32_t)mbw_kb;
    4235             :     } else {
    4236             :       /* If not, fall back to advertised */
    4237           0 :       bw_kb = router_get_advertised_bandwidth(ri) / 1000;
    4238             :     }
    4239             :   }
    4240             : 
    4241           0 :   return bw_kb;
    4242             : }
    4243             : 
    4244             : /**
    4245             :  * Helper: compare the address of family `family` in `a` with the address in
    4246             :  * `b`.  The family must be one of `AF_INET` and `AF_INET6`.
    4247             :  **/
    4248             : static int
    4249         411 : compare_routerinfo_addrs_by_family(const routerinfo_t *a,
    4250             :                                    const routerinfo_t *b,
    4251             :                                    int family)
    4252             : {
    4253         411 :   const tor_addr_t *addr1 = (family==AF_INET) ? &a->ipv4_addr : &a->ipv6_addr;
    4254         411 :   const tor_addr_t *addr2 = (family==AF_INET) ? &b->ipv4_addr : &b->ipv6_addr;
    4255         411 :   return tor_addr_compare(addr1, addr2, CMP_EXACT);
    4256             : }
    4257             : 
    4258             : /** Helper for sorting: compares two ipv4 routerinfos first by ipv4 address,
    4259             :  * and then by descending order of "usefulness"
    4260             :  * (see compare_routerinfo_usefulness)
    4261             :  **/
    4262             : STATIC int
    4263         167 : compare_routerinfo_by_ipv4(const void **a, const void **b)
    4264             : {
    4265         167 :   const routerinfo_t *first = *(const routerinfo_t **)a;
    4266         167 :   const routerinfo_t *second = *(const routerinfo_t **)b;
    4267         167 :   int comparison = compare_routerinfo_addrs_by_family(first, second, AF_INET);
    4268         167 :   if (comparison == 0) {
    4269             :     // If addresses are equal, use other comparison criteria
    4270         120 :     return compare_routerinfo_usefulness(first, second);
    4271             :   } else {
    4272             :     return comparison;
    4273             :   }
    4274             : }
    4275             : 
    4276             : /** Helper for sorting: compares two ipv6 routerinfos first by ipv6 address,
    4277             :  * and then by descending order of "usefulness"
    4278             :  * (see compare_routerinfo_usefulness)
    4279             :  **/
    4280             : STATIC int
    4281          83 : compare_routerinfo_by_ipv6(const void **a, const void **b)
    4282             : {
    4283          83 :   const routerinfo_t *first = *(const routerinfo_t **)a;
    4284          83 :   const routerinfo_t *second = *(const routerinfo_t **)b;
    4285          83 :   int comparison = compare_routerinfo_addrs_by_family(first, second, AF_INET6);
    4286             :   // If addresses are equal, use other comparison criteria
    4287          83 :   if (comparison == 0)
    4288          65 :     return compare_routerinfo_usefulness(first, second);
    4289             :   else
    4290             :     return comparison;
    4291             : }
    4292             : 
    4293             : /**
    4294             : * Compare routerinfos by descending order of "usefulness" :
    4295             : * An authority is more useful than a non-authority; a running router is
    4296             : * more useful than a non-running router; and a router with more bandwidth
    4297             : * is more useful than one with less.
    4298             : **/
    4299             : STATIC int
    4300         189 : compare_routerinfo_usefulness(const routerinfo_t *first,
    4301             :                               const routerinfo_t *second)
    4302             : {
    4303         189 :   int first_is_auth, second_is_auth;
    4304         189 :   const node_t *node_first, *node_second;
    4305         189 :   int first_is_running, second_is_running;
    4306         189 :   uint32_t bw_kb_first, bw_kb_second;
    4307             :   /* Potentially, this next bit could cause k n lg n memeq calls.  But in
    4308             :    * reality, we will almost never get here, since addresses will usually be
    4309             :    * different. */
    4310         189 :   first_is_auth =
    4311         189 :     router_digest_is_trusted_dir(first->cache_info.identity_digest);
    4312         189 :   second_is_auth =
    4313         189 :     router_digest_is_trusted_dir(second->cache_info.identity_digest);
    4314             : 
    4315         189 :   if (first_is_auth && !second_is_auth)
    4316             :     return -1;
    4317         189 :   else if (!first_is_auth && second_is_auth)
    4318             :     return 1;
    4319             : 
    4320         187 :   node_first = node_get_by_id(first->cache_info.identity_digest);
    4321         187 :   node_second = node_get_by_id(second->cache_info.identity_digest);
    4322         187 :   first_is_running = node_first && node_first->is_running;
    4323         187 :   second_is_running = node_second && node_second->is_running;
    4324         187 :   if (first_is_running && !second_is_running)
    4325             :     return -1;
    4326         187 :   else if (!first_is_running && second_is_running)
    4327             :     return 1;
    4328             : 
    4329         186 :   bw_kb_first = dirserv_get_bandwidth_for_router_kb(first);
    4330         186 :   bw_kb_second = dirserv_get_bandwidth_for_router_kb(second);
    4331             : 
    4332         186 :   if (bw_kb_first > bw_kb_second)
    4333             :     return -1;
    4334         186 :   else if (bw_kb_first < bw_kb_second)
    4335             :     return 1;
    4336             : 
    4337             :   /* They're equal! Compare by identity digest, so there's a
    4338             :    * deterministic order and we avoid flapping. */
    4339         185 :   return fast_memcmp(first->cache_info.identity_digest,
    4340             :                      second->cache_info.identity_digest,
    4341             :                      DIGEST_LEN);
    4342             : }
    4343             : 
    4344             : /** Given a list of routerinfo_t in <b>routers</b> that all use the same
    4345             :  * IP version, specified in <b>family</b>, return a new digestmap_t whose keys
    4346             :  * are the identity digests of those routers that we're going to exclude for
    4347             :  * Sybil-like appearance.
    4348             :  */
    4349             : STATIC digestmap_t *
    4350          42 : get_sybil_list_by_ip_version(const smartlist_t *routers, sa_family_t family)
    4351             : {
    4352          42 :   const dirauth_options_t *options = dirauth_get_options();
    4353          42 :   digestmap_t *omit_as_sybil = digestmap_new();
    4354          42 :   smartlist_t *routers_by_ip = smartlist_new();
    4355          42 :   int addr_count = 0;
    4356          42 :   routerinfo_t *last_ri = NULL;
    4357             :   /* Allow at most this number of Tor servers on a single IP address, ... */
    4358          42 :   int max_with_same_addr = options->AuthDirMaxServersPerAddr;
    4359          42 :   if (max_with_same_addr <= 0)
    4360           0 :     max_with_same_addr = INT_MAX;
    4361             : 
    4362          42 :   smartlist_add_all(routers_by_ip, routers);
    4363          42 :   if (family == AF_INET6)
    4364          21 :     smartlist_sort(routers_by_ip, compare_routerinfo_by_ipv6);
    4365             :   else
    4366          21 :     smartlist_sort(routers_by_ip, compare_routerinfo_by_ipv4);
    4367             : 
    4368         238 :   SMARTLIST_FOREACH_BEGIN(routers_by_ip, routerinfo_t *, ri) {
    4369         196 :     bool addrs_equal;
    4370         196 :     if (last_ri)
    4371         161 :       addrs_equal = !compare_routerinfo_addrs_by_family(last_ri, ri, family);
    4372             :     else
    4373             :       addrs_equal = false;
    4374             : 
    4375         161 :     if (! addrs_equal) {
    4376             :       last_ri = ri;
    4377             :       addr_count = 1;
    4378         138 :     } else if (++addr_count > max_with_same_addr) {
    4379          84 :       digestmap_set(omit_as_sybil, ri->cache_info.identity_digest, ri);
    4380             :     }
    4381         196 :   } SMARTLIST_FOREACH_END(ri);
    4382          42 :   smartlist_free(routers_by_ip);
    4383          42 :   return omit_as_sybil;
    4384             : }
    4385             : 
    4386             : /** Given a list of routerinfo_t in <b>routers</b>, return a new digestmap_t
    4387             :  * whose keys are the identity digests of those routers that we're going to
    4388             :  * exclude for Sybil-like appearance. */
    4389             : STATIC digestmap_t *
    4390          14 : get_all_possible_sybil(const smartlist_t *routers)
    4391             : {
    4392          14 :   smartlist_t  *routers_ipv6, *routers_ipv4;
    4393          14 :   routers_ipv6 = smartlist_new();
    4394          14 :   routers_ipv4 = smartlist_new();
    4395          14 :   digestmap_t *omit_as_sybil_ipv4;
    4396          14 :   digestmap_t *omit_as_sybil_ipv6;
    4397          14 :   digestmap_t *omit_as_sybil = digestmap_new();
    4398             :   // Sort the routers in two lists depending on their IP version
    4399         140 :   SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
    4400             :     // If the router has an IPv6 address
    4401         126 :     if (tor_addr_family(&(ri->ipv6_addr)) == AF_INET6) {
    4402          35 :       smartlist_add(routers_ipv6, ri);
    4403             :     }
    4404             :     // If the router has an IPv4 address
    4405         126 :     if (tor_addr_family(&(ri->ipv4_addr)) == AF_INET) {
    4406          91 :       smartlist_add(routers_ipv4, ri);
    4407             :     }
    4408         126 :   } SMARTLIST_FOREACH_END(ri);
    4409          14 :   omit_as_sybil_ipv4 = get_sybil_list_by_ip_version(routers_ipv4, AF_INET);
    4410          14 :   omit_as_sybil_ipv6 = get_sybil_list_by_ip_version(routers_ipv6, AF_INET6);
    4411             : 
    4412             :   // Add all possible sybils to the common digestmap
    4413          56 :   DIGESTMAP_FOREACH (omit_as_sybil_ipv4, sybil_id, routerinfo_t *, ri) {
    4414          42 :     digestmap_set(omit_as_sybil, ri->cache_info.identity_digest, ri);
    4415          14 :   } DIGESTMAP_FOREACH_END;
    4416          28 :   DIGESTMAP_FOREACH (omit_as_sybil_ipv6, sybil_id, routerinfo_t *, ri) {
    4417          14 :     digestmap_set(omit_as_sybil, ri->cache_info.identity_digest, ri);
    4418          14 :   } DIGESTMAP_FOREACH_END;
    4419             :   // Clean the temp variables
    4420          14 :   smartlist_free(routers_ipv4);
    4421          14 :   smartlist_free(routers_ipv6);
    4422          14 :   digestmap_free(omit_as_sybil_ipv4, NULL);
    4423          14 :   digestmap_free(omit_as_sybil_ipv6, NULL);
    4424             :   // Return the digestmap: it now contains all the possible sybils
    4425          14 :   return omit_as_sybil;
    4426             : }
    4427             : 
    4428             : /** Given a platform string as in a routerinfo_t (possibly null), return a
    4429             :  * newly allocated version string for a networkstatus document, or NULL if the
    4430             :  * platform doesn't give a Tor version. */
    4431             : static char *
    4432           0 : version_from_platform(const char *platform)
    4433             : {
    4434           0 :   if (platform && !strcmpstart(platform, "Tor ")) {
    4435           0 :     const char *eos = find_whitespace(platform+4);
    4436           0 :     if (eos && !strcmpstart(eos, " (r")) {
    4437             :       /* XXXX Unify this logic with the other version extraction
    4438             :        * logic in routerparse.c. */
    4439           0 :       eos = find_whitespace(eos+1);
    4440             :     }
    4441           0 :     if (eos) {
    4442           0 :       return tor_strndup(platform, eos-platform);
    4443             :     }
    4444             :   }
    4445             :   return NULL;
    4446             : }
    4447             : 
    4448             : /** Given a (possibly empty) list of config_line_t, each line of which contains
    4449             :  * a list of comma-separated version numbers surrounded by optional space,
    4450             :  * allocate and return a new string containing the version numbers, in order,
    4451             :  * separated by commas.  Used to generate Recommended(Client|Server)?Versions
    4452             :  */
    4453             : char *
    4454        1157 : format_recommended_version_list(const config_line_t *ln, int warn)
    4455             : {
    4456        1157 :   smartlist_t *versions;
    4457        1157 :   char *result;
    4458        1157 :   versions = smartlist_new();
    4459        2327 :   for ( ; ln; ln = ln->next) {
    4460          13 :     smartlist_split_string(versions, ln->value, ",",
    4461             :                            SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    4462             :   }
    4463             : 
    4464             :   /* Handle the case where a dirauth operator has accidentally made some
    4465             :    * versions space-separated instead of comma-separated. */
    4466        1157 :   smartlist_t *more_versions = smartlist_new();
    4467        1182 :   SMARTLIST_FOREACH_BEGIN(versions, char *, v) {
    4468          25 :     if (strchr(v, ' ')) {
    4469           1 :       if (warn)
    4470           1 :         log_warn(LD_DIRSERV, "Unexpected space in versions list member %s. "
    4471             :                  "(These are supposed to be comma-separated; I'll pretend you "
    4472             :                  "used commas instead.)", escaped(v));
    4473           1 :       SMARTLIST_DEL_CURRENT(versions, v);
    4474           1 :       smartlist_split_string(more_versions, v, NULL,
    4475             :                              SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    4476           1 :       tor_free(v);
    4477             :     }
    4478          25 :   } SMARTLIST_FOREACH_END(v);
    4479        1157 :   smartlist_add_all(versions, more_versions);
    4480        1157 :   smartlist_free(more_versions);
    4481             : 
    4482             :   /* Check to make sure everything looks like a version. */
    4483        1157 :   if (warn) {
    4484        1183 :     SMARTLIST_FOREACH_BEGIN(versions, const char *, v) {
    4485          26 :       tor_version_t ver;
    4486          26 :       if (tor_version_parse(v, &ver) < 0) {
    4487           3 :         log_warn(LD_DIRSERV, "Recommended version %s does not look valid. "
    4488             :                  " (I'll include it anyway, since you told me to.)",
    4489             :                  escaped(v));
    4490             :       }
    4491          26 :     } SMARTLIST_FOREACH_END(v);
    4492             :   }
    4493             : 
    4494        1157 :   sort_version_list(versions, 1);
    4495        1157 :   result = smartlist_join_strings(versions,",",0,NULL);
    4496        1183 :   SMARTLIST_FOREACH(versions,char *,s,tor_free(s));
    4497        1157 :   smartlist_free(versions);
    4498        1157 :   return result;
    4499             : }
    4500             : 
    4501             : /** If there are entries in <b>routers</b> with exactly the same ed25519 keys,
    4502             :  * remove the older one.  If they are exactly the same age, remove the one
    4503             :  * with the greater descriptor digest. May alter the order of the list. */
    4504             : static void
    4505           0 : routers_make_ed_keys_unique(smartlist_t *routers)
    4506             : {
    4507           0 :   routerinfo_t *ri2;
    4508           0 :   digest256map_t *by_ed_key = digest256map_new();
    4509             : 
    4510           0 :   SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
    4511           0 :     ri->omit_from_vote = 0;
    4512           0 :     if (ri->cache_info.signing_key_cert == NULL)
    4513           0 :       continue; /* No ed key */
    4514           0 :     const uint8_t *pk = ri->cache_info.signing_key_cert->signing_key.pubkey;
    4515           0 :     if ((ri2 = digest256map_get(by_ed_key, pk))) {
    4516             :       /* Duplicate; must omit one.  Set the omit_from_vote flag in whichever
    4517             :        * one has the earlier published_on. */
    4518           0 :       const time_t ri_pub = ri->cache_info.published_on;
    4519           0 :       const time_t ri2_pub = ri2->cache_info.published_on;
    4520           0 :       if (ri2_pub < ri_pub ||
    4521           0 :           (ri2_pub == ri_pub &&
    4522           0 :            fast_memcmp(ri->cache_info.signed_descriptor_digest,
    4523             :                      ri2->cache_info.signed_descriptor_digest,DIGEST_LEN)<0)) {
    4524           0 :         digest256map_set(by_ed_key, pk, ri);
    4525           0 :         ri2->omit_from_vote = 1;
    4526             :       } else {
    4527           0 :         ri->omit_from_vote = 1;
    4528             :       }
    4529             :     } else {
    4530             :       /* Add to map */
    4531           0 :       digest256map_set(by_ed_key, pk, ri);
    4532             :     }
    4533           0 :   } SMARTLIST_FOREACH_END(ri);
    4534             : 
    4535           0 :   digest256map_free(by_ed_key, NULL);
    4536             : 
    4537             :   /* Now remove every router where the omit_from_vote flag got set. */
    4538           0 :   SMARTLIST_FOREACH_BEGIN(routers, const routerinfo_t *, ri) {
    4539           0 :     if (ri->omit_from_vote) {
    4540           0 :       SMARTLIST_DEL_CURRENT(routers, ri);
    4541             :     }
    4542           0 :   } SMARTLIST_FOREACH_END(ri);
    4543           0 : }
    4544             : 
    4545             : /** Routerstatus <b>rs</b> is part of a group of routers that are on too
    4546             :  * narrow an IP-space. Clear out its flags since we don't want it be used
    4547             :  * because of its Sybil-like appearance.
    4548             :  *
    4549             :  * Leave its BadExit flag alone though, since if we think it's a bad exit,
    4550             :  * we want to vote that way in case all the other authorities are voting
    4551             :  * Running and Exit.
    4552             :  *
    4553             :  * Also set the Sybil flag in order to let a relay operator know that's
    4554             :  * why their relay hasn't been voted on.
    4555             :  */
    4556             : static void
    4557           0 : clear_status_flags_on_sybil(routerstatus_t *rs)
    4558             : {
    4559           0 :   rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
    4560           0 :     rs->is_flagged_running = rs->is_named = rs->is_valid =
    4561           0 :     rs->is_hs_dir = rs->is_v2_dir = rs->is_possible_guard = 0;
    4562           0 :   rs->is_sybil = 1;
    4563             :   /* FFFF we might want some mechanism to check later on if we
    4564             :    * missed zeroing any flags: it's easy to add a new flag but
    4565             :    * forget to add it to this clause. */
    4566           0 : }
    4567             : 
    4568             : /** Space-separated list of all the flags that we will always vote on. */
    4569             : const char DIRVOTE_UNIVERSAL_FLAGS[] =
    4570             :   "Authority "
    4571             :   "Exit "
    4572             :   "Fast "
    4573             :   "Guard "
    4574             :   "HSDir "
    4575             :   "Stable "
    4576             :   "StaleDesc "
    4577             :   "Sybil "
    4578             :   "V2Dir "
    4579             :   "Valid";
    4580             : /** Space-separated list of all flags that we may or may not vote on,
    4581             :  * depending on our configuration. */
    4582             : const char DIRVOTE_OPTIONAL_FLAGS[] =
    4583             :   "BadExit "
    4584             :   "Running";
    4585             : 
    4586             : /** Return a new networkstatus_t* containing our current opinion. (For v3
    4587             :  * authorities) */
    4588             : networkstatus_t *
    4589           0 : dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
    4590             :                                         authority_cert_t *cert)
    4591             : {
    4592           0 :   const or_options_t *options = get_options();
    4593           0 :   const dirauth_options_t *d_options = dirauth_get_options();
    4594           0 :   networkstatus_t *v3_out = NULL;
    4595           0 :   tor_addr_t addr;
    4596           0 :   char *hostname = NULL, *client_versions = NULL, *server_versions = NULL;
    4597           0 :   const char *contact;
    4598           0 :   smartlist_t *routers, *routerstatuses;
    4599           0 :   char identity_digest[DIGEST_LEN];
    4600           0 :   char signing_key_digest[DIGEST_LEN];
    4601           0 :   const int listbadexits = d_options->AuthDirListBadExits;
    4602           0 :   routerlist_t *rl = router_get_routerlist();
    4603           0 :   time_t now = time(NULL);
    4604           0 :   time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
    4605           0 :   networkstatus_voter_info_t *voter = NULL;
    4606           0 :   vote_timing_t timing;
    4607           0 :   const int vote_on_reachability = running_long_enough_to_decide_unreachable();
    4608           0 :   smartlist_t *microdescriptors = NULL;
    4609           0 :   smartlist_t *bw_file_headers = NULL;
    4610           0 :   uint8_t bw_file_digest256[DIGEST256_LEN] = {0};
    4611             : 
    4612           0 :   tor_assert(private_key);
    4613           0 :   tor_assert(cert);
    4614             : 
    4615           0 :   if (crypto_pk_get_digest(private_key, signing_key_digest)<0) {
    4616           0 :     log_err(LD_BUG, "Error computing signing key digest");
    4617           0 :     return NULL;
    4618             :   }
    4619           0 :   if (crypto_pk_get_digest(cert->identity_key, identity_digest)<0) {
    4620           0 :     log_err(LD_BUG, "Error computing identity key digest");
    4621           0 :     return NULL;
    4622             :   }
    4623           0 :   if (!find_my_address(options, AF_INET, LOG_WARN, &addr, NULL, &hostname)) {
    4624           0 :     log_warn(LD_NET, "Couldn't resolve my hostname");
    4625           0 :     return NULL;
    4626             :   }
    4627           0 :   if (!hostname || !strchr(hostname, '.')) {
    4628           0 :     tor_free(hostname);
    4629           0 :     hostname = tor_addr_to_str_dup(&addr);
    4630             :   }
    4631             : 
    4632           0 :   if (!hostname) {
    4633           0 :     log_err(LD_BUG, "Failed to determine hostname AND duplicate address");
    4634           0 :     return NULL;
    4635             :   }
    4636             : 
    4637           0 :   if (d_options->VersioningAuthoritativeDirectory) {
    4638           0 :     client_versions =
    4639           0 :       format_recommended_version_list(d_options->RecommendedClientVersions, 0);
    4640           0 :     server_versions =
    4641           0 :       format_recommended_version_list(d_options->RecommendedServerVersions, 0);
    4642             :   }
    4643             : 
    4644           0 :   contact = get_options()->ContactInfo;
    4645           0 :   if (!contact)
    4646           0 :     contact = "(none)";
    4647             : 
    4648             :   /*
    4649             :    * Do this so dirserv_compute_performance_thresholds() and
    4650             :    * set_routerstatus_from_routerinfo() see up-to-date bandwidth info.
    4651             :    */
    4652           0 :   if (options->V3BandwidthsFile) {
    4653           0 :     dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL, NULL,
    4654             :                                      NULL);
    4655             :   } else {
    4656             :     /*
    4657             :      * No bandwidths file; clear the measured bandwidth cache in case we had
    4658             :      * one last time around.
    4659             :      */
    4660           0 :     if (dirserv_get_measured_bw_cache_size() > 0) {
    4661           0 :       dirserv_clear_measured_bw_cache();
    4662             :     }
    4663             :   }
    4664             : 
    4665             :   /* precompute this part, since we need it to decide what "stable"
    4666             :    * means. */
    4667           0 :   SMARTLIST_FOREACH(rl->routers, routerinfo_t *, ri, {
    4668             :                     dirserv_set_router_is_running(ri, now);
    4669             :                     });
    4670             : 
    4671           0 :   routers = smartlist_new();
    4672           0 :   smartlist_add_all(routers, rl->routers);
    4673           0 :   routers_make_ed_keys_unique(routers);
    4674             :   /* After this point, don't use rl->routers; use 'routers' instead. */
    4675           0 :   routers_sort_by_identity(routers);
    4676             :   /* Get a digestmap of possible sybil routers, IPv4 or IPv6 */
    4677           0 :   digestmap_t *omit_as_sybil = get_all_possible_sybil(routers);
    4678           0 :   DIGESTMAP_FOREACH (omit_as_sybil, sybil_id, void *, ignore) {
    4679           0 :     (void)ignore;
    4680           0 :     rep_hist_make_router_pessimal(sybil_id, now);
    4681             :   } DIGESTMAP_FOREACH_END
    4682             :   /* Count how many have measured bandwidths so we know how to assign flags;
    4683             :    * this must come before dirserv_compute_performance_thresholds() */
    4684           0 :   dirserv_count_measured_bws(routers);
    4685           0 :   dirserv_compute_performance_thresholds(omit_as_sybil);
    4686           0 :   routerstatuses = smartlist_new();
    4687           0 :   microdescriptors = smartlist_new();
    4688             : 
    4689           0 :   SMARTLIST_FOREACH_BEGIN(routers, routerinfo_t *, ri) {
    4690             :     /* If it has a protover list and contains a protocol name greater than
    4691             :      * MAX_PROTOCOL_NAME_LENGTH, skip it. */
    4692           0 :     if (ri->protocol_list &&
    4693           0 :         protover_list_is_invalid(ri->protocol_list)) {
    4694           0 :       continue;
    4695             :     }
    4696           0 :     if (ri->cache_info.published_on >= cutoff) {
    4697           0 :       routerstatus_t *rs;
    4698           0 :       vote_routerstatus_t *vrs;
    4699           0 :       node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest);
    4700           0 :       if (!node)
    4701           0 :         continue;
    4702             : 
    4703           0 :       vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
    4704           0 :       rs = &vrs->status;
    4705           0 :       dirauth_set_routerstatus_from_routerinfo(rs, node, ri, now,
    4706             :                                                listbadexits);
    4707             : 
    4708           0 :       if (ri->cache_info.signing_key_cert) {
    4709           0 :         memcpy(vrs->ed25519_id,
    4710           0 :                ri->cache_info.signing_key_cert->signing_key.pubkey,
    4711             :                ED25519_PUBKEY_LEN);
    4712             :       }
    4713           0 :       if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
    4714           0 :         clear_status_flags_on_sybil(rs);
    4715             : 
    4716           0 :       if (!vote_on_reachability)
    4717           0 :         rs->is_flagged_running = 0;
    4718             : 
    4719           0 :       vrs->version = version_from_platform(ri->platform);
    4720           0 :       if (ri->protocol_list) {
    4721           0 :         vrs->protocols = tor_strdup(ri->protocol_list);
    4722             :       } else {
    4723           0 :         vrs->protocols = tor_strdup(
    4724             :                                 protover_compute_for_old_tor(vrs->version));
    4725             :       }
    4726           0 :       vrs->microdesc = dirvote_format_all_microdesc_vote_lines(ri, now,
    4727             :                                                             microdescriptors);
    4728             : 
    4729           0 :       smartlist_add(routerstatuses, vrs);
    4730             :     }
    4731           0 :   } SMARTLIST_FOREACH_END(ri);
    4732             : 
    4733             :   {
    4734           0 :     smartlist_t *added =
    4735           0 :       microdescs_add_list_to_cache(get_microdesc_cache(),
    4736             :                                    microdescriptors, SAVED_NOWHERE, 0);
    4737           0 :     smartlist_free(added);
    4738           0 :     smartlist_free(microdescriptors);
    4739             :   }
    4740             : 
    4741           0 :   smartlist_free(routers);
    4742           0 :   digestmap_free(omit_as_sybil, NULL);
    4743             : 
    4744             :   /* Apply guardfraction information to routerstatuses. */
    4745           0 :   if (options->GuardfractionFile) {
    4746           0 :     dirserv_read_guardfraction_file(options->GuardfractionFile,
    4747             :                                     routerstatuses);
    4748             :   }
    4749             : 
    4750             :   /* This pass through applies the measured bw lines to the routerstatuses */
    4751           0 :   if (options->V3BandwidthsFile) {
    4752             :     /* Only set bw_file_headers when V3BandwidthsFile is configured */
    4753           0 :     bw_file_headers = smartlist_new();
    4754           0 :     dirserv_read_measured_bandwidths(options->V3BandwidthsFile,
    4755             :                                      routerstatuses, bw_file_headers,
    4756             :                                      bw_file_digest256);
    4757             :   } else {
    4758             :     /*
    4759             :      * No bandwidths file; clear the measured bandwidth cache in case we had
    4760             :      * one last time around.
    4761             :      */
    4762           0 :     if (dirserv_get_measured_bw_cache_size() > 0) {
    4763           0 :       dirserv_clear_measured_bw_cache();
    4764             :     }
    4765             :   }
    4766             : 
    4767           0 :   v3_out = tor_malloc_zero(sizeof(networkstatus_t));
    4768             : 
    4769           0 :   v3_out->type = NS_TYPE_VOTE;
    4770           0 :   dirvote_get_preferred_voting_intervals(&timing);
    4771           0 :   v3_out->published = now;
    4772             :   {
    4773           0 :     char tbuf[ISO_TIME_LEN+1];
    4774           0 :     networkstatus_t *current_consensus =
    4775           0 :       networkstatus_get_live_consensus(now);
    4776           0 :     long last_consensus_interval; /* only used to pick a valid_after */
    4777           0 :     if (current_consensus)
    4778           0 :       last_consensus_interval = current_consensus->fresh_until -
    4779           0 :         current_consensus->valid_after;
    4780             :     else
    4781           0 :       last_consensus_interval = options->TestingV3AuthInitialVotingInterval;
    4782           0 :     v3_out->valid_after =
    4783           0 :       voting_sched_get_start_of_interval_after(now,
    4784             :                                    (int)last_consensus_interval,
    4785           0 :                                    options->TestingV3AuthVotingStartOffset);
    4786           0 :     format_iso_time(tbuf, v3_out->valid_after);
    4787           0 :     log_notice(LD_DIR,"Choosing valid-after time in vote as %s: "
    4788             :                "consensus_set=%d, last_interval=%d",
    4789             :                tbuf, current_consensus?1:0, (int)last_consensus_interval);
    4790             :   }
    4791           0 :   v3_out->fresh_until = v3_out->valid_after + timing.vote_interval;
    4792           0 :   v3_out->valid_until = v3_out->valid_after +
    4793           0 :     (timing.vote_interval * timing.n_intervals_valid);
    4794           0 :   v3_out->vote_seconds = timing.vote_delay;
    4795           0 :   v3_out->dist_seconds = timing.dist_delay;
    4796           0 :   tor_assert(v3_out->vote_seconds > 0);
    4797           0 :   tor_assert(v3_out->dist_seconds > 0);
    4798           0 :   tor_assert(timing.n_intervals_valid > 0);
    4799             : 
    4800           0 :   v3_out->client_versions = client_versions;
    4801           0 :   v3_out->server_versions = server_versions;
    4802             : 
    4803             :   /* These are hardwired, to avoid disaster. */
    4804           0 :   v3_out->recommended_relay_protocols =
    4805           0 :     tor_strdup(DIRVOTE_RECOMMEND_RELAY_PROTO);
    4806           0 :   v3_out->recommended_client_protocols =
    4807           0 :     tor_strdup(DIRVOTE_RECOMMEND_CLIENT_PROTO);
    4808             : 
    4809           0 :   v3_out->required_relay_protocols =
    4810           0 :     tor_strdup(DIRVOTE_REQUIRE_RELAY_PROTO);
    4811           0 :   v3_out->required_client_protocols =
    4812           0 :     tor_strdup(DIRVOTE_REQUIRE_CLIENT_PROTO);
    4813             : 
    4814             :   /* We are not allowed to vote to require anything we don't have. */
    4815           0 :   tor_assert(protover_all_supported(v3_out->required_relay_protocols, NULL));
    4816           0 :   tor_assert(protover_all_supported(v3_out->required_client_protocols, NULL));
    4817             : 
    4818             :   /* We should not recommend anything we don't have. */
    4819           0 :   tor_assert_nonfatal(protover_all_supported(
    4820             :                                v3_out->recommended_relay_protocols, NULL));
    4821           0 :   tor_assert_nonfatal(protover_all_supported(
    4822             :                                v3_out->recommended_client_protocols, NULL));
    4823             : 
    4824           0 :   v3_out->known_flags = smartlist_new();
    4825           0 :   smartlist_split_string(v3_out->known_flags,
    4826             :                          DIRVOTE_UNIVERSAL_FLAGS,
    4827             :                          0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
    4828           0 :   if (vote_on_reachability)
    4829           0 :     smartlist_add_strdup(v3_out->known_flags, "Running");
    4830           0 :   if (listbadexits)
    4831           0 :     smartlist_add_strdup(v3_out->known_flags, "BadExit");
    4832           0 :   smartlist_sort_strings(v3_out->known_flags);
    4833             : 
    4834           0 :   if (d_options->ConsensusParams) {
    4835           0 :     config_line_t *paramline = d_options->ConsensusParams;
    4836           0 :     v3_out->net_params = smartlist_new();
    4837           0 :     for ( ; paramline; paramline = paramline->next) {
    4838           0 :       smartlist_split_string(v3_out->net_params,
    4839           0 :                              paramline->value, NULL, 0, 0);
    4840             :     }
    4841           0 :     smartlist_sort_strings(v3_out->net_params);
    4842             :   }
    4843           0 :   v3_out->bw_file_headers = bw_file_headers;
    4844           0 :   memcpy(v3_out->bw_file_digest256, bw_file_digest256, DIGEST256_LEN);
    4845             : 
    4846           0 :   voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
    4847           0 :   voter->nickname = tor_strdup(options->Nickname);
    4848           0 :   memcpy(voter->identity_digest, identity_digest, DIGEST_LEN);
    4849           0 :   voter->sigs = smartlist_new();
    4850           0 :   voter->address = hostname;
    4851           0 :   tor_addr_copy(&voter->ipv4_addr, &addr);
    4852           0 :   voter->ipv4_dirport = routerconf_find_dir_port(options, 0);
    4853           0 :   voter->ipv4_orport = routerconf_find_or_port(options, AF_INET);
    4854           0 :   voter->contact = tor_strdup(contact);
    4855           0 :   if (options->V3AuthUseLegacyKey) {
    4856           0 :     authority_cert_t *c = get_my_v3_legacy_cert();
    4857           0 :     if (c) {
    4858           0 :       if (crypto_pk_get_digest(c->identity_key, voter->legacy_id_digest)) {
    4859           0 :         log_warn(LD_BUG, "Unable to compute digest of legacy v3 identity key");
    4860           0 :         memset(voter->legacy_id_digest, 0, DIGEST_LEN);
    4861             :       }
    4862             :     }
    4863             :   }
    4864             : 
    4865           0 :   v3_out->voters = smartlist_new();
    4866           0 :   smartlist_add(v3_out->voters, voter);
    4867           0 :   v3_out->cert = authority_cert_dup(cert);
    4868           0 :   v3_out->routerstatus_list = routerstatuses;
    4869             :   /* Note: networkstatus_digest is unset; it won't get set until we actually
    4870             :    * format the vote. */
    4871             : 
    4872           0 :   return v3_out;
    4873             : }

Generated by: LCOV version 1.14