diff options
Diffstat (limited to 'src/or/routerlist.c')
-rw-r--r-- | src/or/routerlist.c | 416 |
1 files changed, 209 insertions, 207 deletions
diff --git a/src/or/routerlist.c b/src/or/routerlist.c index f73ec9baa1..203895c867 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2016, The Tor Project, Inc. */ + * Copyright (c) 2007-2017, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -93,6 +93,7 @@ #define ROUTERLIST_PRIVATE #include "or.h" #include "backtrace.h" +#include "bridges.h" #include "crypto_ed25519.h" #include "circuitstats.h" #include "config.h" @@ -142,6 +143,10 @@ DECLARE_TYPED_DIGESTMAP_FNS(dsmap_, digest_ds_map_t, download_status_t) #define DSMAP_FOREACH(map, keyvar, valvar) \ DIGESTMAP_FOREACH(dsmap_to_digestmap(map), keyvar, download_status_t *, \ valvar) +#define eimap_free(map, fn) MAP_FREE_AND_NULL(eimap, (map), (fn)) +#define rimap_free(map, fn) MAP_FREE_AND_NULL(rimap, (map), (fn)) +#define dsmap_free(map, fn) MAP_FREE_AND_NULL(dsmap, (map), (fn)) +#define sdmap_free(map, fn) MAP_FREE_AND_NULL(sdmap, (map), (fn)) /* Forward declaration for cert_list_t */ typedef struct cert_list_t cert_list_t; @@ -158,7 +163,6 @@ static const routerstatus_t *router_pick_dirserver_generic( smartlist_t *sourcelist, dirinfo_type_t type, int flags); static void mark_all_dirservers_up(smartlist_t *server_list); -static void dir_server_free(dir_server_t *ds); static int signed_desc_digest_is_recognized(signed_descriptor_t *desc); static const char *signed_descriptor_get_body_impl( const signed_descriptor_t *desc, @@ -173,7 +177,7 @@ static void download_status_reset_by_sk_in_cl(cert_list_t *cl, const char *digest); static int download_status_is_ready_by_sk_in_cl(cert_list_t *cl, const char *digest, - time_t now, int max_failures); + time_t now); /****************************************************************************/ @@ -231,7 +235,7 @@ get_n_authorities(dirinfo_type_t type) return n; } -/** Initialise schedule, want_authority, and increment on in the download +/** Initialise schedule, want_authority, and increment_on in the download * status dlstatus, then call download_status_reset() on it. * It is safe to call this function or download_status_reset() multiple times * on a new dlstatus. But it should *not* be called after a dlstatus has been @@ -242,7 +246,6 @@ download_status_cert_init(download_status_t *dlstatus) dlstatus->schedule = DL_SCHED_CONSENSUS; dlstatus->want_authority = DL_WANT_ANY_DIRSERVER; dlstatus->increment_on = DL_SCHED_INCREMENT_FAILURE; - dlstatus->backoff = DL_SCHED_RANDOM_EXPONENTIAL; dlstatus->last_backoff_position = 0; dlstatus->last_delay_used = 0; @@ -284,7 +287,7 @@ download_status_reset_by_sk_in_cl(cert_list_t *cl, const char *digest) static int download_status_is_ready_by_sk_in_cl(cert_list_t *cl, const char *digest, - time_t now, int max_failures) + time_t now) { int rv = 0; download_status_t *dlstatus = NULL; @@ -301,7 +304,7 @@ download_status_is_ready_by_sk_in_cl(cert_list_t *cl, /* Got one? */ if (dlstatus) { /* Use download_status_is_ready() */ - rv = download_status_is_ready(dlstatus, now, max_failures); + rv = download_status_is_ready(dlstatus, now); } else { /* * If we don't know anything about it, return 1, since we haven't @@ -363,7 +366,7 @@ list_authority_ids_with_downloads, (void)) smartlist_add(ids, tmp); } } - /* else definitely no downlaods going since nothing even has a cert list */ + /* else definitely no downloads going since nothing even has a cert list */ return ids; } @@ -426,8 +429,8 @@ list_sk_digests_for_authority_id, (const char *digest)) * download_status_t or NULL if none exists. */ MOCK_IMPL(download_status_t *, - download_status_for_authority_id_and_sk, - (const char *id_digest, const char *sk_digest)) +download_status_for_authority_id_and_sk,(const char *id_digest, + const char *sk_digest)) { download_status_t *dl = NULL; cert_list_t *cl = NULL; @@ -442,9 +445,12 @@ MOCK_IMPL(download_status_t *, return dl; } +#define cert_list_free(val) \ + FREE_AND_NULL(cert_list_t, cert_list_free_, (val)) + /** Release all space held by a cert_list_t */ static void -cert_list_free(cert_list_t *cl) +cert_list_free_(cert_list_t *cl) { if (!cl) return; @@ -458,9 +464,9 @@ cert_list_free(cert_list_t *cl) /** Wrapper for cert_list_free so we can pass it to digestmap_free */ static void -cert_list_free_(void *cl) +cert_list_free_void(void *cl) { - cert_list_free(cl); + cert_list_free_(cl); } /** Reload the cached v3 key certificates from the cached-certs file in @@ -472,7 +478,7 @@ trusted_dirs_reload_certs(void) char *contents; int r; - filename = get_datadir_fname("cached-certs"); + filename = get_cachedir_fname("cached-certs"); contents = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL); tor_free(filename); if (!contents) @@ -587,7 +593,7 @@ trusted_dirs_load_certs_from_string(const char *contents, int source, "signing key %s", from_store ? "cached" : "downloaded", ds->nickname, hex_str(cert->signing_key_digest,DIGEST_LEN)); } else { - int adding = directory_caches_unknown_auth_certs(get_options()); + int adding = we_want_to_fetch_unknown_auth_certs(get_options()); log_info(LD_DIR, "%s %s certificate for unrecognized directory " "authority with signing key %s", adding ? "Adding" : "Not adding", @@ -661,7 +667,7 @@ trusted_dirs_flush_certs_to_disk(void) }); } DIGESTMAP_FOREACH_END; - filename = get_datadir_fname("cached-certs"); + filename = get_cachedir_fname("cached-certs"); if (write_chunks_to_file(filename, chunks, 0, 0)) { log_warn(LD_FS, "Error writing certificates to disk."); } @@ -930,7 +936,8 @@ authority_certs_fetch_resource_impl(const char *resource, const routerstatus_t *rs) { const or_options_t *options = get_options(); - int get_via_tor = purpose_needs_anonymity(DIR_PURPOSE_FETCH_CERTIFICATE, 0); + int get_via_tor = purpose_needs_anonymity(DIR_PURPOSE_FETCH_CERTIFICATE, 0, + resource); /* Make sure bridge clients never connect to anything but a bridge */ if (options->UseBridges) { @@ -946,31 +953,34 @@ authority_certs_fetch_resource_impl(const char *resource, const dir_indirection_t indirection = get_via_tor ? DIRIND_ANONYMOUS : DIRIND_ONEHOP; + directory_request_t *req = NULL; /* If we've just downloaded a consensus from a bridge, re-use that * bridge */ - if (options->UseBridges && node && !get_via_tor) { + if (options->UseBridges && node && node->ri && !get_via_tor) { /* clients always make OR connections to bridges */ tor_addr_port_t or_ap; /* we are willing to use a non-preferred address if we need to */ fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0, &or_ap); - directory_initiate_command(&or_ap.addr, or_ap.port, - NULL, 0, /*no dirport*/ - dir_hint, - DIR_PURPOSE_FETCH_CERTIFICATE, - 0, - indirection, - resource, NULL, 0, 0); - return; - } - if (rs) { - /* If we've just downloaded a consensus from a directory, re-use that + req = directory_request_new(DIR_PURPOSE_FETCH_CERTIFICATE); + directory_request_set_or_addr_port(req, &or_ap); + if (dir_hint) + directory_request_set_directory_id_digest(req, dir_hint); + } else if (rs) { + /* And if we've just downloaded a consensus from a directory, re-use that * directory */ - directory_initiate_command_routerstatus(rs, - DIR_PURPOSE_FETCH_CERTIFICATE, - 0, indirection, resource, NULL, - 0, 0); + req = directory_request_new(DIR_PURPOSE_FETCH_CERTIFICATE); + directory_request_set_routerstatus(req, rs); + } + + if (req) { + /* We've set up a request object -- fill in the other request fields, and + * send the request. */ + directory_request_set_indirection(req, indirection); + directory_request_set_resource(req, resource); + directory_initiate_request(req); + directory_request_free(req); return; } @@ -1012,7 +1022,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now, char *resource = NULL; cert_list_t *cl; const or_options_t *options = get_options(); - const int cache = directory_caches_unknown_auth_certs(options); + const int keep_unknown = we_want_to_fetch_unknown_auth_certs(options); fp_pair_t *fp_tmp = NULL; char id_digest_str[2*DIGEST_LEN+1]; char sk_digest_str[2*DIGEST_LEN+1]; @@ -1057,8 +1067,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now, } } SMARTLIST_FOREACH_END(cert); if (!found && - download_status_is_ready(&(cl->dl_status_by_id), now, - options->TestingCertMaxDownloadTries) && + download_status_is_ready(&(cl->dl_status_by_id), now) && !digestmap_get(pending_id, ds->v3_identity_digest)) { log_info(LD_DIR, "No current certificate known for authority %s " @@ -1084,9 +1093,10 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now, if (!smartlist_len(voter->sigs)) continue; /* This authority never signed this consensus, so don't * go looking for a cert with key digest 0000000000. */ - if (!cache && + if (!keep_unknown && !trusteddirserver_get_by_v3_auth_digest(voter->identity_digest)) - continue; /* We are not a cache, and we don't know this authority.*/ + continue; /* We don't want unknown certs, and we don't know this + * authority.*/ /* * If we don't know *any* cert for this authority, and a download by ID @@ -1120,8 +1130,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now, continue; } if (download_status_is_ready_by_sk_in_cl( - cl, sig->signing_key_digest, - now, options->TestingCertMaxDownloadTries) && + cl, sig->signing_key_digest, now) && !fp_pair_map_get_by_digests(pending_cert, voter->identity_digest, sig->signing_key_digest)) { @@ -1158,7 +1167,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now, } SMARTLIST_FOREACH_END(voter); } - /* Bridge clients look up the node for the dir_hint */ + /* Bridge clients look up the node for the dir_hint */ const node_t *node = NULL; /* All clients, including bridge clients, look up the routerstatus for the * dir_hint */ @@ -1203,7 +1212,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now, int need_plus = 0; smartlist_t *fps = smartlist_new(); - smartlist_add(fps, tor_strdup("fp/")); + smartlist_add_strdup(fps, "fp/"); SMARTLIST_FOREACH_BEGIN(missing_id_digests, const char *, d) { char *fp = NULL; @@ -1243,7 +1252,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now, int need_plus = 0; smartlist_t *fp_pairs = smartlist_new(); - smartlist_add(fp_pairs, tor_strdup("fp-sk/")); + smartlist_add_strdup(fp_pairs, "fp-sk/"); SMARTLIST_FOREACH_BEGIN(missing_cert_digests, const fp_pair_t *, d) { char *fp_pair = NULL; @@ -1333,7 +1342,7 @@ static int signed_desc_append_to_journal(signed_descriptor_t *desc, desc_store_t *store) { - char *fname = get_datadir_fname_suffix(store->fname_base, ".new"); + char *fname = get_cachedir_fname_suffix(store->fname_base, ".new"); const char *body = signed_descriptor_get_body_impl(desc,1); size_t len = desc->signed_descriptor_len + desc->annotations_len; @@ -1404,8 +1413,8 @@ router_rebuild_store(int flags, desc_store_t *store) log_info(LD_DIR, "Rebuilding %s cache", store->description); - fname = get_datadir_fname(store->fname_base); - fname_tmp = get_datadir_fname_suffix(store->fname_base, ".tmp"); + fname = get_cachedir_fname(store->fname_base); + fname_tmp = get_cachedir_fname_suffix(store->fname_base, ".tmp"); chunk_list = smartlist_new(); @@ -1502,7 +1511,7 @@ router_rebuild_store(int flags, desc_store_t *store) } SMARTLIST_FOREACH_END(sd); tor_free(fname); - fname = get_datadir_fname_suffix(store->fname_base, ".new"); + fname = get_cachedir_fname_suffix(store->fname_base, ".new"); write_str_to_file(fname, "", 1); r = 0; @@ -1532,7 +1541,7 @@ router_reload_router_list_impl(desc_store_t *store) int extrainfo = (store->type == EXTRAINFO_STORE); store->journal_len = store->store_len = 0; - fname = get_datadir_fname(store->fname_base); + fname = get_cachedir_fname(store->fname_base); if (store->mmap) { /* get rid of it first */ @@ -1559,7 +1568,7 @@ router_reload_router_list_impl(desc_store_t *store) } tor_free(fname); - fname = get_datadir_fname_suffix(store->fname_base, ".new"); + fname = get_cachedir_fname_suffix(store->fname_base, ".new"); /* don't load empty files - we wouldn't get any data, even if we tried */ if (file_status(fname) == FN_FILE) contents = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st); @@ -1824,43 +1833,24 @@ router_is_already_dir_fetching(const tor_addr_port_t *ap, int serverdesc, return 0; } -/* Check if we already have a directory fetch from ds, for serverdesc - * (including extrainfo) or microdesc documents. - * If so, return 1, if not, return 0. - */ -static int -router_is_already_dir_fetching_ds(const dir_server_t *ds, - int serverdesc, - int microdesc) -{ - tor_addr_port_t ipv4_dir_ap, ipv6_dir_ap; - - /* Assume IPv6 DirPort is the same as IPv4 DirPort */ - tor_addr_from_ipv4h(&ipv4_dir_ap.addr, ds->addr); - ipv4_dir_ap.port = ds->dir_port; - tor_addr_copy(&ipv6_dir_ap.addr, &ds->ipv6_addr); - ipv6_dir_ap.port = ds->dir_port; - - return (router_is_already_dir_fetching(&ipv4_dir_ap, serverdesc, microdesc) - || router_is_already_dir_fetching(&ipv6_dir_ap, serverdesc, microdesc)); -} - -/* Check if we already have a directory fetch from rs, for serverdesc - * (including extrainfo) or microdesc documents. +/* Check if we already have a directory fetch from the ipv4 or ipv6 + * router, for serverdesc (including extrainfo) or microdesc documents. * If so, return 1, if not, return 0. */ static int -router_is_already_dir_fetching_rs(const routerstatus_t *rs, - int serverdesc, - int microdesc) +router_is_already_dir_fetching_(uint32_t ipv4_addr, + const tor_addr_t *ipv6_addr, + uint16_t dir_port, + int serverdesc, + int microdesc) { tor_addr_port_t ipv4_dir_ap, ipv6_dir_ap; /* Assume IPv6 DirPort is the same as IPv4 DirPort */ - tor_addr_from_ipv4h(&ipv4_dir_ap.addr, rs->addr); - ipv4_dir_ap.port = rs->dir_port; - tor_addr_copy(&ipv6_dir_ap.addr, &rs->ipv6_addr); - ipv6_dir_ap.port = rs->dir_port; + tor_addr_from_ipv4h(&ipv4_dir_ap.addr, ipv4_addr); + ipv4_dir_ap.port = dir_port; + tor_addr_copy(&ipv6_dir_ap.addr, ipv6_addr); + ipv6_dir_ap.port = dir_port; return (router_is_already_dir_fetching(&ipv4_dir_ap, serverdesc, microdesc) || router_is_already_dir_fetching(&ipv6_dir_ap, serverdesc, microdesc)); @@ -1886,7 +1876,7 @@ router_picked_poor_directory_log(const routerstatus_t *rs) || !router_have_minimum_dir_info()) { return; } -#endif +#endif /* !LOG_FALSE_POSITIVES_DURING_BOOTSTRAP */ /* We couldn't find a node, or the one we have doesn't fit our preferences. * Sometimes this is normal, sometimes it can be a reachability issue. */ @@ -1952,6 +1942,21 @@ router_picked_poor_directory_log(const routerstatus_t *rs) } \ STMT_END +/* Common code used in the loop within router_pick_directory_server_impl and + * router_pick_trusteddirserver_impl. + * + * Check if the given <b>identity</b> supports extrainfo. If not, skip further + * checks. + */ +#define SKIP_MISSING_TRUSTED_EXTRAINFO(type, identity) \ + STMT_BEGIN \ + int is_trusted_extrainfo = router_digest_is_trusted_dir_type( \ + (identity), EXTRAINFO_DIRINFO); \ + if (((type) & EXTRAINFO_DIRINFO) && \ + !router_supports_extrainfo((identity), is_trusted_extrainfo)) \ + continue; \ + STMT_END + /* When iterating through the routerlist, can OR address/port preference * and reachability checks be skipped? */ @@ -1998,7 +2003,6 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags, const int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL); const int no_serverdesc_fetching =(flags & PDS_NO_EXISTING_SERVERDESC_FETCH); const int no_microdesc_fetching = (flags & PDS_NO_EXISTING_MICRODESC_FETCH); - const int for_guard = (flags & PDS_FOR_GUARD); int try_excluding = 1, n_excluded = 0, n_busy = 0; int try_ip_pref = 1; @@ -2020,7 +2024,7 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags, /* Find all the running dirservers we know about. */ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { - int is_trusted, is_trusted_extrainfo; + int is_trusted; int is_overloaded; const routerstatus_t *status = node->rs; const country_t country = node->country; @@ -2031,20 +2035,9 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags, continue; if (requireother && router_digest_is_me(node->identity)) continue; - is_trusted = router_digest_is_trusted_dir(node->identity); - is_trusted_extrainfo = router_digest_is_trusted_dir_type( - node->identity, EXTRAINFO_DIRINFO); - if ((type & EXTRAINFO_DIRINFO) && - !router_supports_extrainfo(node->identity, is_trusted_extrainfo)) - continue; - /* Don't make the same node a guard twice */ - if (for_guard && node->using_as_guard) { - continue; - } - /* Ensure that a directory guard is actually a guard node. */ - if (for_guard && !node->is_possible_guard) { - continue; - } + + SKIP_MISSING_TRUSTED_EXTRAINFO(type, node->identity); + if (try_excluding && routerset_contains_routerstatus(options->ExcludeNodes, status, country)) { @@ -2052,14 +2045,17 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags, continue; } - if (router_is_already_dir_fetching_rs(status, - no_serverdesc_fetching, - no_microdesc_fetching)) { + if (router_is_already_dir_fetching_(status->addr, + &status->ipv6_addr, + status->dir_port, + no_serverdesc_fetching, + no_microdesc_fetching)) { ++n_busy; continue; } is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now; + is_trusted = router_digest_is_trusted_dir(node->identity); /* Clients use IPv6 addresses if the server has one and the client * prefers IPv6. @@ -2191,11 +2187,9 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist, if (!d->is_running) continue; if ((type & d->type) == 0) continue; - int is_trusted_extrainfo = router_digest_is_trusted_dir_type( - d->digest, EXTRAINFO_DIRINFO); - if ((type & EXTRAINFO_DIRINFO) && - !router_supports_extrainfo(d->digest, is_trusted_extrainfo)) - continue; + + SKIP_MISSING_TRUSTED_EXTRAINFO(type, d->digest); + if (requireother && me && router_digest_is_me(d->digest)) continue; if (try_excluding && @@ -2205,8 +2199,11 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist, continue; } - if (router_is_already_dir_fetching_ds(d, no_serverdesc_fetching, - no_microdesc_fetching)) { + if (router_is_already_dir_fetching_(d->addr, + &d->ipv6_addr, + d->dir_port, + no_serverdesc_fetching, + no_microdesc_fetching)) { ++n_busy; continue; } @@ -2313,7 +2310,7 @@ routerlist_add_node_and_family(smartlist_t *sl, const routerinfo_t *router) { /* XXXX MOVE ? */ node_t fake_node; - const node_t *node = node_get_by_id(router->cache_info.identity_digest);; + const node_t *node = node_get_by_id(router->cache_info.identity_digest); if (node == NULL) { memset(&fake_node, 0, sizeof(fake_node)); fake_node.ri = (routerinfo_t *)router; @@ -2327,19 +2324,18 @@ routerlist_add_node_and_family(smartlist_t *sl, const routerinfo_t *router) * we can pick a node for a circuit. */ void -router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid, - int need_uptime, int need_capacity, - int need_guard, int need_desc, - int pref_addr, int direct_conn) +router_add_running_nodes_to_smartlist(smartlist_t *sl, int need_uptime, + int need_capacity, int need_guard, + int need_desc, int pref_addr, + int direct_conn) { const int check_reach = !router_skip_or_reachability(get_options(), pref_addr); /* XXXX MOVE */ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { - if (!node->is_running || - (!node->is_valid && !allow_invalid)) + if (!node->is_running || !node->is_valid) continue; - if (need_desc && !(node->ri || (node->rs && node->md))) + if (need_desc && !node_has_preferred_descriptor(node, direct_conn)) continue; if (node->ri && node->ri->purpose != ROUTER_PURPOSE_GENERAL) continue; @@ -2653,7 +2649,7 @@ compute_weighted_bandwidths(const smartlist_t *sl, is_dir = node_is_dir(node); if (node->rs) { if (!node->rs->has_bandwidth) { - /* This should never happen, unless all the authorites downgrade + /* This should never happen, unless all the authorities downgrade * to 0.2.0 or rogue routerstatuses get inserted into our consensus. */ if (! warned_missing_bw) { log_warn(LD_BUG, @@ -2762,7 +2758,7 @@ frac_nodes_with_descriptors(const smartlist_t *sl, total <= 0.0) { int n_with_descs = 0; SMARTLIST_FOREACH(sl, const node_t *, node, { - if (node_has_descriptor(node)) + if (node_has_any_descriptor(node)) n_with_descs++; }); @@ -2772,7 +2768,7 @@ frac_nodes_with_descriptors(const smartlist_t *sl, present = 0.0; SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) { - if (node_has_descriptor(node)) + if (node_has_any_descriptor(node)) present += bandwidths[node_sl_idx]; } SMARTLIST_FOREACH_END(node); @@ -2798,8 +2794,6 @@ node_sl_choose_by_bandwidth(const smartlist_t *sl, * a minimum uptime, return one of those. * If <b>CRN_NEED_CAPACITY</b> is set in flags, weight your choice by the * advertised capacity of each router. - * If <b>CRN_ALLOW_INVALID</b> is not set in flags, consider only Valid - * routers. * If <b>CRN_NEED_GUARD</b> is set in flags, consider only Guard routers. * If <b>CRN_WEIGHT_AS_EXIT</b> is set in flags, we weight bandwidths as if * picking an exit node, otherwise we weight bandwidths for picking a relay @@ -2820,11 +2814,11 @@ router_choose_random_node(smartlist_t *excludedsmartlist, const int need_uptime = (flags & CRN_NEED_UPTIME) != 0; const int need_capacity = (flags & CRN_NEED_CAPACITY) != 0; const int need_guard = (flags & CRN_NEED_GUARD) != 0; - const int allow_invalid = (flags & CRN_ALLOW_INVALID) != 0; const int weight_for_exit = (flags & CRN_WEIGHT_AS_EXIT) != 0; const int need_desc = (flags & CRN_NEED_DESC) != 0; const int pref_addr = (flags & CRN_PREF_ADDR) != 0; const int direct_conn = (flags & CRN_DIRECT_CONN) != 0; + const int rendezvous_v3 = (flags & CRN_RENDEZVOUS_V3) != 0; smartlist_t *sl=smartlist_new(), *excludednodes=smartlist_new(); @@ -2836,14 +2830,19 @@ router_choose_random_node(smartlist_t *excludedsmartlist, rule = weight_for_exit ? WEIGHT_FOR_EXIT : (need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID); - /* Exclude relays that allow single hop exit circuits, if the user - * wants to (such relays might be risky) */ - if (get_options()->ExcludeSingleHopRelays) { - SMARTLIST_FOREACH(nodelist_get_list(), node_t *, node, - if (node_allows_single_hop_exits(node)) { - smartlist_add(excludednodes, node); - }); - } + SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), node_t *, node) { + if (node_allows_single_hop_exits(node)) { + /* Exclude relays that allow single hop exit circuits. This is an + * obsolete option since 0.2.9.2-alpha and done by default in + * 0.3.1.0-alpha. */ + smartlist_add(excludednodes, node); + } else if (rendezvous_v3 && + !node_supports_v3_rendezvous_point(node)) { + /* Exclude relays that do not support to rendezvous for a hidden service + * version 3. */ + smartlist_add(excludednodes, node); + } + } SMARTLIST_FOREACH_END(node); /* If the node_t is not found we won't be to exclude ourself but we * won't be able to pick ourself in router_choose_random_node() so @@ -2851,8 +2850,7 @@ router_choose_random_node(smartlist_t *excludedsmartlist, if ((r = router_get_my_routerinfo())) routerlist_add_node_and_family(excludednodes, r); - router_add_running_nodes_to_smartlist(sl, allow_invalid, - need_uptime, need_capacity, + router_add_running_nodes_to_smartlist(sl, need_uptime, need_capacity, need_guard, need_desc, pref_addr, direct_conn); log_debug(LD_CIRC, @@ -2958,7 +2956,7 @@ hex_digest_nickname_decode(const char *hexdigest, * <b>hexdigest</b> is malformed, or it doesn't match. */ int hex_digest_nickname_matches(const char *hexdigest, const char *identity_digest, - const char *nickname, int is_named) + const char *nickname) { char digest[DIGEST_LEN]; char nn_char='\0'; @@ -2967,30 +2965,20 @@ hex_digest_nickname_matches(const char *hexdigest, const char *identity_digest, if (hex_digest_nickname_decode(hexdigest, digest, &nn_char, nn_buf) == -1) return 0; - if (nn_char == '=' || nn_char == '~') { - if (!nickname) + if (nn_char == '=') { + return 0; + } + + if (nn_char == '~') { + if (!nickname) // XXX This seems wrong. -NM return 0; if (strcasecmp(nn_buf, nickname)) return 0; - if (nn_char == '=' && !is_named) - return 0; } return tor_memeq(digest, identity_digest, DIGEST_LEN); } -/** Return true iff <b>router</b> is listed as named in the current - * consensus. */ -int -router_is_named(const routerinfo_t *router) -{ - const char *digest = - networkstatus_get_router_digest_by_nickname(router->nickname); - - return (digest && - tor_memeq(digest, router->cache_info.identity_digest, DIGEST_LEN)); -} - /** Return true iff <b>digest</b> is the digest of the identity key of a * trusted directory matching at least one bit of <b>type</b>. If <b>type</b> * is zero (NO_DIRINFO), or ALL_DIRINFO, any authority is okay. */ @@ -3008,20 +2996,6 @@ router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type) return 0; } -/** Return true iff <b>addr</b> is the address of one of our trusted - * directory authorities. */ -int -router_addr_is_trusted_dir(uint32_t addr) -{ - if (!trusted_dir_servers) - return 0; - SMARTLIST_FOREACH(trusted_dir_servers, dir_server_t *, ent, - if (ent->addr == addr) - return 1; - ); - return 0; -} - /** If hexdigest is correctly formed, base16_decode it into * digest, which must have DIGEST_LEN space in it. * Return 0 on success, -1 on failure. @@ -3087,8 +3061,8 @@ router_get_by_extrainfo_digest,(const char *digest)) /** Return the signed descriptor for the extrainfo_t in our routerlist whose * extra-info-digest is <b>digest</b>. Return NULL if no such extra-info * document is known. */ -signed_descriptor_t * -extrainfo_get_by_descriptor_digest(const char *digest) +MOCK_IMPL(signed_descriptor_t *, +extrainfo_get_by_descriptor_digest,(const char *digest)) { extrainfo_t *ei; tor_assert(digest); @@ -3130,7 +3104,7 @@ signed_descriptor_get_body_impl(const signed_descriptor_t *desc, log_err(LD_DIR, "We couldn't read a descriptor that is supposedly " "mmaped in our cache. Is another process running in our data " "directory? Exiting."); - exit(1); + exit(1); // XXXX bad exit: should recover. } } if (!r) /* no mmap, or not in cache. */ @@ -3144,7 +3118,7 @@ signed_descriptor_get_body_impl(const signed_descriptor_t *desc, log_err(LD_DIR, "descriptor at %p begins with unexpected string %s. " "Is another process running in our data directory? Exiting.", desc, escaped(cp)); - exit(1); + exit(1); // XXXX bad exit: should recover. } } @@ -3198,7 +3172,7 @@ router_get_routerlist(void) /** Free all storage held by <b>router</b>. */ void -routerinfo_free(routerinfo_t *router) +routerinfo_free_(routerinfo_t *router) { if (!router) return; @@ -3228,7 +3202,7 @@ routerinfo_free(routerinfo_t *router) /** Release all storage held by <b>extrainfo</b> */ void -extrainfo_free(extrainfo_t *extrainfo) +extrainfo_free_(extrainfo_t *extrainfo) { if (!extrainfo) return; @@ -3240,9 +3214,12 @@ extrainfo_free(extrainfo_t *extrainfo) tor_free(extrainfo); } +#define signed_descriptor_free(val) \ + FREE_AND_NULL(signed_descriptor_t, signed_descriptor_free_, (val)) + /** Release storage held by <b>sd</b>. */ static void -signed_descriptor_free(signed_descriptor_t *sd) +signed_descriptor_free_(signed_descriptor_t *sd) { if (!sd) return; @@ -3296,21 +3273,21 @@ signed_descriptor_from_routerinfo(routerinfo_t *ri) /** Helper: free the storage held by the extrainfo_t in <b>e</b>. */ static void -extrainfo_free_(void *e) +extrainfo_free_void(void *e) { - extrainfo_free(e); + extrainfo_free_(e); } /** Free all storage held by a routerlist <b>rl</b>. */ void -routerlist_free(routerlist_t *rl) +routerlist_free_(routerlist_t *rl) { if (!rl) return; rimap_free(rl->identity_map, NULL); sdmap_free(rl->desc_digest_map, NULL); sdmap_free(rl->desc_by_eid_map, NULL); - eimap_free(rl->extra_info_map, extrainfo_free_); + eimap_free(rl->extra_info_map, extrainfo_free_void); SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r, routerinfo_free(r)); SMARTLIST_FOREACH(rl->old_routers, signed_descriptor_t *, sd, @@ -3802,7 +3779,7 @@ routerlist_free_all(void) smartlist_free(fallback_dir_servers); trusted_dir_servers = fallback_dir_servers = NULL; if (trusted_dir_certs) { - digestmap_free(trusted_dir_certs, cert_list_free_); + digestmap_free(trusted_dir_certs, cert_list_free_void); trusted_dir_certs = NULL; } } @@ -3926,7 +3903,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, router_describe(router)); *msg = "Router descriptor is not referenced by any network-status."; - /* Only journal this desc if we'll be serving it. */ + /* Only journal this desc if we want to keep old descriptors */ if (!from_cache && should_cache_old_descriptors()) signed_desc_append_to_journal(&router->cache_info, &routerlist->desc_store); @@ -4100,7 +4077,7 @@ routerlist_remove_old_cached_routers_with_id(time_t now, signed_descriptor_t *r = smartlist_get(lst, i); tor_assert(tor_memeq(ident, r->identity_digest, DIGEST_LEN)); } -#endif +#endif /* 1 */ /* Check whether we need to do anything at all. */ { int mdpr = directory_caches_dir_info(get_options()) ? 2 : 1; @@ -4513,7 +4490,7 @@ router_load_extrainfo_from_string(const char *s, const char *eos, ei->cache_info.identity_digest, DIGEST_LEN); smartlist_string_remove(requested_fingerprints, fp); - /* We silently let people stuff us with extrainfos we didn't ask for, + /* We silently let relays stuff us with extrainfos we didn't ask for, * so long as we would have wanted them anyway. Since we always fetch * all the extrainfos we want, and we never actually act on them * inside Tor, this should be harmless. */ @@ -4556,13 +4533,14 @@ router_load_extrainfo_from_string(const char *s, const char *eos, smartlist_free(extrainfo_list); } -/** Return true iff any networkstatus includes a descriptor whose digest - * is that of <b>desc</b>. */ +/** Return true iff the latest ns-flavored consensus includes a descriptor + * whose digest is that of <b>desc</b>. */ static int signed_desc_digest_is_recognized(signed_descriptor_t *desc) { const routerstatus_t *rs; - networkstatus_t *consensus = networkstatus_get_latest_consensus(); + networkstatus_t *consensus = networkstatus_get_latest_consensus_by_flavor( + FLAV_NS); if (consensus) { rs = networkstatus_vote_find_entry(consensus, desc->identity_digest); @@ -4578,7 +4556,7 @@ signed_desc_digest_is_recognized(signed_descriptor_t *desc) void update_all_descriptor_downloads(time_t now) { - if (get_options()->DisableNetwork) + if (should_delay_dir_fetches(get_options(), NULL)) return; update_router_descriptor_downloads(now); update_microdesc_downloads(now); @@ -4608,7 +4586,7 @@ router_exit_policy_rejects_all(const routerinfo_t *router) return router->policy_is_reject_star; } -/** Create an directory server at <b>address</b>:<b>port</b>, with OR identity +/** Create a directory server at <b>address</b>:<b>port</b>, with OR identity * key <b>digest</b> which has DIGEST_LEN bytes. If <b>address</b> is NULL, * add ourself. If <b>is_authority</b>, this is a directory authority. Return * the new directory server entry on success or NULL on failure. */ @@ -4769,7 +4747,7 @@ dir_server_add(dir_server_t *ent) /** Free storage held in <b>cert</b>. */ void -authority_cert_free(authority_cert_t *cert) +authority_cert_free_(authority_cert_t *cert) { if (!cert) return; @@ -4781,9 +4759,12 @@ authority_cert_free(authority_cert_t *cert) tor_free(cert); } +#define dir_server_free(val) \ + FREE_AND_NULL(dir_server_t, dir_server_free_, (val)) + /** Free storage held in <b>ds</b>. */ static void -dir_server_free(dir_server_t *ds) +dir_server_free_(dir_server_t *ds) { if (!ds) return; @@ -4919,9 +4900,10 @@ list_pending_fpsk_downloads(fp_pair_map_t *result) * range.) If <b>source</b> is given, download from <b>source</b>; * otherwise, download from an appropriate random directory server. */ -MOCK_IMPL(STATIC void, initiate_descriptor_downloads, - (const routerstatus_t *source, int purpose, smartlist_t *digests, - int lo, int hi, int pds_flags)) +MOCK_IMPL(STATIC void, +initiate_descriptor_downloads,(const routerstatus_t *source, + int purpose, smartlist_t *digests, + int lo, int hi, int pds_flags)) { char *resource, *cp; int digest_len, enc_digest_len; @@ -4973,10 +4955,11 @@ MOCK_IMPL(STATIC void, initiate_descriptor_downloads, if (source) { /* We know which authority or directory mirror we want. */ - directory_initiate_command_routerstatus(source, purpose, - ROUTER_PURPOSE_GENERAL, - DIRIND_ONEHOP, - resource, NULL, 0, 0); + directory_request_t *req = directory_request_new(purpose); + directory_request_set_routerstatus(req, source); + directory_request_set_resource(req, resource); + directory_initiate_request(req); + directory_request_free(req); } else { directory_get_from_dirserver(purpose, ROUTER_PURPOSE_GENERAL, resource, pds_flags, DL_WANT_ANY_DIRSERVER); @@ -5014,8 +4997,9 @@ max_dl_per_request(const or_options_t *options, int purpose) } /** Don't split our requests so finely that we are requesting fewer than - * this number per server. */ -#define MIN_DL_PER_REQUEST 4 + * this number per server. (Grouping more than this at once leads to + * diminishing returns.) */ +#define MIN_DL_PER_REQUEST 32 /** To prevent a single screwy cache from confusing us by selective reply, * try to split our requests into at least this many requests. */ #define MIN_REQUESTS 3 @@ -5081,7 +5065,7 @@ launch_descriptor_downloads(int purpose, } } - if (!authdir_mode_any_nonhidserv(options)) { + if (!authdir_mode(options)) { /* If we wind up going to the authorities, we want to only open one * connection to each authority at a time, so that we don't overload * them. We do this by setting PDS_NO_EXISTING_SERVERDESC_FETCH @@ -5103,8 +5087,9 @@ launch_descriptor_downloads(int purpose, if (n_per_request > max_dl_per_req) n_per_request = max_dl_per_req; - if (n_per_request < MIN_DL_PER_REQUEST) - n_per_request = MIN_DL_PER_REQUEST; + if (n_per_request < MIN_DL_PER_REQUEST) { + n_per_request = MIN(MIN_DL_PER_REQUEST, n_downloadable); + } if (n_downloadable > n_per_request) req_plural = rtr_plural = "s"; @@ -5181,8 +5166,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote, ++n_inprogress; continue; /* We have an in-progress download. */ } - if (!download_status_is_ready(&rs->dl_status, now, - options->TestingDescriptorMaxDownloadTries)) { + if (!download_status_is_ready(&rs->dl_status, now)) { ++n_delayed; /* Not ready for retry. */ continue; } @@ -5190,8 +5174,8 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote, ++n_would_reject; continue; /* We would throw it out immediately. */ } - if (!directory_caches_dir_info(options) && - !client_would_use_router(rs, now, options)) { + if (!we_want_to_fetch_flavor(options, consensus->flavor) && + !client_would_use_router(rs, now)) { ++n_wouldnt_use; continue; /* We would never use it ourself. */ } @@ -5212,7 +5196,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote, smartlist_add(downloadable, rs->descriptor_digest); } SMARTLIST_FOREACH_END(rsp); - if (!authdir_mode_handles_descs(options, ROUTER_PURPOSE_GENERAL) + if (!authdir_mode_v3(options) && smartlist_len(no_longer_old)) { routerlist_t *rl = router_get_routerlist(); log_info(LD_DIR, "%d router descriptors listed in consensus are " @@ -5221,15 +5205,30 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote, SMARTLIST_FOREACH_BEGIN(no_longer_old, signed_descriptor_t *, sd) { const char *msg; was_router_added_t r; + time_t tmp_cert_expiration_time; routerinfo_t *ri = routerlist_reparse_old(rl, sd); if (!ri) { log_warn(LD_BUG, "Failed to re-parse a router."); continue; } + /* need to remember for below, since add_to_routerlist may free. */ + tmp_cert_expiration_time = ri->cert_expiration_time; + r = router_add_to_routerlist(ri, &msg, 1, 0); if (WRA_WAS_OUTDATED(r)) { - log_warn(LD_DIR, "Couldn't add re-parsed router: %s", + log_warn(LD_DIR, "Couldn't add re-parsed router: %s. This isn't " + "usually a big deal, but you should make sure that your " + "clock and timezone are set correctly.", msg?msg:"???"); + if (r == ROUTER_CERTS_EXPIRED) { + char time_cons[ISO_TIME_LEN+1]; + char time_cert_expires[ISO_TIME_LEN+1]; + format_iso_time(time_cons, consensus->valid_after); + format_iso_time(time_cert_expires, tmp_cert_expiration_time); + log_warn(LD_DIR, " (I'm looking at a consensus from %s; This " + "router's certificates began expiring at %s.)", + time_cons, time_cert_expires); + } } } SMARTLIST_FOREACH_END(sd); routerlist_assert_ok(rl); @@ -5343,8 +5342,7 @@ update_extrainfo_downloads(time_t now) ++n_have; continue; } - if (!download_status_is_ready(&sd->ei_dl_status, now, - options->TestingDescriptorMaxDownloadTries)) { + if (!download_status_is_ready(&sd->ei_dl_status, now)) { ++n_delay; continue; } @@ -5406,8 +5404,10 @@ update_extrainfo_downloads(time_t now) smartlist_free(wanted); } -/** Reset the descriptor download failure count on all routers, so that we - * can retry any long-failed routers immediately. +/** Reset the consensus and extra-info download failure count on all routers. + * When we get a new consensus, + * routers_update_status_from_consensus_networkstatus() will reset the + * download statuses on the descriptors in that consensus. */ void router_reset_descriptor_download_failures(void) @@ -5419,6 +5419,8 @@ router_reset_descriptor_download_failures(void) last_descriptor_download_attempted = 0; if (!routerlist) return; + /* We want to download *all* extra-info descriptors, not just those in + * the consensus we currently have (or are about to have) */ SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, ri, { download_status_reset(&ri->cache_info.ei_dl_status); @@ -5660,11 +5662,11 @@ routerstatus_version_supports_extend2_cells(const routerstatus_t *rs, return allow_unknown_versions; } - if (!rs->protocols_known) { + if (!rs->pv.protocols_known) { return allow_unknown_versions; } - return rs->supports_extend2_cells; + return rs->pv.supports_extend2_cells; } /** Assert that the internal representation of <b>rl</b> is |