test_circuitlist.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. /* Copyright (c) 2013-2016, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. #define TOR_CHANNEL_INTERNAL_
  4. #define CIRCUITBUILD_PRIVATE
  5. #define CIRCUITLIST_PRIVATE
  6. #define HS_CIRCUITMAP_PRIVATE
  7. #include "or.h"
  8. #include "channel.h"
  9. #include "circuitbuild.h"
  10. #include "circuitlist.h"
  11. #include "hs_circuitmap.h"
  12. #include "test.h"
  13. #include "log_test_helpers.h"
  14. static channel_t *
  15. new_fake_channel(void)
  16. {
  17. channel_t *chan = tor_malloc_zero(sizeof(channel_t));
  18. channel_init(chan);
  19. return chan;
  20. }
  21. static struct {
  22. int ncalls;
  23. void *cmux;
  24. void *circ;
  25. cell_direction_t dir;
  26. } cam;
  27. static void
  28. circuitmux_attach_mock(circuitmux_t *cmux, circuit_t *circ,
  29. cell_direction_t dir)
  30. {
  31. ++cam.ncalls;
  32. cam.cmux = cmux;
  33. cam.circ = circ;
  34. cam.dir = dir;
  35. }
  36. static struct {
  37. int ncalls;
  38. void *cmux;
  39. void *circ;
  40. } cdm;
  41. static void
  42. circuitmux_detach_mock(circuitmux_t *cmux, circuit_t *circ)
  43. {
  44. ++cdm.ncalls;
  45. cdm.cmux = cmux;
  46. cdm.circ = circ;
  47. }
  48. #define GOT_CMUX_ATTACH(mux_, circ_, dir_) do { \
  49. tt_int_op(cam.ncalls, OP_EQ, 1); \
  50. tt_ptr_op(cam.cmux, OP_EQ, (mux_)); \
  51. tt_ptr_op(cam.circ, OP_EQ, (circ_)); \
  52. tt_int_op(cam.dir, OP_EQ, (dir_)); \
  53. memset(&cam, 0, sizeof(cam)); \
  54. } while (0)
  55. #define GOT_CMUX_DETACH(mux_, circ_) do { \
  56. tt_int_op(cdm.ncalls, OP_EQ, 1); \
  57. tt_ptr_op(cdm.cmux, OP_EQ, (mux_)); \
  58. tt_ptr_op(cdm.circ, OP_EQ, (circ_)); \
  59. memset(&cdm, 0, sizeof(cdm)); \
  60. } while (0)
  61. static void
  62. test_clist_maps(void *arg)
  63. {
  64. channel_t *ch1 = new_fake_channel();
  65. channel_t *ch2 = new_fake_channel();
  66. channel_t *ch3 = new_fake_channel();
  67. or_circuit_t *or_c1=NULL, *or_c2=NULL;
  68. (void) arg;
  69. MOCK(circuitmux_attach_circuit, circuitmux_attach_mock);
  70. MOCK(circuitmux_detach_circuit, circuitmux_detach_mock);
  71. memset(&cam, 0, sizeof(cam));
  72. memset(&cdm, 0, sizeof(cdm));
  73. tt_assert(ch1);
  74. tt_assert(ch2);
  75. tt_assert(ch3);
  76. ch1->cmux = tor_malloc(1);
  77. ch2->cmux = tor_malloc(1);
  78. ch3->cmux = tor_malloc(1);
  79. or_c1 = or_circuit_new(100, ch2);
  80. tt_assert(or_c1);
  81. GOT_CMUX_ATTACH(ch2->cmux, or_c1, CELL_DIRECTION_IN);
  82. tt_int_op(or_c1->p_circ_id, OP_EQ, 100);
  83. tt_ptr_op(or_c1->p_chan, OP_EQ, ch2);
  84. or_c2 = or_circuit_new(100, ch1);
  85. tt_assert(or_c2);
  86. GOT_CMUX_ATTACH(ch1->cmux, or_c2, CELL_DIRECTION_IN);
  87. tt_int_op(or_c2->p_circ_id, OP_EQ, 100);
  88. tt_ptr_op(or_c2->p_chan, OP_EQ, ch1);
  89. circuit_set_n_circid_chan(TO_CIRCUIT(or_c1), 200, ch1);
  90. GOT_CMUX_ATTACH(ch1->cmux, or_c1, CELL_DIRECTION_OUT);
  91. circuit_set_n_circid_chan(TO_CIRCUIT(or_c2), 200, ch2);
  92. GOT_CMUX_ATTACH(ch2->cmux, or_c2, CELL_DIRECTION_OUT);
  93. tt_ptr_op(circuit_get_by_circid_channel(200, ch1), OP_EQ, TO_CIRCUIT(or_c1));
  94. tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, TO_CIRCUIT(or_c2));
  95. tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, TO_CIRCUIT(or_c1));
  96. /* Try the same thing again, to test the "fast" path. */
  97. tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, TO_CIRCUIT(or_c1));
  98. tt_assert(circuit_id_in_use_on_channel(100, ch2));
  99. tt_assert(! circuit_id_in_use_on_channel(101, ch2));
  100. /* Try changing the circuitid and channel of that circuit. */
  101. circuit_set_p_circid_chan(or_c1, 500, ch3);
  102. GOT_CMUX_DETACH(ch2->cmux, TO_CIRCUIT(or_c1));
  103. GOT_CMUX_ATTACH(ch3->cmux, TO_CIRCUIT(or_c1), CELL_DIRECTION_IN);
  104. tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, NULL);
  105. tt_assert(! circuit_id_in_use_on_channel(100, ch2));
  106. tt_ptr_op(circuit_get_by_circid_channel(500, ch3), OP_EQ, TO_CIRCUIT(or_c1));
  107. /* Now let's see about destroy handling. */
  108. tt_assert(! circuit_id_in_use_on_channel(205, ch2));
  109. tt_assert(circuit_id_in_use_on_channel(200, ch2));
  110. channel_note_destroy_pending(ch2, 200);
  111. channel_note_destroy_pending(ch2, 205);
  112. channel_note_destroy_pending(ch1, 100);
  113. tt_assert(circuit_id_in_use_on_channel(205, ch2))
  114. tt_assert(circuit_id_in_use_on_channel(200, ch2));
  115. tt_assert(circuit_id_in_use_on_channel(100, ch1));
  116. tt_assert(TO_CIRCUIT(or_c2)->n_delete_pending != 0);
  117. tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, TO_CIRCUIT(or_c2));
  118. tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, TO_CIRCUIT(or_c2));
  119. /* Okay, now free ch2 and make sure that the circuit ID is STILL not
  120. * usable, because we haven't declared the destroy to be nonpending */
  121. tt_int_op(cdm.ncalls, OP_EQ, 0);
  122. circuit_free(TO_CIRCUIT(or_c2));
  123. or_c2 = NULL; /* prevent free */
  124. tt_int_op(cdm.ncalls, OP_EQ, 2);
  125. memset(&cdm, 0, sizeof(cdm));
  126. tt_assert(circuit_id_in_use_on_channel(200, ch2));
  127. tt_assert(circuit_id_in_use_on_channel(100, ch1));
  128. tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, NULL);
  129. tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, NULL);
  130. /* Now say that the destroy is nonpending */
  131. channel_note_destroy_not_pending(ch2, 200);
  132. tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, NULL);
  133. channel_note_destroy_not_pending(ch1, 100);
  134. tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, NULL);
  135. tt_assert(! circuit_id_in_use_on_channel(200, ch2));
  136. tt_assert(! circuit_id_in_use_on_channel(100, ch1));
  137. done:
  138. if (or_c1)
  139. circuit_free(TO_CIRCUIT(or_c1));
  140. if (or_c2)
  141. circuit_free(TO_CIRCUIT(or_c2));
  142. if (ch1)
  143. tor_free(ch1->cmux);
  144. if (ch2)
  145. tor_free(ch2->cmux);
  146. if (ch3)
  147. tor_free(ch3->cmux);
  148. tor_free(ch1);
  149. tor_free(ch2);
  150. tor_free(ch3);
  151. UNMOCK(circuitmux_attach_circuit);
  152. UNMOCK(circuitmux_detach_circuit);
  153. }
  154. static void
  155. test_rend_token_maps(void *arg)
  156. {
  157. or_circuit_t *c1, *c2, *c3, *c4;
  158. const uint8_t tok1[REND_TOKEN_LEN] = "The cat can't tell y";
  159. const uint8_t tok2[REND_TOKEN_LEN] = "ou its name, and it ";
  160. const uint8_t tok3[REND_TOKEN_LEN] = "doesn't really care.";
  161. /* -- Adapted from a quote by Fredrik Lundh. */
  162. (void)arg;
  163. (void)tok1; //xxxx
  164. hs_circuitmap_init();
  165. c1 = or_circuit_new(0, NULL);
  166. c2 = or_circuit_new(0, NULL);
  167. c3 = or_circuit_new(0, NULL);
  168. c4 = or_circuit_new(0, NULL);
  169. /* Make sure we really filled up the tok* variables */
  170. tt_int_op(tok1[REND_TOKEN_LEN-1], OP_EQ, 'y');
  171. tt_int_op(tok2[REND_TOKEN_LEN-1], OP_EQ, ' ');
  172. tt_int_op(tok3[REND_TOKEN_LEN-1], OP_EQ, '.');
  173. /* No maps; nothing there. */
  174. tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1));
  175. tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok1));
  176. hs_circuitmap_register_rend_circ(c1, tok1);
  177. hs_circuitmap_register_intro_circ_v2(c2, tok2);
  178. tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok3));
  179. tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3));
  180. tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok2));
  181. tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok1));
  182. /* Without purpose set, we don't get the circuits */
  183. tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1));
  184. tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2));
  185. c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
  186. c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
  187. /* Okay, make sure they show up now. */
  188. tt_ptr_op(c1, OP_EQ, hs_circuitmap_get_rend_circ(tok1));
  189. tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2));
  190. /* Two items at the same place with the same token. */
  191. c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
  192. hs_circuitmap_register_rend_circ(c3, tok2);
  193. tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2));
  194. tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ(tok2));
  195. /* Marking a circuit makes it not get returned any more */
  196. circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED);
  197. tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1));
  198. circuit_free(TO_CIRCUIT(c1));
  199. c1 = NULL;
  200. /* Freeing a circuit makes it not get returned any more. */
  201. circuit_free(TO_CIRCUIT(c2));
  202. c2 = NULL;
  203. tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2));
  204. /* c3 -- are you still there? */
  205. tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ(tok2));
  206. /* Change its cookie. This never happens in Tor per se, but hey. */
  207. c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
  208. hs_circuitmap_register_intro_circ_v2(c3, tok3);
  209. tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok2));
  210. tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3));
  211. /* Now replace c3 with c4. */
  212. c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
  213. hs_circuitmap_register_intro_circ_v2(c4, tok3);
  214. tt_ptr_op(c4, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3));
  215. tt_ptr_op(c3->hs_token, OP_EQ, NULL);
  216. tt_ptr_op(c4->hs_token, OP_NE, NULL);
  217. tt_mem_op(c4->hs_token->token, OP_EQ, tok3, REND_TOKEN_LEN);
  218. /* Now clear c4's cookie. */
  219. hs_circuitmap_remove_circuit(c4);
  220. tt_ptr_op(c4->hs_token, OP_EQ, NULL);
  221. tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3));
  222. done:
  223. if (c1)
  224. circuit_free(TO_CIRCUIT(c1));
  225. if (c2)
  226. circuit_free(TO_CIRCUIT(c2));
  227. if (c3)
  228. circuit_free(TO_CIRCUIT(c3));
  229. if (c4)
  230. circuit_free(TO_CIRCUIT(c4));
  231. }
  232. static void
  233. mock_channel_dump_statistics(channel_t *chan, int severity)
  234. {
  235. (void)chan;
  236. (void)severity;
  237. }
  238. static void
  239. test_pick_circid(void *arg)
  240. {
  241. bitarray_t *ba = NULL;
  242. channel_t *chan1, *chan2;
  243. circid_t circid;
  244. int i;
  245. (void) arg;
  246. MOCK(channel_dump_statistics, mock_channel_dump_statistics);
  247. chan1 = tor_malloc_zero(sizeof(channel_t));
  248. chan2 = tor_malloc_zero(sizeof(channel_t));
  249. chan2->wide_circ_ids = 1;
  250. chan1->cmux = circuitmux_alloc();
  251. chan2->cmux = circuitmux_alloc();
  252. /* CIRC_ID_TYPE_NEITHER is supposed to create a warning. */
  253. chan1->circ_id_type = CIRC_ID_TYPE_NEITHER;
  254. setup_full_capture_of_logs(LOG_WARN);
  255. tt_int_op(0, OP_EQ, get_unique_circ_id_by_chan(chan1));
  256. expect_single_log_msg_containing("Trying to pick a circuit ID for a "
  257. "connection from a client with no identity.");
  258. teardown_capture_of_logs();
  259. /* Basic tests, with no collisions */
  260. chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
  261. for (i = 0; i < 50; ++i) {
  262. circid = get_unique_circ_id_by_chan(chan1);
  263. tt_uint_op(0, OP_LT, circid);
  264. tt_uint_op(circid, OP_LT, (1<<15));
  265. }
  266. chan1->circ_id_type = CIRC_ID_TYPE_HIGHER;
  267. for (i = 0; i < 50; ++i) {
  268. circid = get_unique_circ_id_by_chan(chan1);
  269. tt_uint_op((1<<15), OP_LT, circid);
  270. tt_uint_op(circid, OP_LT, (1<<16));
  271. }
  272. chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
  273. for (i = 0; i < 50; ++i) {
  274. circid = get_unique_circ_id_by_chan(chan2);
  275. tt_uint_op(0, OP_LT, circid);
  276. tt_uint_op(circid, OP_LT, (1u<<31));
  277. }
  278. chan2->circ_id_type = CIRC_ID_TYPE_HIGHER;
  279. for (i = 0; i < 50; ++i) {
  280. circid = get_unique_circ_id_by_chan(chan2);
  281. tt_uint_op((1u<<31), OP_LT, circid);
  282. }
  283. /* Now make sure that we can behave well when we are full up on circuits */
  284. chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
  285. chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
  286. chan1->wide_circ_ids = chan2->wide_circ_ids = 0;
  287. ba = bitarray_init_zero((1<<15));
  288. for (i = 0; i < (1<<15); ++i) {
  289. circid = get_unique_circ_id_by_chan(chan1);
  290. if (circid == 0) {
  291. tt_int_op(i, OP_GT, (1<<14));
  292. break;
  293. }
  294. tt_uint_op(circid, OP_LT, (1<<15));
  295. tt_assert(! bitarray_is_set(ba, circid));
  296. bitarray_set(ba, circid);
  297. channel_mark_circid_unusable(chan1, circid);
  298. }
  299. tt_int_op(i, OP_LT, (1<<15));
  300. /* Make sure that being full on chan1 does not interfere with chan2 */
  301. for (i = 0; i < 100; ++i) {
  302. circid = get_unique_circ_id_by_chan(chan2);
  303. tt_uint_op(circid, OP_GT, 0);
  304. tt_uint_op(circid, OP_LT, (1<<15));
  305. channel_mark_circid_unusable(chan2, circid);
  306. }
  307. done:
  308. circuitmux_free(chan1->cmux);
  309. circuitmux_free(chan2->cmux);
  310. tor_free(chan1);
  311. tor_free(chan2);
  312. bitarray_free(ba);
  313. circuit_free_all();
  314. teardown_capture_of_logs();
  315. UNMOCK(channel_dump_statistics);
  316. }
  317. struct testcase_t circuitlist_tests[] = {
  318. { "maps", test_clist_maps, TT_FORK, NULL, NULL },
  319. { "rend_token_maps", test_rend_token_maps, TT_FORK, NULL, NULL },
  320. { "pick_circid", test_pick_circid, TT_FORK, NULL, NULL },
  321. END_OF_TESTCASES
  322. };