hs_circuitmap.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /* Copyright (c) 2016-2017, 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 both by relays acting as
  8. * intro points and rendezvous points, and also by hidden services themselves.
  9. **/
  10. #define HS_CIRCUITMAP_PRIVATE
  11. #include "or.h"
  12. #include "config.h"
  13. #include "circuitlist.h"
  14. #include "hs_circuitmap.h"
  15. /************************** HS circuitmap code *******************************/
  16. /* This is the hidden service circuitmap. It's a hash table that maps
  17. introduction and rendezvous tokens to specific circuits such that given a
  18. token it's easy to find the corresponding circuit. */
  19. static struct hs_circuitmap_ht *the_hs_circuitmap = NULL;
  20. /* This is a helper function used by the hash table code (HT_). It returns 1 if
  21. * two circuits have the same HS token. */
  22. static int
  23. hs_circuits_have_same_token(const circuit_t *first_circuit,
  24. const circuit_t *second_circuit)
  25. {
  26. const hs_token_t *first_token;
  27. const hs_token_t *second_token;
  28. tor_assert(first_circuit);
  29. tor_assert(second_circuit);
  30. first_token = first_circuit->hs_token;
  31. second_token = second_circuit->hs_token;
  32. /* Both circs must have a token */
  33. if (BUG(!first_token) || BUG(!second_token)) {
  34. return 0;
  35. }
  36. if (first_token->type != second_token->type) {
  37. return 0;
  38. }
  39. if (first_token->token_len != second_token->token_len)
  40. return 0;
  41. return tor_memeq(first_token->token,
  42. second_token->token,
  43. first_token->token_len);
  44. }
  45. /* This is a helper function for the hash table code (HT_). It hashes a circuit
  46. * HS token into an unsigned int for use as a key by the hash table routines.*/
  47. static inline unsigned int
  48. hs_circuit_hash_token(const circuit_t *circuit)
  49. {
  50. tor_assert(circuit->hs_token);
  51. return (unsigned) siphash24g(circuit->hs_token->token,
  52. circuit->hs_token->token_len);
  53. }
  54. /* Register the circuitmap hash table */
  55. HT_PROTOTYPE(hs_circuitmap_ht, // The name of the hashtable struct
  56. circuit_t, // The name of the element struct,
  57. hs_circuitmap_node, // The name of HT_ENTRY member
  58. hs_circuit_hash_token, hs_circuits_have_same_token)
  59. HT_GENERATE2(hs_circuitmap_ht, circuit_t, hs_circuitmap_node,
  60. hs_circuit_hash_token, hs_circuits_have_same_token,
  61. 0.6, tor_reallocarray, tor_free_)
  62. #ifdef TOR_UNIT_TESTS
  63. /* Return the global HS circuitmap. Used by unittests. */
  64. hs_circuitmap_ht *
  65. get_hs_circuitmap(void)
  66. {
  67. return the_hs_circuitmap;
  68. }
  69. #endif
  70. /****************** HS circuitmap utility functions **************************/
  71. /** Return a new HS token of type <b>type</b> containing <b>token</b>. */
  72. static hs_token_t *
  73. hs_token_new(hs_token_type_t type, size_t token_len,
  74. const uint8_t *token)
  75. {
  76. tor_assert(token);
  77. hs_token_t *hs_token = tor_malloc_zero(sizeof(hs_token_t));
  78. hs_token->type = type;
  79. hs_token->token_len = token_len;
  80. hs_token->token = tor_memdup(token, token_len);
  81. return hs_token;
  82. }
  83. /** Free memory allocated by this <b>hs_token</b>. */
  84. static void
  85. hs_token_free(hs_token_t *hs_token)
  86. {
  87. if (!hs_token) {
  88. return;
  89. }
  90. tor_free(hs_token->token);
  91. tor_free(hs_token);
  92. }
  93. /** Return the circuit from the circuitmap with token <b>search_token</b>. */
  94. static circuit_t *
  95. get_circuit_with_token(hs_token_t *search_token)
  96. {
  97. tor_assert(the_hs_circuitmap);
  98. /* We use a dummy circuit object for the hash table search routine. */
  99. circuit_t search_circ;
  100. search_circ.hs_token = search_token;
  101. return HT_FIND(hs_circuitmap_ht, the_hs_circuitmap, &search_circ);
  102. }
  103. /* Helper function that registers <b>circ</b> with <b>token</b> on the HS
  104. circuitmap. This function steals reference of <b>token</b>. */
  105. static void
  106. hs_circuitmap_register_impl(circuit_t *circ, hs_token_t *token)
  107. {
  108. tor_assert(circ);
  109. tor_assert(token);
  110. tor_assert(the_hs_circuitmap);
  111. /* If this circuit already has a token, clear it. */
  112. if (circ->hs_token) {
  113. hs_circuitmap_remove_circuit(circ);
  114. }
  115. /* Kill old circuits with the same token. We want new intro/rend circuits to
  116. take precedence over old ones, so that HSes and clients and reestablish
  117. killed circuits without changing the HS token. */
  118. {
  119. circuit_t *found_circ;
  120. found_circ = get_circuit_with_token(token);
  121. if (found_circ) {
  122. hs_circuitmap_remove_circuit(found_circ);
  123. if (!found_circ->marked_for_close) {
  124. circuit_mark_for_close(found_circ, END_CIRC_REASON_FINISHED);
  125. }
  126. }
  127. }
  128. /* Register circuit and token to circuitmap. */
  129. circ->hs_token = token;
  130. HT_INSERT(hs_circuitmap_ht, the_hs_circuitmap, circ);
  131. }
  132. /** Helper function: Register <b>circ</b> of <b>type</b> on the HS
  133. * circuitmap. Use the HS <b>token</b> as the key to the hash table. If
  134. * <b>token</b> is not set, clear the circuit of any HS tokens. */
  135. static void
  136. hs_circuitmap_register_circuit(circuit_t *circ,
  137. hs_token_type_t type, size_t token_len,
  138. const uint8_t *token)
  139. {
  140. hs_token_t *hs_token = NULL;
  141. /* Create a new token and register it to the circuitmap */
  142. tor_assert(token);
  143. hs_token = hs_token_new(type, token_len, token);
  144. tor_assert(hs_token);
  145. hs_circuitmap_register_impl(circ, hs_token);
  146. }
  147. /* Helper function for hs_circuitmap_get_origin_circuit() and
  148. * hs_circuitmap_get_or_circuit(). Because only circuit_t are indexed in the
  149. * circuitmap, this function returns object type so the specialized functions
  150. * using this helper can upcast it to the right type.
  151. *
  152. * Return NULL if not such circuit is found. */
  153. static circuit_t *
  154. hs_circuitmap_get_circuit_impl(hs_token_type_t type,
  155. size_t token_len,
  156. const uint8_t *token,
  157. uint8_t wanted_circ_purpose)
  158. {
  159. circuit_t *found_circ = NULL;
  160. tor_assert(the_hs_circuitmap);
  161. /* Check the circuitmap if we have a circuit with this token */
  162. {
  163. hs_token_t *search_hs_token = hs_token_new(type, token_len, token);
  164. tor_assert(search_hs_token);
  165. found_circ = get_circuit_with_token(search_hs_token);
  166. hs_token_free(search_hs_token);
  167. }
  168. /* Check that the circuit is useful to us */
  169. if (!found_circ ||
  170. found_circ->purpose != wanted_circ_purpose ||
  171. found_circ->marked_for_close) {
  172. return NULL;
  173. }
  174. return found_circ;
  175. }
  176. /* Helper function: Query circuitmap for origin circuit with <b>token</b> of
  177. * size <b>token_len</b> and <b>type</b>. Only returns a circuit with purpose
  178. * equal to the <b>wanted_circ_purpose</b> parameter and if it is NOT marked
  179. * for close. Return NULL if no such circuit is found. */
  180. static origin_circuit_t *
  181. hs_circuitmap_get_origin_circuit(hs_token_type_t type,
  182. size_t token_len,
  183. const uint8_t *token,
  184. uint8_t wanted_circ_purpose)
  185. {
  186. circuit_t *circ;
  187. tor_assert(token);
  188. tor_assert(CIRCUIT_PURPOSE_IS_ORIGIN(wanted_circ_purpose));
  189. circ = hs_circuitmap_get_circuit_impl(type, token_len, token,
  190. wanted_circ_purpose);
  191. if (!circ) {
  192. return NULL;
  193. }
  194. tor_assert(CIRCUIT_IS_ORIGIN(circ));
  195. return TO_ORIGIN_CIRCUIT(circ);
  196. }
  197. /* Helper function: Query circuitmap for OR circuit with <b>token</b> of size
  198. * <b>token_len</b> and <b>type</b>. Only returns a circuit with purpose equal
  199. * to the <b>wanted_circ_purpose</b> parameter and if it is NOT marked for
  200. * close. Return NULL if no such circuit is found. */
  201. static or_circuit_t *
  202. hs_circuitmap_get_or_circuit(hs_token_type_t type,
  203. size_t token_len,
  204. const uint8_t *token,
  205. uint8_t wanted_circ_purpose)
  206. {
  207. circuit_t *circ;
  208. tor_assert(token);
  209. tor_assert(!CIRCUIT_PURPOSE_IS_ORIGIN(wanted_circ_purpose));
  210. circ = hs_circuitmap_get_circuit_impl(type, token_len, token,
  211. wanted_circ_purpose);
  212. if (!circ) {
  213. return NULL;
  214. }
  215. tor_assert(CIRCUIT_IS_ORCIRC(circ));
  216. return TO_OR_CIRCUIT(circ);
  217. }
  218. /************** Public circuitmap API ****************************************/
  219. /**** Public relay-side getters: */
  220. /* Public function: Return a v3 introduction circuit to this relay with
  221. * <b>auth_key</b>. Return NULL if no such circuit is found in the
  222. * circuitmap. */
  223. or_circuit_t *
  224. hs_circuitmap_get_intro_circ_v3_relay_side(
  225. const ed25519_public_key_t *auth_key)
  226. {
  227. return hs_circuitmap_get_or_circuit(HS_TOKEN_INTRO_V3_RELAY_SIDE,
  228. ED25519_PUBKEY_LEN, auth_key->pubkey,
  229. CIRCUIT_PURPOSE_INTRO_POINT);
  230. }
  231. /* Public function: Return v2 introduction circuit to this relay with
  232. * <b>digest</b>. Return NULL if no such circuit is found in the circuitmap. */
  233. or_circuit_t *
  234. hs_circuitmap_get_intro_circ_v2_relay_side(const uint8_t *digest)
  235. {
  236. return hs_circuitmap_get_or_circuit(HS_TOKEN_INTRO_V2_RELAY_SIDE,
  237. REND_TOKEN_LEN, digest,
  238. CIRCUIT_PURPOSE_INTRO_POINT);
  239. }
  240. /* Public function: Return rendezvous circuit to this relay with rendezvous
  241. * <b>cookie</b>. Return NULL if no such circuit is found in the circuitmap. */
  242. or_circuit_t *
  243. hs_circuitmap_get_rend_circ_relay_side(const uint8_t *cookie)
  244. {
  245. return hs_circuitmap_get_or_circuit(HS_TOKEN_REND_RELAY_SIDE,
  246. REND_TOKEN_LEN, cookie,
  247. CIRCUIT_PURPOSE_REND_POINT_WAITING);
  248. }
  249. /** Public relay-side setters: */
  250. /* Public function: Register rendezvous circuit with key <b>cookie</b> to the
  251. * circuitmap. */
  252. void
  253. hs_circuitmap_register_rend_circ_relay_side(or_circuit_t *circ,
  254. const uint8_t *cookie)
  255. {
  256. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  257. HS_TOKEN_REND_RELAY_SIDE,
  258. REND_TOKEN_LEN, cookie);
  259. }
  260. /* Public function: Register v2 intro circuit with key <b>digest</b> to the
  261. * circuitmap. */
  262. void
  263. hs_circuitmap_register_intro_circ_v2_relay_side(or_circuit_t *circ,
  264. const uint8_t *digest)
  265. {
  266. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  267. HS_TOKEN_INTRO_V2_RELAY_SIDE,
  268. REND_TOKEN_LEN, digest);
  269. }
  270. /* Public function: Register v3 intro circuit with key <b>auth_key</b> to the
  271. * circuitmap. */
  272. void
  273. hs_circuitmap_register_intro_circ_v3_relay_side(or_circuit_t *circ,
  274. const ed25519_public_key_t *auth_key)
  275. {
  276. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  277. HS_TOKEN_INTRO_V3_RELAY_SIDE,
  278. ED25519_PUBKEY_LEN, auth_key->pubkey);
  279. }
  280. /**** Public servide-side getters: */
  281. /* Public function: Return v3 introduction circuit with <b>auth_key</b>
  282. * originating from this hidden service. Return NULL if no such circuit is
  283. * found in the circuitmap. */
  284. origin_circuit_t *
  285. hs_circuitmap_get_intro_circ_v3_service_side(const
  286. ed25519_public_key_t *auth_key)
  287. {
  288. origin_circuit_t *circ = NULL;
  289. /* Check first for established intro circuits */
  290. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V3_SERVICE_SIDE,
  291. ED25519_PUBKEY_LEN, auth_key->pubkey,
  292. CIRCUIT_PURPOSE_S_INTRO);
  293. if (circ) {
  294. return circ;
  295. }
  296. /* ...if nothing found, check for pending intro circs */
  297. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V3_SERVICE_SIDE,
  298. ED25519_PUBKEY_LEN, auth_key->pubkey,
  299. CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
  300. return circ;
  301. }
  302. /* Public function: Return v2 introduction circuit originating from this hidden
  303. * service with <b>digest</b>. Return NULL if no such circuit is found in the
  304. * circuitmap. */
  305. origin_circuit_t *
  306. hs_circuitmap_get_intro_circ_v2_service_side(const uint8_t *digest)
  307. {
  308. origin_circuit_t *circ = NULL;
  309. /* Check first for established intro circuits */
  310. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V2_SERVICE_SIDE,
  311. REND_TOKEN_LEN, digest,
  312. CIRCUIT_PURPOSE_S_INTRO);
  313. if (circ) {
  314. return circ;
  315. }
  316. /* ...if nothing found, check for pending intro circs */
  317. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_INTRO_V2_SERVICE_SIDE,
  318. REND_TOKEN_LEN, digest,
  319. CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
  320. return circ;
  321. }
  322. /* Public function: Return rendezvous circuit originating from this hidden
  323. * service with rendezvous <b>cookie</b>. Return NULL if no such circuit is
  324. * found in the circuitmap. */
  325. origin_circuit_t *
  326. hs_circuitmap_get_rend_circ_service_side(const uint8_t *cookie)
  327. {
  328. origin_circuit_t *circ = NULL;
  329. /* Try to check if we have a connecting circuit. */
  330. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_REND_SERVICE_SIDE,
  331. REND_TOKEN_LEN, cookie,
  332. CIRCUIT_PURPOSE_S_CONNECT_REND);
  333. if (circ) {
  334. return circ;
  335. }
  336. /* Then try for connected circuit. */
  337. circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_REND_SERVICE_SIDE,
  338. REND_TOKEN_LEN, cookie,
  339. CIRCUIT_PURPOSE_S_REND_JOINED);
  340. return circ;
  341. }
  342. /**** Public servide-side setters: */
  343. /* Public function: Register v2 intro circuit with key <b>digest</b> to the
  344. * circuitmap. */
  345. void
  346. hs_circuitmap_register_intro_circ_v2_service_side(origin_circuit_t *circ,
  347. const uint8_t *digest)
  348. {
  349. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  350. HS_TOKEN_INTRO_V2_SERVICE_SIDE,
  351. REND_TOKEN_LEN, digest);
  352. }
  353. /* Public function: Register v3 intro circuit with key <b>auth_key</b> to the
  354. * circuitmap. */
  355. void
  356. hs_circuitmap_register_intro_circ_v3_service_side(origin_circuit_t *circ,
  357. const ed25519_public_key_t *auth_key)
  358. {
  359. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  360. HS_TOKEN_INTRO_V3_SERVICE_SIDE,
  361. ED25519_PUBKEY_LEN, auth_key->pubkey);
  362. }
  363. /* Public function: Register rendezvous circuit with key <b>cookie</b> to the
  364. * circuitmap. */
  365. void
  366. hs_circuitmap_register_rend_circ_service_side(origin_circuit_t *circ,
  367. const uint8_t *cookie)
  368. {
  369. hs_circuitmap_register_circuit(TO_CIRCUIT(circ),
  370. HS_TOKEN_REND_SERVICE_SIDE,
  371. REND_TOKEN_LEN, cookie);
  372. }
  373. /**** Misc public functions: */
  374. /** Public function: Remove this circuit from the HS circuitmap. Clear its HS
  375. * token, and remove it from the hashtable. */
  376. void
  377. hs_circuitmap_remove_circuit(circuit_t *circ)
  378. {
  379. tor_assert(the_hs_circuitmap);
  380. if (!circ || !circ->hs_token) {
  381. return;
  382. }
  383. /* Remove circ from circuitmap */
  384. circuit_t *tmp;
  385. tmp = HT_REMOVE(hs_circuitmap_ht, the_hs_circuitmap, circ);
  386. /* ... and ensure the removal was successful. */
  387. if (tmp) {
  388. tor_assert(tmp == circ);
  389. } else {
  390. log_warn(LD_BUG, "Could not find circuit (%u) in circuitmap.",
  391. circ->n_circ_id);
  392. }
  393. /* Clear token from circ */
  394. hs_token_free(circ->hs_token);
  395. circ->hs_token = NULL;
  396. }
  397. /* Public function: Initialize the global HS circuitmap. */
  398. void
  399. hs_circuitmap_init(void)
  400. {
  401. tor_assert(!the_hs_circuitmap);
  402. the_hs_circuitmap = tor_malloc_zero(sizeof(struct hs_circuitmap_ht));
  403. HT_INIT(hs_circuitmap_ht, the_hs_circuitmap);
  404. }
  405. /* Public function: Free all memory allocated by the global HS circuitmap. */
  406. void
  407. hs_circuitmap_free_all(void)
  408. {
  409. if (the_hs_circuitmap) {
  410. HT_CLEAR(hs_circuitmap_ht, the_hs_circuitmap);
  411. tor_free(the_hs_circuitmap);
  412. }
  413. }