aboutsummaryrefslogtreecommitdiff
path: root/src/feature/nodelist
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature/nodelist')
-rw-r--r--src/feature/nodelist/.may_include1
-rw-r--r--src/feature/nodelist/authcert.c29
-rw-r--r--src/feature/nodelist/authcert.h6
-rw-r--r--src/feature/nodelist/authority_cert_st.h16
-rw-r--r--src/feature/nodelist/desc_store_st.h9
-rw-r--r--src/feature/nodelist/describe.c224
-rw-r--r--src/feature/nodelist/describe.h42
-rw-r--r--src/feature/nodelist/dirlist.c116
-rw-r--r--src/feature/nodelist/dirlist.h14
-rw-r--r--src/feature/nodelist/document_signature_st.h10
-rw-r--r--src/feature/nodelist/extrainfo_st.h10
-rw-r--r--src/feature/nodelist/feature_nodelist.md2
-rw-r--r--src/feature/nodelist/fmt_routerstatus.c73
-rw-r--r--src/feature/nodelist/fmt_routerstatus.h3
-rw-r--r--src/feature/nodelist/include.am49
-rw-r--r--src/feature/nodelist/microdesc.c62
-rw-r--r--src/feature/nodelist/microdesc.h2
-rw-r--r--src/feature/nodelist/microdesc_st.h18
-rw-r--r--src/feature/nodelist/networkstatus.c495
-rw-r--r--src/feature/nodelist/networkstatus.h27
-rw-r--r--src/feature/nodelist/networkstatus_sr_info_st.h10
-rw-r--r--src/feature/nodelist/networkstatus_st.h12
-rw-r--r--src/feature/nodelist/networkstatus_voter_info_st.h15
-rw-r--r--src/feature/nodelist/nickname.c2
-rw-r--r--src/feature/nodelist/nickname.h4
-rw-r--r--src/feature/nodelist/node_select.c256
-rw-r--r--src/feature/nodelist/node_select.h34
-rw-r--r--src/feature/nodelist/node_st.h15
-rw-r--r--src/feature/nodelist/nodefamily.c416
-rw-r--r--src/feature/nodelist/nodefamily.h50
-rw-r--r--src/feature/nodelist/nodefamily_st.h53
-rw-r--r--src/feature/nodelist/nodelist.c512
-rw-r--r--src/feature/nodelist/nodelist.h47
-rw-r--r--src/feature/nodelist/routerinfo.c62
-rw-r--r--src/feature/nodelist/routerinfo.h13
-rw-r--r--src/feature/nodelist/routerinfo_st.h19
-rw-r--r--src/feature/nodelist/routerlist.c254
-rw-r--r--src/feature/nodelist/routerlist.h25
-rw-r--r--src/feature/nodelist/routerlist_st.h10
-rw-r--r--src/feature/nodelist/routerset.c203
-rw-r--r--src/feature/nodelist/routerset.h12
-rw-r--r--src/feature/nodelist/routerstatus_st.h22
-rw-r--r--src/feature/nodelist/signed_descriptor_st.h10
-rw-r--r--src/feature/nodelist/torcert.c20
-rw-r--r--src/feature/nodelist/torcert.h21
-rw-r--r--src/feature/nodelist/vote_routerstatus_st.h8
46 files changed, 2386 insertions, 927 deletions
diff --git a/src/feature/nodelist/.may_include b/src/feature/nodelist/.may_include
new file mode 100644
index 0000000000..424c745c12
--- /dev/null
+++ b/src/feature/nodelist/.may_include
@@ -0,0 +1 @@
+*.h
diff --git a/src/feature/nodelist/authcert.c b/src/feature/nodelist/authcert.c
index 7a065662a7..c5b31be9e3 100644
--- a/src/feature/nodelist/authcert.c
+++ b/src/feature/nodelist/authcert.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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -46,7 +46,7 @@
#include "feature/nodelist/networkstatus_voter_info_st.h"
#include "feature/nodelist/node_st.h"
-DECLARE_TYPED_DIGESTMAP_FNS(dsmap_, digest_ds_map_t, download_status_t)
+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)
@@ -380,7 +380,8 @@ trusted_dirs_load_certs_from_string(const char *contents, int source,
int added_trusted_cert = 0;
for (s = contents; *s; s = eos) {
- authority_cert_t *cert = authority_cert_parse_from_string(s, &eos);
+ authority_cert_t *cert = authority_cert_parse_from_string(s, strlen(s),
+ &eos);
cert_list_t *cl;
if (!cert) {
failure_code = -1;
@@ -459,17 +460,15 @@ trusted_dirs_load_certs_from_string(const char *contents, int source,
if (ds && cert->cache_info.published_on > ds->addr_current_at) {
/* Check to see whether we should update our view of the authority's
* address. */
- if (cert->addr && cert->dir_port &&
- (ds->addr != cert->addr ||
- ds->dir_port != cert->dir_port)) {
- char *a = tor_dup_ip(cert->addr);
+ if (!tor_addr_is_null(&cert->ipv4_addr) && cert->ipv4_dirport &&
+ (!tor_addr_eq(&ds->ipv4_addr, &cert->ipv4_addr) ||
+ ds->ipv4_dirport != cert->ipv4_dirport)) {
log_notice(LD_DIR, "Updating address for directory authority %s "
- "from %s:%d to %s:%d based on certificate.",
- ds->nickname, ds->address, (int)ds->dir_port,
- a, cert->dir_port);
- tor_free(a);
- ds->addr = cert->addr;
- ds->dir_port = cert->dir_port;
+ "from %s:%"PRIu16" to %s:%"PRIu16" based on certificate.",
+ ds->nickname, ds->address, ds->ipv4_dirport,
+ fmt_addr(&cert->ipv4_addr), cert->ipv4_dirport);
+ tor_addr_copy(&ds->ipv4_addr, &cert->ipv4_addr);
+ ds->ipv4_dirport = cert->ipv4_dirport;
}
ds->addr_current_at = cert->cache_info.published_on;
}
@@ -742,7 +741,7 @@ static const char *BAD_SIGNING_KEYS[] = {
* which, because of the old openssl heartbleed vulnerability, should
* never be trusted. */
int
-authority_cert_is_blacklisted(const authority_cert_t *cert)
+authority_cert_is_denylisted(const authority_cert_t *cert)
{
char hex_digest[HEX_DIGEST_LEN+1];
int i;
@@ -809,7 +808,7 @@ authority_certs_fetch_resource_impl(const char *resource,
/* 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,
+ reachable_addr_choose_from_node(node, FIREWALL_OR_CONNECTION, 0,
&or_ap);
req = directory_request_new(DIR_PURPOSE_FETCH_CERTIFICATE);
diff --git a/src/feature/nodelist/authcert.h b/src/feature/nodelist/authcert.h
index 2effdb06e6..4c3d79ceed 100644
--- a/src/feature/nodelist/authcert.h
+++ b/src/feature/nodelist/authcert.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -41,7 +41,7 @@ void authority_cert_dl_failed(const char *id_digest,
void authority_certs_fetch_missing(networkstatus_t *status, time_t now,
const char *dir_hint);
int authority_cert_dl_looks_uncertain(const char *id_digest);
-int authority_cert_is_blacklisted(const authority_cert_t *cert);
+int authority_cert_is_denylisted(const authority_cert_t *cert);
void authority_cert_free_(authority_cert_t *cert);
#define authority_cert_free(cert) \
@@ -57,4 +57,4 @@ MOCK_DECL(download_status_t *, download_status_for_authority_id_and_sk,
void authcert_free_all(void);
-#endif
+#endif /* !defined(TOR_AUTHCERT_H) */
diff --git a/src/feature/nodelist/authority_cert_st.h b/src/feature/nodelist/authority_cert_st.h
index 68a84bc452..aa9831d12e 100644
--- a/src/feature/nodelist/authority_cert_st.h
+++ b/src/feature/nodelist/authority_cert_st.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file authority_cert_st.h
+ * @brief Authority certificate structure.
+ **/
+
#ifndef AUTHORITY_CERT_ST_H
#define AUTHORITY_CERT_ST_H
@@ -22,11 +27,10 @@ struct authority_cert_t {
char signing_key_digest[DIGEST_LEN];
/** The listed expiration time of this certificate. */
time_t expires;
- /** This authority's IPv4 address, in host order. */
- uint32_t addr;
+ /** This authority's IPv4 address. */
+ tor_addr_t ipv4_addr;
/** This authority's directory port. */
- uint16_t dir_port;
+ uint16_t ipv4_dirport;
};
-#endif
-
+#endif /* !defined(AUTHORITY_CERT_ST_H) */
diff --git a/src/feature/nodelist/desc_store_st.h b/src/feature/nodelist/desc_store_st.h
index b04a1abc7d..5f35a490a5 100644
--- a/src/feature/nodelist/desc_store_st.h
+++ b/src/feature/nodelist/desc_store_st.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file desc_store_st.h
+ * @brief Routerinfo/extrainfo storage structure.
+ **/
+
#ifndef DESC_STORE_ST_H
#define DESC_STORE_ST_H
@@ -36,4 +41,4 @@ struct desc_store_t {
size_t bytes_dropped;
};
-#endif
+#endif /* !defined(DESC_STORE_ST_H) */
diff --git a/src/feature/nodelist/describe.c b/src/feature/nodelist/describe.c
index 5c376408c0..b6a0fe74f7 100644
--- a/src/feature/nodelist/describe.c
+++ b/src/feature/nodelist/describe.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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,66 +9,122 @@
* \brief Format short descriptions of relays.
*/
+#define DESCRIBE_PRIVATE
+
#include "core/or/or.h"
+#include "core/or/extendinfo.h"
#include "feature/nodelist/describe.h"
+#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerinfo.h"
+#include "lib/crypt_ops/crypto_ed25519.h"
+#include "lib/crypt_ops/crypto_format.h"
#include "core/or/extend_info_st.h"
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerstatus_st.h"
-
-/**
- * Longest allowed output of format_node_description, plus 1 character for
- * NUL. This allows space for:
- * "$FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF~xxxxxxxxxxxxxxxxxxx at"
- * " [ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]"
- * plus a terminating NUL.
- */
-#define NODE_DESC_BUF_LEN (MAX_VERBOSE_NICKNAME_LEN+4+TOR_ADDR_BUF_LEN)
+#include "feature/nodelist/microdesc_st.h"
/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to
* hold a human-readable description of a node with identity digest
- * <b>id_digest</b>, named-status <b>is_named</b>, nickname <b>nickname</b>,
- * and address <b>addr</b> or <b>addr32h</b>.
+ * <b>id_digest</b>, nickname <b>nickname</b>, and addresses <b>addr32h</b> and
+ * <b>addr</b>.
*
- * The <b>nickname</b> and <b>addr</b> fields are optional and may be set to
- * NULL. The <b>addr32h</b> field is optional and may be set to 0.
+ * The <b>nickname</b>, <b>ipv6_addr</b> and <b>ipv4_addr</b> fields are
+ * optional and may be set to NULL or the null address.
*
* Return a pointer to the front of <b>buf</b>.
+ * If buf is NULL, return a string constant describing the error.
*/
-static const char *
+STATIC const char *
format_node_description(char *buf,
- const char *id_digest,
- int is_named,
+ const char *rsa_id_digest,
+ const ed25519_public_key_t *ed25519_id,
const char *nickname,
- const tor_addr_t *addr,
- uint32_t addr32h)
+ const tor_addr_t *ipv4_addr,
+ const tor_addr_t *ipv6_addr)
{
- char *cp;
+ size_t rv = 0;
+ bool has_ipv6 = ipv6_addr && !tor_addr_is_null(ipv6_addr);
+ bool valid_ipv4 = false;
if (!buf)
return "<NULL BUFFER>";
- buf[0] = '$';
- base16_encode(buf+1, HEX_DIGEST_LEN+1, id_digest, DIGEST_LEN);
- cp = buf+1+HEX_DIGEST_LEN;
+ memset(buf, 0, NODE_DESC_BUF_LEN);
+
+ if (!rsa_id_digest) {
+ /* strlcpy() returns the length of the source string it attempted to copy,
+ * ignoring any required truncation due to the buffer length. */
+ rv = strlcpy(buf, "<NULL ID DIGEST>", NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ return buf;
+ }
+
+ /* strlcat() returns the length of the concatenated string it attempted to
+ * create, ignoring any required truncation due to the buffer length. */
+ rv = strlcat(buf, "$", NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+
+ {
+ char hex_digest[HEX_DIGEST_LEN+1];
+ memset(hex_digest, 0, sizeof(hex_digest));
+
+ base16_encode(hex_digest, sizeof(hex_digest),
+ rsa_id_digest, DIGEST_LEN);
+ rv = strlcat(buf, hex_digest, NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ }
+
if (nickname) {
- buf[1+HEX_DIGEST_LEN] = is_named ? '=' : '~';
- strlcpy(buf+1+HEX_DIGEST_LEN+1, nickname, MAX_NICKNAME_LEN+1);
- cp += strlen(cp);
+ rv = strlcat(buf, "~", NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ rv = strlcat(buf, nickname, NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
}
- if (addr32h || addr) {
- memcpy(cp, " at ", 4);
- cp += 4;
- if (addr) {
- tor_addr_to_str(cp, addr, TOR_ADDR_BUF_LEN, 0);
- } else {
- struct in_addr in;
- in.s_addr = htonl(addr32h);
- tor_inet_ntoa(&in, cp, INET_NTOA_BUF_LEN);
+ if (ed25519_id) {
+ char ed_base64[ED25519_BASE64_LEN+1];
+ ed25519_public_to_base64(ed_base64, ed25519_id);
+ rv = strlcat(buf, " [", NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ rv = strlcat(buf, ed_base64, NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ rv = strlcat(buf, "]", NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ }
+ if (ipv4_addr || has_ipv6) {
+ rv = strlcat(buf, " at ", NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ }
+ if (ipv4_addr) {
+ const char *str_rv = NULL;
+ char addr_str[TOR_ADDR_BUF_LEN];
+ memset(addr_str, 0, sizeof(addr_str));
+
+ str_rv = tor_addr_to_str(addr_str, ipv4_addr, sizeof(addr_str), 0);
+ if (str_rv) {
+ rv = strlcat(buf, addr_str, NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ valid_ipv4 = true;
+ }
+ }
+ /* Both addresses are valid */
+ if (valid_ipv4 && has_ipv6) {
+ rv = strlcat(buf, " and ", NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ }
+ if (has_ipv6) {
+ const char *str_rv = NULL;
+ char addr_str[TOR_ADDR_BUF_LEN];
+ memset(addr_str, 0, sizeof(addr_str));
+
+ str_rv = tor_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str), 1);
+ if (str_rv) {
+ rv = strlcat(buf, addr_str, NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
}
}
+
return buf;
}
@@ -84,12 +140,15 @@ router_describe(const routerinfo_t *ri)
if (!ri)
return "<null>";
+
+ const ed25519_public_key_t *ed25519_id = routerinfo_get_ed25519_id(ri);
+
return format_node_description(buf,
ri->cache_info.identity_digest,
- 0,
+ ed25519_id,
ri->nickname,
- NULL,
- ri->addr);
+ &ri->ipv4_addr,
+ &ri->ipv6_addr);
}
/** Return a human-readable description of the node_t <b>node</b>.
@@ -102,27 +161,37 @@ node_describe(const node_t *node)
{
static char buf[NODE_DESC_BUF_LEN];
const char *nickname = NULL;
- uint32_t addr32h = 0;
- int is_named = 0;
+ const tor_addr_t *ipv6_addr = NULL, *ipv4_addr = NULL;
if (!node)
return "<null>";
if (node->rs) {
nickname = node->rs->nickname;
- is_named = node->rs->is_named;
- addr32h = node->rs->addr;
+ ipv4_addr = &node->rs->ipv4_addr;
+ ipv6_addr = &node->rs->ipv6_addr;
+ /* Support consensus versions less than 28, when IPv6 addresses were in
+ * microdescs. This code can be removed when 0.2.9 is no longer supported,
+ * and the MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC macro is removed. */
+ if (node->md && tor_addr_is_null(ipv6_addr)) {
+ ipv6_addr = &node->md->ipv6_addr;
+ }
} else if (node->ri) {
nickname = node->ri->nickname;
- addr32h = node->ri->addr;
+ ipv4_addr = &node->ri->ipv4_addr;
+ ipv6_addr = &node->ri->ipv6_addr;
+ } else {
+ return "<null rs and ri>";
}
+ const ed25519_public_key_t *ed25519_id = node_get_ed25519_id(node);
+
return format_node_description(buf,
node->identity,
- is_named,
+ ed25519_id,
nickname,
- NULL,
- addr32h);
+ ipv4_addr,
+ ipv6_addr);
}
/** Return a human-readable description of the routerstatus_t <b>rs</b>.
@@ -137,12 +206,13 @@ routerstatus_describe(const routerstatus_t *rs)
if (!rs)
return "<null>";
+
return format_node_description(buf,
rs->identity_digest,
- rs->is_named,
- rs->nickname,
NULL,
- rs->addr);
+ rs->nickname,
+ &rs->ipv4_addr,
+ &rs->ipv6_addr);
}
/** Return a human-readable description of the extend_info_t <b>ei</b>.
@@ -157,12 +227,22 @@ extend_info_describe(const extend_info_t *ei)
if (!ei)
return "<null>";
+
+ const tor_addr_port_t *ap4 = extend_info_get_orport(ei, AF_INET);
+ const tor_addr_port_t *ap6 = extend_info_get_orport(ei, AF_INET6);
+ const tor_addr_t *addr4 = ap4 ? &ap4->addr : NULL;
+ const tor_addr_t *addr6 = ap6 ? &ap6->addr : NULL;
+
+ const ed25519_public_key_t *ed25519_id = &ei->ed_identity;
+ if (ed25519_public_key_is_zero(ed25519_id))
+ ed25519_id = NULL;
+
return format_node_description(buf,
ei->identity_digest,
- 0,
+ ed25519_id,
ei->nickname,
- &ei->addr,
- 0);
+ addr4,
+ addr6);
}
/** Set <b>buf</b> (which must have MAX_VERBOSE_NICKNAME_LEN+1 bytes) to the
@@ -175,9 +255,39 @@ extend_info_describe(const extend_info_t *ei)
void
router_get_verbose_nickname(char *buf, const routerinfo_t *router)
{
- buf[0] = '$';
- base16_encode(buf+1, HEX_DIGEST_LEN+1, router->cache_info.identity_digest,
- DIGEST_LEN);
- buf[1+HEX_DIGEST_LEN] = '~';
- strlcpy(buf+1+HEX_DIGEST_LEN+1, router->nickname, MAX_NICKNAME_LEN+1);
+ size_t rv = 0;
+
+ if (!buf)
+ return;
+
+ memset(buf, 0, MAX_VERBOSE_NICKNAME_LEN+1);
+
+ if (!router) {
+ /* strlcpy() returns the length of the source string it attempted to copy,
+ * ignoring any required truncation due to the buffer length. */
+ rv = strlcpy(buf, "<null>", MAX_VERBOSE_NICKNAME_LEN+1);
+ tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1);
+ return;
+ }
+
+ /* strlcat() returns the length of the concatenated string it attempted to
+ * create, ignoring any required truncation due to the buffer length. */
+ rv = strlcat(buf, "$", MAX_VERBOSE_NICKNAME_LEN+1);
+ tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1);
+
+ {
+ char hex_digest[HEX_DIGEST_LEN+1];
+ memset(hex_digest, 0, sizeof(hex_digest));
+
+ base16_encode(hex_digest, sizeof(hex_digest),
+ router->cache_info.identity_digest, DIGEST_LEN);
+ rv = strlcat(buf, hex_digest, MAX_VERBOSE_NICKNAME_LEN+1);
+ tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1);
+ }
+
+ rv = strlcat(buf, "~", MAX_VERBOSE_NICKNAME_LEN+1);
+ tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1);
+
+ rv = strlcat(buf, router->nickname, MAX_VERBOSE_NICKNAME_LEN+1);
+ tor_assert_nonfatal(rv < MAX_VERBOSE_NICKNAME_LEN+1);
}
diff --git a/src/feature/nodelist/describe.h b/src/feature/nodelist/describe.h
index 018af6470e..898b5c943b 100644
--- a/src/feature/nodelist/describe.h
+++ b/src/feature/nodelist/describe.h
@@ -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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,4 +22,42 @@ const char *node_describe(const struct node_t *node);
const char *router_describe(const struct routerinfo_t *ri);
const char *routerstatus_describe(const struct routerstatus_t *ri);
-#endif
+void router_get_verbose_nickname(char *buf, const routerinfo_t *router);
+
+#if defined(DESCRIBE_PRIVATE) || defined(TOR_UNIT_TESTS)
+
+/**
+ * Longest allowed output for an IPv4 address "255.255.255.255", with NO
+ * terminating NUL.
+ */
+#define IPV4_BUF_LEN_NO_NUL 15
+
+/**
+ * Longest allowed output of format_node_description, plus 1 character for
+ * NUL. This allows space for:
+ * "$FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF~xxxxxxxxxxxxxxxxxxx "
+ * "[+++++++++++++++++++++++++++++++++++++++++++] at"
+ * " 255.255.255.255 and [ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]"
+ * plus a terminating NUL.
+ */
+#define NODE_DESC_BUF_LEN \
+ (MAX_VERBOSE_NICKNAME_LEN+4 \
+ + ED25519_BASE64_LEN+3 \
+ + IPV4_BUF_LEN_NO_NUL+5 \
+ + TOR_ADDR_BUF_LEN)
+
+#endif /* defined(DESCRIBE_PRIVATE) || defined(TOR_UNIT_TESTS) */
+
+#ifdef TOR_UNIT_TESTS
+struct ed25519_public_key_t;
+
+STATIC const char *format_node_description(char *buf,
+ const char *rsa_id_digest,
+ const struct ed25519_public_key_t *ed25519_id,
+ const char *nickname,
+ const tor_addr_t *ipv4_addr,
+ const tor_addr_t *ipv6_addr);
+
+#endif /* defined(TOR_UNIT_TESTS) */
+
+#endif /* !defined(TOR_DESCRIBE_H) */
diff --git a/src/feature/nodelist/dirlist.c b/src/feature/nodelist/dirlist.c
index b4abffad67..423c4106e2 100644
--- a/src/feature/nodelist/dirlist.c
+++ b/src/feature/nodelist/dirlist.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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -27,8 +27,9 @@
#include "core/or/or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "core/or/policies.h"
-#include "feature/control/control.h"
+#include "feature/control/control_events.h"
#include "feature/dirauth/authmode.h"
#include "feature/dircommon/directory.h"
#include "feature/nodelist/dirlist.h"
@@ -54,15 +55,13 @@ static smartlist_t *fallback_dir_servers = NULL;
static void
add_trusted_dir_to_nodelist_addr_set(const dir_server_t *dir)
{
- tor_addr_t tmp_addr;
-
tor_assert(dir);
tor_assert(dir->is_authority);
/* Add IPv4 and then IPv6 if applicable. For authorities, we add the ORPort
* and DirPort so re-entry into the network back to them is not possible. */
- tor_addr_from_ipv4h(&tmp_addr, dir->addr);
- nodelist_add_addr_to_address_set(&tmp_addr, dir->or_port, dir->dir_port);
+ nodelist_add_addr_to_address_set(&dir->ipv4_addr, dir->ipv4_orport,
+ dir->ipv4_dirport);
if (!tor_addr_is_null(&dir->ipv6_addr)) {
/* IPv6 DirPort is not a thing yet for authorities. */
nodelist_add_addr_to_address_set(&dir->ipv6_addr, dir->ipv6_orport, 0);
@@ -240,8 +239,8 @@ mark_all_dirservers_up(smartlist_t *server_list)
/** 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. */
-int
-router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type)
+MOCK_IMPL(int, router_digest_is_trusted_dir_type,
+ (const char *digest, dirinfo_type_t type))
{
if (!trusted_dir_servers)
return 0;
@@ -254,6 +253,34 @@ router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type)
return 0;
}
+/** Return true iff the given address matches a trusted directory that matches
+ * at least one bit of type.
+ *
+ * If type is NO_DIRINFO or ALL_DIRINFO, any authority is matched. */
+bool
+router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type)
+{
+ int family = tor_addr_family(addr);
+
+ if (!trusted_dir_servers) {
+ return false;
+ }
+
+ SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, dir_server_t *, ent) {
+ /* Ignore entries that don't match the given type. */
+ if (type != NO_DIRINFO && (type & ent->type) == 0) {
+ continue;
+ }
+ /* Match IPv4 or IPv6 address. */
+ if ((family == AF_INET && tor_addr_eq(addr, &ent->ipv4_addr)) ||
+ (family == AF_INET6 && tor_addr_eq(addr, &ent->ipv6_addr))) {
+ return true;
+ }
+ } SMARTLIST_FOREACH_END(ent);
+
+ return false;
+}
+
/** 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
@@ -261,16 +288,15 @@ router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type)
static dir_server_t *
dir_server_new(int is_authority,
const char *nickname,
- const tor_addr_t *addr,
+ const tor_addr_t *ipv4_addr,
const char *hostname,
- uint16_t dir_port, uint16_t or_port,
+ uint16_t ipv4_dirport, uint16_t ipv4_orport,
const tor_addr_port_t *addrport_ipv6,
const char *digest, const char *v3_auth_digest,
dirinfo_type_t type,
double weight)
{
dir_server_t *ent;
- uint32_t a;
char *hostname_ = NULL;
tor_assert(digest);
@@ -278,27 +304,26 @@ dir_server_new(int is_authority,
if (weight < 0)
return NULL;
- if (tor_addr_family(addr) == AF_INET)
- a = tor_addr_to_ipv4h(addr);
- else
+ if (!ipv4_addr) {
return NULL;
+ }
if (!hostname)
- hostname_ = tor_addr_to_str_dup(addr);
+ hostname_ = tor_addr_to_str_dup(ipv4_addr);
else
hostname_ = tor_strdup(hostname);
ent = tor_malloc_zero(sizeof(dir_server_t));
ent->nickname = nickname ? tor_strdup(nickname) : NULL;
ent->address = hostname_;
- ent->addr = a;
- ent->dir_port = dir_port;
- ent->or_port = or_port;
+ tor_addr_copy(&ent->ipv4_addr, ipv4_addr);
+ ent->ipv4_dirport = ipv4_dirport;
+ ent->ipv4_orport = ipv4_orport;
ent->is_running = 1;
ent->is_authority = is_authority;
ent->type = type;
ent->weight = weight;
- if (addrport_ipv6) {
+ if (addrport_ipv6 && tor_addr_port_is_valid_ap(addrport_ipv6, 0)) {
if (tor_addr_family(&addrport_ipv6->addr) != AF_INET6) {
log_warn(LD_BUG, "Hey, I got a non-ipv6 addr as addrport_ipv6.");
tor_addr_make_unspec(&ent->ipv6_addr);
@@ -315,13 +340,13 @@ dir_server_new(int is_authority,
memcpy(ent->v3_identity_digest, v3_auth_digest, DIGEST_LEN);
if (nickname)
- tor_asprintf(&ent->description, "directory server \"%s\" at %s:%d",
- nickname, hostname_, (int)dir_port);
+ tor_asprintf(&ent->description, "directory server \"%s\" at %s:%" PRIu16,
+ nickname, hostname_, ipv4_dirport);
else
- tor_asprintf(&ent->description, "directory server at %s:%d",
- hostname_, (int)dir_port);
+ tor_asprintf(&ent->description, "directory server at %s:%" PRIu16,
+ hostname_, ipv4_dirport);
- ent->fake_status.addr = ent->addr;
+ tor_addr_copy(&ent->fake_status.ipv4_addr, &ent->ipv4_addr);
tor_addr_copy(&ent->fake_status.ipv6_addr, &ent->ipv6_addr);
memcpy(ent->fake_status.identity_digest, digest, DIGEST_LEN);
if (nickname)
@@ -329,41 +354,43 @@ dir_server_new(int is_authority,
sizeof(ent->fake_status.nickname));
else
ent->fake_status.nickname[0] = '\0';
- ent->fake_status.dir_port = ent->dir_port;
- ent->fake_status.or_port = ent->or_port;
+ ent->fake_status.ipv4_dirport = ent->ipv4_dirport;
+ ent->fake_status.ipv4_orport = ent->ipv4_orport;
ent->fake_status.ipv6_orport = ent->ipv6_orport;
return ent;
}
-/** Create an authoritative directory server at
- * <b>address</b>:<b>port</b>, with identity key <b>digest</b>. If
- * <b>address</b> is NULL, add ourself. Return the new trusted directory
- * server entry on success or NULL if we couldn't add it. */
+/** Create an authoritative directory server at <b>address</b>:<b>port</b>,
+ * with identity key <b>digest</b>. If <b>ipv4_addr_str</b> is NULL, add
+ * ourself. Return the new trusted directory server entry on success or NULL
+ * if we couldn't add it. */
dir_server_t *
trusted_dir_server_new(const char *nickname, const char *address,
- uint16_t dir_port, uint16_t or_port,
+ uint16_t ipv4_dirport, uint16_t ipv4_orport,
const tor_addr_port_t *ipv6_addrport,
const char *digest, const char *v3_auth_digest,
dirinfo_type_t type, double weight)
{
- uint32_t a;
- tor_addr_t addr;
+ tor_addr_t ipv4_addr;
char *hostname=NULL;
dir_server_t *result;
if (!address) { /* The address is us; we should guess. */
- if (resolve_my_address(LOG_WARN, get_options(),
- &a, NULL, &hostname) < 0) {
+ if (!find_my_address(get_options(), AF_INET, LOG_WARN, &ipv4_addr,
+ NULL, &hostname)) {
log_warn(LD_CONFIG,
"Couldn't find a suitable address when adding ourself as a "
"trusted directory server.");
return NULL;
}
if (!hostname)
- hostname = tor_dup_ip(a);
+ hostname = tor_addr_to_str_dup(&ipv4_addr);
+
+ if (!hostname)
+ return NULL;
} else {
- if (tor_lookup_hostname(address, &a)) {
+ if (tor_addr_lookup(address, AF_INET, &ipv4_addr)) {
log_warn(LD_CONFIG,
"Unable to lookup address for directory server at '%s'",
address);
@@ -371,10 +398,9 @@ trusted_dir_server_new(const char *nickname, const char *address,
}
hostname = tor_strdup(address);
}
- tor_addr_from_ipv4h(&addr, a);
- result = dir_server_new(1, nickname, &addr, hostname,
- dir_port, or_port,
+ result = dir_server_new(1, nickname, &ipv4_addr, hostname,
+ ipv4_dirport, ipv4_orport,
ipv6_addrport,
digest,
v3_auth_digest, type, weight);
@@ -386,15 +412,13 @@ trusted_dir_server_new(const char *nickname, const char *address,
* <b>addr</b>:<b>or_port</b>/<b>dir_port</b>, with identity key digest
* <b>id_digest</b> */
dir_server_t *
-fallback_dir_server_new(const tor_addr_t *addr,
- uint16_t dir_port, uint16_t or_port,
+fallback_dir_server_new(const tor_addr_t *ipv4_addr,
+ uint16_t ipv4_dirport, uint16_t ipv4_orport,
const tor_addr_port_t *addrport_ipv6,
const char *id_digest, double weight)
{
- return dir_server_new(0, NULL, addr, NULL, dir_port, or_port,
- addrport_ipv6,
- id_digest,
- NULL, ALL_DIRINFO, weight);
+ return dir_server_new(0, NULL, ipv4_addr, NULL, ipv4_dirport, ipv4_orport,
+ addrport_ipv6, id_digest, NULL, ALL_DIRINFO, weight);
}
/** Add a directory server to the global list(s). */
diff --git a/src/feature/nodelist/dirlist.h b/src/feature/nodelist/dirlist.h
index 527af35427..ae3debf4e5 100644
--- a/src/feature/nodelist/dirlist.h
+++ b/src/feature/nodelist/dirlist.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -25,8 +25,14 @@ int router_digest_is_fallback_dir(const char *digest);
MOCK_DECL(dir_server_t *, trusteddirserver_get_by_v3_auth_digest,
(const char *d));
-int router_digest_is_trusted_dir_type(const char *digest,
- dirinfo_type_t type);
+MOCK_DECL(int, router_digest_is_trusted_dir_type,
+ (const char *digest, dirinfo_type_t type));
+
+bool router_addr_is_trusted_dir_type(const tor_addr_t *addr,
+ dirinfo_type_t type);
+#define router_addr_is_trusted_dir(d) \
+ router_addr_is_trusted_dir_type((d), NO_DIRINFO)
+
#define router_digest_is_trusted_dir(d) \
router_digest_is_trusted_dir_type((d), NO_DIRINFO)
@@ -46,4 +52,4 @@ void dirlist_free_all(void);
MOCK_DECL(void, dirlist_add_trusted_dir_addresses, (void));
-#endif
+#endif /* !defined(TOR_DIRLIST_H) */
diff --git a/src/feature/nodelist/document_signature_st.h b/src/feature/nodelist/document_signature_st.h
index 66e32c422f..4bde9d89ec 100644
--- a/src/feature/nodelist/document_signature_st.h
+++ b/src/feature/nodelist/document_signature_st.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file document_signature_st.h
+ * @brief Authority signature structure
+ **/
+
#ifndef DOCUMENT_SIGNATURE_ST_H
#define DOCUMENT_SIGNATURE_ST_H
@@ -25,5 +30,4 @@ struct document_signature_t {
* as good. */
};
-#endif
-
+#endif /* !defined(DOCUMENT_SIGNATURE_ST_H) */
diff --git a/src/feature/nodelist/extrainfo_st.h b/src/feature/nodelist/extrainfo_st.h
index c54277b05e..6bd6232cd8 100644
--- a/src/feature/nodelist/extrainfo_st.h
+++ b/src/feature/nodelist/extrainfo_st.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file extrainfo_st.h
+ * @brief A relay's extra-info structure.
+ **/
+
#ifndef EXTRAINFO_ST_H
#define EXTRAINFO_ST_H
@@ -26,5 +31,4 @@ struct extrainfo_t {
size_t pending_sig_len;
};
-#endif
-
+#endif /* !defined(EXTRAINFO_ST_H) */
diff --git a/src/feature/nodelist/feature_nodelist.md b/src/feature/nodelist/feature_nodelist.md
new file mode 100644
index 0000000000..9d715308c2
--- /dev/null
+++ b/src/feature/nodelist/feature_nodelist.md
@@ -0,0 +1,2 @@
+@dir /feature/nodelist
+@brief feature/nodelist: Download and manage a list of relays
diff --git a/src/feature/nodelist/fmt_routerstatus.c b/src/feature/nodelist/fmt_routerstatus.c
index 75cab7a0af..252b2e61fe 100644
--- a/src/feature/nodelist/fmt_routerstatus.c
+++ b/src/feature/nodelist/fmt_routerstatus.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,64 +14,19 @@
#include "core/or/or.h"
#include "feature/nodelist/fmt_routerstatus.h"
-/* #include "lib/container/buffers.h" */
-/* #include "app/config/config.h" */
-/* #include "app/config/confparse.h" */
-/* #include "core/or/channel.h" */
-/* #include "core/or/channeltls.h" */
-/* #include "core/or/command.h" */
-/* #include "core/mainloop/connection.h" */
-/* #include "core/or/connection_or.h" */
-/* #include "feature/dircache/conscache.h" */
-/* #include "feature/dircache/consdiffmgr.h" */
-/* #include "feature/control/control.h" */
-/* #include "feature/dircache/directory.h" */
-/* #include "feature/dircache/dirserv.h" */
-/* #include "feature/hibernate/hibernate.h" */
-/* #include "feature/dirauth/keypin.h" */
-/* #include "core/mainloop/mainloop.h" */
-/* #include "feature/nodelist/microdesc.h" */
-/* #include "feature/nodelist/networkstatus.h" */
-/* #include "feature/nodelist/nodelist.h" */
#include "core/or/policies.h"
-/* #include "core/or/protover.h" */
-/* #include "feature/stats/rephist.h" */
-/* #include "feature/relay/router.h" */
-/* #include "feature/nodelist/dirlist.h" */
#include "feature/nodelist/routerlist.h"
-
-/* #include "feature/nodelist/routerparse.h" */
-/* #include "feature/nodelist/routerset.h" */
-/* #include "feature/nodelist/torcert.h" */
-/* #include "feature/dircommon/voting_schedule.h" */
-
#include "feature/dirauth/dirvote.h"
-/* #include "feature/dircache/cached_dir_st.h" */
-/* #include "feature/dircommon/dir_connection_st.h" */
-/* #include "feature/nodelist/extrainfo_st.h" */
-/* #include "feature/nodelist/microdesc_st.h" */
-/* #include "feature/nodelist/node_st.h" */
#include "feature/nodelist/routerinfo_st.h"
-/* #include "feature/nodelist/routerlist_st.h" */
-/* #include "core/or/tor_version_st.h" */
#include "feature/nodelist/vote_routerstatus_st.h"
-/* #include "lib/compress/compress.h" */
-/* #include "lib/container/order.h" */
#include "lib/crypt_ops/crypto_format.h"
-/* #include "lib/encoding/confline.h" */
-
-/* #include "lib/encoding/keyval.h" */
/** Helper: write the router-status information in <b>rs</b> into a newly
* allocated character buffer. Use the same format as in network-status
* documents. If <b>version</b> is non-NULL, add a "v" line for the platform.
*
- * consensus_method is the current consensus method when format is
- * NS_V3_CONSENSUS or NS_V3_CONSENSUS_MICRODESC. It is ignored for other
- * formats: pass ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD.
- *
* Return 0 on success, -1 on failure.
*
* The format argument has one of the following values:
@@ -88,7 +43,6 @@ char *
routerstatus_format_entry(const routerstatus_t *rs, const char *version,
const char *protocols,
routerstatus_format_type_t format,
- int consensus_method,
const vote_routerstatus_t *vrs)
{
char *summary;
@@ -99,32 +53,30 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
char digest64[BASE64_DIGEST_LEN+1];
smartlist_t *chunks = smartlist_new();
+ const char *ip_str = fmt_addr(&rs->ipv4_addr);
+ if (ip_str[0] == '\0')
+ goto err;
+
format_iso_time(published, rs->published_on);
digest_to_base64(identity64, rs->identity_digest);
digest_to_base64(digest64, rs->descriptor_digest);
smartlist_add_asprintf(chunks,
- "r %s %s %s%s%s %s %d %d\n",
+ "r %s %s %s%s%s %s %" PRIu16 " %" PRIu16 "\n",
rs->nickname,
identity64,
(format==NS_V3_CONSENSUS_MICRODESC)?"":digest64,
(format==NS_V3_CONSENSUS_MICRODESC)?"":" ",
published,
- fmt_addr32(rs->addr),
- (int)rs->or_port,
- (int)rs->dir_port);
+ ip_str,
+ rs->ipv4_orport,
+ rs->ipv4_dirport);
/* TODO: Maybe we want to pass in what we need to build the rest of
* this here, instead of in the caller. Then we could use the
* networkstatus_type_t values, with an additional control port value
* added -MP */
- /* V3 microdesc consensuses only have "a" lines in later consensus methods
- */
- if (format == NS_V3_CONSENSUS_MICRODESC &&
- consensus_method < MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS)
- goto done;
-
/* Possible "a" line. At most one for now. */
if (!tor_addr_is_null(&rs->ipv6_addr)) {
smartlist_add_asprintf(chunks, "a %s\n",
@@ -135,7 +87,7 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
goto done;
smartlist_add_asprintf(chunks,
- "s%s%s%s%s%s%s%s%s%s%s\n",
+ "s%s%s%s%s%s%s%s%s%s%s%s\n",
/* These must stay in alphabetical order. */
rs->is_authority?" Authority":"",
rs->is_bad_exit?" BadExit":"",
@@ -145,6 +97,7 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
rs->is_hs_dir?" HSDir":"",
rs->is_flagged_running?" Running":"",
rs->is_stable?" Stable":"",
+ rs->is_staledesc?" StaleDesc":"",
rs->is_v2_dir?" V2Dir":"",
rs->is_valid?" Valid":"");
@@ -164,6 +117,8 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
if (format != NS_CONTROL_PORT) {
/* Blow up more or less nicely if we didn't get anything or not the
* thing we expected.
+ * This should be kept in sync with the function
+ * routerstatus_has_visibly_changed and the struct routerstatus_t
*/
if (!desc) {
char id[HEX_DIGEST_LEN+1];
@@ -232,7 +187,7 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
}
if (format == NS_V3_VOTE && vrs) {
- if (tor_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) {
+ if (fast_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) {
smartlist_add_strdup(chunks, "id ed25519 none\n");
} else {
char ed_b64[BASE64_DIGEST256_LEN+1];
diff --git a/src/feature/nodelist/fmt_routerstatus.h b/src/feature/nodelist/fmt_routerstatus.h
index ddd7a7cf37..a007989af3 100644
--- a/src/feature/nodelist/fmt_routerstatus.h
+++ b/src/feature/nodelist/fmt_routerstatus.h
@@ -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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -35,7 +35,6 @@ char *routerstatus_format_entry(
const char *version,
const char *protocols,
routerstatus_format_type_t format,
- int consensus_method,
const vote_routerstatus_t *vrs);
#endif /* !defined(TOR_FMT_ROUTERSTATUS_H) */
diff --git a/src/feature/nodelist/include.am b/src/feature/nodelist/include.am
new file mode 100644
index 0000000000..2f5d58ec1c
--- /dev/null
+++ b/src/feature/nodelist/include.am
@@ -0,0 +1,49 @@
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_APP_A_SOURCES += \
+ src/feature/nodelist/authcert.c \
+ src/feature/nodelist/describe.c \
+ src/feature/nodelist/dirlist.c \
+ src/feature/nodelist/microdesc.c \
+ src/feature/nodelist/networkstatus.c \
+ src/feature/nodelist/nickname.c \
+ src/feature/nodelist/nodefamily.c \
+ src/feature/nodelist/nodelist.c \
+ src/feature/nodelist/node_select.c \
+ src/feature/nodelist/routerinfo.c \
+ src/feature/nodelist/routerlist.c \
+ src/feature/nodelist/routerset.c \
+ src/feature/nodelist/fmt_routerstatus.c \
+ src/feature/nodelist/torcert.c
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/feature/nodelist/authcert.h \
+ src/feature/nodelist/authority_cert_st.h \
+ src/feature/nodelist/describe.h \
+ src/feature/nodelist/desc_store_st.h \
+ src/feature/nodelist/dirlist.h \
+ src/feature/nodelist/document_signature_st.h \
+ src/feature/nodelist/extrainfo_st.h \
+ src/feature/nodelist/microdesc.h \
+ src/feature/nodelist/microdesc_st.h \
+ src/feature/nodelist/networkstatus.h \
+ src/feature/nodelist/networkstatus_sr_info_st.h \
+ src/feature/nodelist/networkstatus_st.h \
+ src/feature/nodelist/networkstatus_voter_info_st.h \
+ src/feature/nodelist/nickname.h \
+ src/feature/nodelist/node_st.h \
+ src/feature/nodelist/nodefamily.h \
+ src/feature/nodelist/nodefamily_st.h \
+ src/feature/nodelist/nodelist.h \
+ src/feature/nodelist/node_select.h \
+ src/feature/nodelist/routerinfo.h \
+ src/feature/nodelist/routerinfo_st.h \
+ src/feature/nodelist/routerlist.h \
+ src/feature/nodelist/routerlist_st.h \
+ src/feature/nodelist/routerset.h \
+ src/feature/nodelist/fmt_routerstatus.h \
+ src/feature/nodelist/routerstatus_st.h \
+ src/feature/nodelist/signed_descriptor_st.h \
+ src/feature/nodelist/torcert.h \
+ src/feature/nodelist/vote_routerstatus_st.h
diff --git a/src/feature/nodelist/microdesc.c b/src/feature/nodelist/microdesc.c
index dafaabb5e5..01dccd160b 100644
--- a/src/feature/nodelist/microdesc.c
+++ b/src/feature/nodelist/microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2019, The Tor Project, Inc. */
+/* Copyright (c) 2009-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -18,11 +18,13 @@
#include "feature/client/entrynodes.h"
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dlstatus.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dircommon/directory.h"
#include "feature/dirparse/microdesc_parse.h"
#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
+#include "feature/nodelist/nodefamily.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
#include "feature/relay/router.h"
@@ -69,6 +71,8 @@ struct microdesc_cache_t {
};
static microdesc_cache_t *get_microdesc_cache_noload(void);
+static void warn_if_nul_found(const char *inp, size_t len, int64_t offset,
+ const char *activity);
/** Helper: computes a hash of <b>md</b> to place it in a hash table. */
static inline unsigned int
@@ -86,10 +90,10 @@ microdesc_eq_(microdesc_t *a, microdesc_t *b)
}
HT_PROTOTYPE(microdesc_map, microdesc_t, node,
- microdesc_hash_, microdesc_eq_)
+ microdesc_hash_, microdesc_eq_);
HT_GENERATE2(microdesc_map, microdesc_t, node,
microdesc_hash_, microdesc_eq_, 0.6,
- tor_reallocarray_, tor_free_)
+ tor_reallocarray_, tor_free_);
/************************* md fetch fail cache *****************************/
@@ -110,8 +114,9 @@ microdesc_note_outdated_dirserver(const char *relay_digest)
/* If we have a reasonably live consensus, then most of our dirservers should
* still be caching all the microdescriptors in it. Reasonably live
- * consensuses are up to a day old. But microdescriptors expire 7 days after
- * the last consensus that referenced them. */
+ * consensuses are up to a day old (or a day in the future). But
+ * microdescriptors expire 7 days after the last consensus that referenced
+ * them. */
if (!networkstatus_get_reasonably_live_consensus(approx_time(),
FLAV_MICRODESC)) {
return;
@@ -124,8 +129,9 @@ microdesc_note_outdated_dirserver(const char *relay_digest)
tor_assert(outdated_dirserver_list);
/* If the list grows too big, clean it up */
- if (BUG(smartlist_len(outdated_dirserver_list) >
- TOO_MANY_OUTDATED_DIRSERVERS)) {
+ if (smartlist_len(outdated_dirserver_list) > TOO_MANY_OUTDATED_DIRSERVERS) {
+ log_info(LD_GENERAL,"Too many outdated directory servers (%d). Resetting.",
+ smartlist_len(outdated_dirserver_list));
microdesc_reset_outdated_dirservers_list();
}
@@ -221,6 +227,8 @@ dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out)
}
md->off = tor_fd_getpos(fd);
+ warn_if_nul_found(md->body, md->bodylen, (int64_t) md->off,
+ "dumping a microdescriptor");
written = write_all_to_fd(fd, md->body, md->bodylen);
if (written != (ssize_t)md->bodylen) {
written = written < 0 ? 0 : written;
@@ -480,6 +488,27 @@ microdesc_cache_clear(microdesc_cache_t *cache)
cache->bytes_dropped = 0;
}
+static void
+warn_if_nul_found(const char *inp, size_t len, int64_t offset,
+ const char *activity)
+{
+ const char *nul_found = memchr(inp, 0, len);
+ if (BUG(nul_found)) {
+ log_warn(LD_BUG, "Found unexpected NUL while %s, offset %"PRId64
+ "at position %"TOR_PRIuSZ"/%"TOR_PRIuSZ".",
+ activity, offset, (nul_found - inp), len);
+ const char *start_excerpt_at, *eos = inp + len;
+ if ((nul_found - inp) >= 16)
+ start_excerpt_at = nul_found - 16;
+ else
+ start_excerpt_at = inp;
+ size_t excerpt_len = MIN(32, eos - start_excerpt_at);
+ char tmp[65];
+ base16_encode(tmp, sizeof(tmp), start_excerpt_at, excerpt_len);
+ log_warn(LD_BUG, " surrounding string: %s", tmp);
+ }
+}
+
/** Reload the contents of <b>cache</b> from disk. If it is empty, load it
* for the first time. Return 0 on success, -1 on failure. */
int
@@ -497,6 +526,7 @@ microdesc_cache_reload(microdesc_cache_t *cache)
mm = cache->cache_content = tor_mmap_file(cache->cache_fname);
if (mm) {
+ warn_if_nul_found(mm->data, mm->size, 0, "scanning microdesc cache");
added = microdescs_add_to_cache(cache, mm->data, mm->data+mm->size,
SAVED_IN_CACHE, 0, -1, NULL);
if (added) {
@@ -508,7 +538,9 @@ microdesc_cache_reload(microdesc_cache_t *cache)
journal_content = read_file_to_str(cache->journal_fname,
RFTS_IGNORE_MISSING, &st);
if (journal_content) {
- cache->journal_len = (size_t) st.st_size;
+ cache->journal_len = strlen(journal_content);
+ warn_if_nul_found(journal_content, (size_t)st.st_size, 0,
+ "reading microdesc journal");
added = microdescs_add_to_cache(cache, journal_content,
journal_content+st.st_size,
SAVED_IN_JOURNAL, 0, -1, NULL);
@@ -544,8 +576,8 @@ microdesc_cache_clean(microdesc_cache_t *cache, time_t cutoff, int force)
size_t bytes_dropped = 0;
time_t now = time(NULL);
- /* If we don't know a live consensus, don't believe last_listed values: we
- * might be starting up after being down for a while. */
+ /* If we don't know a reasonably live consensus, don't believe last_listed
+ * values: we might be starting up after being down for a while. */
if (! force &&
! networkstatus_get_reasonably_live_consensus(now, FLAV_MICRODESC))
return;
@@ -884,10 +916,7 @@ microdesc_free_(microdesc_t *md, const char *fname, int lineno)
if (md->body && md->saved_location != SAVED_IN_CACHE)
tor_free(md->body);
- if (md->family) {
- SMARTLIST_FOREACH(md->family, char *, cp, tor_free(cp));
- smartlist_free(md->family);
- }
+ nodefamily_free(md->family);
short_policy_free(md->exit_policy);
short_policy_free(md->ipv6_exit_policy);
@@ -943,7 +972,7 @@ microdesc_list_missing_digest256(networkstatus_t *ns, microdesc_cache_t *cache,
continue;
if (skip && digest256map_get(skip, (const uint8_t*)rs->descriptor_digest))
continue;
- if (tor_mem_is_zero(rs->descriptor_digest, DIGEST256_LEN))
+ if (fast_mem_is_zero(rs->descriptor_digest, DIGEST256_LEN))
continue;
/* XXXX Also skip if we're a noncache and wouldn't use this router.
* XXXX NM Microdesc
@@ -970,9 +999,10 @@ update_microdesc_downloads(time_t now)
if (should_delay_dir_fetches(options, NULL))
return;
- if (directory_too_idle_to_fetch_descriptors(options, now))
+ if (dirclient_too_idle_to_fetch_descriptors(options, now))
return;
+ /* Give up if we don't have a reasonably live consensus. */
consensus = networkstatus_get_reasonably_live_consensus(now, FLAV_MICRODESC);
if (!consensus)
return;
diff --git a/src/feature/nodelist/microdesc.h b/src/feature/nodelist/microdesc.h
index c18099d540..b352f58e34 100644
--- a/src/feature/nodelist/microdesc.h
+++ b/src/feature/nodelist/microdesc.h
@@ -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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/microdesc_st.h b/src/feature/nodelist/microdesc_st.h
index bb8b23d664..410403e965 100644
--- a/src/feature/nodelist/microdesc_st.h
+++ b/src/feature/nodelist/microdesc_st.h
@@ -1,16 +1,24 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file microdesc_st.h
+ * @brief Microdescriptor structure
+ **/
+
#ifndef MICRODESC_ST_H
#define MICRODESC_ST_H
struct curve25519_public_key_t;
struct ed25519_public_key_t;
+struct nodefamily_t;
struct short_policy_t;
+#include "ext/ht.h"
+
/** A microdescriptor is the smallest amount of information needed to build a
* circuit through a router. They are generated by the directory authorities,
* using information from the uploaded routerinfo documents. They are not
@@ -32,6 +40,8 @@ struct microdesc_t {
unsigned int no_save : 1;
/** If true, this microdesc has an entry in the microdesc_map */
unsigned int held_in_map : 1;
+ /** True iff the exit policy for this router rejects everything. */
+ unsigned int policy_is_reject_star : 1;
/** Reference count: how many node_ts have a reference to this microdesc? */
unsigned int held_by_nodes;
@@ -69,12 +79,12 @@ struct microdesc_t {
tor_addr_t ipv6_addr;
/** As routerinfo_t.ipv6_orport */
uint16_t ipv6_orport;
- /** As routerinfo_t.family */
- smartlist_t *family;
+ /** As routerinfo_t.family, with readable members parsed. */
+ struct nodefamily_t *family;
/** IPv4 exit policy summary */
struct short_policy_t *exit_policy;
/** IPv6 exit policy summary */
struct short_policy_t *ipv6_exit_policy;
};
-#endif
+#endif /* !defined(MICRODESC_ST_H) */
diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c
index c74acd8b74..80940e6092 100644
--- a/src/feature/nodelist/networkstatus.c
+++ b/src/feature/nodelist/networkstatus.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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -44,6 +44,7 @@
#include "core/mainloop/netstatus.h"
#include "core/or/channel.h"
#include "core/or/channelpadding.h"
+#include "core/or/circuitpadding.h"
#include "core/or/circuitmux.h"
#include "core/or/circuitmux_ewma.h"
#include "core/or/circuitstats.h"
@@ -57,16 +58,18 @@
#include "feature/client/bridges.h"
#include "feature/client/entrynodes.h"
#include "feature/client/transports.h"
-#include "feature/control/control.h"
+#include "feature/control/control_events.h"
#include "feature/dirauth/reachability.h"
#include "feature/dircache/consdiffmgr.h"
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dirclient.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/directory.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dirparse/ns_parse.h"
#include "feature/hibernate/hibernate.h"
+#include "feature/hs/hs_dos.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/fmt_routerstatus.h"
@@ -81,6 +84,7 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
+#include "feature/dirauth/dirauth_periodic.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/authmode.h"
#include "feature/dirauth/shared_random.h"
@@ -98,6 +102,7 @@
#include "feature/nodelist/routerlist_st.h"
#include "feature/dirauth/vote_microdesc_hash_st.h"
#include "feature/nodelist/vote_routerstatus_st.h"
+#include "feature/nodelist/routerstatus_st.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@@ -116,8 +121,6 @@ STATIC networkstatus_t *current_md_consensus = NULL;
typedef struct consensus_waiting_for_certs_t {
/** The consensus itself. */
networkstatus_t *consensus;
- /** The encoded version of the consensus, nul-terminated. */
- char *body;
/** When did we set the current value of consensus_waiting_for_certs? If
* this is too recent, we shouldn't try to fetch a new consensus for a
* little while, to give ourselves time to get certificates for this one. */
@@ -179,6 +182,10 @@ static void update_consensus_bootstrap_multiple_downloads(
static int networkstatus_check_required_protocols(const networkstatus_t *ns,
int client_mode,
char **warning_out);
+static int reload_consensus_from_file(const char *fname,
+ const char *flavor,
+ unsigned flags,
+ const char *source_dir);
/** Forget that we've warned about anything networkstatus-related, so we will
* give fresh warnings if the same behavior happens again. */
@@ -210,14 +217,11 @@ networkstatus_reset_download_failures(void)
download_status_reset(&consensus_bootstrap_dl_status[i]);
}
-/**
- * Read and and return the cached consensus of type <b>flavorname</b>. If
- * <b>unverified</b> is true, get the one we haven't verified. Return NULL if
- * the file isn't there. */
-static char *
-networkstatus_read_cached_consensus_impl(int flav,
- const char *flavorname,
- int unverified_consensus)
+/** Return the filename used to cache the consensus of a given flavor */
+MOCK_IMPL(char *,
+networkstatus_get_cache_fname,(int flav,
+ const char *flavorname,
+ int unverified_consensus))
{
char buf[128];
const char *prefix;
@@ -232,21 +236,35 @@ networkstatus_read_cached_consensus_impl(int flav,
tor_snprintf(buf, sizeof(buf), "%s-%s-consensus", prefix, flavorname);
}
- char *filename = get_cachedir_fname(buf);
- char *result = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
+ return get_cachedir_fname(buf);
+}
+
+/**
+ * Read and and return the cached consensus of type <b>flavorname</b>. If
+ * <b>unverified</b> is false, get the one we haven't verified. Return NULL if
+ * the file isn't there. */
+static tor_mmap_t *
+networkstatus_map_cached_consensus_impl(int flav,
+ const char *flavorname,
+ int unverified_consensus)
+{
+ char *filename = networkstatus_get_cache_fname(flav,
+ flavorname,
+ unverified_consensus);
+ tor_mmap_t *result = tor_mmap_file(filename);
tor_free(filename);
return result;
}
-/** Return a new string containing the current cached consensus of flavor
- * <b>flavorname</b>. */
-char *
-networkstatus_read_cached_consensus(const char *flavorname)
- {
+/** Map the file containing the current cached consensus of flavor
+ * <b>flavorname</b> */
+tor_mmap_t *
+networkstatus_map_cached_consensus(const char *flavorname)
+{
int flav = networkstatus_parse_flavor_name(flavorname);
if (flav < 0)
return NULL;
- return networkstatus_read_cached_consensus_impl(flav, flavorname, 0);
+ return networkstatus_map_cached_consensus_impl(flav, flavorname, 0);
}
/** Read every cached v3 consensus networkstatus from the disk. */
@@ -259,25 +277,15 @@ router_reload_consensus_networkstatus(void)
/* FFFF Suppress warnings if cached consensus is bad? */
for (flav = 0; flav < N_CONSENSUS_FLAVORS; ++flav) {
const char *flavor = networkstatus_get_flavor_name(flav);
- char *s = networkstatus_read_cached_consensus_impl(flav, flavor, 0);
- if (s) {
- if (networkstatus_set_current_consensus(s, flavor, flags, NULL) < -1) {
- log_warn(LD_FS, "Couldn't load consensus %s networkstatus from cache",
- flavor);
- }
- tor_free(s);
- }
+ char *fname = networkstatus_get_cache_fname(flav, flavor, 0);
+ reload_consensus_from_file(fname, flavor, flags, NULL);
+ tor_free(fname);
- s = networkstatus_read_cached_consensus_impl(flav, flavor, 1);
- if (s) {
- if (networkstatus_set_current_consensus(s, flavor,
- flags | NSSET_WAS_WAITING_FOR_CERTS,
- NULL)) {
- log_info(LD_FS, "Couldn't load unverified consensus %s networkstatus "
- "from cache", flavor);
- }
- tor_free(s);
- }
+ fname = networkstatus_get_cache_fname(flav, flavor, 1);
+ reload_consensus_from_file(fname, flavor,
+ flags | NSSET_WAS_WAITING_FOR_CERTS,
+ NULL);
+ tor_free(fname);
}
update_certificate_downloads(time(NULL));
@@ -463,8 +471,8 @@ networkstatus_check_document_signature(const networkstatus_t *consensus,
DIGEST_LEN))
return -1;
- if (authority_cert_is_blacklisted(cert)) {
- /* We implement blacklisting for authority signing keys by treating
+ if (authority_cert_is_denylisted(cert)) {
+ /* We implement denylisting for authority signing keys by treating
* all their signatures as always bad. That way we don't get into
* crazy loops of dropping and re-fetching signatures. */
log_warn(LD_DIR, "Ignoring a consensus signature made with deprecated"
@@ -600,25 +608,25 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus,
SMARTLIST_FOREACH(unrecognized, networkstatus_voter_info_t *, voter,
{
tor_log(severity, LD_DIR, "Consensus includes unrecognized authority "
- "'%s' at %s:%d (contact %s; identity %s)",
- voter->nickname, voter->address, (int)voter->dir_port,
+ "'%s' at %s:%" PRIu16 " (contact %s; identity %s)",
+ voter->nickname, voter->address, voter->ipv4_dirport,
voter->contact?voter->contact:"n/a",
hex_str(voter->identity_digest, DIGEST_LEN));
});
SMARTLIST_FOREACH(need_certs_from, networkstatus_voter_info_t *, voter,
{
tor_log(severity, LD_DIR, "Looks like we need to download a new "
- "certificate from authority '%s' at %s:%d (contact %s; "
- "identity %s)",
- voter->nickname, voter->address, (int)voter->dir_port,
+ "certificate from authority '%s' at %s:%" PRIu16
+ " (contact %s; identity %s)",
+ voter->nickname, voter->address, voter->ipv4_dirport,
voter->contact?voter->contact:"n/a",
hex_str(voter->identity_digest, DIGEST_LEN));
});
SMARTLIST_FOREACH(missing_authorities, dir_server_t *, ds,
{
tor_log(severity, LD_DIR, "Consensus does not include configured "
- "authority '%s' at %s:%d (identity %s)",
- ds->nickname, ds->address, (int)ds->dir_port,
+ "authority '%s' at %s:%" PRIu16 " (identity %s)",
+ ds->nickname, ds->address, ds->ipv4_dirport,
hex_str(ds->v3_identity_digest, DIGEST_LEN));
});
{
@@ -713,8 +721,8 @@ networkstatus_vote_find_mutable_entry(networkstatus_t *ns, const char *digest)
/** Return the entry in <b>ns</b> for the identity digest <b>digest</b>, or
* NULL if none was found. */
-const routerstatus_t *
-networkstatus_vote_find_entry(networkstatus_t *ns, const char *digest)
+MOCK_IMPL(const routerstatus_t *,
+networkstatus_vote_find_entry,(networkstatus_t *ns, const char *digest))
{
return networkstatus_vote_find_mutable_entry(ns, digest);
}
@@ -1156,7 +1164,7 @@ update_consensus_networkstatus_fetch_time_impl(time_t now, int flav)
}
}
- if (directory_fetches_dir_info_early(options)) {
+ if (dirclient_fetches_dir_info_early(options)) {
/* We want to cache the next one at some point after this one
* is no longer fresh... */
start = (time_t)(c->fresh_until + min_sec_before_caching);
@@ -1178,7 +1186,7 @@ update_consensus_networkstatus_fetch_time_impl(time_t now, int flav)
/* If we're a bridge user, make use of the numbers we just computed
* to choose the rest of the interval *after* them. */
- if (directory_fetches_dir_info_later(options)) {
+ if (dirclient_fetches_dir_info_later(options)) {
/* Give all the *clients* enough time to download the consensus. */
start = (time_t)(start + dl_interval + min_sec_before_caching);
/* But try to get it before ours actually expires. */
@@ -1377,7 +1385,7 @@ networkstatus_get_dl_status_by_flavor_running,(consensus_flavor_t flavor))
}
/** Return the most recent consensus that we have downloaded, or NULL if we
- * don't have one. */
+ * don't have one. May return future or expired consensuses. */
MOCK_IMPL(networkstatus_t *,
networkstatus_get_latest_consensus,(void))
{
@@ -1388,7 +1396,7 @@ networkstatus_get_latest_consensus,(void))
}
/** Return the latest consensus we have whose flavor matches <b>f</b>, or NULL
- * if we don't have one. */
+ * if we don't have one. May return future or expired consensuses. */
MOCK_IMPL(networkstatus_t *,
networkstatus_get_latest_consensus_by_flavor,(consensus_flavor_t f))
{
@@ -1422,10 +1430,11 @@ networkstatus_is_live(const networkstatus_t *ns, time_t now)
return (ns->valid_after <= now && now <= ns->valid_until);
}
-/** Determine if <b>consensus</b> is valid or expired recently enough that
- * we can still use it.
+/** Determine if <b>consensus</b> is valid, or expired recently enough, or not
+ * too far in the future, so that we can still use it.
*
- * Return 1 if the consensus is reasonably live, or 0 if it is too old.
+ * Return 1 if the consensus is reasonably live, or 0 if it is too old or
+ * too new.
*/
int
networkstatus_consensus_reasonably_live(const networkstatus_t *consensus,
@@ -1434,29 +1443,42 @@ networkstatus_consensus_reasonably_live(const networkstatus_t *consensus,
if (BUG(!consensus))
return 0;
- return networkstatus_valid_until_is_reasonably_live(consensus->valid_until,
+ return networkstatus_valid_after_is_reasonably_live(consensus->valid_after,
+ now) &&
+ networkstatus_valid_until_is_reasonably_live(consensus->valid_until,
now);
}
+#define REASONABLY_LIVE_TIME (24*60*60)
+
+/** As networkstatus_consensus_reasonably_live, but takes a valid_after
+ * time, and checks to see if it is in the past, or not too far in the future.
+ */
+int
+networkstatus_valid_after_is_reasonably_live(time_t valid_after,
+ time_t now)
+{
+ return (now >= valid_after - REASONABLY_LIVE_TIME);
+}
+
/** As networkstatus_consensus_reasonably_live, but takes a valid_until
- * time rather than an entire consensus. */
+ * time, and checks to see if it is in the future, or not too far in the past.
+ */
int
networkstatus_valid_until_is_reasonably_live(time_t valid_until,
time_t now)
{
-#define REASONABLY_LIVE_TIME (24*60*60)
return (now <= valid_until + REASONABLY_LIVE_TIME);
}
/** As networkstatus_get_live_consensus(), but is way more tolerant of expired
- * consensuses. */
+ * and future consensuses. */
MOCK_IMPL(networkstatus_t *,
networkstatus_get_reasonably_live_consensus,(time_t now, int flavor))
{
networkstatus_t *consensus =
networkstatus_get_latest_consensus_by_flavor(flavor);
if (consensus &&
- consensus->valid_after <= now &&
networkstatus_consensus_reasonably_live(consensus, now))
return consensus;
else
@@ -1517,7 +1539,7 @@ networkstatus_consensus_can_use_extra_fallbacks,(const or_options_t *options))
>= smartlist_len(router_get_trusted_dir_servers()));
/* If we don't fetch from the authorities, and we have additional mirrors,
* we can use them. */
- return (!directory_fetches_from_authorities(options)
+ return (!dirclient_fetches_from_authorities(options)
&& (smartlist_len(router_get_fallback_dir_servers())
> smartlist_len(router_get_trusted_dir_servers())));
}
@@ -1557,44 +1579,24 @@ networkstatus_consensus_is_already_downloading(const char *resource)
return answer;
}
-/* Does the current, reasonably live consensus have IPv6 addresses?
- * Returns 1 if there is a reasonably live consensus and its consensus method
- * includes IPv6 addresses in the consensus.
- * Otherwise, if there is no consensus, or the method does not include IPv6
- * addresses, returns 0. */
-int
-networkstatus_consensus_has_ipv6(const or_options_t* options)
-{
- const networkstatus_t *cons = networkstatus_get_reasonably_live_consensus(
- approx_time(),
- usable_consensus_flavor());
-
- /* If we have no consensus, we have no IPv6 in it */
- if (!cons) {
- return 0;
- }
-
- /* Different flavours of consensus gained IPv6 at different times */
- if (we_use_microdescriptors_for_circuits(options)) {
- return
- cons->consensus_method >= MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS;
- } else {
- return 1;
- }
-}
-
-/** Given two router status entries for the same router identity, return 1 if
- * if the contents have changed between them. Otherwise, return 0. */
-static int
-routerstatus_has_changed(const routerstatus_t *a, const routerstatus_t *b)
+/** Given two router status entries for the same router identity, return 1
+ * if the contents have changed between them. Otherwise, return 0.
+ * It only checks for fields that are output by control port.
+ * This should be kept in sync with the struct routerstatus_t
+ * and the printing function routerstatus_format_entry in
+ * NS_CONTROL_PORT mode.
+ **/
+STATIC int
+routerstatus_has_visibly_changed(const routerstatus_t *a,
+ const routerstatus_t *b)
{
tor_assert(tor_memeq(a->identity_digest, b->identity_digest, DIGEST_LEN));
return strcmp(a->nickname, b->nickname) ||
fast_memneq(a->descriptor_digest, b->descriptor_digest, DIGEST_LEN) ||
- a->addr != b->addr ||
- a->or_port != b->or_port ||
- a->dir_port != b->dir_port ||
+ !tor_addr_eq(&a->ipv4_addr, &b->ipv4_addr) ||
+ a->ipv4_orport != b->ipv4_orport ||
+ a->ipv4_dirport != b->ipv4_dirport ||
a->is_authority != b->is_authority ||
a->is_exit != b->is_exit ||
a->is_stable != b->is_stable ||
@@ -1605,9 +1607,14 @@ routerstatus_has_changed(const routerstatus_t *a, const routerstatus_t *b)
a->is_valid != b->is_valid ||
a->is_possible_guard != b->is_possible_guard ||
a->is_bad_exit != b->is_bad_exit ||
- a->is_hs_dir != b->is_hs_dir;
- // XXXX this function needs a huge refactoring; it has gotten out
- // XXXX of sync with routerstatus_t, and it will do so again.
+ a->is_hs_dir != b->is_hs_dir ||
+ a->is_staledesc != b->is_staledesc ||
+ a->has_bandwidth != b->has_bandwidth ||
+ a->published_on != b->published_on ||
+ a->ipv6_orport != b->ipv6_orport ||
+ a->is_v2_dir != b->is_v2_dir ||
+ a->bandwidth_kb != b->bandwidth_kb ||
+ tor_addr_compare(&a->ipv6_addr, &b->ipv6_addr, CMP_EXACT);
}
/** Notify controllers of any router status entries that changed between
@@ -1639,7 +1646,7 @@ notify_control_networkstatus_changed(const networkstatus_t *old_c,
tor_memcmp(rs_old->identity_digest,
rs_new->identity_digest, DIGEST_LEN),
smartlist_add(changed, (void*) rs_new)) {
- if (routerstatus_has_changed(rs_old, rs_new))
+ if (routerstatus_has_visibly_changed(rs_old, rs_new))
smartlist_add(changed, (void*)rs_new);
} SMARTLIST_FOREACH_JOIN_END(rs_old, rs_new);
@@ -1655,6 +1662,7 @@ notify_before_networkstatus_changes(const networkstatus_t *old_c,
notify_control_networkstatus_changed(old_c, new_c);
dos_consensus_has_changed(new_c);
relay_consensus_has_changed(new_c);
+ hs_dos_consensus_has_changed(new_c);
}
/* Called after a new consensus has been put in the global state. It is safe
@@ -1662,7 +1670,35 @@ notify_before_networkstatus_changes(const networkstatus_t *old_c,
static void
notify_after_networkstatus_changes(void)
{
+ const networkstatus_t *c = networkstatus_get_latest_consensus();
+ const or_options_t *options = get_options();
+ const time_t now = approx_time();
+
scheduler_notify_networkstatus_changed();
+
+ /* The "current" consensus has just been set and it is a usable flavor so
+ * the first thing we need to do is recalculate the voting schedule static
+ * object so we can use the timings in there needed by some subsystems
+ * such as hidden service and shared random. */
+ dirauth_sched_recalculate_timing(options, now);
+ reschedule_dirvote(options);
+
+ nodelist_set_consensus(c);
+
+ update_consensus_networkstatus_fetch_time(now);
+
+ /* Change the cell EWMA settings */
+ cmux_ewma_set_options(options, c);
+
+ /* XXXX this call might be unnecessary here: can changing the
+ * current consensus really alter our view of any OR's rate limits? */
+ connection_or_update_token_buckets(get_connection_array(), options);
+
+ circuit_build_times_new_consensus_params(
+ get_circuit_build_times_mutable(), c);
+ channelpadding_new_consensus_params(c);
+ circpad_new_consensus_params(c);
+ router_new_consensus_params(c);
}
/** Copy all the ancillary information (like router download status and so on)
@@ -1725,6 +1761,44 @@ networkstatus_set_current_consensus_from_ns(networkstatus_t *c,
#endif /* defined(TOR_UNIT_TESTS) */
/**
+ * Helper: Read the current consensus of type <b>flavor</b> from
+ * <b>fname</b>. Flags and return values are as for
+ * networkstatus_set_current_consensus().
+ **/
+static int
+reload_consensus_from_file(const char *fname,
+ const char *flavor,
+ unsigned flags,
+ const char *source_dir)
+{
+ tor_mmap_t *map = tor_mmap_file(fname);
+ if (!map)
+ return 0;
+
+ int rv = networkstatus_set_current_consensus(map->data, map->size,
+ flavor, flags, source_dir);
+#ifdef _WIN32
+ if (rv < 0 && tor_memstr(map->data, map->size, "\r\n")) {
+ log_notice(LD_GENERAL, "Looks like the above failures are probably "
+ "because of a CRLF in consensus file %s; falling back to "
+ "read_file_to_string. Nothing to worry about: this file "
+ "was probably saved by an earlier version of Tor.",
+ escaped(fname));
+ char *content = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
+ rv = networkstatus_set_current_consensus(content, strlen(content),
+ flavor, flags, source_dir);
+ tor_free(content);
+ }
+#endif /* defined(_WIN32) */
+ if (rv < -1) {
+ log_warn(LD_GENERAL, "Couldn't set consensus from cache file %s",
+ escaped(fname));
+ }
+ tor_munmap_file(map);
+ return rv;
+}
+
+/**
* Helper for handle_missing_protocol_warning: handles either the
* client case (if <b>is_client</b> is set) or the server case otherwise.
*/
@@ -1841,6 +1915,7 @@ warn_early_consensus(const networkstatus_t *c, const char *flavor,
*/
int
networkstatus_set_current_consensus(const char *consensus,
+ size_t consensus_len,
const char *flavor,
unsigned flags,
const char *source_dir)
@@ -1869,7 +1944,9 @@ networkstatus_set_current_consensus(const char *consensus,
}
/* Make sure it's parseable. */
- c = networkstatus_parse_vote_from_string(consensus, NULL, NS_TYPE_CONSENSUS);
+ c = networkstatus_parse_vote_from_string(consensus,
+ consensus_len,
+ NULL, NS_TYPE_CONSENSUS);
if (!c) {
log_warn(LD_DIR, "Unable to parse networkstatus consensus");
result = -2;
@@ -1957,14 +2034,12 @@ networkstatus_set_current_consensus(const char *consensus,
c->valid_after > current_valid_after) {
waiting = &consensus_waiting_for_certs[flav];
networkstatus_vote_free(waiting->consensus);
- tor_free(waiting->body);
waiting->consensus = c;
free_consensus = 0;
- waiting->body = tor_strdup(consensus);
waiting->set_at = now;
waiting->dl_failed = 0;
if (!from_cache) {
- write_str_to_file(unverified_fname, consensus, 0);
+ write_bytes_to_file(unverified_fname, consensus, consensus_len, 1);
}
if (dl_certs)
authority_certs_fetch_missing(c, now, source_dir);
@@ -1976,9 +2051,9 @@ networkstatus_set_current_consensus(const char *consensus,
* latest consensus. */
if (was_waiting_for_certs && from_cache)
if (unlink(unverified_fname) != 0) {
- log_warn(LD_FS,
- "Failed to unlink %s: %s",
- unverified_fname, strerror(errno));
+ log_debug(LD_FS,
+ "Failed to unlink %s: %s",
+ unverified_fname, strerror(errno));
}
}
goto done;
@@ -1991,9 +2066,9 @@ networkstatus_set_current_consensus(const char *consensus,
}
if (was_waiting_for_certs && (r < -1) && from_cache) {
if (unlink(unverified_fname) != 0) {
- log_warn(LD_FS,
- "Failed to unlink %s: %s",
- unverified_fname, strerror(errno));
+ log_debug(LD_FS,
+ "Failed to unlink %s: %s",
+ unverified_fname, strerror(errno));
}
}
goto done;
@@ -2055,16 +2130,12 @@ networkstatus_set_current_consensus(const char *consensus,
waiting->consensus->valid_after <= c->valid_after) {
networkstatus_vote_free(waiting->consensus);
waiting->consensus = NULL;
- if (consensus != waiting->body)
- tor_free(waiting->body);
- else
- waiting->body = NULL;
waiting->set_at = 0;
waiting->dl_failed = 0;
if (unlink(unverified_fname) != 0) {
- log_warn(LD_FS,
- "Failed to unlink %s: %s",
- unverified_fname, strerror(errno));
+ log_debug(LD_FS,
+ "Failed to unlink %s: %s",
+ unverified_fname, strerror(errno));
}
}
@@ -2072,29 +2143,6 @@ networkstatus_set_current_consensus(const char *consensus,
/* Notify that we just changed the consensus so the current global value
* can be looked at. */
notify_after_networkstatus_changes();
-
- /* The "current" consensus has just been set and it is a usable flavor so
- * the first thing we need to do is recalculate the voting schedule static
- * object so we can use the timings in there needed by some subsystems
- * such as hidden service and shared random. */
- voting_schedule_recalculate_timing(options, now);
- reschedule_dirvote(options);
-
- nodelist_set_consensus(c);
-
- /* XXXXNM Microdescs: needs a non-ns variant. ???? NM*/
- update_consensus_networkstatus_fetch_time(now);
-
- /* Change the cell EWMA settings */
- cmux_ewma_set_options(options, c);
-
- /* XXXX this call might be unnecessary here: can changing the
- * current consensus really alter our view of any OR's rate limits? */
- connection_or_update_token_buckets(get_connection_array(), options);
-
- circuit_build_times_new_consensus_params(
- get_circuit_build_times_mutable(), c);
- channelpadding_new_consensus_params(c);
}
/* Reset the failure count only if this consensus is actually valid. */
@@ -2108,22 +2156,23 @@ networkstatus_set_current_consensus(const char *consensus,
if (we_want_to_fetch_flavor(options, flav)) {
if (dir_server_mode(get_options())) {
dirserv_set_cached_consensus_networkstatus(consensus,
+ consensus_len,
flavor,
&c->digests,
c->digest_sha3_as_signed,
c->valid_after);
- consdiffmgr_add_consensus(consensus, c);
+ consdiffmgr_add_consensus(consensus, consensus_len, c);
}
}
if (!from_cache) {
- write_str_to_file(consensus_fname, consensus, 0);
+ write_bytes_to_file(consensus_fname, consensus, consensus_len, 1);
}
warn_early_consensus(c, flavor, now);
- /* We got a new consesus. Reset our md fetch fail cache */
+ /* We got a new consensus. Reset our md fetch fail cache */
microdesc_reset_outdated_dirservers_list();
router_dir_info_changed();
@@ -2154,14 +2203,10 @@ networkstatus_note_certs_arrived(const char *source_dir)
if (!waiting->consensus)
continue;
if (networkstatus_check_consensus_signature(waiting->consensus, 0)>=0) {
- char *waiting_body = waiting->body;
- if (!networkstatus_set_current_consensus(
- waiting_body,
- flavor_name,
- NSSET_WAS_WAITING_FOR_CERTS,
- source_dir)) {
- tor_free(waiting_body);
- }
+ char *fname = networkstatus_get_cache_fname(i, flavor_name, 1);
+ reload_consensus_from_file(fname, flavor_name,
+ NSSET_WAS_WAITING_FOR_CERTS, source_dir);
+ tor_free(fname);
}
}
}
@@ -2311,10 +2356,52 @@ char *
networkstatus_getinfo_helper_single(const routerstatus_t *rs)
{
return routerstatus_format_entry(rs, NULL, NULL, NS_CONTROL_PORT,
- ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD,
NULL);
}
+/**
+ * Extract status information from <b>ri</b> and from other authority
+ * functions and store it in <b>rs</b>. <b>rs</b> is zeroed out before it is
+ * set.
+ *
+ * We assume that node-\>is_running has already been set, e.g. by
+ * dirserv_set_router_is_running(ri, now);
+ */
+void
+set_routerstatus_from_routerinfo(routerstatus_t *rs,
+ const node_t *node,
+ const routerinfo_t *ri)
+{
+ memset(rs, 0, sizeof(routerstatus_t));
+
+ rs->is_authority =
+ router_digest_is_trusted_dir(ri->cache_info.identity_digest);
+
+ /* Set by compute_performance_thresholds or from consensus */
+ rs->is_exit = node->is_exit;
+ rs->is_stable = node->is_stable;
+ rs->is_fast = node->is_fast;
+ rs->is_flagged_running = node->is_running;
+ rs->is_valid = node->is_valid;
+ rs->is_possible_guard = node->is_possible_guard;
+ rs->is_bad_exit = node->is_bad_exit;
+ rs->is_hs_dir = node->is_hs_dir;
+ rs->is_named = rs->is_unnamed = 0;
+
+ rs->published_on = ri->cache_info.published_on;
+ memcpy(rs->identity_digest, node->identity, DIGEST_LEN);
+ memcpy(rs->descriptor_digest, ri->cache_info.signed_descriptor_digest,
+ DIGEST_LEN);
+ tor_addr_copy(&rs->ipv4_addr, &ri->ipv4_addr);
+ strlcpy(rs->nickname, ri->nickname, sizeof(rs->nickname));
+ rs->ipv4_orport = ri->ipv4_orport;
+ rs->ipv4_dirport = ri->ipv4_dirport;
+ rs->is_v2_dir = ri->supports_tunnelled_dir_requests;
+
+ tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr);
+ rs->ipv6_orport = ri->ipv6_orport;
+}
+
/** Alloc and return a string describing routerstatuses for the most
* recent info of each router we know about that is of purpose
* <b>purpose_string</b>. Return NULL if unrecognized purpose.
@@ -2331,7 +2418,6 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now)
smartlist_t *statuses;
const uint8_t purpose = router_purpose_from_string(purpose_string);
routerstatus_t rs;
- const int bridge_auth = authdir_mode_bridge(get_options());
if (purpose == ROUTER_PURPOSE_UNKNOWN) {
log_info(LD_DIR, "Unrecognized purpose '%s' when listing router statuses.",
@@ -2348,11 +2434,7 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now)
continue;
if (ri->purpose != purpose)
continue;
- /* TODO: modifying the running flag in a getinfo is a bad idea */
- if (bridge_auth && ri->purpose == ROUTER_PURPOSE_BRIDGE)
- dirserv_set_router_is_running(ri, now);
- /* then generate and write out status lines for each of them */
- set_routerstatus_from_routerinfo(&rs, node, ri, now, 0);
+ set_routerstatus_from_routerinfo(&rs, node, ri);
smartlist_add(statuses, networkstatus_getinfo_helper_single(&rs));
} SMARTLIST_FOREACH_END(ri);
@@ -2362,42 +2444,12 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now)
return answer;
}
-/** Write out router status entries for all our bridge descriptors. */
-void
-networkstatus_dump_bridge_status_to_file(time_t now)
-{
- char *status = networkstatus_getinfo_by_purpose("bridge", now);
- char *fname = NULL;
- char *thresholds = NULL;
- char *published_thresholds_and_status = NULL;
- char published[ISO_TIME_LEN+1];
- const routerinfo_t *me = router_get_my_routerinfo();
- char fingerprint[FINGERPRINT_LEN+1];
- char *fingerprint_line = NULL;
-
- if (me && crypto_pk_get_fingerprint(me->identity_pkey,
- fingerprint, 0) >= 0) {
- tor_asprintf(&fingerprint_line, "fingerprint %s\n", fingerprint);
- } else {
- log_warn(LD_BUG, "Error computing fingerprint for bridge status.");
- }
- format_iso_time(published, now);
- dirserv_compute_bridge_flag_thresholds();
- thresholds = dirserv_get_flag_thresholds_line();
- tor_asprintf(&published_thresholds_and_status,
- "published %s\nflag-thresholds %s\n%s%s",
- published, thresholds, fingerprint_line ? fingerprint_line : "",
- status);
- fname = get_datadir_fname("networkstatus-bridges");
- write_str_to_file(fname,published_thresholds_and_status,0);
- tor_free(thresholds);
- tor_free(published_thresholds_and_status);
- tor_free(fname);
- tor_free(status);
- tor_free(fingerprint_line);
-}
-
-/* DOCDOC get_net_param_from_list */
+/**
+ * Search through a smartlist of "key=int32" strings for a value beginning
+ * with "param_name=". If one is found, clip it to be between min_val and
+ * max_val inclusive and return it. If one is not found, return
+ * default_val.
+ ***/
static int32_t
get_net_param_from_list(smartlist_t *net_params, const char *param_name,
int32_t default_val, int32_t min_val, int32_t max_val)
@@ -2668,6 +2720,16 @@ networkstatus_check_required_protocols(const networkstatus_t *ns,
const char *required, *recommended;
char *missing = NULL;
+ const bool consensus_postdates_this_release =
+ ns->valid_after >= tor_get_approx_release_date();
+
+ if (! consensus_postdates_this_release) {
+ // We can't meaningfully warn about this case: This consensus is from
+ // before we were released, so whatever is says about required or
+ // recommended versions may no longer be true.
+ return 0;
+ }
+
tor_assert(warning_out);
if (client_mode) {
@@ -2718,6 +2780,49 @@ networkstatus_free_all(void)
networkstatus_vote_free(waiting->consensus);
waiting->consensus = NULL;
}
- tor_free(waiting->body);
}
}
+
+/** Return the start of the next interval of size <b>interval</b> (in
+ * seconds) after <b>now</b>, plus <b>offset</b>. Midnight always
+ * starts a fresh interval, and if the last interval of a day would be
+ * truncated to less than half its size, it is rolled into the
+ * previous interval. */
+time_t
+voting_sched_get_start_of_interval_after(time_t now, int interval,
+ int offset)
+{
+ struct tm tm;
+ time_t midnight_today=0;
+ time_t midnight_tomorrow;
+ time_t next;
+
+ tor_gmtime_r(&now, &tm);
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+
+ if (tor_timegm(&tm, &midnight_today) < 0) {
+ // LCOV_EXCL_START
+ log_warn(LD_BUG, "Ran into an invalid time when trying to find midnight.");
+ // LCOV_EXCL_STOP
+ }
+ midnight_tomorrow = midnight_today + (24*60*60);
+
+ next = midnight_today + ((now-midnight_today)/interval + 1)*interval;
+
+ /* Intervals never cross midnight. */
+ if (next > midnight_tomorrow)
+ next = midnight_tomorrow;
+
+ /* If the interval would only last half as long as it's supposed to, then
+ * skip over to the next day. */
+ if (next + interval/2 > midnight_tomorrow)
+ next = midnight_tomorrow;
+
+ next += offset;
+ if (next - interval > now)
+ next -= interval;
+
+ return next;
+}
diff --git a/src/feature/nodelist/networkstatus.h b/src/feature/nodelist/networkstatus.h
index 9e7b0f1bb0..ce050aeadc 100644
--- a/src/feature/nodelist/networkstatus.h
+++ b/src/feature/nodelist/networkstatus.h
@@ -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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,7 +16,10 @@
void networkstatus_reset_warnings(void);
void networkstatus_reset_download_failures(void);
-char *networkstatus_read_cached_consensus(const char *flavorname);
+MOCK_DECL(char *,networkstatus_get_cache_fname,(int flav,
+ const char *flavorname,
+ int unverified_consensus));
+tor_mmap_t *networkstatus_map_cached_consensus(const char *flavorname);
int router_reload_consensus_networkstatus(void);
void routerstatus_free_(routerstatus_t *rs);
#define routerstatus_free(rs) \
@@ -40,8 +43,9 @@ int compare_digest_to_routerstatus_entry(const void *_key,
const void **_member);
int compare_digest_to_vote_routerstatus_entry(const void *_key,
const void **_member);
-const routerstatus_t *networkstatus_vote_find_entry(networkstatus_t *ns,
- const char *digest);
+MOCK_DECL(const routerstatus_t *,networkstatus_vote_find_entry,(
+ networkstatus_t *ns,
+ const char *digest));
routerstatus_t *networkstatus_vote_find_mutable_entry(networkstatus_t *ns,
const char *digest);
int networkstatus_vote_find_entry_idx(networkstatus_t *ns,
@@ -87,6 +91,8 @@ MOCK_DECL(networkstatus_t *, networkstatus_get_live_consensus,(time_t now));
int networkstatus_is_live(const networkstatus_t *ns, time_t now);
int networkstatus_consensus_reasonably_live(const networkstatus_t *consensus,
time_t now);
+int networkstatus_valid_after_is_reasonably_live(time_t valid_after,
+ time_t now);
int networkstatus_valid_until_is_reasonably_live(time_t valid_until,
time_t now);
MOCK_DECL(networkstatus_t *,networkstatus_get_reasonably_live_consensus,
@@ -98,7 +104,6 @@ int networkstatus_consensus_can_use_multiple_directories(
MOCK_DECL(int, networkstatus_consensus_can_use_extra_fallbacks,(
const or_options_t *options));
int networkstatus_consensus_is_already_downloading(const char *resource);
-int networkstatus_consensus_has_ipv6(const or_options_t* options);
#define NSSET_FROM_CACHE 1
#define NSSET_WAS_WAITING_FOR_CERTS 2
@@ -106,6 +111,7 @@ int networkstatus_consensus_has_ipv6(const or_options_t* options);
#define NSSET_ACCEPT_OBSOLETE 8
#define NSSET_REQUIRE_FLAVOR 16
int networkstatus_set_current_consensus(const char *consensus,
+ size_t consensus_len,
const char *flavor,
unsigned flags,
const char *source_dir);
@@ -118,7 +124,6 @@ void signed_descs_update_status_from_consensus_networkstatus(
char *networkstatus_getinfo_helper_single(const routerstatus_t *rs);
char *networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now);
-void networkstatus_dump_bridge_status_to_file(time_t now);
MOCK_DECL(int32_t, networkstatus_get_param,
(const networkstatus_t *ns, const char *param_name,
int32_t default_val, int32_t min_val, int32_t max_val));
@@ -145,6 +150,13 @@ void vote_routerstatus_free_(vote_routerstatus_t *rs);
#define vote_routerstatus_free(rs) \
FREE_AND_NULL(vote_routerstatus_t, vote_routerstatus_free_, (rs))
+void set_routerstatus_from_routerinfo(routerstatus_t *rs,
+ const node_t *node,
+ const routerinfo_t *ri);
+time_t voting_sched_get_start_of_interval_after(time_t now,
+ int interval,
+ int offset);
+
#ifdef NETWORKSTATUS_PRIVATE
#ifdef TOR_UNIT_TESTS
STATIC int networkstatus_set_current_consensus_from_ns(networkstatus_t *c,
@@ -154,7 +166,8 @@ STATIC void warn_early_consensus(const networkstatus_t *c, const char *flavor,
extern networkstatus_t *current_ns_consensus;
extern networkstatus_t *current_md_consensus;
#endif /* defined(TOR_UNIT_TESTS) */
+STATIC int routerstatus_has_visibly_changed(const routerstatus_t *a,
+ const routerstatus_t *b);
#endif /* defined(NETWORKSTATUS_PRIVATE) */
#endif /* !defined(TOR_NETWORKSTATUS_H) */
-
diff --git a/src/feature/nodelist/networkstatus_sr_info_st.h b/src/feature/nodelist/networkstatus_sr_info_st.h
index 677d8ed811..04d0dfe8f6 100644
--- a/src/feature/nodelist/networkstatus_sr_info_st.h
+++ b/src/feature/nodelist/networkstatus_sr_info_st.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file networkstatus_sr_info_st.h
+ * @brief Shared-randomness structure.
+ **/
+
#ifndef NETWORKSTATUS_SR_INFO_ST_H
#define NETWORKSTATUS_SR_INFO_ST_H
@@ -19,5 +24,4 @@ struct networkstatus_sr_info_t {
smartlist_t *commits;
};
-#endif
-
+#endif /* !defined(NETWORKSTATUS_SR_INFO_ST_H) */
diff --git a/src/feature/nodelist/networkstatus_st.h b/src/feature/nodelist/networkstatus_st.h
index 6160f12361..021168d3ca 100644
--- a/src/feature/nodelist/networkstatus_st.h
+++ b/src/feature/nodelist/networkstatus_st.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file networkstatus_st.h
+ * @brief Networkstatus consensus/vote structure.
+ **/
+
#ifndef NETWORKSTATUS_ST_H
#define NETWORKSTATUS_ST_H
@@ -99,6 +104,9 @@ struct networkstatus_t {
/** List of key=value strings from the headers of the bandwidth list file */
smartlist_t *bw_file_headers;
+
+ /** A SHA256 digest of the bandwidth file used in a vote. */
+ uint8_t bw_file_digest256[DIGEST256_LEN];
};
-#endif
+#endif /* !defined(NETWORKSTATUS_ST_H) */
diff --git a/src/feature/nodelist/networkstatus_voter_info_st.h b/src/feature/nodelist/networkstatus_voter_info_st.h
index 4037fcdeca..a0fba2e1b5 100644
--- a/src/feature/nodelist/networkstatus_voter_info_st.h
+++ b/src/feature/nodelist/networkstatus_voter_info_st.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file networkstatus_voter_info_st.h
+ * @brief Single consensus voter structure.
+ **/
+
#ifndef NETWORKSTATUS_VOTER_INFO_ST_H
#define NETWORKSTATUS_VOTER_INFO_ST_H
@@ -16,9 +21,9 @@ struct networkstatus_voter_info_t {
* consensuses, we treat legacy keys as additional signers. */
char legacy_id_digest[DIGEST_LEN];
char *address; /**< Address of this voter, in string format. */
- uint32_t addr; /**< Address of this voter, in IPv4, in host order. */
- uint16_t dir_port; /**< Directory port of this voter */
- uint16_t or_port; /**< OR port of this voter */
+ tor_addr_t ipv4_addr;
+ uint16_t ipv4_dirport; /**< Directory port of this voter */
+ uint16_t ipv4_orport; /**< OR port of this voter */
char *contact; /**< Contact information for this voter. */
char vote_digest[DIGEST_LEN]; /**< Digest of this voter's vote, as signed. */
@@ -27,4 +32,4 @@ struct networkstatus_voter_info_t {
smartlist_t *sigs;
};
-#endif
+#endif /* !defined(NETWORKSTATUS_VOTER_INFO_ST_H) */
diff --git a/src/feature/nodelist/nickname.c b/src/feature/nodelist/nickname.c
index 5378b749ca..c022dd6bc4 100644
--- a/src/feature/nodelist/nickname.c
+++ b/src/feature/nodelist/nickname.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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/nodelist/nickname.h b/src/feature/nodelist/nickname.h
index 9bdc6b50e8..11c6416f3a 100644
--- a/src/feature/nodelist/nickname.h
+++ b/src/feature/nodelist/nickname.h
@@ -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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,4 +16,4 @@ int is_legal_nickname(const char *s);
int is_legal_nickname_or_hexdigest(const char *s);
int is_legal_hexdigest(const char *s);
-#endif
+#endif /* !defined(TOR_NICKNAME_H) */
diff --git a/src/feature/nodelist/node_select.c b/src/feature/nodelist/node_select.c
index 7b9e241e5b..ecb70aef14 100644
--- a/src/feature/nodelist/node_select.c
+++ b/src/feature/nodelist/node_select.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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,6 +19,7 @@
#include "core/or/reasons.h"
#include "feature/client/entrynodes.h"
#include "feature/dirclient/dirclient.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dircommon/directory.h"
#include "feature/nodelist/describe.h"
#include "feature/nodelist/dirlist.h"
@@ -30,6 +31,7 @@
#include "feature/nodelist/routerset.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
+#include "lib/container/bitarray.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/math/fp.h"
@@ -139,14 +141,14 @@ router_pick_dirserver_generic(smartlist_t *sourcelist,
#define RETRY_ALTERNATE_IP_VERSION(retry_label) \
STMT_BEGIN \
if (result == NULL && try_ip_pref && options->ClientUseIPv4 \
- && fascist_firewall_use_ipv6(options) && !server_mode(options) \
+ && reachable_addr_use_ipv6(options) && !server_mode(options) \
&& !n_busy) { \
n_excluded = 0; \
n_busy = 0; \
try_ip_pref = 0; \
goto retry_label; \
} \
- STMT_END \
+ STMT_END
/* Common retry code for router_pick_directory_server_impl and
* router_pick_trusteddirserver_impl. Retry without excluding nodes, but with
@@ -210,18 +212,20 @@ router_picked_poor_directory_log(const routerstatus_t *rs)
log_debug(LD_DIR, "Wanted to make an outgoing directory connection, but "
"we couldn't find a directory that fit our criteria. "
"Perhaps we will succeed next time with less strict criteria.");
- } else if (!fascist_firewall_allows_rs(rs, FIREWALL_OR_CONNECTION, 1)
- && !fascist_firewall_allows_rs(rs, FIREWALL_DIR_CONNECTION, 1)
+ } else if (!reachable_addr_allows_rs(rs, FIREWALL_OR_CONNECTION, 1)
+ && !reachable_addr_allows_rs(rs, FIREWALL_DIR_CONNECTION, 1)
) {
/* This is rare, and might be interesting to users trying to diagnose
* connection issues on dual-stack machines. */
+ char *ipv4_str = tor_addr_to_str_dup(&rs->ipv4_addr);
log_info(LD_DIR, "Selected a directory %s with non-preferred OR and Dir "
"addresses for launching an outgoing connection: "
"IPv4 %s OR %d Dir %d IPv6 %s OR %d Dir %d",
routerstatus_describe(rs),
- fmt_addr32(rs->addr), rs->or_port,
- rs->dir_port, fmt_addr(&rs->ipv6_addr),
- rs->ipv6_orport, rs->dir_port);
+ ipv4_str, rs->ipv4_orport,
+ rs->ipv4_dirport, fmt_addr(&rs->ipv6_addr),
+ rs->ipv6_orport, rs->ipv4_dirport);
+ tor_free(ipv4_str);
}
}
@@ -264,7 +268,7 @@ router_is_already_dir_fetching(const tor_addr_port_t *ap, int serverdesc,
* If so, return 1, if not, return 0.
*/
static int
-router_is_already_dir_fetching_(uint32_t ipv4_addr,
+router_is_already_dir_fetching_(const tor_addr_t *ipv4_addr,
const tor_addr_t *ipv6_addr,
uint16_t dir_port,
int serverdesc,
@@ -273,7 +277,7 @@ router_is_already_dir_fetching_(uint32_t ipv4_addr,
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, ipv4_addr);
+ tor_addr_copy(&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;
@@ -319,9 +323,13 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
overloaded_direct = smartlist_new();
overloaded_tunnel = smartlist_new();
- const int skip_or_fw = router_skip_or_reachability(options, try_ip_pref);
- const int skip_dir_fw = router_skip_dir_reachability(options, try_ip_pref);
- const int must_have_or = directory_must_use_begindir(options);
+ const int skip_or_fw = router_or_conn_should_skip_reachable_address_check(
+ options,
+ try_ip_pref);
+ const int skip_dir_fw = router_dir_conn_should_skip_reachable_address_check(
+ options,
+ try_ip_pref);
+ const int must_have_or = dirclient_must_use_begindir(options);
/* Find all the running dirservers we know about. */
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
@@ -346,9 +354,9 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
continue;
}
- if (router_is_already_dir_fetching_(status->addr,
+ if (router_is_already_dir_fetching_(&status->ipv4_addr,
&status->ipv6_addr,
- status->dir_port,
+ status->ipv4_dirport,
no_serverdesc_fetching,
no_microdesc_fetching)) {
++n_busy;
@@ -366,12 +374,12 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
* we try routers that only have one address both times.)
*/
if (!fascistfirewall || skip_or_fw ||
- fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION,
+ reachable_addr_allows_node(node, FIREWALL_OR_CONNECTION,
try_ip_pref))
smartlist_add(is_trusted ? trusted_tunnel :
is_overloaded ? overloaded_tunnel : tunnel, (void*)node);
else if (!must_have_or && (skip_dir_fw ||
- fascist_firewall_allows_node(node, FIREWALL_DIR_CONNECTION,
+ reachable_addr_allows_node(node, FIREWALL_DIR_CONNECTION,
try_ip_pref)))
smartlist_add(is_trusted ? trusted_direct :
is_overloaded ? overloaded_direct : direct, (void*)node);
@@ -630,6 +638,7 @@ compute_weighted_bandwidths(const smartlist_t *sl,
}
weight_scale = networkstatus_get_weight_scale_param(NULL);
+ tor_assert(weight_scale >= 1);
if (rule == WEIGHT_FOR_GUARD) {
Wg = networkstatus_get_bw_weight(NULL, "Wgg", -1);
@@ -871,90 +880,79 @@ routerlist_add_node_and_family(smartlist_t *sl, const routerinfo_t *router)
nodelist_add_node_and_family(sl, node);
}
-/** Return a random running node from the nodelist. Never
- * pick a node that is in
- * <b>excludedsmartlist</b>, or which matches <b>excludedset</b>,
- * even if they are the only nodes available.
- * If <b>CRN_NEED_UPTIME</b> is set in flags and any router has more than
- * 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_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
- * node (that is, possibly discounting exit nodes).
- * If <b>CRN_NEED_DESC</b> is set in flags, we only consider nodes that
- * have a routerinfo or microdescriptor -- that is, enough info to be
- * used to build a circuit.
- * If <b>CRN_PREF_ADDR</b> is set in flags, we only consider nodes that
- * have an address that is preferred by the ClientPreferIPv6ORPort setting
- * (regardless of this flag, we exclude nodes that aren't allowed by the
- * firewall, including ClientUseIPv4 0 and fascist_firewall_use_ipv6() == 0).
- */
-const node_t *
-router_choose_random_node(smartlist_t *excludedsmartlist,
- routerset_t *excludedset,
- router_crn_flags_t flags)
-{ /* XXXX MOVE */
- 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 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();
- const node_t *choice = NULL;
- const routerinfo_t *r;
- bandwidth_weight_rule_t rule;
+/**
+ * Remove every node_t that appears in <b>excluded</b> from <b>sl</b>.
+ *
+ * Behaves like smartlist_subtract, but uses nodelist_idx values to deliver
+ * linear performance when smartlist_subtract would be quadratic.
+ **/
+static void
+nodelist_subtract(smartlist_t *sl, const smartlist_t *excluded)
+{
+ const smartlist_t *nodelist = nodelist_get_list();
+ const int nodelist_len = smartlist_len(nodelist);
+ bitarray_t *excluded_idx = bitarray_init_zero(nodelist_len);
- tor_assert(!(weight_for_exit && need_guard));
- rule = weight_for_exit ? WEIGHT_FOR_EXIT :
- (need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID);
-
- 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);
+ /* We haven't used nodelist_idx in this way previously, so I'm going to be
+ * paranoid in this code, and check that nodelist_idx is correct for every
+ * node before we use it. If we fail, we fall back to smartlist_subtract().
+ */
+
+ /* Set the excluded_idx bit corresponding to every excluded node...
+ */
+ SMARTLIST_FOREACH_BEGIN(excluded, const node_t *, node) {
+ const int idx = node->nodelist_idx;
+ if (BUG(idx < 0) || BUG(idx >= nodelist_len) ||
+ BUG(node != smartlist_get(nodelist, idx))) {
+ goto internal_error;
}
+ bitarray_set(excluded_idx, idx);
} 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
- * this is fine to at least try with our routerinfo_t object. */
- if ((r = router_get_my_routerinfo()))
- routerlist_add_node_and_family(excludednodes, r);
+ /* Then remove them from sl.
+ */
+ SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
+ const int idx = node->nodelist_idx;
+ if (BUG(idx < 0) || BUG(idx >= nodelist_len) ||
+ BUG(node != smartlist_get(nodelist, idx))) {
+ goto internal_error;
+ }
+ if (bitarray_is_set(excluded_idx, idx)) {
+ SMARTLIST_DEL_CURRENT(sl, node);
+ }
+ } SMARTLIST_FOREACH_END(node);
+
+ bitarray_free(excluded_idx);
+ return;
+
+ internal_error:
+ log_warn(LD_BUG, "Internal error prevented us from using the fast method "
+ "for subtracting nodelists. Falling back to the quadratic way.");
+ smartlist_subtract(sl, excluded);
+ bitarray_free(excluded_idx);
+}
+
+/* Node selection helper for router_choose_random_node().
+ *
+ * Populates a node list based on <b>flags</b>, ignoring nodes in
+ * <b>excludednodes</b> and <b>excludedset</b>. Chooses the node based on
+ * <b>rule</b>. */
+static const node_t *
+router_choose_random_node_helper(smartlist_t *excludednodes,
+ routerset_t *excludedset,
+ router_crn_flags_t flags,
+ bandwidth_weight_rule_t rule)
+{
+ smartlist_t *sl=smartlist_new();
+ const node_t *choice = NULL;
- router_add_running_nodes_to_smartlist(sl, need_uptime, need_capacity,
- need_guard, need_desc, pref_addr,
- direct_conn);
+ router_add_running_nodes_to_smartlist(sl, flags);
log_debug(LD_CIRC,
"We found %d running nodes.",
smartlist_len(sl));
- smartlist_subtract(sl,excludednodes);
- log_debug(LD_CIRC,
- "We removed %d excludednodes, leaving %d nodes.",
- smartlist_len(excludednodes),
- smartlist_len(sl));
+ nodelist_subtract(sl, excludednodes);
- if (excludedsmartlist) {
- smartlist_subtract(sl,excludedsmartlist);
- log_debug(LD_CIRC,
- "We removed %d excludedsmartlist, leaving %d nodes.",
- smartlist_len(excludedsmartlist),
- smartlist_len(sl));
- }
if (excludedset) {
routerset_subtract_nodes(sl,excludedset);
log_debug(LD_CIRC,
@@ -966,18 +964,66 @@ router_choose_random_node(smartlist_t *excludedsmartlist,
choice = node_sl_choose_by_bandwidth(sl, rule);
smartlist_free(sl);
+
+ return choice;
+}
+
+/** Return a random running node from the nodelist. Never pick a node that is
+ * in <b>excludedsmartlist</b>, or which matches <b>excludedset</b>, even if
+ * they are the only nodes available.
+ *
+ * <b>flags</b> is a set of CRN_* flags, see
+ * router_add_running_nodes_to_smartlist() for details.
+ */
+const node_t *
+router_choose_random_node(smartlist_t *excludedsmartlist,
+ routerset_t *excludedset,
+ router_crn_flags_t flags)
+{
+ /* A limited set of flags, used for fallback node selection.
+ */
+ const bool need_uptime = (flags & CRN_NEED_UPTIME) != 0;
+ const bool need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
+ const bool need_guard = (flags & CRN_NEED_GUARD) != 0;
+ const bool pref_addr = (flags & CRN_PREF_ADDR) != 0;
+
+ smartlist_t *excludednodes=smartlist_new();
+ const node_t *choice = NULL;
+ const routerinfo_t *r;
+ bandwidth_weight_rule_t rule;
+
+ rule = (need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID);
+
+ /* 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
+ * this is fine to at least try with our routerinfo_t object. */
+ if ((r = router_get_my_routerinfo()))
+ routerlist_add_node_and_family(excludednodes, r);
+
+ if (excludedsmartlist) {
+ smartlist_add_all(excludednodes, excludedsmartlist);
+ }
+
+ choice = router_choose_random_node_helper(excludednodes,
+ excludedset,
+ flags,
+ rule);
+
if (!choice && (need_uptime || need_capacity || need_guard || pref_addr)) {
- /* try once more -- recurse but with fewer restrictions. */
+ /* try once more, with fewer restrictions. */
log_info(LD_CIRC,
- "We couldn't find any live%s%s%s routers; falling back "
+ "We couldn't find any live%s%s%s%s routers; falling back "
"to list of all routers.",
need_capacity?", fast":"",
need_uptime?", stable":"",
- need_guard?", guard":"");
+ need_guard?", guard":"",
+ pref_addr?", preferred address":"");
flags &= ~ (CRN_NEED_UPTIME|CRN_NEED_CAPACITY|CRN_NEED_GUARD|
CRN_PREF_ADDR);
- choice = router_choose_random_node(
- excludedsmartlist, excludedset, flags);
+ choice = router_choose_random_node_helper(excludednodes,
+ excludedset,
+ flags,
+ rule);
}
smartlist_free(excludednodes);
if (!choice) {
@@ -1072,9 +1118,13 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
overloaded_direct = smartlist_new();
overloaded_tunnel = smartlist_new();
- const int skip_or_fw = router_skip_or_reachability(options, try_ip_pref);
- const int skip_dir_fw = router_skip_dir_reachability(options, try_ip_pref);
- const int must_have_or = directory_must_use_begindir(options);
+ const int skip_or_fw = router_or_conn_should_skip_reachable_address_check(
+ options,
+ try_ip_pref);
+ const int skip_dir_fw = router_dir_conn_should_skip_reachable_address_check(
+ options,
+ try_ip_pref);
+ const int must_have_or = dirclient_must_use_begindir(options);
SMARTLIST_FOREACH_BEGIN(sourcelist, const dir_server_t *, d)
{
@@ -1095,9 +1145,9 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
continue;
}
- if (router_is_already_dir_fetching_(d->addr,
+ if (router_is_already_dir_fetching_(&d->ipv4_addr,
&d->ipv6_addr,
- d->dir_port,
+ d->ipv4_dirport,
no_serverdesc_fetching,
no_microdesc_fetching)) {
++n_busy;
@@ -1112,11 +1162,11 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
* we try routers that only have one address both times.)
*/
if (!fascistfirewall || skip_or_fw ||
- fascist_firewall_allows_dir_server(d, FIREWALL_OR_CONNECTION,
+ reachable_addr_allows_dir_server(d, FIREWALL_OR_CONNECTION,
try_ip_pref))
smartlist_add(is_overloaded ? overloaded_tunnel : tunnel, (void*)d);
else if (!must_have_or && (skip_dir_fw ||
- fascist_firewall_allows_dir_server(d, FIREWALL_DIR_CONNECTION,
+ reachable_addr_allows_dir_server(d, FIREWALL_DIR_CONNECTION,
try_ip_pref)))
smartlist_add(is_overloaded ? overloaded_direct : direct, (void*)d);
}
diff --git a/src/feature/nodelist/node_select.h b/src/feature/nodelist/node_select.h
index ed7450b92c..1776d8ea1a 100644
--- a/src/feature/nodelist/node_select.h
+++ b/src/feature/nodelist/node_select.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,20 +14,26 @@
/** Flags to be passed to control router_choose_random_node() to indicate what
* kind of nodes to pick according to what algorithm. */
typedef enum router_crn_flags_t {
+ /* Try to choose stable nodes. */
CRN_NEED_UPTIME = 1<<0,
+ /* Try to choose nodes with a reasonable amount of bandwidth. */
CRN_NEED_CAPACITY = 1<<1,
- CRN_NEED_GUARD = 1<<2,
- /* XXXX not used, apparently. */
- CRN_WEIGHT_AS_EXIT = 1<<5,
- CRN_NEED_DESC = 1<<6,
- /* On clients, only provide nodes that satisfy ClientPreferIPv6OR */
- CRN_PREF_ADDR = 1<<7,
+ /* Only choose nodes if we have downloaded their descriptor or
+ * microdescriptor. */
+ CRN_NEED_DESC = 1<<2,
+ /* Choose nodes that can be used as Guard relays. */
+ CRN_NEED_GUARD = 1<<3,
/* On clients, only provide nodes that we can connect to directly, based on
- * our firewall rules */
- CRN_DIRECT_CONN = 1<<8,
- /* On clients, only provide nodes with HSRend >= 2 protocol version which
- * is required for hidden service version >= 3. */
- CRN_RENDEZVOUS_V3 = 1<<9,
+ * our firewall rules. */
+ CRN_DIRECT_CONN = 1<<4,
+ /* On clients, if choosing a node for a direct connection, only provide
+ * nodes that satisfy ClientPreferIPv6OR. */
+ CRN_PREF_ADDR = 1<<5,
+ /* On clients, only provide nodes with HSRend=2 protocol version which
+ * is required for hidden service version 3. */
+ CRN_RENDEZVOUS_V3 = 1<<6,
+ /* On clients, only provide nodes that can initiate IPv6 extends. */
+ CRN_INITIATE_IPV6_EXTEND = 1<<7,
} router_crn_flags_t;
/** Possible ways to weight routers when choosing one randomly. See
@@ -97,6 +103,6 @@ STATIC const routerstatus_t *router_pick_directory_server_impl(
int *n_busy_out);
STATIC int router_is_already_dir_fetching(const tor_addr_port_t *ap,
int serverdesc, int microdesc);
-#endif
+#endif /* defined(NODE_SELECT_PRIVATE) */
-#endif
+#endif /* !defined(TOR_NODE_SELECT_H) */
diff --git a/src/feature/nodelist/node_st.h b/src/feature/nodelist/node_st.h
index 53ffde29e4..3769f9dc84 100644
--- a/src/feature/nodelist/node_st.h
+++ b/src/feature/nodelist/node_st.h
@@ -1,14 +1,20 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file node_st.h
+ * @brief Node information structure.
+ **/
+
#ifndef NODE_ST_H
#define NODE_ST_H
#include "feature/hs/hsdir_index_st.h"
#include "lib/crypt_ops/crypto_ed25519.h"
+#include "ext/ht.h"
/** A node_t represents a Tor router.
*
@@ -78,12 +84,11 @@ struct node_t {
/* Local info: derived. */
- /** True if the IPv6 OR port is preferred over the IPv4 OR port.
- * XX/teor - can this become out of date if the torrc changes? */
+ /** True if the IPv6 OR port is preferred over the IPv4 OR port. */
unsigned int ipv6_preferred:1;
/** According to the geoip db what country is this router in? */
- /* XXXprop186 what is this suppose to mean with multiple OR ports? */
+ /* IPv6: what is this supposed to mean with multiple OR ports? */
country_t country;
/* The below items are used only by authdirservers for
@@ -99,4 +104,4 @@ struct node_t {
struct hsdir_index_t hsdir_index;
};
-#endif
+#endif /* !defined(NODE_ST_H) */
diff --git a/src/feature/nodelist/nodefamily.c b/src/feature/nodelist/nodefamily.c
new file mode 100644
index 0000000000..feaa3730dc
--- /dev/null
+++ b/src/feature/nodelist/nodefamily.c
@@ -0,0 +1,416 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file nodefamily.c
+ * \brief Code to manipulate encoded, reference-counted node families. We
+ * use these tricks to save space, since these families would otherwise
+ * require a large number of tiny allocations.
+ **/
+
+#include "core/or/or.h"
+#include "feature/nodelist/nickname.h"
+#include "feature/nodelist/nodefamily.h"
+#include "feature/nodelist/nodefamily_st.h"
+#include "feature/nodelist/nodelist.h"
+#include "feature/relay/router.h"
+#include "feature/nodelist/routerlist.h"
+
+#include "ht.h"
+#include "siphash.h"
+
+#include "lib/container/smartlist.h"
+#include "lib/ctime/di_ops.h"
+#include "lib/defs/digest_sizes.h"
+#include "lib/log/util_bug.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Allocate and return a blank node family with space to hold <b>n_members</b>
+ * members.
+ */
+static nodefamily_t *
+nodefamily_alloc(int n_members)
+{
+ size_t alloc_len = offsetof(nodefamily_t, family_members) +
+ NODEFAMILY_ARRAY_SIZE(n_members);
+ nodefamily_t *nf = tor_malloc_zero(alloc_len);
+ nf->n_members = n_members;
+ return nf;
+}
+
+/**
+ * Hashtable hash implementation.
+ */
+static inline unsigned int
+nodefamily_hash(const nodefamily_t *nf)
+{
+ return (unsigned) siphash24g(nf->family_members,
+ NODEFAMILY_ARRAY_SIZE(nf->n_members));
+}
+
+/**
+ * Hashtable equality implementation.
+ */
+static inline unsigned int
+nodefamily_eq(const nodefamily_t *a, const nodefamily_t *b)
+{
+ return (a->n_members == b->n_members) &&
+ fast_memeq(a->family_members, b->family_members,
+ NODEFAMILY_ARRAY_SIZE(a->n_members));
+}
+
+static HT_HEAD(nodefamily_map, nodefamily_t) the_node_families
+ = HT_INITIALIZER();
+
+HT_PROTOTYPE(nodefamily_map, nodefamily_t, ht_ent, nodefamily_hash,
+ nodefamily_eq);
+HT_GENERATE2(nodefamily_map, nodefamily_t, ht_ent, nodefamily_hash,
+ node_family_eq, 0.6, tor_reallocarray_, tor_free_);
+
+/**
+ * Parse the family declaration in <b>s</b>, returning the canonical
+ * <b>nodefamily_t</b> for its members. Return NULL on error.
+ *
+ * If <b>rsa_id_self</b> is provided, it is a DIGEST_LEN-byte digest
+ * for the router that declared this family: insert it into the
+ * family declaration if it is not there already.
+ *
+ * If NF_WARN_MALFORMED is set in <b>flags</b>, warn about any
+ * elements that we can't parse. (By default, we log at info.)
+ *
+ * If NF_REJECT_MALFORMED is set in <b>flags</b>, treat any unparseable
+ * elements as an error. (By default, we simply omit them.)
+ **/
+nodefamily_t *
+nodefamily_parse(const char *s, const uint8_t *rsa_id_self,
+ unsigned flags)
+{
+ smartlist_t *sl = smartlist_new();
+ smartlist_split_string(sl, s, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ nodefamily_t *result = nodefamily_from_members(sl, rsa_id_self, flags, NULL);
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_free(sl);
+ return result;
+}
+
+/**
+ * Canonicalize the family list <b>s</b>, returning a newly allocated string.
+ *
+ * The canonicalization rules are fully specified in dir-spec.txt, but,
+ * briefly: $hexid entries are put in caps, $hexid[=~]foo entries are
+ * truncated, nicknames are put into lowercase, unrecognized entries are left
+ * alone, and everything is sorted.
+ **/
+char *
+nodefamily_canonicalize(const char *s, const uint8_t *rsa_id_self,
+ unsigned flags)
+{
+ smartlist_t *sl = smartlist_new();
+ smartlist_t *result_members = smartlist_new();
+ smartlist_split_string(sl, s, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ nodefamily_t *nf = nodefamily_from_members(sl, rsa_id_self, flags,
+ result_members);
+
+ char *formatted = nodefamily_format(nf);
+ smartlist_split_string(result_members, formatted, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ smartlist_sort_strings(result_members);
+ char *combined = smartlist_join_strings(result_members, " ", 0, NULL);
+
+ nodefamily_free(nf);
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_free(sl);
+ SMARTLIST_FOREACH(result_members, char *, cp, tor_free(cp));
+ smartlist_free(result_members);
+ tor_free(formatted);
+
+ return combined;
+}
+
+/**
+ * qsort helper for encoded nodefamily elements.
+ **/
+static int
+compare_members(const void *a, const void *b)
+{
+ return fast_memcmp(a, b, NODEFAMILY_MEMBER_LEN);
+}
+
+/**
+ * Parse the member strings in <b>members</b>, returning their canonical
+ * <b>nodefamily_t</b>. Return NULL on error.
+ *
+ * If <b>rsa_id_self</b> is provided, it is a DIGEST_LEN-byte digest
+ * for the router that declared this family: insert it into the
+ * family declaration if it is not there already.
+ *
+ * The <b>flags</b> element is interpreted as in nodefamily_parse().
+ *
+ * If <b>unrecognized</b> is provided, fill it copies of any unrecognized
+ * members. (Note that malformed $hexids are not considered unrecognized.)
+ **/
+nodefamily_t *
+nodefamily_from_members(const smartlist_t *members,
+ const uint8_t *rsa_id_self,
+ unsigned flags,
+ smartlist_t *unrecognized_out)
+{
+ const int n_self = rsa_id_self ? 1 : 0;
+ int n_bad_elements = 0;
+ int n_members = smartlist_len(members) + n_self;
+ nodefamily_t *tmp = nodefamily_alloc(n_members);
+ uint8_t *ptr = NODEFAMILY_MEMBER_PTR(tmp, 0);
+
+ SMARTLIST_FOREACH_BEGIN(members, const char *, cp) {
+ bool bad_element = true;
+ if (is_legal_nickname(cp)) {
+ ptr[0] = NODEFAMILY_BY_NICKNAME;
+ tor_assert(strlen(cp) < DIGEST_LEN); // guaranteed by is_legal_nickname
+ memcpy(ptr+1, cp, strlen(cp));
+ tor_strlower((char*) ptr+1);
+ bad_element = false;
+ } else if (is_legal_hexdigest(cp)) {
+ char digest_buf[DIGEST_LEN];
+ char nn_buf[MAX_NICKNAME_LEN+1];
+ char nn_char=0;
+ if (hex_digest_nickname_decode(cp, digest_buf, &nn_char, nn_buf)==0) {
+ bad_element = false;
+ ptr[0] = NODEFAMILY_BY_RSA_ID;
+ memcpy(ptr+1, digest_buf, DIGEST_LEN);
+ }
+ } else {
+ if (unrecognized_out)
+ smartlist_add_strdup(unrecognized_out, cp);
+ }
+
+ if (bad_element) {
+ const int severity = (flags & NF_WARN_MALFORMED) ? LOG_WARN : LOG_INFO;
+ log_fn(severity, LD_GENERAL,
+ "Bad element %s while parsing a node family.",
+ escaped(cp));
+ ++n_bad_elements;
+ } else {
+ ptr += NODEFAMILY_MEMBER_LEN;
+ }
+ } SMARTLIST_FOREACH_END(cp);
+
+ if (n_bad_elements && (flags & NF_REJECT_MALFORMED))
+ goto err;
+
+ if (rsa_id_self) {
+ /* Add self. */
+ ptr[0] = NODEFAMILY_BY_RSA_ID;
+ memcpy(ptr+1, rsa_id_self, DIGEST_LEN);
+ }
+
+ n_members -= n_bad_elements;
+
+ /* Sort tmp into canonical order. */
+ qsort(tmp->family_members, n_members, NODEFAMILY_MEMBER_LEN,
+ compare_members);
+
+ /* Remove duplicates. */
+ int i;
+ for (i = 0; i < n_members-1; ++i) {
+ uint8_t *thisptr = NODEFAMILY_MEMBER_PTR(tmp, i);
+ uint8_t *nextptr = NODEFAMILY_MEMBER_PTR(tmp, i+1);
+ if (fast_memeq(thisptr, nextptr, NODEFAMILY_MEMBER_LEN)) {
+ memmove(thisptr, nextptr, (n_members-i-1)*NODEFAMILY_MEMBER_LEN);
+ --n_members;
+ --i;
+ }
+ }
+ int n_members_alloc = tmp->n_members;
+ tmp->n_members = n_members;
+
+ /* See if we already allocated this family. */
+ nodefamily_t *found = HT_FIND(nodefamily_map, &the_node_families, tmp);
+ if (found) {
+ /* If we did, great: incref it and return it. */
+ ++found->refcnt;
+ tor_free(tmp);
+ return found;
+ } else {
+ /* If not, insert it into the hashtable. */
+ if (n_members_alloc != n_members) {
+ /* Compact the family if needed */
+ nodefamily_t *tmp2 = nodefamily_alloc(n_members);
+ memcpy(tmp2->family_members, tmp->family_members,
+ n_members * NODEFAMILY_MEMBER_LEN);
+ tor_free(tmp);
+ tmp = tmp2;
+ }
+
+ tmp->refcnt = 1;
+ HT_INSERT(nodefamily_map, &the_node_families, tmp);
+ return tmp;
+ }
+
+ err:
+ tor_free(tmp);
+ return NULL;
+}
+
+/**
+ * Drop our reference to <b>family</b>, freeing it if there are no more
+ * references.
+ */
+void
+nodefamily_free_(nodefamily_t *family)
+{
+ if (family == NULL)
+ return;
+
+ --family->refcnt;
+
+ if (family->refcnt == 0) {
+ HT_REMOVE(nodefamily_map, &the_node_families, family);
+ tor_free(family);
+ }
+}
+
+/**
+ * Return true iff <b>family</b> contains the SHA1 RSA1024 identity
+ * <b>rsa_id</b>.
+ */
+bool
+nodefamily_contains_rsa_id(const nodefamily_t *family,
+ const uint8_t *rsa_id)
+{
+ if (family == NULL)
+ return false;
+
+ unsigned i;
+ for (i = 0; i < family->n_members; ++i) {
+ const uint8_t *ptr = NODEFAMILY_MEMBER_PTR(family, i);
+ if (ptr[0] == NODEFAMILY_BY_RSA_ID &&
+ fast_memeq(ptr+1, rsa_id, DIGEST_LEN)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Return true iff <b>family</b> contains the nickname <b>name</b>.
+ */
+bool
+nodefamily_contains_nickname(const nodefamily_t *family,
+ const char *name)
+{
+ if (family == NULL)
+ return false;
+
+ unsigned i;
+ for (i = 0; i < family->n_members; ++i) {
+ const uint8_t *ptr = NODEFAMILY_MEMBER_PTR(family, i);
+ // note that the strcasecmp() is safe because there is always at least one
+ // NUL in the encoded nickname, because all legal nicknames are less than
+ // DIGEST_LEN bytes long.
+ if (ptr[0] == NODEFAMILY_BY_NICKNAME && !strcasecmp((char*)ptr+1, name)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Return true if <b>family</b> contains the nickname or the RSA ID for
+ * <b>node</b>
+ **/
+bool
+nodefamily_contains_node(const nodefamily_t *family,
+ const node_t *node)
+{
+ return
+ nodefamily_contains_nickname(family, node_get_nickname(node))
+ ||
+ nodefamily_contains_rsa_id(family, node_get_rsa_id_digest(node));
+}
+
+/**
+ * Look up every entry in <b>family</b>, and add add the corresponding
+ * node_t to <b>out</b>.
+ **/
+void
+nodefamily_add_nodes_to_smartlist(const nodefamily_t *family,
+ smartlist_t *out)
+{
+ if (!family)
+ return;
+
+ unsigned i;
+ for (i = 0; i < family->n_members; ++i) {
+ const uint8_t *ptr = NODEFAMILY_MEMBER_PTR(family, i);
+ const node_t *node = NULL;
+ switch (ptr[0]) {
+ case NODEFAMILY_BY_NICKNAME:
+ node = node_get_by_nickname((char*)ptr+1, NNF_NO_WARN_UNNAMED);
+ break;
+ case NODEFAMILY_BY_RSA_ID:
+ node = node_get_by_id((char*)ptr+1);
+ break;
+ default:
+ /* LCOV_EXCL_START */
+ tor_assert_nonfatal_unreached();
+ break;
+ /* LCOV_EXCL_STOP */
+ }
+ if (node)
+ smartlist_add(out, (void *)node);
+ }
+}
+
+/**
+ * Encode <b>family</b> as a space-separated string.
+ */
+char *
+nodefamily_format(const nodefamily_t *family)
+{
+ if (!family)
+ return tor_strdup("");
+
+ unsigned i;
+ smartlist_t *sl = smartlist_new();
+ for (i = 0; i < family->n_members; ++i) {
+ const uint8_t *ptr = NODEFAMILY_MEMBER_PTR(family, i);
+ switch (ptr[0]) {
+ case NODEFAMILY_BY_NICKNAME:
+ smartlist_add_strdup(sl, (char*)ptr+1);
+ break;
+ case NODEFAMILY_BY_RSA_ID: {
+ char buf[HEX_DIGEST_LEN+2];
+ buf[0]='$';
+ base16_encode(buf+1, sizeof(buf)-1, (char*)ptr+1, DIGEST_LEN);
+ tor_strupper(buf);
+ smartlist_add_strdup(sl, buf);
+ break;
+ }
+ default:
+ /* LCOV_EXCL_START */
+ tor_assert_nonfatal_unreached();
+ break;
+ /* LCOV_EXCL_STOP */
+ }
+ }
+
+ char *result = smartlist_join_strings(sl, " ", 0, NULL);
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_free(sl);
+ return result;
+}
+
+/**
+ * Free all storage held in the nodefamily map.
+ **/
+void
+nodefamily_free_all(void)
+{
+ HT_CLEAR(nodefamily_map, &the_node_families);
+}
diff --git a/src/feature/nodelist/nodefamily.h b/src/feature/nodelist/nodefamily.h
new file mode 100644
index 0000000000..16e161ba82
--- /dev/null
+++ b/src/feature/nodelist/nodefamily.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file nodefamily.h
+ * \brief Header file for nodefamily.c.
+ **/
+
+#ifndef TOR_NODEFAMILY_H
+#define TOR_NODEFAMILY_H
+
+#include "lib/malloc/malloc.h"
+#include <stdbool.h>
+
+typedef struct nodefamily_t nodefamily_t;
+struct node_t;
+struct smartlist_t;
+
+#define NF_WARN_MALFORMED (1u<<0)
+#define NF_REJECT_MALFORMED (1u<<1)
+
+nodefamily_t *nodefamily_parse(const char *s,
+ const uint8_t *rsa_id_self,
+ unsigned flags);
+nodefamily_t *nodefamily_from_members(const struct smartlist_t *members,
+ const uint8_t *rsa_id_self,
+ unsigned flags,
+ smartlist_t *unrecognized_out);
+void nodefamily_free_(nodefamily_t *family);
+#define nodefamily_free(family) \
+ FREE_AND_NULL(nodefamily_t, nodefamily_free_, (family))
+
+bool nodefamily_contains_rsa_id(const nodefamily_t *family,
+ const uint8_t *rsa_id);
+bool nodefamily_contains_nickname(const nodefamily_t *family,
+ const char *name);
+bool nodefamily_contains_node(const nodefamily_t *family,
+ const struct node_t *node);
+void nodefamily_add_nodes_to_smartlist(const nodefamily_t *family,
+ struct smartlist_t *out);
+char *nodefamily_format(const nodefamily_t *family);
+char *nodefamily_canonicalize(const char *s, const uint8_t *rsa_id_self,
+ unsigned flags);
+
+void nodefamily_free_all(void);
+
+#endif /* !defined(TOR_NODEFAMILY_H) */
diff --git a/src/feature/nodelist/nodefamily_st.h b/src/feature/nodelist/nodefamily_st.h
new file mode 100644
index 0000000000..c581c917a9
--- /dev/null
+++ b/src/feature/nodelist/nodefamily_st.h
@@ -0,0 +1,53 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file nodefamily_st.h
+ * @brief Compact node-family structure
+ **/
+
+#ifndef TOR_NODEFAMILY_ST_H
+#define TOR_NODEFAMILY_ST_H
+
+#include "orconfig.h"
+#include "ht.h"
+
+struct nodefamily_t {
+ /** Entry for this nodefamily_t within the hashtable. */
+ HT_ENTRY(nodefamily_t) ht_ent;
+ /** Reference count. (The hashtable is not treated as a reference */
+ uint32_t refcnt;
+ /** Number of items encoded in <b>family_members</b>. */
+ uint32_t n_members;
+ /* A byte-array encoding the members of this family. We encode each member
+ * as one byte to indicate whether it's a nickname or a fingerprint, plus
+ * DIGEST_LEN bytes of data. The entries are lexically sorted.
+ */
+ uint8_t family_members[FLEXIBLE_ARRAY_MEMBER];
+};
+
+#define NODEFAMILY_MEMBER_LEN (1+DIGEST_LEN)
+
+/** Tag byte, indicates that the following bytes are a RSA1024 SHA1 ID.
+ */
+#define NODEFAMILY_BY_RSA_ID 0
+/** Tag byte, indicates that the following bytes are a NUL-padded nickname.
+ */
+#define NODEFAMILY_BY_NICKNAME 1
+
+/**
+ * Number of bytes to allocate in the array for a nodefamily_t with N members.
+ **/
+#define NODEFAMILY_ARRAY_SIZE(n) \
+ ((n) * NODEFAMILY_MEMBER_LEN)
+
+/**
+ * Pointer to the i'th member of <b>nf</b>, as encoded.
+ */
+#define NODEFAMILY_MEMBER_PTR(nf, i) \
+ (&((nf)->family_members[(i) * NODEFAMILY_MEMBER_LEN]))
+
+#endif /* !defined(TOR_NODEFAMILY_ST_H) */
diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c
index 9d56f2c3aa..03b158e68d 100644
--- a/src/feature/nodelist/nodelist.c
+++ b/src/feature/nodelist/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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -49,9 +49,9 @@
#include "core/or/protover.h"
#include "feature/client/bridges.h"
#include "feature/client/entrynodes.h"
-#include "feature/control/control.h"
+#include "feature/control/control_events.h"
#include "feature/dirauth/process_descs.h"
-#include "feature/dircache/dirserv.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_common.h"
#include "feature/nodelist/describe.h"
@@ -59,6 +59,7 @@
#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/node_select.h"
+#include "feature/nodelist/nodefamily.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/routerset.h"
@@ -126,7 +127,7 @@ typedef struct nodelist_t {
*
* Whenever a node's routerinfo or microdescriptor is about to change,
* you should remove it from this map with node_remove_from_ed25519_map().
- * Whenever a node's routerinfo or microdescriptor has just chaned,
+ * Whenever a node's routerinfo or microdescriptor has just changed,
* you should add it to this map with node_add_to_ed25519_map().
*/
HT_HEAD(nodelist_ed_map, node_t) nodes_by_ed_id;
@@ -156,9 +157,9 @@ 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_PROTOTYPE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq);
HT_GENERATE2(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq,
- 0.6, tor_reallocarray_, tor_free_)
+ 0.6, tor_reallocarray_, tor_free_);
static inline unsigned int
node_ed_id_hash(const node_t *node)
@@ -173,9 +174,9 @@ node_ed_id_eq(const node_t *node1, const node_t *node2)
}
HT_PROTOTYPE(nodelist_ed_map, node_t, ed_ht_ent, node_ed_id_hash,
- node_ed_id_eq)
+ node_ed_id_eq);
HT_GENERATE2(nodelist_ed_map, node_t, ed_ht_ent, node_ed_id_hash,
- node_ed_id_eq, 0.6, tor_reallocarray_, tor_free_)
+ node_ed_id_eq, 0.6, tor_reallocarray_, tor_free_);
/** The global nodelist. */
static nodelist_t *the_nodelist=NULL;
@@ -450,8 +451,6 @@ node_addrs_changed(node_t *node)
static void
node_add_to_address_set(const node_t *node)
{
- tor_addr_t tmp_addr;
-
if (!the_nodelist ||
!the_nodelist->node_addrs || !the_nodelist->reentry_set)
return;
@@ -464,19 +463,17 @@ node_add_to_address_set(const node_t *node)
* test succeeds and thus the 0 value for the DirPort. */
if (node->rs) {
- if (node->rs->addr) {
- tor_addr_from_ipv4h(&tmp_addr, node->rs->addr);
- nodelist_add_addr_to_address_set(&tmp_addr, node->rs->or_port, 0);
- }
+ if (!tor_addr_is_null(&node->rs->ipv4_addr))
+ nodelist_add_addr_to_address_set(&node->rs->ipv4_addr,
+ node->rs->ipv4_orport, 0);
if (!tor_addr_is_null(&node->rs->ipv6_addr))
nodelist_add_addr_to_address_set(&node->rs->ipv6_addr,
node->rs->ipv6_orport, 0);
}
if (node->ri) {
- if (node->ri->addr) {
- tor_addr_from_ipv4h(&tmp_addr, node->ri->addr);
- nodelist_add_addr_to_address_set(&tmp_addr, node->ri->or_port, 0);
- }
+ if (!tor_addr_is_null(&node->ri->ipv4_addr))
+ nodelist_add_addr_to_address_set(&node->ri->ipv4_addr,
+ node->ri->ipv4_orport, 0);
if (!tor_addr_is_null(&node->ri->ipv6_addr))
nodelist_add_addr_to_address_set(&node->ri->ipv6_addr,
node->ri->ipv6_orport, 0);
@@ -530,7 +527,7 @@ nodelist_add_addr_to_address_set(const tor_addr_t *addr,
uint16_t or_port, uint16_t dir_port)
{
if (BUG(!addr) || tor_addr_is_null(addr) ||
- (!tor_addr_is_v4(addr) && tor_addr_family(addr) != AF_INET6) ||
+ (!tor_addr_is_v4(addr) && !tor_addr_is_v6(addr)) ||
!the_nodelist || !the_nodelist->node_addrs ||
!the_nodelist->reentry_set) {
return;
@@ -690,7 +687,7 @@ get_estimated_address_per_node, (void))
* and grab microdescriptors into nodes as appropriate.
*/
void
-nodelist_set_consensus(networkstatus_t *ns)
+nodelist_set_consensus(const networkstatus_t *ns)
{
const or_options_t *options = get_options();
int authdir = authdir_mode_v3(options);
@@ -702,7 +699,8 @@ nodelist_set_consensus(networkstatus_t *ns)
SMARTLIST_FOREACH(the_nodelist->nodes, node_t *, node,
node->rs = NULL);
- /* Conservatively estimate that every node will have 2 addresses. */
+ /* Conservatively estimate that every node will have 2 addresses (v4 and
+ * v6). Then we add the number of configured trusted authorities we have. */
int estimated_addresses = smartlist_len(ns->routerstatus_list) *
get_estimated_address_per_node();
estimated_addresses += (get_n_authorities(V3_DIRINFO | BRIDGE_DIRINFO) *
@@ -747,7 +745,7 @@ nodelist_set_consensus(networkstatus_t *ns)
node->is_bad_exit = rs->is_bad_exit;
node->is_hs_dir = rs->is_hs_dir;
node->ipv6_preferred = 0;
- if (fascist_firewall_prefer_ipv6_orport(options) &&
+ if (reachable_addr_prefer_ipv6_orport(options) &&
(tor_addr_is_null(&rs->ipv6_addr) == 0 ||
(node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0)))
node->ipv6_preferred = 1;
@@ -1026,7 +1024,7 @@ nodelist_assert_ok(void)
/** Ensure that the nodelist has been created with the most recent consensus.
* If that's not the case, make it so. */
void
-nodelist_ensure_freshness(networkstatus_t *ns)
+nodelist_ensure_freshness(const networkstatus_t *ns)
{
tor_assert(ns);
@@ -1045,7 +1043,7 @@ nodelist_ensure_freshness(networkstatus_t *ns)
/** 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.) */
-MOCK_IMPL(smartlist_t *,
+MOCK_IMPL(const smartlist_t *,
nodelist_get_list,(void))
{
init_nodelist();
@@ -1148,8 +1146,8 @@ node_get_by_nickname,(const char *nickname, unsigned flags))
/** 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)
+MOCK_IMPL(const ed25519_public_key_t *,
+node_get_ed25519_id,(const node_t *node))
{
const ed25519_public_key_t *ri_pk = NULL;
const ed25519_public_key_t *md_pk = NULL;
@@ -1207,7 +1205,7 @@ node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id)
/** Dummy object that should be unreturnable. Used to ensure that
* node_get_protover_summary_flags() always returns non-NULL. */
static const protover_summary_flags_t zero_protover_flags = {
- 0,0,0,0,0,0,0
+ 0,0,0,0,0,0,0,0,0,0,0,0
};
/** Return the protover_summary_flags for a given node. */
@@ -1232,9 +1230,9 @@ node_get_protover_summary_flags(const node_t *node)
* by ed25519 ID during the link handshake. If <b>compatible_with_us</b>,
* it needs to be using a link authentication method that we understand.
* If not, any plausible link authentication method will do. */
-int
-node_supports_ed25519_link_authentication(const node_t *node,
- int compatible_with_us)
+MOCK_IMPL(bool,
+node_supports_ed25519_link_authentication,(const node_t *node,
+ bool compatible_with_us))
{
if (! node_get_ed25519_id(node))
return 0;
@@ -1249,7 +1247,7 @@ node_supports_ed25519_link_authentication(const node_t *node,
/** Return true iff <b>node</b> supports the hidden service directory version
* 3 protocol (proposal 224). */
-int
+bool
node_supports_v3_hsdir(const node_t *node)
{
tor_assert(node);
@@ -1259,7 +1257,7 @@ node_supports_v3_hsdir(const node_t *node)
/** Return true iff <b>node</b> supports ed25519 authentication as an hidden
* service introduction point.*/
-int
+bool
node_supports_ed25519_hs_intro(const node_t *node)
{
tor_assert(node);
@@ -1267,9 +1265,9 @@ node_supports_ed25519_hs_intro(const node_t *node)
return node_get_protover_summary_flags(node)->supports_ed25519_hs_intro;
}
-/** Return true iff <b>node</b> supports to be a rendezvous point for hidden
+/** Return true iff <b>node</b> can be a rendezvous point for hidden
* service version 3 (HSRend=2). */
-int
+bool
node_supports_v3_rendezvous_point(const node_t *node)
{
tor_assert(node);
@@ -1282,6 +1280,67 @@ node_supports_v3_rendezvous_point(const node_t *node)
return node_get_protover_summary_flags(node)->supports_v3_rendezvous_point;
}
+/** Return true iff <b>node</b> supports the DoS ESTABLISH_INTRO cell
+ * extension. */
+bool
+node_supports_establish_intro_dos_extension(const node_t *node)
+{
+ tor_assert(node);
+
+ return node_get_protover_summary_flags(node)->
+ supports_establish_intro_dos_extension;
+}
+
+/** Return true iff <b>node</b> can initiate IPv6 extends (Relay=3).
+ *
+ * This check should only be performed by client path selection code.
+ *
+ * Extending relays should check their own IPv6 support using
+ * router_can_extend_over_ipv6(). Like other extends, they should not verify
+ * the link specifiers in the extend cell against the consensus, because it
+ * may be out of date. */
+bool
+node_supports_initiating_ipv6_extends(const node_t *node)
+{
+ tor_assert(node);
+
+ /* Relays can't initiate an IPv6 extend, unless they have an IPv6 ORPort. */
+ if (!node_has_ipv6_orport(node)) {
+ return 0;
+ }
+
+ /* Initiating relays also need to support the relevant protocol version. */
+ return
+ node_get_protover_summary_flags(node)->supports_initiating_ipv6_extends;
+}
+
+/** Return true iff <b>node</b> can accept IPv6 extends (Relay=2 or Relay=3)
+ * from other relays. If <b>need_canonical_ipv6_conn</b> is true, also check
+ * if the relay supports canonical IPv6 connections (Relay=3 only).
+ *
+ * This check should only be performed by client path selection code.
+ */
+bool
+node_supports_accepting_ipv6_extends(const node_t *node,
+ bool need_canonical_ipv6_conn)
+{
+ tor_assert(node);
+
+ /* Relays can't accept an IPv6 extend, unless they have an IPv6 ORPort. */
+ if (!node_has_ipv6_orport(node)) {
+ return 0;
+ }
+
+ /* Accepting relays also need to support the relevant protocol version. */
+ if (need_canonical_ipv6_conn) {
+ return
+ node_get_protover_summary_flags(node)->supports_canonical_ipv6_conns;
+ } else {
+ return
+ node_get_protover_summary_flags(node)->supports_accepting_ipv6_extends;
+ }
+}
+
/** Return the RSA ID key's SHA1 digest for the provided node. */
const uint8_t *
node_get_rsa_id_digest(const node_t *node)
@@ -1290,6 +1349,102 @@ node_get_rsa_id_digest(const node_t *node)
return (const uint8_t*)node->identity;
}
+/* Returns a new smartlist with all possible link specifiers from node:
+ * - legacy ID is mandatory thus MUST be present in node;
+ * - include ed25519 link specifier if present in the node, and the node
+ * supports ed25519 link authentication, and:
+ * - if direct_conn is true, its link versions are compatible with us,
+ * - if direct_conn is false, regardless of its link versions;
+ * - include IPv4 link specifier, if the primary address is not IPv4, log a
+ * BUG() warning, and return an empty smartlist;
+ * - include IPv6 link specifier if present in the node.
+ *
+ * If node is NULL, returns an empty smartlist.
+ *
+ * The smartlist must be freed using link_specifier_smartlist_free(). */
+MOCK_IMPL(smartlist_t *,
+node_get_link_specifier_smartlist,(const node_t *node, bool direct_conn))
+{
+ link_specifier_t *ls;
+ tor_addr_port_t ap;
+ smartlist_t *lspecs = smartlist_new();
+
+ if (!node)
+ return lspecs;
+
+ /* Get the relay's IPv4 address. */
+ node_get_prim_orport(node, &ap);
+
+ /* We expect the node's primary address to be a valid IPv4 address.
+ * This conforms to the protocol, which requires either an IPv4 or IPv6
+ * address (or both). */
+ if (BUG(!tor_addr_is_v4(&ap.addr)) ||
+ BUG(!tor_addr_port_is_valid_ap(&ap, 0))) {
+ return lspecs;
+ }
+
+ ls = link_specifier_new();
+ link_specifier_set_ls_type(ls, LS_IPV4);
+ link_specifier_set_un_ipv4_addr(ls, tor_addr_to_ipv4h(&ap.addr));
+ link_specifier_set_un_ipv4_port(ls, ap.port);
+ /* Four bytes IPv4 and two bytes port. */
+ link_specifier_set_ls_len(ls, sizeof(ap.addr.addr.in_addr) +
+ sizeof(ap.port));
+ smartlist_add(lspecs, ls);
+
+ /* Legacy ID is mandatory and will always be present in node. */
+ ls = link_specifier_new();
+ link_specifier_set_ls_type(ls, LS_LEGACY_ID);
+ memcpy(link_specifier_getarray_un_legacy_id(ls), node->identity,
+ link_specifier_getlen_un_legacy_id(ls));
+ link_specifier_set_ls_len(ls, link_specifier_getlen_un_legacy_id(ls));
+ smartlist_add(lspecs, ls);
+
+ /* ed25519 ID is only included if the node has it, and the node declares a
+ protocol version that supports ed25519 link authentication.
+ If direct_conn is true, we also require that the node's link version is
+ compatible with us. (Otherwise, we will be sending the ed25519 key
+ to another tor, which may support different link versions.) */
+ if (!ed25519_public_key_is_zero(&node->ed25519_id) &&
+ node_supports_ed25519_link_authentication(node, direct_conn)) {
+ ls = link_specifier_new();
+ link_specifier_set_ls_type(ls, LS_ED25519_ID);
+ memcpy(link_specifier_getarray_un_ed25519_id(ls), &node->ed25519_id,
+ link_specifier_getlen_un_ed25519_id(ls));
+ link_specifier_set_ls_len(ls, link_specifier_getlen_un_ed25519_id(ls));
+ smartlist_add(lspecs, ls);
+ }
+
+ /* Check for IPv6. If so, include it as well. */
+ if (node_has_ipv6_orport(node)) {
+ ls = link_specifier_new();
+ node_get_pref_ipv6_orport(node, &ap);
+ link_specifier_set_ls_type(ls, LS_IPV6);
+ size_t addr_len = link_specifier_getlen_un_ipv6_addr(ls);
+ const uint8_t *in6_addr = tor_addr_to_in6_addr8(&ap.addr);
+ uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(ls);
+ memcpy(ipv6_array, in6_addr, addr_len);
+ link_specifier_set_un_ipv6_port(ls, ap.port);
+ /* Sixteen bytes IPv6 and two bytes port. */
+ link_specifier_set_ls_len(ls, addr_len + sizeof(ap.port));
+ smartlist_add(lspecs, ls);
+ }
+
+ return lspecs;
+}
+
+/* Free a link specifier list. */
+void
+link_specifier_smartlist_free_(smartlist_t *ls_list)
+{
+ if (!ls_list)
+ return;
+
+ SMARTLIST_FOREACH(ls_list, link_specifier_t *, lspec,
+ link_specifier_free(lspec));
+ smartlist_free(ls_list);
+}
+
/** Return the nickname of <b>node</b>, or NULL if we can't find one. */
const char *
node_get_nickname(const node_t *node)
@@ -1429,8 +1584,7 @@ node_exit_policy_rejects_all(const node_t *node)
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);
+ return node->md->policy_is_reject_star;
else
return 1;
}
@@ -1459,32 +1613,14 @@ node_exit_policy_is_exact(const node_t *node, sa_family_t family)
* "addr" is an IPv4 host-order address and port_field is a uint16_t.
* r is typically a routerinfo_t or routerstatus_t.
*/
-#define SL_ADD_NEW_IPV4_AP(r, port_field, sl, valid) \
- STMT_BEGIN \
- if (tor_addr_port_is_valid_ipv4h((r)->addr, (r)->port_field, 0)) { \
- valid = 1; \
- tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); \
- tor_addr_from_ipv4h(&ap->addr, (r)->addr); \
- ap->port = (r)->port_field; \
- smartlist_add((sl), ap); \
- } \
- STMT_END
-
-/* Check if the "addr" and port_field fields from r are a valid non-listening
- * address/port. If so, set valid to true and add a newly allocated
- * tor_addr_port_t containing "addr" and port_field to sl.
- * "addr" is a tor_addr_t and port_field is a uint16_t.
- * r is typically a routerinfo_t or routerstatus_t.
- */
-#define SL_ADD_NEW_IPV6_AP(r, port_field, sl, valid) \
- STMT_BEGIN \
- if (tor_addr_port_is_valid(&(r)->ipv6_addr, (r)->port_field, 0)) { \
- valid = 1; \
- tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); \
- tor_addr_copy(&ap->addr, &(r)->ipv6_addr); \
- ap->port = (r)->port_field; \
- smartlist_add((sl), ap); \
- } \
+#define SL_ADD_NEW_AP(r, addr_field, port_field, sl, valid) \
+ STMT_BEGIN \
+ if (tor_addr_port_is_valid(&(r)->addr_field, (r)->port_field, 0)) { \
+ valid = 1; \
+ tor_addr_port_t *ap = tor_addr_port_new(&(r)->addr_field, \
+ (r)->port_field); \
+ smartlist_add((sl), ap); \
+ } \
STMT_END
/** Return list of tor_addr_port_t with all OR ports (in the sense IP
@@ -1503,33 +1639,32 @@ node_get_all_orports(const node_t *node)
/* Find a valid IPv4 address and port */
if (node->ri != NULL) {
- SL_ADD_NEW_IPV4_AP(node->ri, or_port, sl, valid);
+ SL_ADD_NEW_AP(node->ri, ipv4_addr, ipv4_orport, sl, valid);
}
/* If we didn't find a valid address/port in the ri, try the rs */
if (!valid && node->rs != NULL) {
- SL_ADD_NEW_IPV4_AP(node->rs, or_port, sl, valid);
+ SL_ADD_NEW_AP(node->rs, ipv4_addr, ipv4_orport, sl, valid);
}
/* Find a valid IPv6 address and port */
valid = 0;
if (node->ri != NULL) {
- SL_ADD_NEW_IPV6_AP(node->ri, ipv6_orport, sl, valid);
+ SL_ADD_NEW_AP(node->ri, ipv6_addr, ipv6_orport, sl, valid);
}
if (!valid && node->rs != NULL) {
- SL_ADD_NEW_IPV6_AP(node->rs, ipv6_orport, sl, valid);
+ SL_ADD_NEW_AP(node->rs, ipv6_addr, ipv6_orport, sl, valid);
}
if (!valid && node->md != NULL) {
- SL_ADD_NEW_IPV6_AP(node->md, ipv6_orport, sl, valid);
+ SL_ADD_NEW_AP(node->md, ipv6_addr, ipv6_orport, sl, valid);
}
return sl;
}
-#undef SL_ADD_NEW_IPV4_AP
-#undef SL_ADD_NEW_IPV6_AP
+#undef SL_ADD_NEW_AP
/** Wrapper around node_get_prim_orport for backward
compatibility. */
@@ -1541,21 +1676,20 @@ node_get_addr(const node_t *node, tor_addr_t *addr_out)
tor_addr_copy(addr_out, &ap.addr);
}
-/** Return the host-order IPv4 address for <b>node</b>, or 0 if it doesn't
- * seem to have one. */
-uint32_t
-node_get_prim_addr_ipv4h(const node_t *node)
+/** Return the IPv4 address for <b>node</b>, or NULL if none found. */
+static const tor_addr_t *
+node_get_prim_addr_ipv4(const node_t *node)
{
/* Don't check the ORPort or DirPort, as this function isn't port-specific,
* and the node might have a valid IPv4 address, yet have a zero
* ORPort or DirPort.
*/
- if (node->ri && tor_addr_is_valid_ipv4h(node->ri->addr, 0)) {
- return node->ri->addr;
- } else if (node->rs && tor_addr_is_valid_ipv4h(node->rs->addr, 0)) {
- return node->rs->addr;
+ if (node->ri && tor_addr_is_valid(&node->ri->ipv4_addr, 0)) {
+ return &node->ri->ipv4_addr;
+ } else if (node->rs && tor_addr_is_valid(&node->rs->ipv4_addr, 0)) {
+ return &node->rs->ipv4_addr;
}
- return 0;
+ return NULL;
}
/** Copy a string representation of an IP address for <b>node</b> into
@@ -1563,12 +1697,10 @@ node_get_prim_addr_ipv4h(const node_t *node)
void
node_get_address_string(const node_t *node, char *buf, size_t len)
{
- uint32_t ipv4_addr = node_get_prim_addr_ipv4h(node);
+ const tor_addr_t *ipv4_addr = node_get_prim_addr_ipv4(node);
- if (tor_addr_is_valid_ipv4h(ipv4_addr, 0)) {
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, ipv4_addr);
- tor_addr_to_str(buf, &addr, len, 0);
+ if (ipv4_addr) {
+ tor_addr_to_str(buf, ipv4_addr, len, 0);
} else if (len > 0) {
buf[0] = '\0';
}
@@ -1605,19 +1737,6 @@ node_is_me(const node_t *node)
return router_digest_is_me(node->identity);
}
-/** Return <b>node</b> 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;
-}
-
/* Does this node have a valid IPv6 address?
* Prefer node_has_ipv6_orport() or node_has_ipv6_dirport() for
* checking specific ports. */
@@ -1666,7 +1785,7 @@ node_has_ipv6_dirport(const node_t *node)
* ii) the router has no IPv4 OR address.
*
* If you don't have a node, consider looking it up.
- * If there is no node, use fascist_firewall_prefer_ipv6_orport().
+ * If there is no node, use reachable_addr_prefer_ipv6_orport().
*/
int
node_ipv6_or_preferred(const node_t *node)
@@ -1676,10 +1795,10 @@ node_ipv6_or_preferred(const node_t *node)
node_assert_ok(node);
/* XX/teor - node->ipv6_preferred is set from
- * fascist_firewall_prefer_ipv6_orport() each time the consensus is loaded.
+ * reachable_addr_prefer_ipv6_orport() each time the consensus is loaded.
*/
node_get_prim_orport(node, &ipv4_addr);
- if (!fascist_firewall_use_ipv6(options)) {
+ if (!reachable_addr_use_ipv6(options)) {
return 0;
} else if (node->ipv6_preferred ||
!tor_addr_port_is_valid_ap(&ipv4_addr, 0)) {
@@ -1688,12 +1807,12 @@ node_ipv6_or_preferred(const node_t *node)
return 0;
}
-#define RETURN_IPV4_AP(r, port_field, ap_out) \
- STMT_BEGIN \
- if (r && tor_addr_port_is_valid_ipv4h((r)->addr, (r)->port_field, 0)) { \
- tor_addr_from_ipv4h(&(ap_out)->addr, (r)->addr); \
- (ap_out)->port = (r)->port_field; \
- } \
+#define RETURN_IPV4_AP(r, port_field, ap_out) \
+ STMT_BEGIN \
+ if (r && tor_addr_port_is_valid(&(r)->ipv4_addr, (r)->port_field, 0)) { \
+ tor_addr_copy(&(ap_out)->addr, &(r)->ipv4_addr); \
+ (ap_out)->port = (r)->port_field; \
+ } \
STMT_END
/** Copy the primary (IPv4) OR port (IP address and TCP port) for <b>node</b>
@@ -1712,8 +1831,8 @@ node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
/* Check ri first, because rewrite_node_address_for_bridge() updates
* node->ri with the configured bridge address. */
- RETURN_IPV4_AP(node->ri, or_port, ap_out);
- RETURN_IPV4_AP(node->rs, or_port, ap_out);
+ RETURN_IPV4_AP(node->ri, ipv4_orport, ap_out);
+ RETURN_IPV4_AP(node->rs, ipv4_orport, ap_out);
/* Microdescriptors only have an IPv6 address */
}
@@ -1774,7 +1893,7 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
* or
* ii) our preference is for IPv6 Dir addresses.
*
- * If there is no node, use fascist_firewall_prefer_ipv6_dirport().
+ * If there is no node, use reachable_addr_prefer_ipv6_dirport().
*/
int
node_ipv6_dir_preferred(const node_t *node)
@@ -1783,15 +1902,15 @@ node_ipv6_dir_preferred(const node_t *node)
tor_addr_port_t ipv4_addr;
node_assert_ok(node);
- /* node->ipv6_preferred is set from fascist_firewall_prefer_ipv6_orport(),
+ /* node->ipv6_preferred is set from reachable_addr_prefer_ipv6_orport(),
* so we can't use it to determine DirPort IPv6 preference.
* This means that bridge clients will use IPv4 DirPorts by default.
*/
node_get_prim_dirport(node, &ipv4_addr);
- if (!fascist_firewall_use_ipv6(options)) {
+ if (!reachable_addr_use_ipv6(options)) {
return 0;
} else if (!tor_addr_port_is_valid_ap(&ipv4_addr, 0)
- || fascist_firewall_prefer_ipv6_dirport(get_options())) {
+ || reachable_addr_prefer_ipv6_dirport(get_options())) {
return node_has_ipv6_dirport(node);
}
return 0;
@@ -1813,8 +1932,8 @@ node_get_prim_dirport(const node_t *node, tor_addr_port_t *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);
+ RETURN_IPV4_AP(node->ri, ipv4_dirport, ap_out);
+ RETURN_IPV4_AP(node->rs, ipv4_dirport, ap_out);
/* Microdescriptors only have an IPv6 address */
}
@@ -1851,13 +1970,13 @@ node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out)
/* Assume IPv4 and IPv6 dirports are the same */
if (node->ri && tor_addr_port_is_valid(&node->ri->ipv6_addr,
- node->ri->dir_port, 0)) {
+ node->ri->ipv4_dirport, 0)) {
tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr);
- ap_out->port = node->ri->dir_port;
+ ap_out->port = node->ri->ipv4_dirport;
} else if (node->rs && tor_addr_port_is_valid(&node->rs->ipv6_addr,
- node->rs->dir_port, 0)) {
+ node->rs->ipv4_dirport, 0)) {
tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr);
- ap_out->port = node->rs->dir_port;
+ ap_out->port = node->rs->ipv4_dirport;
} else {
tor_addr_make_null(&ap_out->addr, AF_INET6);
ap_out->port = 0;
@@ -1877,7 +1996,7 @@ microdesc_has_curve25519_onion_key(const microdesc_t *md)
return 0;
}
- if (tor_mem_is_zero((const char*)md->onion_curve25519_pkey->public_key,
+ if (fast_mem_is_zero((const char*)md->onion_curve25519_pkey->public_key,
CURVE25519_PUBKEY_LEN)) {
return 0;
}
@@ -1909,7 +2028,7 @@ node_get_curve25519_onion_key(const node_t *node)
/* Return a newly allocacted RSA onion public key taken from the given node.
*
* Return NULL if node is NULL or no RSA onion public key can be found. It is
- * the caller responsability to free the returned object. */
+ * the caller responsibility to free the returned object. */
crypto_pk_t *
node_get_rsa_onion_key(const node_t *node)
{
@@ -1942,22 +2061,28 @@ node_get_rsa_onion_key(const node_t *node)
void
node_set_country(node_t *node)
{
- tor_addr_t addr = TOR_ADDR_NULL;
+ const tor_addr_t *ipv4_addr = NULL;
/* XXXXipv6 */
if (node->rs)
- tor_addr_from_ipv4h(&addr, node->rs->addr);
+ ipv4_addr = &node->rs->ipv4_addr;
else if (node->ri)
- tor_addr_from_ipv4h(&addr, node->ri->addr);
+ ipv4_addr = &node->ri->ipv4_addr;
- node->country = geoip_get_country_by_addr(&addr);
+ /* IPv4 is mandatory for a relay so this should not happen unless we are
+ * attempting to set the country code on a node without a descriptor. */
+ if (BUG(!ipv4_addr)) {
+ node->country = -1;
+ return;
+ }
+ node->country = geoip_get_country_by_addr(ipv4_addr);
}
/** Set the country code of all routers in the routerlist. */
void
nodelist_refresh_countries(void)
{
- smartlist_t *nodes = nodelist_get_list();
+ const smartlist_t *nodes = nodelist_get_list();
SMARTLIST_FOREACH(nodes, node_t *, node,
node_set_country(node));
}
@@ -1965,9 +2090,12 @@ 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 */
int
-addrs_in_same_network_family(const tor_addr_t *a1,
+router_addrs_in_same_network(const tor_addr_t *a1,
const tor_addr_t *a2)
{
+ if (tor_addr_is_null(a1) || tor_addr_is_null(a2))
+ return 0;
+
switch (tor_addr_family(a1)) {
case AF_INET:
return 0 == tor_addr_compare_masked(a1, a2, 16, CMP_SEMANTIC);
@@ -1983,7 +2111,7 @@ addrs_in_same_network_family(const tor_addr_t *a1,
* (case-insensitive), or if <b>node's</b> identity key digest
* matches a hexadecimal value stored in <b>nickname</b>. Return
* false otherwise. */
-static int
+STATIC int
node_nickname_matches(const node_t *node, const char *nickname)
{
const char *n = node_get_nickname(node);
@@ -1995,7 +2123,7 @@ node_nickname_matches(const node_t *node, const char *nickname)
}
/** Return true iff <b>node</b> is named by some nickname in <b>lst</b>. */
-static inline int
+STATIC int
node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node)
{
if (!lst) return 0;
@@ -2006,6 +2134,61 @@ node_in_nickname_smartlist(const smartlist_t *lst, const node_t *node)
return 0;
}
+/** Return true iff n1's declared family contains n2. */
+STATIC int
+node_family_contains(const node_t *n1, const node_t *n2)
+{
+ if (n1->ri && n1->ri->declared_family) {
+ return node_in_nickname_smartlist(n1->ri->declared_family, n2);
+ } else if (n1->md) {
+ return nodefamily_contains_node(n1->md->family, n2);
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Return true iff <b>node</b> has declared a nonempty family.
+ **/
+STATIC bool
+node_has_declared_family(const node_t *node)
+{
+ if (node->ri && node->ri->declared_family &&
+ smartlist_len(node->ri->declared_family)) {
+ return true;
+ }
+
+ if (node->md && node->md->family) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Add to <b>out</b> every node_t that is listed by <b>node</b> as being in
+ * its family. (Note that these nodes are not in node's family unless they
+ * also agree that node is in their family.)
+ **/
+STATIC void
+node_lookup_declared_family(smartlist_t *out, const node_t *node)
+{
+ if (node->ri && node->ri->declared_family &&
+ smartlist_len(node->ri->declared_family)) {
+ SMARTLIST_FOREACH_BEGIN(node->ri->declared_family, const char *, name) {
+ const node_t *n2 = node_get_by_nickname(name, NNF_NO_WARN_UNNAMED);
+ if (n2) {
+ smartlist_add(out, (node_t *)n2);
+ }
+ } SMARTLIST_FOREACH_END(name);
+ return;
+ }
+
+ if (node->md && node->md->family) {
+ nodefamily_add_nodes_to_smartlist(node->md->family, out);
+ }
+}
+
/** Return true iff r1 and r2 are in the same family, but not the same
* router. */
int
@@ -2018,19 +2201,20 @@ nodes_in_same_family(const node_t *node1, const node_t *node2)
tor_addr_t a1, a2;
node_get_addr(node1, &a1);
node_get_addr(node2, &a2);
- if (addrs_in_same_network_family(&a1, &a2))
+
+ tor_addr_port_t ap6_1, ap6_2;
+ node_get_pref_ipv6_orport(node1, &ap6_1);
+ node_get_pref_ipv6_orport(node2, &ap6_2);
+
+ if (router_addrs_in_same_network(&a1, &a2) ||
+ router_addrs_in_same_network(&ap6_1.addr, &ap6_2.addr))
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;
+ if (node_family_contains(node1, node2) &&
+ node_family_contains(node2, node1)) {
+ return 1;
}
/* Are they in the same family because the user says they are? */
@@ -2058,13 +2242,10 @@ 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);
@@ -2075,35 +2256,35 @@ nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
/* First, add any nodes with similar network addresses. */
if (options->EnforceDistinctSubnets) {
tor_addr_t node_addr;
+ tor_addr_port_t node_ap6;
node_get_addr(node, &node_addr);
+ node_get_pref_ipv6_orport(node, &node_ap6);
SMARTLIST_FOREACH_BEGIN(all_nodes, const node_t *, node2) {
tor_addr_t a;
+ tor_addr_port_t ap6;
node_get_addr(node2, &a);
- if (addrs_in_same_network_family(&a, &node_addr))
+ node_get_pref_ipv6_orport(node2, &ap6);
+ if (router_addrs_in_same_network(&a, &node_addr) ||
+ router_addrs_in_same_network(&ap6.addr, &node_ap6.addr))
smartlist_add(sl, (void*)node2);
} SMARTLIST_FOREACH_END(node2);
}
- /* Now, add all nodes in the declared_family of this node, if they
+ /* 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) {
+ if (node_has_declared_family(node)) {
+ smartlist_t *declared_family = smartlist_new();
+ node_lookup_declared_family(declared_family, node);
+
/* 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, NNF_NO_WARN_UNNAMED)))
- 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);
+ SMARTLIST_FOREACH_BEGIN(declared_family, const node_t *, node2) {
+ if (node_family_contains(node2, node)) {
+ smartlist_add(sl, (void*)node2);
+ }
+ } SMARTLIST_FOREACH_END(node2);
+ smartlist_free(declared_family);
}
/* If the user declared any families locally, honor those too. */
@@ -2125,21 +2306,18 @@ nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
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;
+ tor_addr_t ipv4_addr;
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);
+ tor_addr_from_in(&ipv4_addr, &in);
SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, {
- if (node_get_addr_ipv4h(node) == addr &&
+ if (tor_addr_eq(node_get_prim_addr_ipv4(node), &ipv4_addr) &&
node->is_running &&
- compare_tor_addr_to_node_policy(&a, port, node) ==
+ compare_tor_addr_to_node_policy(&ipv4_addr, port, node) ==
ADDR_POLICY_ACCEPTED &&
!routerset_contains_node(options->ExcludeExitNodesUnion_, node))
return node;
@@ -2408,7 +2586,7 @@ 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, now, NULL,
+ mid, consensus, now, options->MiddleNodes,
USABLE_DESCRIPTOR_ALL);
log_debug(LD_NET,
"%s: %d present, %d usable",
@@ -2610,7 +2788,7 @@ count_loading_descriptors_progress(void)
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 -
+ (fraction*(BOOTSTRAP_STATUS_ENOUGH_DIRINFO-1 -
BOOTSTRAP_STATUS_LOADING_DESCRIPTORS));
}
@@ -2697,14 +2875,14 @@ update_router_have_minimum_dir_info(void)
/* If paths have just become available in this update. */
if (res && !have_min_dir_info) {
control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO");
- control_event_boot_dir(BOOTSTRAP_STATUS_CONN_OR, 0);
+ control_event_boot_dir(BOOTSTRAP_STATUS_ENOUGH_DIRINFO, 0);
log_info(LD_DIR,
"We now have enough directory information to build circuits.");
}
/* If paths have just become unavailable in this update. */
if (!res && have_min_dir_info) {
- int quiet = directory_too_idle_to_fetch_descriptors(options, now);
+ int quiet = dirclient_too_idle_to_fetch_descriptors(options, now);
tor_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);
diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h
index bc09731ce2..44b8918b06 100644
--- a/src/feature/nodelist/nodelist.h
+++ b/src/feature/nodelist/nodelist.h
@@ -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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -32,8 +32,8 @@ const node_t *node_get_by_hex_id(const char *identity_digest,
unsigned flags);
node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out);
node_t *nodelist_add_microdesc(microdesc_t *md);
-void nodelist_set_consensus(networkstatus_t *ns);
-void nodelist_ensure_freshness(networkstatus_t *ns);
+void nodelist_set_consensus(const networkstatus_t *ns);
+void nodelist_ensure_freshness(const networkstatus_t *ns);
int nodelist_probably_contains_address(const tor_addr_t *addr);
bool nodelist_reentry_contains(const tor_addr_t *addr, uint16_t port);
void nodelist_add_addr_to_address_set(const tor_addr_t *addr,
@@ -68,19 +68,29 @@ smartlist_t *node_get_all_orports(const node_t *node);
int node_allows_single_hop_exits(const node_t *node);
const char *node_get_nickname(const node_t *node);
const char *node_get_platform(const node_t *node);
-uint32_t node_get_prim_addr_ipv4h(const node_t *node);
void node_get_address_string(const node_t *node, char *cp, size_t len);
long node_get_declared_uptime(const node_t *node);
-const smartlist_t *node_get_declared_family(const node_t *node);
-const struct ed25519_public_key_t *node_get_ed25519_id(const node_t *node);
+MOCK_DECL(const struct ed25519_public_key_t *,node_get_ed25519_id,
+ (const node_t *node));
int node_ed25519_id_matches(const node_t *node,
const struct ed25519_public_key_t *id);
-int node_supports_ed25519_link_authentication(const node_t *node,
- int compatible_with_us);
-int node_supports_v3_hsdir(const node_t *node);
-int node_supports_ed25519_hs_intro(const node_t *node);
-int node_supports_v3_rendezvous_point(const node_t *node);
+MOCK_DECL(bool,node_supports_ed25519_link_authentication,
+ (const node_t *node,
+ bool compatible_with_us));
+bool node_supports_v3_hsdir(const node_t *node);
+bool node_supports_ed25519_hs_intro(const node_t *node);
+bool node_supports_v3_rendezvous_point(const node_t *node);
+bool node_supports_establish_intro_dos_extension(const node_t *node);
+bool node_supports_initiating_ipv6_extends(const node_t *node);
+bool node_supports_accepting_ipv6_extends(const node_t *node,
+ bool need_canonical_ipv6_conn);
+
const uint8_t *node_get_rsa_id_digest(const node_t *node);
+MOCK_DECL(smartlist_t *,node_get_link_specifier_smartlist,(const node_t *node,
+ bool direct_conn));
+void link_specifier_smartlist_free_(smartlist_t *ls_list);
+#define link_specifier_smartlist_free(ls_list) \
+ FREE_AND_NULL(smartlist_t, link_specifier_smartlist_free_, (ls_list))
int node_has_ipv6_addr(const node_t *node);
int node_has_ipv6_orport(const node_t *node);
@@ -100,11 +110,10 @@ const struct curve25519_public_key_t *node_get_curve25519_onion_key(
const node_t *node);
crypto_pk_t *node_get_rsa_onion_key(const node_t *node);
-MOCK_DECL(smartlist_t *, nodelist_get_list, (void));
+MOCK_DECL(const smartlist_t *, nodelist_get_list, (void));
/* Temporary during transition to multiple addresses. */
void node_get_addr(const node_t *node, tor_addr_t *addr_out);
-#define node_get_addr_ipv4h(n) node_get_prim_addr_ipv4h((n))
void nodelist_refresh_countries(void);
void node_set_country(node_t *node);
@@ -118,7 +127,7 @@ int node_is_unreliable(const node_t *router, int need_uptime,
int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
int need_uptime);
void router_set_status(const char *digest, int up);
-int addrs_in_same_network_family(const tor_addr_t *a1,
+int router_addrs_in_same_network(const tor_addr_t *a1,
const tor_addr_t *a2);
/** router_have_minimum_dir_info tests to see if we have enough
@@ -158,10 +167,16 @@ int count_loading_descriptors_progress(void);
#ifdef NODELIST_PRIVATE
+STATIC int node_nickname_matches(const node_t *node, const char *nickname);
+STATIC int node_in_nickname_smartlist(const smartlist_t *lst,
+ const node_t *node);
+STATIC int node_family_contains(const node_t *n1, const node_t *n2);
+STATIC bool node_has_declared_family(const node_t *node);
+STATIC void node_lookup_declared_family(smartlist_t *out, const node_t *node);
+
#ifdef TOR_UNIT_TESTS
-STATIC void
-node_set_hsdir_index(node_t *node, const networkstatus_t *ns);
+STATIC void node_set_hsdir_index(node_t *node, const networkstatus_t *ns);
#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/feature/nodelist/routerinfo.c b/src/feature/nodelist/routerinfo.c
index 975b503615..eb8eb74daa 100644
--- a/src/feature/nodelist/routerinfo.c
+++ b/src/feature/nodelist/routerinfo.c
@@ -1,33 +1,62 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file routerinfo.c
+ * @brief Manipulate full router descriptors.
+ **/
+
#include "core/or/or.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerinfo.h"
+#include "feature/nodelist/torcert.h"
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerinfo_st.h"
-/** Copy the primary (IPv4) OR port (IP address and TCP port) for
- * <b>router</b> into *<b>ap_out</b>. */
-void
-router_get_prim_orport(const routerinfo_t *router, tor_addr_port_t *ap_out)
+/** Copy the OR port (IP address and TCP port) for <b>router</b> and
+ * <b>family</b> into *<b>ap_out</b>.
+ *
+ * If the requested ORPort does not exist, sets *<b>ap_out</b> to the null
+ * address and port, and returns -1. Otherwise, returns 0. */
+int
+router_get_orport(const routerinfo_t *router,
+ tor_addr_port_t *ap_out,
+ int family)
{
tor_assert(ap_out != NULL);
- tor_addr_from_ipv4h(&ap_out->addr, router->addr);
- ap_out->port = router->or_port;
+ if (family == AF_INET) {
+ tor_addr_copy(&ap_out->addr, &router->ipv4_addr);
+ ap_out->port = router->ipv4_orport;
+ return 0;
+ } else if (family == AF_INET6) {
+ /* IPv6 addresses are optional, so check if it is valid. */
+ if (tor_addr_port_is_valid(&router->ipv6_addr, router->ipv6_orport, 0)) {
+ tor_addr_copy(&ap_out->addr, &router->ipv6_addr);
+ ap_out->port = router->ipv6_orport;
+ return 0;
+ } else {
+ tor_addr_port_make_null_ap(ap_out, AF_INET6);
+ return -1;
+ }
+ } else {
+ /* Unsupported address family */
+ tor_assert_nonfatal_unreached();
+ tor_addr_port_make_null_ap(ap_out, AF_UNSPEC);
+ return -1;
+ }
}
int
router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport)
{
return
- (tor_addr_eq_ipv4h(&orport->addr, router->addr) &&
- orport->port == router->or_port) ||
+ (tor_addr_eq(&orport->addr, &router->ipv4_addr) &&
+ orport->port == router->ipv4_orport) ||
(tor_addr_eq(&orport->addr, &router->ipv6_addr) &&
orport->port == router->ipv6_orport);
}
@@ -47,6 +76,21 @@ router_get_all_orports(const routerinfo_t *ri)
return node_get_all_orports(&fake_node);
}
+/** Return the Ed25519 identity key for this routerinfo, or NULL if it
+ * doesn't have one. */
+const ed25519_public_key_t *
+routerinfo_get_ed25519_id(const routerinfo_t *ri)
+{
+ if (BUG(! ri))
+ return NULL;
+
+ const tor_cert_t *cert = ri->cache_info.signing_key_cert;
+ if (cert && ! ed25519_public_key_is_zero(&cert->signing_key))
+ return &cert->signing_key;
+ else
+ return NULL;
+}
+
/** Given a router purpose, convert it to a string. Don't call this on
* ROUTER_PURPOSE_UNKNOWN: The whole point of that value is that we don't
* know its string representation. */
diff --git a/src/feature/nodelist/routerinfo.h b/src/feature/nodelist/routerinfo.h
index bfa28c7754..bc78beb402 100644
--- a/src/feature/nodelist/routerinfo.h
+++ b/src/feature/nodelist/routerinfo.h
@@ -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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,16 +12,19 @@
#ifndef TOR_ROUTERINFO_H
#define TOR_ROUTERINFO_H
-void router_get_prim_orport(const routerinfo_t *router,
- tor_addr_port_t *addr_port_out);
+int router_get_orport(const routerinfo_t *router,
+ tor_addr_port_t *addr_port_out,
+ int family);
int router_has_orport(const routerinfo_t *router,
const tor_addr_port_t *orport);
-void router_get_verbose_nickname(char *buf, const routerinfo_t *router);
+struct ed25519_public_key_t;
+const struct ed25519_public_key_t *routerinfo_get_ed25519_id(
+ const routerinfo_t *ri);
smartlist_t *router_get_all_orports(const routerinfo_t *ri);
const char *router_purpose_to_string(uint8_t p);
uint8_t router_purpose_from_string(const char *s);
-#endif
+#endif /* !defined(TOR_ROUTERINFO_H) */
diff --git a/src/feature/nodelist/routerinfo_st.h b/src/feature/nodelist/routerinfo_st.h
index 59656818c1..7197c88c18 100644
--- a/src/feature/nodelist/routerinfo_st.h
+++ b/src/feature/nodelist/routerinfo_st.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file routerinfo_st.h
+ * @brief Router descriptor structure.
+ **/
+
#ifndef ROUTERINFO_ST_H
#define ROUTERINFO_ST_H
@@ -16,14 +21,12 @@ struct routerinfo_t {
signed_descriptor_t cache_info;
char *nickname; /**< Human-readable OR name. */
- uint32_t addr; /**< IPv4 address of OR, in host order. */
- uint16_t or_port; /**< Port for TLS connections. */
- uint16_t dir_port; /**< Port for HTTP directory connections. */
+ /** A router's IPv4 address. */
+ tor_addr_t ipv4_addr;
+ uint16_t ipv4_orport;
+ uint16_t ipv4_dirport;
/** A router's IPv6 address, if it has one. */
- /* XXXXX187 Actually these should probably be part of a list of addresses,
- * not just a special case. Use abstractions to access these; don't do it
- * directly. */
tor_addr_t ipv6_addr;
uint16_t ipv6_orport;
@@ -112,4 +115,4 @@ struct routerinfo_t {
uint8_t purpose;
};
-#endif
+#endif /* !defined(ROUTERINFO_ST_H) */
diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c
index c7fa868929..a1a348edb9 100644
--- a/src/feature/nodelist/routerlist.c
+++ b/src/feature/nodelist/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-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -65,14 +65,18 @@
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
+#include "core/or/circuitlist.h"
+#include "core/or/circuituse.h"
+#include "core/or/extendinfo.h"
#include "core/or/policies.h"
#include "feature/client/bridges.h"
-#include "feature/control/control.h"
+#include "feature/control/control_events.h"
#include "feature/dirauth/authmode.h"
#include "feature/dirauth/process_descs.h"
#include "feature/dirauth/reachability.h"
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dirclient.h"
+#include "feature/dirclient/dirclient_modes.h"
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/directory.h"
#include "feature/nodelist/authcert.h"
@@ -88,6 +92,7 @@
#include "feature/nodelist/routerset.h"
#include "feature/nodelist/torcert.h"
#include "feature/relay/routermode.h"
+#include "feature/relay/relay_find_addr.h"
#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -116,9 +121,9 @@
/* Typed wrappers for different digestmap types; used to avoid type
* confusion. */
-DECLARE_TYPED_DIGESTMAP_FNS(sdmap_, digest_sd_map_t, signed_descriptor_t)
-DECLARE_TYPED_DIGESTMAP_FNS(rimap_, digest_ri_map_t, routerinfo_t)
-DECLARE_TYPED_DIGESTMAP_FNS(eimap_, digest_ei_map_t, extrainfo_t)
+DECLARE_TYPED_DIGESTMAP_FNS(sdmap, digest_sd_map_t, signed_descriptor_t)
+DECLARE_TYPED_DIGESTMAP_FNS(rimap, digest_ri_map_t, routerinfo_t)
+DECLARE_TYPED_DIGESTMAP_FNS(eimap, digest_ei_map_t, extrainfo_t)
#define SDMAP_FOREACH(map, keyvar, valvar) \
DIGESTMAP_FOREACH(sdmap_to_digestmap(map), keyvar, signed_descriptor_t *, \
valvar)
@@ -135,8 +140,6 @@ static int signed_desc_digest_is_recognized(signed_descriptor_t *desc);
static const char *signed_descriptor_get_body_impl(
const signed_descriptor_t *desc,
int with_annotations);
-static void launch_dummy_descriptor_download_as_needed(time_t now,
- const or_options_t *options);
/****************************************************************************/
@@ -160,7 +163,7 @@ static time_t last_descriptor_download_attempted = 0;
*
* From time to time, we replace "cached-descriptors" with a new file
* containing only the live, non-superseded descriptors, and clear
- * cached-routers.new.
+ * cached-descriptors.new.
*
* On startup, we read both files.
*/
@@ -464,11 +467,20 @@ router_reload_router_list(void)
return 0;
}
-/* When iterating through the routerlist, can OR address/port preference
- * and reachability checks be skipped?
+/* When selecting a router for a direct connection, can OR address/port
+ * preference and reachability checks be skipped?
+ *
+ * Servers never check ReachableAddresses or ClientPreferIPv6. Returns
+ * true for servers.
+ *
+ * Otherwise, if <b>try_ip_pref</b> is true, returns false. Used to make
+ * clients check ClientPreferIPv6, even if ReachableAddresses is not set.
+ * Finally, return true if ReachableAddresses is set.
*/
int
-router_skip_or_reachability(const or_options_t *options, int try_ip_pref)
+router_or_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref)
{
/* Servers always have and prefer IPv4.
* And if clients are checking against the firewall for reachability only,
@@ -476,11 +488,15 @@ router_skip_or_reachability(const or_options_t *options, int try_ip_pref)
return server_mode(options) || (!try_ip_pref && !firewall_is_fascist_or());
}
-/* When iterating through the routerlist, can Dir address/port preference
+/* When selecting a router for a direct connection, can Dir address/port
* and reachability checks be skipped?
+ *
+ * This function is obsolete, because clients only use ORPorts.
*/
int
-router_skip_dir_reachability(const or_options_t *options, int try_ip_pref)
+router_dir_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref)
{
/* Servers always have and prefer IPv4.
* And if clients are checking against the firewall for reachability only,
@@ -492,45 +508,115 @@ router_skip_dir_reachability(const or_options_t *options, int try_ip_pref)
int
routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2)
{
- return r1->addr == r2->addr && r1->or_port == r2->or_port &&
+ return tor_addr_eq(&r1->ipv4_addr, &r2->ipv4_addr) &&
+ r1->ipv4_orport == r2->ipv4_orport &&
tor_addr_eq(&r1->ipv6_addr, &r2->ipv6_addr) &&
r1->ipv6_orport == r2->ipv6_orport;
}
+/* Returns true if <b>node</b> can be chosen based on <b>flags</b>.
+ *
+ * The following conditions are applied to all nodes:
+ * - is running;
+ * - is valid;
+ * - supports EXTEND2 cells;
+ * - has an ntor circuit crypto key; and
+ * - does not allow single-hop exits.
+ *
+ * If the node has a routerinfo, we're checking for a direct connection, and
+ * we're using bridges, the following condition is applied:
+ * - has a bridge-purpose routerinfo;
+ * and for all other nodes:
+ * - has a general-purpose routerinfo (or no routerinfo).
+ *
+ * Nodes that don't have a routerinfo must be general-purpose nodes, because
+ * routerstatuses and microdescriptors only come via consensuses.
+ *
+ * The <b>flags</b> check that <b>node</b>:
+ * - <b>CRN_NEED_UPTIME</b>: has more than a minimum uptime;
+ * - <b>CRN_NEED_CAPACITY</b>: has more than a minimum capacity;
+ * - <b>CRN_NEED_GUARD</b>: is a Guard;
+ * - <b>CRN_NEED_DESC</b>: has a routerinfo or microdescriptor -- that is,
+ * enough info to be used to build a circuit;
+ * - <b>CRN_DIRECT_CONN</b>: is suitable for direct connections. Checks
+ * for the relevant descriptors. Checks the address
+ * against ReachableAddresses, ClientUseIPv4 0, and
+ * reachable_addr_use_ipv6() == 0);
+ * - <b>CRN_PREF_ADDR</b>: if we are connecting directly to the node, it has
+ * an address that is preferred by the
+ * ClientPreferIPv6ORPort setting;
+ * - <b>CRN_RENDEZVOUS_V3</b>: can become a v3 onion service rendezvous point;
+ * - <b>CRN_INITIATE_IPV6_EXTEND</b>: can initiate IPv6 extends.
+ */
+bool
+router_can_choose_node(const node_t *node, int flags)
+{
+ /* The full set of flags used for node selection. */
+ const bool need_uptime = (flags & CRN_NEED_UPTIME) != 0;
+ const bool need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
+ const bool need_guard = (flags & CRN_NEED_GUARD) != 0;
+ const bool need_desc = (flags & CRN_NEED_DESC) != 0;
+ const bool pref_addr = (flags & CRN_PREF_ADDR) != 0;
+ const bool direct_conn = (flags & CRN_DIRECT_CONN) != 0;
+ const bool rendezvous_v3 = (flags & CRN_RENDEZVOUS_V3) != 0;
+ const bool initiate_ipv6_extend = (flags & CRN_INITIATE_IPV6_EXTEND) != 0;
+
+ const or_options_t *options = get_options();
+ const bool check_reach =
+ !router_or_conn_should_skip_reachable_address_check(options, pref_addr);
+ const bool direct_bridge = direct_conn && options->UseBridges;
+
+ if (!node->is_running || !node->is_valid)
+ return false;
+ if (need_desc && !node_has_preferred_descriptor(node, direct_conn))
+ return false;
+ if (node->ri) {
+ if (direct_bridge && node->ri->purpose != ROUTER_PURPOSE_BRIDGE)
+ return false;
+ else if (node->ri->purpose != ROUTER_PURPOSE_GENERAL)
+ return false;
+ }
+ if (node_is_unreliable(node, need_uptime, need_capacity, need_guard))
+ return false;
+ /* Don't choose nodes if we are certain they can't do EXTEND2 cells */
+ if (node->rs && !routerstatus_version_supports_extend2_cells(node->rs, 1))
+ return false;
+ /* Don't choose nodes if we are certain they can't do ntor. */
+ if ((node->ri || node->md) && !node_has_curve25519_onion_key(node))
+ return false;
+ /* 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. */
+ if (node_allows_single_hop_exits(node))
+ return false;
+ /* Exclude relays that can not become a rendezvous for a hidden service
+ * version 3. */
+ if (rendezvous_v3 &&
+ !node_supports_v3_rendezvous_point(node))
+ return false;
+ /* Choose a node with an OR address that matches the firewall rules */
+ if (direct_conn && check_reach &&
+ !reachable_addr_allows_node(node,
+ FIREWALL_OR_CONNECTION,
+ pref_addr))
+ return false;
+ if (initiate_ipv6_extend && !node_supports_initiating_ipv6_extends(node))
+ return false;
+
+ return true;
+}
+
/** Add every suitable node from our nodelist to <b>sl</b>, so that
- * we can pick a node for a circuit.
+ * we can pick a node for a circuit based on <b>flags</b>.
+ *
+ * See router_can_choose_node() for details of <b>flags</b>.
*/
void
-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 */
+router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags)
+{
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
- if (!node->is_running || !node->is_valid)
- continue;
- if (need_desc && !node_has_preferred_descriptor(node, direct_conn))
+ if (!router_can_choose_node(node, flags))
continue;
- if (node->ri && node->ri->purpose != ROUTER_PURPOSE_GENERAL)
- continue;
- if (node_is_unreliable(node, need_uptime, need_capacity, need_guard))
- continue;
- /* Don't choose nodes if we are certain they can't do EXTEND2 cells */
- if (node->rs && !routerstatus_version_supports_extend2_cells(node->rs, 1))
- continue;
- /* Don't choose nodes if we are certain they can't do ntor. */
- if ((node->ri || node->md) && !node_has_curve25519_onion_key(node))
- continue;
- /* Choose a node with an OR address that matches the firewall rules */
- if (direct_conn && check_reach &&
- !fascist_firewall_allows_node(node,
- FIREWALL_OR_CONNECTION,
- pref_addr))
- continue;
-
smartlist_add(sl, (void *)node);
} SMARTLIST_FOREACH_END(node);
}
@@ -1463,12 +1549,13 @@ router_descriptor_is_older_than,(const routerinfo_t *router, int seconds))
}
/** Add <b>router</b> to the routerlist, if we don't already have it. Replace
- * older entries (if any) with the same key. Note: Callers should not hold
- * their pointers to <b>router</b> if this function fails; <b>router</b>
- * will either be inserted into the routerlist or freed. Similarly, even
- * if this call succeeds, they should not hold their pointers to
- * <b>router</b> after subsequent calls with other routerinfo's -- they
- * might cause the original routerinfo to get freed.
+ * older entries (if any) with the same key.
+ *
+ * Note: Callers should not hold their pointers to <b>router</b> if this
+ * function fails; <b>router</b> will either be inserted into the routerlist or
+ * freed. Similarly, even if this call succeeds, they should not hold their
+ * pointers to <b>router</b> after subsequent calls with other routerinfo's --
+ * they might cause the original routerinfo to get freed.
*
* Returns the status for the operation. Might set *<b>msg</b> if it wants
* the poster of the router to know something.
@@ -1930,6 +2017,8 @@ routerlist_remove_old_routers(void)
void
routerlist_descriptors_added(smartlist_t *sl, int from_cache)
{
+ // XXXX use pubsub mechanism here.
+
tor_assert(sl);
control_event_descriptors_changed(sl);
SMARTLIST_FOREACH_BEGIN(sl, routerinfo_t *, ri) {
@@ -2218,7 +2307,6 @@ update_all_descriptor_downloads(time_t now)
return;
update_router_descriptor_downloads(now);
update_microdesc_downloads(now);
- launch_dummy_descriptor_download_as_needed(now, get_options());
}
/** Clear all our timeouts for fetching v3 directory stuff, and then
@@ -2405,7 +2493,7 @@ max_dl_per_request(const or_options_t *options, int purpose)
}
/* If we're going to tunnel our connections, we can ask for a lot more
* in a request. */
- if (directory_must_use_begindir(options)) {
+ if (dirclient_must_use_begindir(options)) {
max = 500;
}
return max;
@@ -2448,7 +2536,7 @@ launch_descriptor_downloads(int purpose,
if (!n_downloadable)
return;
- if (!directory_fetches_dir_info_early(options)) {
+ if (!dirclient_fetches_dir_info_early(options)) {
if (n_downloadable >= MAX_DL_TO_DELAY) {
log_debug(LD_DIR,
"There are enough downloadable %ss to launch requests.",
@@ -2539,7 +2627,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
int n_delayed=0, n_have=0, n_would_reject=0, n_wouldnt_use=0,
n_inprogress=0, n_in_oldrouters=0;
- if (directory_too_idle_to_fetch_descriptors(options, now))
+ if (dirclient_too_idle_to_fetch_descriptors(options, now))
goto done;
if (!consensus)
goto done;
@@ -2559,8 +2647,15 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
map = digestmap_new();
list_pending_descriptor_downloads(map, 0);
SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, void *, rsp) {
- routerstatus_t *rs =
- is_vote ? &(((vote_routerstatus_t *)rsp)->status) : rsp;
+ routerstatus_t *rs;
+ vote_routerstatus_t *vrs;
+ if (is_vote) {
+ rs = &(((vote_routerstatus_t *)rsp)->status);
+ vrs = rsp;
+ } else {
+ rs = rsp;
+ vrs = NULL;
+ }
signed_descriptor_t *sd;
if ((sd = router_get_by_descriptor_digest(rs->descriptor_digest))) {
const routerinfo_t *ri;
@@ -2585,7 +2680,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
++n_delayed; /* Not ready for retry. */
continue;
}
- if (authdir && dirserv_would_reject_router(rs)) {
+ if (authdir && is_vote && dirserv_would_reject_router(rs, vrs)) {
++n_would_reject;
continue; /* We would throw it out immediately. */
}
@@ -2665,39 +2760,6 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
smartlist_free(no_longer_old);
}
-/** How often should we launch a server/authority request to be sure of getting
- * a guess for our IP? */
-/*XXXX+ this info should come from netinfo cells or something, or we should
- * do this only when we aren't seeing incoming data. see bug 652. */
-#define DUMMY_DOWNLOAD_INTERVAL (20*60)
-
-/** As needed, launch a dummy router descriptor fetch to see if our
- * address has changed. */
-static void
-launch_dummy_descriptor_download_as_needed(time_t now,
- const or_options_t *options)
-{
- static time_t last_dummy_download = 0;
- /* XXXX+ we could be smarter here; see notes on bug 652. */
- /* If we're a server that doesn't have a configured address, we rely on
- * directory fetches to learn when our address changes. So if we haven't
- * tried to get any routerdescs in a long time, try a dummy fetch now. */
- if (!options->Address &&
- server_mode(options) &&
- last_descriptor_download_attempted + DUMMY_DOWNLOAD_INTERVAL < now &&
- last_dummy_download + DUMMY_DOWNLOAD_INTERVAL < now) {
- last_dummy_download = now;
- /* XX/teor - do we want an authority here, because they are less likely
- * to give us the wrong address? (See #17782)
- * I'm leaving the previous behaviour intact, because I don't like
- * the idea of some relays contacting an authority every 20 minutes. */
- directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC,
- ROUTER_PURPOSE_GENERAL, "authority.z",
- PDS_RETRY_IF_NO_SERVERS,
- DL_WANT_ANY_DIRSERVER);
- }
-}
-
/** Launch downloads for router status as needed. */
void
update_router_descriptor_downloads(time_t now)
@@ -2871,12 +2933,12 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2)
}
/* If any key fields differ, they're different. */
- if (r1->addr != r2->addr ||
+ if (!tor_addr_eq(&r1->ipv4_addr, &r2->ipv4_addr) ||
strcasecmp(r1->nickname, r2->nickname) ||
- r1->or_port != r2->or_port ||
+ r1->ipv4_orport != r2->ipv4_orport ||
!tor_addr_eq(&r1->ipv6_addr, &r2->ipv6_addr) ||
r1->ipv6_orport != r2->ipv6_orport ||
- r1->dir_port != r2->dir_port ||
+ r1->ipv4_dirport != r2->ipv4_dirport ||
r1->purpose != r2->purpose ||
r1->onion_pkey_len != r2->onion_pkey_len ||
!tor_memeq(r1->onion_pkey, r2->onion_pkey, r1->onion_pkey_len) ||
@@ -2915,7 +2977,7 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2)
(r1->bandwidthburst != r2->bandwidthburst))
return 0;
- /* Did more than 12 hours pass? */
+ /* Has enough time passed between the publication times? */
if (r1->cache_info.published_on + ROUTER_MAX_COSMETIC_TIME_DIFFERENCE
< r2->cache_info.published_on)
return 0;
@@ -2975,7 +3037,7 @@ routerinfo_incompatible_with_extrainfo(const crypto_pk_t *identity_pkey,
digest256_matches = tor_memeq(ei->digest256,
sd->extra_info_digest256, DIGEST256_LEN);
digest256_matches |=
- tor_mem_is_zero(sd->extra_info_digest256, DIGEST256_LEN);
+ fast_mem_is_zero(sd->extra_info_digest256, DIGEST256_LEN);
/* The identity must match exactly to have been generated at the same time
* by the same router. */
@@ -3059,7 +3121,7 @@ routerinfo_has_curve25519_onion_key(const routerinfo_t *ri)
return 0;
}
- if (tor_mem_is_zero((const char*)ri->onion_curve25519_pkey->public_key,
+ if (fast_mem_is_zero((const char*)ri->onion_curve25519_pkey->public_key,
CURVE25519_PUBKEY_LEN)) {
return 0;
}
@@ -3227,6 +3289,8 @@ refresh_all_country_info(void)
routerset_refresh_countries(options->EntryNodes);
if (options->ExitNodes)
routerset_refresh_countries(options->ExitNodes);
+ if (options->MiddleNodes)
+ routerset_refresh_countries(options->MiddleNodes);
if (options->ExcludeNodes)
routerset_refresh_countries(options->ExcludeNodes);
if (options->ExcludeExitNodes)
diff --git a/src/feature/nodelist/routerlist.h b/src/feature/nodelist/routerlist.h
index 5771ebb1ab..98472b2771 100644
--- a/src/feature/nodelist/routerlist.h
+++ b/src/feature/nodelist/routerlist.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -37,9 +37,12 @@ typedef enum was_router_added_t {
ROUTER_WAS_NOT_WANTED = -6,
/* Router descriptor was rejected because it was older than
* OLD_ROUTER_DESC_MAX_AGE. */
- ROUTER_WAS_TOO_OLD = -7, /* note contrast with 'NOT_NEW' */
- /* DOCDOC */
- ROUTER_CERTS_EXPIRED = -8
+ ROUTER_WAS_TOO_OLD = -7, /* note contrast with 'ROUTER_IS_ALREADY_KNOWN' */
+ /* Some certs on this router are expired. */
+ ROUTER_CERTS_EXPIRED = -8,
+ /* We couldn't format the annotations for this router. This is a directory
+ * authority bug. */
+ ROUTER_AUTHDIR_BUG_ANNOTATIONS = -10
} was_router_added_t;
/** How long do we avoid using a directory server after it's given us a 503? */
@@ -47,14 +50,16 @@ typedef enum was_router_added_t {
int router_reload_router_list(void);
-int router_skip_or_reachability(const or_options_t *options, int try_ip_pref);
-int router_skip_dir_reachability(const or_options_t *options, int try_ip_pref);
+int router_or_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref);
+int router_dir_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref);
void router_reset_status_download_failures(void);
int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2);
-void 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);
+bool router_can_choose_node(const node_t *node, int flags);
+void router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags);
const routerinfo_t *routerlist_find_my_routerinfo(void);
uint32_t router_get_advertised_bandwidth(const routerinfo_t *router);
diff --git a/src/feature/nodelist/routerlist_st.h b/src/feature/nodelist/routerlist_st.h
index 7446ead3cb..ec8933c7cb 100644
--- a/src/feature/nodelist/routerlist_st.h
+++ b/src/feature/nodelist/routerlist_st.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file routerlist_st.h
+ * @brief Router descriptor list structure.
+ **/
+
#ifndef ROUTERLIST_ST_H
#define ROUTERLIST_ST_H
@@ -36,5 +41,4 @@ struct routerlist_t {
desc_store_t extrainfo_store;
};
-#endif
-
+#endif /* !defined(ROUTERLIST_ST_H) */
diff --git a/src/feature/nodelist/routerset.c b/src/feature/nodelist/routerset.c
index 55e2756959..0d123956d9 100644
--- a/src/feature/nodelist/routerset.c
+++ b/src/feature/nodelist/routerset.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
-n * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,7 +17,7 @@ n * Copyright (c) 2001-2004, Roger Dingledine.
*
* Routersets are typically used for user-specified restrictions, and
* are created by invoking routerset_new and routerset_parse from
- * config.c and confparse.c. To use a routerset, invoke one of
+ * config.c and confmgt.c. To use a routerset, invoke one of
* routerset_contains_...() functions , or use
* routerstatus_get_all_nodes() / routerstatus_subtract_nodes() to
* manipulate a smartlist of node_t pointers.
@@ -34,6 +34,9 @@ n * Copyright (c) 2001-2004, Roger Dingledine.
#include "feature/nodelist/nickname.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerset.h"
+#include "lib/conf/conftypes.h"
+#include "lib/confmgt/typedvar.h"
+#include "lib/encoding/confline.h"
#include "lib/geoip/geoip.h"
#include "core/or/addr_policy_st.h"
@@ -41,6 +44,7 @@ n * Copyright (c) 2001-2004, Roger Dingledine.
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerstatus_st.h"
+#include "lib/confmgt/var_type_def_st.h"
/** Return a new empty routerset. */
routerset_t *
@@ -52,6 +56,7 @@ routerset_new(void)
result->digests = digestmap_new();
result->policies = smartlist_new();
result->country_names = smartlist_new();
+ result->fragile = 0;
return result;
}
@@ -219,11 +224,11 @@ routerset_len(const routerset_t *set)
*
* (If country is -1, then we take the country
* from addr.) */
-STATIC int
-routerset_contains(const routerset_t *set, const tor_addr_t *addr,
- uint16_t orport,
- const char *nickname, const char *id_digest,
- country_t country)
+static int
+routerset_contains2(const routerset_t *set, const tor_addr_t *addr,
+ uint16_t orport, const tor_addr_t *addr2,
+ uint16_t orport2, const char *nickname,
+ const char *id_digest, country_t country)
{
if (!set || !set->list)
return 0;
@@ -234,6 +239,9 @@ routerset_contains(const routerset_t *set, const tor_addr_t *addr,
if (addr && compare_tor_addr_to_addr_policy(addr, orport, set->policies)
== ADDR_POLICY_REJECTED)
return 3;
+ if (addr2 && compare_tor_addr_to_addr_policy(addr2, orport2, set->policies)
+ == ADDR_POLICY_REJECTED)
+ return 3;
if (set->countries) {
if (country < 0 && addr)
country = geoip_get_country_by_addr(addr);
@@ -245,6 +253,17 @@ routerset_contains(const routerset_t *set, const tor_addr_t *addr,
return 0;
}
+/** Helper. Like routerset_contains2() but for a single IP/port combo.
+ */
+STATIC int
+routerset_contains(const routerset_t *set, const tor_addr_t *addr,
+ uint16_t orport, const char *nickname,
+ const char *id_digest, country_t country)
+{
+ return routerset_contains2(set, addr, orport, NULL, 0,
+ nickname, id_digest, country);
+}
+
/** If *<b>setp</b> includes at least one country code, or if
* <b>only_some_cc_set</b> is 0, add the ?? and A1 country codes to
* *<b>setp</b>, creating it as needed. Return true iff *<b>setp</b> changed.
@@ -288,12 +307,19 @@ routerset_add_unknown_ccs(routerset_t **setp, int only_if_some_cc_set)
int
routerset_contains_extendinfo(const routerset_t *set, const extend_info_t *ei)
{
- return routerset_contains(set,
- &ei->addr,
- ei->port,
- ei->nickname,
- ei->identity_digest,
- -1 /*country*/);
+ const tor_addr_port_t *ap1 = NULL, *ap2 = NULL;
+ if (! tor_addr_is_null(&ei->orports[0].addr))
+ ap1 = &ei->orports[0];
+ if (! tor_addr_is_null(&ei->orports[1].addr))
+ ap2 = &ei->orports[1];
+ return routerset_contains2(set,
+ ap1 ? &ap1->addr : NULL,
+ ap1 ? ap1->port : 0,
+ ap2 ? &ap2->addr : NULL,
+ ap2 ? ap2->port : 0,
+ ei->nickname,
+ ei->identity_digest,
+ -1 /*country*/);
}
/** Return true iff <b>ri</b> is in <b>set</b>. If country is <b>-1</b>, we
@@ -302,14 +328,9 @@ int
routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
country_t country)
{
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, ri->addr);
- return routerset_contains(set,
- &addr,
- ri->or_port,
- ri->nickname,
- ri->cache_info.identity_digest,
- country);
+ return routerset_contains2(set, &ri->ipv4_addr, ri->ipv4_orport,
+ &ri->ipv6_addr, ri->ipv6_orport, ri->nickname,
+ ri->cache_info.identity_digest, country);
}
/** Return true iff <b>rs</b> is in <b>set</b>. If country is <b>-1</b>, we
@@ -319,11 +340,9 @@ routerset_contains_routerstatus(const routerset_t *set,
const routerstatus_t *rs,
country_t country)
{
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, rs->addr);
return routerset_contains(set,
- &addr,
- rs->or_port,
+ &rs->ipv4_addr,
+ rs->ipv4_orport,
rs->nickname,
rs->identity_digest,
country);
@@ -378,7 +397,7 @@ routerset_get_all_nodes(smartlist_t *out, const routerset_t *routerset,
} else {
/* We need to iterate over the routerlist to get all the ones of the
* right kind. */
- smartlist_t *nodes = nodelist_get_list();
+ const smartlist_t *nodes = nodelist_get_list();
SMARTLIST_FOREACH(nodes, const node_t *, node, {
if (running_only && !node->is_running)
continue;
@@ -461,3 +480,133 @@ routerset_free_(routerset_t *routerset)
bitarray_free(routerset->countries);
tor_free(routerset);
}
+
+/**
+ * config helper: parse a routerset-typed variable.
+ *
+ * Takes as input as a single line in <b>line</b>; writes its results into a
+ * routerset_t** passed as <b>target</b>. On success return 0; on failure
+ * return -1 and store an error message into *<b>errmsg</b>.
+ **/
+/*
+ * Warning: For this type, the default value (NULL) and "" are sometimes
+ * considered different values. That is generally risky, and best avoided for
+ * other types in the future. For cases where we want the default to be "all
+ * routers" (like EntryNodes) we should add a new routerset value indicating
+ * "all routers" (see #31908)
+ */
+static int
+routerset_kv_parse(void *target, const config_line_t *line, char **errmsg,
+ const void *params)
+{
+ (void)params;
+ routerset_t **lines = target;
+
+ if (*lines && (*lines)->fragile) {
+ if (line->command == CONFIG_LINE_APPEND) {
+ (*lines)->fragile = 0;
+ } else {
+ routerset_free(*lines); // Represent empty sets as NULL
+ }
+ }
+
+ int ret;
+ routerset_t *rs = routerset_new();
+ if (routerset_parse(rs, line->value, line->key) < 0) {
+ *errmsg = tor_strdup("Invalid router list.");
+ ret = -1;
+ } else {
+ if (!routerset_is_empty(rs)) {
+ if (!*lines) {
+ *lines = routerset_new();
+ }
+ routerset_union(*lines, rs);
+ }
+ ret = 0;
+ }
+ routerset_free(rs);
+ return ret;
+}
+
+/**
+ * config helper: encode a routerset-typed variable.
+ *
+ * Return a newly allocated string containing the value of the
+ * routerset_t** passed as <b>value</b>.
+ */
+static char *
+routerset_encode(const void *value, const void *params)
+{
+ (void)params;
+ const routerset_t **p = (const routerset_t**)value;
+ return routerset_to_string(*p);
+}
+
+/**
+ * config helper: free and clear a routerset-typed variable.
+ *
+ * Clear the routerset_t** passed as <b>value</b>.
+ */
+static void
+routerset_clear(void *value, const void *params)
+{
+ (void)params;
+ routerset_t **p = (routerset_t**)value;
+ routerset_free(*p); // sets *p to NULL.
+}
+
+/**
+ * config helper: copy a routerset-typed variable.
+ *
+ * Takes it input from a routerset_t** in <b>src</b>; writes its output to a
+ * routerset_t** in <b>dest</b>. Returns 0 on success, -1 on (impossible)
+ * failure.
+ **/
+static int
+routerset_copy(void *dest, const void *src, const void *params)
+{
+ (void)params;
+ routerset_t **output = (routerset_t**)dest;
+ const routerset_t *input = *(routerset_t**)src;
+ routerset_free(*output); // sets *output to NULL
+ if (! routerset_is_empty(input)) {
+ *output = routerset_new();
+ routerset_union(*output, input);
+ }
+ return 0;
+}
+
+static void
+routerset_mark_fragile(void *target, const void *params)
+{
+ (void)params;
+ routerset_t **ptr = (routerset_t **)target;
+ if (*ptr)
+ (*ptr)->fragile = 1;
+}
+
+/**
+ * Function table to implement a routerset_t-based configuration type.
+ **/
+static const var_type_fns_t routerset_type_fns = {
+ .kv_parse = routerset_kv_parse,
+ .encode = routerset_encode,
+ .clear = routerset_clear,
+ .copy = routerset_copy,
+ .mark_fragile = routerset_mark_fragile,
+};
+
+/**
+ * Definition of a routerset_t-based configuration type.
+ *
+ * Values are mapped to and from strings using the format defined in
+ * routerset_parse(): nicknames, IP address patterns, and fingerprints--with
+ * optional space, separated by commas.
+ *
+ * Empty sets are represented as NULL.
+ **/
+const var_type_def_t ROUTERSET_type_defn = {
+ .name = "RouterList",
+ .fns = &routerset_type_fns,
+ .flags = CFLG_NOREPLACE
+};
diff --git a/src/feature/nodelist/routerset.h b/src/feature/nodelist/routerset.h
index ca8b6fed93..18a0e31ba7 100644
--- a/src/feature/nodelist/routerset.h
+++ b/src/feature/nodelist/routerset.h
@@ -1,10 +1,10 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
- * \file routerlist.h
+ * \file routerset.h
* \brief Header file for routerset.c
**/
@@ -44,6 +44,10 @@ void routerset_free_(routerset_t *routerset);
#define routerset_free(rs) FREE_AND_NULL(routerset_t, routerset_free_, (rs))
int routerset_len(const routerset_t *set);
+struct var_type_def_t;
+extern const struct var_type_def_t ROUTERSET_type_defn;
+typedef routerset_t *config_decl_ROUTERSET;
+
#ifdef ROUTERSET_PRIVATE
#include "lib/container/bitarray.h"
@@ -84,6 +88,10 @@ struct routerset_t {
* routerset_refresh_countries() whenever the geoip country list is
* reloaded. */
bitarray_t *countries;
+ /** If true, subsequent assignments to this routerset should replace
+ * it, not extend it. Set only on the first item in a routerset in an
+ * or_options_t. */
+ unsigned int fragile:1;
};
#endif /* defined(ROUTERSET_PRIVATE) */
#endif /* !defined(TOR_ROUTERSET_H) */
diff --git a/src/feature/nodelist/routerstatus_st.h b/src/feature/nodelist/routerstatus_st.h
index 288edf5982..254ba73f7f 100644
--- a/src/feature/nodelist/routerstatus_st.h
+++ b/src/feature/nodelist/routerstatus_st.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file routerstatus_st.h
+ * @brief Routerstatus (consensus entry) structure
+ **/
+
#ifndef ROUTERSTATUS_ST_H
#define ROUTERSTATUS_ST_H
@@ -12,6 +17,10 @@
/** Contents of a single router entry in a network status object.
*/
struct routerstatus_t {
+ /* This should be kept in sync with the function
+ * routerstatus_has_visibly_changed and the printing function
+ * routerstatus_format_entry in NS_CONTROL_PORT mode.
+ */
time_t published_on; /**< When was this router published? */
char nickname[MAX_NICKNAME_LEN+1]; /**< The nickname this router says it
* has. */
@@ -20,9 +29,9 @@ struct routerstatus_t {
/** Digest of the router's most recent descriptor or microdescriptor.
* If it's a descriptor, we only use the first DIGEST_LEN bytes. */
char descriptor_digest[DIGEST256_LEN];
- uint32_t addr; /**< IPv4 address for this router, in host order. */
- uint16_t or_port; /**< IPv4 OR port for this router. */
- uint16_t dir_port; /**< Directory port for this router. */
+ tor_addr_t ipv4_addr;
+ uint16_t ipv4_orport; /**< IPv4 OR port for this router. */
+ uint16_t ipv4_dirport; /**< Directory port for this router. */
tor_addr_t ipv6_addr; /**< IPv6 address for this router. */
uint16_t ipv6_orport; /**< IPv6 OR port for this router. */
unsigned int is_authority:1; /**< True iff this router is an authority. */
@@ -47,6 +56,8 @@ struct routerstatus_t {
unsigned int is_v2_dir:1; /** True iff this router publishes an open DirPort
* or it claims to accept tunnelled dir requests.
*/
+ unsigned int is_staledesc:1; /** True iff the authorities think this router
+ * should upload a new descriptor soon. */
unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */
unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */
@@ -76,5 +87,4 @@ struct routerstatus_t {
};
-#endif
-
+#endif /* !defined(ROUTERSTATUS_ST_H) */
diff --git a/src/feature/nodelist/signed_descriptor_st.h b/src/feature/nodelist/signed_descriptor_st.h
index bdcebf184a..068f2a733c 100644
--- a/src/feature/nodelist/signed_descriptor_st.h
+++ b/src/feature/nodelist/signed_descriptor_st.h
@@ -1,9 +1,14 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file signed_descriptor_st.h
+ * @brief Descriptor/extrainfo signature structure
+ **/
+
#ifndef SIGNED_DESCRIPTOR_ST_H
#define SIGNED_DESCRIPTOR_ST_H
@@ -57,5 +62,4 @@ struct signed_descriptor_t {
unsigned int send_unencrypted : 1;
};
-#endif
-
+#endif /* !defined(SIGNED_DESCRIPTOR_ST_H) */
diff --git a/src/feature/nodelist/torcert.c b/src/feature/nodelist/torcert.c
index b0197e9f13..dc36626122 100644
--- a/src/feature/nodelist/torcert.c
+++ b/src/feature/nodelist/torcert.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -37,11 +37,11 @@
#include "core/or/or_handshake_certs_st.h"
-/** Helper for tor_cert_create(): signs any 32 bytes, not just an ed25519
- * key.
+/** As tor_cert_create(), but accept an arbitrary signed_key_type as the
+ * subject key -- not just an ed25519 key.
*/
-static tor_cert_t *
-tor_cert_sign_impl(const ed25519_keypair_t *signing_key,
+tor_cert_t *
+tor_cert_create_raw(const ed25519_keypair_t *signing_key,
uint8_t cert_type,
uint8_t signed_key_type,
const uint8_t signed_key_info[32],
@@ -74,7 +74,7 @@ tor_cert_sign_impl(const ed25519_keypair_t *signing_key,
tor_assert(real_len == alloc_len);
tor_assert(real_len > ED25519_SIG_LEN);
uint8_t *sig = encoded + (real_len - ED25519_SIG_LEN);
- tor_assert(tor_mem_is_zero((char*)sig, ED25519_SIG_LEN));
+ tor_assert(fast_mem_is_zero((char*)sig, ED25519_SIG_LEN));
ed25519_signature_t signature;
if (ed25519_sign(&signature, encoded,
@@ -128,13 +128,13 @@ tor_cert_sign_impl(const ed25519_keypair_t *signing_key,
* the public part of <b>signing_key</b> in the certificate.
*/
tor_cert_t *
-tor_cert_create(const ed25519_keypair_t *signing_key,
+tor_cert_create_ed25519(const ed25519_keypair_t *signing_key,
uint8_t cert_type,
const ed25519_public_key_t *signed_key,
time_t now, time_t lifetime,
uint32_t flags)
{
- return tor_cert_sign_impl(signing_key, cert_type,
+ return tor_cert_create_raw(signing_key, cert_type,
SIGNED_KEY_TYPE_ED25519, signed_key->pubkey,
now, lifetime, flags);
}
@@ -290,8 +290,8 @@ tor_cert_describe_signature_status(const tor_cert_t *cert)
}
/** Return a new copy of <b>cert</b> */
-tor_cert_t *
-tor_cert_dup(const tor_cert_t *cert)
+MOCK_IMPL(tor_cert_t *,
+tor_cert_dup,(const tor_cert_t *cert))
{
tor_cert_t *newcert = tor_memdup(cert, sizeof(tor_cert_t));
if (cert->encoded)
diff --git a/src/feature/nodelist/torcert.h b/src/feature/nodelist/torcert.h
index 492275b514..3314ee2550 100644
--- a/src/feature/nodelist/torcert.h
+++ b/src/feature/nodelist/torcert.h
@@ -1,12 +1,19 @@
-/* Copyright (c) 2014-2019, The Tor Project, Inc. */
+/* Copyright (c) 2014-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file torcert.h
+ * @brief Header for torcert.c
+ **/
+
#ifndef TORCERT_H_INCLUDED
#define TORCERT_H_INCLUDED
#include "lib/crypt_ops/crypto_ed25519.h"
-#define SIGNED_KEY_TYPE_ED25519 0x01
+#define SIGNED_KEY_TYPE_ED25519 0x01
+#define SIGNED_KEY_TYPE_SHA256_OF_RSA 0x02
+#define SIGNED_KEY_TYPE_SHA256_OF_X509 0x03
#define CERT_TYPE_ID_SIGNING 0x04
#define CERT_TYPE_SIGNING_LINK 0x05
@@ -51,11 +58,17 @@ typedef struct tor_cert_st {
struct tor_tls_t;
-tor_cert_t *tor_cert_create(const ed25519_keypair_t *signing_key,
+tor_cert_t *tor_cert_create_ed25519(const ed25519_keypair_t *signing_key,
uint8_t cert_type,
const ed25519_public_key_t *signed_key,
time_t now, time_t lifetime,
uint32_t flags);
+tor_cert_t * tor_cert_create_raw(const ed25519_keypair_t *signing_key,
+ uint8_t cert_type,
+ uint8_t signed_key_type,
+ const uint8_t signed_key_info[32],
+ time_t now, time_t lifetime,
+ uint32_t flags);
tor_cert_t *tor_cert_parse(const uint8_t *cert, size_t certlen);
@@ -71,7 +84,7 @@ int tor_cert_checksig(tor_cert_t *cert,
const ed25519_public_key_t *pubkey, time_t now);
const char *tor_cert_describe_signature_status(const tor_cert_t *cert);
-tor_cert_t *tor_cert_dup(const tor_cert_t *cert);
+MOCK_DECL(tor_cert_t *,tor_cert_dup,(const tor_cert_t *cert));
int tor_cert_eq(const tor_cert_t *cert1, const tor_cert_t *cert2);
int tor_cert_opt_eq(const tor_cert_t *cert1, const tor_cert_t *cert2);
diff --git a/src/feature/nodelist/vote_routerstatus_st.h b/src/feature/nodelist/vote_routerstatus_st.h
index 366754c166..ad0ee3f23b 100644
--- a/src/feature/nodelist/vote_routerstatus_st.h
+++ b/src/feature/nodelist/vote_routerstatus_st.h
@@ -1,9 +1,13 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/**
+ * @file vote_routerstatus_st.h
+ * @brief Routerstatus (vote entry) structure
+ **/
#ifndef VOTE_ROUTERSTATUS_ST_H
#define VOTE_ROUTERSTATUS_ST_H
@@ -38,4 +42,4 @@ struct vote_routerstatus_t {
uint8_t ed25519_id[ED25519_PUBKEY_LEN];
};
-#endif
+#endif /* !defined(VOTE_ROUTERSTATUS_ST_H) */