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 : }
|