Tor  0.4.7.0-alpha-dev
protover.c
Go to the documentation of this file.
1 /* Copyright (c) 2016-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
4 /**
5  * \file protover.c
6  * \brief Versioning information for different pieces of the Tor protocol.
7  *
8  * Starting in version 0.2.9.3-alpha, Tor places separate version numbers on
9  * each of the different components of its protocol. Relays use these numbers
10  * to advertise what versions of the protocols they can support, and clients
11  * use them to find what they can ask a given relay to do. Authorities vote
12  * on the supported protocol versions for each relay, and also vote on the
13  * which protocols you should have to support in order to be on the Tor
14  * network. All Tor instances use these required/recommended protocol versions
15  * to tell what level of support for recent protocols each relay has, and
16  * to decide whether they should be running given their current protocols.
17  *
18  * The main advantage of these protocol versions numbers over using Tor
19  * version numbers is that they allow different implementations of the Tor
20  * protocols to develop independently, without having to claim compatibility
21  * with specific versions of Tor.
22  **/
23 
24 #define PROTOVER_PRIVATE
25 
26 #include "core/or/or.h"
27 #include "core/or/protover.h"
28 #include "core/or/versions.h"
29 #include "lib/tls/tortls.h"
30 
31 #ifndef HAVE_RUST
32 
33 static const smartlist_t *get_supported_protocol_list(void);
34 static int protocol_list_contains(const smartlist_t *protos,
35  protocol_type_t pr, uint32_t ver);
36 static const proto_entry_t *find_entry_by_name(const smartlist_t *protos,
37  const char *name);
38 
39 /** Mapping between protocol type string and protocol type. */
40 /// C_RUST_COUPLED: src/rust/protover/protover.rs `PROTOCOL_NAMES`
41 static const struct {
42  protocol_type_t protover_type;
43  const char *name;
44 /* If you add a new protocol here, you probably also want to add
45  * parsing for it in summarize_protover_flags(), so that it has a
46  * summary flag in routerstatus_t */
47 } PROTOCOL_NAMES[] = {
48  { PRT_LINK, "Link" },
49  { PRT_LINKAUTH, "LinkAuth" },
50  { PRT_RELAY, "Relay" },
51  { PRT_DIRCACHE, "DirCache" },
52  { PRT_HSDIR, "HSDir" },
53  { PRT_HSINTRO, "HSIntro" },
54  { PRT_HSREND, "HSRend" },
55  { PRT_DESC, "Desc" },
56  { PRT_MICRODESC, "Microdesc"},
57  { PRT_PADDING, "Padding"},
58  { PRT_CONS, "Cons" },
59  { PRT_FLOWCTRL, "FlowCtrl"},
60 };
61 
62 #define N_PROTOCOL_NAMES ARRAY_LENGTH(PROTOCOL_NAMES)
63 
64 /* Maximum allowed length of any single subprotocol name. */
65 // C_RUST_COUPLED: src/rust/protover/protover.rs
66 // `MAX_PROTOCOL_NAME_LENGTH`
67 static const unsigned MAX_PROTOCOL_NAME_LENGTH = 100;
68 
69 /**
70  * Given a protocol_type_t, return the corresponding string used in
71  * descriptors.
72  */
73 STATIC const char *
75 {
76  unsigned i;
77  for (i=0; i < N_PROTOCOL_NAMES; ++i) {
78  if (PROTOCOL_NAMES[i].protover_type == pr)
79  return PROTOCOL_NAMES[i].name;
80  }
81  /* LCOV_EXCL_START */
82  tor_assert_nonfatal_unreached_once();
83  return "UNKNOWN";
84  /* LCOV_EXCL_STOP */
85 }
86 
87 /**
88  * Release all space held by a single proto_entry_t structure
89  */
90 STATIC void
91 proto_entry_free_(proto_entry_t *entry)
92 {
93  if (!entry)
94  return;
95  tor_free(entry->name);
96  tor_free(entry);
97 }
98 
99 /** The largest possible protocol version. */
100 #define MAX_PROTOCOL_VERSION (63)
101 
102 /**
103  * Given a string <b>s</b> and optional end-of-string pointer
104  * <b>end_of_range</b>, parse the protocol range and store it in
105  * <b>low_out</b> and <b>high_out</b>. A protocol range has the format U, or
106  * U-U, where U is an unsigned integer between 0 and 63 inclusive.
107  */
108 static int
109 parse_version_range(const char *s, const char *end_of_range,
110  uint32_t *low_out, uint32_t *high_out)
111 {
112  uint32_t low, high;
113  char *next = NULL;
114  int ok;
115 
116  tor_assert(high_out);
117  tor_assert(low_out);
118 
119  if (BUG(!end_of_range))
120  end_of_range = s + strlen(s); // LCOV_EXCL_LINE
121 
122  /* A range must start with a digit. */
123  if (!TOR_ISDIGIT(*s)) {
124  goto error;
125  }
126 
127  /* Note that this wouldn't be safe if we didn't know that eventually,
128  * we'd hit a NUL */
129  low = (uint32_t) tor_parse_ulong(s, 10, 0, MAX_PROTOCOL_VERSION, &ok, &next);
130  if (!ok)
131  goto error;
132  if (next > end_of_range)
133  goto error;
134  if (next == end_of_range) {
135  high = low;
136  goto done;
137  }
138 
139  if (*next != '-')
140  goto error;
141  s = next+1;
142 
143  /* ibid */
144  if (!TOR_ISDIGIT(*s)) {
145  goto error;
146  }
147  high = (uint32_t) tor_parse_ulong(s, 10, 0,
148  MAX_PROTOCOL_VERSION, &ok, &next);
149  if (!ok)
150  goto error;
151  if (next != end_of_range)
152  goto error;
153 
154  if (low > high)
155  goto error;
156 
157  done:
158  *high_out = high;
159  *low_out = low;
160  return 0;
161 
162  error:
163  return -1;
164 }
165 
166 static int
167 is_valid_keyword(const char *s, size_t n)
168 {
169  for (size_t i = 0; i < n; i++) {
170  if (!TOR_ISALNUM(s[i]) && s[i] != '-')
171  return 0;
172  }
173  return 1;
174 }
175 
176 /** The x'th bit in a bitmask. */
177 #define BIT(x) (UINT64_C(1)<<(x))
178 
179 /**
180  * Return a bitmask so that bits 'low' through 'high' inclusive are set,
181  * and all other bits are cleared.
182  **/
183 static uint64_t
184 bitmask_for_range(uint32_t low, uint32_t high)
185 {
186  uint64_t mask = ~(uint64_t)0;
187  mask <<= 63 - high;
188  mask >>= 63 - high + low;
189  mask <<= low;
190  return mask;
191 }
192 
193 /** Parse a single protocol entry from <b>s</b> up to an optional
194  * <b>end_of_entry</b> pointer, and return that protocol entry. Return NULL
195  * on error.
196  *
197  * A protocol entry has a keyword, an = sign, and zero or more ranges. */
198 static proto_entry_t *
199 parse_single_entry(const char *s, const char *end_of_entry)
200 {
201  proto_entry_t *out = tor_malloc_zero(sizeof(proto_entry_t));
202  const char *equals;
203 
204  if (BUG (!end_of_entry))
205  end_of_entry = s + strlen(s); // LCOV_EXCL_LINE
206 
207  /* There must be an =. */
208  equals = memchr(s, '=', end_of_entry - s);
209  if (!equals)
210  goto error;
211 
212  /* The name must be nonempty */
213  if (equals == s)
214  goto error;
215 
216  /* The name must not be longer than MAX_PROTOCOL_NAME_LENGTH. */
217  if (equals - s > (int)MAX_PROTOCOL_NAME_LENGTH) {
218  log_warn(LD_NET, "When parsing a protocol entry, I got a very large "
219  "protocol name. This is possibly an attack or a bug, unless "
220  "the Tor network truly supports protocol names larger than "
221  "%ud characters. The offending string was: %s",
222  MAX_PROTOCOL_NAME_LENGTH, escaped(out->name));
223  goto error;
224  }
225 
226  /* The name must contain only alphanumeric characters and hyphens. */
227  if (!is_valid_keyword(s, equals-s))
228  goto error;
229 
230  out->name = tor_strndup(s, equals-s);
231 
232  tor_assert(equals < end_of_entry);
233 
234  s = equals + 1;
235  while (s < end_of_entry) {
236  const char *comma = memchr(s, ',', end_of_entry-s);
237  if (! comma)
238  comma = end_of_entry;
239 
240  uint32_t low=0, high=0;
241  if (parse_version_range(s, comma, &low, &high) < 0) {
242  goto error;
243  }
244 
245  out->bitmask |= bitmask_for_range(low,high);
246 
247  s = comma;
248  // Skip the comma separator between ranges. Don't ignore a trailing comma.
249  if (s < (end_of_entry - 1))
250  ++s;
251  }
252 
253  return out;
254 
255  error:
256  proto_entry_free(out);
257  return NULL;
258 }
259 
260 /**
261  * Parse the protocol list from <b>s</b> and return it as a smartlist of
262  * proto_entry_t
263  */
265 parse_protocol_list(const char *s)
266 {
267  smartlist_t *entries = smartlist_new();
268 
269  while (*s) {
270  /* Find the next space or the NUL. */
271  const char *end_of_entry = strchr(s, ' ');
272  proto_entry_t *entry;
273  if (!end_of_entry)
274  end_of_entry = s + strlen(s);
275 
276  entry = parse_single_entry(s, end_of_entry);
277 
278  if (! entry)
279  goto error;
280 
281  smartlist_add(entries, entry);
282 
283  s = end_of_entry;
284  while (*s == ' ')
285  ++s;
286  }
287 
288  return entries;
289 
290  error:
291  SMARTLIST_FOREACH(entries, proto_entry_t *, ent, proto_entry_free(ent));
292  smartlist_free(entries);
293  return NULL;
294 }
295 
296 /**
297  * Return true if the unparsed protover list in <b>s</b> contains a
298  * parsing error, such as extra commas, a bad number, or an over-long
299  * name.
300  */
301 bool
303 {
304  smartlist_t *list = parse_protocol_list(s);
305  if (!list)
306  return true; /* yes, has a dangerous name */
307  SMARTLIST_FOREACH(list, proto_entry_t *, ent, proto_entry_free(ent));
308  smartlist_free(list);
309  return false; /* no, looks fine */
310 }
311 
312 /**
313  * Given a protocol type and version number, return true iff we know
314  * how to speak that protocol.
315  */
316 int
318 {
320  return protocol_list_contains(ours, pr, ver);
321 }
322 
323 /**
324  * Return true iff "list" encodes a protocol list that includes support for
325  * the indicated protocol and version.
326  *
327  * If the protocol list is unparseable, treat it as if it defines no
328  * protocols, and return 0.
329  */
330 int
332  uint32_t version)
333 {
334  /* NOTE: This is a pretty inefficient implementation. If it ever shows
335  * up in profiles, we should memoize it.
336  */
337  smartlist_t *protocols = parse_protocol_list(list);
338  if (!protocols) {
339  return 0;
340  }
341  int contains = protocol_list_contains(protocols, tp, version);
342 
343  SMARTLIST_FOREACH(protocols, proto_entry_t *, ent, proto_entry_free(ent));
344  smartlist_free(protocols);
345  return contains;
346 }
347 
348 /**
349  * Return true iff "list" encodes a protocol list that includes support for
350  * the indicated protocol and version, or some later version.
351  *
352  * If the protocol list is unparseable, treat it as if it defines no
353  * protocols, and return 0.
354  */
355 int
357  protocol_type_t tp,
358  uint32_t version)
359 {
360  /* NOTE: This is a pretty inefficient implementation. If it ever shows
361  * up in profiles, we should memoize it.
362  */
363  smartlist_t *protocols = parse_protocol_list(list);
364  if (!protocols) {
365  return 0;
366  }
367  const char *pr_name = protocol_type_to_str(tp);
368 
369  int contains = 0;
370  const uint64_t mask = bitmask_for_range(version, 63);
371 
372  SMARTLIST_FOREACH_BEGIN(protocols, proto_entry_t *, proto) {
373  if (strcasecmp(proto->name, pr_name))
374  continue;
375  if (0 != (proto->bitmask & mask)) {
376  contains = 1;
377  goto found;
378  }
379  } SMARTLIST_FOREACH_END(proto);
380 
381  found:
382  SMARTLIST_FOREACH(protocols, proto_entry_t *, ent, proto_entry_free(ent));
383  smartlist_free(protocols);
384  return contains;
385 }
386 
387 /** Return the canonical string containing the list of protocols
388  * that we support. */
389 /// C_RUST_COUPLED: src/rust/protover/protover.rs `SUPPORTED_PROTOCOLS`
390 const char *
392 {
393  /* WARNING!
394  *
395  * Remember to edit the SUPPORTED_PROTOCOLS list in protover.rs if you
396  * are editing this list.
397  */
398  return
399  "Cons=1-2 "
400  "Desc=1-2 "
401  "DirCache=2 "
402  "FlowCtrl=1 "
403  "HSDir=1-2 "
404  "HSIntro=3-5 "
405  "HSRend=1-2 "
406  "Link=1-5 "
407 #ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
408  "LinkAuth=1,3 "
409 #else
410  "LinkAuth=3 "
411 #endif
412  "Microdesc=1-2 "
413  "Padding=2 "
414  "Relay=1-3";
415 }
416 
417 /** The protocols from protover_get_supported_protocols(), as parsed into a
418  * list of proto_entry_t values. Access this via
419  * get_supported_protocol_list. */
421 
422 /** Return a pointer to a smartlist of proto_entry_t for the protocols
423  * we support. */
424 static const smartlist_t *
426 {
427  if (PREDICT_UNLIKELY(supported_protocol_list == NULL)) {
430  }
432 }
433 
434 /** Return the number of trailing zeros in x. Undefined if x is 0. */
435 static int
436 trailing_zeros(uint64_t x)
437 {
438 #ifdef __GNUC__
439  return __builtin_ctzll((unsigned long long)x);
440 #else
441  int i;
442  for (i = 0; i <= 64; ++i) {
443  if (x&1)
444  return i;
445  x>>=1;
446  }
447  return i;
448 #endif /* defined(__GNUC__) */
449 }
450 
451 /**
452  * Given a protocol entry, encode it at the end of the smartlist <b>chunks</b>
453  * as one or more newly allocated strings.
454  */
455 static void
456 proto_entry_encode_into(smartlist_t *chunks, const proto_entry_t *entry)
457 {
458  smartlist_add_asprintf(chunks, "%s=", entry->name);
459 
460  uint64_t mask = entry->bitmask;
461  int shift = 0; // how much have we shifted by so far?
462  bool first = true;
463  while (mask) {
464  const char *comma = first ? "" : ",";
465  if (first) {
466  first = false;
467  }
468  int zeros = trailing_zeros(mask);
469  mask >>= zeros;
470  shift += zeros;
471  int ones = !mask ? 64 : trailing_zeros(~mask);
472  if (ones == 1) {
473  smartlist_add_asprintf(chunks, "%s%d", comma, shift);
474  } else {
475  smartlist_add_asprintf(chunks, "%s%d-%d", comma,
476  shift, shift + ones - 1);
477  }
478  if (ones == 64) {
479  break; // avoid undefined behavior; can't shift by 64.
480  }
481  mask >>= ones;
482  shift += ones;
483  }
484 }
485 
486 /** Given a list of space-separated proto_entry_t items,
487  * encode it into a newly allocated space-separated string. */
488 STATIC char *
490 {
491  const char *separator = "";
492  smartlist_t *chunks = smartlist_new();
493  SMARTLIST_FOREACH_BEGIN(sl, const proto_entry_t *, ent) {
494  smartlist_add_strdup(chunks, separator);
495 
496  proto_entry_encode_into(chunks, ent);
497 
498  separator = " ";
499  } SMARTLIST_FOREACH_END(ent);
500 
501  char *result = smartlist_join_strings(chunks, "", 0, NULL);
502 
503  SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
504  smartlist_free(chunks);
505 
506  return result;
507 }
508 
509 /**
510  * Protocol voting implementation.
511  *
512  * Given a list of strings describing protocol versions, return a newly
513  * allocated string encoding all of the protocols that are listed by at
514  * least <b>threshold</b> of the inputs.
515  *
516  * The string is minimal and sorted according to the rules of
517  * contract_protocol_list above.
518  */
519 char *
520 protover_compute_vote(const smartlist_t *list_of_proto_strings,
521  int threshold)
522 {
523  // we use u8 counters below.
524  tor_assert(smartlist_len(list_of_proto_strings) < 256);
525 
526  if (smartlist_len(list_of_proto_strings) == 0) {
527  return tor_strdup("");
528  }
529 
530  smartlist_t *parsed = smartlist_new(); // smartlist of smartlist of entries
531  smartlist_t *proto_names = smartlist_new(); // smartlist of strings
532  smartlist_t *result = smartlist_new(); // smartlist of entries
533 
534  // First, parse the inputs, and accumulate a list of protocol names.
535  SMARTLIST_FOREACH_BEGIN(list_of_proto_strings, const char *, vote) {
536  smartlist_t *unexpanded = parse_protocol_list(vote);
537  if (! unexpanded) {
538  log_warn(LD_NET, "I failed with parsing a protocol list from "
539  "an authority. The offending string was: %s",
540  escaped(vote));
541  continue;
542  }
543  SMARTLIST_FOREACH_BEGIN(unexpanded, const proto_entry_t *, ent) {
544  if (!smartlist_contains_string(proto_names,ent->name)) {
545  smartlist_add(proto_names, ent->name);
546  }
547  } SMARTLIST_FOREACH_END(ent);
548  smartlist_add(parsed, unexpanded);
549  } SMARTLIST_FOREACH_END(vote);
550 
551  // Sort the list of names.
552  smartlist_sort_strings(proto_names);
553 
554  // For each named protocol, compute the consensus.
555  //
556  // This is not super-efficient, but it's not critical path.
557  SMARTLIST_FOREACH_BEGIN(proto_names, const char *, name) {
558  uint8_t counts[64];
559  memset(counts, 0, sizeof(counts));
560  // Count how many votes we got for each bit.
561  SMARTLIST_FOREACH_BEGIN(parsed, const smartlist_t *, vote) {
562  const proto_entry_t *ent = find_entry_by_name(vote, name);
563  if (! ent)
564  continue;
565 
566  for (int i = 0; i < 64; ++i) {
567  if ((ent->bitmask & BIT(i)) != 0) {
568  ++ counts[i];
569  }
570  }
571  } SMARTLIST_FOREACH_END(vote);
572 
573  uint64_t result_bitmask = 0;
574  for (int i = 0; i < 64; ++i) {
575  if (counts[i] >= threshold) {
576  result_bitmask |= BIT(i);
577  }
578  }
579  if (result_bitmask != 0) {
580  proto_entry_t *newent = tor_malloc_zero(sizeof(proto_entry_t));
581  newent->name = tor_strdup(name);
582  newent->bitmask = result_bitmask;
583  smartlist_add(result, newent);
584  }
585  } SMARTLIST_FOREACH_END(name);
586 
587  char *consensus = encode_protocol_list(result);
588 
589  SMARTLIST_FOREACH(result, proto_entry_t *, ent, proto_entry_free(ent));
590  smartlist_free(result);
591  smartlist_free(proto_names); // no need to free members; they are aliases.
592  SMARTLIST_FOREACH_BEGIN(parsed, smartlist_t *, v) {
593  SMARTLIST_FOREACH(v, proto_entry_t *, ent, proto_entry_free(ent));
594  smartlist_free(v);
595  } SMARTLIST_FOREACH_END(v);
596  smartlist_free(parsed);
597 
598  return consensus;
599 }
600 
601 /** Return true if every protocol version described in the string <b>s</b> is
602  * one that we support, and false otherwise. If <b>missing_out</b> is
603  * provided, set it to the list of protocols we do not support.
604  *
605  * If the protocol version string is unparseable, treat it as if it defines no
606  * protocols, and return 1.
607  **/
608 int
609 protover_all_supported(const char *s, char **missing_out)
610 {
611  if (!s) {
612  return 1;
613  }
614 
615  smartlist_t *entries = parse_protocol_list(s);
616  if (BUG(entries == NULL)) {
617  log_warn(LD_NET, "Received an unparseable protocol list %s"
618  " from the consensus", escaped(s));
619  return 1;
620  }
621  const smartlist_t *supported = get_supported_protocol_list();
622  smartlist_t *missing = smartlist_new();
623 
624  SMARTLIST_FOREACH_BEGIN(entries, const proto_entry_t *, ent) {
625  const proto_entry_t *mine = find_entry_by_name(supported, ent->name);
626  if (mine == NULL) {
627  if (ent->bitmask != 0) {
628  proto_entry_t *m = tor_malloc_zero(sizeof(proto_entry_t));
629  m->name = tor_strdup(ent->name);
630  m->bitmask = ent->bitmask;
631  smartlist_add(missing, m);
632  }
633  continue;
634  }
635 
636  uint64_t missing_mask = ent->bitmask & ~mine->bitmask;
637  if (missing_mask != 0) {
638  proto_entry_t *m = tor_malloc_zero(sizeof(proto_entry_t));
639  m->name = tor_strdup(ent->name);
640  m->bitmask = missing_mask;
641  smartlist_add(missing, m);
642  }
643  } SMARTLIST_FOREACH_END(ent);
644 
645  const int all_supported = (smartlist_len(missing) == 0);
646  if (!all_supported && missing_out) {
647  *missing_out = encode_protocol_list(missing);
648  }
649 
650  SMARTLIST_FOREACH(missing, proto_entry_t *, ent, proto_entry_free(ent));
651  smartlist_free(missing);
652 
653  SMARTLIST_FOREACH(entries, proto_entry_t *, ent, proto_entry_free(ent));
654  smartlist_free(entries);
655 
656  return all_supported;
657 }
658 
659 /** Helper: return the member of 'protos' whose name is
660  * 'name', or NULL if there is no such member. */
661 static const proto_entry_t *
662 find_entry_by_name(const smartlist_t *protos, const char *name)
663 {
664  if (!protos) {
665  return NULL;
666  }
667  SMARTLIST_FOREACH_BEGIN(protos, const proto_entry_t *, ent) {
668  if (!strcmp(ent->name, name)) {
669  return ent;
670  }
671  } SMARTLIST_FOREACH_END(ent);
672 
673  return NULL;
674 }
675 
676 /** Helper: Given a list of proto_entry_t, return true iff
677  * <b>pr</b>=<b>ver</b> is included in that list. */
678 static int
680  protocol_type_t pr, uint32_t ver)
681 {
682  if (BUG(protos == NULL)) {
683  return 0; // LCOV_EXCL_LINE
684  }
685  const char *pr_name = protocol_type_to_str(pr);
686  if (BUG(pr_name == NULL)) {
687  return 0; // LCOV_EXCL_LINE
688  }
689  if (ver > MAX_PROTOCOL_VERSION) {
690  return 0;
691  }
692 
693  const proto_entry_t *ent = find_entry_by_name(protos, pr_name);
694  if (ent) {
695  return (ent->bitmask & BIT(ver)) != 0;
696  }
697  return 0;
698 }
699 
700 /** Return a string describing the protocols supported by tor version
701  * <b>version</b>, or an empty string if we cannot tell.
702  *
703  * Note that this is only used to infer protocols for Tor versions that
704  * can't declare their own.
705  **/
706 /// C_RUST_COUPLED: src/rust/protover/protover.rs `compute_for_old_tor`
707 const char *
708 protover_compute_for_old_tor(const char *version)
709 {
710  if (version == NULL) {
711  /* No known version; guess the oldest series that is still supported. */
712  version = "0.2.5.15";
713  }
714 
715  if (tor_version_as_new_as(version,
717  return "";
718  } else if (tor_version_as_new_as(version, "0.2.9.1-alpha")) {
719  /* 0.2.9.1-alpha HSRend=2 */
720  return "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 "
721  "Link=1-4 LinkAuth=1 "
722  "Microdesc=1-2 Relay=1-2";
723  } else if (tor_version_as_new_as(version, "0.2.7.5")) {
724  /* 0.2.7-stable added Desc=2, Microdesc=2, Cons=2, which indicate
725  * ed25519 support. We'll call them present only in "stable" 027,
726  * though. */
727  return "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
728  "Link=1-4 LinkAuth=1 "
729  "Microdesc=1-2 Relay=1-2";
730  } else if (tor_version_as_new_as(version, "0.2.4.19")) {
731  /* No currently supported Tor server versions are older than this, or
732  * lack these protocols. */
733  return "Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
734  "Link=1-4 LinkAuth=1 "
735  "Microdesc=1 Relay=1-2";
736  } else {
737  /* Cannot infer protocols. */
738  return "";
739  }
740 }
741 
742 /**
743  * Release all storage held by static fields in protover.c
744  */
745 void
747 {
750  SMARTLIST_FOREACH(entries, proto_entry_t *, ent, proto_entry_free(ent));
751  smartlist_free(entries);
753  }
754 }
755 
756 #endif /* !defined(HAVE_RUST) */
const char * name
Definition: config.c:2434
static conn_counts_t counts
Definition: connstats.c:72
const char * escaped(const char *s)
Definition: escape.c:126
#define LD_NET
Definition: log.h:66
#define tor_free(p)
Definition: malloc.h:52
Master header file for Tor-specific functionality.
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
STATIC const char * protocol_type_to_str(protocol_type_t pr)
Definition: protover.c:74
const char * protover_compute_for_old_tor(const char *version)
C_RUST_COUPLED: src/rust/protover/protover.rs compute_for_old_tor
Definition: protover.c:708
static const proto_entry_t * find_entry_by_name(const smartlist_t *protos, const char *name)
Definition: protover.c:662
static uint64_t bitmask_for_range(uint32_t low, uint32_t high)
Definition: protover.c:184
bool protover_list_is_invalid(const char *s)
Definition: protover.c:302
STATIC void proto_entry_free_(proto_entry_t *entry)
Definition: protover.c:91
static smartlist_t * supported_protocol_list
Definition: protover.c:420
static const smartlist_t * get_supported_protocol_list(void)
Definition: protover.c:425
#define MAX_PROTOCOL_VERSION
Definition: protover.c:100
const char * protover_get_supported_protocols(void)
C_RUST_COUPLED: src/rust/protover/protover.rs SUPPORTED_PROTOCOLS
Definition: protover.c:391
void protover_free_all(void)
Definition: protover.c:746
static const struct @12 PROTOCOL_NAMES[]
C_RUST_COUPLED: src/rust/protover/protover.rs PROTOCOL_NAMES
static void proto_entry_encode_into(smartlist_t *chunks, const proto_entry_t *entry)
Definition: protover.c:456
int protover_is_supported_here(protocol_type_t pr, uint32_t ver)
Definition: protover.c:317
static int protocol_list_contains(const smartlist_t *protos, protocol_type_t pr, uint32_t ver)
Definition: protover.c:679
static proto_entry_t * parse_single_entry(const char *s, const char *end_of_entry)
Definition: protover.c:199
int protocol_list_supports_protocol(const char *list, protocol_type_t tp, uint32_t version)
Definition: protover.c:331
int protocol_list_supports_protocol_or_later(const char *list, protocol_type_t tp, uint32_t version)
Definition: protover.c:356
char * protover_compute_vote(const smartlist_t *list_of_proto_strings, int threshold)
Definition: protover.c:520
STATIC char * encode_protocol_list(const smartlist_t *sl)
Definition: protover.c:489
static int parse_version_range(const char *s, const char *end_of_range, uint32_t *low_out, uint32_t *high_out)
Definition: protover.c:109
#define BIT(x)
Definition: protover.c:177
STATIC smartlist_t * parse_protocol_list(const char *s)
Definition: protover.c:265
static int trailing_zeros(uint64_t x)
Definition: protover.c:436
int protover_all_supported(const char *s, char **missing_out)
Definition: protover.c:609
Headers and type declarations for protover.c.
#define FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS
Definition: protover.h:23
protocol_type_t
Definition: protover.h:57
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
Definition: smartlist.c:36
void smartlist_sort_strings(smartlist_t *sl)
Definition: smartlist.c:549
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
Definition: smartlist.c:279
int smartlist_contains_string(const smartlist_t *sl, const char *element)
Definition: smartlist.c:93
smartlist_t * smartlist_new(void)
void smartlist_add_strdup(struct smartlist_t *sl, const char *string)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
#define STATIC
Definition: testsupport.h:32
Headers for tortls.c.
#define tor_assert(expr)
Definition: util_bug.h:102
int tor_version_as_new_as(const char *platform, const char *cutoff)
Definition: versions.c:171
Header file for versions.c.