hs_cache.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. /* Copyright (c) 2016-2017, 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 "hs_cache.h"
  10. #include "or.h"
  11. #include "config.h"
  12. #include "hs_common.h"
  13. #include "hs_descriptor.h"
  14. #include "networkstatus.h"
  15. #include "rendcache.h"
  16. /* Directory descriptor cache. Map indexed by blinded key. */
  17. static digest256map_t *hs_cache_v3_dir;
  18. /* Remove a given descriptor from our cache. */
  19. static void
  20. remove_v3_desc_as_dir(const hs_cache_dir_descriptor_t *desc)
  21. {
  22. tor_assert(desc);
  23. digest256map_remove(hs_cache_v3_dir, desc->key);
  24. }
  25. /* Store a given descriptor in our cache. */
  26. static void
  27. store_v3_desc_as_dir(hs_cache_dir_descriptor_t *desc)
  28. {
  29. tor_assert(desc);
  30. digest256map_set(hs_cache_v3_dir, desc->key, desc);
  31. }
  32. /* Query our cache and return the entry or NULL if not found. */
  33. static hs_cache_dir_descriptor_t *
  34. lookup_v3_desc_as_dir(const uint8_t *key)
  35. {
  36. tor_assert(key);
  37. return digest256map_get(hs_cache_v3_dir, key);
  38. }
  39. /* Free a directory descriptor object. */
  40. static void
  41. cache_dir_desc_free(hs_cache_dir_descriptor_t *desc)
  42. {
  43. if (desc == NULL) {
  44. return;
  45. }
  46. hs_desc_plaintext_data_free(desc->plaintext_data);
  47. tor_free(desc->encoded_desc);
  48. tor_free(desc);
  49. }
  50. /* Helper function: Use by the free all function using the digest256map
  51. * interface to cache entries. */
  52. static void
  53. cache_dir_desc_free_(void *ptr)
  54. {
  55. hs_cache_dir_descriptor_t *desc = ptr;
  56. cache_dir_desc_free(desc);
  57. }
  58. /* Create a new directory cache descriptor object from a encoded descriptor.
  59. * On success, return the heap-allocated cache object, otherwise return NULL if
  60. * we can't decode the descriptor. */
  61. static hs_cache_dir_descriptor_t *
  62. cache_dir_desc_new(const char *desc)
  63. {
  64. hs_cache_dir_descriptor_t *dir_desc;
  65. tor_assert(desc);
  66. dir_desc = tor_malloc_zero(sizeof(hs_cache_dir_descriptor_t));
  67. dir_desc->plaintext_data =
  68. tor_malloc_zero(sizeof(hs_desc_plaintext_data_t));
  69. dir_desc->encoded_desc = tor_strdup(desc);
  70. if (hs_desc_decode_plaintext(desc, dir_desc->plaintext_data) < 0) {
  71. log_debug(LD_DIR, "Unable to decode descriptor. Rejecting.");
  72. goto err;
  73. }
  74. /* The blinded pubkey is the indexed key. */
  75. dir_desc->key = dir_desc->plaintext_data->blinded_pubkey.pubkey;
  76. dir_desc->created_ts = time(NULL);
  77. return dir_desc;
  78. err:
  79. cache_dir_desc_free(dir_desc);
  80. return NULL;
  81. }
  82. /* Return the size of a cache entry in bytes. */
  83. static size_t
  84. cache_get_entry_size(const hs_cache_dir_descriptor_t *entry)
  85. {
  86. return (sizeof(*entry) + hs_desc_plaintext_obj_size(entry->plaintext_data)
  87. + strlen(entry->encoded_desc));
  88. }
  89. /* Try to store a valid version 3 descriptor in the directory cache. Return 0
  90. * on success else a negative value is returned indicating that we have a
  91. * newer version in our cache. On error, caller is responsible to free the
  92. * given descriptor desc. */
  93. static int
  94. cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc)
  95. {
  96. hs_cache_dir_descriptor_t *cache_entry;
  97. tor_assert(desc);
  98. /* Verify if we have an entry in the cache for that key and if yes, check
  99. * if we should replace it? */
  100. cache_entry = lookup_v3_desc_as_dir(desc->key);
  101. if (cache_entry != NULL) {
  102. /* Only replace descriptor if revision-counter is greater than the one
  103. * in our cache */
  104. if (cache_entry->plaintext_data->revision_counter >=
  105. desc->plaintext_data->revision_counter) {
  106. log_info(LD_REND, "Descriptor revision counter in our cache is "
  107. "greater or equal than the one we received (%d/%d). "
  108. "Rejecting!",
  109. (int)cache_entry->plaintext_data->revision_counter,
  110. (int)desc->plaintext_data->revision_counter);
  111. goto err;
  112. }
  113. /* We now know that the descriptor we just received is a new one so
  114. * remove the entry we currently have from our cache so we can then
  115. * store the new one. */
  116. remove_v3_desc_as_dir(cache_entry);
  117. rend_cache_decrement_allocation(cache_get_entry_size(cache_entry));
  118. cache_dir_desc_free(cache_entry);
  119. }
  120. /* Store the descriptor we just got. We are sure here that either we
  121. * don't have the entry or we have a newer descriptor and the old one
  122. * has been removed from the cache. */
  123. store_v3_desc_as_dir(desc);
  124. /* Update our total cache size with this entry for the OOM. This uses the
  125. * old HS protocol cache subsystem for which we are tied with. */
  126. rend_cache_increment_allocation(cache_get_entry_size(desc));
  127. /* XXX: Update HS statistics. We should have specific stats for v3. */
  128. return 0;
  129. err:
  130. return -1;
  131. }
  132. /* Using the query which is the base64 encoded blinded key of a version 3
  133. * descriptor, lookup in our directory cache the entry. If found, 1 is
  134. * returned and desc_out is populated with a newly allocated string being the
  135. * encoded descriptor. If not found, 0 is returned and desc_out is untouched.
  136. * On error, a negative value is returned and desc_out is untouched. */
  137. static int
  138. cache_lookup_v3_as_dir(const char *query, const char **desc_out)
  139. {
  140. int found = 0;
  141. ed25519_public_key_t blinded_key;
  142. const hs_cache_dir_descriptor_t *entry;
  143. tor_assert(query);
  144. /* Decode blinded key using the given query value. */
  145. if (ed25519_public_from_base64(&blinded_key, query) < 0) {
  146. log_info(LD_REND, "Unable to decode the v3 HSDir query %s.",
  147. safe_str_client(query));
  148. goto err;
  149. }
  150. entry = lookup_v3_desc_as_dir(blinded_key.pubkey);
  151. if (entry != NULL) {
  152. found = 1;
  153. if (desc_out) {
  154. *desc_out = entry->encoded_desc;
  155. }
  156. }
  157. return found;
  158. err:
  159. return -1;
  160. }
  161. /* Clean the v3 cache by removing any entry that has expired using the
  162. * <b>global_cutoff</b> value. If <b>global_cutoff</b> is 0, the cleaning
  163. * process will use the lifetime found in the plaintext data section. Return
  164. * the number of bytes cleaned. */
  165. STATIC size_t
  166. cache_clean_v3_as_dir(time_t now, time_t global_cutoff)
  167. {
  168. size_t bytes_removed = 0;
  169. /* Code flow error if this ever happens. */
  170. tor_assert(global_cutoff >= 0);
  171. if (!hs_cache_v3_dir) { /* No cache to clean. Just return. */
  172. return 0;
  173. }
  174. DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_dir, key,
  175. hs_cache_dir_descriptor_t *, entry) {
  176. size_t entry_size;
  177. time_t cutoff = global_cutoff;
  178. if (!cutoff) {
  179. /* Cutoff is the lifetime of the entry found in the descriptor. */
  180. cutoff = now - entry->plaintext_data->lifetime_sec;
  181. }
  182. /* If the entry has been created _after_ the cutoff, not expired so
  183. * continue to the next entry in our v3 cache. */
  184. if (entry->created_ts > cutoff) {
  185. continue;
  186. }
  187. /* Here, our entry has expired, remove and free. */
  188. MAP_DEL_CURRENT(key);
  189. entry_size = cache_get_entry_size(entry);
  190. bytes_removed += entry_size;
  191. /* Entry is not in the cache anymore, destroy it. */
  192. cache_dir_desc_free(entry);
  193. /* Update our cache entry allocation size for the OOM. */
  194. rend_cache_decrement_allocation(entry_size);
  195. /* Logging. */
  196. {
  197. char key_b64[BASE64_DIGEST256_LEN + 1];
  198. base64_encode(key_b64, sizeof(key_b64), (const char *) key,
  199. DIGEST256_LEN, 0);
  200. log_info(LD_REND, "Removing v3 descriptor '%s' from HSDir cache",
  201. safe_str_client(key_b64));
  202. }
  203. } DIGEST256MAP_FOREACH_END;
  204. return bytes_removed;
  205. }
  206. /* Given an encoded descriptor, store it in the directory cache depending on
  207. * which version it is. Return a negative value on error. On success, 0 is
  208. * returned. */
  209. int
  210. hs_cache_store_as_dir(const char *desc)
  211. {
  212. hs_cache_dir_descriptor_t *dir_desc = NULL;
  213. tor_assert(desc);
  214. /* Create a new cache object. This can fail if the descriptor plaintext data
  215. * is unparseable which in this case a log message will be triggered. */
  216. dir_desc = cache_dir_desc_new(desc);
  217. if (dir_desc == NULL) {
  218. goto err;
  219. }
  220. /* Call the right function against the descriptor version. At this point,
  221. * we are sure that the descriptor's version is supported else the
  222. * decoding would have failed. */
  223. switch (dir_desc->plaintext_data->version) {
  224. case HS_VERSION_THREE:
  225. default:
  226. if (cache_store_v3_as_dir(dir_desc) < 0) {
  227. goto err;
  228. }
  229. break;
  230. }
  231. return 0;
  232. err:
  233. cache_dir_desc_free(dir_desc);
  234. return -1;
  235. }
  236. /* Using the query, lookup in our directory cache the entry. If found, 1 is
  237. * returned and desc_out is populated with a newly allocated string being
  238. * the encoded descriptor. If not found, 0 is returned and desc_out is
  239. * untouched. On error, a negative value is returned and desc_out is
  240. * untouched. */
  241. int
  242. hs_cache_lookup_as_dir(uint32_t version, const char *query,
  243. const char **desc_out)
  244. {
  245. int found;
  246. tor_assert(query);
  247. /* This should never be called with an unsupported version. */
  248. tor_assert(hs_desc_is_supported_version(version));
  249. switch (version) {
  250. case HS_VERSION_THREE:
  251. default:
  252. found = cache_lookup_v3_as_dir(query, desc_out);
  253. break;
  254. }
  255. return found;
  256. }
  257. /* Clean all directory caches using the current time now. */
  258. void
  259. hs_cache_clean_as_dir(time_t now)
  260. {
  261. time_t cutoff;
  262. /* Start with v2 cache cleaning. */
  263. cutoff = now - rend_cache_max_entry_lifetime();
  264. rend_cache_clean_v2_descs_as_dir(cutoff);
  265. /* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function
  266. * to compute the cutoff by itself using the lifetime value. */
  267. cache_clean_v3_as_dir(now, 0);
  268. }
  269. /* Do a round of OOM cleanup on all directory caches. Return the amount of
  270. * removed bytes. It is possible that the returned value is lower than
  271. * min_remove_bytes if the caches get emptied out so the caller should be
  272. * aware of this. */
  273. size_t
  274. hs_cache_handle_oom(time_t now, size_t min_remove_bytes)
  275. {
  276. time_t k;
  277. size_t bytes_removed = 0;
  278. /* Our OOM handler called with 0 bytes to remove is a code flow error. */
  279. tor_assert(min_remove_bytes != 0);
  280. /* The algorithm is as follow. K is the oldest expected descriptor age.
  281. *
  282. * 1) Deallocate all entries from v2 cache that are older than K hours.
  283. * 1.1) If the amount of remove bytes has been reached, stop.
  284. * 2) Deallocate all entries from v3 cache that are older than K hours
  285. * 2.1) If the amount of remove bytes has been reached, stop.
  286. * 3) Set K = K - RendPostPeriod and repeat process until K is < 0.
  287. *
  288. * This ends up being O(Kn).
  289. */
  290. /* Set K to the oldest expected age in seconds which is the maximum
  291. * lifetime of a cache entry. We'll use the v2 lifetime because it's much
  292. * bigger than the v3 thus leading to cleaning older descriptors. */
  293. k = rend_cache_max_entry_lifetime();
  294. do {
  295. time_t cutoff;
  296. /* If K becomes negative, it means we've empty the caches so stop and
  297. * return what we were able to cleanup. */
  298. if (k < 0) {
  299. break;
  300. }
  301. /* Compute a cutoff value with K and the current time. */
  302. cutoff = now - k;
  303. /* Start by cleaning the v2 cache with that cutoff. */
  304. bytes_removed += rend_cache_clean_v2_descs_as_dir(cutoff);
  305. if (bytes_removed < min_remove_bytes) {
  306. /* We haven't remove enough bytes so clean v3 cache. */
  307. bytes_removed += cache_clean_v3_as_dir(now, cutoff);
  308. /* Decrement K by a post period to shorten the cutoff. */
  309. k -= get_options()->RendPostPeriod;
  310. }
  311. } while (bytes_removed < min_remove_bytes);
  312. return bytes_removed;
  313. }
  314. /**
  315. * Return the maximum size of an HS descriptor we are willing to accept as an
  316. * HSDir.
  317. */
  318. unsigned int
  319. hs_cache_get_max_descriptor_size(void)
  320. {
  321. return (unsigned) networkstatus_get_param(NULL,
  322. "HSV3MaxDescriptorSize",
  323. HS_DESC_MAX_LEN, 1, INT32_MAX);
  324. }
  325. /* Initialize the hidden service cache subsystem. */
  326. void
  327. hs_cache_init(void)
  328. {
  329. /* Calling this twice is very wrong code flow. */
  330. tor_assert(!hs_cache_v3_dir);
  331. hs_cache_v3_dir = digest256map_new();
  332. }
  333. /* Cleanup the hidden service cache subsystem. */
  334. void
  335. hs_cache_free_all(void)
  336. {
  337. digest256map_free(hs_cache_v3_dir, cache_dir_desc_free_);
  338. hs_cache_v3_dir = NULL;
  339. }