hs_cache.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986
  1. /* Copyright (c) 2016-2018, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file hs_cache.c
  5. * \brief Handle hidden service descriptor caches.
  6. **/
  7. /* For unit tests.*/
  8. #define HS_CACHE_PRIVATE
  9. #include "core/or/or.h"
  10. #include "app/config/config.h"
  11. #include "lib/crypt_ops/crypto_format.h"
  12. #include "lib/crypt_ops/crypto_util.h"
  13. #include "feature/hs/hs_ident.h"
  14. #include "feature/hs/hs_common.h"
  15. #include "feature/hs/hs_client.h"
  16. #include "feature/hs/hs_descriptor.h"
  17. #include "feature/nodelist/networkstatus.h"
  18. #include "feature/rend/rendcache.h"
  19. #include "feature/hs/hs_cache.h"
  20. #include "feature/nodelist/networkstatus_st.h"
  21. static int cached_client_descriptor_has_expired(time_t now,
  22. const hs_cache_client_descriptor_t *cached_desc);
  23. /********************** Directory HS cache ******************/
  24. /* Directory descriptor cache. Map indexed by blinded key. */
  25. static digest256map_t *hs_cache_v3_dir;
  26. /* Remove a given descriptor from our cache. */
  27. static void
  28. remove_v3_desc_as_dir(const hs_cache_dir_descriptor_t *desc)
  29. {
  30. tor_assert(desc);
  31. digest256map_remove(hs_cache_v3_dir, desc->key);
  32. }
  33. /* Store a given descriptor in our cache. */
  34. static void
  35. store_v3_desc_as_dir(hs_cache_dir_descriptor_t *desc)
  36. {
  37. tor_assert(desc);
  38. digest256map_set(hs_cache_v3_dir, desc->key, desc);
  39. }
  40. /* Query our cache and return the entry or NULL if not found. */
  41. static hs_cache_dir_descriptor_t *
  42. lookup_v3_desc_as_dir(const uint8_t *key)
  43. {
  44. tor_assert(key);
  45. return digest256map_get(hs_cache_v3_dir, key);
  46. }
  47. #define cache_dir_desc_free(val) \
  48. FREE_AND_NULL(hs_cache_dir_descriptor_t, cache_dir_desc_free_, (val))
  49. /* Free a directory descriptor object. */
  50. static void
  51. cache_dir_desc_free_(hs_cache_dir_descriptor_t *desc)
  52. {
  53. if (desc == NULL) {
  54. return;
  55. }
  56. hs_desc_plaintext_data_free(desc->plaintext_data);
  57. tor_free(desc->encoded_desc);
  58. tor_free(desc);
  59. }
  60. /* Helper function: Use by the free all function using the digest256map
  61. * interface to cache entries. */
  62. static void
  63. cache_dir_desc_free_void(void *ptr)
  64. {
  65. cache_dir_desc_free_(ptr);
  66. }
  67. /* Create a new directory cache descriptor object from a encoded descriptor.
  68. * On success, return the heap-allocated cache object, otherwise return NULL if
  69. * we can't decode the descriptor. */
  70. static hs_cache_dir_descriptor_t *
  71. cache_dir_desc_new(const char *desc)
  72. {
  73. hs_cache_dir_descriptor_t *dir_desc;
  74. tor_assert(desc);
  75. dir_desc = tor_malloc_zero(sizeof(hs_cache_dir_descriptor_t));
  76. dir_desc->plaintext_data =
  77. tor_malloc_zero(sizeof(hs_desc_plaintext_data_t));
  78. dir_desc->encoded_desc = tor_strdup(desc);
  79. if (hs_desc_decode_plaintext(desc, dir_desc->plaintext_data) < 0) {
  80. log_debug(LD_DIR, "Unable to decode descriptor. Rejecting.");
  81. goto err;
  82. }
  83. /* The blinded pubkey is the indexed key. */
  84. dir_desc->key = dir_desc->plaintext_data->blinded_pubkey.pubkey;
  85. dir_desc->created_ts = time(NULL);
  86. return dir_desc;
  87. err:
  88. cache_dir_desc_free(dir_desc);
  89. return NULL;
  90. }
  91. /* Return the size of a cache entry in bytes. */
  92. static size_t
  93. cache_get_dir_entry_size(const hs_cache_dir_descriptor_t *entry)
  94. {
  95. return (sizeof(*entry) + hs_desc_plaintext_obj_size(entry->plaintext_data)
  96. + strlen(entry->encoded_desc));
  97. }
  98. /* Try to store a valid version 3 descriptor in the directory cache. Return 0
  99. * on success else a negative value is returned indicating that we have a
  100. * newer version in our cache. On error, caller is responsible to free the
  101. * given descriptor desc. */
  102. static int
  103. cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc)
  104. {
  105. hs_cache_dir_descriptor_t *cache_entry;
  106. tor_assert(desc);
  107. /* Verify if we have an entry in the cache for that key and if yes, check
  108. * if we should replace it? */
  109. cache_entry = lookup_v3_desc_as_dir(desc->key);
  110. if (cache_entry != NULL) {
  111. /* Only replace descriptor if revision-counter is greater than the one
  112. * in our cache */
  113. if (cache_entry->plaintext_data->revision_counter >=
  114. desc->plaintext_data->revision_counter) {
  115. log_info(LD_REND, "Descriptor revision counter in our cache is "
  116. "greater or equal than the one we received (%d/%d). "
  117. "Rejecting!",
  118. (int)cache_entry->plaintext_data->revision_counter,
  119. (int)desc->plaintext_data->revision_counter);
  120. goto err;
  121. }
  122. /* We now know that the descriptor we just received is a new one so
  123. * remove the entry we currently have from our cache so we can then
  124. * store the new one. */
  125. remove_v3_desc_as_dir(cache_entry);
  126. rend_cache_decrement_allocation(cache_get_dir_entry_size(cache_entry));
  127. cache_dir_desc_free(cache_entry);
  128. }
  129. /* Store the descriptor we just got. We are sure here that either we
  130. * don't have the entry or we have a newer descriptor and the old one
  131. * has been removed from the cache. */
  132. store_v3_desc_as_dir(desc);
  133. /* Update our total cache size with this entry for the OOM. This uses the
  134. * old HS protocol cache subsystem for which we are tied with. */
  135. rend_cache_increment_allocation(cache_get_dir_entry_size(desc));
  136. /* XXX: Update HS statistics. We should have specific stats for v3. */
  137. return 0;
  138. err:
  139. return -1;
  140. }
  141. /* Using the query which is the base64 encoded blinded key of a version 3
  142. * descriptor, lookup in our directory cache the entry. If found, 1 is
  143. * returned and desc_out is populated with a newly allocated string being the
  144. * encoded descriptor. If not found, 0 is returned and desc_out is untouched.
  145. * On error, a negative value is returned and desc_out is untouched. */
  146. static int
  147. cache_lookup_v3_as_dir(const char *query, const char **desc_out)
  148. {
  149. int found = 0;
  150. ed25519_public_key_t blinded_key;
  151. const hs_cache_dir_descriptor_t *entry;
  152. tor_assert(query);
  153. /* Decode blinded key using the given query value. */
  154. if (ed25519_public_from_base64(&blinded_key, query) < 0) {
  155. log_info(LD_REND, "Unable to decode the v3 HSDir query %s.",
  156. safe_str_client(query));
  157. goto err;
  158. }
  159. entry = lookup_v3_desc_as_dir(blinded_key.pubkey);
  160. if (entry != NULL) {
  161. found = 1;
  162. if (desc_out) {
  163. *desc_out = entry->encoded_desc;
  164. }
  165. }
  166. return found;
  167. err:
  168. return -1;
  169. }
  170. /* Clean the v3 cache by removing any entry that has expired using the
  171. * <b>global_cutoff</b> value. If <b>global_cutoff</b> is 0, the cleaning
  172. * process will use the lifetime found in the plaintext data section. Return
  173. * the number of bytes cleaned. */
  174. STATIC size_t
  175. cache_clean_v3_as_dir(time_t now, time_t global_cutoff)
  176. {
  177. size_t bytes_removed = 0;
  178. /* Code flow error if this ever happens. */
  179. tor_assert(global_cutoff >= 0);
  180. if (!hs_cache_v3_dir) { /* No cache to clean. Just return. */
  181. return 0;
  182. }
  183. DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_dir, key,
  184. hs_cache_dir_descriptor_t *, entry) {
  185. size_t entry_size;
  186. time_t cutoff = global_cutoff;
  187. if (!cutoff) {
  188. /* Cutoff is the lifetime of the entry found in the descriptor. */
  189. cutoff = now - entry->plaintext_data->lifetime_sec;
  190. }
  191. /* If the entry has been created _after_ the cutoff, not expired so
  192. * continue to the next entry in our v3 cache. */
  193. if (entry->created_ts > cutoff) {
  194. continue;
  195. }
  196. /* Here, our entry has expired, remove and free. */
  197. MAP_DEL_CURRENT(key);
  198. entry_size = cache_get_dir_entry_size(entry);
  199. bytes_removed += entry_size;
  200. /* Entry is not in the cache anymore, destroy it. */
  201. cache_dir_desc_free(entry);
  202. /* Update our cache entry allocation size for the OOM. */
  203. rend_cache_decrement_allocation(entry_size);
  204. /* Logging. */
  205. {
  206. char key_b64[BASE64_DIGEST256_LEN + 1];
  207. digest256_to_base64(key_b64, (const char *) key);
  208. log_info(LD_REND, "Removing v3 descriptor '%s' from HSDir cache",
  209. safe_str_client(key_b64));
  210. }
  211. } DIGEST256MAP_FOREACH_END;
  212. return bytes_removed;
  213. }
  214. /* Given an encoded descriptor, store it in the directory cache depending on
  215. * which version it is. Return a negative value on error. On success, 0 is
  216. * returned. */
  217. int
  218. hs_cache_store_as_dir(const char *desc)
  219. {
  220. hs_cache_dir_descriptor_t *dir_desc = NULL;
  221. tor_assert(desc);
  222. /* Create a new cache object. This can fail if the descriptor plaintext data
  223. * is unparseable which in this case a log message will be triggered. */
  224. dir_desc = cache_dir_desc_new(desc);
  225. if (dir_desc == NULL) {
  226. goto err;
  227. }
  228. /* Call the right function against the descriptor version. At this point,
  229. * we are sure that the descriptor's version is supported else the
  230. * decoding would have failed. */
  231. switch (dir_desc->plaintext_data->version) {
  232. case HS_VERSION_THREE:
  233. default:
  234. if (cache_store_v3_as_dir(dir_desc) < 0) {
  235. goto err;
  236. }
  237. break;
  238. }
  239. return 0;
  240. err:
  241. cache_dir_desc_free(dir_desc);
  242. return -1;
  243. }
  244. /* Using the query, lookup in our directory cache the entry. If found, 1 is
  245. * returned and desc_out is populated with a newly allocated string being
  246. * the encoded descriptor. If not found, 0 is returned and desc_out is
  247. * untouched. On error, a negative value is returned and desc_out is
  248. * untouched. */
  249. int
  250. hs_cache_lookup_as_dir(uint32_t version, const char *query,
  251. const char **desc_out)
  252. {
  253. int found;
  254. tor_assert(query);
  255. /* This should never be called with an unsupported version. */
  256. tor_assert(hs_desc_is_supported_version(version));
  257. switch (version) {
  258. case HS_VERSION_THREE:
  259. default:
  260. found = cache_lookup_v3_as_dir(query, desc_out);
  261. break;
  262. }
  263. return found;
  264. }
  265. /* Clean all directory caches using the current time now. */
  266. void
  267. hs_cache_clean_as_dir(time_t now)
  268. {
  269. time_t cutoff;
  270. /* Start with v2 cache cleaning. */
  271. cutoff = now - rend_cache_max_entry_lifetime();
  272. rend_cache_clean_v2_descs_as_dir(cutoff);
  273. /* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function
  274. * to compute the cutoff by itself using the lifetime value. */
  275. cache_clean_v3_as_dir(now, 0);
  276. }
  277. /********************** Client-side HS cache ******************/
  278. /* Client-side HS descriptor cache. Map indexed by service identity key. */
  279. static digest256map_t *hs_cache_v3_client;
  280. /* Client-side introduction point state cache. Map indexed by service public
  281. * identity key (onion address). It contains hs_cache_client_intro_state_t
  282. * objects all related to a specific service. */
  283. static digest256map_t *hs_cache_client_intro_state;
  284. /* Return the size of a client cache entry in bytes. */
  285. static size_t
  286. cache_get_client_entry_size(const hs_cache_client_descriptor_t *entry)
  287. {
  288. return sizeof(*entry) +
  289. strlen(entry->encoded_desc) + hs_desc_obj_size(entry->desc);
  290. }
  291. /* Remove a given descriptor from our cache. */
  292. static void
  293. remove_v3_desc_as_client(const hs_cache_client_descriptor_t *desc)
  294. {
  295. tor_assert(desc);
  296. digest256map_remove(hs_cache_v3_client, desc->key.pubkey);
  297. /* Update cache size with this entry for the OOM handler. */
  298. rend_cache_decrement_allocation(cache_get_client_entry_size(desc));
  299. }
  300. /* Store a given descriptor in our cache. */
  301. static void
  302. store_v3_desc_as_client(hs_cache_client_descriptor_t *desc)
  303. {
  304. tor_assert(desc);
  305. digest256map_set(hs_cache_v3_client, desc->key.pubkey, desc);
  306. /* Update cache size with this entry for the OOM handler. */
  307. rend_cache_increment_allocation(cache_get_client_entry_size(desc));
  308. }
  309. /* Query our cache and return the entry or NULL if not found or if expired. */
  310. STATIC hs_cache_client_descriptor_t *
  311. lookup_v3_desc_as_client(const uint8_t *key)
  312. {
  313. time_t now = approx_time();
  314. hs_cache_client_descriptor_t *cached_desc;
  315. tor_assert(key);
  316. /* Do the lookup */
  317. cached_desc = digest256map_get(hs_cache_v3_client, key);
  318. if (!cached_desc) {
  319. return NULL;
  320. }
  321. /* Don't return expired entries */
  322. if (cached_client_descriptor_has_expired(now, cached_desc)) {
  323. return NULL;
  324. }
  325. return cached_desc;
  326. }
  327. /* Parse the encoded descriptor in <b>desc_str</b> using
  328. * <b>service_identity_pk<b> to decrypt it first.
  329. *
  330. * If everything goes well, allocate and return a new
  331. * hs_cache_client_descriptor_t object. In case of error, return NULL. */
  332. static hs_cache_client_descriptor_t *
  333. cache_client_desc_new(const char *desc_str,
  334. const ed25519_public_key_t *service_identity_pk)
  335. {
  336. hs_descriptor_t *desc = NULL;
  337. hs_cache_client_descriptor_t *client_desc = NULL;
  338. tor_assert(desc_str);
  339. tor_assert(service_identity_pk);
  340. /* Decode the descriptor we just fetched. */
  341. if (hs_client_decode_descriptor(desc_str, service_identity_pk, &desc) < 0) {
  342. goto end;
  343. }
  344. tor_assert(desc);
  345. /* All is good: make a cache object for this descriptor */
  346. client_desc = tor_malloc_zero(sizeof(hs_cache_client_descriptor_t));
  347. ed25519_pubkey_copy(&client_desc->key, service_identity_pk);
  348. /* Set expiration time for this cached descriptor to be the start of the next
  349. * time period since that's when clients need to start using the next blinded
  350. * pk of the service (and hence will need its next descriptor). */
  351. client_desc->expiration_ts = hs_get_start_time_of_next_time_period(0);
  352. client_desc->desc = desc;
  353. client_desc->encoded_desc = tor_strdup(desc_str);
  354. end:
  355. return client_desc;
  356. }
  357. #define cache_client_desc_free(val) \
  358. FREE_AND_NULL(hs_cache_client_descriptor_t, cache_client_desc_free_, (val))
  359. /** Free memory allocated by <b>desc</b>. */
  360. static void
  361. cache_client_desc_free_(hs_cache_client_descriptor_t *desc)
  362. {
  363. if (desc == NULL) {
  364. return;
  365. }
  366. hs_descriptor_free(desc->desc);
  367. memwipe(&desc->key, 0, sizeof(desc->key));
  368. memwipe(desc->encoded_desc, 0, strlen(desc->encoded_desc));
  369. tor_free(desc->encoded_desc);
  370. tor_free(desc);
  371. }
  372. /** Helper function: Use by the free all function to clear the client cache */
  373. static void
  374. cache_client_desc_free_void(void *ptr)
  375. {
  376. hs_cache_client_descriptor_t *desc = ptr;
  377. cache_client_desc_free(desc);
  378. }
  379. /* Return a newly allocated and initialized hs_cache_intro_state_t object. */
  380. static hs_cache_intro_state_t *
  381. cache_intro_state_new(void)
  382. {
  383. hs_cache_intro_state_t *state = tor_malloc_zero(sizeof(*state));
  384. state->created_ts = approx_time();
  385. return state;
  386. }
  387. #define cache_intro_state_free(val) \
  388. FREE_AND_NULL(hs_cache_intro_state_t, cache_intro_state_free_, (val))
  389. /* Free an hs_cache_intro_state_t object. */
  390. static void
  391. cache_intro_state_free_(hs_cache_intro_state_t *state)
  392. {
  393. tor_free(state);
  394. }
  395. /* Helper function: used by the free all function. */
  396. static void
  397. cache_intro_state_free_void(void *state)
  398. {
  399. cache_intro_state_free_(state);
  400. }
  401. /* Return a newly allocated and initialized hs_cache_client_intro_state_t
  402. * object. */
  403. static hs_cache_client_intro_state_t *
  404. cache_client_intro_state_new(void)
  405. {
  406. hs_cache_client_intro_state_t *cache = tor_malloc_zero(sizeof(*cache));
  407. cache->intro_points = digest256map_new();
  408. return cache;
  409. }
  410. #define cache_client_intro_state_free(val) \
  411. FREE_AND_NULL(hs_cache_client_intro_state_t, \
  412. cache_client_intro_state_free_, (val))
  413. /* Free a cache_client_intro_state object. */
  414. static void
  415. cache_client_intro_state_free_(hs_cache_client_intro_state_t *cache)
  416. {
  417. if (cache == NULL) {
  418. return;
  419. }
  420. digest256map_free(cache->intro_points, cache_intro_state_free_void);
  421. tor_free(cache);
  422. }
  423. /* Helper function: used by the free all function. */
  424. static void
  425. cache_client_intro_state_free_void(void *entry)
  426. {
  427. cache_client_intro_state_free_(entry);
  428. }
  429. /* For the given service identity key service_pk and an introduction
  430. * authentication key auth_key, lookup the intro state object. Return 1 if
  431. * found and put it in entry if not NULL. Return 0 if not found and entry is
  432. * untouched. */
  433. static int
  434. cache_client_intro_state_lookup(const ed25519_public_key_t *service_pk,
  435. const ed25519_public_key_t *auth_key,
  436. hs_cache_intro_state_t **entry)
  437. {
  438. hs_cache_intro_state_t *state;
  439. hs_cache_client_intro_state_t *cache;
  440. tor_assert(service_pk);
  441. tor_assert(auth_key);
  442. /* Lookup the intro state cache for this service key. */
  443. cache = digest256map_get(hs_cache_client_intro_state, service_pk->pubkey);
  444. if (cache == NULL) {
  445. goto not_found;
  446. }
  447. /* From the cache we just found for the service, lookup in the introduction
  448. * points map for the given authentication key. */
  449. state = digest256map_get(cache->intro_points, auth_key->pubkey);
  450. if (state == NULL) {
  451. goto not_found;
  452. }
  453. if (entry) {
  454. *entry = state;
  455. }
  456. return 1;
  457. not_found:
  458. return 0;
  459. }
  460. /* Note the given failure in state. */
  461. static void
  462. cache_client_intro_state_note(hs_cache_intro_state_t *state,
  463. rend_intro_point_failure_t failure)
  464. {
  465. tor_assert(state);
  466. switch (failure) {
  467. case INTRO_POINT_FAILURE_GENERIC:
  468. state->error = 1;
  469. break;
  470. case INTRO_POINT_FAILURE_TIMEOUT:
  471. state->timed_out = 1;
  472. break;
  473. case INTRO_POINT_FAILURE_UNREACHABLE:
  474. state->unreachable_count++;
  475. break;
  476. default:
  477. tor_assert_nonfatal_unreached();
  478. return;
  479. }
  480. }
  481. /* For the given service identity key service_pk and an introduction
  482. * authentication key auth_key, add an entry in the client intro state cache
  483. * If no entry exists for the service, it will create one. If state is non
  484. * NULL, it will point to the new intro state entry. */
  485. static void
  486. cache_client_intro_state_add(const ed25519_public_key_t *service_pk,
  487. const ed25519_public_key_t *auth_key,
  488. hs_cache_intro_state_t **state)
  489. {
  490. hs_cache_intro_state_t *entry, *old_entry;
  491. hs_cache_client_intro_state_t *cache;
  492. tor_assert(service_pk);
  493. tor_assert(auth_key);
  494. /* Lookup the state cache for this service key. */
  495. cache = digest256map_get(hs_cache_client_intro_state, service_pk->pubkey);
  496. if (cache == NULL) {
  497. cache = cache_client_intro_state_new();
  498. digest256map_set(hs_cache_client_intro_state, service_pk->pubkey, cache);
  499. }
  500. entry = cache_intro_state_new();
  501. old_entry = digest256map_set(cache->intro_points, auth_key->pubkey, entry);
  502. /* This should never happened because the code flow is to lookup the entry
  503. * before adding it. But, just in case, non fatal assert and free it. */
  504. tor_assert_nonfatal(old_entry == NULL);
  505. tor_free(old_entry);
  506. if (state) {
  507. *state = entry;
  508. }
  509. }
  510. /* Remove every intro point state entry from cache that has been created
  511. * before or at the cutoff. */
  512. static void
  513. cache_client_intro_state_clean(time_t cutoff,
  514. hs_cache_client_intro_state_t *cache)
  515. {
  516. tor_assert(cache);
  517. DIGEST256MAP_FOREACH_MODIFY(cache->intro_points, key,
  518. hs_cache_intro_state_t *, entry) {
  519. if (entry->created_ts <= cutoff) {
  520. cache_intro_state_free(entry);
  521. MAP_DEL_CURRENT(key);
  522. }
  523. } DIGEST256MAP_FOREACH_END;
  524. }
  525. /* Return true iff no intro points are in this cache. */
  526. static int
  527. cache_client_intro_state_is_empty(const hs_cache_client_intro_state_t *cache)
  528. {
  529. return digest256map_isempty(cache->intro_points);
  530. }
  531. /** Check whether <b>client_desc</b> is useful for us, and store it in the
  532. * client-side HS cache if so. The client_desc is freed if we already have a
  533. * fresher (higher revision counter count) in the cache. */
  534. static int
  535. cache_store_as_client(hs_cache_client_descriptor_t *client_desc)
  536. {
  537. hs_cache_client_descriptor_t *cache_entry;
  538. /* TODO: Heavy code duplication with cache_store_as_dir(). Consider
  539. * refactoring and uniting! */
  540. tor_assert(client_desc);
  541. /* Check if we already have a descriptor from this HS in cache. If we do,
  542. * check if this descriptor is newer than the cached one */
  543. cache_entry = lookup_v3_desc_as_client(client_desc->key.pubkey);
  544. if (cache_entry != NULL) {
  545. /* If we have an entry in our cache that has a revision counter greater
  546. * than the one we just fetched, discard the one we fetched. */
  547. if (cache_entry->desc->plaintext_data.revision_counter >
  548. client_desc->desc->plaintext_data.revision_counter) {
  549. cache_client_desc_free(client_desc);
  550. goto done;
  551. }
  552. /* Remove old entry. Make space for the new one! */
  553. remove_v3_desc_as_client(cache_entry);
  554. /* We just removed an old descriptor and will replace it. We'll close all
  555. * intro circuits related to this old one so we don't have leftovers. We
  556. * leave the rendezvous circuits opened because they could be in use. */
  557. hs_client_close_intro_circuits_from_desc(cache_entry->desc);
  558. /* Free it. */
  559. cache_client_desc_free(cache_entry);
  560. }
  561. /* Store descriptor in cache */
  562. store_v3_desc_as_client(client_desc);
  563. done:
  564. return 0;
  565. }
  566. /* Return true iff the cached client descriptor at <b>cached_desc</b has
  567. * expired. */
  568. static int
  569. cached_client_descriptor_has_expired(time_t now,
  570. const hs_cache_client_descriptor_t *cached_desc)
  571. {
  572. /* We use the current consensus time to see if we should expire this
  573. * descriptor since we use consensus time for all other parts of the protocol
  574. * as well (e.g. to build the blinded key and compute time periods). */
  575. const networkstatus_t *ns = networkstatus_get_live_consensus(now);
  576. /* If we don't have a recent consensus, consider this entry expired since we
  577. * will want to fetch a new HS desc when we get a live consensus. */
  578. if (!ns) {
  579. return 1;
  580. }
  581. if (cached_desc->expiration_ts <= ns->valid_after) {
  582. return 1;
  583. }
  584. return 0;
  585. }
  586. /* clean the client cache using now as the current time. Return the total size
  587. * of removed bytes from the cache. */
  588. static size_t
  589. cache_clean_v3_as_client(time_t now)
  590. {
  591. size_t bytes_removed = 0;
  592. if (!hs_cache_v3_client) { /* No cache to clean. Just return. */
  593. return 0;
  594. }
  595. DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_client, key,
  596. hs_cache_client_descriptor_t *, entry) {
  597. size_t entry_size;
  598. /* If the entry has not expired, continue to the next cached entry */
  599. if (!cached_client_descriptor_has_expired(now, entry)) {
  600. continue;
  601. }
  602. /* Here, our entry has expired, remove and free. */
  603. MAP_DEL_CURRENT(key);
  604. entry_size = cache_get_client_entry_size(entry);
  605. bytes_removed += entry_size;
  606. /* Entry is not in the cache anymore, destroy it. */
  607. cache_client_desc_free(entry);
  608. /* Update our OOM. We didn't use the remove() function because we are in
  609. * a loop so we have to explicitly decrement. */
  610. rend_cache_decrement_allocation(entry_size);
  611. /* Logging. */
  612. {
  613. char key_b64[BASE64_DIGEST256_LEN + 1];
  614. digest256_to_base64(key_b64, (const char *) key);
  615. log_info(LD_REND, "Removing hidden service v3 descriptor '%s' "
  616. "from client cache",
  617. safe_str_client(key_b64));
  618. }
  619. } DIGEST256MAP_FOREACH_END;
  620. return bytes_removed;
  621. }
  622. /** Public API: Given the HS ed25519 identity public key in <b>key</b>, return
  623. * its HS encoded descriptor if it's stored in our cache, or NULL if not. */
  624. const char *
  625. hs_cache_lookup_encoded_as_client(const ed25519_public_key_t *key)
  626. {
  627. hs_cache_client_descriptor_t *cached_desc = NULL;
  628. tor_assert(key);
  629. cached_desc = lookup_v3_desc_as_client(key->pubkey);
  630. if (cached_desc) {
  631. tor_assert(cached_desc->encoded_desc);
  632. return cached_desc->encoded_desc;
  633. }
  634. return NULL;
  635. }
  636. /** Public API: Given the HS ed25519 identity public key in <b>key</b>, return
  637. * its HS descriptor if it's stored in our cache, or NULL if not. */
  638. const hs_descriptor_t *
  639. hs_cache_lookup_as_client(const ed25519_public_key_t *key)
  640. {
  641. hs_cache_client_descriptor_t *cached_desc = NULL;
  642. tor_assert(key);
  643. cached_desc = lookup_v3_desc_as_client(key->pubkey);
  644. if (cached_desc) {
  645. tor_assert(cached_desc->desc);
  646. return cached_desc->desc;
  647. }
  648. return NULL;
  649. }
  650. /** Public API: Given an encoded descriptor, store it in the client HS
  651. * cache. Return -1 on error, 0 on success .*/
  652. int
  653. hs_cache_store_as_client(const char *desc_str,
  654. const ed25519_public_key_t *identity_pk)
  655. {
  656. hs_cache_client_descriptor_t *client_desc = NULL;
  657. tor_assert(desc_str);
  658. tor_assert(identity_pk);
  659. /* Create client cache descriptor object */
  660. client_desc = cache_client_desc_new(desc_str, identity_pk);
  661. if (!client_desc) {
  662. log_warn(LD_GENERAL, "Failed to parse received descriptor %s.",
  663. escaped(desc_str));
  664. goto err;
  665. }
  666. /* Push it to the cache */
  667. if (cache_store_as_client(client_desc) < 0) {
  668. goto err;
  669. }
  670. return 0;
  671. err:
  672. cache_client_desc_free(client_desc);
  673. return -1;
  674. }
  675. /* Clean all client caches using the current time now. */
  676. void
  677. hs_cache_clean_as_client(time_t now)
  678. {
  679. /* Start with v2 cache cleaning. */
  680. rend_cache_clean(now, REND_CACHE_TYPE_CLIENT);
  681. /* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function
  682. * to compute the cutoff by itself using the lifetime value. */
  683. cache_clean_v3_as_client(now);
  684. }
  685. /* Purge the client descriptor cache. */
  686. void
  687. hs_cache_purge_as_client(void)
  688. {
  689. DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_client, key,
  690. hs_cache_client_descriptor_t *, entry) {
  691. size_t entry_size = cache_get_client_entry_size(entry);
  692. MAP_DEL_CURRENT(key);
  693. cache_client_desc_free(entry);
  694. /* Update our OOM. We didn't use the remove() function because we are in
  695. * a loop so we have to explicitly decrement. */
  696. rend_cache_decrement_allocation(entry_size);
  697. } DIGEST256MAP_FOREACH_END;
  698. log_info(LD_REND, "Hidden service client descriptor cache purged.");
  699. }
  700. /* For a given service identity public key and an introduction authentication
  701. * key, note the given failure in the client intro state cache. */
  702. void
  703. hs_cache_client_intro_state_note(const ed25519_public_key_t *service_pk,
  704. const ed25519_public_key_t *auth_key,
  705. rend_intro_point_failure_t failure)
  706. {
  707. int found;
  708. hs_cache_intro_state_t *entry;
  709. tor_assert(service_pk);
  710. tor_assert(auth_key);
  711. found = cache_client_intro_state_lookup(service_pk, auth_key, &entry);
  712. if (!found) {
  713. /* Create a new entry and add it to the cache. */
  714. cache_client_intro_state_add(service_pk, auth_key, &entry);
  715. }
  716. /* Note down the entry. */
  717. cache_client_intro_state_note(entry, failure);
  718. }
  719. /* For a given service identity public key and an introduction authentication
  720. * key, return true iff it is present in the failure cache. */
  721. const hs_cache_intro_state_t *
  722. hs_cache_client_intro_state_find(const ed25519_public_key_t *service_pk,
  723. const ed25519_public_key_t *auth_key)
  724. {
  725. hs_cache_intro_state_t *state = NULL;
  726. cache_client_intro_state_lookup(service_pk, auth_key, &state);
  727. return state;
  728. }
  729. /* Cleanup the client introduction state cache. */
  730. void
  731. hs_cache_client_intro_state_clean(time_t now)
  732. {
  733. time_t cutoff = now - HS_CACHE_CLIENT_INTRO_STATE_MAX_AGE;
  734. DIGEST256MAP_FOREACH_MODIFY(hs_cache_client_intro_state, key,
  735. hs_cache_client_intro_state_t *, cache) {
  736. /* Cleanup intro points failure. */
  737. cache_client_intro_state_clean(cutoff, cache);
  738. /* Is this cache empty for this service key? If yes, remove it from the
  739. * cache. Else keep it. */
  740. if (cache_client_intro_state_is_empty(cache)) {
  741. cache_client_intro_state_free(cache);
  742. MAP_DEL_CURRENT(key);
  743. }
  744. } DIGEST256MAP_FOREACH_END;
  745. }
  746. /* Purge the client introduction state cache. */
  747. void
  748. hs_cache_client_intro_state_purge(void)
  749. {
  750. DIGEST256MAP_FOREACH_MODIFY(hs_cache_client_intro_state, key,
  751. hs_cache_client_intro_state_t *, cache) {
  752. MAP_DEL_CURRENT(key);
  753. cache_client_intro_state_free(cache);
  754. } DIGEST256MAP_FOREACH_END;
  755. log_info(LD_REND, "Hidden service client introduction point state "
  756. "cache purged.");
  757. }
  758. /**************** Generics *********************************/
  759. /* Do a round of OOM cleanup on all directory caches. Return the amount of
  760. * removed bytes. It is possible that the returned value is lower than
  761. * min_remove_bytes if the caches get emptied out so the caller should be
  762. * aware of this. */
  763. size_t
  764. hs_cache_handle_oom(time_t now, size_t min_remove_bytes)
  765. {
  766. time_t k;
  767. size_t bytes_removed = 0;
  768. /* Our OOM handler called with 0 bytes to remove is a code flow error. */
  769. tor_assert(min_remove_bytes != 0);
  770. /* The algorithm is as follow. K is the oldest expected descriptor age.
  771. *
  772. * 1) Deallocate all entries from v2 cache that are older than K hours.
  773. * 1.1) If the amount of remove bytes has been reached, stop.
  774. * 2) Deallocate all entries from v3 cache that are older than K hours
  775. * 2.1) If the amount of remove bytes has been reached, stop.
  776. * 3) Set K = K - RendPostPeriod and repeat process until K is < 0.
  777. *
  778. * This ends up being O(Kn).
  779. */
  780. /* Set K to the oldest expected age in seconds which is the maximum
  781. * lifetime of a cache entry. We'll use the v2 lifetime because it's much
  782. * bigger than the v3 thus leading to cleaning older descriptors. */
  783. k = rend_cache_max_entry_lifetime();
  784. do {
  785. time_t cutoff;
  786. /* If K becomes negative, it means we've empty the caches so stop and
  787. * return what we were able to cleanup. */
  788. if (k < 0) {
  789. break;
  790. }
  791. /* Compute a cutoff value with K and the current time. */
  792. cutoff = now - k;
  793. /* Start by cleaning the v2 cache with that cutoff. */
  794. bytes_removed += rend_cache_clean_v2_descs_as_dir(cutoff);
  795. if (bytes_removed < min_remove_bytes) {
  796. /* We haven't remove enough bytes so clean v3 cache. */
  797. bytes_removed += cache_clean_v3_as_dir(now, cutoff);
  798. /* Decrement K by a post period to shorten the cutoff. */
  799. k -= get_options()->RendPostPeriod;
  800. }
  801. } while (bytes_removed < min_remove_bytes);
  802. return bytes_removed;
  803. }
  804. /* Return the maximum size of a v3 HS descriptor. */
  805. unsigned int
  806. hs_cache_get_max_descriptor_size(void)
  807. {
  808. return (unsigned) networkstatus_get_param(NULL,
  809. "HSV3MaxDescriptorSize",
  810. HS_DESC_MAX_LEN, 1, INT32_MAX);
  811. }
  812. /* Initialize the hidden service cache subsystem. */
  813. void
  814. hs_cache_init(void)
  815. {
  816. /* Calling this twice is very wrong code flow. */
  817. tor_assert(!hs_cache_v3_dir);
  818. hs_cache_v3_dir = digest256map_new();
  819. tor_assert(!hs_cache_v3_client);
  820. hs_cache_v3_client = digest256map_new();
  821. tor_assert(!hs_cache_client_intro_state);
  822. hs_cache_client_intro_state = digest256map_new();
  823. }
  824. /* Cleanup the hidden service cache subsystem. */
  825. void
  826. hs_cache_free_all(void)
  827. {
  828. digest256map_free(hs_cache_v3_dir, cache_dir_desc_free_void);
  829. hs_cache_v3_dir = NULL;
  830. digest256map_free(hs_cache_v3_client, cache_client_desc_free_void);
  831. hs_cache_v3_client = NULL;
  832. digest256map_free(hs_cache_client_intro_state,
  833. cache_client_intro_state_free_void);
  834. hs_cache_client_intro_state = NULL;
  835. }