aboutsummaryrefslogtreecommitdiff
path: root/src/or/nodelist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/nodelist.c')
-rw-r--r--src/or/nodelist.c160
1 files changed, 130 insertions, 30 deletions
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index 26f990b08c..aaec39f7b8 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.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 */
/**
@@ -10,6 +10,32 @@
* \brief Structures and functions for tracking what we know about the routers
* on the Tor network, and correlating information from networkstatus,
* routerinfo, and microdescs.
+ *
+ * The key structure here is node_t: that's the canonical way to refer
+ * to a Tor relay that we might want to build a circuit through. Every
+ * node_t has either a routerinfo_t, or a routerstatus_t from the current
+ * networkstatus consensus. If it has a routerstatus_t, it will also
+ * need to have a microdesc_t before you can use it for circuits.
+ *
+ * The nodelist_t is a global singleton that maps identities to node_t
+ * objects. Access them with the node_get_*() functions. The nodelist_t
+ * is maintained by calls throughout the codebase
+ *
+ * Generally, other code should not have to reach inside a node_t to
+ * see what information it has. Instead, you should call one of the
+ * many accessor functions that works on a generic node_t. If there
+ * isn't one that does what you need, it's better to make such a function,
+ * and then use it.
+ *
+ * For historical reasons, some of the functions that select a node_t
+ * from the list of all usable node_t objects are in the routerlist.c
+ * module, since they originally selected a routerinfo_t. (TODO: They
+ * should move!)
+ *
+ * (TODO: Perhaps someday we should abstract the remaining ways of
+ * talking about a relay to also be node_t instances. Those would be
+ * routerstatus_t as used for directory requests, and dir_server_t as
+ * used for authorities and fallback directories.)
*/
#include "or.h"
@@ -18,16 +44,19 @@
#include "config.h"
#include "control.h"
#include "dirserv.h"
+#include "entrynodes.h"
#include "geoip.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "policies.h"
+#include "protover.h"
#include "rendservice.h"
#include "router.h"
#include "routerlist.h"
#include "routerset.h"
+#include "torcert.h"
#include <string.h>
@@ -46,7 +75,6 @@ static void count_usable_descriptors(int *num_present,
int *num_usable,
smartlist_t *descs_out,
const networkstatus_t *consensus,
- const or_options_t *options,
time_t now,
routerset_t *in_set,
usable_descriptor_t exit_only);
@@ -697,6 +725,73 @@ node_get_by_nickname,(const char *nickname, int warn_if_unnamed))
}
}
+/** Return the Ed25519 identity key for the provided node, or NULL if it
+ * doesn't have one. */
+const ed25519_public_key_t *
+node_get_ed25519_id(const node_t *node)
+{
+ if (node->ri) {
+ if (node->ri->cache_info.signing_key_cert) {
+ const ed25519_public_key_t *pk =
+ &node->ri->cache_info.signing_key_cert->signing_key;
+ if (BUG(ed25519_public_key_is_zero(pk)))
+ goto try_the_md;
+ return pk;
+ }
+ }
+ try_the_md:
+ if (node->md) {
+ if (node->md->ed25519_identity_pkey) {
+ return node->md->ed25519_identity_pkey;
+ }
+ }
+ return NULL;
+}
+
+/** Return true iff this node's Ed25519 identity matches <b>id</b>.
+ * (An absent Ed25519 identity matches NULL or zero.) */
+int
+node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id)
+{
+ const ed25519_public_key_t *node_id = node_get_ed25519_id(node);
+ if (node_id == NULL || ed25519_public_key_is_zero(node_id)) {
+ return id == NULL || ed25519_public_key_is_zero(id);
+ } else {
+ return id && ed25519_pubkey_eq(node_id, id);
+ }
+}
+
+/** Return true iff <b>node</b> supports authenticating itself
+ * by ed25519 ID during the link handshake in a way that we can understand
+ * when we probe it. */
+int
+node_supports_ed25519_link_authentication(const node_t *node)
+{
+ /* XXXX Oh hm. What if some day in the future there are link handshake
+ * versions that aren't 3 but which are ed25519 */
+ if (! node_get_ed25519_id(node))
+ return 0;
+ if (node->ri) {
+ const char *protos = node->ri->protocol_list;
+ if (protos == NULL)
+ return 0;
+ return protocol_list_supports_protocol(protos, PRT_LINKAUTH, 3);
+ }
+ if (node->rs) {
+ return node->rs->supports_ed25519_link_handshake;
+ }
+ tor_assert_nonfatal_unreached_once();
+ return 0;
+}
+
+/** Return the RSA ID key's SHA1 digest for the provided node. */
+const uint8_t *
+node_get_rsa_id_digest(const node_t *node)
+{
+ tor_assert(node);
+ return (const uint8_t*)node->identity;
+}
+
/** Return the nickname of <b>node</b>, or NULL if we can't find one. */
const char *
node_get_nickname(const node_t *node)
@@ -992,16 +1087,6 @@ node_get_platform(const node_t *node)
return NULL;
}
-/** Return <b>node</b>'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 <b>node</b> is one representing this router. */
int
node_is_me(const node_t *node)
@@ -1146,9 +1231,11 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
node_assert_ok(node);
tor_assert(ap_out);
- /* Prefer routerstatus over microdesc for consistency with the
- * fascist_firewall_* functions. Also check if the address or port are valid,
- * and try another alternative if they are not. */
+ /* Check ri first, because rewrite_node_address_for_bridge() updates
+ * node->ri with the configured bridge address.
+ * Prefer rs over md for consistency with the fascist_firewall_* functions.
+ * Check if the address or port are valid, and try another alternative
+ * if they are not. */
if (node->ri && tor_addr_port_is_valid(&node->ri->ipv6_addr,
node->ri->ipv6_orport, 0)) {
@@ -1208,6 +1295,9 @@ node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out)
node_assert_ok(node);
tor_assert(ap_out);
+ /* Check ri first, because rewrite_node_address_for_bridge() updates
+ * node->ri with the configured bridge address. */
+
RETURN_IPV4_AP(node->ri, dir_port, ap_out);
RETURN_IPV4_AP(node->rs, dir_port, ap_out);
/* Microdescriptors only have an IPv6 address */
@@ -1240,8 +1330,11 @@ node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out)
node_assert_ok(node);
tor_assert(ap_out);
- /* Check if the address or port are valid, and try another alternative if
- * they are not. Note that microdescriptors have no dir_port. */
+ /* Check ri first, because rewrite_node_address_for_bridge() updates
+ * node->ri with the configured bridge address.
+ * Prefer rs over md for consistency with the fascist_firewall_* functions.
+ * Check if the address or port are valid, and try another alternative
+ * if they are not. */
/* Assume IPv4 and IPv6 dirports are the same */
if (node->ri && tor_addr_port_is_valid(&node->ri->ipv6_addr,
@@ -1321,7 +1414,7 @@ nodelist_refresh_countries(void)
/** 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
+int
addrs_in_same_network_family(const tor_addr_t *a1,
const tor_addr_t *a2)
{
@@ -1628,8 +1721,8 @@ router_have_minimum_dir_info(void)
* this can cause router_have_consensus_path() to be set to
* CONSENSUS_PATH_EXIT, even if there are no nodes with accept exit policies.
*/
-consensus_path_type_t
-router_have_consensus_path(void)
+MOCK_IMPL(consensus_path_type_t,
+router_have_consensus_path, (void))
{
return have_consensus_path;
}
@@ -1668,7 +1761,7 @@ static void
count_usable_descriptors(int *num_present, int *num_usable,
smartlist_t *descs_out,
const networkstatus_t *consensus,
- const or_options_t *options, time_t now,
+ time_t now,
routerset_t *in_set,
usable_descriptor_t exit_only)
{
@@ -1685,7 +1778,7 @@ count_usable_descriptors(int *num_present, int *num_usable,
continue;
if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1))
continue;
- if (client_would_use_router(rs, now, options)) {
+ if (client_would_use_router(rs, now)) {
const char * const digest = rs->descriptor_digest;
int present;
++*num_usable; /* the consensus says we want it. */
@@ -1718,9 +1811,9 @@ count_usable_descriptors(int *num_present, int *num_usable,
* If **<b>status_out</b> is present, allocate a new string and print the
* available percentages of guard, middle, and exit nodes to it, noting
* whether there are exits in the consensus.
- * If there are no guards in the consensus,
- * we treat the exit fraction as 100%.
- */
+ * If there are no exits in the consensus, we treat the exit fraction as 100%,
+ * but set router_have_consensus_path() so that we can only build internal
+ * paths. */
static double
compute_frac_paths_available(const networkstatus_t *consensus,
const or_options_t *options, time_t now,
@@ -1739,10 +1832,10 @@ compute_frac_paths_available(const networkstatus_t *consensus,
const int authdir = authdir_mode_v3(options);
count_usable_descriptors(num_present_out, num_usable_out,
- mid, consensus, options, now, NULL,
+ mid, consensus, now, NULL,
USABLE_DESCRIPTOR_ALL);
if (options->EntryNodes) {
- count_usable_descriptors(&np, &nu, guards, consensus, options, now,
+ count_usable_descriptors(&np, &nu, guards, consensus, now,
options->EntryNodes, USABLE_DESCRIPTOR_ALL);
} else {
SMARTLIST_FOREACH(mid, const node_t *, node, {
@@ -1763,7 +1856,7 @@ compute_frac_paths_available(const networkstatus_t *consensus,
* an unavoidable feature of forcing authorities to declare
* certain nodes as exits.
*/
- count_usable_descriptors(&np, &nu, exits, consensus, options, now,
+ count_usable_descriptors(&np, &nu, exits, consensus, now,
NULL, USABLE_DESCRIPTOR_EXIT_ONLY);
log_debug(LD_NET,
"%s: %d present, %d usable",
@@ -1812,7 +1905,7 @@ compute_frac_paths_available(const networkstatus_t *consensus,
smartlist_t *myexits_unflagged = smartlist_new();
/* All nodes with exit flag in ExitNodes option */
- count_usable_descriptors(&np, &nu, myexits, consensus, options, now,
+ count_usable_descriptors(&np, &nu, myexits, consensus, now,
options->ExitNodes, USABLE_DESCRIPTOR_EXIT_ONLY);
log_debug(LD_NET,
"%s: %d present, %d usable",
@@ -1823,7 +1916,7 @@ compute_frac_paths_available(const networkstatus_t *consensus,
/* Now compute the nodes in the ExitNodes option where which we don't know
* what their exit policy is, or we know it permits something. */
count_usable_descriptors(&np, &nu, myexits_unflagged,
- consensus, options, now,
+ consensus, now,
options->ExitNodes, USABLE_DESCRIPTOR_ALL);
log_debug(LD_NET,
"%s: %d present, %d usable",
@@ -1970,6 +2063,13 @@ update_router_have_minimum_dir_info(void)
using_md = consensus->flavor == FLAV_MICRODESC;
+ if (! entry_guards_have_enough_dir_info_to_build_circuits()) {
+ strlcpy(dir_info_status, "We're missing descriptors for some of our "
+ "primary entry guards", sizeof(dir_info_status));
+ res = 0;
+ goto done;
+ }
+
/* Check fraction of available paths */
{
char *status = NULL;