hs_circuitmap.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. /* Copyright (c) 2016-2019, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file hs_circuitmap.c
  5. *
  6. * \brief Hidden service circuitmap: A hash table that maps binary tokens to
  7. * introduction and rendezvous circuits; it's used:
  8. * (a) by relays acting as intro points and rendezvous points
  9. * (b) by hidden services to find intro and rend circuits and
  10. * (c) by HS clients to find rendezvous circuits.
  11. **/
  12. #define HS_CIRCUITMAP_PRIVATE
  13. #include "core/or/or.h"
  14. #include "app/config/config.h"
  15. #include "core/or/circuitlist.h"
  16. #include "feature/hs/hs_circuitmap.h"
  17. #include "core/or/or_circuit_st.h"
  18. #include "core/or/origin_circuit_st.h"
  19. /************************** HS circuitmap code *******************************/
  20. /* This is the hidden service circuitmap. It's a hash table that maps
  21. introduction and rendezvous tokens to specific circuits such that given a
  22. token it's easy to find the corresponding circuit. */
  23. static struct hs_circuitmap_ht *the_hs_circuitmap = NULL;
  24. /* This is a helper function used by the hash table code (HT_). It returns 1 if
  25. * two circuits have the same HS token. */
  26. static int
  27. hs_circuits_have_same_token(const circuit_t *first_circuit,
  28. const circuit_t *second_circuit)
  29. {
  30. const hs_token_t *first_token;
  31. const hs_token_t *second_token;
  32. tor_assert(first_circuit);
  33. tor_assert(second_circuit);
  34. first_token = first_circuit->hs_token;
  35. second_token = second_circuit->hs_token;
  36. /* Both circs must have a token */
  37. if (BUG(!first_token) || BUG(!second_token)) {
  38. return 0;
  39. }
  40. if (first_token->type != second_token->type) {
  41. return 0;
  42. }
  43. if (first_token->token_len != second_token->token_len)
  44. return 0;
  45. return tor_memeq(first_token->token,
  46. second_token->token,
  47. first_token->token_len);
  48. }
  49. /* This is a helper function for the hash table code (HT_). It hashes a circuit
  50. * HS token into an unsigned int for use as a key by the hash table routines.*/
  51. static inline unsigned int
  52. hs_circuit_hash_token(const circuit_t *circuit)
  53. {
  54. tor_assert(circuit->hs_token);
  55. return (unsigned) siphash24g(circuit->hs_token->token,
  56. circuit->hs_token->token_len);
  57. }
  58. /* Register the circuitmap hash table */
  59. HT_PROTOTYPE(hs_circuitmap_ht, // The name of the hashtable struct
  60. circuit_t, // The name of the element struct,
  61. hs_circuitmap_node, // The name of HT_ENTRY member
  62. hs_circuit_hash_token, hs_circuits_have_same_token)
  63. HT_GENERATE2(hs_circuitmap_ht, circuit_t, hs_circuitmap_node,
  64. hs_circuit_hash_token, hs_circuits_have_same_token,
  65. 0.6, tor_reallocarray, tor_free_)
  66. #ifdef TOR_UNIT_TESTS
  67. /* Return the global HS circuitmap. Used by unittests. */
  68. hs_circuitmap_ht *
  69. get_hs_circuitmap(void)
  70. {
  71. return the_hs_circuitmap;
  72. }
  73. #endif /* defined(TOR_UNIT_TESTS) */
  74. /****************** HS circuitmap utility functions **************************/
  75. /** Return a new HS token of type <b>type</b> containing <b>token</b>. */
  76. static hs_token_t *
  77. hs_token_new(hs_token_type_t type, size_t token_len,
  78. const uint8_t *token)
  79. {
  80. tor_assert(token);
  81. hs_token_t *hs_token = tor_malloc_zero(sizeof(hs_token_t));
  82. hs_token->type = type;
  83. hs_token->token_len = token_len;
  84. hs_token->token = tor_memdup(token, token_len);
  85. return hs_token;
  86. }
  87. #define hs_token_free(val) \
  88. FREE_AND_NULL(hs_token_t, hs_token_free_, (val))
  89. /** Free memory allocated by this <b>hs_token</b>. */
  90. static void
  91. hs_token_free_(hs_token_t *hs_token)
  92. {
  93. if (!hs_token) {
  94. return;
  95. }
  96. tor_free(hs_token->token);
  97. tor_free(hs_token);
  98. }
  99. /** Return the circuit from the circuitmap with token <b>search_token</b>. */
  100. static circuit_t *
  101. get_circuit_with_token(hs_token_t *search_token)
  102. {
  103. tor_assert(the_hs_circuitmap);
  104. /* We use a dummy circuit object for the hash table search routine. */
  105. circuit_t search_circ;
  106. search_circ.hs_token = search_token;
  107. return HT_FIND(hs_circuitmap_ht, the_hs_circuitmap, &search_circ);
  108. }
  109. /* Helper function that registers <b>circ</b> with <b>token</b> on the HS
  110. circuitmap. This function steals reference of <b>token</b>. */
  111. static void
  112. hs_circuitmap_register_impl(circuit_t *circ, hs_token_t *token)
  113. {
  114. tor_assert(circ);
  115. tor_assert(token);
  116. tor_assert(the_hs_circuitmap);
  117. /* If this circuit already has a token, clear it. */
  118. if (circ->hs_token) {
  119. hs_circuitmap_remove_circuit(circ);
  120. }
  121. /* Kill old circuits with the same token. We want new intro/rend circuits to
  122. take precedence over old ones, so that HSes and clients and reestablish
  123. killed circuits without changing the HS token. */
  124. {
  125. circuit_t *found_circ;
  126. found_circ = get_circuit_with_token(token);
  127. if (found_circ) {
  128. hs_circuitmap_remove_circuit(found_circ);
  129. if (!found_circ->marked_for_close) {
  130. circuit_mark_for_close(found_circ, END_CIRC_REASON_FINISHED);
  131. }
  132. }
  133. }
  134. /* Register circuit and token to circuitmap. */
  135. circ->hs_token = token;
  136. HT_INSERT(hs_circuitmap_ht, the_hs_circuitmap, circ);
  137. }
  138. /** Helper function: Register <b>circ</b> of <b>type</b> on the HS
  139. * circuitmap. Use the HS <b>token</b> as the key to the hash table. If
  140. * <b>token</b> is not set, clear the circuit of any HS tokens. */
  141. static void
  142. hs_circuitmap_register_circuit(circuit_t *circ,
  143. hs_token_type_t type, size_t token_len,
  144. const uint8_t *token)
  145. {
  146. hs_token_t *hs_token = NULL;
  147. /* Create a new token and register it to the circuitmap */
  148. tor_assert(token);
  149. hs_token = hs_token_new(type, token_len, token);
  150. tor_assert(hs_token);
  151. hs_circuitmap_register_impl(circ, hs_token);
  152. }
  153. /* Helper function for hs_circuitmap_get_origin_circuit() and
  154. * hs_circuitmap_get_or_circuit(). Because only circuit_t are indexed in the
  155. * circuitmap, this function returns object type so the specialized functions
  156. * using this helper can upcast it to the right type.
  157. *
  158. * Return NULL if not such circuit is found. */
  159. static circuit_t *
  160. hs_circuitmap_get_circuit_impl(hs_token_type_t type,
  161. size_t token_len,
  162. const uint8_t *token,
  163. uint8_t wanted_circ_purpose)
  164. {
  165. circuit_t *found_circ = NULL;
  166. tor_assert(the_hs_circuitmap);
  167. /* Check the circuitmap if we have a circuit with this token */
  168. {
  169. hs_token_t *search_hs_token = hs_token_new(type, token_len, token);
  170. tor_assert(search_hs_token);
  171. found_circ = get_circuit_with_token(search_hs_token);
  172. hs_token_free(search_hs_token);
  173. }
  174. /* Check that the circuit is useful to us */
  175. if (!found_circ ||
  176. found_circ->purpose != wanted_circ_purpose ||
  177. found_circ->marked_for_close) {
  178. return NULL;
  179. }
  180. return found_circ;
  181. }
  182. /* Helper function: Query circuitmap for origin circuit with <b>token</b> of
  183. * size <b>token_len</b> and <b>type</b>. Only returns a circuit with purpose
  184. * equal to the <b>wanted_circ_purpose</b> parameter and if it is NOT marked
  185. * for close. Return NULL if no such circuit is found. */
  186. static origin_circuit_t *
  187. hs_circuitmap_get_origin_circuit(hs_token_type_t type,
  188. size_t token_len,
  189. const uint8_t *token,
  190. uint8_t wanted_circ_purpose)
  191. {
  192. circuit_t *circ;
  193. tor_assert(token);
  194. tor_assert(CIRCUIT_PURPOSE_IS_ORIGIN(wanted_circ_purpose));
  195. circ = hs_circuitmap_get_circuit_impl(type, token_len, token,
  196. wanted_circ_purpose);
  197. if (!circ) {
  198. return NULL;
  199. }
  200. tor_assert(CIRCUIT_IS_ORIGIN(circ));
  201. return TO_ORIGIN_CIRCUIT(circ);
  202. }
  203. /* Helper function: Query circuitmap for OR circuit with <b>token</b> of size
  204. * <b>token_len</b> and <b>type</b>. Only returns a circuit with purpose equal
  205. * to the <b>wanted_circ_purpose</b> parameter and if it is NOT marked for
  206. * close. Return NULL if no such circuit is found. */
  207. static or_circuit_t *
  208. hs_circuitmap_get_or_circuit(hs_token_type_t type,
  209. size_t token_len,
  210. const uint8_t *token,
  211. uint8_t wanted_circ_purpose)
  212. {
  213. circuit_t *circ;
  214. tor_assert(token);
  215. tor_assert(!CIRCUIT_PURPOSE_IS_ORIGIN(wanted_circ_purpose));
  216. circ = hs_circuitmap_get_circuit_impl(type, token_len, token,
  217. wanted_circ_purpose);
  218. if (!circ) {
  219. return NULL;
  220. }
  221. tor_assert(CIRCUIT_IS_ORCIRC(circ));
  222. return TO_OR_CIRCUIT(circ);
  223. }
  224. /************** Public circuitmap API ****************************************/
  225. /**** Public relay-side getters: */
  226. /* Public function: Return v2 and v3 introduction circuit to this relay.
  227. * Always return a newly allocated list for which it is the caller's
  228. * responsability to free it. */
  229. smartlist_t *
  230. hs_circuitmap_get_all_intro_circ_relay_side(void)
  231. {
  232. circuit_t **iter;
  233. smartlist_t *circuit_list = smartlist_new();
  234. HT_FOREACH(iter, hs_circuitmap_ht, the_hs_circuitmap) {
  235. circuit_t *circ = *iter;
  236. /* An origin circuit or purpose is wrong or the hs token is not set to be
  237. * a v2 or v3 intro relay side type, we ignore the circuit. Else, we have
  238. * a match so add it to our list. */
  239. if (CIRCUIT_IS_ORIGIN(circ) ||
  240. circ->purpose != CIRCUIT_PURPOSE_INTRO_POINT ||
  241. (circ->hs_token->type != HS_TOKEN_INTRO_V3_RELAY_SIDE &&
  242. circ->hs_token->type != HS_TOKEN_INTRO_V2_RELAY_SIDE)) {
  243. continue;
  244. }
  245. smartlist_add(circuit_list, circ);
  246. }
  247. return circuit_list;
  248. }
  249. /* Public function: Return a v3 introduction circuit to this relay with
  250. * <b>auth_key</b>. Return NULL if no such circuit is found in the
  251. * circuitmap. */
  252. or_circuit_t *
  253. hs_circuitmap_get_intro_circ_v3_relay_side(
  254. const ed25519_public_key_t *auth_key)
  255. {
  256. return hs_circuitmap_get_or_circuit(HS_TOKEN_INTRO_V3_RELAY_SIDE,
  257. ED25519_PUBKEY_LEN, auth_key->pubkey,
  258. CIRCUIT_PURPOSE_INTRO_POINT);
  259. }
  260. /* Public function: Return v2 introduction circuit to this relay with
  261. * <b>digest</b>. Return NULL if no such circuit is found in the circuitmap. */
  262. or_circuit_t *
  263. hs_circuitmap_get_intro_circ_v2_relay_side(const uint8_t *digest)
  264. {
  265. return hs_circuitmap_get_or_circuit(HS_TOKEN_INTRO_V2_RELAY_SIDE,
  266. REND_TOKEN_LEN, digest,
  267. CIRCUIT_PURPOSE_INTRO_POINT);
  268. }
  269. /* Public function: Return rendezvous circuit to this relay with rendezvous
  270. * <b>cookie</b>. Return NULL if no such circuit is found in the circuitmap. */
  271. or_circuit_t *
  272. hs_circuitmap_get_rend_circ_relay_side(const uint8_t *cookie)
  273. {
  274. return hs_circuitmap_get_or_circuit(HS_TOKEN_REND_RELAY_SIDE,
  275. REND_TOKEN_LEN, cookie,
  276. CIRCUIT_PURPOSE_REND_POINT_WAITING);
  277. }
  278. /** Public relay-side setters: */
  279. /* Public function: Register rendezvous circuit with key <b>cookie</b> to the
  280. * circuitmap. */
  281. void
  282. hs_circuitmap_register_rend_circ_relay_side(or_circuit_t *circ,
  283. const uint8_t *cookie)
  284. {
  285. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  286. HS_TOKEN_REND_RELAY_SIDE,
  287. REND_TOKEN_LEN, cookie);
  288. }
  289. /* Public function: Register v2 intro circuit with key <b>digest</b> to the
  290. * circuitmap. */
  291. void
  292. hs_circuitmap_register_intro_circ_v2_relay_side(or_circuit_t *circ,
  293. const uint8_t *digest)
  294. {
  295. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  296. HS_TOKEN_INTRO_V2_RELAY_SIDE,
  297. REND_TOKEN_LEN, digest);
  298. }
  299. /* Public function: Register v3 intro circuit with key <b>auth_key</b> to the
  300. * circuitmap. */
  301. void
  302. hs_circuitmap_register_intro_circ_v3_relay_side(or_circuit_t *circ,
  303. const ed25519_public_key_t *auth_key)
  304. {
  305. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  306. HS_TOKEN_INTRO_V3_RELAY_SIDE,
  307. ED25519_PUBKEY_LEN, auth_key->pubkey);
  308. }
  309. /**** Public servide-side getters: */
  310. /* Public function: Return v3 introduction circuit with <b>auth_key</b>
  311. * originating from this hidden service. Return NULL if no such circuit is
  312. * found in the circuitmap. */
  313. origin_circuit_t *
  314. hs_circuitmap_get_intro_circ_v3_service_side(const
  315. ed25519_public_key_t *auth_key)
  316. {
  317. origin_circuit_t *circ = NULL;
  318. /* Check first for established intro circuits */
  319. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V3_SERVICE_SIDE,
  320. ED25519_PUBKEY_LEN, auth_key->pubkey,
  321. CIRCUIT_PURPOSE_S_INTRO);
  322. if (circ) {
  323. return circ;
  324. }
  325. /* ...if nothing found, check for pending intro circs */
  326. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V3_SERVICE_SIDE,
  327. ED25519_PUBKEY_LEN, auth_key->pubkey,
  328. CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
  329. return circ;
  330. }
  331. /* Public function: Return v2 introduction circuit originating from this hidden
  332. * service with <b>digest</b>. Return NULL if no such circuit is found in the
  333. * circuitmap. */
  334. origin_circuit_t *
  335. hs_circuitmap_get_intro_circ_v2_service_side(const uint8_t *digest)
  336. {
  337. origin_circuit_t *circ = NULL;
  338. /* Check first for established intro circuits */
  339. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V2_SERVICE_SIDE,
  340. REND_TOKEN_LEN, digest,
  341. CIRCUIT_PURPOSE_S_INTRO);
  342. if (circ) {
  343. return circ;
  344. }
  345. /* ...if nothing found, check for pending intro circs */
  346. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V2_SERVICE_SIDE,
  347. REND_TOKEN_LEN, digest,
  348. CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
  349. return circ;
  350. }
  351. /* Public function: Return rendezvous circuit originating from this hidden
  352. * service with rendezvous <b>cookie</b>. Return NULL if no such circuit is
  353. * found in the circuitmap. */
  354. origin_circuit_t *
  355. hs_circuitmap_get_rend_circ_service_side(const uint8_t *cookie)
  356. {
  357. origin_circuit_t *circ = NULL;
  358. /* Try to check if we have a connecting circuit. */
  359. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_REND_SERVICE_SIDE,
  360. REND_TOKEN_LEN, cookie,
  361. CIRCUIT_PURPOSE_S_CONNECT_REND);
  362. if (circ) {
  363. return circ;
  364. }
  365. /* Then try for connected circuit. */
  366. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_REND_SERVICE_SIDE,
  367. REND_TOKEN_LEN, cookie,
  368. CIRCUIT_PURPOSE_S_REND_JOINED);
  369. return circ;
  370. }
  371. /* Public function: Return client-side rendezvous circuit with rendezvous
  372. * <b>cookie</b>. It will look for circuits with the following purposes:
  373. * a) CIRCUIT_PURPOSE_C_REND_READY: Established rend circuit (received
  374. * RENDEZVOUS_ESTABLISHED). Waiting for RENDEZVOUS2 from service, and for
  375. * INTRODUCE_ACK from intro point.
  376. *
  377. * b) CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: Established rend circuit and
  378. * introduce circuit acked. Waiting for RENDEZVOUS2 from service.
  379. *
  380. * c) CIRCUIT_PURPOSE_C_REND_JOINED: Established rend circuit and received
  381. * RENDEZVOUS2 from service.
  382. *
  383. * d) CIRCUIT_PURPOSE_C_ESTABLISH_REND: Rend circuit open but not yet
  384. * established.
  385. *
  386. * Return NULL if no such circuit is found in the circuitmap. */
  387. origin_circuit_t *
  388. hs_circuitmap_get_rend_circ_client_side(const uint8_t *cookie)
  389. {
  390. origin_circuit_t *circ = NULL;
  391. circ = hs_circuitmap_get_established_rend_circ_client_side(cookie);
  392. if (circ) {
  393. return circ;
  394. }
  395. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_REND_CLIENT_SIDE,
  396. REND_TOKEN_LEN, cookie,
  397. CIRCUIT_PURPOSE_C_ESTABLISH_REND);
  398. return circ;
  399. }
  400. /* Public function: Return client-side established rendezvous circuit with
  401. * rendezvous <b>cookie</b>. It will look for circuits with the following
  402. * purposes:
  403. *
  404. * a) CIRCUIT_PURPOSE_C_REND_READY: Established rend circuit (received
  405. * RENDEZVOUS_ESTABLISHED). Waiting for RENDEZVOUS2 from service, and for
  406. * INTRODUCE_ACK from intro point.
  407. *
  408. * b) CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: Established rend circuit and
  409. * introduce circuit acked. Waiting for RENDEZVOUS2 from service.
  410. *
  411. * c) CIRCUIT_PURPOSE_C_REND_JOINED: Established rend circuit and received
  412. * RENDEZVOUS2 from service.
  413. *
  414. * Return NULL if no such circuit is found in the circuitmap. */
  415. origin_circuit_t *
  416. hs_circuitmap_get_established_rend_circ_client_side(const uint8_t *cookie)
  417. {
  418. origin_circuit_t *circ = NULL;
  419. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_REND_CLIENT_SIDE,
  420. REND_TOKEN_LEN, cookie,
  421. CIRCUIT_PURPOSE_C_REND_READY);
  422. if (circ) {
  423. return circ;
  424. }
  425. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_REND_CLIENT_SIDE,
  426. REND_TOKEN_LEN, cookie,
  427. CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED);
  428. if (circ) {
  429. return circ;
  430. }
  431. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_REND_CLIENT_SIDE,
  432. REND_TOKEN_LEN, cookie,
  433. CIRCUIT_PURPOSE_C_REND_JOINED);
  434. return circ;
  435. }
  436. /**** Public servide-side setters: */
  437. /* Public function: Register v2 intro circuit with key <b>digest</b> to the
  438. * circuitmap. */
  439. void
  440. hs_circuitmap_register_intro_circ_v2_service_side(origin_circuit_t *circ,
  441. const uint8_t *digest)
  442. {
  443. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  444. HS_TOKEN_INTRO_V2_SERVICE_SIDE,
  445. REND_TOKEN_LEN, digest);
  446. }
  447. /* Public function: Register v3 intro circuit with key <b>auth_key</b> to the
  448. * circuitmap. */
  449. void
  450. hs_circuitmap_register_intro_circ_v3_service_side(origin_circuit_t *circ,
  451. const ed25519_public_key_t *auth_key)
  452. {
  453. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  454. HS_TOKEN_INTRO_V3_SERVICE_SIDE,
  455. ED25519_PUBKEY_LEN, auth_key->pubkey);
  456. }
  457. /* Public function: Register rendezvous circuit with key <b>cookie</b> to the
  458. * circuitmap. */
  459. void
  460. hs_circuitmap_register_rend_circ_service_side(origin_circuit_t *circ,
  461. const uint8_t *cookie)
  462. {
  463. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  464. HS_TOKEN_REND_SERVICE_SIDE,
  465. REND_TOKEN_LEN, cookie);
  466. }
  467. /* Public function: Register rendezvous circuit with key <b>cookie</b> to the
  468. * client-side circuitmap. */
  469. void
  470. hs_circuitmap_register_rend_circ_client_side(origin_circuit_t *or_circ,
  471. const uint8_t *cookie)
  472. {
  473. circuit_t *circ = TO_CIRCUIT(or_circ);
  474. { /* Basic circ purpose sanity checking */
  475. tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
  476. }
  477. hs_circuitmap_register_circuit(circ, HS_TOKEN_REND_CLIENT_SIDE,
  478. REND_TOKEN_LEN, cookie);
  479. }
  480. /**** Misc public functions: */
  481. /** Public function: Remove this circuit from the HS circuitmap. Clear its HS
  482. * token, and remove it from the hashtable. */
  483. void
  484. hs_circuitmap_remove_circuit(circuit_t *circ)
  485. {
  486. tor_assert(the_hs_circuitmap);
  487. if (!circ || !circ->hs_token) {
  488. return;
  489. }
  490. /* Remove circ from circuitmap */
  491. circuit_t *tmp;
  492. tmp = HT_REMOVE(hs_circuitmap_ht, the_hs_circuitmap, circ);
  493. /* ... and ensure the removal was successful. */
  494. if (tmp) {
  495. tor_assert(tmp == circ);
  496. } else {
  497. log_warn(LD_BUG, "Could not find circuit (%u) in circuitmap.",
  498. circ->n_circ_id);
  499. }
  500. /* Clear token from circ */
  501. hs_token_free(circ->hs_token);
  502. circ->hs_token = NULL;
  503. }
  504. /* Public function: Initialize the global HS circuitmap. */
  505. void
  506. hs_circuitmap_init(void)
  507. {
  508. tor_assert(!the_hs_circuitmap);
  509. the_hs_circuitmap = tor_malloc_zero(sizeof(struct hs_circuitmap_ht));
  510. HT_INIT(hs_circuitmap_ht, the_hs_circuitmap);
  511. }
  512. /* Public function: Free all memory allocated by the global HS circuitmap. */
  513. void
  514. hs_circuitmap_free_all(void)
  515. {
  516. if (the_hs_circuitmap) {
  517. HT_CLEAR(hs_circuitmap_ht, the_hs_circuitmap);
  518. tor_free(the_hs_circuitmap);
  519. }
  520. }