hs_circuitmap.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /* Copyright (c) 2016-2017, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file hs_circuitmap.c
  5. *
  6. * \brief Manage the hidden service circuitmap: A hash table that maps binary
  7. * tokens to introduction and rendezvous circuits.
  8. **/
  9. #define HS_CIRCUITMAP_PRIVATE
  10. #include "or.h"
  11. #include "config.h"
  12. #include "circuitlist.h"
  13. #include "hs_circuitmap.h"
  14. /************************** HS circuitmap code *******************************/
  15. /* This is the hidden service circuitmap. It's a hash table that maps
  16. introduction and rendezvous tokens to specific circuits such that given a
  17. token it's easy to find the corresponding circuit. */
  18. static struct hs_circuitmap_ht *the_hs_circuitmap = NULL;
  19. /* This is a helper function used by the hash table code (HT_). It returns 1 if
  20. * two circuits have the same HS token. */
  21. static int
  22. hs_circuits_have_same_token(const circuit_t *first_circuit,
  23. const circuit_t *second_circuit)
  24. {
  25. const hs_token_t *first_token;
  26. const hs_token_t *second_token;
  27. tor_assert(first_circuit);
  28. tor_assert(second_circuit);
  29. first_token = first_circuit->hs_token;
  30. second_token = second_circuit->hs_token;
  31. /* Both circs must have a token */
  32. if (BUG(!first_token) || BUG(!second_token)) {
  33. return 0;
  34. }
  35. if (first_token->type != second_token->type) {
  36. return 0;
  37. }
  38. if (first_token->token_len != second_token->token_len)
  39. return 0;
  40. return tor_memeq(first_token->token,
  41. second_token->token,
  42. first_token->token_len);
  43. }
  44. /* This is a helper function for the hash table code (HT_). It hashes a circuit
  45. * HS token into an unsigned int for use as a key by the hash table routines.*/
  46. static inline unsigned int
  47. hs_circuit_hash_token(const circuit_t *circuit)
  48. {
  49. tor_assert(circuit->hs_token);
  50. return (unsigned) siphash24g(circuit->hs_token->token,
  51. circuit->hs_token->token_len);
  52. }
  53. /* Register the circuitmap hash table */
  54. HT_PROTOTYPE(hs_circuitmap_ht, // The name of the hashtable struct
  55. circuit_t, // The name of the element struct,
  56. hs_circuitmap_node, // The name of HT_ENTRY member
  57. hs_circuit_hash_token, hs_circuits_have_same_token)
  58. HT_GENERATE2(hs_circuitmap_ht, circuit_t, hs_circuitmap_node,
  59. hs_circuit_hash_token, hs_circuits_have_same_token,
  60. 0.6, tor_reallocarray, tor_free_)
  61. #ifdef TOR_UNIT_TESTS
  62. /* Return the global HS circuitmap. Used by unittests. */
  63. hs_circuitmap_ht *
  64. get_hs_circuitmap(void)
  65. {
  66. return the_hs_circuitmap;
  67. }
  68. #endif
  69. /****************** HS circuitmap utility functions **************************/
  70. /** Return a new HS token of type <b>type</b> containing <b>token</b>. */
  71. static hs_token_t *
  72. hs_token_new(hs_token_type_t type, size_t token_len,
  73. const uint8_t *token)
  74. {
  75. tor_assert(token);
  76. hs_token_t *hs_token = tor_malloc_zero(sizeof(hs_token_t));
  77. hs_token->type = type;
  78. hs_token->token_len = token_len;
  79. hs_token->token = tor_memdup(token, token_len);
  80. return hs_token;
  81. }
  82. /** Free memory allocated by this <b>hs_token</b>. */
  83. static void
  84. hs_token_free(hs_token_t *hs_token)
  85. {
  86. if (!hs_token) {
  87. return;
  88. }
  89. tor_free(hs_token->token);
  90. tor_free(hs_token);
  91. }
  92. /** Return the circuit from the circuitmap with token <b>search_token</b>. */
  93. static circuit_t *
  94. get_circuit_with_token(hs_token_t *search_token)
  95. {
  96. tor_assert(the_hs_circuitmap);
  97. /* We use a dummy circuit object for the hash table search routine. */
  98. circuit_t search_circ;
  99. search_circ.hs_token = search_token;
  100. return HT_FIND(hs_circuitmap_ht, the_hs_circuitmap, &search_circ);
  101. }
  102. /* Helper function that registers <b>circ</b> with <b>token</b> on the HS
  103. circuitmap. This function steals reference of <b>token</b>. */
  104. static void
  105. hs_circuitmap_register_impl(circuit_t *circ, hs_token_t *token)
  106. {
  107. tor_assert(circ);
  108. tor_assert(token);
  109. tor_assert(the_hs_circuitmap);
  110. /* If this circuit already has a token, clear it. */
  111. if (circ->hs_token) {
  112. hs_circuitmap_remove_circuit(circ);
  113. }
  114. /* Kill old circuits with the same token. We want new intro/rend circuits to
  115. take precedence over old ones, so that HSes and clients and reestablish
  116. killed circuits without changing the HS token. */
  117. {
  118. circuit_t *found_circ;
  119. found_circ = get_circuit_with_token(token);
  120. if (found_circ) {
  121. hs_circuitmap_remove_circuit(found_circ);
  122. if (!found_circ->marked_for_close) {
  123. circuit_mark_for_close(found_circ, END_CIRC_REASON_FINISHED);
  124. }
  125. }
  126. }
  127. /* Register circuit and token to circuitmap. */
  128. circ->hs_token = token;
  129. HT_INSERT(hs_circuitmap_ht, the_hs_circuitmap, circ);
  130. }
  131. /** Helper function: Register <b>circ</b> of <b>type</b> on the HS
  132. * circuitmap. Use the HS <b>token</b> as the key to the hash table. If
  133. * <b>token</b> is not set, clear the circuit of any HS tokens. */
  134. static void
  135. hs_circuitmap_register_circuit(circuit_t *circ,
  136. hs_token_type_t type, size_t token_len,
  137. const uint8_t *token)
  138. {
  139. hs_token_t *hs_token = NULL;
  140. /* Create a new token and register it to the circuitmap */
  141. tor_assert(token);
  142. hs_token = hs_token_new(type, token_len, token);
  143. tor_assert(hs_token);
  144. hs_circuitmap_register_impl(circ, hs_token);
  145. }
  146. /* Query circuitmap for circuit with <b>token</b> of size <b>token_len</b>.
  147. * Only returns a circuit with purpose equal to the <b>wanted_circ_purpose</b>
  148. * parameter and if it is NOT marked for close. Return NULL if no such circuit
  149. * is found. */
  150. static circuit_t *
  151. hs_circuitmap_get_circuit(hs_token_type_t type,
  152. size_t token_len,
  153. const uint8_t *token,
  154. uint8_t wanted_circ_purpose)
  155. {
  156. circuit_t *found_circ = NULL;
  157. tor_assert(the_hs_circuitmap);
  158. /* Check the circuitmap if we have a circuit with this token */
  159. {
  160. hs_token_t *search_hs_token = hs_token_new(type, token_len, token);
  161. tor_assert(search_hs_token);
  162. found_circ = get_circuit_with_token(search_hs_token);
  163. hs_token_free(search_hs_token);
  164. }
  165. /* Check that the circuit is useful to us */
  166. if (!found_circ ||
  167. found_circ->purpose != wanted_circ_purpose ||
  168. found_circ->marked_for_close) {
  169. return NULL;
  170. }
  171. return found_circ;
  172. }
  173. /************** Public circuitmap API ****************************************/
  174. /* Public function: Return v3 introduction circuit with <b>auth_key</b>. Return
  175. * NULL if no such circuit is found in the circuitmap. */
  176. or_circuit_t *
  177. hs_circuitmap_get_intro_circ_v3(const ed25519_public_key_t *auth_key)
  178. {
  179. circuit_t *circ;
  180. tor_assert(auth_key);
  181. circ = hs_circuitmap_get_circuit(HS_TOKEN_INTRO_V3,
  182. ED25519_PUBKEY_LEN, auth_key->pubkey,
  183. CIRCUIT_PURPOSE_INTRO_POINT);
  184. if (!circ) {
  185. return NULL;
  186. }
  187. tor_assert(CIRCUIT_IS_ORCIRC(circ));
  188. return TO_OR_CIRCUIT(circ);
  189. }
  190. /* Public function: Return v2 introduction circuit with <b>digest</b>. Return
  191. * NULL if no such circuit is found in the circuitmap. */
  192. or_circuit_t *
  193. hs_circuitmap_get_intro_circ_v2(const uint8_t *digest)
  194. {
  195. circuit_t *circ;
  196. tor_assert(digest);
  197. circ = hs_circuitmap_get_circuit(HS_TOKEN_INTRO_V2,
  198. REND_TOKEN_LEN, digest,
  199. CIRCUIT_PURPOSE_INTRO_POINT);
  200. if (!circ) {
  201. return NULL;
  202. }
  203. tor_assert(CIRCUIT_IS_ORCIRC(circ));
  204. return TO_OR_CIRCUIT(circ);
  205. }
  206. /* Public function: Return rendezvous circuit with rendezvous
  207. * <b>cookie</b>. Return NULL if no such circuit is found in the circuitmap. */
  208. or_circuit_t *
  209. hs_circuitmap_get_rend_circ(const uint8_t *cookie)
  210. {
  211. circuit_t *circ;
  212. tor_assert(cookie);
  213. circ = hs_circuitmap_get_circuit(HS_TOKEN_REND,
  214. REND_TOKEN_LEN, cookie,
  215. CIRCUIT_PURPOSE_REND_POINT_WAITING);
  216. if (!circ) {
  217. return NULL;
  218. }
  219. tor_assert(CIRCUIT_IS_ORCIRC(circ));
  220. return TO_OR_CIRCUIT(circ);
  221. }
  222. /* Public function: Register rendezvous circuit with key <b>cookie</b> to the
  223. * circuitmap. */
  224. void
  225. hs_circuitmap_register_rend_circ(or_circuit_t *circ, const uint8_t *cookie)
  226. {
  227. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  228. HS_TOKEN_REND,
  229. REND_TOKEN_LEN, cookie);
  230. }
  231. /* Public function: Register v2 intro circuit with key <b>digest</b> to the
  232. * circuitmap. */
  233. void
  234. hs_circuitmap_register_intro_circ_v2(or_circuit_t *circ, const uint8_t *digest)
  235. {
  236. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  237. HS_TOKEN_INTRO_V2,
  238. REND_TOKEN_LEN, digest);
  239. }
  240. /* Public function: Register v3 intro circuit with key <b>auth_key</b> to the
  241. * circuitmap. */
  242. void
  243. hs_circuitmap_register_intro_circ_v3(or_circuit_t *circ,
  244. const ed25519_public_key_t *auth_key)
  245. {
  246. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  247. HS_TOKEN_INTRO_V3,
  248. ED25519_PUBKEY_LEN, auth_key->pubkey);
  249. }
  250. /** Remove this circuit from the HS circuitmap. Clear its HS token, and remove
  251. * it from the hashtable. */
  252. void
  253. hs_circuitmap_remove_circuit(circuit_t *circ)
  254. {
  255. tor_assert(the_hs_circuitmap);
  256. if (!circ || !circ->hs_token) {
  257. return;
  258. }
  259. /* Remove circ from circuitmap */
  260. circuit_t *tmp;
  261. tmp = HT_REMOVE(hs_circuitmap_ht, the_hs_circuitmap, circ);
  262. /* ... and ensure the removal was successful. */
  263. if (tmp) {
  264. tor_assert(tmp == circ);
  265. } else {
  266. log_warn(LD_BUG, "Could not find circuit (%u) in circuitmap.",
  267. circ->n_circ_id);
  268. }
  269. /* Clear token from circ */
  270. hs_token_free(circ->hs_token);
  271. circ->hs_token = NULL;
  272. }
  273. /* Initialize the global HS circuitmap. */
  274. void
  275. hs_circuitmap_init(void)
  276. {
  277. tor_assert(!the_hs_circuitmap);
  278. the_hs_circuitmap = tor_malloc_zero(sizeof(struct hs_circuitmap_ht));
  279. HT_INIT(hs_circuitmap_ht, the_hs_circuitmap);
  280. }
  281. /* Free all memory allocated by the global HS circuitmap. */
  282. void
  283. hs_circuitmap_free_all(void)
  284. {
  285. if (the_hs_circuitmap) {
  286. HT_CLEAR(hs_circuitmap_ht, the_hs_circuitmap);
  287. tor_free(the_hs_circuitmap);
  288. }
  289. }