1 /* Copyright (c) 2016-2017, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #define PROTOVER_PRIVATE
12 #include "connection_or.h"
15 test_protover_parse(void *arg
)
19 /** This test is disabled on rust builds, because it only exists to test
20 * internal C functions. */
25 char *re_encoded
= NULL
;
27 const char *orig
= "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16,900";
28 smartlist_t
*elts
= parse_protocol_list(orig
);
31 tt_int_op(smartlist_len(elts
), OP_EQ
, 4);
33 const proto_entry_t
*e
;
34 const proto_range_t
*r
;
35 e
= smartlist_get(elts
, 0);
36 tt_str_op(e
->name
, OP_EQ
, "Foo");
37 tt_int_op(smartlist_len(e
->ranges
), OP_EQ
, 2);
39 r
= smartlist_get(e
->ranges
, 0);
40 tt_int_op(r
->low
, OP_EQ
, 1);
41 tt_int_op(r
->high
, OP_EQ
, 1);
43 r
= smartlist_get(e
->ranges
, 1);
44 tt_int_op(r
->low
, OP_EQ
, 3);
45 tt_int_op(r
->high
, OP_EQ
, 3);
48 e
= smartlist_get(elts
, 1);
49 tt_str_op(e
->name
, OP_EQ
, "Bar");
50 tt_int_op(smartlist_len(e
->ranges
), OP_EQ
, 1);
52 r
= smartlist_get(e
->ranges
, 0);
53 tt_int_op(r
->low
, OP_EQ
, 3);
54 tt_int_op(r
->high
, OP_EQ
, 3);
57 e
= smartlist_get(elts
, 2);
58 tt_str_op(e
->name
, OP_EQ
, "Baz");
59 tt_int_op(smartlist_len(e
->ranges
), OP_EQ
, 0);
61 e
= smartlist_get(elts
, 3);
62 tt_str_op(e
->name
, OP_EQ
, "Quux");
63 tt_int_op(smartlist_len(e
->ranges
), OP_EQ
, 4);
65 r
= smartlist_get(e
->ranges
, 0);
66 tt_int_op(r
->low
, OP_EQ
, 9);
67 tt_int_op(r
->high
, OP_EQ
, 12);
69 r
= smartlist_get(e
->ranges
, 1);
70 tt_int_op(r
->low
, OP_EQ
, 14);
71 tt_int_op(r
->high
, OP_EQ
, 14);
73 r
= smartlist_get(e
->ranges
, 2);
74 tt_int_op(r
->low
, OP_EQ
, 15);
75 tt_int_op(r
->high
, OP_EQ
, 16);
77 r
= smartlist_get(e
->ranges
, 3);
78 tt_int_op(r
->low
, OP_EQ
, 900);
79 tt_int_op(r
->high
, OP_EQ
, 900);
82 re_encoded
= encode_protocol_list(elts
);
83 tt_assert(re_encoded
);
84 tt_str_op(re_encoded
, OP_EQ
, orig
);
88 SMARTLIST_FOREACH(elts
, proto_entry_t
*, ent
, proto_entry_free(ent
));
95 test_protover_parse_fail(void *arg
)
99 /** This test is disabled on rust builds, because it only exists to test
100 * internal C functions. */
106 elts
= parse_protocol_list("!!3@*");
107 tt_ptr_op(elts
, OP_EQ
, NULL
);
109 /* Missing equals sign in an entry */
110 elts
= parse_protocol_list("Link=4 Haprauxymatyve Desc=9");
111 tt_ptr_op(elts
, OP_EQ
, NULL
);
114 elts
= parse_protocol_list("Link=4 =3 Desc=9");
115 tt_ptr_op(elts
, OP_EQ
, NULL
);
118 elts
= parse_protocol_list("Link=fred");
119 tt_ptr_op(elts
, OP_EQ
, NULL
);
120 elts
= parse_protocol_list("Link=1,fred");
121 tt_ptr_op(elts
, OP_EQ
, NULL
);
122 elts
= parse_protocol_list("Link=1,fred,3");
123 tt_ptr_op(elts
, OP_EQ
, NULL
);
126 elts
= parse_protocol_list("Link=1,9-8,3");
127 tt_ptr_op(elts
, OP_EQ
, NULL
);
129 /* Protocol name too long */
130 elts
= parse_protocol_list("DoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
131 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
132 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
133 tt_ptr_op(elts
, OP_EQ
, NULL
);
141 test_protover_vote(void *arg
)
145 smartlist_t
*lst
= smartlist_new();
146 char *result
= protover_compute_vote(lst
, 1);
148 tt_str_op(result
, OP_EQ
, "");
151 smartlist_add(lst
, (void*) "Foo=1-10,500 Bar=1,3-7,8");
152 result
= protover_compute_vote(lst
, 1);
153 tt_str_op(result
, OP_EQ
, "Bar=1,3-8 Foo=1-10,500");
156 smartlist_add(lst
, (void*) "Quux=123-456,78 Bar=2-6,8 Foo=9");
157 result
= protover_compute_vote(lst
, 1);
158 tt_str_op(result
, OP_EQ
, "Bar=1-8 Foo=1-10,500 Quux=78,123-456");
161 result
= protover_compute_vote(lst
, 2);
162 tt_str_op(result
, OP_EQ
, "Bar=3-6,8 Foo=9");
166 result
= protover_compute_vote(lst
, 3);
167 tt_str_op(result
, OP_EQ
, "");
170 /* Bad votes: the result must be empty */
171 smartlist_clear(lst
);
172 smartlist_add(lst
, (void*) "Faux=10-5");
173 result
= protover_compute_vote(lst
, 1);
174 tt_str_op(result
, OP_EQ
, "");
177 /* This fails, since "-0" is not valid. */
178 smartlist_clear(lst
);
179 smartlist_add(lst
, (void*) "Faux=-0");
180 result
= protover_compute_vote(lst
, 1);
181 tt_str_op(result
, OP_EQ
, "");
184 /* Vote large protover lists that are just below the threshold */
186 /* Just below the threshold: Rust */
187 smartlist_clear(lst
);
188 smartlist_add(lst
, (void*) "Sleen=1-500");
189 result
= protover_compute_vote(lst
, 1);
190 tt_str_op(result
, OP_EQ
, "Sleen=1-500");
193 /* Just below the threshold: C */
194 smartlist_clear(lst
);
195 smartlist_add(lst
, (void*) "Sleen=1-65536");
196 result
= protover_compute_vote(lst
, 1);
197 tt_str_op(result
, OP_EQ
, "Sleen=1-65536");
200 /* Large protover lists that exceed the threshold */
202 /* By adding two votes, C allows us to exceed the limit */
203 smartlist_add(lst
, (void*) "Sleen=1-65536");
204 smartlist_add(lst
, (void*) "Sleen=100000");
205 result
= protover_compute_vote(lst
, 1);
206 tt_str_op(result
, OP_EQ
, "Sleen=1-65536,100000");
210 smartlist_clear(lst
);
211 smartlist_add(lst
, (void*) "Sleen=4294967294");
212 result
= protover_compute_vote(lst
, 1);
213 tt_str_op(result
, OP_EQ
, "Sleen=4294967294");
216 /* This parses, but fails at the vote stage */
217 smartlist_clear(lst
);
218 smartlist_add(lst
, (void*) "Sleen=4294967295");
219 result
= protover_compute_vote(lst
, 1);
220 tt_str_op(result
, OP_EQ
, "");
223 smartlist_clear(lst
);
224 smartlist_add(lst
, (void*) "Sleen=4294967296");
225 result
= protover_compute_vote(lst
, 1);
226 tt_str_op(result
, OP_EQ
, "");
229 /* Protocol name too long */
230 smartlist_clear(lst
);
231 smartlist_add(lst
, (void*) "DoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
232 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
233 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
234 result
= protover_compute_vote(lst
, 1);
235 tt_str_op(result
, OP_EQ
, "");
244 test_protover_all_supported(void *arg
)
249 tt_assert(protover_all_supported(NULL
, &msg
));
250 tt_ptr_op(msg
, OP_EQ
, NULL
);
252 tt_assert(protover_all_supported("", &msg
));
253 tt_ptr_op(msg
, OP_EQ
, NULL
);
255 // Some things that we do support
256 tt_assert(protover_all_supported("Link=3-4", &msg
));
257 tt_ptr_op(msg
, OP_EQ
, NULL
);
258 tt_assert(protover_all_supported("Link=3-4 Desc=2", &msg
));
259 tt_ptr_op(msg
, OP_EQ
, NULL
);
261 // Some things we don't support
262 tt_assert(! protover_all_supported("Wombat=9", NULL
));
263 tt_assert(! protover_all_supported("Wombat=9", &msg
));
264 tt_str_op(msg
, OP_EQ
, "Wombat=9");
266 tt_assert(! protover_all_supported("Link=999", &msg
));
267 tt_str_op(msg
, OP_EQ
, "Link=999");
270 // Mix of things we support and things we don't
271 tt_assert(! protover_all_supported("Link=3-4 Wombat=9", &msg
));
272 tt_str_op(msg
, OP_EQ
, "Wombat=9");
275 /* Mix of things we support and don't support within a single protocol
276 * which we do support */
277 tt_assert(! protover_all_supported("Link=3-999", &msg
));
278 tt_str_op(msg
, OP_EQ
, "Link=6-999");
280 tt_assert(! protover_all_supported("Link=1-3,345-666", &msg
));
281 tt_str_op(msg
, OP_EQ
, "Link=345-666");
283 tt_assert(! protover_all_supported("Link=1-3,5-12", &msg
));
284 tt_str_op(msg
, OP_EQ
, "Link=6-12");
287 /* Mix of protocols we do support and some we don't, where the protocols
288 * we do support have some versions we don't support. */
289 tt_assert(! protover_all_supported("Link=1-3,5-12 Quokka=9000-9001", &msg
));
290 tt_str_op(msg
, OP_EQ
, "Link=6-12 Quokka=9000-9001");
293 /* We shouldn't be able to DoS ourselves parsing a large range. */
294 tt_assert(! protover_all_supported("Sleen=1-2147483648", &msg
));
295 tt_str_op(msg
, OP_EQ
, "Sleen=1-2147483648");
298 /* This case is allowed. */
299 tt_assert(! protover_all_supported("Sleen=1-4294967294", &msg
));
300 tt_str_op(msg
, OP_EQ
, "Sleen=1-4294967294");
303 /* If we get a (barely) valid (but unsupported list, we say "yes, that's
305 tt_assert(protover_all_supported("Fribble=", &msg
));
306 tt_ptr_op(msg
, OP_EQ
, NULL
);
308 /* If we get a completely unparseable list, protover_all_supported should
309 * hit a fatal assertion for BUG(entries == NULL). */
310 tor_capture_bugs_(1);
311 tt_assert(protover_all_supported("Fribble", &msg
));
312 tor_end_capture_bugs_();
314 /* If we get a completely unparseable list, protover_all_supported should
315 * hit a fatal assertion for BUG(entries == NULL). */
316 tor_capture_bugs_(1);
317 tt_assert(protover_all_supported("Sleen=1-4294967295", &msg
));
318 tor_end_capture_bugs_();
320 /* Protocol name too long */
321 #ifndef HAVE_RUST // XXXXXX ?????
322 tor_capture_bugs_(1);
323 tt_assert(protover_all_supported(
324 "DoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
325 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
326 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
327 "aaaaaaaaaaaa=1-65536", &msg
));
328 tor_end_capture_bugs_();
332 tor_end_capture_bugs_();
337 test_protover_list_supports_protocol_returns_true(void *arg
)
341 const char *protocols
= "Link=1";
342 int is_supported
= protocol_list_supports_protocol(protocols
, PRT_LINK
, 1);
343 tt_int_op(is_supported
, OP_EQ
, 1);
350 test_protover_list_supports_protocol_for_unsupported_returns_false(void *arg
)
354 const char *protocols
= "Link=1";
355 int is_supported
= protocol_list_supports_protocol(protocols
, PRT_LINK
, 10);
356 tt_int_op(is_supported
, OP_EQ
, 0);
363 test_protover_supports_version(void *arg
)
367 tt_assert(protocol_list_supports_protocol("Link=3-6", PRT_LINK
, 3));
368 tt_assert(protocol_list_supports_protocol("Link=3-6", PRT_LINK
, 6));
369 tt_assert(!protocol_list_supports_protocol("Link=3-6", PRT_LINK
, 7));
370 tt_assert(!protocol_list_supports_protocol("Link=3-6", PRT_LINKAUTH
, 3));
372 tt_assert(!protocol_list_supports_protocol("Link=4-6 LinkAuth=3",
374 tt_assert(protocol_list_supports_protocol("Link=4-6 LinkAuth=3",
376 tt_assert(!protocol_list_supports_protocol("Link=4-6 LinkAuth=3",
378 tt_assert(!protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3",
380 tt_assert(protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3",
382 tt_assert(protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3",
385 tt_assert(!protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3",
391 /* This could be MAX_PROTOCOLS_TO_EXPAND, but that's not exposed by protover */
392 #define MAX_PROTOCOLS_TO_TEST 1024
394 /* LinkAuth and Relay protocol versions.
395 * Hard-coded here, because they are not in the code, or not exposed in the
397 #define PROTOVER_LINKAUTH_V1 1
398 #define PROTOVER_LINKAUTH_V3 3
400 #define PROTOVER_RELAY_V1 1
401 #define PROTOVER_RELAY_V2 2
403 /* Highest supported HSv2 introduce protocol version.
404 * Hard-coded here, because it does not appear anywhere in the code.
405 * It's not clear if we actually support version 2, see #25068. */
406 #define PROTOVER_HSINTRO_V2 3
408 /* HSv2 Rend and HSDir protocol versions.
409 * Hard-coded here, because they do not appear anywhere in the code. */
410 #define PROTOVER_HS_RENDEZVOUS_POINT_V2 1
411 #define PROTOVER_HSDIR_V2 1
413 /* DirCache, Desc, Microdesc, and Cons protocol versions.
414 * Hard-coded here, because they do not appear anywhere in the code. */
415 #define PROTOVER_DIRCACHE_V1 1
416 #define PROTOVER_DIRCACHE_V2 2
418 #define PROTOVER_DESC_V1 1
419 #define PROTOVER_DESC_V2 2
421 #define PROTOVER_MICRODESC_V1 1
422 #define PROTOVER_MICRODESC_V2 2
424 #define PROTOVER_CONS_V1 1
425 #define PROTOVER_CONS_V2 2
427 /* Make sure we haven't forgotten any supported protocols */
429 test_protover_supported_protocols(void *arg
)
433 const char *supported_protocols
= protover_get_supported_protocols();
435 /* Test for new Link in the code, that hasn't been added to supported
437 tt_assert(protocol_list_supports_protocol(supported_protocols
,
440 for (uint16_t i
= 0; i
< MAX_PROTOCOLS_TO_TEST
; i
++) {
441 if (is_or_protocol_version_known(i
)) {
442 tt_assert(protocol_list_supports_protocol(supported_protocols
,
448 /* Legacy LinkAuth does not appear anywhere in the code. */
449 tt_assert(protocol_list_supports_protocol(supported_protocols
,
451 PROTOVER_LINKAUTH_V1
));
452 /* Latest LinkAuth is not exposed in the headers. */
453 tt_assert(protocol_list_supports_protocol(supported_protocols
,
455 PROTOVER_LINKAUTH_V3
));
456 /* Is there any way to test for new LinkAuth? */
458 /* Relay protovers do not appear anywhere in the code. */
459 tt_assert(protocol_list_supports_protocol(supported_protocols
,
462 tt_assert(protocol_list_supports_protocol(supported_protocols
,
465 /* Is there any way to test for new Relay? */
467 /* We could test legacy HSIntro by calling rend_service_update_descriptor(),
468 * and checking the protocols field. But that's unlikely to change, so
469 * we just use a hard-coded value. */
470 tt_assert(protocol_list_supports_protocol(supported_protocols
,
472 PROTOVER_HSINTRO_V2
));
473 /* Test for HSv3 HSIntro */
474 tt_assert(protocol_list_supports_protocol(supported_protocols
,
476 PROTOVER_HS_INTRO_V3
));
477 /* Is there any way to test for new HSIntro? */
479 /* Legacy HSRend does not appear anywhere in the code. */
480 tt_assert(protocol_list_supports_protocol(supported_protocols
,
482 PROTOVER_HS_RENDEZVOUS_POINT_V2
));
483 /* Test for HSv3 HSRend */
484 tt_assert(protocol_list_supports_protocol(supported_protocols
,
486 PROTOVER_HS_RENDEZVOUS_POINT_V3
));
487 /* Is there any way to test for new HSRend? */
489 /* Legacy HSDir does not appear anywhere in the code. */
490 tt_assert(protocol_list_supports_protocol(supported_protocols
,
493 /* Test for HSv3 HSDir */
494 tt_assert(protocol_list_supports_protocol(supported_protocols
,
497 /* Is there any way to test for new HSDir? */
499 /* No DirCache versions appear anywhere in the code. */
500 tt_assert(protocol_list_supports_protocol(supported_protocols
,
502 PROTOVER_DIRCACHE_V1
));
503 tt_assert(protocol_list_supports_protocol(supported_protocols
,
505 PROTOVER_DIRCACHE_V2
));
506 /* Is there any way to test for new DirCache? */
508 /* No Desc versions appear anywhere in the code. */
509 tt_assert(protocol_list_supports_protocol(supported_protocols
,
512 tt_assert(protocol_list_supports_protocol(supported_protocols
,
515 /* Is there any way to test for new Desc? */
517 /* No Microdesc versions appear anywhere in the code. */
518 tt_assert(protocol_list_supports_protocol(supported_protocols
,
520 PROTOVER_MICRODESC_V1
));
521 tt_assert(protocol_list_supports_protocol(supported_protocols
,
523 PROTOVER_MICRODESC_V2
));
524 /* Is there any way to test for new Microdesc? */
526 /* No Cons versions appear anywhere in the code. */
527 tt_assert(protocol_list_supports_protocol(supported_protocols
,
530 tt_assert(protocol_list_supports_protocol(supported_protocols
,
533 /* Is there any way to test for new Cons? */
540 test_protover_vote_roundtrip(void *args
)
543 static const struct {
545 const char *expected_output
;
547 { "Risqu\u00e9=1", NULL
},
550 { "Foo_Bar=1", NULL
},
551 { "Fkrkljdsf", NULL
},
552 { "Zn=4294967295", NULL
},
553 { "Zn=4294967295-1", NULL
},
554 { "Zn=4294967293-4294967295", NULL
},
555 /* Will fail because of 4294967295. */
556 { "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16,900 Zn=1,4294967295",
558 { "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16,900 Zn=1,4294967294",
559 "Bar=3 Foo=1,3 Quux=9-12,14-16,900 Zn=1,4294967294" },
560 { "Zu16=1,65536", "Zu16=1,65536" },
561 { "N-1=1,2", "N-1=1-2" },
562 { "-1=4294967295", NULL
},
566 /* Missing equals sign */
567 { "Link=4 Haprauxymatyve Desc=9", NULL
},
568 { "Link=4 Haprauxymatyve=7 Desc=9",
569 "Desc=9 Haprauxymatyve=7 Link=4" },
571 { "X=10-11", "X=10-11" },
572 { "Link=4 =3 Desc=9", NULL
},
573 { "Link=4 Z=3 Desc=9", "Desc=9 Link=4 Z=3" },
574 { "Link=fred", NULL
},
575 { "Link=1,fred", NULL
},
576 { "Link=1,fred,3", NULL
},
577 { "Link=1,9-8,3", NULL
},
579 { "Faux=0--0", NULL
},
581 { "Faux=-1-3", NULL
},
582 { "Faux=1--1", NULL
},
584 { "Link=4294967296", NULL
},
586 { "Sleen=1-501", "Sleen=1-501" },
587 { "Sleen=1-65537", NULL
},
588 /* Both C/Rust implementations should be able to handle this mild DoS. */
589 { "Sleen=1-2147483648", NULL
},
590 /* Rust tests are built in debug mode, so ints are bounds-checked. */
591 { "Sleen=1-4294967295", NULL
},
594 smartlist_t
*votes
= smartlist_new();
597 for (u
= 0; u
< ARRAY_LENGTH(examples
); ++u
) {
598 const char *input
= examples
[u
].input
;
599 const char *expected_output
= examples
[u
].expected_output
;
601 smartlist_add(votes
, (void*)input
);
602 result
= protover_compute_vote(votes
, 1);
603 if (expected_output
!= NULL
) {
604 tt_str_op(result
, OP_EQ
, expected_output
);
606 tt_str_op(result
, OP_EQ
, "");
609 smartlist_clear(votes
);
614 smartlist_free(votes
);
618 #define PV_TEST(name, flags) \
619 { #name, test_protover_ ##name, (flags), NULL, NULL }
621 struct testcase_t protover_tests
[] = {
623 PV_TEST(parse_fail
, 0),
625 PV_TEST(all_supported
, 0),
626 PV_TEST(list_supports_protocol_for_unsupported_returns_false
, 0),
627 PV_TEST(list_supports_protocol_returns_true
, 0),
628 PV_TEST(supports_version
, 0),
629 PV_TEST(supported_protocols
, 0),
630 PV_TEST(vote_roundtrip
, 0),