/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2012, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "or.h" #include "address.h" #include "config.h" #include "control.h" #include "dirserv.h" #include "geoip.h" #include "main.h" #include "microdesc.h" #include "networkstatus.h" #include "nodelist.h" #include "policies.h" #include "rendservice.h" #include "router.h" #include "routerlist.h" #include "routerset.h" #include static void nodelist_drop_node(node_t *node, int remove_from_ht); static void node_free(node_t *node); static void update_router_have_minimum_dir_info(void); /** A nodelist_t holds a node_t object for every router we're "willing to use * for something". Specifically, it should hold a node_t for every node that * is currently in the routerlist, or currently in the consensus we're using. */ typedef struct nodelist_t { /* A list of all the nodes. */ smartlist_t *nodes; /* Hash table to map from node ID digest to node. */ HT_HEAD(nodelist_map, node_t) nodes_by_id; } nodelist_t; static INLINE unsigned int node_id_hash(const node_t *node) { #if SIZEOF_INT == 4 const uint32_t *p = (const uint32_t*)node->identity; return p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4]; #elif SIZEOF_INT == 8 const uint64_t *p = (const uint32_t*)node->identity; const uint32_t *p32 = (const uint32_t*)node->identity; return p[0] ^ p[1] ^ p32[4]; #endif } static INLINE unsigned int node_id_eq(const node_t *node1, const node_t *node2) { return tor_memeq(node1->identity, node2->identity, DIGEST_LEN); } HT_PROTOTYPE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq); HT_GENERATE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq, 0.6, malloc, realloc, free); /** The global nodelist. */ static nodelist_t *the_nodelist=NULL; /** Create an empty nodelist if we haven't done so already. */ static void init_nodelist(void) { if (PREDICT_UNLIKELY(the_nodelist == NULL)) { the_nodelist = tor_malloc_zero(sizeof(nodelist_t)); HT_INIT(nodelist_map, &the_nodelist->nodes_by_id); the_nodelist->nodes = smartlist_new(); } } /** As node_get_by_id, but returns a non-const pointer */ node_t * node_get_mutable_by_id(const char *identity_digest) { node_t search, *node; if (PREDICT_UNLIKELY(the_nodelist == NULL)) return NULL; memcpy(&search.identity, identity_digest, DIGEST_LEN); node = HT_FIND(nodelist_map, &the_nodelist->nodes_by_id, &search); return node; } /** Return the node_t whose identity is identity_digest, or NULL * if no such node exists. */ const node_t * node_get_by_id(const char *identity_digest) { return node_get_mutable_by_id(identity_digest); } /** Internal: return the node_t whose identity_digest is * identity_digest. If none exists, create a new one, add it to the * nodelist, and return it. * * Requires that the nodelist be initialized. */ static node_t * node_get_or_create(const char *identity_digest) { node_t *node; if ((node = node_get_mutable_by_id(identity_digest))) return node; node = tor_malloc_zero(sizeof(node_t)); memcpy(node->identity, identity_digest, DIGEST_LEN); HT_INSERT(nodelist_map, &the_nodelist->nodes_by_id, node); smartlist_add(the_nodelist->nodes, node); node->nodelist_idx = smartlist_len(the_nodelist->nodes) - 1; node->country = -1; return node; } /** Called when a node's address changes. */ static void node_addrs_changed(node_t *node) { node->last_reachable = node->last_reachable6 = 0; node->country = -1; } /** Add ri to an appropriate node in the nodelist. If we replace an * old routerinfo, and ri_old_out is not NULL, set *ri_old_out * to the previous routerinfo. */ node_t * nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out) { node_t *node; const char *id_digest; int had_router = 0; tor_assert(ri); init_nodelist(); id_digest = ri->cache_info.identity_digest; node = node_get_or_create(id_digest); if (node->ri) { if (!routers_have_same_or_addrs(node->ri, ri)) { node_addrs_changed(node); } had_router = 1; if (ri_old_out) *ri_old_out = node->ri; } else { if (ri_old_out) *ri_old_out = NULL; } node->ri = ri; if (node->country == -1) node_set_country(node); if (authdir_mode(get_options()) && !had_router) { const char *discard=NULL; uint32_t status = dirserv_router_get_status(ri, &discard); dirserv_set_node_flags_from_authoritative_status(node, status); } return node; } /** Set the appropriate node_t to use md as its microdescriptor. * * Called when a new microdesc has arrived and the usable consensus flavor * is "microdesc". **/ node_t * nodelist_add_microdesc(microdesc_t *md) { networkstatus_t *ns = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC); const routerstatus_t *rs; node_t *node; if (ns == NULL) return NULL; init_nodelist(); /* Microdescriptors don't carry an identity digest, so we need to figure * it out by looking up the routerstatus. */ rs = router_get_consensus_status_by_descriptor_digest(ns, md->digest); if (rs == NULL) return NULL; node = node_get_mutable_by_id(rs->identity_digest); if (node) { if (node->md) node->md->held_by_nodes--; node->md = md; md->held_by_nodes++; } return node; } /** Tell the nodelist that the current usable consensus is ns. * This makes the nodelist change all of the routerstatus entries for * the nodes, drop nodes that no longer have enough info to get used, * and grab microdescriptors into nodes as appropriate. */ void nodelist_set_consensus(networkstatus_t *ns) { const or_options_t *options = get_options(); int authdir = authdir_mode_v2(options) || authdir_mode_v3(options); int client = !server_mode(options); init_nodelist(); if (ns->flavor == FLAV_MICRODESC) (void) get_microdesc_cache(); /* Make sure it exists first. */ SMARTLIST_FOREACH(the_nodelist->nodes, node_t *, node, node->rs = NULL); SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { node_t *node = node_get_or_create(rs->identity_digest); node->rs = rs; if (ns->flavor == FLAV_MICRODESC) { if (node->md == NULL || tor_memneq(node->md->digest,rs->descriptor_digest,DIGEST256_LEN)) { if (node->md) node->md->held_by_nodes--; node->md = microdesc_cache_lookup_by_digest256(NULL, rs->descriptor_digest); if (node->md) node->md->held_by_nodes++; } } node_set_country(node); /* If we're not an authdir, believe others. */ if (!authdir) { node->is_valid = rs->is_valid; node->is_running = rs->is_flagged_running; node->is_fast = rs->is_fast; node->is_stable = rs->is_stable; node->is_possible_guard = rs->is_possible_guard; node->is_exit = rs->is_exit; node->is_bad_directory = rs->is_bad_directory; node->is_bad_exit = rs->is_bad_exit; node->is_hs_dir = rs->is_hs_dir; node->ipv6_preferred = 0; if (client && options->ClientPreferIPv6ORPort == 1 && (tor_addr_is_null(&rs->ipv6_addr) == 0 || (node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0))) node->ipv6_preferred = 1; } } SMARTLIST_FOREACH_END(rs); nodelist_purge(); if (! authdir) { SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { /* We have no routerstatus for this router. Clear flags so we can skip * it, maybe.*/ if (!node->rs) { tor_assert(node->ri); /* if it had only an md, or nothing, purge * would have removed it. */ if (node->ri->purpose == ROUTER_PURPOSE_GENERAL) { /* Clear all flags. */ node->is_valid = node->is_running = node->is_hs_dir = node->is_fast = node->is_stable = node->is_possible_guard = node->is_exit = node->is_bad_exit = node->is_bad_directory = node->ipv6_preferred = 0; } } } SMARTLIST_FOREACH_END(node); } } /** Helper: return true iff a node has a usable amount of information*/ static INLINE int node_is_usable(const node_t *node) { return (node->rs) || (node->ri); } /** Tell the nodelist that md is no longer a microdescriptor for the * node with identity_digest. */ void nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md) { node_t *node = node_get_mutable_by_id(identity_digest); if (node && node->md == md) { node->md = NULL; md->held_by_nodes--; } } /** Tell the nodelist that ri is no longer in the routerlist. */ void nodelist_remove_routerinfo(routerinfo_t *ri) { node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest); if (node && node->ri == ri) { node->ri = NULL; if (! node_is_usable(node)) { nodelist_drop_node(node, 1); node_free(node); } } } /** Remove node from the nodelist. (Asserts that it was there to begin * with.) */ static void nodelist_drop_node(node_t *node, int remove_from_ht) { node_t *tmp; int idx; if (remove_from_ht) { tmp = HT_REMOVE(nodelist_map, &the_nodelist->nodes_by_id, node); tor_assert(tmp == node); } idx = node->nodelist_idx; tor_assert(idx >= 0); tor_assert(node == smartlist_get(the_nodelist->nodes, idx)); smartlist_del(the_nodelist->nodes, idx); if (idx < smartlist_len(the_nodelist->nodes)) { tmp = smartlist_get(the_nodelist->nodes, idx); tmp->nodelist_idx = idx; } node->nodelist_idx = -1; } /** Release storage held by node */ static void node_free(node_t *node) { if (!node) return; if (node->md) node->md->held_by_nodes--; tor_assert(node->nodelist_idx == -1); tor_free(node); } /** Remove all entries from the nodelist that don't have enough info to be * usable for anything. */ void nodelist_purge(void) { node_t **iter; if (PREDICT_UNLIKELY(the_nodelist == NULL)) return; /* Remove the non-usable nodes. */ for (iter = HT_START(nodelist_map, &the_nodelist->nodes_by_id); iter; ) { node_t *node = *iter; if (node->md && !node->rs) { /* An md is only useful if there is an rs. */ node->md->held_by_nodes--; node->md = NULL; } if (node_is_usable(node)) { iter = HT_NEXT(nodelist_map, &the_nodelist->nodes_by_id, iter); } else { iter = HT_NEXT_RMV(nodelist_map, &the_nodelist->nodes_by_id, iter); nodelist_drop_node(node, 0); node_free(node); } } nodelist_assert_ok(); } /** Release all storage held by the nodelist. */ void nodelist_free_all(void) { if (PREDICT_UNLIKELY(the_nodelist == NULL)) return; HT_CLEAR(nodelist_map, &the_nodelist->nodes_by_id); SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { node->nodelist_idx = -1; node_free(node); } SMARTLIST_FOREACH_END(node); smartlist_free(the_nodelist->nodes); tor_free(the_nodelist); } /** Check that the nodelist is internally consistent, and consistent with * the directory info it's derived from. */ void nodelist_assert_ok(void) { routerlist_t *rl = router_get_routerlist(); networkstatus_t *ns = networkstatus_get_latest_consensus(); digestmap_t *dm; if (!the_nodelist) return; dm = digestmap_new(); /* every routerinfo in rl->routers should be in the nodelist. */ if (rl) { SMARTLIST_FOREACH_BEGIN(rl->routers, routerinfo_t *, ri) { const node_t *node = node_get_by_id(ri->cache_info.identity_digest); tor_assert(node && node->ri == ri); tor_assert(fast_memeq(ri->cache_info.identity_digest, node->identity, DIGEST_LEN)); tor_assert(! digestmap_get(dm, node->identity)); digestmap_set(dm, node->identity, (void*)node); } SMARTLIST_FOREACH_END(ri); } /* every routerstatus in ns should be in the nodelist */ if (ns) { SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) { const node_t *node = node_get_by_id(rs->identity_digest); tor_assert(node && node->rs == rs); tor_assert(fast_memeq(rs->identity_digest, node->identity, DIGEST_LEN)); digestmap_set(dm, node->identity, (void*)node); if (ns->flavor == FLAV_MICRODESC) { /* If it's a microdesc consensus, every entry that has a * microdescriptor should be in the nodelist. */ microdesc_t *md = microdesc_cache_lookup_by_digest256(NULL, rs->descriptor_digest); tor_assert(md == node->md); if (md) tor_assert(md->held_by_nodes >= 1); } } SMARTLIST_FOREACH_END(rs); } /* The nodelist should have no other entries, and its entries should be * well-formed. */ SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { tor_assert(digestmap_get(dm, node->identity) != NULL); tor_assert(node_sl_idx == node->nodelist_idx); } SMARTLIST_FOREACH_END(node); tor_assert((long)smartlist_len(the_nodelist->nodes) == (long)HT_SIZE(&the_nodelist->nodes_by_id)); digestmap_free(dm, NULL); } /** Return a list of a node_t * for every node we know about. The caller * MUST NOT modify the list. (You can set and clear flags in the nodes if * you must, but you must not add or remove nodes.) */ smartlist_t * nodelist_get_list(void) { init_nodelist(); return the_nodelist->nodes; } /** Given a hex-encoded nickname of the format DIGEST, $DIGEST, $DIGEST=name, * or $DIGEST~name, return the node with the matching identity digest and * nickname (if any). Return NULL if no such node exists, or if hex_id * is not well-formed. */ const node_t * node_get_by_hex_id(const char *hex_id) { char digest_buf[DIGEST_LEN]; char nn_buf[MAX_NICKNAME_LEN+1]; char nn_char='\0'; if (hex_digest_nickname_decode(hex_id, digest_buf, &nn_char, nn_buf)==0) { const node_t *node = node_get_by_id(digest_buf); if (!node) return NULL; if (nn_char) { const char *real_name = node_get_nickname(node); if (!real_name || strcasecmp(real_name, nn_buf)) return NULL; if (nn_char == '=') { const char *named_id = networkstatus_get_router_digest_by_nickname(nn_buf); if (!named_id || tor_memneq(named_id, digest_buf, DIGEST_LEN)) return NULL; } } return node; } return NULL; } /** Given a nickname (possibly verbose, possibly a hexadecimal digest), return * the corresponding node_t, or NULL if none exists. Warn the user if * warn_if_unnamed is set, and they have specified a router by * nickname, but the Named flag isn't set for that router. */ const node_t * node_get_by_nickname(const char *nickname, int warn_if_unnamed) { const node_t *node; if (!the_nodelist) return NULL; /* Handle these cases: DIGEST, $DIGEST, $DIGEST=name, $DIGEST~name. */ if ((node = node_get_by_hex_id(nickname)) != NULL) return node; if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) return NULL; /* Okay, so if we get here, the nickname is just a nickname. Is there * a binding for it in the consensus? */ { const char *named_id = networkstatus_get_router_digest_by_nickname(nickname); if (named_id) return node_get_by_id(named_id); } /* Is it marked as owned-by-someone-else? */ if (networkstatus_nickname_is_unnamed(nickname)) { log_info(LD_GENERAL, "The name %s is listed as Unnamed: there is some " "router that holds it, but not one listed in the current " "consensus.", escaped(nickname)); return NULL; } /* Okay, so the name is not canonical for anybody. */ { smartlist_t *matches = smartlist_new(); const node_t *choice = NULL; SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) { if (!strcasecmp(node_get_nickname(node), nickname)) smartlist_add(matches, node); } SMARTLIST_FOREACH_END(node); if (smartlist_len(matches)>1 && warn_if_unnamed) { int any_unwarned = 0; SMARTLIST_FOREACH_BEGIN(matches, node_t *, node) { if (!node->name_lookup_warned) { node->name_lookup_warned = 1; any_unwarned = 1; } } SMARTLIST_FOREACH_END(node); if (any_unwarned) { log_warn(LD_CONFIG, "There are multiple matches for the name %s, " "but none is listed as Named in the directory consensus. " "Choosing one arbitrarily.", nickname); } } else if (smartlist_len(matches)>1 && warn_if_unnamed) { char fp[HEX_DIGEST_LEN+1]; node_t *node = smartlist_get(matches, 0); if (node->name_lookup_warned) { base16_encode(fp, sizeof(fp), node->identity, DIGEST_LEN); log_warn(LD_CONFIG, "You specified a server \"%s\" by name, but the directory " "authorities do not have any key registered for this " "nickname -- so it could be used by any server, not just " "the one you meant. " "To make sure you get the same server in the future, refer " "to it by key, as \"$%s\".", nickname, fp); node->name_lookup_warned = 1; } } if (smartlist_len(matches)) choice = smartlist_get(matches, 0); smartlist_free(matches); return choice; } } /** Return the nickname of node, or NULL if we can't find one. */ const char * node_get_nickname(const node_t *node) { tor_assert(node); if (node->rs) return node->rs->nickname; else if (node->ri) return node->ri->nickname; else return NULL; } /** Return true iff the nickname of node is canonical, based on the * latest consensus. */ int node_is_named(const node_t *node) { const char *named_id; const char *nickname = node_get_nickname(node); if (!nickname) return 0; named_id = networkstatus_get_router_digest_by_nickname(nickname); if (!named_id) return 0; return tor_memeq(named_id, node->identity, DIGEST_LEN); } /** Return true iff node appears to be a directory authority or * directory cache */ int node_is_dir(const node_t *node) { if (node->rs) return node->rs->dir_port != 0; else if (node->ri) return node->ri->dir_port != 0; else return 0; } /** Return true iff node has either kind of usable descriptor -- that * is, a routerdescriptor or a microdescriptor. */ int node_has_descriptor(const node_t *node) { return (node->ri || (node->rs && node->md)); } /** Return the router_purpose of node. */ int node_get_purpose(const node_t *node) { if (node->ri) return node->ri->purpose; else return ROUTER_PURPOSE_GENERAL; } /** Compute the verbose ("extended") nickname of node and store it * into the MAX_VERBOSE_NICKNAME_LEN+1 character buffer at * verbose_nickname_out */ void node_get_verbose_nickname(const node_t *node, char *verbose_name_out) { const char *nickname = node_get_nickname(node); int is_named = node_is_named(node); verbose_name_out[0] = '$'; base16_encode(verbose_name_out+1, HEX_DIGEST_LEN+1, node->identity, DIGEST_LEN); if (!nickname) return; verbose_name_out[1+HEX_DIGEST_LEN] = is_named ? '=' : '~'; strlcpy(verbose_name_out+1+HEX_DIGEST_LEN+1, nickname, MAX_NICKNAME_LEN+1); } /** Return true iff it seems that node allows circuits to exit * through it directlry from the client. */ int node_allows_single_hop_exits(const node_t *node) { if (node && node->ri) return node->ri->allow_single_hop_exits; else return 0; } /** Return true iff it seems that node has an exit policy that doesn't * actually permit anything to exit, or we don't know its exit policy */ int node_exit_policy_rejects_all(const node_t *node) { if (node->rejects_all) return 1; if (node->ri) return node->ri->policy_is_reject_star; else if (node->md) return node->md->exit_policy == NULL || short_policy_is_reject_star(node->md->exit_policy); else return 1; } /** Return list of tor_addr_port_t with all OR ports (in the sense IP * addr + TCP port) for node. Caller must free all elements * using tor_free() and free the list using smartlist_free(). * * XXX this is potentially a memory fragmentation hog -- if on * critical path consider the option of having the caller allocate the * memory */ smartlist_t * node_get_all_orports(const node_t *node) { smartlist_t *sl = smartlist_new(); if (node->ri != NULL) { if (node->ri->addr != 0) { tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); tor_addr_from_ipv4h(&ap->addr, node->ri->addr); ap->port = node->ri->or_port; smartlist_add(sl, ap); } if (!tor_addr_is_null(&node->ri->ipv6_addr)) { tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); tor_addr_copy(&ap->addr, &node->ri->ipv6_addr); ap->port = node->ri->or_port; smartlist_add(sl, ap); } } else if (node->rs != NULL) { tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); tor_addr_from_ipv4h(&ap->addr, node->rs->addr); ap->port = node->rs->or_port; smartlist_add(sl, ap); } return sl; } /** Wrapper around node_get_prim_orport for backward compatibility. */ void node_get_addr(const node_t *node, tor_addr_t *addr_out) { tor_addr_port_t ap; node_get_prim_orport(node, &ap); tor_addr_copy(addr_out, &ap.addr); } /** Return the host-order IPv4 address for node, or 0 if it doesn't * seem to have one. */ uint32_t node_get_prim_addr_ipv4h(const node_t *node) { if (node->ri) { return node->ri->addr; } else if (node->rs) { return node->rs->addr; } return 0; } /** Copy a string representation of an IP address for node into * the len-byte buffer at buf. */ void node_get_address_string(const node_t *node, char *buf, size_t len) { if (node->ri) { strlcpy(buf, node->ri->address, len); } else if (node->rs) { tor_addr_t addr; tor_addr_from_ipv4h(&addr, node->rs->addr); tor_addr_to_str(buf, &addr, len, 0); } else { buf[0] = '\0'; } } /** Return node's declared uptime, or -1 if it doesn't seem to have * one. */ long node_get_declared_uptime(const node_t *node) { if (node->ri) return node->ri->uptime; else return -1; } /** Return node's platform string, or NULL if we don't know it. */ const char * node_get_platform(const node_t *node) { /* If we wanted, we could record the version in the routerstatus_t, since * the consensus lists it. We don't, though, so this function just won't * work with microdescriptors. */ if (node->ri) return node->ri->platform; else return NULL; } /** Return node's time of publication, or 0 if we don't have one. */ time_t node_get_published_on(const node_t *node) { if (node->ri) return node->ri->cache_info.published_on; else return 0; } /** Return true iff node is one representing this router. */ int node_is_me(const node_t *node) { return router_digest_is_me(node->identity); } /** Return node declared family (as a list of names), or NULL if * the node didn't declare a family. */ const smartlist_t * node_get_declared_family(const node_t *node) { if (node->ri && node->ri->declared_family) return node->ri->declared_family; else if (node->md && node->md->family) return node->md->family; else return NULL; } /** Return 1 if we prefer the IPv6 address and OR TCP port of * node, else 0. * * We prefer the IPv6 address if the router has an IPv6 address and * i) the node_t says that it prefers IPv6 * or * ii) the router has no IPv4 address. */ int node_ipv6_preferred(const node_t *node) { tor_addr_port_t ipv4_addr; node_assert_ok(node); if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr)) { if (node->ri) return !tor_addr_is_null(&node->ri->ipv6_addr); if (node->md) return !tor_addr_is_null(&node->md->ipv6_addr); if (node->rs) return !tor_addr_is_null(&node->rs->ipv6_addr); } return 0; } /** Copy the primary (IPv4) OR port (IP address and TCP port) for * node into *ap_out. Return 0 if a valid address and * port was copied, else return non-zero.*/ int node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out) { node_assert_ok(node); tor_assert(ap_out); if (node->ri) { if (node->ri->addr == 0 || node->ri->or_port == 0) return -1; tor_addr_from_ipv4h(&ap_out->addr, node->ri->addr); ap_out->port = node->ri->or_port; return 0; } if (node->rs) { if (node->rs->addr == 0 || node->rs->or_port == 0) return -1; tor_addr_from_ipv4h(&ap_out->addr, node->rs->addr); ap_out->port = node->rs->or_port; return 0; } return -1; } /** Copy the preferred OR port (IP address and TCP port) for * node into *ap_out. */ void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out) { const or_options_t *options = get_options(); tor_assert(ap_out); /* Cheap implementation of config option ClientUseIPv6 -- simply don't prefer IPv6 when ClientUseIPv6 is not set and we're not a client running with bridges. See #4455 for more on this subject. Note that this filter is too strict since we're hindering not only clients! Erring on the safe side shouldn't be a problem though. XXX move this check to where outgoing connections are made? -LN */ if ((options->ClientUseIPv6 || options->UseBridges) && node_ipv6_preferred(node)) { node_get_pref_ipv6_orport(node, ap_out); } else { node_get_prim_orport(node, ap_out); } } /** Copy the preferred IPv6 OR port (IP address and TCP port) for * node into *ap_out. */ void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out) { node_assert_ok(node); tor_assert(ap_out); /* We prefer the microdesc over a potential routerstatus here. They are not being synchronised atm so there might be a chance that they differ at some point, f.ex. when flipping UseMicrodescriptors? -LN */ if (node->ri) { tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr); ap_out->port = node->ri->ipv6_orport; } else if (node->md) { tor_addr_copy(&ap_out->addr, &node->md->ipv6_addr); ap_out->port = node->md->ipv6_orport; } else if (node->rs) { tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr); ap_out->port = node->rs->ipv6_orport; } } /** Refresh the country code of ri. This function MUST be called on * each router when the GeoIP database is reloaded, and on all new routers. */ void node_set_country(node_t *node) { tor_addr_t addr = TOR_ADDR_NULL; /* XXXXipv6 */ if (node->rs) tor_addr_from_ipv4h(&addr, node->rs->addr); else if (node->ri) tor_addr_from_ipv4h(&addr, node->ri->addr); node->country = geoip_get_country_by_addr(&addr); } /** Set the country code of all routers in the routerlist. */ void nodelist_refresh_countries(void) { smartlist_t *nodes = nodelist_get_list(); SMARTLIST_FOREACH(nodes, node_t *, node, node_set_country(node)); } /** Return true iff router1 and router2 have similar enough network addresses * that we should treat them as being in the same family */ static INLINE int addrs_in_same_network_family(const tor_addr_t *a1, const tor_addr_t *a2) { return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC); } /** Return true if node's nickname matches nickname * (case-insensitive), or if node's identity key digest * matches a hexadecimal value stored in nickname. Return * false otherwise. */ static int node_nickname_matches(const node_t *node, const char *nickname) { const char *n = node_get_nickname(node); if (n && nickname[0]!='$' && !strcasecmp(n, nickname)) return 1; return hex_digest_nickname_matches(nickname, node->identity, n, node_is_named(node)); } /** Return true iff node is named by some nickname in lst. */ static INLINE int node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node) { if (!lst) return 0; SMARTLIST_FOREACH(lst, const char *, name, { if (node_nickname_matches(node, name)) return 1; }); return 0; } /** Return true iff r1 and r2 are in the same family, but not the same * router. */ int nodes_in_same_family(const node_t *node1, const node_t *node2) { const or_options_t *options = get_options(); /* Are they in the same family because of their addresses? */ if (options->EnforceDistinctSubnets) { tor_addr_t a1, a2; node_get_addr(node1, &a1); node_get_addr(node2, &a2); if (addrs_in_same_network_family(&a1, &a2)) return 1; } /* Are they in the same family because the agree they are? */ { const smartlist_t *f1, *f2; f1 = node_get_declared_family(node1); f2 = node_get_declared_family(node2); if (f1 && f2 && node_in_nickname_smartlist(f1, node2) && node_in_nickname_smartlist(f2, node1)) return 1; } /* Are they in the same option because the user says they are? */ if (options->NodeFamilySets) { SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, { if (routerset_contains_node(rs, node1) && routerset_contains_node(rs, node2)) return 1; }); } return 0; } /** * Add all the family of node, including node itself, to * the smartlist sl. * * This is used to make sure we don't pick siblings in a single path, or * pick more than one relay from a family for our entry guard list. * Note that a node may be added to sl more than once if it is * part of node's family for more than one reason. */ void nodelist_add_node_and_family(smartlist_t *sl, const node_t *node) { const smartlist_t *all_nodes = nodelist_get_list(); const smartlist_t *declared_family; const or_options_t *options = get_options(); tor_assert(node); declared_family = node_get_declared_family(node); /* Let's make sure that we have the node itself, if it's a real node. */ { const node_t *real_node = node_get_by_id(node->identity); if (real_node) smartlist_add(sl, (node_t*)real_node); } /* First, add any nodes with similar network addresses. */ if (options->EnforceDistinctSubnets) { tor_addr_t node_addr; node_get_addr(node, &node_addr); SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) { tor_addr_t a; node_get_addr(node2, &a); if (addrs_in_same_network_family(&a, &node_addr)) smartlist_add(sl, (void*)node2); } SMARTLIST_FOREACH_END(node2); } /* Now, add all nodes in the declared_family of this node, if they * also declare this node to be in their family. */ if (declared_family) { /* Add every r such that router declares familyness with node, and node * declares familyhood with router. */ SMARTLIST_FOREACH_BEGIN(declared_family, const char *, name) { const node_t *node2; const smartlist_t *family2; if (!(node2 = node_get_by_nickname(name, 0))) continue; if (!(family2 = node_get_declared_family(node2))) continue; SMARTLIST_FOREACH_BEGIN(family2, const char *, name2) { if (node_nickname_matches(node, name2)) { smartlist_add(sl, (void*)node2); break; } } SMARTLIST_FOREACH_END(name2); } SMARTLIST_FOREACH_END(name); } /* If the user declared any families locally, honor those too. */ if (options->NodeFamilySets) { SMARTLIST_FOREACH(options->NodeFamilySets, const routerset_t *, rs, { if (routerset_contains_node(rs, node)) { routerset_get_all_nodes(sl, rs, NULL, 0); } }); } } /** Find a router that's up, that has this IP address, and * that allows exit to this address:port, or return NULL if there * isn't a good one. * Don't exit enclave to excluded relays -- it wouldn't actually * hurt anything, but this way there are fewer confused users. */ const node_t * router_find_exact_exit_enclave(const char *address, uint16_t port) {/*XXXX MOVE*/ uint32_t addr; struct in_addr in; tor_addr_t a; const or_options_t *options = get_options(); if (!tor_inet_aton(address, &in)) return NULL; /* it's not an IP already */ addr = ntohl(in.s_addr); tor_addr_from_ipv4h(&a, addr); SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, { if (node_get_addr_ipv4h(node) == addr && node->is_running && compare_tor_addr_to_node_policy(&a, port, node) == ADDR_POLICY_ACCEPTED && !routerset_contains_node(options->ExcludeExitNodesUnion_, node)) return node; }); return NULL; } /** Return 1 if router is not suitable for these parameters, else 0. * If need_uptime is non-zero, we require a minimum uptime. * If need_capacity is non-zero, we require a minimum advertised * bandwidth. * If need_guard, we require that the router is a possible entry guard. */ int node_is_unreliable(const node_t *node, int need_uptime, int need_capacity, int need_guard) { if (need_uptime && !node->is_stable) return 1; if (need_capacity && !node->is_fast) return 1; if (need_guard && !node->is_possible_guard) return 1; return 0; } /** Return 1 if all running sufficiently-stable routers we can use will reject * addr:port. Return 0 if any might accept it. */ int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port, int need_uptime) { addr_policy_result_t r; SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { if (node->is_running && !node_is_unreliable(node, need_uptime, 0, 0)) { r = compare_tor_addr_to_node_policy(addr, port, node); if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED) return 0; /* this one could be ok. good enough. */ } } SMARTLIST_FOREACH_END(node); return 1; /* all will reject. */ } /** Mark the router with ID digest as running or non-running * in our routerlist. */ void router_set_status(const char *digest, int up) { node_t *node; tor_assert(digest); SMARTLIST_FOREACH(router_get_fallback_dir_servers(), dir_server_t *, d, if (tor_memeq(d->digest, digest, DIGEST_LEN)) d->is_running = up); SMARTLIST_FOREACH(router_get_trusted_dir_servers(), dir_server_t *, d, if (tor_memeq(d->digest, digest, DIGEST_LEN)) d->is_running = up); node = node_get_mutable_by_id(digest); if (node) { #if 0 log_debug(LD_DIR,"Marking router %s as %s.", node_describe(node), up ? "up" : "down"); #endif if (!up && node_is_me(node) && !net_is_disabled()) log_warn(LD_NET, "We just marked ourself as down. Are your external " "addresses reachable?"); node->is_running = up; } router_dir_info_changed(); } /** True iff, the last time we checked whether we had enough directory info * to build circuits, the answer was "yes". */ static int have_min_dir_info = 0; /** True iff enough has changed since the last time we checked whether we had * enough directory info to build circuits that our old answer can no longer * be trusted. */ static int need_to_update_have_min_dir_info = 1; /** String describing what we're missing before we have enough directory * info. */ static char dir_info_status[128] = ""; /** Return true iff we have enough networkstatus and router information to * start building circuits. Right now, this means "more than half the * networkstatus documents, and at least 1/4 of expected routers." */ //XXX should consider whether we have enough exiting nodes here. int router_have_minimum_dir_info(void) { if (PREDICT_UNLIKELY(need_to_update_have_min_dir_info)) { update_router_have_minimum_dir_info(); need_to_update_have_min_dir_info = 0; } return have_min_dir_info; } /** Called when our internal view of the directory has changed. This can be * when the authorities change, networkstatuses change, the list of routerdescs * changes, or number of running routers changes. */ void router_dir_info_changed(void) { need_to_update_have_min_dir_info = 1; rend_hsdir_routers_changed(); } /** Return a string describing what we're missing before we have enough * directory info. */ const char * get_dir_info_status_string(void) { return dir_info_status; } /** Iterate over the servers listed in consensus, and count how many of * them seem like ones we'd use, and how many of those we have * descriptors for. Store the former in *num_usable and the latter in * *num_present. If in_set is non-NULL, only consider those * routers in in_set. If exit_only is true, only consider nodes * with the Exit flag. */ static void count_usable_descriptors(int *num_present, int *num_usable, const networkstatus_t *consensus, const or_options_t *options, time_t now, routerset_t *in_set, int exit_only) { const int md = (consensus->flavor == FLAV_MICRODESC); *num_present = 0, *num_usable=0; SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs) { if (exit_only && ! rs->is_exit) continue; if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1)) continue; if (client_would_use_router(rs, now, options)) { const char * const digest = rs->descriptor_digest; int present; ++*num_usable; /* the consensus says we want it. */ if (md) present = NULL != microdesc_cache_lookup_by_digest256(NULL, digest); else present = NULL != router_get_by_descriptor_digest(digest); if (present) { /* we have the descriptor listed in the consensus. */ ++*num_present; } } } SMARTLIST_FOREACH_END(rs); log_debug(LD_DIR, "%d usable, %d present (%s%s).", *num_usable, *num_present, md ? "microdesc" : "desc", exit_only ? " exits" : "s"); } /** We just fetched a new set of descriptors. Compute how far through * the "loading descriptors" bootstrapping phase we are, so we can inform * the controller of our progress. */ int count_loading_descriptors_progress(void) { int num_present = 0, num_usable=0; time_t now = time(NULL); const networkstatus_t *consensus = networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor()); double fraction; if (!consensus) return 0; /* can't count descriptors if we have no list of them */ count_usable_descriptors(&num_present, &num_usable, consensus, get_options(), now, NULL, 0); if (num_usable == 0) return 0; /* don't div by 0 */ fraction = num_present / (num_usable/4.); if (fraction > 1.0) return 0; /* it's not the number of descriptors holding us back */ return BOOTSTRAP_STATUS_LOADING_DESCRIPTORS + (int) (fraction*(BOOTSTRAP_STATUS_CONN_OR-1 - BOOTSTRAP_STATUS_LOADING_DESCRIPTORS)); } /** Change the value of have_min_dir_info, setting it true iff we have enough * network and router information to build circuits. Clear the value of * need_to_update_have_min_dir_info. */ static void update_router_have_minimum_dir_info(void) { int num_present = 0, num_usable=0; int num_exit_present = 0, num_exit_usable = 0; time_t now = time(NULL); int res; const or_options_t *options = get_options(); const networkstatus_t *consensus = networkstatus_get_reasonably_live_consensus(now,usable_consensus_flavor()); int using_md; if (!consensus) { if (!networkstatus_get_latest_consensus()) strlcpy(dir_info_status, "We have no usable consensus.", sizeof(dir_info_status)); else strlcpy(dir_info_status, "We have no recent usable consensus.", sizeof(dir_info_status)); res = 0; goto done; } if (should_delay_dir_fetches(get_options())) { log_notice(LD_DIR, "no known bridge descriptors running yet; stalling"); strlcpy(dir_info_status, "No live bridge descriptors.", sizeof(dir_info_status)); res = 0; goto done; } using_md = consensus->flavor == FLAV_MICRODESC; count_usable_descriptors(&num_present, &num_usable, consensus, options, now, NULL, 0); count_usable_descriptors(&num_exit_present, &num_exit_usable, consensus, options, now, options->ExitNodes, 1); /* What fraction of desired server descriptors do we need before we will * build circuits? */ #define FRAC_USABLE_NEEDED .75 /* What fraction of desired _exit_ server descriptors do we need before we * will build circuits? */ #define FRAC_EXIT_USABLE_NEEDED .5 if (num_present < num_usable * FRAC_USABLE_NEEDED) { tor_snprintf(dir_info_status, sizeof(dir_info_status), "We have only %d/%d usable %sdescriptors.", num_present, num_usable, using_md ? "micro" : ""); res = 0; control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); goto done; } else if (num_present < 2) { tor_snprintf(dir_info_status, sizeof(dir_info_status), "Only %d %sdescriptor%s here and believed reachable!", num_present, using_md ? "micro" : "", num_present ? "" : "s"); res = 0; goto done; } else if (num_exit_present < num_exit_usable * FRAC_EXIT_USABLE_NEEDED) { tor_snprintf(dir_info_status, sizeof(dir_info_status), "We have only %d/%d usable exit node descriptors.", num_exit_present, num_exit_usable); res = 0; control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); goto done; } /* Check for entry nodes. */ if (options->EntryNodes) { count_usable_descriptors(&num_present, &num_usable, consensus, options, now, options->EntryNodes, 0); if (!num_usable || !num_present) { tor_snprintf(dir_info_status, sizeof(dir_info_status), "We have only %d/%d usable entry node %sdescriptors.", num_present, num_usable, using_md?"micro":""); res = 0; goto done; } } res = 1; done: if (res && !have_min_dir_info) { log(LOG_NOTICE, LD_DIR, "We now have enough directory information to build circuits."); control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO"); control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0); } if (!res && have_min_dir_info) { int quiet = directory_too_idle_to_fetch_descriptors(options, now); log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR, "Our directory information is no longer up-to-date " "enough to build circuits: %s", dir_info_status); /* a) make us log when we next complete a circuit, so we know when Tor * is back up and usable, and b) disable some activities that Tor * should only do while circuits are working, like reachability tests * and fetching bridge descriptors only over circuits. */ can_complete_circuit = 0; control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO"); } have_min_dir_info = res; need_to_update_have_min_dir_info = 0; }