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