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