tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

hs_cache.c (42832B)


      1 /* Copyright (c) 2016-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file hs_cache.c
      6 * \brief Handle hidden service descriptor caches.
      7 **/
      8 
      9 /* For unit tests.*/
     10 #define HS_CACHE_PRIVATE
     11 
     12 #include "core/or/or.h"
     13 #include "app/config/config.h"
     14 #include "lib/crypt_ops/crypto_format.h"
     15 #include "lib/crypt_ops/crypto_util.h"
     16 #include "lib/cc/torint.h"
     17 #include "feature/hs/hs_ident.h"
     18 #include "feature/hs/hs_common.h"
     19 #include "feature/hs/hs_client.h"
     20 #include "feature/hs/hs_descriptor.h"
     21 #include "feature/nodelist/microdesc.h"
     22 #include "feature/nodelist/networkstatus.h"
     23 #include "feature/stats/rephist.h"
     24 
     25 #include "feature/hs/hs_cache.h"
     26 
     27 #include "feature/nodelist/networkstatus_st.h"
     28 
     29 /**
     30 * Spare room for 1000 descriptors when pruning cache to avoid thrashing
     31 * and memory fragmentation. */
     32 #define HSCACHE_PRUNE_SPARE_ROOM (1000 * HS_DESC_MAX_LEN)
     33 
     34 /* Total counter of the cache size. */
     35 static size_t hs_cache_total_allocation = 0;
     36 
     37 static int cached_client_descriptor_has_expired(time_t now,
     38           const hs_cache_client_descriptor_t *cached_desc);
     39 
     40 /** Helper function: Return true iff the cache entry has a decrypted
     41 * descriptor.
     42 *
     43 * A NULL desc object in the entry means that we were not able to decrypt the
     44 * descriptor because we are likely lacking client authorization.  It is still
     45 * a valid entry but some operations can't be done without the decrypted
     46 * descriptor thus this function MUST be used to safe guard access to the
     47 * decrypted desc object. */
     48 static inline bool
     49 entry_has_decrypted_descriptor(const hs_cache_client_descriptor_t *entry)
     50 {
     51  tor_assert(entry);
     52  return (entry->desc != NULL);
     53 }
     54 
     55 /********************** Directory HS cache ******************/
     56 
     57 /** Directory descriptor cache. Map indexed by blinded key. */
     58 static digest256map_t *hs_cache_v3_dir;
     59 
     60 /** Remove a given descriptor from our cache. */
     61 static void
     62 remove_v3_desc_as_dir(const hs_cache_dir_descriptor_t *desc)
     63 {
     64  tor_assert(desc);
     65  digest256map_remove(hs_cache_v3_dir, desc->key);
     66 }
     67 
     68 /** Store a given descriptor in our cache. */
     69 static void
     70 store_v3_desc_as_dir(hs_cache_dir_descriptor_t *desc)
     71 {
     72  tor_assert(desc);
     73  digest256map_set(hs_cache_v3_dir, desc->key, desc);
     74 }
     75 
     76 /** Query our cache and return the entry or NULL if not found. */
     77 STATIC hs_cache_dir_descriptor_t *
     78 lookup_v3_desc_as_dir(const uint8_t *key)
     79 {
     80  tor_assert(key);
     81  return digest256map_get(hs_cache_v3_dir, key);
     82 }
     83 
     84 #define cache_dir_desc_free(val) \
     85  FREE_AND_NULL(hs_cache_dir_descriptor_t, cache_dir_desc_free_, (val))
     86 
     87 /** Free a directory descriptor object. */
     88 static void
     89 cache_dir_desc_free_(hs_cache_dir_descriptor_t *desc)
     90 {
     91  if (desc == NULL) {
     92    return;
     93  }
     94  hs_desc_plaintext_data_free(desc->plaintext_data);
     95  tor_free(desc->encoded_desc);
     96  tor_free(desc);
     97 }
     98 
     99 /** Helper function: Use by the free all function using the digest256map
    100 * interface to cache entries. */
    101 static void
    102 cache_dir_desc_free_void(void *ptr)
    103 {
    104  cache_dir_desc_free_(ptr);
    105 }
    106 
    107 /** Create a new directory cache descriptor object from a encoded descriptor.
    108 * On success, return the heap-allocated cache object, otherwise return NULL if
    109 * we can't decode the descriptor. */
    110 static hs_cache_dir_descriptor_t *
    111 cache_dir_desc_new(const char *desc)
    112 {
    113  hs_cache_dir_descriptor_t *dir_desc;
    114 
    115  tor_assert(desc);
    116 
    117  dir_desc = tor_malloc_zero(sizeof(hs_cache_dir_descriptor_t));
    118  dir_desc->plaintext_data =
    119    tor_malloc_zero(sizeof(hs_desc_plaintext_data_t));
    120  dir_desc->encoded_desc = tor_strdup(desc);
    121 
    122  if (hs_desc_decode_plaintext(desc, dir_desc->plaintext_data) < 0) {
    123    log_debug(LD_DIR, "Unable to decode descriptor. Rejecting.");
    124    goto err;
    125  }
    126 
    127  /* The blinded pubkey is the indexed key. */
    128  dir_desc->key = dir_desc->plaintext_data->blinded_pubkey.pubkey;
    129  dir_desc->created_ts = time(NULL);
    130  return dir_desc;
    131 
    132 err:
    133  cache_dir_desc_free(dir_desc);
    134  return NULL;
    135 }
    136 
    137 /** Return the size of a cache entry in bytes. */
    138 static size_t
    139 cache_get_dir_entry_size(const hs_cache_dir_descriptor_t *entry)
    140 {
    141  return (sizeof(*entry) + hs_desc_plaintext_obj_size(entry->plaintext_data)
    142          + strlen(entry->encoded_desc));
    143 }
    144 
    145 /** Try to store a valid version 3 descriptor in the directory cache. Return 0
    146 * on success else a negative value is returned indicating that we have a
    147 * newer version in our cache. On error, caller is responsible to free the
    148 * given descriptor desc. */
    149 static int
    150 cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc)
    151 {
    152  hs_cache_dir_descriptor_t *cache_entry;
    153 
    154  tor_assert(desc);
    155 
    156  /* Check if we've exceeded the MaxHSDirCacheBytes limit after adding
    157   * this descriptor. If so, prune excess bytes leaving room for more. */
    158  const size_t max_cache_bytes = hs_cache_get_max_bytes();
    159  const size_t current_cache_bytes = hs_cache_get_total_allocation();
    160  if (max_cache_bytes > 0 && current_cache_bytes > max_cache_bytes) {
    161    /* We prune only 1000 descriptors worth of memory here because
    162     * pruning is an expensive O(n^2) option to keep finding lowest
    163     * download count descs. */
    164    size_t bytes_to_remove = current_cache_bytes/2;
    165    /* Ensure user didn't set a really low max hsdir cache vlue */
    166    if (HSCACHE_PRUNE_SPARE_ROOM < max_cache_bytes) {
    167      bytes_to_remove = current_cache_bytes -
    168                         (max_cache_bytes - HSCACHE_PRUNE_SPARE_ROOM);
    169    }
    170    size_t removed = hs_cache_handle_oom(bytes_to_remove);
    171    static ratelim_t hs_cache_oom_ratelim = RATELIM_INIT(600);
    172    log_fn_ratelim(&hs_cache_oom_ratelim, LOG_NOTICE, LD_REND,
    173               "HSDir cache exceeded limit "
    174               "(%"TOR_PRIuSZ " > %"TOR_PRIuSZ " bytes). "
    175               "Pruned %"TOR_PRIuSZ " bytes during an HS descriptor upload.",
    176               current_cache_bytes, max_cache_bytes, removed);
    177  }
    178 
    179  /* Verify if we have an entry in the cache for that key and if yes, check
    180   * if we should replace it? */
    181  cache_entry = lookup_v3_desc_as_dir(desc->key);
    182  if (cache_entry != NULL) {
    183    /* Only replace descriptor if revision-counter is greater than the one
    184     * in our cache */
    185    if (cache_entry->plaintext_data->revision_counter >=
    186        desc->plaintext_data->revision_counter) {
    187      log_info(LD_REND, "Descriptor revision counter in our cache is "
    188               "greater or equal than the one we received (%d/%d). "
    189               "Rejecting!",
    190               (int)cache_entry->plaintext_data->revision_counter,
    191               (int)desc->plaintext_data->revision_counter);
    192      goto err;
    193    }
    194    /* We now know that the descriptor we just received is a new one so
    195     * preserve the downloaded counter from the old entry and then
    196     * remove the entry we currently have from our cache so we can then
    197     * store the new one. */
    198    desc->n_downloaded = cache_entry->n_downloaded;
    199    remove_v3_desc_as_dir(cache_entry);
    200    hs_cache_decrement_allocation(cache_get_dir_entry_size(cache_entry));
    201    cache_dir_desc_free(cache_entry);
    202  }
    203 
    204  /* Store the descriptor we just got. We are sure here that either we
    205   * don't have the entry or we have a newer descriptor and the old one
    206   * has been removed from the cache. We do this *after* pruning
    207   * other descriptors so that this descriptor is not immediately pruned,
    208   * if new. This prevents probing to detect OOM threshholds via its
    209   * absence. */
    210  store_v3_desc_as_dir(desc);
    211 
    212  /* Update our total cache size with this entry for the OOM. This uses the
    213   * old HS protocol cache subsystem for which we are tied with. */
    214  hs_cache_increment_allocation(cache_get_dir_entry_size(desc));
    215 
    216  /* Update HSv3 statistics */
    217  if (get_options()->HiddenServiceStatistics) {
    218    rep_hist_hsdir_stored_maybe_new_v3_onion(desc->key);
    219  }
    220 
    221  return 0;
    222 
    223 err:
    224  return -1;
    225 }
    226 
    227 /** Using the query which is the base64 encoded blinded key of a version 3
    228 * descriptor, lookup in our directory cache the entry. If found, 1 is
    229 * returned and desc_out is populated with a newly allocated string being the
    230 * encoded descriptor. If not found, 0 is returned and desc_out is untouched.
    231 * On error, a negative value is returned and desc_out is untouched. */
    232 static int
    233 cache_lookup_v3_as_dir(const char *query, const char **desc_out)
    234 {
    235  int found = 0;
    236  ed25519_public_key_t blinded_key;
    237  const hs_cache_dir_descriptor_t *entry;
    238 
    239  tor_assert(query);
    240 
    241  /* Decode blinded key using the given query value. */
    242  if (ed25519_public_from_base64(&blinded_key, query) < 0) {
    243    log_info(LD_REND, "Unable to decode the v3 HSDir query %s.",
    244             safe_str_client(query));
    245    goto err;
    246  }
    247 
    248  entry = lookup_v3_desc_as_dir(blinded_key.pubkey);
    249  if (entry != NULL) {
    250    found = 1;
    251    if (desc_out) {
    252      *desc_out = entry->encoded_desc;
    253    }
    254  }
    255 
    256  return found;
    257 
    258 err:
    259  return -1;
    260 }
    261 
    262 /** Clean the v3 cache by removing entries that are below or equal the
    263 * downloaded target.
    264 *
    265 * Stop when the max_remove_bytes is reached. It is possible that more bytes
    266 * are removed if max_remove_bytes is not aligned on cache entry size.
    267 *
    268 * Return the amount of bytes freed. The next_lowest param is set to the
    269 * lowest n_downloaded value in the cache that is above target.
    270 *
    271 * If both next_lowest and returned value are 0, the cache is empty. */
    272 STATIC size_t
    273 cache_clean_v3_by_downloaded_as_dir(const uint64_t target,
    274                                    const size_t max_remove_bytes,
    275                                    uint64_t *next_lowest)
    276 {
    277  size_t bytes_removed = 0;
    278  uint64_t lowest = 0;
    279 
    280  if (!hs_cache_v3_dir) { /* No cache to clean. Just return. */
    281    goto end;
    282  }
    283 
    284  log_info(LD_REND, "Cleaning HS cache for downloaded target of %" PRIu64
    285                    ". Maximum bytes to removed: %" TOR_PRIuSZ,
    286           target, max_remove_bytes);
    287 
    288  DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_dir, key,
    289                              hs_cache_dir_descriptor_t *, entry) {
    290    /* Downloaded counter is above target, ignore. Record next lowest. */
    291    if (entry->n_downloaded > target) {
    292      if (lowest == 0 || lowest > entry->n_downloaded) {
    293        lowest = entry->n_downloaded;
    294      }
    295      continue;
    296    }
    297    /* We have removed enough, avoid cleaning this entry. Reason we continue
    298     * the loop is so we can find the next lowest value. Yes, with many
    299     * entries, this could be expensive but this is only called during OOM
    300     * cleanup which should be fairly rare. */
    301    if (bytes_removed >= max_remove_bytes) {
    302      continue;
    303    }
    304    size_t entry_size = cache_get_dir_entry_size(entry);
    305    /* Logging. */
    306    {
    307      char key_b64[BASE64_DIGEST256_LEN + 1];
    308      digest256_to_base64(key_b64, (const char *) key);
    309      log_info(LD_REND, "Removing v3 descriptor '%s' from HSDir cache. "
    310                        "Downloaded %" PRIu64 " times and "
    311                        "size of %" TOR_PRIuSZ " bytes",
    312               safe_str_client(key_b64), entry->n_downloaded, entry_size);
    313    }
    314    /* Remove it from our cache. */
    315    MAP_DEL_CURRENT(key);
    316    bytes_removed += entry_size;
    317    /* Entry is not in the cache anymore, destroy it. */
    318    cache_dir_desc_free(entry);
    319    /* Update our cache entry allocation size for the OOM. */
    320    hs_cache_decrement_allocation(entry_size);
    321  } DIGEST256MAP_FOREACH_END;
    322 
    323 end:
    324  *next_lowest = lowest;
    325  return bytes_removed;
    326 }
    327 
    328 /** Clean the v3 cache by removing any entry that has expired using the
    329 * <b>global_cutoff</b> value. If <b>global_cutoff</b> is 0, the cleaning
    330 * process will use the lifetime found in the plaintext data section. Return
    331 * the number of bytes cleaned. */
    332 STATIC size_t
    333 cache_clean_v3_as_dir(time_t now, time_t global_cutoff)
    334 {
    335  size_t bytes_removed = 0;
    336 
    337  /* Code flow error if this ever happens. */
    338  tor_assert(global_cutoff >= 0);
    339 
    340  if (!hs_cache_v3_dir) { /* No cache to clean. Just return. */
    341    return 0;
    342  }
    343 
    344  DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_dir, key,
    345                              hs_cache_dir_descriptor_t *, entry) {
    346    size_t entry_size;
    347    time_t cutoff = global_cutoff;
    348    if (!cutoff) {
    349      /* Cutoff is the lifetime of the entry found in the descriptor. */
    350      cutoff = now - entry->plaintext_data->lifetime_sec;
    351    }
    352 
    353    /* If the entry has been created _after_ the cutoff, not expired so
    354     * continue to the next entry in our v3 cache. */
    355    if (entry->created_ts > cutoff) {
    356      continue;
    357    }
    358    /* Here, our entry has expired, remove and free. */
    359    MAP_DEL_CURRENT(key);
    360    entry_size = cache_get_dir_entry_size(entry);
    361    bytes_removed += entry_size;
    362    /* Entry is not in the cache anymore, destroy it. */
    363    cache_dir_desc_free(entry);
    364    /* Update our cache entry allocation size for the OOM. */
    365    hs_cache_decrement_allocation(entry_size);
    366    /* Logging. */
    367    {
    368      char key_b64[BASE64_DIGEST256_LEN + 1];
    369      digest256_to_base64(key_b64, (const char *) key);
    370      log_info(LD_REND, "Removing v3 descriptor '%s' from HSDir cache",
    371               safe_str_client(key_b64));
    372    }
    373  } DIGEST256MAP_FOREACH_END;
    374 
    375  return bytes_removed;
    376 }
    377 
    378 /** Given an encoded descriptor, store it in the directory cache depending on
    379 * which version it is. Return a negative value on error. On success, 0 is
    380 * returned. */
    381 int
    382 hs_cache_store_as_dir(const char *desc)
    383 {
    384  hs_cache_dir_descriptor_t *dir_desc = NULL;
    385 
    386  tor_assert(desc);
    387 
    388  /* Create a new cache object. This can fail if the descriptor plaintext data
    389   * is unparseable which in this case a log message will be triggered. */
    390  dir_desc = cache_dir_desc_new(desc);
    391  if (dir_desc == NULL) {
    392    goto err;
    393  }
    394 
    395  /* Call the right function against the descriptor version. At this point,
    396   * we are sure that the descriptor's version is supported else the
    397   * decoding would have failed. */
    398  switch (dir_desc->plaintext_data->version) {
    399  case HS_VERSION_THREE:
    400  default:
    401    if (cache_store_v3_as_dir(dir_desc) < 0) {
    402      goto err;
    403    }
    404    break;
    405  }
    406  return 0;
    407 
    408 err:
    409  cache_dir_desc_free(dir_desc);
    410  return -1;
    411 }
    412 
    413 /** Using the query, lookup in our directory cache the entry. If found, 1 is
    414 * returned and desc_out is populated with a newly allocated string being
    415 * the encoded descriptor. If not found, 0 is returned and desc_out is
    416 * untouched. On error, a negative value is returned and desc_out is
    417 * untouched. */
    418 int
    419 hs_cache_lookup_as_dir(uint32_t version, const char *query,
    420                       const char **desc_out)
    421 {
    422  int found;
    423 
    424  tor_assert(query);
    425  /* This should never be called with an unsupported version. */
    426  tor_assert(hs_desc_is_supported_version(version));
    427 
    428  switch (version) {
    429  case HS_VERSION_THREE:
    430  default:
    431    found = cache_lookup_v3_as_dir(query, desc_out);
    432    break;
    433  }
    434 
    435  return found;
    436 }
    437 
    438 /** Using the given directory identifier, lookup the descriptor in our cache
    439 * and if present, increment the downloaded counter. This is done when the
    440 * directory connection fetching this descriptor is closed. */
    441 void
    442 hs_cache_mark_dowloaded_as_dir(const hs_ident_dir_conn_t *ident)
    443 {
    444  hs_cache_dir_descriptor_t *entry;
    445 
    446  tor_assert(ident);
    447 
    448  entry = lookup_v3_desc_as_dir(ident->blinded_pk.pubkey);
    449  if (entry) {
    450    entry->n_downloaded++;
    451  }
    452 }
    453 
    454 /** Clean all directory caches using the current time now. */
    455 void
    456 hs_cache_clean_as_dir(time_t now)
    457 {
    458  /* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function
    459   * to compute the cutoff by itself using the lifetime value. */
    460  cache_clean_v3_as_dir(now, 0);
    461 }
    462 
    463 /********************** Client-side HS cache ******************/
    464 
    465 /** Client-side HS descriptor cache. Map indexed by service identity key. */
    466 static digest256map_t *hs_cache_v3_client;
    467 
    468 /** Client-side introduction point state cache. Map indexed by service public
    469 * identity key (onion address). It contains hs_cache_client_intro_state_t
    470 * objects all related to a specific service. */
    471 static digest256map_t *hs_cache_client_intro_state;
    472 
    473 #define cache_client_desc_free(val) \
    474  FREE_AND_NULL(hs_cache_client_descriptor_t, cache_client_desc_free_, (val))
    475 
    476 /** Free memory allocated by <b>desc</b>. */
    477 static void
    478 cache_client_desc_free_(hs_cache_client_descriptor_t *desc)
    479 {
    480  if (desc == NULL) {
    481    return;
    482  }
    483  hs_descriptor_free(desc->desc);
    484  memwipe(&desc->key, 0, sizeof(desc->key));
    485  memwipe(desc->encoded_desc, 0, strlen(desc->encoded_desc));
    486  tor_free(desc->encoded_desc);
    487  tor_free(desc);
    488 }
    489 
    490 /** Helper function: Use by the free all function to clear the client cache */
    491 static void
    492 cache_client_desc_free_void(void *ptr)
    493 {
    494  hs_cache_client_descriptor_t *desc = ptr;
    495  cache_client_desc_free(desc);
    496 }
    497 
    498 /** Return the size of a client cache entry in bytes. */
    499 static size_t
    500 cache_get_client_entry_size(const hs_cache_client_descriptor_t *entry)
    501 {
    502  size_t size = 0;
    503 
    504  if (entry == NULL) {
    505    goto end;
    506  }
    507  size += sizeof(*entry);
    508 
    509  if (entry->encoded_desc) {
    510    size += strlen(entry->encoded_desc);
    511  }
    512 
    513  if (entry_has_decrypted_descriptor(entry)) {
    514    size += hs_desc_obj_size(entry->desc);
    515  }
    516 
    517 end:
    518  return size;
    519 }
    520 
    521 /** Remove a given descriptor from our cache. */
    522 static void
    523 remove_v3_desc_as_client(const hs_cache_client_descriptor_t *desc)
    524 {
    525  tor_assert(desc);
    526  digest256map_remove(hs_cache_v3_client, desc->key.pubkey);
    527  /* Update cache size with this entry for the OOM handler. */
    528  hs_cache_decrement_allocation(cache_get_client_entry_size(desc));
    529 }
    530 
    531 /** Store a given descriptor in our cache. */
    532 static void
    533 store_v3_desc_as_client(hs_cache_client_descriptor_t *desc)
    534 {
    535  hs_cache_client_descriptor_t *cached_desc;
    536 
    537  tor_assert(desc);
    538 
    539  /* Because the lookup function doesn't return an expired entry, it can linger
    540   * in the cache until we clean it up or a new descriptor is stored. So,
    541   * before adding, we'll make sure we are not overwriting an old descriptor
    542   * (which is OK in terms of semantic) but leads to memory leak. */
    543  cached_desc = digest256map_get(hs_cache_v3_client, desc->key.pubkey);
    544  if (cached_desc) {
    545    cache_client_desc_free(cached_desc);
    546  }
    547  digest256map_set(hs_cache_v3_client, desc->key.pubkey, desc);
    548  /* Update cache size with this entry for the OOM handler. */
    549  hs_cache_increment_allocation(cache_get_client_entry_size(desc));
    550 }
    551 
    552 /** Query our cache and return the entry or NULL if not found or if expired. */
    553 STATIC hs_cache_client_descriptor_t *
    554 lookup_v3_desc_as_client(const uint8_t *key)
    555 {
    556  time_t now = approx_time();
    557  hs_cache_client_descriptor_t *cached_desc;
    558 
    559  tor_assert(key);
    560 
    561  /* Do the lookup */
    562  cached_desc = digest256map_get(hs_cache_v3_client, key);
    563  if (!cached_desc) {
    564    return NULL;
    565  }
    566 
    567  /* Don't return expired entries */
    568  if (cached_client_descriptor_has_expired(now, cached_desc)) {
    569    return NULL;
    570  }
    571 
    572  return cached_desc;
    573 }
    574 
    575 /** Parse the encoded descriptor in <b>desc_str</b> using
    576 * <b>service_identity_pk</b> to decrypt it first.
    577 *
    578 * If everything goes well, allocate and return a new
    579 * hs_cache_client_descriptor_t object. In case of error, return NULL. */
    580 static hs_cache_client_descriptor_t *
    581 cache_client_desc_new(const char *desc_str,
    582                      const ed25519_public_key_t *service_identity_pk,
    583                      hs_desc_decode_status_t *decode_status_out)
    584 {
    585  hs_desc_decode_status_t ret;
    586  hs_descriptor_t *desc = NULL;
    587  hs_cache_client_descriptor_t *client_desc = NULL;
    588 
    589  tor_assert(desc_str);
    590  tor_assert(service_identity_pk);
    591 
    592  /* Decode the descriptor we just fetched. */
    593  ret = hs_client_decode_descriptor(desc_str, service_identity_pk, &desc);
    594  if (ret != HS_DESC_DECODE_OK &&
    595      ret != HS_DESC_DECODE_NEED_CLIENT_AUTH &&
    596      ret != HS_DESC_DECODE_BAD_CLIENT_AUTH) {
    597    /* In the case of a missing or bad client authorization, we'll keep the
    598     * descriptor in the cache because those credentials can arrive later. */
    599    goto end;
    600  }
    601  /* Make sure we do have a descriptor if decoding was successful. */
    602  if (ret == HS_DESC_DECODE_OK) {
    603    tor_assert(desc);
    604  } else {
    605    if (BUG(desc != NULL)) {
    606      /* We are not suppose to have a descriptor if the decoding code is not
    607       * indicating success. Just in case, bail early to recover. */
    608      goto end;
    609    }
    610  }
    611 
    612  /* All is good: make a cache object for this descriptor */
    613  client_desc = tor_malloc_zero(sizeof(hs_cache_client_descriptor_t));
    614  ed25519_pubkey_copy(&client_desc->key, service_identity_pk);
    615  /* Set expiration time for this cached descriptor to be the start of the next
    616   * time period since that's when clients need to start using the next blinded
    617   * pk of the service (and hence will need its next descriptor). */
    618  client_desc->expiration_ts = hs_get_start_time_of_next_time_period(0);
    619  client_desc->desc = desc;
    620  client_desc->encoded_desc = tor_strdup(desc_str);
    621 
    622 end:
    623  if (decode_status_out) {
    624    *decode_status_out = ret;
    625  }
    626  return client_desc;
    627 }
    628 
    629 /** Return a newly allocated and initialized hs_cache_intro_state_t object. */
    630 static hs_cache_intro_state_t *
    631 cache_intro_state_new(void)
    632 {
    633  hs_cache_intro_state_t *state = tor_malloc_zero(sizeof(*state));
    634  state->created_ts = approx_time();
    635  return state;
    636 }
    637 
    638 #define cache_intro_state_free(val) \
    639  FREE_AND_NULL(hs_cache_intro_state_t, cache_intro_state_free_, (val))
    640 
    641 /** Free an hs_cache_intro_state_t object. */
    642 static void
    643 cache_intro_state_free_(hs_cache_intro_state_t *state)
    644 {
    645  tor_free(state);
    646 }
    647 
    648 /** Helper function: used by the free all function. */
    649 static void
    650 cache_intro_state_free_void(void *state)
    651 {
    652  cache_intro_state_free_(state);
    653 }
    654 
    655 /** Return a newly allocated and initialized hs_cache_client_intro_state_t
    656 * object. */
    657 static hs_cache_client_intro_state_t *
    658 cache_client_intro_state_new(void)
    659 {
    660  hs_cache_client_intro_state_t *cache = tor_malloc_zero(sizeof(*cache));
    661  cache->intro_points = digest256map_new();
    662  return cache;
    663 }
    664 
    665 #define cache_client_intro_state_free(val)              \
    666  FREE_AND_NULL(hs_cache_client_intro_state_t,          \
    667                cache_client_intro_state_free_, (val))
    668 
    669 /** Free a cache_client_intro_state object. */
    670 static void
    671 cache_client_intro_state_free_(hs_cache_client_intro_state_t *cache)
    672 {
    673  if (cache == NULL) {
    674    return;
    675  }
    676  digest256map_free(cache->intro_points, cache_intro_state_free_void);
    677  tor_free(cache);
    678 }
    679 
    680 /** Helper function: used by the free all function. */
    681 static void
    682 cache_client_intro_state_free_void(void *entry)
    683 {
    684  cache_client_intro_state_free_(entry);
    685 }
    686 
    687 /** For the given service identity key service_pk and an introduction
    688 * authentication key auth_key, lookup the intro state object. Return 1 if
    689 * found and put it in entry if not NULL. Return 0 if not found and entry is
    690 * untouched. */
    691 static int
    692 cache_client_intro_state_lookup(const ed25519_public_key_t *service_pk,
    693                                const ed25519_public_key_t *auth_key,
    694                                hs_cache_intro_state_t **entry)
    695 {
    696  hs_cache_intro_state_t *state;
    697  hs_cache_client_intro_state_t *cache;
    698 
    699  tor_assert(service_pk);
    700  tor_assert(auth_key);
    701  tor_assert_nonfatal(!ed25519_public_key_is_zero(service_pk));
    702  tor_assert_nonfatal(!ed25519_public_key_is_zero(auth_key));
    703 
    704  /* Lookup the intro state cache for this service key. */
    705  cache = digest256map_get(hs_cache_client_intro_state, service_pk->pubkey);
    706  if (cache == NULL) {
    707    goto not_found;
    708  }
    709 
    710  /* From the cache we just found for the service, lookup in the introduction
    711   * points map for the given authentication key. */
    712  state = digest256map_get(cache->intro_points, auth_key->pubkey);
    713  if (state == NULL) {
    714    goto not_found;
    715  }
    716  if (entry) {
    717    *entry = state;
    718  }
    719  return 1;
    720 not_found:
    721  return 0;
    722 }
    723 
    724 /** Note the given failure in state. */
    725 static void
    726 cache_client_intro_state_note(hs_cache_intro_state_t *state,
    727                              rend_intro_point_failure_t failure)
    728 {
    729  tor_assert(state);
    730  switch (failure) {
    731  case INTRO_POINT_FAILURE_GENERIC:
    732    state->error = 1;
    733    break;
    734  case INTRO_POINT_FAILURE_TIMEOUT:
    735    state->timed_out = 1;
    736    break;
    737  case INTRO_POINT_FAILURE_UNREACHABLE:
    738    state->unreachable_count++;
    739    break;
    740  default:
    741    tor_assert_nonfatal_unreached();
    742    return;
    743  }
    744 }
    745 
    746 /** For the given service identity key service_pk and an introduction
    747 * authentication key auth_key, add an entry in the client intro state cache
    748 * If no entry exists for the service, it will create one. If state is non
    749 * NULL, it will point to the new intro state entry. */
    750 static void
    751 cache_client_intro_state_add(const ed25519_public_key_t *service_pk,
    752                             const ed25519_public_key_t *auth_key,
    753                             hs_cache_intro_state_t **state)
    754 {
    755  hs_cache_intro_state_t *entry, *old_entry;
    756  hs_cache_client_intro_state_t *cache;
    757 
    758  tor_assert(service_pk);
    759  tor_assert(auth_key);
    760 
    761  /* Lookup the state cache for this service key. */
    762  cache = digest256map_get(hs_cache_client_intro_state, service_pk->pubkey);
    763  if (cache == NULL) {
    764    cache = cache_client_intro_state_new();
    765    digest256map_set(hs_cache_client_intro_state, service_pk->pubkey, cache);
    766  }
    767 
    768  entry = cache_intro_state_new();
    769  old_entry = digest256map_set(cache->intro_points, auth_key->pubkey, entry);
    770  /* This should never happened because the code flow is to lookup the entry
    771   * before adding it. But, just in case, non fatal assert and free it. */
    772  tor_assert_nonfatal(old_entry == NULL);
    773  tor_free(old_entry);
    774 
    775  if (state) {
    776    *state = entry;
    777  }
    778 }
    779 
    780 /** Remove every intro point state entry from cache that has been created
    781 * before or at the cutoff. */
    782 static void
    783 cache_client_intro_state_clean(time_t cutoff,
    784                               hs_cache_client_intro_state_t *cache)
    785 {
    786  tor_assert(cache);
    787 
    788  DIGEST256MAP_FOREACH_MODIFY(cache->intro_points, key,
    789                              hs_cache_intro_state_t *, entry) {
    790    if (entry->created_ts <= cutoff) {
    791      cache_intro_state_free(entry);
    792      MAP_DEL_CURRENT(key);
    793    }
    794  } DIGEST256MAP_FOREACH_END;
    795 }
    796 
    797 /** Return true iff no intro points are in this cache. */
    798 static int
    799 cache_client_intro_state_is_empty(const hs_cache_client_intro_state_t *cache)
    800 {
    801  return digest256map_isempty(cache->intro_points);
    802 }
    803 
    804 /** Check whether <b>client_desc</b> is useful for us, and store it in the
    805 *  client-side HS cache if so. The client_desc is freed if we already have a
    806 *  fresher (higher revision counter count) in the cache. */
    807 static int
    808 cache_store_as_client(hs_cache_client_descriptor_t *client_desc)
    809 {
    810  hs_cache_client_descriptor_t *cache_entry;
    811 
    812  /* TODO: Heavy code duplication with cache_store_as_dir(). Consider
    813   * refactoring and uniting! */
    814 
    815  tor_assert(client_desc);
    816 
    817  /* Check if we already have a descriptor from this HS in cache. If we do,
    818   * check if this descriptor is newer than the cached one only if we have a
    819   * decoded descriptor. We do keep non-decoded descriptor that requires
    820   * client authorization. */
    821  cache_entry = lookup_v3_desc_as_client(client_desc->key.pubkey);
    822  if (cache_entry != NULL) {
    823    /* If the current or the new cache entry don't have a decrypted descriptor
    824     * (missing client authorization), we always replace the current one with
    825     * the new one. Reason is that we can't inspect the revision counter
    826     * within the plaintext data so we blindly replace. */
    827    if (!entry_has_decrypted_descriptor(cache_entry) ||
    828        !entry_has_decrypted_descriptor(client_desc)) {
    829      remove_v3_desc_as_client(cache_entry);
    830      cache_client_desc_free(cache_entry);
    831      goto store;
    832    }
    833 
    834    /* From this point on, we know that the decrypted descriptor is in the
    835     * current entry and new object thus safe to access. */
    836 
    837    /* If we have an entry in our cache that has a revision counter greater
    838     * than the one we just fetched, discard the one we fetched. */
    839    if (cache_entry->desc->plaintext_data.revision_counter >
    840        client_desc->desc->plaintext_data.revision_counter) {
    841      cache_client_desc_free(client_desc);
    842      goto done;
    843    }
    844    /* Remove old entry. Make space for the new one! */
    845    remove_v3_desc_as_client(cache_entry);
    846 
    847    /* We just removed an old descriptor and will replace it. We'll close all
    848     * intro circuits related to this old one so we don't have leftovers. We
    849     * leave the rendezvous circuits opened because they could be in use. */
    850    hs_client_close_intro_circuits_from_desc(cache_entry->desc);
    851 
    852    /* Free it. */
    853    cache_client_desc_free(cache_entry);
    854  }
    855 
    856 store:
    857  /* Store descriptor in cache */
    858  store_v3_desc_as_client(client_desc);
    859 
    860 done:
    861  return 0;
    862 }
    863 
    864 /** Return true iff the cached client descriptor at <b>cached_desc</b> has
    865 * expired. */
    866 static int
    867 cached_client_descriptor_has_expired(time_t now,
    868                               const hs_cache_client_descriptor_t *cached_desc)
    869 {
    870  /* We use the current consensus time to see if we should expire this
    871   * descriptor since we use consensus time for all other parts of the protocol
    872   * as well (e.g. to build the blinded key and compute time periods). */
    873  const networkstatus_t *ns =
    874    networkstatus_get_reasonably_live_consensus(now,
    875      usable_consensus_flavor());
    876  /* If we don't have a recent consensus, consider this entry expired since we
    877   * will want to fetch a new HS desc when we get a live consensus. */
    878  if (!ns) {
    879    return 1;
    880  }
    881 
    882  if (cached_desc->expiration_ts <= ns->valid_after) {
    883    return 1;
    884  }
    885 
    886  return 0;
    887 }
    888 
    889 /** clean the client cache using now as the current time. Return the total size
    890 * of removed bytes from the cache. */
    891 static size_t
    892 cache_clean_v3_as_client(time_t now)
    893 {
    894  size_t bytes_removed = 0;
    895 
    896  if (!hs_cache_v3_client) { /* No cache to clean. Just return. */
    897    return 0;
    898  }
    899 
    900  DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_client, key,
    901                              hs_cache_client_descriptor_t *, entry) {
    902    size_t entry_size;
    903 
    904    /* If the entry has not expired, continue to the next cached entry */
    905    if (!cached_client_descriptor_has_expired(now, entry)) {
    906      continue;
    907    }
    908    /* Here, our entry has expired, remove and free. */
    909    MAP_DEL_CURRENT(key);
    910    entry_size = cache_get_client_entry_size(entry);
    911    bytes_removed += entry_size;
    912 
    913    /* We just removed an old descriptor. We need to close all intro circuits
    914     * if the descriptor is decrypted so we don't have leftovers that can be
    915     * selected while lacking a descriptor. Circuits are selected by intro
    916     * authentication key thus we need the descriptor. We leave the rendezvous
    917     * circuits opened because they could be in use. */
    918    if (entry_has_decrypted_descriptor(entry)) {
    919      hs_client_close_intro_circuits_from_desc(entry->desc);
    920    }
    921    /* Entry is not in the cache anymore, destroy it. */
    922    cache_client_desc_free(entry);
    923    /* Update our OOM. We didn't use the remove() function because we are in
    924     * a loop so we have to explicitly decrement. */
    925    hs_cache_decrement_allocation(entry_size);
    926    /* Logging. */
    927    {
    928      char key_b64[BASE64_DIGEST256_LEN + 1];
    929      digest256_to_base64(key_b64, (const char *) key);
    930      log_info(LD_REND, "Removing hidden service v3 descriptor '%s' "
    931                        "from client cache",
    932               safe_str_client(key_b64));
    933    }
    934  } DIGEST256MAP_FOREACH_END;
    935 
    936  return bytes_removed;
    937 }
    938 
    939 /** Public API: Given the HS ed25519 identity public key in <b>key</b>, return
    940 *  its HS encoded descriptor if it's stored in our cache, or NULL if not. */
    941 const char *
    942 hs_cache_lookup_encoded_as_client(const ed25519_public_key_t *key)
    943 {
    944  hs_cache_client_descriptor_t *cached_desc = NULL;
    945 
    946  tor_assert(key);
    947 
    948  cached_desc = lookup_v3_desc_as_client(key->pubkey);
    949  if (cached_desc) {
    950    tor_assert(cached_desc->encoded_desc);
    951    return cached_desc->encoded_desc;
    952  }
    953 
    954  return NULL;
    955 }
    956 
    957 /** Public API: Given the HS ed25519 identity public key in <b>key</b>, return
    958 *  its HS descriptor if it's stored in our cache, or NULL if not or if the
    959 *  descriptor was never decrypted. The later can happen if we are waiting for
    960 *  client authorization to be added. */
    961 const hs_descriptor_t *
    962 hs_cache_lookup_as_client(const ed25519_public_key_t *key)
    963 {
    964  hs_cache_client_descriptor_t *cached_desc = NULL;
    965 
    966  tor_assert(key);
    967 
    968  cached_desc = lookup_v3_desc_as_client(key->pubkey);
    969  if (cached_desc && entry_has_decrypted_descriptor(cached_desc)) {
    970    return cached_desc->desc;
    971  }
    972 
    973  return NULL;
    974 }
    975 
    976 /** Public API: Given an encoded descriptor, store it in the client HS cache.
    977 *  Return a decode status which changes how we handle the SOCKS connection
    978 *  depending on its value:
    979 *
    980 *  HS_DESC_DECODE_OK: Returned on success. Descriptor was properly decoded
    981 *                     and is now stored.
    982 *
    983 *  HS_DESC_DECODE_NEED_CLIENT_AUTH: Client authorization is needed but the
    984 *                                   descriptor was still stored.
    985 *
    986 *  HS_DESC_DECODE_BAD_CLIENT_AUTH: Client authorization for this descriptor
    987 *                                  was not usable but the descriptor was
    988 *                                  still stored.
    989 *
    990 *  Any other codes means indicate where the error occurred and the descriptor
    991 *  was not stored. */
    992 hs_desc_decode_status_t
    993 hs_cache_store_as_client(const char *desc_str,
    994                         const ed25519_public_key_t *identity_pk)
    995 {
    996  hs_desc_decode_status_t ret;
    997  hs_cache_client_descriptor_t *client_desc = NULL;
    998 
    999  tor_assert(desc_str);
   1000  tor_assert(identity_pk);
   1001 
   1002  /* Create client cache descriptor object */
   1003  client_desc = cache_client_desc_new(desc_str, identity_pk, &ret);
   1004  if (!client_desc) {
   1005    log_warn(LD_GENERAL, "HSDesc parsing failed!");
   1006    log_debug(LD_GENERAL, "Failed to parse HSDesc: %s.", escaped(desc_str));
   1007    goto err;
   1008  }
   1009 
   1010  /* Push it to the cache */
   1011  if (cache_store_as_client(client_desc) < 0) {
   1012    ret = HS_DESC_DECODE_GENERIC_ERROR;
   1013    goto err;
   1014  }
   1015 
   1016  return ret;
   1017 
   1018 err:
   1019  cache_client_desc_free(client_desc);
   1020  return ret;
   1021 }
   1022 
   1023 /** Remove and free a client cache descriptor entry for the given onion
   1024 * service ed25519 public key. If the descriptor is decoded, the intro
   1025 * circuits are closed if any.
   1026 *
   1027 * This does nothing if no descriptor exists for the given key. */
   1028 void
   1029 hs_cache_remove_as_client(const ed25519_public_key_t *key)
   1030 {
   1031  hs_cache_client_descriptor_t *cached_desc = NULL;
   1032 
   1033  tor_assert(key);
   1034 
   1035  cached_desc = lookup_v3_desc_as_client(key->pubkey);
   1036  if (!cached_desc) {
   1037    return;
   1038  }
   1039  /* If we have a decrypted/decoded descriptor, attempt to close its
   1040   * introduction circuit(s). We shouldn't have circuit(s) without a
   1041   * descriptor else it will lead to a failure. */
   1042  if (entry_has_decrypted_descriptor(cached_desc)) {
   1043    hs_client_close_intro_circuits_from_desc(cached_desc->desc);
   1044  }
   1045  /* Remove and free. */
   1046  remove_v3_desc_as_client(cached_desc);
   1047  cache_client_desc_free(cached_desc);
   1048 
   1049  /* Logging. */
   1050  {
   1051    char key_b64[BASE64_DIGEST256_LEN + 1];
   1052    digest256_to_base64(key_b64, (const char *) key);
   1053    log_info(LD_REND, "Onion service v3 descriptor '%s' removed "
   1054                      "from client cache",
   1055             safe_str_client(key_b64));
   1056  }
   1057 }
   1058 
   1059 /** Clean all client caches using the current time now. */
   1060 void
   1061 hs_cache_clean_as_client(time_t now)
   1062 {
   1063  /* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function
   1064   * to compute the cutoff by itself using the lifetime value. */
   1065  cache_clean_v3_as_client(now);
   1066 }
   1067 
   1068 /** Purge the client descriptor cache. */
   1069 void
   1070 hs_cache_purge_as_client(void)
   1071 {
   1072  DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_client, key,
   1073                              hs_cache_client_descriptor_t *, entry) {
   1074    size_t entry_size = cache_get_client_entry_size(entry);
   1075    MAP_DEL_CURRENT(key);
   1076    cache_client_desc_free(entry);
   1077    /* Update our OOM. We didn't use the remove() function because we are in
   1078     * a loop so we have to explicitly decrement. */
   1079    hs_cache_decrement_allocation(entry_size);
   1080  } DIGEST256MAP_FOREACH_END;
   1081 
   1082  log_info(LD_REND, "Hidden service client descriptor cache purged.");
   1083 }
   1084 
   1085 /** For a given service identity public key and an introduction authentication
   1086 * key, note the given failure in the client intro state cache. */
   1087 void
   1088 hs_cache_client_intro_state_note(const ed25519_public_key_t *service_pk,
   1089                                 const ed25519_public_key_t *auth_key,
   1090                                 rend_intro_point_failure_t failure)
   1091 {
   1092  int found;
   1093  hs_cache_intro_state_t *entry;
   1094 
   1095  tor_assert(service_pk);
   1096  tor_assert(auth_key);
   1097 
   1098  found = cache_client_intro_state_lookup(service_pk, auth_key, &entry);
   1099  if (!found) {
   1100    /* Create a new entry and add it to the cache. */
   1101    cache_client_intro_state_add(service_pk, auth_key, &entry);
   1102  }
   1103  /* Note down the entry. */
   1104  cache_client_intro_state_note(entry, failure);
   1105 }
   1106 
   1107 /** For a given service identity public key and an introduction authentication
   1108 * key, return true iff it is present in the failure cache. */
   1109 const hs_cache_intro_state_t *
   1110 hs_cache_client_intro_state_find(const ed25519_public_key_t *service_pk,
   1111                                 const ed25519_public_key_t *auth_key)
   1112 {
   1113  hs_cache_intro_state_t *state = NULL;
   1114  cache_client_intro_state_lookup(service_pk, auth_key, &state);
   1115  return state;
   1116 }
   1117 
   1118 /** Cleanup the client introduction state cache. */
   1119 void
   1120 hs_cache_client_intro_state_clean(time_t now)
   1121 {
   1122  time_t cutoff = now - HS_CACHE_CLIENT_INTRO_STATE_MAX_AGE;
   1123 
   1124  DIGEST256MAP_FOREACH_MODIFY(hs_cache_client_intro_state, key,
   1125                              hs_cache_client_intro_state_t *, cache) {
   1126    /* Cleanup intro points failure. */
   1127    cache_client_intro_state_clean(cutoff, cache);
   1128 
   1129    /* Is this cache empty for this service key? If yes, remove it from the
   1130     * cache. Else keep it. */
   1131    if (cache_client_intro_state_is_empty(cache)) {
   1132      cache_client_intro_state_free(cache);
   1133      MAP_DEL_CURRENT(key);
   1134    }
   1135  } DIGEST256MAP_FOREACH_END;
   1136 }
   1137 
   1138 /** Purge the client introduction state cache. */
   1139 void
   1140 hs_cache_client_intro_state_purge(void)
   1141 {
   1142  DIGEST256MAP_FOREACH_MODIFY(hs_cache_client_intro_state, key,
   1143                              hs_cache_client_intro_state_t *, cache) {
   1144    MAP_DEL_CURRENT(key);
   1145    cache_client_intro_state_free(cache);
   1146  } DIGEST256MAP_FOREACH_END;
   1147 
   1148  log_info(LD_REND, "Hidden service client introduction point state "
   1149                    "cache purged.");
   1150 }
   1151 
   1152 /* This is called when new client authorization was added to the global state.
   1153 * It attempts to decode the descriptor of the given service identity key.
   1154 *
   1155 * Return true if decoding was successful else false. */
   1156 bool
   1157 hs_cache_client_new_auth_parse(const ed25519_public_key_t *service_pk)
   1158 {
   1159  bool ret = false;
   1160  hs_cache_client_descriptor_t *cached_desc = NULL;
   1161 
   1162  tor_assert(service_pk);
   1163 
   1164  if (!hs_cache_v3_client) {
   1165    return false;
   1166  }
   1167 
   1168  cached_desc = lookup_v3_desc_as_client(service_pk->pubkey);
   1169  if (cached_desc == NULL || entry_has_decrypted_descriptor(cached_desc)) {
   1170    /* No entry for that service or the descriptor is already decoded. */
   1171    goto end;
   1172  }
   1173 
   1174  /* Attempt a decode. If we are successful, inform the caller. */
   1175  if (hs_client_decode_descriptor(cached_desc->encoded_desc, service_pk,
   1176                                  &cached_desc->desc) == HS_DESC_DECODE_OK) {
   1177    ret = true;
   1178  }
   1179 
   1180 end:
   1181  return ret;
   1182 }
   1183 
   1184 /**************** Generics *********************************/
   1185 
   1186 /** Do a round of OOM cleanup on all directory caches. Return the amount of
   1187 * removed bytes. It is possible that the returned value is lower than
   1188 * min_remove_bytes if the caches get emptied out so the caller should be
   1189 * aware of this. */
   1190 size_t
   1191 hs_cache_handle_oom(size_t min_remove_bytes)
   1192 {
   1193  size_t bytes_removed = 0;
   1194  /* The downloaded counter value to remove. Start at 0 and increment to the
   1195   * next lowest value in the cache. */
   1196  uint64_t target = 0;
   1197 
   1198  /* Our OOM handler called with 0 bytes to remove is a code flow error. */
   1199  tor_assert(min_remove_bytes != 0);
   1200 
   1201  /* Loop until we have an empty cache or we have removed enough bytes. */
   1202  do {
   1203    /* This is valid due to the loop condition. At the start, min_remove_bytes
   1204     * can't be 0. */
   1205    size_t bytes_to_free = (min_remove_bytes - bytes_removed);
   1206    size_t bytes_freed =
   1207      cache_clean_v3_by_downloaded_as_dir(target, bytes_to_free, &target);
   1208    if (bytes_freed == 0 && target == 0) {
   1209      /* Indicate that the cache is empty. */
   1210      break;
   1211    }
   1212    bytes_removed += bytes_freed;
   1213  } while (bytes_removed < min_remove_bytes);
   1214 
   1215  return bytes_removed;
   1216 }
   1217 
   1218 /** Return the maximum size of a v3 HS descriptor. */
   1219 unsigned int
   1220 hs_cache_get_max_descriptor_size(void)
   1221 {
   1222  return (unsigned) networkstatus_get_param(NULL,
   1223                                            "HSV3MaxDescriptorSize",
   1224                                            HS_DESC_MAX_LEN, 1, INT32_MAX);
   1225 }
   1226 
   1227 /** Initialize the hidden service cache subsystem. */
   1228 void
   1229 hs_cache_init(void)
   1230 {
   1231  /* Calling this twice is very wrong code flow. */
   1232  tor_assert(!hs_cache_v3_dir);
   1233  hs_cache_v3_dir = digest256map_new();
   1234 
   1235  tor_assert(!hs_cache_v3_client);
   1236  hs_cache_v3_client = digest256map_new();
   1237 
   1238  tor_assert(!hs_cache_client_intro_state);
   1239  hs_cache_client_intro_state = digest256map_new();
   1240 }
   1241 
   1242 /** Cleanup the hidden service cache subsystem. */
   1243 void
   1244 hs_cache_free_all(void)
   1245 {
   1246  digest256map_free(hs_cache_v3_dir, cache_dir_desc_free_void);
   1247  hs_cache_v3_dir = NULL;
   1248 
   1249  digest256map_free(hs_cache_v3_client, cache_client_desc_free_void);
   1250  hs_cache_v3_client = NULL;
   1251 
   1252  digest256map_free(hs_cache_client_intro_state,
   1253                    cache_client_intro_state_free_void);
   1254  hs_cache_client_intro_state = NULL;
   1255  hs_cache_total_allocation = 0;
   1256 }
   1257 
   1258 /** Get the configured maximum cache size. */
   1259 uint64_t
   1260 hs_cache_get_max_bytes(void)
   1261 {
   1262  uint64_t opt = get_options()->MaxHSDirCacheBytes;
   1263  return opt != 0 ? opt : get_options()->MaxMemInQueues / 5;
   1264 }
   1265 
   1266 /* Return total size of the cache. */
   1267 size_t
   1268 hs_cache_get_total_allocation(void)
   1269 {
   1270  return hs_cache_total_allocation;
   1271 }
   1272 
   1273 /** Decrement the total bytes attributed to the rendezvous cache by n. */
   1274 void
   1275 hs_cache_decrement_allocation(size_t n)
   1276 {
   1277  static int have_underflowed = 0;
   1278 
   1279  if (hs_cache_total_allocation >= n) {
   1280    hs_cache_total_allocation -= n;
   1281  } else {
   1282    hs_cache_total_allocation = 0;
   1283    if (! have_underflowed) {
   1284      have_underflowed = 1;
   1285      log_warn(LD_BUG, "Underflow in hs_cache_decrement_allocation");
   1286    }
   1287  }
   1288 }
   1289 
   1290 /** Increase the total bytes attributed to the rendezvous cache by n. */
   1291 void
   1292 hs_cache_increment_allocation(size_t n)
   1293 {
   1294  static int have_overflowed = 0;
   1295  if (hs_cache_total_allocation <= SIZE_MAX - n) {
   1296    hs_cache_total_allocation += n;
   1297  } else {
   1298    hs_cache_total_allocation = SIZE_MAX;
   1299    if (! have_overflowed) {
   1300      have_overflowed = 1;
   1301      log_warn(LD_BUG, "Overflow in hs_cache_increment_allocation");
   1302    }
   1303  }
   1304 }
   1305 
   1306 #ifdef TOR_UNIT_TESTS
   1307 
   1308 /** Test only: Set the downloaded counter value of a HSDir cache entry. */
   1309 void
   1310 dir_set_downloaded(const ed25519_public_key_t *pk, uint64_t value)
   1311 {
   1312  hs_cache_dir_descriptor_t *entry = lookup_v3_desc_as_dir(pk->pubkey);
   1313  if (entry) {
   1314    entry->n_downloaded = value;
   1315  }
   1316 }
   1317 
   1318 #endif /* TOR_UNIT_TESTS */