Tor 0.4.9.0-alpha-dev
ns_parse.c
1/* Copyright (c) 2001 Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2021, The Tor Project, Inc. */
5/* See LICENSE for licensing information */
6
7/**
8 * \file routerparse.c
9 * \brief Code to parse and validate consensus documents and votes.
10 */
11
12#define NS_PARSE_PRIVATE
13
14#include "core/or/or.h"
15#include "app/config/config.h"
16#include "core/or/protover.h"
17#include "core/or/versions.h"
32#include "lib/memarea/memarea.h"
33
41
42#undef log
43#include <math.h>
44
45/** List of tokens recognized in the body part of v3 networkstatus
46 * documents. */
47// clang-format off
48static token_rule_t rtrstatus_token_table[] = {
49 T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
50 T1( "r", K_R, GE(7), NO_OBJ ),
51 T0N("a", K_A, GE(1), NO_OBJ ),
52 T1( "s", K_S, ARGS, NO_OBJ ),
53 T01("v", K_V, CONCAT_ARGS, NO_OBJ ),
54 T01("w", K_W, ARGS, NO_OBJ ),
55 T0N("m", K_M, CONCAT_ARGS, NO_OBJ ),
56 T0N("id", K_ID, GE(2), NO_OBJ ),
57 T1("pr", K_PROTO, CONCAT_ARGS, NO_OBJ ),
58 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
60};
61// clang-format on
62
63/** List of tokens recognized in V3 networkstatus votes. */
64// clang-format off
65static token_rule_t networkstatus_token_table[] = {
66 T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
67 GE(1), NO_OBJ ),
68 T1("vote-status", K_VOTE_STATUS, GE(1), NO_OBJ ),
69 T1("published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
70 T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ),
71 T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ),
72 T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ),
73 T1("voting-delay", K_VOTING_DELAY, GE(2), NO_OBJ ),
74 T1("known-flags", K_KNOWN_FLAGS, ARGS, NO_OBJ ),
75 T01("params", K_PARAMS, ARGS, NO_OBJ ),
76 T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
77 T01("signing-ed25519", K_SIGNING_CERT_ED, NO_ARGS , NEED_OBJ ),
78 T01("shared-rand-participate",K_SR_FLAG, NO_ARGS, NO_OBJ ),
79 T0N("shared-rand-commit", K_COMMIT, GE(3), NO_OBJ ),
80 T01("shared-rand-previous-value", K_PREVIOUS_SRV,EQ(2), NO_OBJ ),
81 T01("shared-rand-current-value", K_CURRENT_SRV, EQ(2), NO_OBJ ),
82 T0N("package", K_PACKAGE, CONCAT_ARGS, NO_OBJ ),
83 T01("recommended-client-protocols", K_RECOMMENDED_CLIENT_PROTOCOLS,
85 T01("recommended-relay-protocols", K_RECOMMENDED_RELAY_PROTOCOLS,
87 T01("required-client-protocols", K_REQUIRED_CLIENT_PROTOCOLS,
89 T01("required-relay-protocols", K_REQUIRED_RELAY_PROTOCOLS,
91
92 AUTHCERT_MEMBERS,
93
94 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
95 T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
96 T1( "dir-source", K_DIR_SOURCE, GE(6), NO_OBJ ),
97 T01("legacy-dir-key", K_LEGACY_DIR_KEY, GE(1), NO_OBJ ),
98 T1( "known-flags", K_KNOWN_FLAGS, CONCAT_ARGS, NO_OBJ ),
99 T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
100 T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
101 T1( "consensus-methods", K_CONSENSUS_METHODS, GE(1), NO_OBJ ),
102
104};
105// clang-format on
106
107/** List of tokens recognized in V3 networkstatus consensuses. */
108// clang-format off
109static token_rule_t networkstatus_consensus_token_table[] = {
110 T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
111 GE(1), NO_OBJ ),
112 T1("vote-status", K_VOTE_STATUS, GE(1), NO_OBJ ),
113 T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ),
114 T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ),
115 T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ),
116 T1("voting-delay", K_VOTING_DELAY, GE(2), NO_OBJ ),
117
118 T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
119
120 T1N("dir-source", K_DIR_SOURCE, GE(6), NO_OBJ ),
121 T1N("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
122 T1N("vote-digest", K_VOTE_DIGEST, GE(1), NO_OBJ ),
123
124 T1( "known-flags", K_KNOWN_FLAGS, CONCAT_ARGS, NO_OBJ ),
125
126 T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
127 T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
128 T01("consensus-method", K_CONSENSUS_METHOD, EQ(1), NO_OBJ),
129 T01("params", K_PARAMS, ARGS, NO_OBJ ),
130
131 T01("shared-rand-previous-value", K_PREVIOUS_SRV, EQ(2), NO_OBJ ),
132 T01("shared-rand-current-value", K_CURRENT_SRV, EQ(2), NO_OBJ ),
133
134 T01("recommended-client-protocols", K_RECOMMENDED_CLIENT_PROTOCOLS,
136 T01("recommended-relay-protocols", K_RECOMMENDED_RELAY_PROTOCOLS,
138 T01("required-client-protocols", K_REQUIRED_CLIENT_PROTOCOLS,
140 T01("required-relay-protocols", K_REQUIRED_RELAY_PROTOCOLS,
142
144};
145// clang-format on
146
147/** List of tokens recognized in the footer of v1 directory footers. */
148// clang-format off
149static token_rule_t networkstatus_vote_footer_token_table[] = {
150 T01("directory-footer", K_DIRECTORY_FOOTER, NO_ARGS, NO_OBJ ),
151 T01("bandwidth-weights", K_BW_WEIGHTS, ARGS, NO_OBJ ),
152 T( "directory-signature", K_DIRECTORY_SIGNATURE, GE(2), NEED_OBJ ),
154};
155// clang-format on
156
157/** Try to find the start and end of the signed portion of a networkstatus
158 * document in <b>s</b>. On success, set <b>start_out</b> to the first
159 * character of the document, and <b>end_out</b> to a position one after the
160 * final character of the signed document, and return 0. On failure, return
161 * -1. */
162int
164 size_t len,
165 const char **start_out,
166 const char **end_out)
167{
168 return router_get_hash_impl_helper(s, len,
169 "network-status-version",
170 "\ndirectory-signature",
171 ' ', LOG_INFO,
172 start_out, end_out);
173}
174
175/** Set <b>digest_out</b> to the SHA3-256 digest of the signed portion of the
176 * networkstatus vote in <b>s</b> -- or of the entirety of <b>s</b> if no
177 * signed portion can be identified. Return 0 on success, -1 on failure. */
178int
180 const char *s, size_t len)
181{
182 const char *start, *end;
184 &start, &end) < 0) {
185 start = s;
186 end = s + len;
187 }
188 tor_assert(start);
189 tor_assert(end);
190 return crypto_digest256((char*)digest_out, start, end-start,
191 DIGEST_SHA3_256);
192}
193
194/** Set <b>digests</b> to all the digests of the consensus document in
195 * <b>s</b> */
196int
197router_get_networkstatus_v3_hashes(const char *s, size_t len,
198 common_digests_t *digests)
199{
200 return router_get_hashes_impl(s, len, digests,
201 "network-status-version",
202 "\ndirectory-signature",
203 ' ');
204}
205
206/** Helper: given a string <b>s</b>, return the start of the next router-status
207 * object (starting with "r " at the start of a line). If none is found,
208 * return the start of the directory footer, or the next directory signature.
209 * If none is found, return the end of the string. */
210static inline const char *
211find_start_of_next_routerstatus(const char *s, const char *s_eos)
212{
213 const char *eos, *footer, *sig;
214 if ((eos = tor_memstr(s, s_eos - s, "\nr ")))
215 ++eos;
216 else
217 eos = s_eos;
218
219 footer = tor_memstr(s, eos-s, "\ndirectory-footer");
220 sig = tor_memstr(s, eos-s, "\ndirectory-signature");
221
222 if (footer && sig)
223 return MIN(footer, sig) + 1;
224 else if (footer)
225 return footer+1;
226 else if (sig)
227 return sig+1;
228 else
229 return eos;
230}
231
232/** Parse the GuardFraction string from a consensus or vote.
233 *
234 * If <b>vote</b> or <b>vote_rs</b> are set the document getting
235 * parsed is a vote routerstatus. Otherwise it's a consensus. This is
236 * the same semantic as in routerstatus_parse_entry_from_string(). */
237STATIC int
238routerstatus_parse_guardfraction(const char *guardfraction_str,
239 networkstatus_t *vote,
240 vote_routerstatus_t *vote_rs,
241 routerstatus_t *rs)
242{
243 int ok;
244 const char *end_of_header = NULL;
245 int is_consensus = !vote_rs;
246 uint32_t guardfraction;
247
248 tor_assert(bool_eq(vote, vote_rs));
249
250 /* If this info comes from a consensus, but we shouldn't apply
251 guardfraction, just exit. */
252 if (is_consensus && !should_apply_guardfraction(NULL)) {
253 return 0;
254 }
255
256 end_of_header = strchr(guardfraction_str, '=');
257 if (!end_of_header) {
258 return -1;
259 }
260
261 guardfraction = (uint32_t)tor_parse_ulong(end_of_header+1,
262 10, 0, 100, &ok, NULL);
263 if (!ok) {
264 log_warn(LD_DIR, "Invalid GuardFraction %s", escaped(guardfraction_str));
265 return -1;
266 }
267
268 log_debug(LD_GENERAL, "[*] Parsed %s guardfraction '%s' for '%s'.",
269 is_consensus ? "consensus" : "vote",
270 guardfraction_str, rs->nickname);
271
272 if (!is_consensus) { /* We are parsing a vote */
273 vote_rs->status.guardfraction_percentage = guardfraction;
274 vote_rs->status.has_guardfraction = 1;
275 } else {
276 /* We are parsing a consensus. Only apply guardfraction to guards. */
277 if (rs->is_possible_guard) {
278 rs->guardfraction_percentage = guardfraction;
279 rs->has_guardfraction = 1;
280 } else {
281 log_warn(LD_BUG, "Got GuardFraction for non-guard %s. "
282 "This is not supposed to happen. Not applying. ", rs->nickname);
283 }
284 }
285
286 return 0;
287}
288
289/** Given a string at *<b>s</b>, containing a routerstatus object, and an
290 * empty smartlist at <b>tokens</b>, parse and return the first router status
291 * object in the string, and advance *<b>s</b> to just after the end of the
292 * router status. Return NULL and advance *<b>s</b> on error.
293 *
294 * If <b>vote</b> and <b>vote_rs</b> are provided, don't allocate a fresh
295 * routerstatus but use <b>vote_rs</b> instead.
296 *
297 * If <b>consensus_method</b> is nonzero, this routerstatus is part of a
298 * consensus, and we should parse it according to the method used to
299 * make that consensus.
300 *
301 * Parse according to the syntax used by the consensus flavor <b>flav</b>.
302 **/
304routerstatus_parse_entry_from_string(memarea_t *area,
305 const char **s, const char *s_eos,
306 smartlist_t *tokens,
307 networkstatus_t *vote,
308 vote_routerstatus_t *vote_rs,
309 int consensus_method,
311{
312 const char *eos, *s_dup = *s;
313 routerstatus_t *rs = NULL;
315 char timebuf[ISO_TIME_LEN+1];
316 struct in_addr in;
317 int offset = 0;
318 tor_assert(tokens);
319 tor_assert(bool_eq(vote, vote_rs));
320
321 if (!consensus_method)
322 flav = FLAV_NS;
323 tor_assert(flav == FLAV_NS || flav == FLAV_MICRODESC);
324
325 eos = find_start_of_next_routerstatus(*s, s_eos);
326
327 if (tokenize_string(area,*s, eos, tokens, rtrstatus_token_table,0)) {
328 log_warn(LD_DIR, "Error tokenizing router status");
329 goto err;
330 }
331 if (smartlist_len(tokens) < 1) {
332 log_warn(LD_DIR, "Impossibly short router status");
333 goto err;
334 }
335 tok = find_by_keyword(tokens, K_R);
336 tor_assert(tok->n_args >= 7); /* guaranteed by GE(7) in K_R setup */
337 if (flav == FLAV_NS) {
338 if (tok->n_args < 8) {
339 log_warn(LD_DIR, "Too few arguments to r");
340 goto err;
341 }
342 } else if (flav == FLAV_MICRODESC) {
343 offset = -1; /* There is no descriptor digest in an md consensus r line */
344 }
345
346 if (vote_rs) {
347 rs = &vote_rs->status;
348 } else {
349 rs = tor_malloc_zero(sizeof(routerstatus_t));
350 }
351
352 if (!is_legal_nickname(tok->args[0])) {
353 log_warn(LD_DIR,
354 "Invalid nickname %s in router status; skipping.",
355 escaped(tok->args[0]));
356 goto err;
357 }
358 strlcpy(rs->nickname, tok->args[0], sizeof(rs->nickname));
359
360 if (digest_from_base64(rs->identity_digest, tok->args[1])) {
361 log_warn(LD_DIR, "Error decoding identity digest %s",
362 escaped(tok->args[1]));
363 goto err;
364 }
365
366 if (flav == FLAV_NS) {
367 if (digest_from_base64(rs->descriptor_digest, tok->args[2])) {
368 log_warn(LD_DIR, "Error decoding descriptor digest %s",
369 escaped(tok->args[2]));
370 goto err;
371 }
372 }
373
374 time_t published_on;
375 if (tor_snprintf(timebuf, sizeof(timebuf), "%s %s",
376 tok->args[3+offset], tok->args[4+offset]) < 0 ||
377 parse_iso_time(timebuf, &published_on)<0) {
378 log_warn(LD_DIR, "Error parsing time '%s %s' [%d %d]",
379 tok->args[3+offset], tok->args[4+offset],
380 offset, (int)flav);
381 goto err;
382 }
383 if (vote_rs)
384 vote_rs->published_on = published_on;
385
386 if (tor_inet_aton(tok->args[5+offset], &in) == 0) {
387 log_warn(LD_DIR, "Error parsing router address in network-status %s",
388 escaped(tok->args[5+offset]));
389 goto err;
390 }
391 tor_addr_from_in(&rs->ipv4_addr, &in);
392
393 rs->ipv4_orport = (uint16_t) tor_parse_long(tok->args[6+offset],
394 10,0,65535,NULL,NULL);
395 rs->ipv4_dirport = (uint16_t) tor_parse_long(tok->args[7+offset],
396 10,0,65535,NULL,NULL);
397
398 {
399 smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
400 if (a_lines) {
401 find_single_ipv6_orport(a_lines, &rs->ipv6_addr, &rs->ipv6_orport);
402 smartlist_free(a_lines);
403 }
404 }
405
406 tok = find_opt_by_keyword(tokens, K_S);
407 if (tok && vote) {
408 int i;
409 vote_rs->flags = 0;
410 for (i=0; i < tok->n_args; ++i) {
411 int p = smartlist_string_pos(vote->known_flags, tok->args[i]);
412 if (p >= 0) {
413 vote_rs->flags |= (UINT64_C(1)<<p);
414 } else {
415 log_warn(LD_DIR, "Flags line had a flag %s not listed in known_flags.",
416 escaped(tok->args[i]));
417 goto err;
418 }
419 }
420 } else if (tok) {
421 /* This is a consensus, not a vote. */
422 int i;
423 for (i=0; i < tok->n_args; ++i) {
424 if (!strcmp(tok->args[i], "Exit"))
425 rs->is_exit = 1;
426 else if (!strcmp(tok->args[i], "Stable"))
427 rs->is_stable = 1;
428 else if (!strcmp(tok->args[i], "Fast"))
429 rs->is_fast = 1;
430 else if (!strcmp(tok->args[i], "Running"))
431 rs->is_flagged_running = 1;
432 else if (!strcmp(tok->args[i], "Named"))
433 rs->is_named = 1;
434 else if (!strcmp(tok->args[i], "Valid"))
435 rs->is_valid = 1;
436 else if (!strcmp(tok->args[i], "Guard"))
437 rs->is_possible_guard = 1;
438 else if (!strcmp(tok->args[i], "BadExit"))
439 rs->is_bad_exit = 1;
440 else if (!strcmp(tok->args[i], "MiddleOnly"))
441 rs->is_middle_only = 1;
442 else if (!strcmp(tok->args[i], "Authority"))
443 rs->is_authority = 1;
444 else if (!strcmp(tok->args[i], "Unnamed") &&
445 consensus_method >= 2) {
446 /* Unnamed is computed right by consensus method 2 and later. */
447 rs->is_unnamed = 1;
448 } else if (!strcmp(tok->args[i], "HSDir")) {
449 rs->is_hs_dir = 1;
450 } else if (!strcmp(tok->args[i], "V2Dir")) {
451 rs->is_v2_dir = 1;
452 } else if (!strcmp(tok->args[i], "StaleDesc")) {
453 rs->is_staledesc = 1;
454 } else if (!strcmp(tok->args[i], "Sybil")) {
455 rs->is_sybil = 1;
456 }
457 }
458 /* These are implied true by having been included in a consensus made
459 * with a given method */
460 rs->is_flagged_running = 1; /* Starting with consensus method 4. */
461 rs->is_valid = 1; /* Starting with consensus method 24. */
462 }
463 {
464 const char *protocols = NULL, *version = NULL;
465 if ((tok = find_opt_by_keyword(tokens, K_PROTO))) {
466 tor_assert(tok->n_args == 1);
467 protocols = tok->args[0];
468 }
469 if ((tok = find_opt_by_keyword(tokens, K_V))) {
470 tor_assert(tok->n_args == 1);
471 version = tok->args[0];
472 if (vote_rs) {
473 vote_rs->version = tor_strdup(tok->args[0]);
474 }
475 }
476
477 // If the protover line is malformed, reject this routerstatus.
478 if (protocols && protover_list_is_invalid(protocols)) {
479 goto err;
480 }
481 summarize_protover_flags(&rs->pv, protocols, version);
482 }
483
484 /* handle weighting/bandwidth info */
485 if ((tok = find_opt_by_keyword(tokens, K_W))) {
486 int i;
487 for (i=0; i < tok->n_args; ++i) {
488 if (!strcmpstart(tok->args[i], "Bandwidth=")) {
489 int ok;
490 rs->bandwidth_kb =
491 (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
492 10, 0, UINT32_MAX,
493 &ok, NULL);
494 if (!ok) {
495 log_warn(LD_DIR, "Invalid Bandwidth %s", escaped(tok->args[i]));
496 goto err;
497 }
498 rs->has_bandwidth = 1;
499 } else if (!strcmpstart(tok->args[i], "Measured=") && vote_rs) {
500 int ok;
501 vote_rs->measured_bw_kb =
502 (uint32_t)tor_parse_ulong(strchr(tok->args[i], '=')+1,
503 10, 0, UINT32_MAX, &ok, NULL);
504 if (!ok) {
505 log_warn(LD_DIR, "Invalid Measured Bandwidth %s",
506 escaped(tok->args[i]));
507 goto err;
508 }
509 vote_rs->has_measured_bw = 1;
510 vote->has_measured_bws = 1;
511 } else if (!strcmpstart(tok->args[i], "Unmeasured=1")) {
512 rs->bw_is_unmeasured = 1;
513 } else if (!strcmpstart(tok->args[i], "GuardFraction=")) {
514 if (routerstatus_parse_guardfraction(tok->args[i],
515 vote, vote_rs, rs) < 0) {
516 goto err;
517 }
518 }
519 }
520 }
521
522 /* parse exit policy summaries */
523 if ((tok = find_opt_by_keyword(tokens, K_P))) {
524 tor_assert(tok->n_args == 1);
525 if (strcmpstart(tok->args[0], "accept ") &&
526 strcmpstart(tok->args[0], "reject ")) {
527 log_warn(LD_DIR, "Unknown exit policy summary type %s.",
528 escaped(tok->args[0]));
529 goto err;
530 }
531 /* XXX weasel: parse this into ports and represent them somehow smart,
532 * maybe not here but somewhere on if we need it for the client.
533 * we should still parse it here to check it's valid tho.
534 */
535 rs->exitsummary = tor_strdup(tok->args[0]);
536 rs->has_exitsummary = 1;
537 }
538
539 if (vote_rs) {
541 if (t->tp == K_M && t->n_args) {
543 tor_malloc(sizeof(vote_microdesc_hash_t));
544 line->next = vote_rs->microdesc;
545 line->microdesc_hash_line = tor_strdup(t->args[0]);
546 vote_rs->microdesc = line;
547 }
548 if (t->tp == K_ID) {
549 tor_assert(t->n_args >= 2);
550 if (!strcmp(t->args[0], "ed25519")) {
551 vote_rs->has_ed25519_listing = 1;
552 if (strcmp(t->args[1], "none") &&
553 digest256_from_base64((char*)vote_rs->ed25519_id,
554 t->args[1])<0) {
555 log_warn(LD_DIR, "Bogus ed25519 key in networkstatus vote");
556 goto err;
557 }
558 }
559 }
560 if (t->tp == K_PROTO) {
561 tor_assert(t->n_args == 1);
562 vote_rs->protocols = tor_strdup(t->args[0]);
563 }
564 } SMARTLIST_FOREACH_END(t);
565 } else if (flav == FLAV_MICRODESC) {
566 tok = find_opt_by_keyword(tokens, K_M);
567 if (tok) {
568 tor_assert(tok->n_args);
569 if (digest256_from_base64(rs->descriptor_digest, tok->args[0])) {
570 log_warn(LD_DIR, "Error decoding microdescriptor digest %s",
571 escaped(tok->args[0]));
572 goto err;
573 }
574 } else {
575 log_info(LD_BUG, "Found an entry in networkstatus with no "
576 "microdescriptor digest. (Router %s ($%s) at %s:%d.)",
578 fmt_addr(&rs->ipv4_addr), rs->ipv4_orport);
579 }
580 }
581
582 if (!strcasecmp(rs->nickname, UNNAMED_ROUTER_NICKNAME))
583 rs->is_named = 0;
584
585 goto done;
586 err:
587 dump_desc(s_dup, "routerstatus entry");
588 if (rs && !vote_rs)
589 routerstatus_free(rs);
590 rs = NULL;
591 done:
593 smartlist_clear(tokens);
594 if (area) {
595 DUMP_AREA(area, "routerstatus entry");
596 memarea_clear(area);
597 }
598 *s = eos;
599
600 return rs;
601}
602
603int
604compare_vote_routerstatus_entries(const void **_a, const void **_b)
605{
606 const vote_routerstatus_t *a = *_a, *b = *_b;
607 return fast_memcmp(a->status.identity_digest, b->status.identity_digest,
608 DIGEST_LEN);
609}
610
611/** Verify the bandwidth weights of a network status document */
612int
614{
615 int64_t G=0, M=0, E=0, D=0, T=0;
616 double Wgg, Wgm, Wgd, Wmg, Wmm, Wme, Wmd, Weg, Wem, Wee, Wed;
617 double Gtotal=0, Mtotal=0, Etotal=0;
618 const char *casename = NULL;
619 int valid = 1;
620 (void) consensus_method;
621
622 const int64_t weight_scale = networkstatus_get_weight_scale_param(ns);
623 tor_assert(weight_scale >= 1);
624 Wgg = networkstatus_get_bw_weight(ns, "Wgg", -1);
625 Wgm = networkstatus_get_bw_weight(ns, "Wgm", -1);
626 Wgd = networkstatus_get_bw_weight(ns, "Wgd", -1);
627 Wmg = networkstatus_get_bw_weight(ns, "Wmg", -1);
628 Wmm = networkstatus_get_bw_weight(ns, "Wmm", -1);
629 Wme = networkstatus_get_bw_weight(ns, "Wme", -1);
630 Wmd = networkstatus_get_bw_weight(ns, "Wmd", -1);
631 Weg = networkstatus_get_bw_weight(ns, "Weg", -1);
632 Wem = networkstatus_get_bw_weight(ns, "Wem", -1);
633 Wee = networkstatus_get_bw_weight(ns, "Wee", -1);
634 Wed = networkstatus_get_bw_weight(ns, "Wed", -1);
635
636 if (Wgg<0 || Wgm<0 || Wgd<0 || Wmg<0 || Wmm<0 || Wme<0 || Wmd<0 || Weg<0
637 || Wem<0 || Wee<0 || Wed<0) {
638 log_warn(LD_BUG, "No bandwidth weights produced in consensus!");
639 return 0;
640 }
641
642 // First, sanity check basic summing properties that hold for all cases
643 // We use > 1 as the check for these because they are computed as integers.
644 // Sometimes there are rounding errors.
645 if (fabs(Wmm - weight_scale) > 1) {
646 log_warn(LD_BUG, "Wmm=%f != %"PRId64,
647 Wmm, (weight_scale));
648 valid = 0;
649 }
650
651 if (fabs(Wem - Wee) > 1) {
652 log_warn(LD_BUG, "Wem=%f != Wee=%f", Wem, Wee);
653 valid = 0;
654 }
655
656 if (fabs(Wgm - Wgg) > 1) {
657 log_warn(LD_BUG, "Wgm=%f != Wgg=%f", Wgm, Wgg);
658 valid = 0;
659 }
660
661 if (fabs(Weg - Wed) > 1) {
662 log_warn(LD_BUG, "Wed=%f != Weg=%f", Wed, Weg);
663 valid = 0;
664 }
665
666 if (fabs(Wgg + Wmg - weight_scale) > 0.001*weight_scale) {
667 log_warn(LD_BUG, "Wgg=%f != %"PRId64" - Wmg=%f", Wgg,
668 (weight_scale), Wmg);
669 valid = 0;
670 }
671
672 if (fabs(Wee + Wme - weight_scale) > 0.001*weight_scale) {
673 log_warn(LD_BUG, "Wee=%f != %"PRId64" - Wme=%f", Wee,
674 (weight_scale), Wme);
675 valid = 0;
676 }
677
678 if (fabs(Wgd + Wmd + Wed - weight_scale) > 0.001*weight_scale) {
679 log_warn(LD_BUG, "Wgd=%f + Wmd=%f + Wed=%f != %"PRId64,
680 Wgd, Wmd, Wed, (weight_scale));
681 valid = 0;
682 }
683
684 Wgg /= weight_scale;
685 Wgm /= weight_scale; (void) Wgm; // unused from here on.
686 Wgd /= weight_scale;
687
688 Wmg /= weight_scale;
689 Wmm /= weight_scale;
690 Wme /= weight_scale;
691 Wmd /= weight_scale;
692
693 Weg /= weight_scale; (void) Weg; // unused from here on.
694 Wem /= weight_scale; (void) Wem; // unused from here on.
695 Wee /= weight_scale;
696 Wed /= weight_scale;
697
698 // Then, gather G, M, E, D, T to determine case
700 int is_exit = 0;
701 /* Bug #2203: Don't count bad exits as exits for balancing */
702 is_exit = rs->is_exit && !rs->is_bad_exit;
703 if (rs->has_bandwidth) {
704 T += rs->bandwidth_kb;
705 if (is_exit && rs->is_possible_guard) {
706 D += rs->bandwidth_kb;
707 Gtotal += Wgd*rs->bandwidth_kb;
708 Mtotal += Wmd*rs->bandwidth_kb;
709 Etotal += Wed*rs->bandwidth_kb;
710 } else if (is_exit) {
711 E += rs->bandwidth_kb;
712 Mtotal += Wme*rs->bandwidth_kb;
713 Etotal += Wee*rs->bandwidth_kb;
714 } else if (rs->is_possible_guard) {
715 G += rs->bandwidth_kb;
716 Gtotal += Wgg*rs->bandwidth_kb;
717 Mtotal += Wmg*rs->bandwidth_kb;
718 } else {
719 M += rs->bandwidth_kb;
720 Mtotal += Wmm*rs->bandwidth_kb;
721 }
722 } else {
723 log_warn(LD_BUG, "Missing consensus bandwidth for router %s",
725 }
726 } SMARTLIST_FOREACH_END(rs);
727
728 // Finally, check equality conditions depending upon case 1, 2 or 3
729 // Full equality cases: 1, 3b
730 // Partial equality cases: 2b (E=G), 3a (M=E)
731 // Fully unknown: 2a
732 if (3*E >= T && 3*G >= T) {
733 // Case 1: Neither are scarce
734 casename = "Case 1";
735 if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
736 log_warn(LD_DIR,
737 "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
738 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
739 " T=%"PRId64". "
740 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
741 casename, Etotal, Mtotal,
742 (G), (M), (E),
743 (D), (T),
744 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
745 valid = 0;
746 }
747 if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
748 log_warn(LD_DIR,
749 "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
750 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
751 " T=%"PRId64". "
752 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
753 casename, Etotal, Gtotal,
754 (G), (M), (E),
755 (D), (T),
756 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
757 valid = 0;
758 }
759 if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
760 log_warn(LD_DIR,
761 "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
762 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
763 " T=%"PRId64". "
764 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
765 casename, Mtotal, Gtotal,
766 (G), (M), (E),
767 (D), (T),
768 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
769 valid = 0;
770 }
771 } else if (3*E < T && 3*G < T) {
772 int64_t R = MIN(E, G);
773 int64_t S = MAX(E, G);
774 /*
775 * Case 2: Both Guards and Exits are scarce
776 * Balance D between E and G, depending upon
777 * D capacity and scarcity. Devote no extra
778 * bandwidth to middle nodes.
779 */
780 if (R+D < S) { // Subcase a
781 double Rtotal, Stotal;
782 if (E < G) {
783 Rtotal = Etotal;
784 Stotal = Gtotal;
785 } else {
786 Rtotal = Gtotal;
787 Stotal = Etotal;
788 }
789 casename = "Case 2a";
790 // Rtotal < Stotal
791 if (Rtotal > Stotal) {
792 log_warn(LD_DIR,
793 "Bw Weight Failure for %s: Rtotal %f > Stotal %f. "
794 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
795 " T=%"PRId64". "
796 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
797 casename, Rtotal, Stotal,
798 (G), (M), (E),
799 (D), (T),
800 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
801 valid = 0;
802 }
803 // Rtotal < T/3
804 if (3*Rtotal > T) {
805 log_warn(LD_DIR,
806 "Bw Weight Failure for %s: 3*Rtotal %f > T "
807 "%"PRId64". G=%"PRId64" M=%"PRId64" E=%"PRId64
808 " D=%"PRId64" T=%"PRId64". "
809 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
810 casename, Rtotal*3, (T),
811 (G), (M), (E),
812 (D), (T),
813 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
814 valid = 0;
815 }
816 // Stotal < T/3
817 if (3*Stotal > T) {
818 log_warn(LD_DIR,
819 "Bw Weight Failure for %s: 3*Stotal %f > T "
820 "%"PRId64". G=%"PRId64" M=%"PRId64" E=%"PRId64
821 " D=%"PRId64" T=%"PRId64". "
822 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
823 casename, Stotal*3, (T),
824 (G), (M), (E),
825 (D), (T),
826 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
827 valid = 0;
828 }
829 // Mtotal > T/3
830 if (3*Mtotal < T) {
831 log_warn(LD_DIR,
832 "Bw Weight Failure for %s: 3*Mtotal %f < T "
833 "%"PRId64". "
834 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
835 " T=%"PRId64". "
836 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
837 casename, Mtotal*3, (T),
838 (G), (M), (E),
839 (D), (T),
840 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
841 valid = 0;
842 }
843 } else { // Subcase b: R+D > S
844 casename = "Case 2b";
845
846 /* Check the rare-M redirect case. */
847 if (D != 0 && 3*M < T) {
848 casename = "Case 2b (balanced)";
849 if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
850 log_warn(LD_DIR,
851 "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
852 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
853 " T=%"PRId64". "
854 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
855 casename, Etotal, Mtotal,
856 (G), (M), (E),
857 (D), (T),
858 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
859 valid = 0;
860 }
861 if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
862 log_warn(LD_DIR,
863 "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
864 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
865 " T=%"PRId64". "
866 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
867 casename, Etotal, Gtotal,
868 (G), (M), (E),
869 (D), (T),
870 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
871 valid = 0;
872 }
873 if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
874 log_warn(LD_DIR,
875 "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
876 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
877 " T=%"PRId64". "
878 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
879 casename, Mtotal, Gtotal,
880 (G), (M), (E),
881 (D), (T),
882 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
883 valid = 0;
884 }
885 } else {
886 if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
887 log_warn(LD_DIR,
888 "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
889 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
890 " T=%"PRId64". "
891 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
892 casename, Etotal, Gtotal,
893 (G), (M), (E),
894 (D), (T),
895 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
896 valid = 0;
897 }
898 }
899 }
900 } else { // if (E < T/3 || G < T/3) {
901 int64_t S = MIN(E, G);
902 int64_t NS = MAX(E, G);
903 if (3*(S+D) < T) { // Subcase a:
904 double Stotal;
905 double NStotal;
906 if (G < E) {
907 casename = "Case 3a (G scarce)";
908 Stotal = Gtotal;
909 NStotal = Etotal;
910 } else { // if (G >= E) {
911 casename = "Case 3a (E scarce)";
912 NStotal = Gtotal;
913 Stotal = Etotal;
914 }
915 // Stotal < T/3
916 if (3*Stotal > T) {
917 log_warn(LD_DIR,
918 "Bw Weight Failure for %s: 3*Stotal %f > T "
919 "%"PRId64". G=%"PRId64" M=%"PRId64" E=%"PRId64
920 " D=%"PRId64" T=%"PRId64". "
921 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
922 casename, Stotal*3, (T),
923 (G), (M), (E),
924 (D), (T),
925 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
926 valid = 0;
927 }
928 if (NS >= M) {
929 if (fabs(NStotal-Mtotal) > 0.01*MAX(NStotal,Mtotal)) {
930 log_warn(LD_DIR,
931 "Bw Weight Failure for %s: NStotal %f != Mtotal %f. "
932 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
933 " T=%"PRId64". "
934 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
935 casename, NStotal, Mtotal,
936 (G), (M), (E),
937 (D), (T),
938 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
939 valid = 0;
940 }
941 } else {
942 // if NS < M, NStotal > T/3 because only one of G or E is scarce
943 if (3*NStotal < T) {
944 log_warn(LD_DIR,
945 "Bw Weight Failure for %s: 3*NStotal %f < T "
946 "%"PRId64". G=%"PRId64" M=%"PRId64
947 " E=%"PRId64" D=%"PRId64" T=%"PRId64". "
948 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
949 casename, NStotal*3, (T),
950 (G), (M), (E),
951 (D), (T),
952 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
953 valid = 0;
954 }
955 }
956 } else { // Subcase b: S+D >= T/3
957 casename = "Case 3b";
958 if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) {
959 log_warn(LD_DIR,
960 "Bw Weight Failure for %s: Etotal %f != Mtotal %f. "
961 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
962 " T=%"PRId64". "
963 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
964 casename, Etotal, Mtotal,
965 (G), (M), (E),
966 (D), (T),
967 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
968 valid = 0;
969 }
970 if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) {
971 log_warn(LD_DIR,
972 "Bw Weight Failure for %s: Etotal %f != Gtotal %f. "
973 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
974 " T=%"PRId64". "
975 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
976 casename, Etotal, Gtotal,
977 (G), (M), (E),
978 (D), (T),
979 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
980 valid = 0;
981 }
982 if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) {
983 log_warn(LD_DIR,
984 "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. "
985 "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64
986 " T=%"PRId64". "
987 "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f",
988 casename, Mtotal, Gtotal,
989 (G), (M), (E),
990 (D), (T),
991 Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed);
992 valid = 0;
993 }
994 }
995 }
996
997 if (valid)
998 log_notice(LD_DIR, "Bandwidth-weight %s is verified and valid.",
999 casename);
1000
1001 return valid;
1002}
1003
1004/** Check if a shared random value of type <b>srv_type</b> is in
1005 * <b>tokens</b>. If there is, parse it and set it to <b>srv_out</b>. Return
1006 * -1 on failure, 0 on success. The resulting srv is allocated on the heap and
1007 * it's the responsibility of the caller to free it. */
1008static int
1009extract_one_srv(smartlist_t *tokens, directory_keyword srv_type,
1010 sr_srv_t **srv_out)
1011{
1012 int ret = -1;
1013 directory_token_t *tok;
1014 sr_srv_t *srv = NULL;
1015 smartlist_t *chunks;
1016
1017 tor_assert(tokens);
1018
1019 chunks = smartlist_new();
1020 tok = find_opt_by_keyword(tokens, srv_type);
1021 if (!tok) {
1022 /* That's fine, no SRV is allowed. */
1023 ret = 0;
1024 goto end;
1025 }
1026 for (int i = 0; i < tok->n_args; i++) {
1027 smartlist_add(chunks, tok->args[i]);
1028 }
1029 srv = sr_parse_srv(chunks);
1030 if (srv == NULL) {
1031 log_warn(LD_DIR, "SR: Unparseable SRV %s", escaped(tok->object_body));
1032 goto end;
1033 }
1034 /* All is good. */
1035 *srv_out = srv;
1036 ret = 0;
1037 end:
1038 smartlist_free(chunks);
1039 return ret;
1040}
1041
1042/** Extract any shared random values found in <b>tokens</b> and place them in
1043 * the networkstatus <b>ns</b>. */
1044static void
1045extract_shared_random_srvs(networkstatus_t *ns, smartlist_t *tokens)
1046{
1047 const char *voter_identity;
1049
1050 tor_assert(ns);
1051 tor_assert(tokens);
1052 /* Can be only one of them else code flow. */
1053 tor_assert(ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_CONSENSUS);
1054
1055 if (ns->type == NS_TYPE_VOTE) {
1056 voter = smartlist_get(ns->voters, 0);
1057 tor_assert(voter);
1058 voter_identity = hex_str(voter->identity_digest,
1059 sizeof(voter->identity_digest));
1060 } else {
1061 /* Consensus has multiple voters so no specific voter. */
1062 voter_identity = "consensus";
1063 }
1064
1065 /* We extract both, and on error everything is stopped because it means
1066 * the vote is malformed for the shared random value(s). */
1067 if (extract_one_srv(tokens, K_PREVIOUS_SRV, &ns->sr_info.previous_srv) < 0) {
1068 log_warn(LD_DIR, "SR: Unable to parse previous SRV from %s",
1069 voter_identity);
1070 /* Maybe we have a chance with the current SRV so let's try it anyway. */
1071 }
1072 if (extract_one_srv(tokens, K_CURRENT_SRV, &ns->sr_info.current_srv) < 0) {
1073 log_warn(LD_DIR, "SR: Unable to parse current SRV from %s",
1074 voter_identity);
1075 }
1076}
1077
1078/** Allocate a copy of a protover line, if present. If present but malformed,
1079 * set *error to true. */
1080static char *
1081dup_protocols_string(smartlist_t *tokens, bool *error, directory_keyword kw)
1082{
1083 directory_token_t *tok = find_opt_by_keyword(tokens, kw);
1084 if (!tok)
1085 return NULL;
1086 if (protover_list_is_invalid(tok->args[0]))
1087 *error = true;
1088 return tor_strdup(tok->args[0]);
1089}
1090
1091/** Parse a v3 networkstatus vote, opinion, or consensus (depending on
1092 * ns_type), from <b>s</b>, and return the result. Return NULL on failure. */
1095 size_t s_len,
1096 const char **eos_out,
1097 networkstatus_type_t ns_type)
1098{
1099 smartlist_t *tokens = smartlist_new();
1100 smartlist_t *rs_tokens = NULL, *footer_tokens = NULL;
1101 networkstatus_voter_info_t *voter = NULL;
1102 networkstatus_t *ns = NULL;
1103 common_digests_t ns_digests;
1104 uint8_t sha3_as_signed[DIGEST256_LEN];
1105 const char *cert, *end_of_header, *end_of_footer, *s_dup = s;
1106 directory_token_t *tok;
1107 struct in_addr in;
1108 int i, inorder, n_signatures = 0;
1109 memarea_t *area = NULL, *rs_area = NULL;
1110 consensus_flavor_t flav = FLAV_NS;
1111 char *last_kwd=NULL;
1112 const char *eos = s + s_len;
1113
1114 tor_assert(s);
1115
1116 if (eos_out)
1117 *eos_out = NULL;
1118
1119 if (router_get_networkstatus_v3_hashes(s, s_len, &ns_digests) ||
1121 s, s_len)<0) {
1122 log_warn(LD_DIR, "Unable to compute digest of network-status");
1123 goto err;
1124 }
1125
1126 area = memarea_new();
1127 end_of_header = find_start_of_next_routerstatus(s, eos);
1128 if (tokenize_string(area, s, end_of_header, tokens,
1129 (ns_type == NS_TYPE_CONSENSUS) ?
1130 networkstatus_consensus_token_table :
1131 networkstatus_token_table, 0)) {
1132 log_warn(LD_DIR, "Error tokenizing network-status header");
1133 goto err;
1134 }
1135
1136 ns = tor_malloc_zero(sizeof(networkstatus_t));
1137 memcpy(&ns->digests, &ns_digests, sizeof(ns_digests));
1138 memcpy(&ns->digest_sha3_as_signed, sha3_as_signed, sizeof(sha3_as_signed));
1139
1140 tok = find_by_keyword(tokens, K_NETWORK_STATUS_VERSION);
1141 tor_assert(tok);
1142 if (tok->n_args > 1) {
1143 int flavor = networkstatus_parse_flavor_name(tok->args[1]);
1144 if (flavor < 0) {
1145 log_warn(LD_DIR, "Can't parse document with unknown flavor %s",
1146 escaped(tok->args[1]));
1147 goto err;
1148 }
1149 ns->flavor = flav = flavor;
1150 }
1151 if (flav != FLAV_NS && ns_type != NS_TYPE_CONSENSUS) {
1152 log_warn(LD_DIR, "Flavor found on non-consensus networkstatus.");
1153 goto err;
1154 }
1155
1156 if (ns_type != NS_TYPE_CONSENSUS) {
1157 const char *end_of_cert = NULL;
1158 if (!(cert = tor_memstr(s, end_of_header - s,
1159 "\ndir-key-certificate-version")))
1160 goto err;
1161 ++cert;
1162 ns->cert = authority_cert_parse_from_string(cert, end_of_header - cert,
1163 &end_of_cert);
1164 if (!ns->cert || !end_of_cert || end_of_cert > end_of_header)
1165 goto err;
1166 }
1167
1168 tok = find_by_keyword(tokens, K_VOTE_STATUS);
1169 tor_assert(tok->n_args);
1170 if (!strcmp(tok->args[0], "vote")) {
1171 ns->type = NS_TYPE_VOTE;
1172 } else if (!strcmp(tok->args[0], "consensus")) {
1173 ns->type = NS_TYPE_CONSENSUS;
1174 } else if (!strcmp(tok->args[0], "opinion")) {
1175 ns->type = NS_TYPE_OPINION;
1176 } else {
1177 log_warn(LD_DIR, "Unrecognized vote status %s in network-status",
1178 escaped(tok->args[0]));
1179 goto err;
1180 }
1181 if (ns_type != ns->type) {
1182 log_warn(LD_DIR, "Got the wrong kind of v3 networkstatus.");
1183 goto err;
1184 }
1185
1186 if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_OPINION) {
1187 tok = find_by_keyword(tokens, K_PUBLISHED);
1188 if (parse_iso_time(tok->args[0], &ns->published))
1189 goto err;
1190
1192 tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHODS);
1193 if (tok) {
1194 for (i=0; i < tok->n_args; ++i)
1196 } else {
1198 }
1199 } else {
1200 tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHOD);
1201 if (tok) {
1202 int num_ok;
1203 ns->consensus_method = (int)tor_parse_long(tok->args[0], 10, 1, INT_MAX,
1204 &num_ok, NULL);
1205 if (!num_ok)
1206 goto err;
1207 } else {
1208 ns->consensus_method = 1;
1209 }
1210 }
1211
1212 // Reject the vote if any of the protocols lines are malformed.
1213 bool unparseable = false;
1214 ns->recommended_client_protocols = dup_protocols_string(tokens, &unparseable,
1215 K_RECOMMENDED_CLIENT_PROTOCOLS);
1216 ns->recommended_relay_protocols = dup_protocols_string(tokens, &unparseable,
1217 K_RECOMMENDED_RELAY_PROTOCOLS);
1218 ns->required_client_protocols = dup_protocols_string(tokens, &unparseable,
1219 K_REQUIRED_CLIENT_PROTOCOLS);
1220 ns->required_relay_protocols = dup_protocols_string(tokens, &unparseable,
1221 K_REQUIRED_RELAY_PROTOCOLS);
1222 if (unparseable)
1223 goto err;
1224
1225 tok = find_by_keyword(tokens, K_VALID_AFTER);
1226 if (parse_iso_time(tok->args[0], &ns->valid_after))
1227 goto err;
1228
1229 tok = find_by_keyword(tokens, K_FRESH_UNTIL);
1230 if (parse_iso_time(tok->args[0], &ns->fresh_until))
1231 goto err;
1232
1233 tok = find_by_keyword(tokens, K_VALID_UNTIL);
1234 if (parse_iso_time(tok->args[0], &ns->valid_until))
1235 goto err;
1236
1237 tok = find_by_keyword(tokens, K_VOTING_DELAY);
1238 tor_assert(tok->n_args >= 2);
1239 {
1240 int ok;
1241 ns->vote_seconds =
1242 (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &ok, NULL);
1243 if (!ok)
1244 goto err;
1245 ns->dist_seconds =
1246 (int) tor_parse_long(tok->args[1], 10, 0, INT_MAX, &ok, NULL);
1247 if (!ok)
1248 goto err;
1249 }
1250 if (ns->valid_after +
1253 log_warn(LD_DIR, "Vote/consensus freshness interval is too short");
1254 goto err;
1255 }
1256 if (ns->valid_after +
1257 (get_options()->TestingTorNetwork ?
1259 log_warn(LD_DIR, "Vote/consensus liveness interval is too short");
1260 goto err;
1261 }
1262 if (ns->vote_seconds < MIN_VOTE_SECONDS) {
1263 log_warn(LD_DIR, "Vote seconds is too short");
1264 goto err;
1265 }
1266 if (ns->dist_seconds < MIN_DIST_SECONDS) {
1267 log_warn(LD_DIR, "Dist seconds is too short");
1268 goto err;
1269 }
1270
1271 if ((tok = find_opt_by_keyword(tokens, K_CLIENT_VERSIONS))) {
1272 ns->client_versions = tor_strdup(tok->args[0]);
1273 }
1274 if ((tok = find_opt_by_keyword(tokens, K_SERVER_VERSIONS))) {
1275 ns->server_versions = tor_strdup(tok->args[0]);
1276 }
1277
1278 {
1279 smartlist_t *package_lst = find_all_by_keyword(tokens, K_PACKAGE);
1281 if (package_lst) {
1282 SMARTLIST_FOREACH(package_lst, directory_token_t *, t,
1283 smartlist_add_strdup(ns->package_lines, t->args[0]));
1284 }
1285 smartlist_free(package_lst);
1286 }
1287
1288 tok = find_by_keyword(tokens, K_KNOWN_FLAGS);
1289 ns->known_flags = smartlist_new();
1290 inorder = 1;
1291 for (i = 0; i < tok->n_args; ++i) {
1293 if (i>0 && strcmp(tok->args[i-1], tok->args[i])>= 0) {
1294 log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]);
1295 inorder = 0;
1296 }
1297 }
1298 if (!inorder) {
1299 log_warn(LD_DIR, "known-flags not in order");
1300 goto err;
1301 }
1302 if (ns->type != NS_TYPE_CONSENSUS &&
1303 smartlist_len(ns->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) {
1304 /* If we allowed more than 64 flags in votes, then parsing them would make
1305 * us invoke undefined behavior whenever we used 1<<flagnum to do a
1306 * bit-shift. This is only for votes and opinions: consensus users don't
1307 * care about flags they don't recognize, and so don't build a bitfield
1308 * for them. */
1309 log_warn(LD_DIR, "Too many known-flags in consensus vote or opinion");
1310 goto err;
1311 }
1312
1313 tok = find_opt_by_keyword(tokens, K_PARAMS);
1314 if (tok) {
1315 int any_dups = 0;
1316 inorder = 1;
1317 ns->net_params = smartlist_new();
1318 for (i = 0; i < tok->n_args; ++i) {
1319 int ok=0;
1320 char *eq = strchr(tok->args[i], '=');
1321 size_t eq_pos;
1322 if (!eq) {
1323 log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
1324 goto err;
1325 }
1326 eq_pos = eq-tok->args[i];
1327 tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
1328 if (!ok) {
1329 log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
1330 goto err;
1331 }
1332 if (i > 0 && strcmp(tok->args[i-1], tok->args[i]) >= 0) {
1333 log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]);
1334 inorder = 0;
1335 }
1336 if (last_kwd && eq_pos == strlen(last_kwd) &&
1337 fast_memeq(last_kwd, tok->args[i], eq_pos)) {
1338 log_warn(LD_DIR, "Duplicate value for %s parameter",
1339 escaped(tok->args[i]));
1340 any_dups = 1;
1341 }
1342 tor_free(last_kwd);
1343 last_kwd = tor_strndup(tok->args[i], eq_pos);
1344 smartlist_add_strdup(ns->net_params, tok->args[i]);
1345 }
1346 if (!inorder) {
1347 log_warn(LD_DIR, "params not in order");
1348 goto err;
1349 }
1350 if (any_dups) {
1351 log_warn(LD_DIR, "Duplicate in parameters");
1352 goto err;
1353 }
1354 }
1355
1356 ns->voters = smartlist_new();
1357
1359 tok = _tok;
1360 if (tok->tp == K_DIR_SOURCE) {
1361 tor_assert(tok->n_args >= 6);
1362
1363 if (voter)
1364 smartlist_add(ns->voters, voter);
1365 voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
1366 voter->sigs = smartlist_new();
1367 if (ns->type != NS_TYPE_CONSENSUS)
1368 memcpy(voter->vote_digest, ns_digests.d[DIGEST_SHA1], DIGEST_LEN);
1369
1370 voter->nickname = tor_strdup(tok->args[0]);
1371 if (strlen(tok->args[1]) != HEX_DIGEST_LEN ||
1372 base16_decode(voter->identity_digest, sizeof(voter->identity_digest),
1373 tok->args[1], HEX_DIGEST_LEN)
1374 != sizeof(voter->identity_digest)) {
1375 log_warn(LD_DIR, "Error decoding identity digest %s in "
1376 "network-status document.", escaped(tok->args[1]));
1377 goto err;
1378 }
1379 if (ns->type != NS_TYPE_CONSENSUS &&
1381 voter->identity_digest, DIGEST_LEN)) {
1382 log_warn(LD_DIR,"Mismatch between identities in certificate and vote");
1383 goto err;
1384 }
1385 if (ns->type != NS_TYPE_CONSENSUS) {
1387 log_warn(LD_DIR, "Rejecting vote signature made with denylisted "
1388 "signing key %s",
1390 goto err;
1391 }
1392 }
1393 voter->address = tor_strdup(tok->args[2]);
1394 if (!tor_inet_aton(tok->args[3], &in)) {
1395 log_warn(LD_DIR, "Error decoding IP address %s in network-status.",
1396 escaped(tok->args[3]));
1397 goto err;
1398 }
1399 tor_addr_from_in(&voter->ipv4_addr, &in);
1400 int ok;
1401 voter->ipv4_dirport = (uint16_t)
1402 tor_parse_long(tok->args[4], 10, 0, 65535, &ok, NULL);
1403 if (!ok)
1404 goto err;
1405 voter->ipv4_orport = (uint16_t)
1406 tor_parse_long(tok->args[5], 10, 0, 65535, &ok, NULL);
1407 if (!ok)
1408 goto err;
1409 } else if (tok->tp == K_CONTACT) {
1410 if (!voter || voter->contact) {
1411 log_warn(LD_DIR, "contact element is out of place.");
1412 goto err;
1413 }
1414 voter->contact = tor_strdup(tok->args[0]);
1415 } else if (tok->tp == K_VOTE_DIGEST) {
1416 tor_assert(ns->type == NS_TYPE_CONSENSUS);
1417 tor_assert(tok->n_args >= 1);
1418 if (!voter || ! tor_digest_is_zero(voter->vote_digest)) {
1419 log_warn(LD_DIR, "vote-digest element is out of place.");
1420 goto err;
1421 }
1422 if (strlen(tok->args[0]) != HEX_DIGEST_LEN ||
1423 base16_decode(voter->vote_digest, sizeof(voter->vote_digest),
1424 tok->args[0], HEX_DIGEST_LEN)
1425 != sizeof(voter->vote_digest)) {
1426 log_warn(LD_DIR, "Error decoding vote digest %s in "
1427 "network-status consensus.", escaped(tok->args[0]));
1428 goto err;
1429 }
1430 }
1431 } SMARTLIST_FOREACH_END(_tok);
1432 if (voter) {
1433 smartlist_add(ns->voters, voter);
1434 voter = NULL;
1435 }
1436 if (smartlist_len(ns->voters) == 0) {
1437 log_warn(LD_DIR, "Missing dir-source elements in a networkstatus.");
1438 goto err;
1439 } else if (ns->type != NS_TYPE_CONSENSUS && smartlist_len(ns->voters) != 1) {
1440 log_warn(LD_DIR, "Too many dir-source elements in a vote networkstatus.");
1441 goto err;
1442 }
1443
1444 if (ns->type != NS_TYPE_CONSENSUS &&
1445 (tok = find_opt_by_keyword(tokens, K_LEGACY_DIR_KEY))) {
1446 int bad = 1;
1447 if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
1448 networkstatus_voter_info_t *voter_0 = smartlist_get(ns->voters, 0);
1450 tok->args[0], HEX_DIGEST_LEN) != DIGEST_LEN)
1451 bad = 1;
1452 else
1453 bad = 0;
1454 }
1455 if (bad) {
1456 log_warn(LD_DIR, "Invalid legacy key digest %s on vote.",
1457 escaped(tok->args[0]));
1458 }
1459 }
1460
1461 /* If this is a vote document, check if information about the shared
1462 randomness protocol is included, and extract it. */
1463 if (ns->type == NS_TYPE_VOTE) {
1464 dirvote_parse_sr_commits(ns, tokens);
1465 }
1466 /* For both a vote and consensus, extract the shared random values. */
1467 if (ns->type == NS_TYPE_VOTE || ns->type == NS_TYPE_CONSENSUS) {
1468 extract_shared_random_srvs(ns, tokens);
1469 }
1470
1471 /* Parse routerstatus lines. */
1472 rs_tokens = smartlist_new();
1473 rs_area = memarea_new();
1474 s = end_of_header;
1476
1477 while (eos - s >= 2 && fast_memeq(s, "r ", 2)) {
1478 if (ns->type != NS_TYPE_CONSENSUS) {
1479 vote_routerstatus_t *rs = tor_malloc_zero(sizeof(vote_routerstatus_t));
1480 if (routerstatus_parse_entry_from_string(rs_area, &s, eos, rs_tokens, ns,
1481 rs, 0, 0)) {
1483 } else {
1484 vote_routerstatus_free(rs);
1485 goto err; // Malformed routerstatus, reject this vote.
1486 }
1487 } else {
1488 routerstatus_t *rs;
1489 if ((rs = routerstatus_parse_entry_from_string(rs_area, &s, eos,
1490 rs_tokens,
1491 NULL, NULL,
1492 ns->consensus_method,
1493 flav))) {
1494 /* Use exponential-backoff scheduling when downloading microdescs */
1496 } else {
1497 goto err; // Malformed routerstatus, reject this vote.
1498 }
1499 }
1500 }
1501 for (i = 1; i < smartlist_len(ns->routerstatus_list); ++i) {
1502 routerstatus_t *rs1, *rs2;
1503 if (ns->type != NS_TYPE_CONSENSUS) {
1504 vote_routerstatus_t *a = smartlist_get(ns->routerstatus_list, i-1);
1505 vote_routerstatus_t *b = smartlist_get(ns->routerstatus_list, i);
1506 rs1 = &a->status; rs2 = &b->status;
1507 } else {
1508 rs1 = smartlist_get(ns->routerstatus_list, i-1);
1509 rs2 = smartlist_get(ns->routerstatus_list, i);
1510 }
1512 >= 0) {
1513 log_warn(LD_DIR, "Networkstatus entries not sorted by identity digest");
1514 goto err;
1515 }
1516 }
1517 if (ns_type != NS_TYPE_CONSENSUS) {
1518 digest256map_t *ed_id_map = digest256map_new();
1520 vrs) {
1521 if (! vrs->has_ed25519_listing ||
1522 fast_mem_is_zero((const char *)vrs->ed25519_id, DIGEST256_LEN))
1523 continue;
1524 if (digest256map_get(ed_id_map, vrs->ed25519_id) != NULL) {
1525 log_warn(LD_DIR, "Vote networkstatus ed25519 identities were not "
1526 "unique");
1527 digest256map_free(ed_id_map, NULL);
1528 goto err;
1529 }
1530 digest256map_set(ed_id_map, vrs->ed25519_id, (void*)1);
1531 } SMARTLIST_FOREACH_END(vrs);
1532 digest256map_free(ed_id_map, NULL);
1533 }
1534
1535 /* Parse footer; check signature. */
1536 footer_tokens = smartlist_new();
1537 if ((end_of_footer = tor_memstr(s, eos-s, "\nnetwork-status-version ")))
1538 ++end_of_footer;
1539 else
1540 end_of_footer = eos;
1541 if (tokenize_string(area,s, end_of_footer, footer_tokens,
1542 networkstatus_vote_footer_token_table, 0)) {
1543 log_warn(LD_DIR, "Error tokenizing network-status vote footer.");
1544 goto err;
1545 }
1546
1547 {
1548 int found_sig = 0;
1549 SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) {
1550 tok = _tok;
1551 if (tok->tp == K_DIRECTORY_SIGNATURE)
1552 found_sig = 1;
1553 else if (found_sig) {
1554 log_warn(LD_DIR, "Extraneous token after first directory-signature");
1555 goto err;
1556 }
1557 } SMARTLIST_FOREACH_END(_tok);
1558 }
1559
1560 if ((tok = find_opt_by_keyword(footer_tokens, K_DIRECTORY_FOOTER))) {
1561 if (tok != smartlist_get(footer_tokens, 0)) {
1562 log_warn(LD_DIR, "Misplaced directory-footer token");
1563 goto err;
1564 }
1565 }
1566
1567 tok = find_opt_by_keyword(footer_tokens, K_BW_WEIGHTS);
1568 if (tok) {
1570 for (i = 0; i < tok->n_args; ++i) {
1571 int ok=0;
1572 char *eq = strchr(tok->args[i], '=');
1573 if (!eq) {
1574 log_warn(LD_DIR, "Bad element '%s' in weight params",
1575 escaped(tok->args[i]));
1576 goto err;
1577 }
1578 tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL);
1579 if (!ok) {
1580 log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
1581 goto err;
1582 }
1584 }
1585 }
1586
1587 SMARTLIST_FOREACH_BEGIN(footer_tokens, directory_token_t *, _tok) {
1588 char declared_identity[DIGEST_LEN];
1591 const char *id_hexdigest = NULL;
1592 const char *sk_hexdigest = NULL;
1593 digest_algorithm_t alg = DIGEST_SHA1;
1594 tok = _tok;
1595 if (tok->tp != K_DIRECTORY_SIGNATURE)
1596 continue;
1597 tor_assert(tok->n_args >= 2);
1598 if (tok->n_args == 2) {
1599 id_hexdigest = tok->args[0];
1600 sk_hexdigest = tok->args[1];
1601 } else {
1602 const char *algname = tok->args[0];
1603 int a;
1604 id_hexdigest = tok->args[1];
1605 sk_hexdigest = tok->args[2];
1607 if (a<0) {
1608 log_warn(LD_DIR, "Unknown digest algorithm %s; skipping",
1609 escaped(algname));
1610 continue;
1611 }
1612 alg = a;
1613 }
1614
1615 if (!tok->object_type ||
1616 strcmp(tok->object_type, "SIGNATURE") ||
1617 tok->object_size < 128 || tok->object_size > 512) {
1618 log_warn(LD_DIR, "Bad object type or length on directory-signature");
1619 goto err;
1620 }
1621
1622 if (strlen(id_hexdigest) != HEX_DIGEST_LEN ||
1623 base16_decode(declared_identity, sizeof(declared_identity),
1624 id_hexdigest, HEX_DIGEST_LEN)
1625 != sizeof(declared_identity)) {
1626 log_warn(LD_DIR, "Error decoding declared identity %s in "
1627 "network-status document.", escaped(id_hexdigest));
1628 goto err;
1629 }
1630 if (!(v = networkstatus_get_voter_by_id(ns, declared_identity))) {
1631 log_warn(LD_DIR, "ID on signature on network-status document does "
1632 "not match any declared directory source.");
1633 goto err;
1634 }
1635 sig = tor_malloc_zero(sizeof(document_signature_t));
1636 memcpy(sig->identity_digest, v->identity_digest, DIGEST_LEN);
1637 sig->alg = alg;
1638 if (strlen(sk_hexdigest) != HEX_DIGEST_LEN ||
1640 sk_hexdigest, HEX_DIGEST_LEN)
1641 != sizeof(sig->signing_key_digest)) {
1642 log_warn(LD_DIR, "Error decoding declared signing key digest %s in "
1643 "network-status document.", escaped(sk_hexdigest));
1644 tor_free(sig);
1645 goto err;
1646 }
1647
1648 if (ns->type != NS_TYPE_CONSENSUS) {
1649 if (tor_memneq(declared_identity, ns->cert->cache_info.identity_digest,
1650 DIGEST_LEN)) {
1651 log_warn(LD_DIR, "Digest mismatch between declared and actual on "
1652 "network-status vote.");
1653 tor_free(sig);
1654 goto err;
1655 }
1656 }
1657
1659 /* We already parsed a vote with this algorithm from this voter. Use the
1660 first one. */
1661 log_fn(LOG_PROTOCOL_WARN, LD_DIR, "We received a networkstatus "
1662 "that contains two signatures from the same voter with the same "
1663 "algorithm. Ignoring the second signature.");
1664 tor_free(sig);
1665 continue;
1666 }
1667
1668 if (ns->type != NS_TYPE_CONSENSUS) {
1669 if (check_signature_token(ns_digests.d[DIGEST_SHA1], DIGEST_LEN,
1670 tok, ns->cert->signing_key, 0,
1671 "network-status document")) {
1672 tor_free(sig);
1673 goto err;
1674 }
1675 sig->good_signature = 1;
1676 } else {
1677 if (tok->object_size >= INT_MAX || tok->object_size >= SIZE_T_CEILING) {
1678 tor_free(sig);
1679 goto err;
1680 }
1681 sig->signature = tor_memdup(tok->object_body, tok->object_size);
1682 sig->signature_len = (int) tok->object_size;
1683 }
1684 smartlist_add(v->sigs, sig);
1685
1686 ++n_signatures;
1687 } SMARTLIST_FOREACH_END(_tok);
1688
1689 if (! n_signatures) {
1690 log_warn(LD_DIR, "No signatures on networkstatus document.");
1691 goto err;
1692 } else if (ns->type == NS_TYPE_VOTE && n_signatures != 1) {
1693 log_warn(LD_DIR, "Received more than one signature on a "
1694 "network-status vote.");
1695 goto err;
1696 }
1697
1698 if (eos_out)
1699 *eos_out = end_of_footer;
1700
1701 goto done;
1702 err:
1703 dump_desc(s_dup, "v3 networkstatus");
1704 networkstatus_vote_free(ns);
1705 ns = NULL;
1706 done:
1707 if (tokens) {
1709 smartlist_free(tokens);
1710 }
1711 if (voter) {
1712 if (voter->sigs) {
1714 document_signature_free(sig));
1715 smartlist_free(voter->sigs);
1716 }
1717 tor_free(voter->nickname);
1718 tor_free(voter->address);
1719 tor_free(voter->contact);
1720 tor_free(voter);
1721 }
1722 if (rs_tokens) {
1723 SMARTLIST_FOREACH(rs_tokens, directory_token_t *, t, token_clear(t));
1724 smartlist_free(rs_tokens);
1725 }
1726 if (footer_tokens) {
1727 SMARTLIST_FOREACH(footer_tokens, directory_token_t *, t, token_clear(t));
1728 smartlist_free(footer_tokens);
1729 }
1730 if (area) {
1731 DUMP_AREA(area, "v3 networkstatus");
1732 memarea_drop_all(area);
1733 }
1734 if (rs_area)
1735 memarea_drop_all(rs_area);
1736 tor_free(last_kwd);
1737
1738 return ns;
1739}
#define tor_addr_from_in(dest, in)
Definition: address.h:331
#define fmt_addr(a)
Definition: address.h:239
int authority_cert_is_denylisted(const authority_cert_t *cert)
Definition: authcert.c:744
Header file for authcert.c.
List of tokens common to V3 authority certificates and V3 consensuses.
authority_cert_t * authority_cert_parse_from_string(const char *s, size_t maxlen, const char **end_of_string)
Header file for authcert_parse.c.
Authority certificate structure.
const char * hex_str(const char *from, size_t fromlen)
Definition: binascii.c:34
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
Definition: binascii.c:506
#define MAX(a, b)
Definition: cmp.h:22
const or_options_t * get_options(void)
Definition: config.c:944
Header file for config.c.
int crypto_digest_algorithm_parse_name(const char *name)
Definition: crypto_digest.c:68
digest_algorithm_t
Definition: crypto_digest.h:44
#define HEX_DIGEST_LEN
Definition: crypto_digest.h:35
int crypto_digest256(char *digest, const char *m, size_t len, digest_algorithm_t algorithm)
int digest256_from_base64(char *digest, const char *d64)
int digest_from_base64(char *digest, const char *d64)
Header for crypto_format.c.
const char * routerstatus_describe(const routerstatus_t *rs)
Definition: describe.c:203
Header file for describe.c.
#define fast_memeq(a, b, c)
Definition: di_ops.h:35
#define fast_memcmp(a, b, c)
Definition: di_ops.h:28
#define tor_memneq(a, b, sz)
Definition: di_ops.h:21
#define DIGEST_LEN
Definition: digest_sizes.h:20
#define DIGEST256_LEN
Definition: digest_sizes.h:23
Header file for dirvote.c.
#define MIN_VOTE_INTERVAL_TESTING
Definition: dirvote.h:46
#define MIN_VOTE_INTERVAL
Definition: dirvote.h:37
#define MIN_DIST_SECONDS
Definition: dirvote.h:32
#define MIN_VOTE_SECONDS
Definition: dirvote.h:27
Authority signature structure.
int should_apply_guardfraction(const networkstatus_t *ns)
Definition: entrynodes.c:189
Header file for circuitbuild.c.
const char * escaped(const char *s)
Definition: escape.c:126
int tor_inet_aton(const char *str, struct in_addr *addr)
Definition: inaddr.c:40
#define log_fn(severity, domain, args,...)
Definition: log.h:283
#define LD_BUG
Definition: log.h:86
#define LD_GENERAL
Definition: log.h:62
#define LD_DIR
Definition: log.h:88
#define LOG_INFO
Definition: log.h:45
#define bool_eq(a, b)
Definition: logic.h:16
#define tor_free(p)
Definition: malloc.h:56
void memarea_clear(memarea_t *area)
Definition: memarea.c:178
memarea_t * memarea_new(void)
Definition: memarea.c:153
Header for memarea.c.
#define memarea_drop_all(area)
Definition: memarea.h:22
int networkstatus_parse_flavor_name(const char *flavname)
document_signature_t * networkstatus_get_voter_sig_by_alg(const networkstatus_voter_info_t *voter, digest_algorithm_t alg)
networkstatus_voter_info_t * networkstatus_get_voter_by_id(networkstatus_t *vote, const char *identity)
int32_t networkstatus_get_bw_weight(networkstatus_t *ns, const char *weight_name, int32_t default_val)
int networkstatus_get_weight_scale_param(networkstatus_t *ns)
Header file for networkstatus.c.
Networkstatus consensus/vote structure.
networkstatus_type_t
Single consensus voter structure.
int is_legal_nickname(const char *s)
Definition: nickname.c:19
Header file for nickname.c.
Header file for ns_parse.c.
int router_get_networkstatus_v3_sha3_as_signed(uint8_t *digest_out, const char *s, size_t len)
Definition: ns_parse.c:179
int router_get_networkstatus_v3_signed_boundaries(const char *s, size_t len, const char **start_out, const char **end_out)
Definition: ns_parse.c:163
networkstatus_t * networkstatus_parse_vote_from_string(const char *s, size_t len, const char **eos_out, enum networkstatus_type_t ns_type)
Definition: ns_parse.c:1094
int networkstatus_verify_bw_weights(networkstatus_t *ns, int)
Definition: ns_parse.c:613
int router_get_networkstatus_v3_hashes(const char *s, size_t len, common_digests_t *digests)
Definition: ns_parse.c:197
Master header file for Tor-specific functionality.
#define UNNAMED_ROUTER_NICKNAME
Definition: or.h:449
consensus_flavor_t
Definition: or.h:763
long tor_parse_long(const char *s, int base, long min, long max, int *ok, char **next)
Definition: parse_int.c:59
unsigned long tor_parse_ulong(const char *s, int base, unsigned long min, unsigned long max, int *ok, char **next)
Definition: parse_int.c:78
void token_clear(directory_token_t *tok)
Definition: parsecommon.c:41
smartlist_t * find_all_by_keyword(const smartlist_t *s, directory_keyword k)
Definition: parsecommon.c:451
int tokenize_string(memarea_t *area, const char *start, const char *end, smartlist_t *out, const token_rule_t *table, int flags)
Definition: parsecommon.c:53
directory_token_t * find_opt_by_keyword(const smartlist_t *s, directory_keyword keyword)
Definition: parsecommon.c:440
Header file for parsecommon.c.
#define T0N(s, t, a, o)
Definition: parsecommon.h:249
#define T01(s, t, a, o)
Definition: parsecommon.h:259
#define NO_ARGS
Definition: parsecommon.h:266
@ OBJ_OK
Definition: parsecommon.h:225
@ NO_OBJ
Definition: parsecommon.h:221
@ NEED_OBJ
Definition: parsecommon.h:222
directory_keyword
Definition: parsecommon.h:23
#define T(s, t, a, o)
Definition: parsecommon.h:247
#define T1_START(s, t, a, o)
Definition: parsecommon.h:253
#define T1N(s, t, a, o)
Definition: parsecommon.h:257
#define GE(n)
Definition: parsecommon.h:270
#define CONCAT_ARGS
Definition: parsecommon.h:268
#define T1(s, t, a, o)
Definition: parsecommon.h:251
#define EQ(n)
Definition: parsecommon.h:272
#define END_OF_TABLE
Definition: parsecommon.h:245
#define ARGS
Definition: parsecommon.h:264
int tor_snprintf(char *str, size_t size, const char *format,...)
Definition: printf.c:27
bool protover_list_is_invalid(const char *s)
Definition: protover.c:301
Headers and type declarations for protover.c.
int find_single_ipv6_orport(const smartlist_t *list, tor_addr_t *addr_out, uint16_t *port_out)
Definition: routerparse.c:340
Header file for routerparse.c.
sr_srv_t * sr_parse_srv(const smartlist_t *args)
Header file for shared_random_client.c.
int check_signature_token(const char *digest, ssize_t digest_len, directory_token_t *tok, crypto_pk_t *pkey, int flags, const char *doctype)
Definition: sigcommon.c:148
int router_get_hash_impl_helper(const char *s, size_t s_len, const char *start_str, const char *end_str, char end_c, int log_severity, const char **start_out, const char **end_out)
Definition: sigcommon.c:27
int router_get_hashes_impl(const char *s, size_t s_len, common_digests_t *digests, const char *start_str, const char *end_str, char end_c)
Definition: sigcommon.c:112
Header file for sigcommon.c.
int smartlist_string_pos(const smartlist_t *sl, const char *element)
Definition: smartlist.c:106
void smartlist_add_strdup(struct smartlist_t *sl, const char *string)
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
void smartlist_clear(smartlist_t *sl)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
crypto_pk_t * signing_key
char signing_key_digest[DIGEST_LEN]
signed_descriptor_t cache_info
char d[N_COMMON_DIGEST_ALGORITHMS][DIGEST256_LEN]
Definition: crypto_digest.h:89
directory_keyword tp
Definition: parsecommon.h:204
char identity_digest[DIGEST_LEN]
digest_algorithm_t alg
char signing_key_digest[DIGEST_LEN]
smartlist_t * known_flags
common_digests_t digests
char * recommended_relay_protocols
smartlist_t * voters
smartlist_t * net_params
smartlist_t * weight_params
smartlist_t * package_lines
smartlist_t * supported_methods
smartlist_t * routerstatus_list
unsigned int has_measured_bws
networkstatus_sr_info_t sr_info
uint8_t digest_sha3_as_signed[DIGEST256_LEN]
struct authority_cert_t * cert
consensus_flavor_t flavor
networkstatus_type_t type
unsigned int is_bad_exit
uint16_t ipv6_orport
tor_addr_t ipv6_addr
unsigned int is_sybil
protover_summary_flags_t pv
unsigned int is_staledesc
char descriptor_digest[DIGEST256_LEN]
unsigned int has_exitsummary
char identity_digest[DIGEST_LEN]
unsigned int is_hs_dir
unsigned int has_guardfraction
unsigned int is_valid
unsigned int bw_is_unmeasured
char nickname[MAX_NICKNAME_LEN+1]
unsigned int has_bandwidth
uint16_t ipv4_dirport
unsigned int is_named
unsigned int is_possible_guard
unsigned int is_stable
unsigned int is_flagged_running
unsigned int is_exit
unsigned int is_middle_only
unsigned int is_authority
uint32_t guardfraction_percentage
unsigned int is_fast
uint32_t bandwidth_kb
uint16_t ipv4_orport
unsigned int is_unnamed
char identity_digest[DIGEST_LEN]
struct vote_microdesc_hash_t * next
uint8_t ed25519_id[ED25519_PUBKEY_LEN]
unsigned int has_ed25519_listing
vote_microdesc_hash_t * microdesc
#define STATIC
Definition: testsupport.h:32
int parse_iso_time(const char *cp, time_t *t)
Definition: time_fmt.c:423
#define SIZE_T_CEILING
Definition: torint.h:126
void dump_desc(const char *desc, const char *type)
Definition: unparseable.c:496
Header file for unparseable.c.
#define tor_assert(expr)
Definition: util_bug.h:103
int strcmpstart(const char *s1, const char *s2)
Definition: util_string.c:217
int fast_mem_is_zero(const char *mem, size_t len)
Definition: util_string.c:76
int tor_digest_is_zero(const char *digest)
Definition: util_string.c:98
void summarize_protover_flags(protover_summary_flags_t *out, const char *protocols, const char *version)
Definition: versions.c:514
Header file for versions.c.
Microdescriptor-hash voting structure.
Routerstatus (vote entry) structure.
#define MAX_KNOWN_FLAGS_IN_VOTE