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 */