Line data Source code
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 *
74 2019 : protocol_type_to_str(protocol_type_t pr)
75 : {
76 2019 : unsigned i;
77 5458 : for (i=0; i < N_PROTOCOL_NAMES; ++i) {
78 5458 : if (PROTOCOL_NAMES[i].protover_type == pr)
79 2019 : 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 22459 : proto_entry_free_(proto_entry_t *entry)
92 : {
93 22459 : if (!entry)
94 : return;
95 22459 : tor_free(entry->name);
96 22459 : 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 23847 : parse_version_range(const char *s, const char *end_of_range,
110 : uint32_t *low_out, uint32_t *high_out)
111 : {
112 23847 : uint32_t low, high;
113 23847 : char *next = NULL;
114 23847 : int ok;
115 :
116 23847 : tor_assert(high_out);
117 23847 : tor_assert(low_out);
118 :
119 23847 : 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 23847 : if (!TOR_ISDIGIT(*s)) {
124 56 : 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 23791 : low = (uint32_t) tor_parse_ulong(s, 10, 0, MAX_PROTOCOL_VERSION, &ok, &next);
130 23791 : if (!ok)
131 22 : goto error;
132 23769 : if (next > end_of_range)
133 0 : goto error;
134 23769 : if (next == end_of_range) {
135 12141 : high = low;
136 12141 : goto done;
137 : }
138 :
139 11628 : if (*next != '-')
140 15 : goto error;
141 11613 : s = next+1;
142 :
143 : /* ibid */
144 11613 : if (!TOR_ISDIGIT(*s)) {
145 201 : goto error;
146 : }
147 11412 : high = (uint32_t) tor_parse_ulong(s, 10, 0,
148 : MAX_PROTOCOL_VERSION, &ok, &next);
149 11412 : if (!ok)
150 3 : goto error;
151 11409 : if (next != end_of_range)
152 11 : goto error;
153 :
154 11398 : if (low > high)
155 4 : goto error;
156 :
157 11394 : done:
158 23535 : *high_out = high;
159 23535 : *low_out = low;
160 23535 : return 0;
161 :
162 : error:
163 : return -1;
164 : }
165 :
166 : static int
167 22407 : is_valid_keyword(const char *s, size_t n)
168 : {
169 155181 : for (size_t i = 0; i < n; i++) {
170 132833 : 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 23620 : bitmask_for_range(uint32_t low, uint32_t high)
185 : {
186 23620 : uint64_t mask = ~(uint64_t)0;
187 23620 : mask <<= 63 - high;
188 23620 : mask >>= 63 - high + low;
189 23620 : mask <<= low;
190 23620 : 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 22452 : parse_single_entry(const char *s, const char *end_of_entry)
200 : {
201 22452 : proto_entry_t *out = tor_malloc_zero(sizeof(proto_entry_t));
202 22452 : const char *equals;
203 :
204 22452 : if (BUG (!end_of_entry))
205 : end_of_entry = s + strlen(s); // LCOV_EXCL_LINE
206 :
207 : /* There must be an =. */
208 22452 : equals = memchr(s, '=', end_of_entry - s);
209 22452 : if (!equals)
210 32 : goto error;
211 :
212 : /* The name must be nonempty */
213 22420 : if (equals == s)
214 7 : goto error;
215 :
216 : /* The name must not be longer than MAX_PROTOCOL_NAME_LENGTH. */
217 22413 : if (equals - s > (int)MAX_PROTOCOL_NAME_LENGTH) {
218 6 : 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 6 : goto error;
224 : }
225 :
226 : /* The name must contain only alphanumeric characters and hyphens. */
227 22407 : if (!is_valid_keyword(s, equals-s))
228 59 : goto error;
229 :
230 22348 : out->name = tor_strndup(s, equals-s);
231 :
232 22348 : tor_assert(equals < end_of_entry);
233 :
234 22348 : s = equals + 1;
235 45883 : while (s < end_of_entry) {
236 23847 : const char *comma = memchr(s, ',', end_of_entry-s);
237 23847 : if (! comma)
238 21834 : comma = end_of_entry;
239 :
240 23847 : uint32_t low=0, high=0;
241 23847 : if (parse_version_range(s, comma, &low, &high) < 0) {
242 312 : goto error;
243 : }
244 :
245 23535 : out->bitmask |= bitmask_for_range(low,high);
246 :
247 23535 : s = comma;
248 : // Skip the comma separator between ranges. Don't ignore a trailing comma.
249 23535 : if (s < (end_of_entry - 1))
250 1966 : ++s;
251 : }
252 :
253 : return out;
254 :
255 416 : error:
256 416 : proto_entry_free(out);
257 416 : 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 : */
264 : STATIC smartlist_t *
265 3998 : parse_protocol_list(const char *s)
266 : {
267 3998 : smartlist_t *entries = smartlist_new();
268 :
269 26034 : while (*s) {
270 : /* Find the next space or the NUL. */
271 22452 : const char *end_of_entry = strchr(s, ' ');
272 22452 : proto_entry_t *entry;
273 22452 : if (!end_of_entry)
274 3082 : end_of_entry = s + strlen(s);
275 :
276 22452 : entry = parse_single_entry(s, end_of_entry);
277 :
278 22452 : if (! entry)
279 416 : goto error;
280 :
281 22036 : smartlist_add(entries, entry);
282 :
283 22036 : s = end_of_entry;
284 42538 : while (*s == ' ')
285 20502 : ++s;
286 : }
287 :
288 : return entries;
289 :
290 416 : error:
291 719 : SMARTLIST_FOREACH(entries, proto_entry_t *, ent, proto_entry_free(ent));
292 416 : smartlist_free(entries);
293 416 : 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
302 1683 : protover_list_is_invalid(const char *s)
303 : {
304 1683 : smartlist_t *list = parse_protocol_list(s);
305 1683 : if (!list)
306 : return true; /* yes, has a dangerous name */
307 7065 : SMARTLIST_FOREACH(list, proto_entry_t *, ent, proto_entry_free(ent));
308 1510 : smartlist_free(list);
309 1510 : 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
317 0 : protover_is_supported_here(protocol_type_t pr, uint32_t ver)
318 : {
319 0 : const smartlist_t *ours = get_supported_protocol_list();
320 0 : 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
331 2110 : protocol_list_supports_protocol(const char *list, protocol_type_t tp,
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 2110 : smartlist_t *protocols = parse_protocol_list(list);
338 2110 : if (!protocols) {
339 : return 0;
340 : }
341 1934 : int contains = protocol_list_contains(protocols, tp, version);
342 :
343 17638 : SMARTLIST_FOREACH(protocols, proto_entry_t *, ent, proto_entry_free(ent));
344 1934 : smartlist_free(protocols);
345 1934 : 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
356 101 : protocol_list_supports_protocol_or_later(const char *list,
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 101 : smartlist_t *protocols = parse_protocol_list(list);
364 101 : if (!protocols) {
365 : return 0;
366 : }
367 85 : const char *pr_name = protocol_type_to_str(tp);
368 :
369 85 : int contains = 0;
370 85 : const uint64_t mask = bitmask_for_range(version, 63);
371 :
372 332 : SMARTLIST_FOREACH_BEGIN(protocols, proto_entry_t *, proto) {
373 269 : if (strcasecmp(proto->name, pr_name))
374 241 : continue;
375 28 : if (0 != (proto->bitmask & mask)) {
376 22 : contains = 1;
377 22 : goto found;
378 : }
379 247 : } SMARTLIST_FOREACH_END(proto);
380 :
381 63 : found:
382 385 : SMARTLIST_FOREACH(protocols, proto_entry_t *, ent, proto_entry_free(ent));
383 85 : smartlist_free(protocols);
384 85 : 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 *
391 20 : protover_get_supported_protocols(void)
392 : {
393 : /* WARNING!
394 : *
395 : * Remember to edit the SUPPORTED_PROTOCOLS list in protover.rs if you
396 : * are editing this list.
397 : */
398 20 : return
399 20 : "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. */
420 : static smartlist_t *supported_protocol_list = NULL;
421 :
422 : /** Return a pointer to a smartlist of proto_entry_t for the protocols
423 : * we support. */
424 : static const smartlist_t *
425 22 : get_supported_protocol_list(void)
426 : {
427 22 : if (PREDICT_UNLIKELY(supported_protocol_list == NULL)) {
428 6 : supported_protocol_list =
429 6 : parse_protocol_list(protover_get_supported_protocols());
430 : }
431 22 : return supported_protocol_list;
432 : }
433 :
434 : /** Return the number of trailing zeros in x. Undefined if x is 0. */
435 : static int
436 186 : trailing_zeros(uint64_t x)
437 : {
438 : #ifdef __GNUC__
439 186 : 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 82 : proto_entry_encode_into(smartlist_t *chunks, const proto_entry_t *entry)
457 : {
458 82 : smartlist_add_asprintf(chunks, "%s=", entry->name);
459 :
460 82 : uint64_t mask = entry->bitmask;
461 82 : int shift = 0; // how much have we shifted by so far?
462 82 : bool first = true;
463 175 : while (mask) {
464 93 : const char *comma = first ? "" : ",";
465 93 : if (first) {
466 : first = false;
467 : }
468 93 : int zeros = trailing_zeros(mask);
469 93 : mask >>= zeros;
470 93 : shift += zeros;
471 93 : int ones = !mask ? 64 : trailing_zeros(~mask);
472 93 : if (ones == 1) {
473 62 : smartlist_add_asprintf(chunks, "%s%d", comma, shift);
474 : } else {
475 31 : smartlist_add_asprintf(chunks, "%s%d-%d", comma,
476 31 : shift, shift + ones - 1);
477 : }
478 93 : if (ones == 64) {
479 : break; // avoid undefined behavior; can't shift by 64.
480 : }
481 93 : mask >>= ones;
482 93 : shift += ones;
483 : }
484 82 : }
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 *
489 68 : encode_protocol_list(const smartlist_t *sl)
490 : {
491 68 : const char *separator = "";
492 68 : smartlist_t *chunks = smartlist_new();
493 150 : SMARTLIST_FOREACH_BEGIN(sl, const proto_entry_t *, ent) {
494 82 : smartlist_add_strdup(chunks, separator);
495 :
496 82 : proto_entry_encode_into(chunks, ent);
497 :
498 82 : separator = " ";
499 82 : } SMARTLIST_FOREACH_END(ent);
500 :
501 68 : char *result = smartlist_join_strings(chunks, "", 0, NULL);
502 :
503 325 : SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
504 68 : smartlist_free(chunks);
505 :
506 68 : 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 157 : protover_compute_vote(const smartlist_t *list_of_proto_strings,
521 : int threshold)
522 : {
523 : // we use u8 counters below.
524 157 : tor_assert(smartlist_len(list_of_proto_strings) < 256);
525 :
526 157 : if (smartlist_len(list_of_proto_strings) == 0) {
527 97 : return tor_strdup("");
528 : }
529 :
530 60 : smartlist_t *parsed = smartlist_new(); // smartlist of smartlist of entries
531 60 : smartlist_t *proto_names = smartlist_new(); // smartlist of strings
532 60 : smartlist_t *result = smartlist_new(); // smartlist of entries
533 :
534 : // First, parse the inputs, and accumulate a list of protocol names.
535 124 : SMARTLIST_FOREACH_BEGIN(list_of_proto_strings, const char *, vote) {
536 64 : smartlist_t *unexpanded = parse_protocol_list(vote);
537 64 : if (! unexpanded) {
538 40 : log_warn(LD_NET, "I failed with parsing a protocol list from "
539 : "an authority. The offending string was: %s",
540 : escaped(vote));
541 40 : continue;
542 : }
543 108 : SMARTLIST_FOREACH_BEGIN(unexpanded, const proto_entry_t *, ent) {
544 84 : if (!smartlist_contains_string(proto_names,ent->name)) {
545 77 : smartlist_add(proto_names, ent->name);
546 : }
547 84 : } SMARTLIST_FOREACH_END(ent);
548 24 : smartlist_add(parsed, unexpanded);
549 64 : } SMARTLIST_FOREACH_END(vote);
550 :
551 : // Sort the list of names.
552 60 : 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 137 : SMARTLIST_FOREACH_BEGIN(proto_names, const char *, name) {
558 77 : uint8_t counts[64];
559 77 : memset(counts, 0, sizeof(counts));
560 : // Count how many votes we got for each bit.
561 165 : SMARTLIST_FOREACH_BEGIN(parsed, const smartlist_t *, vote) {
562 88 : const proto_entry_t *ent = find_entry_by_name(vote, name);
563 88 : if (! ent)
564 5 : continue;
565 :
566 5395 : for (int i = 0; i < 64; ++i) {
567 5312 : if ((ent->bitmask & BIT(i)) != 0) {
568 464 : ++ counts[i];
569 : }
570 : }
571 88 : } SMARTLIST_FOREACH_END(vote);
572 :
573 : uint64_t result_bitmask = 0;
574 5005 : for (int i = 0; i < 64; ++i) {
575 4928 : if (counts[i] >= threshold) {
576 342 : result_bitmask |= BIT(i);
577 : }
578 : }
579 77 : if (result_bitmask != 0) {
580 70 : proto_entry_t *newent = tor_malloc_zero(sizeof(proto_entry_t));
581 70 : newent->name = tor_strdup(name);
582 70 : newent->bitmask = result_bitmask;
583 70 : smartlist_add(result, newent);
584 : }
585 77 : } SMARTLIST_FOREACH_END(name);
586 :
587 60 : char *consensus = encode_protocol_list(result);
588 :
589 130 : SMARTLIST_FOREACH(result, proto_entry_t *, ent, proto_entry_free(ent));
590 60 : smartlist_free(result);
591 60 : smartlist_free(proto_names); // no need to free members; they are aliases.
592 84 : SMARTLIST_FOREACH_BEGIN(parsed, smartlist_t *, v) {
593 108 : SMARTLIST_FOREACH(v, proto_entry_t *, ent, proto_entry_free(ent));
594 24 : smartlist_free(v);
595 24 : } SMARTLIST_FOREACH_END(v);
596 60 : smartlist_free(parsed);
597 :
598 60 : 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 26 : protover_all_supported(const char *s, char **missing_out)
610 : {
611 26 : if (!s) {
612 : return 1;
613 : }
614 :
615 25 : smartlist_t *entries = parse_protocol_list(s);
616 25 : if (BUG(entries == NULL)) {
617 3 : log_warn(LD_NET, "Received an unparseable protocol list %s"
618 : " from the consensus", escaped(s));
619 3 : return 1;
620 : }
621 22 : const smartlist_t *supported = get_supported_protocol_list();
622 22 : smartlist_t *missing = smartlist_new();
623 :
624 36 : SMARTLIST_FOREACH_BEGIN(entries, const proto_entry_t *, ent) {
625 14 : const proto_entry_t *mine = find_entry_by_name(supported, ent->name);
626 14 : if (mine == NULL) {
627 5 : if (ent->bitmask != 0) {
628 4 : proto_entry_t *m = tor_malloc_zero(sizeof(proto_entry_t));
629 4 : m->name = tor_strdup(ent->name);
630 4 : m->bitmask = ent->bitmask;
631 4 : smartlist_add(missing, m);
632 : }
633 5 : continue;
634 : }
635 :
636 9 : uint64_t missing_mask = ent->bitmask & ~mine->bitmask;
637 9 : if (missing_mask != 0) {
638 5 : proto_entry_t *m = tor_malloc_zero(sizeof(proto_entry_t));
639 5 : m->name = tor_strdup(ent->name);
640 5 : m->bitmask = missing_mask;
641 5 : smartlist_add(missing, m);
642 : }
643 14 : } SMARTLIST_FOREACH_END(ent);
644 :
645 22 : const int all_supported = (smartlist_len(missing) == 0);
646 22 : if (!all_supported && missing_out) {
647 7 : *missing_out = encode_protocol_list(missing);
648 : }
649 :
650 31 : SMARTLIST_FOREACH(missing, proto_entry_t *, ent, proto_entry_free(ent));
651 22 : smartlist_free(missing);
652 :
653 36 : SMARTLIST_FOREACH(entries, proto_entry_t *, ent, proto_entry_free(ent));
654 22 : smartlist_free(entries);
655 :
656 22 : 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 1076 : find_entry_by_name(const smartlist_t *protos, const char *name)
663 : {
664 1076 : if (!protos) {
665 : return NULL;
666 : }
667 4557 : SMARTLIST_FOREACH_BEGIN(protos, const proto_entry_t *, ent) {
668 3873 : if (!strcmp(ent->name, name)) {
669 392 : return ent;
670 : }
671 3481 : } 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
679 1934 : protocol_list_contains(const smartlist_t *protos,
680 : protocol_type_t pr, uint32_t ver)
681 : {
682 1934 : if (BUG(protos == NULL)) {
683 : return 0; // LCOV_EXCL_LINE
684 : }
685 1934 : const char *pr_name = protocol_type_to_str(pr);
686 1934 : if (BUG(pr_name == NULL)) {
687 : return 0; // LCOV_EXCL_LINE
688 : }
689 1934 : if (ver > MAX_PROTOCOL_VERSION) {
690 : return 0;
691 : }
692 :
693 974 : const proto_entry_t *ent = find_entry_by_name(protos, pr_name);
694 974 : if (ent) {
695 300 : 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 0 : protover_compute_for_old_tor(const char *version)
709 : {
710 0 : if (version == NULL) {
711 : /* No known version; guess the oldest series that is still supported. */
712 0 : version = "0.2.5.15";
713 : }
714 :
715 0 : if (tor_version_as_new_as(version,
716 : FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS)) {
717 : return "";
718 0 : } 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 0 : } 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 0 : } 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 0 : return "";
739 : }
740 : }
741 :
742 : /**
743 : * Release all storage held by static fields in protover.c
744 : */
745 : void
746 235 : protover_free_all(void)
747 : {
748 235 : if (supported_protocol_list) {
749 0 : smartlist_t *entries = supported_protocol_list;
750 0 : SMARTLIST_FOREACH(entries, proto_entry_t *, ent, proto_entry_free(ent));
751 0 : smartlist_free(entries);
752 0 : supported_protocol_list = NULL;
753 : }
754 235 : }
755 :
756 : #endif /* !defined(HAVE_RUST) */
|