1 /* Copyright (c) 2009-2017, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
7 * \brief Implements microdescriptors -- an abbreviated description of
8 * less-frequently-changing router information.
12 #include "circuitbuild.h"
14 #include "directory.h"
16 #include "entrynodes.h"
17 #include "microdesc.h"
18 #include "networkstatus.h"
22 #include "routerlist.h"
23 #include "routerparse.h"
25 /** A data structure to hold a bunch of cached microdescriptors. There are
26 * two active files in the cache: a "cache file" that we mmap, and a "journal
27 * file" that we append to. Periodically, we rebuild the cache file to hold
28 * only the microdescriptors that we want to keep */
29 struct microdesc_cache_t
{
30 /** Map from sha256-digest to microdesc_t for every microdesc_t in the
32 HT_HEAD(microdesc_map
, microdesc_t
) map
;
34 /** Name of the cache file. */
36 /** Name of the journal file. */
38 /** Mmap'd contents of the cache file, or NULL if there is none. */
39 tor_mmap_t
*cache_content
;
40 /** Number of bytes used in the journal file. */
42 /** Number of bytes in descriptors removed as too old. */
45 /** Total bytes of microdescriptor bodies we have added to this cache */
46 uint64_t total_len_seen
;
47 /** Total number of microdescriptors we have added to this cache */
50 /** True iff we have loaded this cache from disk ever. */
54 static microdesc_cache_t
*get_microdesc_cache_noload(void);
56 /** Helper: computes a hash of <b>md</b> to place it in a hash table. */
57 static inline unsigned int
58 microdesc_hash_(microdesc_t
*md
)
60 return (unsigned) siphash24g(md
->digest
, sizeof(md
->digest
));
63 /** Helper: compares <b>a</b> and <b>b</b> for equality for hash-table
66 microdesc_eq_(microdesc_t
*a
, microdesc_t
*b
)
68 return tor_memeq(a
->digest
, b
->digest
, DIGEST256_LEN
);
71 HT_PROTOTYPE(microdesc_map
, microdesc_t
, node
,
72 microdesc_hash_
, microdesc_eq_
)
73 HT_GENERATE2(microdesc_map
, microdesc_t
, node
,
74 microdesc_hash_
, microdesc_eq_
, 0.6,
75 tor_reallocarray_
, tor_free_
)
77 /************************* md fetch fail cache *****************************/
79 /* If we end up with too many outdated dirservers, something probably went
80 * wrong so clean up the list. */
81 #define TOO_MANY_OUTDATED_DIRSERVERS 30
83 /** List of dirservers with outdated microdesc information. The smartlist is
84 * filled with the hex digests of outdated dirservers. */
85 static smartlist_t
*outdated_dirserver_list
= NULL
;
87 /** Note that we failed to fetch a microdescriptor from the relay with
88 * <b>relay_digest</b> (of size DIGEST_LEN). */
90 microdesc_note_outdated_dirserver(const char *relay_digest
)
92 char relay_hexdigest
[HEX_DIGEST_LEN
+1];
94 /* Don't register outdated dirservers if we don't have a live consensus,
95 * since we might be trying to fetch microdescriptors that are not even
96 * currently active. */
97 if (!networkstatus_get_live_consensus(approx_time())) {
101 if (!outdated_dirserver_list
) {
102 outdated_dirserver_list
= smartlist_new();
105 tor_assert(outdated_dirserver_list
);
107 /* If the list grows too big, clean it up */
108 if (BUG(smartlist_len(outdated_dirserver_list
) >
109 TOO_MANY_OUTDATED_DIRSERVERS
)) {
110 microdesc_reset_outdated_dirservers_list();
113 /* Turn the binary relay digest to a hex since smartlists have better support
114 * for strings than digests. */
115 base16_encode(relay_hexdigest
,sizeof(relay_hexdigest
),
116 relay_digest
, DIGEST_LEN
);
118 /* Make sure we don't add a dirauth as an outdated dirserver */
119 if (router_get_trusteddirserver_by_digest(relay_digest
)) {
120 log_info(LD_GENERAL
, "Auth %s gave us outdated dirinfo.", relay_hexdigest
);
124 /* Don't double-add outdated dirservers */
125 if (smartlist_contains_string(outdated_dirserver_list
, relay_hexdigest
)) {
129 /* Add it to the list of outdated dirservers */
130 smartlist_add_strdup(outdated_dirserver_list
, relay_hexdigest
);
132 log_info(LD_GENERAL
, "Noted %s as outdated md dirserver", relay_hexdigest
);
135 /** Return True if the relay with <b>relay_digest</b> (size DIGEST_LEN) is an
136 * outdated dirserver */
138 microdesc_relay_is_outdated_dirserver(const char *relay_digest
)
140 char relay_hexdigest
[HEX_DIGEST_LEN
+1];
142 if (!outdated_dirserver_list
) {
146 /* Convert identity digest to hex digest */
147 base16_encode(relay_hexdigest
, sizeof(relay_hexdigest
),
148 relay_digest
, DIGEST_LEN
);
150 /* Last time we tried to fetch microdescs, was this directory mirror missing
151 * any mds we asked for? */
152 if (smartlist_contains_string(outdated_dirserver_list
, relay_hexdigest
)) {
159 /** Reset the list of outdated dirservers. */
161 microdesc_reset_outdated_dirservers_list(void)
163 if (!outdated_dirserver_list
) {
167 SMARTLIST_FOREACH(outdated_dirserver_list
, char *, cp
, tor_free(cp
));
168 smartlist_clear(outdated_dirserver_list
);
171 /****************************************************************************/
173 /** Write the body of <b>md</b> into <b>f</b>, with appropriate annotations.
174 * On success, return the total number of bytes written, and set
175 * *<b>annotation_len_out</b> to the number of bytes written as
178 dump_microdescriptor(int fd
, microdesc_t
*md
, size_t *annotation_len_out
)
182 if (md
->body
== NULL
) {
183 *annotation_len_out
= 0;
186 /* XXXX drops unknown annotations. */
187 if (md
->last_listed
) {
188 char buf
[ISO_TIME_LEN
+1];
189 char annotation
[ISO_TIME_LEN
+32];
190 format_iso_time(buf
, md
->last_listed
);
191 tor_snprintf(annotation
, sizeof(annotation
), "@last-listed %s\n", buf
);
192 if (write_all(fd
, annotation
, strlen(annotation
), 0) < 0) {
194 "Couldn't write microdescriptor annotation: %s",
198 r
+= strlen(annotation
);
199 *annotation_len_out
= r
;
201 *annotation_len_out
= 0;
204 md
->off
= tor_fd_getpos(fd
);
205 written
= write_all(fd
, md
->body
, md
->bodylen
, 0);
206 if (written
!= (ssize_t
)md
->bodylen
) {
207 written
= written
< 0 ? 0 : written
;
209 "Couldn't dump microdescriptor (wrote %ld out of %lu): %s",
210 (long)written
, (unsigned long)md
->bodylen
,
218 /** Holds a pointer to the current microdesc_cache_t object, or NULL if no
219 * such object has been allocated. */
220 static microdesc_cache_t
*the_microdesc_cache
= NULL
;
222 /** Return a pointer to the microdescriptor cache, loading it if necessary. */
224 get_microdesc_cache(void)
226 microdesc_cache_t
*cache
= get_microdesc_cache_noload();
227 if (PREDICT_UNLIKELY(cache
->is_loaded
== 0)) {
228 microdesc_cache_reload(cache
);
233 /** Return a pointer to the microdescriptor cache, creating (but not loading)
234 * it if necessary. */
235 static microdesc_cache_t
*
236 get_microdesc_cache_noload(void)
238 if (PREDICT_UNLIKELY(the_microdesc_cache
==NULL
)) {
239 microdesc_cache_t
*cache
= tor_malloc_zero(sizeof(*cache
));
240 HT_INIT(microdesc_map
, &cache
->map
);
241 cache
->cache_fname
= get_cachedir_fname("cached-microdescs");
242 cache
->journal_fname
= get_cachedir_fname("cached-microdescs.new");
243 the_microdesc_cache
= cache
;
245 return the_microdesc_cache
;
248 /* There are three sources of microdescriptors:
249 1) Generated by us while acting as a directory authority.
250 2) Loaded from the cache on disk.
254 /** Decode the microdescriptors from the string starting at <b>s</b> and
255 * ending at <b>eos</b>, and store them in <b>cache</b>. If <b>no_save</b>,
256 * mark them as non-writable to disk. If <b>where</b> is SAVED_IN_CACHE,
257 * leave their bodies as pointers to the mmap'd cache. If where is
258 * <b>SAVED_NOWHERE</b>, do not allow annotations. If listed_at is not -1,
259 * set the last_listed field of every microdesc to listed_at. If
260 * requested_digests is non-null, then it contains a list of digests we mean
261 * to allow, so we should reject any non-requested microdesc with a different
262 * digest, and alter the list to contain only the digests of those microdescs
264 * Return a newly allocated list of the added microdescriptors, or NULL */
266 microdescs_add_to_cache(microdesc_cache_t
*cache
,
267 const char *s
, const char *eos
, saved_location_t where
,
268 int no_save
, time_t listed_at
,
269 smartlist_t
*requested_digests256
)
271 void * const DIGEST_REQUESTED
= (void*)1;
272 void * const DIGEST_RECEIVED
= (void*)2;
273 void * const DIGEST_INVALID
= (void*)3;
275 smartlist_t
*descriptors
, *added
;
276 const int allow_annotations
= (where
!= SAVED_NOWHERE
);
277 smartlist_t
*invalid_digests
= smartlist_new();
279 descriptors
= microdescs_parse_from_string(s
, eos
,
281 where
, invalid_digests
);
282 if (listed_at
!= (time_t)-1) {
283 SMARTLIST_FOREACH(descriptors
, microdesc_t
*, md
,
284 md
->last_listed
= listed_at
);
286 if (requested_digests256
) {
287 digest256map_t
*requested
;
288 requested
= digest256map_new();
289 /* Set requested[d] to DIGEST_REQUESTED for every md we requested. */
290 SMARTLIST_FOREACH(requested_digests256
, const uint8_t *, cp
,
291 digest256map_set(requested
, cp
, DIGEST_REQUESTED
));
292 /* Set requested[d] to DIGEST_INVALID for every md we requested which we
293 * will never be able to parse. Remove the ones we didn't request from
296 SMARTLIST_FOREACH_BEGIN(invalid_digests
, uint8_t *, cp
) {
297 if (digest256map_get(requested
, cp
)) {
298 digest256map_set(requested
, cp
, DIGEST_INVALID
);
301 SMARTLIST_DEL_CURRENT(invalid_digests
, cp
);
303 } SMARTLIST_FOREACH_END(cp
);
304 /* Update requested[d] to 2 for the mds we asked for and got. Delete the
305 * ones we never requested from the 'descriptors' smartlist.
307 SMARTLIST_FOREACH_BEGIN(descriptors
, microdesc_t
*, md
) {
308 if (digest256map_get(requested
, (const uint8_t*)md
->digest
)) {
309 digest256map_set(requested
, (const uint8_t*)md
->digest
,
312 log_fn(LOG_PROTOCOL_WARN
, LD_DIR
, "Received non-requested microdesc");
314 SMARTLIST_DEL_CURRENT(descriptors
, md
);
316 } SMARTLIST_FOREACH_END(md
);
317 /* Remove the ones we got or the invalid ones from requested_digests256.
319 SMARTLIST_FOREACH_BEGIN(requested_digests256
, uint8_t *, cp
) {
320 void *status
= digest256map_get(requested
, cp
);
321 if (status
== DIGEST_RECEIVED
|| status
== DIGEST_INVALID
) {
323 SMARTLIST_DEL_CURRENT(requested_digests256
, cp
);
325 } SMARTLIST_FOREACH_END(cp
);
326 digest256map_free(requested
, NULL
);
329 /* For every requested microdescriptor that was unparseable, mark it
330 * as not to be retried. */
331 if (smartlist_len(invalid_digests
)) {
332 networkstatus_t
*ns
=
333 networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC
);
335 SMARTLIST_FOREACH_BEGIN(invalid_digests
, char *, d
) {
337 router_get_mutable_consensus_status_by_descriptor_digest(ns
, d
);
338 if (rs
&& tor_memeq(d
, rs
->descriptor_digest
, DIGEST256_LEN
)) {
339 download_status_mark_impossible(&rs
->dl_status
);
341 } SMARTLIST_FOREACH_END(d
);
344 SMARTLIST_FOREACH(invalid_digests
, uint8_t *, d
, tor_free(d
));
345 smartlist_free(invalid_digests
);
347 added
= microdescs_add_list_to_cache(cache
, descriptors
, where
, no_save
);
348 smartlist_free(descriptors
);
352 /** As microdescs_add_to_cache, but takes a list of microdescriptors instead of
353 * a string to decode. Frees any members of <b>descriptors</b> that it does
356 microdescs_add_list_to_cache(microdesc_cache_t
*cache
,
357 smartlist_t
*descriptors
, saved_location_t where
,
361 open_file_t
*open_file
= NULL
;
366 if (where
== SAVED_NOWHERE
&& !no_save
) {
367 fd
= start_writing_to_file(cache
->journal_fname
,
368 OPEN_FLAGS_APPEND
|O_BINARY
,
371 log_warn(LD_DIR
, "Couldn't append to journal in %s: %s",
372 cache
->journal_fname
, strerror(errno
));
376 added
= smartlist_new();
377 SMARTLIST_FOREACH_BEGIN(descriptors
, microdesc_t
*, md
) {
379 md2
= HT_FIND(microdesc_map
, &cache
->map
, md
);
381 /* We already had this one. */
382 if (md2
->last_listed
< md
->last_listed
)
383 md2
->last_listed
= md
->last_listed
;
385 if (where
!= SAVED_NOWHERE
)
386 cache
->bytes_dropped
+= size
;
390 /* Okay, it's a new one. */
392 size_t annotation_len
;
393 size
= dump_microdescriptor(fd
, md
, &annotation_len
);
395 /* we already warned in dump_microdescriptor */
396 abort_writing_to_file(open_file
);
399 md
->saved_location
= SAVED_IN_JOURNAL
;
400 cache
->journal_len
+= size
;
403 md
->saved_location
= where
;
406 md
->no_save
= no_save
;
408 HT_INSERT(microdesc_map
, &cache
->map
, md
);
410 smartlist_add(added
, md
);
412 cache
->total_len_seen
+= md
->bodylen
;
413 } SMARTLIST_FOREACH_END(md
);
416 if (finish_writing_to_file(open_file
) < 0) {
417 log_warn(LD_DIR
, "Error appending to microdescriptor file: %s",
419 smartlist_clear(added
);
425 networkstatus_t
*ns
= networkstatus_get_latest_consensus();
426 if (ns
&& ns
->flavor
== FLAV_MICRODESC
)
427 SMARTLIST_FOREACH(added
, microdesc_t
*, md
, nodelist_add_microdesc(md
));
430 if (smartlist_len(added
))
431 router_dir_info_changed();
436 /** Remove every microdescriptor in <b>cache</b>. */
438 microdesc_cache_clear(microdesc_cache_t
*cache
)
440 microdesc_t
**entry
, **next
;
442 for (entry
= HT_START(microdesc_map
, &cache
->map
); entry
; entry
= next
) {
443 microdesc_t
*md
= *entry
;
444 next
= HT_NEXT_RMV(microdesc_map
, &cache
->map
, entry
);
448 HT_CLEAR(microdesc_map
, &cache
->map
);
449 if (cache
->cache_content
) {
450 int res
= tor_munmap_file(cache
->cache_content
);
453 "tor_munmap_file() failed clearing microdesc cache; "
454 "we are probably about to leak memory.");
455 /* TODO something smarter? */
457 cache
->cache_content
= NULL
;
459 cache
->total_len_seen
= 0;
461 cache
->bytes_dropped
= 0;
464 /** Reload the contents of <b>cache</b> from disk. If it is empty, load it
465 * for the first time. Return 0 on success, -1 on failure. */
467 microdesc_cache_reload(microdesc_cache_t
*cache
)
470 char *journal_content
;
475 microdesc_cache_clear(cache
);
477 cache
->is_loaded
= 1;
479 mm
= cache
->cache_content
= tor_mmap_file(cache
->cache_fname
);
481 added
= microdescs_add_to_cache(cache
, mm
->data
, mm
->data
+mm
->size
,
482 SAVED_IN_CACHE
, 0, -1, NULL
);
484 total
+= smartlist_len(added
);
485 smartlist_free(added
);
489 journal_content
= read_file_to_str(cache
->journal_fname
,
490 RFTS_IGNORE_MISSING
, &st
);
491 if (journal_content
) {
492 cache
->journal_len
= (size_t) st
.st_size
;
493 added
= microdescs_add_to_cache(cache
, journal_content
,
494 journal_content
+st
.st_size
,
495 SAVED_IN_JOURNAL
, 0, -1, NULL
);
497 total
+= smartlist_len(added
);
498 smartlist_free(added
);
500 tor_free(journal_content
);
502 log_info(LD_DIR
, "Reloaded microdescriptor cache. Found %d descriptors.",
505 microdesc_cache_rebuild(cache
, 0 /* don't force */);
510 /** By default, we remove any microdescriptors that have gone at least this
511 * long without appearing in a current consensus. */
512 #define TOLERATE_MICRODESC_AGE (7*24*60*60)
514 /** Remove all microdescriptors from <b>cache</b> that haven't been listed for
515 * a long time. Does not rebuild the cache on disk. If <b>cutoff</b> is
516 * positive, specifically remove microdescriptors that have been unlisted
517 * since <b>cutoff</b>. If <b>force</b> is true, remove microdescriptors even
518 * if we have no current live microdescriptor consensus.
521 microdesc_cache_clean(microdesc_cache_t
*cache
, time_t cutoff
, int force
)
523 microdesc_t
**mdp
, *victim
;
524 int dropped
=0, kept
=0;
525 size_t bytes_dropped
= 0;
526 time_t now
= time(NULL
);
528 /* If we don't know a live consensus, don't believe last_listed values: we
529 * might be starting up after being down for a while. */
531 ! networkstatus_get_reasonably_live_consensus(now
, FLAV_MICRODESC
))
535 cutoff
= now
- TOLERATE_MICRODESC_AGE
;
537 for (mdp
= HT_START(microdesc_map
, &cache
->map
); mdp
!= NULL
; ) {
538 const int is_old
= (*mdp
)->last_listed
< cutoff
;
539 const unsigned held_by_nodes
= (*mdp
)->held_by_nodes
;
540 if (is_old
&& !held_by_nodes
) {
543 mdp
= HT_NEXT_RMV(microdesc_map
, &cache
->map
, mdp
);
544 victim
->held_in_map
= 0;
545 bytes_dropped
+= victim
->bodylen
;
546 microdesc_free(victim
);
549 /* It's old, but it has held_by_nodes set. That's not okay. */
550 /* Let's try to diagnose and fix #7164 . */
551 smartlist_t
*nodes
= nodelist_find_nodes_with_microdesc(*mdp
);
552 const networkstatus_t
*ns
= networkstatus_get_latest_consensus();
553 long networkstatus_age
= -1;
554 const int ht_badness
= HT_REP_IS_BAD_(microdesc_map
, &cache
->map
);
556 networkstatus_age
= now
- ns
->valid_after
;
558 log_warn(LD_BUG
, "Microdescriptor seemed very old "
559 "(last listed %d hours ago vs %d hour cutoff), but is still "
560 "marked as being held by %d node(s). I found %d node(s) "
561 "holding it. Current networkstatus is %ld hours old. "
562 "Hashtable badness is %d.",
563 (int)((now
- (*mdp
)->last_listed
) / 3600),
564 (int)((now
- cutoff
) / 3600),
566 smartlist_len(nodes
),
567 networkstatus_age
/ 3600,
570 SMARTLIST_FOREACH_BEGIN(nodes
, const node_t
*, node
) {
571 const char *rs_match
= "No RS";
572 const char *rs_present
= "";
574 if (tor_memeq(node
->rs
->descriptor_digest
,
575 (*mdp
)->digest
, DIGEST256_LEN
)) {
576 rs_match
= "Microdesc digest in RS matches";
578 rs_match
= "Microdesc digest in RS does match";
581 /* This should be impossible, but let's see! */
582 rs_present
= " RS not present in networkstatus.";
583 SMARTLIST_FOREACH(ns
->routerstatus_list
, routerstatus_t
*,rs
, {
584 if (rs
== node
->rs
) {
585 rs_present
= " RS okay in networkstatus.";
590 log_warn(LD_BUG
, " [%d]: ID=%s. md=%p, rs=%p, ri=%p. %s.%s",
592 hex_str(node
->identity
, DIGEST_LEN
),
593 node
->md
, node
->rs
, node
->ri
, rs_match
, rs_present
);
594 } SMARTLIST_FOREACH_END(node
);
595 smartlist_free(nodes
);
596 (*mdp
)->last_listed
= now
;
600 mdp
= HT_NEXT(microdesc_map
, &cache
->map
, mdp
);
605 log_info(LD_DIR
, "Removed %d/%d microdescriptors as old.",
606 dropped
,dropped
+kept
);
607 cache
->bytes_dropped
+= bytes_dropped
;
612 should_rebuild_md_cache(microdesc_cache_t
*cache
)
614 const size_t old_len
=
615 cache
->cache_content
? cache
->cache_content
->size
: 0;
616 const size_t journal_len
= cache
->journal_len
;
617 const size_t dropped
= cache
->bytes_dropped
;
619 if (journal_len
< 16384)
620 return 0; /* Don't bother, not enough has happened yet. */
621 if (dropped
> (journal_len
+ old_len
) / 3)
622 return 1; /* We could save 1/3 or more of the currently used space. */
623 if (journal_len
> old_len
/ 2)
624 return 1; /* We should append to the regular file */
630 * Mark <b>md</b> as having no body, and release any storage previously held
634 microdesc_wipe_body(microdesc_t
*md
)
639 if (md
->saved_location
!= SAVED_IN_CACHE
)
643 md
->saved_location
= SAVED_NOWHERE
;
649 /** Regenerate the main cache file for <b>cache</b>, clear the journal file,
650 * and update every microdesc_t in the cache with pointers to its new
651 * location. If <b>force</b> is true, do this unconditionally. If
652 * <b>force</b> is false, do it only if we expect to save space on disk. */
654 microdesc_cache_rebuild(microdesc_cache_t
*cache
, int force
)
656 open_file_t
*open_file
;
661 off_t off
= 0, off_real
;
662 int orig_size
, new_size
;
665 cache
= the_microdesc_cache
;
670 /* Remove dead descriptors */
671 microdesc_cache_clean(cache
, 0/*cutoff*/, 0/*force*/);
673 if (!force
&& !should_rebuild_md_cache(cache
))
676 log_info(LD_DIR
, "Rebuilding the microdescriptor cache...");
678 orig_size
= (int)(cache
->cache_content
? cache
->cache_content
->size
: 0);
679 orig_size
+= (int)cache
->journal_len
;
681 fd
= start_writing_to_file(cache
->cache_fname
,
682 OPEN_FLAGS_REPLACE
|O_BINARY
,
687 wrote
= smartlist_new();
689 HT_FOREACH(mdp
, microdesc_map
, &cache
->map
) {
690 microdesc_t
*md
= *mdp
;
691 size_t annotation_len
;
692 if (md
->no_save
|| !md
->body
)
695 size
= dump_microdescriptor(fd
, md
, &annotation_len
);
697 microdesc_wipe_body(md
);
699 /* rewind, in case it was a partial write. */
700 tor_fd_setpos(fd
, off
);
703 tor_assert(((size_t)size
) == annotation_len
+ md
->bodylen
);
704 md
->off
= off
+ annotation_len
;
706 off_real
= tor_fd_getpos(fd
);
707 if (off_real
!= off
) {
708 log_warn(LD_BUG
, "Discontinuity in position in microdescriptor cache."
709 "By my count, I'm at "I64_FORMAT
710 ", but I should be at "I64_FORMAT
,
711 I64_PRINTF_ARG(off
), I64_PRINTF_ARG(off_real
));
715 if (md
->saved_location
!= SAVED_IN_CACHE
) {
717 md
->saved_location
= SAVED_IN_CACHE
;
719 smartlist_add(wrote
, md
);
722 /* We must do this unmap _before_ we call finish_writing_to_file(), or
723 * windows will not actually replace the file. */
724 if (cache
->cache_content
) {
725 res
= tor_munmap_file(cache
->cache_content
);
728 "Failed to unmap old microdescriptor cache while rebuilding");
730 cache
->cache_content
= NULL
;
733 if (finish_writing_to_file(open_file
) < 0) {
734 log_warn(LD_DIR
, "Error rebuilding microdescriptor cache: %s",
736 /* Okay. Let's prevent from making things worse elsewhere. */
737 cache
->cache_content
= NULL
;
738 HT_FOREACH(mdp
, microdesc_map
, &cache
->map
) {
739 microdesc_t
*md
= *mdp
;
740 if (md
->saved_location
== SAVED_IN_CACHE
) {
741 microdesc_wipe_body(md
);
744 smartlist_free(wrote
);
748 cache
->cache_content
= tor_mmap_file(cache
->cache_fname
);
750 if (!cache
->cache_content
&& smartlist_len(wrote
)) {
751 log_err(LD_DIR
, "Couldn't map file that we just wrote to %s!",
753 smartlist_free(wrote
);
756 SMARTLIST_FOREACH_BEGIN(wrote
, microdesc_t
*, md
) {
757 tor_assert(md
->saved_location
== SAVED_IN_CACHE
);
758 md
->body
= (char*)cache
->cache_content
->data
+ md
->off
;
759 if (PREDICT_UNLIKELY(
760 md
->bodylen
< 9 || fast_memneq(md
->body
, "onion-key", 9) != 0)) {
761 /* XXXX once bug 2022 is solved, we can kill this block and turn it
762 * into just the tor_assert(fast_memeq) */
763 off_t avail
= cache
->cache_content
->size
- md
->off
;
765 tor_assert(avail
>= 0);
766 bad_str
= tor_strndup(md
->body
, MIN(128, (size_t)avail
));
767 log_err(LD_BUG
, "After rebuilding microdesc cache, offsets seem wrong. "
768 " At offset %d, I expected to find a microdescriptor starting "
769 " with \"onion-key\". Instead I got %s.",
770 (int)md
->off
, escaped(bad_str
));
772 tor_assert(fast_memeq(md
->body
, "onion-key", 9));
774 } SMARTLIST_FOREACH_END(md
);
776 smartlist_free(wrote
);
778 write_str_to_file(cache
->journal_fname
, "", 1);
779 cache
->journal_len
= 0;
780 cache
->bytes_dropped
= 0;
782 new_size
= cache
->cache_content
? (int)cache
->cache_content
->size
: 0;
783 log_info(LD_DIR
, "Done rebuilding microdesc cache. "
784 "Saved %d bytes; %d still used.",
785 orig_size
-new_size
, new_size
);
790 /** Make sure that the reference count of every microdescriptor in cache is
793 microdesc_check_counts(void)
796 if (!the_microdesc_cache
)
799 HT_FOREACH(mdp
, microdesc_map
, &the_microdesc_cache
->map
) {
800 microdesc_t
*md
= *mdp
;
801 unsigned int found
=0;
802 const smartlist_t
*nodes
= nodelist_get_list();
803 SMARTLIST_FOREACH(nodes
, node_t
*, node
, {
804 if (node
->md
== md
) {
808 tor_assert(found
== md
->held_by_nodes
);
812 /** Deallocate a single microdescriptor. Note: the microdescriptor MUST have
813 * previously been removed from the cache if it had ever been inserted. */
815 microdesc_free_(microdesc_t
*md
, const char *fname
, int lineno
)
820 /* Make sure that the microdesc was really removed from the appropriate data
822 if (md
->held_in_map
) {
823 microdesc_cache_t
*cache
= get_microdesc_cache_noload();
824 microdesc_t
*md2
= HT_FIND(microdesc_map
, &cache
->map
, md
);
826 log_warn(LD_BUG
, "microdesc_free() called from %s:%d, but md was still "
827 "in microdesc_map", fname
, lineno
);
828 HT_REMOVE(microdesc_map
, &cache
->map
, md
);
830 log_warn(LD_BUG
, "microdesc_free() called from %s:%d with held_in_map "
831 "set, but microdesc was not in the map.", fname
, lineno
);
833 tor_fragile_assert();
835 if (md
->held_by_nodes
) {
836 microdesc_cache_t
*cache
= get_microdesc_cache_noload();
838 const smartlist_t
*nodes
= nodelist_get_list();
839 const int ht_badness
= HT_REP_IS_BAD_(microdesc_map
, &cache
->map
);
840 SMARTLIST_FOREACH(nodes
, node_t
*, node
, {
841 if (node
->md
== md
) {
847 log_warn(LD_BUG
, "microdesc_free() called from %s:%d, but md was still "
848 "referenced %d node(s); held_by_nodes == %u, ht_badness == %d",
849 fname
, lineno
, found
, md
->held_by_nodes
, ht_badness
);
851 log_warn(LD_BUG
, "microdesc_free() called from %s:%d with held_by_nodes "
852 "set to %u, but md was not referenced by any nodes. "
854 fname
, lineno
, md
->held_by_nodes
, ht_badness
);
856 tor_fragile_assert();
858 //tor_assert(md->held_in_map == 0);
859 //tor_assert(md->held_by_nodes == 0);
862 crypto_pk_free(md
->onion_pkey
);
863 tor_free(md
->onion_curve25519_pkey
);
864 tor_free(md
->ed25519_identity_pkey
);
865 if (md
->body
&& md
->saved_location
!= SAVED_IN_CACHE
)
869 SMARTLIST_FOREACH(md
->family
, char *, cp
, tor_free(cp
));
870 smartlist_free(md
->family
);
872 short_policy_free(md
->exit_policy
);
873 short_policy_free(md
->ipv6_exit_policy
);
878 /** Free all storage held in the microdesc.c module. */
880 microdesc_free_all(void)
882 if (the_microdesc_cache
) {
883 microdesc_cache_clear(the_microdesc_cache
);
884 tor_free(the_microdesc_cache
->cache_fname
);
885 tor_free(the_microdesc_cache
->journal_fname
);
886 tor_free(the_microdesc_cache
);
889 if (outdated_dirserver_list
) {
890 SMARTLIST_FOREACH(outdated_dirserver_list
, char *, cp
, tor_free(cp
));
891 smartlist_free(outdated_dirserver_list
);
895 /** If there is a microdescriptor in <b>cache</b> whose sha256 digest is
896 * <b>d</b>, return it. Otherwise return NULL. */
898 microdesc_cache_lookup_by_digest256(microdesc_cache_t
*cache
, const char *d
)
900 microdesc_t
*md
, search
;
902 cache
= get_microdesc_cache();
903 memcpy(search
.digest
, d
, DIGEST256_LEN
);
904 md
= HT_FIND(microdesc_map
, &cache
->map
, &search
);
908 /** Return a smartlist of all the sha256 digest of the microdescriptors that
909 * are listed in <b>ns</b> but not present in <b>cache</b>. Returns pointers
910 * to internals of <b>ns</b>; you should not free the members of the resulting
911 * smartlist. Omit all microdescriptors whose digest appear in <b>skip</b>. */
913 microdesc_list_missing_digest256(networkstatus_t
*ns
, microdesc_cache_t
*cache
,
914 int downloadable_only
, digest256map_t
*skip
)
916 smartlist_t
*result
= smartlist_new();
917 time_t now
= time(NULL
);
918 tor_assert(ns
->flavor
== FLAV_MICRODESC
);
919 SMARTLIST_FOREACH_BEGIN(ns
->routerstatus_list
, routerstatus_t
*, rs
) {
920 if (microdesc_cache_lookup_by_digest256(cache
, rs
->descriptor_digest
))
922 if (downloadable_only
&&
923 !download_status_is_ready(&rs
->dl_status
, now
))
925 if (skip
&& digest256map_get(skip
, (const uint8_t*)rs
->descriptor_digest
))
927 if (tor_mem_is_zero(rs
->descriptor_digest
, DIGEST256_LEN
))
929 /* XXXX Also skip if we're a noncache and wouldn't use this router.
932 smartlist_add(result
, rs
->descriptor_digest
);
933 } SMARTLIST_FOREACH_END(rs
);
937 /** Launch download requests for microdescriptors as appropriate.
939 * Specifically, we should launch download requests if we are configured to
940 * download mirodescriptors, and there are some microdescriptors listed in the
941 * current microdesc consensus that we don't have, and either we never asked
942 * for them, or we failed to download them but we're willing to retry.
945 update_microdesc_downloads(time_t now
)
947 const or_options_t
*options
= get_options();
948 networkstatus_t
*consensus
;
949 smartlist_t
*missing
;
950 digest256map_t
*pending
;
952 if (should_delay_dir_fetches(options
, NULL
))
954 if (directory_too_idle_to_fetch_descriptors(options
, now
))
957 consensus
= networkstatus_get_reasonably_live_consensus(now
, FLAV_MICRODESC
);
961 if (!we_fetch_microdescriptors(options
))
964 pending
= digest256map_new();
965 list_pending_microdesc_downloads(pending
);
967 missing
= microdesc_list_missing_digest256(consensus
,
968 get_microdesc_cache(),
971 digest256map_free(pending
, NULL
);
973 launch_descriptor_downloads(DIR_PURPOSE_FETCH_MICRODESC
,
976 smartlist_free(missing
);
979 /** For every microdescriptor listed in the current microdescriptor consensus,
980 * update its last_listed field to be at least as recent as the publication
981 * time of the current microdescriptor consensus.
984 update_microdescs_from_networkstatus(time_t now
)
986 microdesc_cache_t
*cache
= get_microdesc_cache();
988 networkstatus_t
*ns
=
989 networkstatus_get_reasonably_live_consensus(now
, FLAV_MICRODESC
);
994 tor_assert(ns
->flavor
== FLAV_MICRODESC
);
996 SMARTLIST_FOREACH_BEGIN(ns
->routerstatus_list
, routerstatus_t
*, rs
) {
997 md
= microdesc_cache_lookup_by_digest256(cache
, rs
->descriptor_digest
);
998 if (md
&& ns
->valid_after
> md
->last_listed
)
999 md
->last_listed
= ns
->valid_after
;
1000 } SMARTLIST_FOREACH_END(rs
);
1003 /** Return true iff we should prefer to use microdescriptors rather than
1004 * routerdescs for building circuits. */
1006 we_use_microdescriptors_for_circuits(const or_options_t
*options
)
1008 if (options
->UseMicrodescriptors
== 0)
1009 return 0; /* the user explicitly picked no */
1010 return 1; /* yes and auto both mean yes */
1013 /** Return true iff we should try to download microdescriptors at all. */
1015 we_fetch_microdescriptors(const or_options_t
*options
)
1017 if (directory_caches_dir_info(options
))
1019 if (options
->FetchUselessDescriptors
)
1021 return we_use_microdescriptors_for_circuits(options
);
1024 /** Return true iff we should try to download router descriptors at all. */
1026 we_fetch_router_descriptors(const or_options_t
*options
)
1028 if (directory_caches_dir_info(options
))
1030 if (options
->FetchUselessDescriptors
)
1032 return ! we_use_microdescriptors_for_circuits(options
);
1035 /** Return the consensus flavor we actually want to use to build circuits. */
1037 usable_consensus_flavor
,(void))
1039 if (we_use_microdescriptors_for_circuits(get_options())) {
1040 return FLAV_MICRODESC
;