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