aboutsummaryrefslogtreecommitdiff
path: root/src/feature/relay
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature/relay')
-rw-r--r--src/feature/relay/circuitbuild_relay.c6
-rw-r--r--src/feature/relay/circuitbuild_relay.h2
-rw-r--r--src/feature/relay/dns.c169
-rw-r--r--src/feature/relay/dns.h5
-rw-r--r--src/feature/relay/dns_structs.h2
-rw-r--r--src/feature/relay/ext_orport.c73
-rw-r--r--src/feature/relay/ext_orport.h13
-rw-r--r--src/feature/relay/include.am2
-rw-r--r--src/feature/relay/onion_queue.c211
-rw-r--r--src/feature/relay/onion_queue.h4
-rw-r--r--src/feature/relay/relay_config.c4
-rw-r--r--src/feature/relay/relay_config.h4
-rw-r--r--src/feature/relay/relay_find_addr.c4
-rw-r--r--src/feature/relay/relay_find_addr.h4
-rw-r--r--src/feature/relay/relay_handshake.c2
-rw-r--r--src/feature/relay/relay_handshake.h2
-rw-r--r--src/feature/relay/relay_metrics.c1058
-rw-r--r--src/feature/relay/relay_metrics.h73
-rw-r--r--src/feature/relay/relay_periodic.c22
-rw-r--r--src/feature/relay/relay_periodic.h2
-rw-r--r--src/feature/relay/relay_stub.c2
-rw-r--r--src/feature/relay/relay_sys.c7
-rw-r--r--src/feature/relay/relay_sys.h2
-rw-r--r--src/feature/relay/router.c26
-rw-r--r--src/feature/relay/router.h2
-rw-r--r--src/feature/relay/routerkeys.c2
-rw-r--r--src/feature/relay/routerkeys.h2
-rw-r--r--src/feature/relay/routermode.c2
-rw-r--r--src/feature/relay/routermode.h2
-rw-r--r--src/feature/relay/selftest.c192
-rw-r--r--src/feature/relay/selftest.h15
-rw-r--r--src/feature/relay/transport_config.c2
-rw-r--r--src/feature/relay/transport_config.h2
33 files changed, 1535 insertions, 385 deletions
diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c
index 289a5be557..5b1609a1af 100644
--- a/src/feature/relay/circuitbuild_relay.c
+++ b/src/feature/relay/circuitbuild_relay.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -392,7 +392,9 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec,
NULL, /*onion_key*/
NULL, /*curve25519_key*/
&chosen_ap->addr,
- chosen_ap->port);
+ chosen_ap->port,
+ NULL /* protover summary */,
+ false);
circ->n_chan_create_cell = tor_memdup(&ec->create_cell,
sizeof(ec->create_cell));
diff --git a/src/feature/relay/circuitbuild_relay.h b/src/feature/relay/circuitbuild_relay.h
index dc0b886a34..307825bb5c 100644
--- a/src/feature/relay/circuitbuild_relay.h
+++ b/src/feature/relay/circuitbuild_relay.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/dns.c b/src/feature/relay/dns.c
index 8b684fd9eb..a38bf5cf5a 100644
--- a/src/feature/relay/dns.c
+++ b/src/feature/relay/dns.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -61,8 +61,10 @@
#include "core/or/relay.h"
#include "feature/control/control_events.h"
#include "feature/relay/dns.h"
+#include "feature/nodelist/networkstatus.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
+#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/evloop/compat_libevent.h"
#include "lib/sandbox/sandbox.h"
@@ -109,6 +111,7 @@ static int answer_is_wildcarded(const char *ip);
static int evdns_err_is_transient(int err);
static void inform_pending_connections(cached_resolve_t *resolve);
static void make_pending_resolve_cached(cached_resolve_t *cached);
+static void configure_libevent_options(void);
#ifdef DEBUG_DNS_CACHE
static void assert_cache_ok_(void);
@@ -211,6 +214,19 @@ evdns_log_cb(int warn, const char *msg)
tor_log(severity, LD_EXIT, "eventdns: %s", msg);
}
+/** New consensus just appeared, take appropriate actions if need be. */
+void
+dns_new_consensus_params(const networkstatus_t *ns)
+{
+ (void) ns;
+
+ /* Consensus has parameters for the Exit relay DNS side and so we only reset
+ * the DNS nameservers if we are in server mode. */
+ if (server_mode(get_options())) {
+ configure_libevent_options();
+ }
+}
+
/** Initialize the DNS subsystem; called by the OR process. */
int
dns_init(void)
@@ -1352,6 +1368,111 @@ configured_nameserver_address(const size_t idx)
}
#endif /* defined(HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR) */
+/** Return a pointer to a stack allocated buffer containing the string
+ * representation of the exit_dns_timeout consensus parameter. */
+static const char *
+get_consensus_param_exit_dns_timeout(void)
+{
+ static char str[4];
+
+ /* Get the Exit DNS timeout value from the consensus or default. This is in
+ * milliseconds. */
+#define EXIT_DNS_TIMEOUT_DEFAULT (1000)
+#define EXIT_DNS_TIMEOUT_MIN (1)
+#define EXIT_DNS_TIMEOUT_MAX (120000)
+ int32_t val = networkstatus_get_param(NULL, "exit_dns_timeout",
+ EXIT_DNS_TIMEOUT_DEFAULT,
+ EXIT_DNS_TIMEOUT_MIN,
+ EXIT_DNS_TIMEOUT_MAX);
+ /* NOTE: We convert it to seconds because libevent only supports that. In the
+ * future, if we support different resolver(s), we might want to specialize
+ * this call. */
+
+ /* NOTE: We also don't allow 0 and so we must cap the division to 1 second
+ * else all DNS request would fail if the consensus would ever tell us a
+ * value below 1000 (1 sec). */
+ val = MAX(1, val / 1000);
+
+ tor_snprintf(str, sizeof(str), "%d", val);
+ return str;
+}
+
+/** Return a pointer to a stack allocated buffer containing the string
+ * representation of the exit_dns_num_attempts consensus parameter. */
+static const char *
+get_consensus_param_exit_dns_attempts(void)
+{
+ static char str[4];
+
+ /* Get the Exit DNS number of attempt value from the consensus or default. */
+#define EXIT_DNS_NUM_ATTEMPTS_DEFAULT (2)
+#define EXIT_DNS_NUM_ATTEMPTS_MIN (0)
+#define EXIT_DNS_NUM_ATTEMPTS_MAX (255)
+ int32_t val = networkstatus_get_param(NULL, "exit_dns_num_attempts",
+ EXIT_DNS_NUM_ATTEMPTS_DEFAULT,
+ EXIT_DNS_NUM_ATTEMPTS_MIN,
+ EXIT_DNS_NUM_ATTEMPTS_MAX);
+ tor_snprintf(str, sizeof(str), "%d", val);
+ return str;
+}
+
+/** Configure the libevent options. This can safely be called after
+ * initialization or even if the evdns base is not set. */
+static void
+configure_libevent_options(void)
+{
+ /* This is possible because we can get called when a new consensus is set
+ * while the DNS subsystem is not initialized just yet. It should be
+ * harmless. */
+ if (!the_evdns_base) {
+ return;
+ }
+
+#define SET(k,v) evdns_base_set_option(the_evdns_base, (k), (v))
+
+ // If we only have one nameserver, it does not make sense to back off
+ // from it for a timeout. Unfortunately, the value for max-timeouts is
+ // currently clamped by libevent to 255, but it does not hurt to set
+ // it higher in case libevent gets a patch for this. Higher-than-
+ // default maximum of 3 with multiple nameservers to avoid spuriously
+ // marking one down on bursts of timeouts resulting from scans/attacks
+ // against non-responding authoritative DNS servers.
+ if (evdns_base_count_nameservers(the_evdns_base) == 1) {
+ SET("max-timeouts:", "1000000");
+ } else {
+ SET("max-timeouts:", "10");
+ }
+
+ // Elongate the queue of maximum inflight dns requests, so if a bunch
+ // remain pending at the resolver (happens commonly with Unbound) we won't
+ // stall every other DNS request. This potentially means some wasted
+ // CPU as there's a walk over a linear queue involved, but this is a
+ // much better tradeoff compared to just failing DNS requests because
+ // of a full queue.
+ SET("max-inflight:", "8192");
+
+ /* Set timeout to be 1 second. This tells libevent that it shouldn't wait
+ * more than N second to drop a DNS query and consider it "timed out". It is
+ * very important to differentiate here a libevent timeout and a DNS server
+ * timeout. And so, by setting this to N second, libevent sends back
+ * "DNS_ERR_TIMEOUT" if that N second is reached which does NOT indicate that
+ * the query itself timed out in transit. */
+ SET("timeout:", get_consensus_param_exit_dns_timeout());
+
+ /* This tells libevent to attemps up to X times a DNS query if the previous
+ * one failed to complete within N second. We believe that this should be
+ * enough to catch temporary hiccups on the first query. But after that, it
+ * should signal us that it won't be able to resolve it. */
+ SET("attempts:", get_consensus_param_exit_dns_attempts());
+
+ if (get_options()->ServerDNSRandomizeCase)
+ SET("randomize-case:", "1");
+ else
+ SET("randomize-case:", "0");
+
+#undef SET
+}
+
/** Configure eventdns nameservers if force is true, or if the configuration
* has changed since the last time we called this function, or if we failed on
* our last attempt. On Unix, this reads from /etc/resolv.conf or
@@ -1465,43 +1586,10 @@ configure_nameservers(int force)
}
#endif /* defined(_WIN32) */
-#define SET(k,v) evdns_base_set_option(the_evdns_base, (k), (v))
-
- // If we only have one nameserver, it does not make sense to back off
- // from it for a timeout. Unfortunately, the value for max-timeouts is
- // currently clamped by libevent to 255, but it does not hurt to set
- // it higher in case libevent gets a patch for this. Higher-than-
- // default maximum of 3 with multiple nameservers to avoid spuriously
- // marking one down on bursts of timeouts resulting from scans/attacks
- // against non-responding authoritative DNS servers.
- if (evdns_base_count_nameservers(the_evdns_base) == 1) {
- SET("max-timeouts:", "1000000");
- } else {
- SET("max-timeouts:", "10");
- }
-
- // Elongate the queue of maximum inflight dns requests, so if a bunch
- // remain pending at the resolver (happens commonly with Unbound) we won't
- // stall every other DNS request. This potentially means some wasted
- // CPU as there's a walk over a linear queue involved, but this is a
- // much better tradeoff compared to just failing DNS requests because
- // of a full queue.
- SET("max-inflight:", "8192");
-
- // Two retries at 5 and 10 seconds for bind9/named which relies on
- // clients to handle retries. Second retry for retried circuits with
- // extended 15 second timeout. Superfluous with local-system Unbound
- // instance--has its own elaborate retry scheme.
- SET("timeout:", "5");
- SET("attempts:","3");
-
- if (options->ServerDNSRandomizeCase)
- SET("randomize-case:", "1");
- else
- SET("randomize-case:", "0");
-
-#undef SET
+ /* Setup libevent options. */
+ configure_libevent_options();
+ /* Relaunch periodical DNS check event. */
dns_servers_relaunch_checks();
nameservers_configured = 1;
@@ -1639,6 +1727,10 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
dns_found_answer(string_address, orig_query_type,
result, &addr, hostname, clip_dns_fuzzy_ttl(ttl));
+ /* The result can be changed within this function thus why we note the result
+ * at the end. */
+ rep_hist_note_dns_error(type, result);
+
tor_free(arg_);
}
@@ -1657,6 +1749,9 @@ launch_one_resolve(const char *address, uint8_t query_type,
addr[0] = (char) query_type;
memcpy(addr+1, address, addr_len + 1);
+ /* Note the query for our statistics. */
+ rep_hist_note_dns_request(query_type);
+
switch (query_type) {
case DNS_IPv4_A:
req = evdns_base_resolve_ipv4(the_evdns_base,
diff --git a/src/feature/relay/dns.h b/src/feature/relay/dns.h
index 120b75bf8d..3f8519bd97 100644
--- a/src/feature/relay/dns.h
+++ b/src/feature/relay/dns.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -26,6 +26,7 @@ void dns_reset_correctness_checks(void);
size_t dns_cache_total_allocation(void);
void dump_dns_mem_usage(int severity);
size_t dns_cache_handle_oom(time_t now, size_t min_remove_bytes);
+void dns_new_consensus_params(const networkstatus_t *ns);
/* These functions are only used within the feature/relay module, and don't
* need stubs. */
@@ -47,6 +48,8 @@ void dns_launch_correctness_checks(void);
((void)(severity))
#define dns_cache_handle_oom(now, bytes) \
((void)(now), (void)(bytes), 0)
+#define dns_new_consensus_params(ns) \
+ ((void) ns)
#define connection_dns_remove(conn) \
STMT_BEGIN \
diff --git a/src/feature/relay/dns_structs.h b/src/feature/relay/dns_structs.h
index 27a791b9b3..d153629bf8 100644
--- a/src/feature/relay/dns_structs.h
+++ b/src/feature/relay/dns_structs.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/ext_orport.c b/src/feature/relay/ext_orport.c
index 1bb8741e45..89b287b0b4 100644
--- a/src/feature/relay/ext_orport.c
+++ b/src/feature/relay/ext_orport.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2020, The Tor Project, Inc. */
+/* Copyright (c) 2012-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -656,77 +656,6 @@ connection_ext_or_start_auth(or_connection_t *or_conn)
return 0;
}
-/** Global map between Extended ORPort identifiers and OR
- * connections. */
-static digestmap_t *orconn_ext_or_id_map = NULL;
-
-/** Remove the Extended ORPort identifier of <b>conn</b> from the
- * global identifier list. Also, clear the identifier from the
- * connection itself. */
-void
-connection_or_remove_from_ext_or_id_map(or_connection_t *conn)
-{
- or_connection_t *tmp;
- if (!orconn_ext_or_id_map)
- return;
- if (!conn->ext_or_conn_id)
- return;
-
- tmp = digestmap_remove(orconn_ext_or_id_map, conn->ext_or_conn_id);
- if (!tor_digest_is_zero(conn->ext_or_conn_id))
- tor_assert(tmp == conn);
-
- memset(conn->ext_or_conn_id, 0, EXT_OR_CONN_ID_LEN);
-}
-
-#ifdef TOR_UNIT_TESTS
-/** Return the connection whose ext_or_id is <b>id</b>. Return NULL if no such
- * connection is found. */
-or_connection_t *
-connection_or_get_by_ext_or_id(const char *id)
-{
- if (!orconn_ext_or_id_map)
- return NULL;
- return digestmap_get(orconn_ext_or_id_map, id);
-}
-#endif /* defined(TOR_UNIT_TESTS) */
-
-/** Deallocate the global Extended ORPort identifier list */
-void
-connection_or_clear_ext_or_id_map(void)
-{
- digestmap_free(orconn_ext_or_id_map, NULL);
- orconn_ext_or_id_map = NULL;
-}
-
-/** Creates an Extended ORPort identifier for <b>conn</b> and deposits
- * it into the global list of identifiers. */
-void
-connection_or_set_ext_or_identifier(or_connection_t *conn)
-{
- char random_id[EXT_OR_CONN_ID_LEN];
- or_connection_t *tmp;
-
- if (!orconn_ext_or_id_map)
- orconn_ext_or_id_map = digestmap_new();
-
- /* Remove any previous identifiers: */
- if (conn->ext_or_conn_id && !tor_digest_is_zero(conn->ext_or_conn_id))
- connection_or_remove_from_ext_or_id_map(conn);
-
- do {
- crypto_rand(random_id, sizeof(random_id));
- } while (digestmap_get(orconn_ext_or_id_map, random_id));
-
- if (!conn->ext_or_conn_id)
- conn->ext_or_conn_id = tor_malloc_zero(EXT_OR_CONN_ID_LEN);
-
- memcpy(conn->ext_or_conn_id, random_id, EXT_OR_CONN_ID_LEN);
-
- tmp = digestmap_set(orconn_ext_or_id_map, random_id, conn);
- tor_assert(!tmp);
-}
-
/** Free any leftover allocated memory of the ext_orport.c subsystem. */
void
ext_orport_free_all(void)
diff --git a/src/feature/relay/ext_orport.h b/src/feature/relay/ext_orport.h
index 416c358397..5a9063d005 100644
--- a/src/feature/relay/ext_orport.h
+++ b/src/feature/relay/ext_orport.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -35,9 +35,6 @@
int connection_ext_or_start_auth(or_connection_t *or_conn);
-void connection_or_set_ext_or_identifier(or_connection_t *conn);
-void connection_or_remove_from_ext_or_id_map(or_connection_t *conn);
-void connection_or_clear_ext_or_id_map(void);
int connection_ext_or_finished_flushing(or_connection_t *conn);
int connection_ext_or_process_inbuf(or_connection_t *or_conn);
char *get_ext_or_auth_cookie_file_name(void);
@@ -69,13 +66,6 @@ connection_ext_or_process_inbuf(or_connection_t *conn)
tor_assert_nonfatal_unreached();
return -1;
}
-#define connection_or_set_ext_or_identifier(conn) \
- ((void)(conn))
-#define connection_or_remove_from_ext_or_id_map(conn) \
- ((void)(conn))
-#define connection_or_clear_ext_or_id_map() \
- STMT_NIL
-
#define get_ext_or_auth_cookie_file_name() \
(NULL)
@@ -94,7 +84,6 @@ STATIC int handle_client_auth_nonce(const char *client_nonce,
#ifdef TOR_UNIT_TESTS
extern uint8_t *ext_or_auth_cookie;
extern int ext_or_auth_cookie_is_set;
-or_connection_t *connection_or_get_by_ext_or_id(const char *id);
#endif
#endif /* defined(EXT_ORPORT_PRIVATE) */
diff --git a/src/feature/relay/include.am b/src/feature/relay/include.am
index 84bb1ff35e..8a121cef01 100644
--- a/src/feature/relay/include.am
+++ b/src/feature/relay/include.am
@@ -15,6 +15,7 @@ MODULE_RELAY_SOURCES = \
src/feature/relay/routermode.c \
src/feature/relay/relay_config.c \
src/feature/relay/relay_handshake.c \
+ src/feature/relay/relay_metrics.c \
src/feature/relay/relay_periodic.c \
src/feature/relay/relay_sys.c \
src/feature/relay/routerkeys.c \
@@ -30,6 +31,7 @@ noinst_HEADERS += \
src/feature/relay/onion_queue.h \
src/feature/relay/relay_config.h \
src/feature/relay/relay_handshake.h \
+ src/feature/relay/relay_metrics.h \
src/feature/relay/relay_periodic.h \
src/feature/relay/relay_sys.h \
src/feature/relay/relay_find_addr.h \
diff --git a/src/feature/relay/onion_queue.c b/src/feature/relay/onion_queue.c
index 3cbaa65d28..b844aefcd1 100644
--- a/src/feature/relay/onion_queue.c
+++ b/src/feature/relay/onion_queue.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -33,39 +33,104 @@
#include "core/or/circuitlist.h"
#include "core/or/onion.h"
#include "feature/nodelist/networkstatus.h"
+#include "feature/stats/rephist.h"
#include "core/or/or_circuit_st.h"
+#include "core/or/channel.h"
+
+/** Onion queue default, max and min. */
+
+/* In seconds. */
+#define ONION_QUEUE_WAIT_CUTOFF_DEFAULT 5
+#define ONION_QUEUE_WAIT_CUTOFF_MIN 0
+#define ONION_QUEUE_WAIT_CUTOFF_MAX INT32_MAX
+
+/* In msec. */
+#define ONION_QUEUE_MAX_DELAY_DEFAULT 1750
+#define ONION_QUEUE_MAX_DELAY_MIN 1
+#define ONION_QUEUE_MAX_DELAY_MAX INT32_MAX
+
+#define NUM_NTORS_PER_TAP_DEFAULT 10
+#define NUM_NTORS_PER_TAP_MIN 1
+#define NUM_NTORS_PER_TAP_MAX 100000
/** Type for a linked list of circuits that are waiting for a free CPU worker
* to process a waiting onion handshake. */
typedef struct onion_queue_t {
TOR_TAILQ_ENTRY(onion_queue_t) next;
or_circuit_t *circ;
- uint16_t handshake_type;
+ uint16_t queue_idx;
create_cell_t *onionskin;
time_t when_added;
} onion_queue_t;
-/** 5 seconds on the onion queue til we just send back a destroy */
-#define ONIONQUEUE_WAIT_CUTOFF 5
-
TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t);
typedef struct onion_queue_head_t onion_queue_head_t;
+/** We have 3 queues: tap, fast, and ntor. (ntorv3 goes into ntor queue). */
+#define MAX_QUEUE_IDX ONION_HANDSHAKE_TYPE_NTOR
+
/** Array of queues of circuits waiting for CPU workers. An element is NULL
* if that queue is empty.*/
-static onion_queue_head_t ol_list[MAX_ONION_HANDSHAKE_TYPE+1] =
+static onion_queue_head_t ol_list[MAX_QUEUE_IDX+1] =
{ TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]), /* tap */
TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]), /* fast */
TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]), /* ntor */
};
/** Number of entries of each type currently in each element of ol_list[]. */
-static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1];
+static int ol_entries[MAX_QUEUE_IDX+1];
-static int num_ntors_per_tap(void);
static void onion_queue_entry_remove(onion_queue_t *victim);
+/** Consensus parameters. */
+static int32_t ns_num_ntors_per_tap = NUM_NTORS_PER_TAP_DEFAULT;
+static time_t ns_onion_queue_wait_cutoff = ONION_QUEUE_WAIT_CUTOFF_DEFAULT;
+static uint32_t ns_onion_queue_max_delay = ONION_QUEUE_MAX_DELAY_DEFAULT;
+
+/** Return the number of ntors per tap from the cached parameter. */
+static inline int32_t
+get_num_ntors_per_tap(void)
+{
+ return ns_num_ntors_per_tap;
+}
+
+/** Return the onion queue wait cutoff value from the cached parameter. */
+static inline time_t
+get_onion_queue_wait_cutoff(void)
+{
+ return ns_onion_queue_wait_cutoff;
+}
+
+/** Return the max onion queue delay value either from the torrc options (if
+ * the user explicitly set it) else from the cached parameter. */
+static inline uint32_t
+get_onion_queue_max_delay(const or_options_t *options)
+{
+ if (options && options->MaxOnionQueueDelay > 0) {
+ return options->MaxOnionQueueDelay;
+ }
+ return ns_onion_queue_max_delay;
+}
+
+/**
+ * We combine ntorv3 and ntor into the same queue, so we must
+ * use this function to covert the cell type to a queue index.
+ */
+static inline uint16_t
+onionskin_type_to_queue(uint16_t type)
+{
+ if (type == ONION_HANDSHAKE_TYPE_NTOR_V3) {
+ return ONION_HANDSHAKE_TYPE_NTOR;
+ }
+
+ if (BUG(type > MAX_QUEUE_IDX)) {
+ return MAX_QUEUE_IDX; // use ntor if out of range
+ }
+
+ return type;
+}
+
/* XXXX Check lengths vs MAX_ONIONSKIN_{CHALLENGE,REPLY}_LEN.
*
* (By which I think I meant, "make sure that no
@@ -80,13 +145,22 @@ have_room_for_onionskin(uint16_t type)
{
const or_options_t *options = get_options();
int num_cpus;
+ uint64_t max_onion_queue_delay;
uint64_t tap_usec, ntor_usec;
uint64_t ntor_during_tap_usec, tap_during_ntor_usec;
/* If we've got fewer than 50 entries, we always have room for one more. */
if (ol_entries[type] < 50)
return 1;
- num_cpus = get_num_cpus(options);
+
+ /* If zero, this means our thread pool was never initialized meaning we can't
+ * really get here but make sure we don't have such value because we are
+ * using as a divisor. */
+ num_cpus = cpuworker_get_n_threads();
+ tor_assert(num_cpus > 0);
+
+ max_onion_queue_delay = get_onion_queue_max_delay(options);
+
/* Compute how many microseconds we'd expect to need to clear all
* onionskins in various combinations of the queues. */
@@ -104,32 +178,30 @@ have_room_for_onionskin(uint16_t type)
* process while draining the ntor queue? */
tap_during_ntor_usec = estimated_usec_for_onionskins(
MIN(ol_entries[ONION_HANDSHAKE_TYPE_TAP],
- ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / num_ntors_per_tap()),
+ ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / get_num_ntors_per_tap()),
ONION_HANDSHAKE_TYPE_TAP) / num_cpus;
/* How long would it take to process the ntor cells that we expect to
* process while draining the tap queue? */
ntor_during_tap_usec = estimated_usec_for_onionskins(
MIN(ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
- ol_entries[ONION_HANDSHAKE_TYPE_TAP] * num_ntors_per_tap()),
+ ol_entries[ONION_HANDSHAKE_TYPE_TAP] * get_num_ntors_per_tap()),
ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
/* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue
* this. */
if (type == ONION_HANDSHAKE_TYPE_NTOR &&
- (ntor_usec + tap_during_ntor_usec) / 1000 >
- (uint64_t)options->MaxOnionQueueDelay)
+ (ntor_usec + tap_during_ntor_usec) / 1000 > max_onion_queue_delay)
return 0;
if (type == ONION_HANDSHAKE_TYPE_TAP &&
- (tap_usec + ntor_during_tap_usec) / 1000 >
- (uint64_t)options->MaxOnionQueueDelay)
+ (tap_usec + ntor_during_tap_usec) / 1000 > max_onion_queue_delay)
return 0;
/* If we support the ntor handshake, then don't let TAP handshakes use
* more than 2/3 of the space on the queue. */
if (type == ONION_HANDSHAKE_TYPE_TAP &&
- tap_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay * 2 / 3)
+ tap_usec / 1000 > max_onion_queue_delay * 2 / 3)
return 0;
return 1;
@@ -143,6 +215,7 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
{
onion_queue_t *tmp;
time_t now = time(NULL);
+ uint16_t queue_idx = 0;
if (onionskin->handshake_type > MAX_ONION_HANDSHAKE_TYPE) {
/* LCOV_EXCL_START
@@ -153,43 +226,52 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
/* LCOV_EXCL_STOP */
}
+ queue_idx = onionskin_type_to_queue(onionskin->handshake_type);
+
tmp = tor_malloc_zero(sizeof(onion_queue_t));
tmp->circ = circ;
- tmp->handshake_type = onionskin->handshake_type;
+ tmp->queue_idx = queue_idx;
tmp->onionskin = onionskin;
tmp->when_added = now;
- if (!have_room_for_onionskin(onionskin->handshake_type)) {
+ if (!have_room_for_onionskin(queue_idx)) {
#define WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL (60)
static ratelim_t last_warned =
RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL);
- char *m;
- if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR &&
- (m = rate_limit_log(&last_warned, approx_time()))) {
- log_warn(LD_GENERAL,
- "Your computer is too slow to handle this many circuit "
- "creation requests! Please consider using the "
- "MaxAdvertisedBandwidth config option or choosing a more "
- "restricted exit policy.%s",m);
- tor_free(m);
+ if (!channel_is_client(circ->p_chan)) {
+ // Avoid counting create cells from clients, to go with the same
+ // check in command_process_create_cell().
+ rep_hist_note_circuit_handshake_dropped(queue_idx);
+ }
+ if (queue_idx == ONION_HANDSHAKE_TYPE_NTOR) {
+ char *m;
+ if ((m = rate_limit_log(&last_warned, approx_time()))) {
+ log_warn(LD_GENERAL,
+ "Your computer is too slow to handle this many circuit "
+ "creation requests! Please consider using the "
+ "MaxAdvertisedBandwidth config option or choosing a more "
+ "restricted exit policy.%s",
+ m);
+ tor_free(m);
+ }
}
tor_free(tmp);
return -1;
}
- ++ol_entries[onionskin->handshake_type];
+ ++ol_entries[queue_idx];
log_info(LD_OR, "New create (%s). Queues now ntor=%d and tap=%d.",
- onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
+ queue_idx == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
ol_entries[ONION_HANDSHAKE_TYPE_TAP]);
circ->onionqueue_entry = tmp;
- TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next);
+ TOR_TAILQ_INSERT_TAIL(&ol_list[queue_idx], tmp, next);
/* cull elderly requests. */
while (1) {
- onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]);
- if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF)
+ onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[queue_idx]);
+ if (now - head->when_added < get_onion_queue_wait_cutoff())
break;
circ = head->circ;
@@ -204,24 +286,6 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
return 0;
}
-/** Return a fairness parameter, to prefer processing NTOR style
- * handshakes but still slowly drain the TAP queue so we don't starve
- * it entirely. */
-static int
-num_ntors_per_tap(void)
-{
-#define DEFAULT_NUM_NTORS_PER_TAP 10
-#define MIN_NUM_NTORS_PER_TAP 1
-#define MAX_NUM_NTORS_PER_TAP 100000
-
- int result = networkstatus_get_param(NULL, "NumNTorsPerTAP",
- DEFAULT_NUM_NTORS_PER_TAP,
- MIN_NUM_NTORS_PER_TAP,
- MAX_NUM_NTORS_PER_TAP);
- tor_assert(result > 0);
- return result;
-}
-
/** Choose which onion queue we'll pull from next. If one is empty choose
* the other; if they both have elements, load balance across them but
* favoring NTOR. */
@@ -245,7 +309,7 @@ decide_next_handshake_type(void)
* once tap is rare. We should reevaluate whether we like this decision
* once tap gets more rare. */
if (ol_entries[ONION_HANDSHAKE_TYPE_NTOR] &&
- recently_chosen_ntors <= num_ntors_per_tap())
+ recently_chosen_ntors <= get_num_ntors_per_tap())
++recently_chosen_ntors;
return ONION_HANDSHAKE_TYPE_NTOR; /* no taps? try ntor */
@@ -253,7 +317,7 @@ decide_next_handshake_type(void)
/* They both have something queued. Pick ntor if we haven't done that
* too much lately. */
- if (++recently_chosen_ntors <= num_ntors_per_tap()) {
+ if (++recently_chosen_ntors <= get_num_ntors_per_tap()) {
return ONION_HANDSHAKE_TYPE_NTOR;
}
@@ -276,15 +340,15 @@ onion_next_task(create_cell_t **onionskin_out)
return NULL; /* no onions pending, we're done */
tor_assert(head->circ);
- tor_assert(head->handshake_type <= MAX_ONION_HANDSHAKE_TYPE);
+ tor_assert(head->queue_idx <= MAX_QUEUE_IDX);
// tor_assert(head->circ->p_chan); /* make sure it's still valid */
/* XXX I only commented out the above line to make the unit tests
* more manageable. That's probably not good long-term. -RD */
circ = head->circ;
if (head->onionskin)
- --ol_entries[head->handshake_type];
+ --ol_entries[head->queue_idx];
log_info(LD_OR, "Processing create (%s). Queues now ntor=%d and tap=%d.",
- head->handshake_type == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
+ head->queue_idx == ONION_HANDSHAKE_TYPE_NTOR ? "ntor" : "tap",
ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
ol_entries[ONION_HANDSHAKE_TYPE_TAP]);
@@ -300,7 +364,7 @@ onion_next_task(create_cell_t **onionskin_out)
int
onion_num_pending(uint16_t handshake_type)
{
- return ol_entries[handshake_type];
+ return ol_entries[onionskin_type_to_queue(handshake_type)];
}
/** Go through ol_list, find the onion_queue_t element which points to
@@ -326,23 +390,23 @@ onion_pending_remove(or_circuit_t *circ)
static void
onion_queue_entry_remove(onion_queue_t *victim)
{
- if (victim->handshake_type > MAX_ONION_HANDSHAKE_TYPE) {
+ if (victim->queue_idx > MAX_QUEUE_IDX) {
/* LCOV_EXCL_START
* We should have rejected this far before this point */
log_warn(LD_BUG, "Handshake %d out of range! Dropping.",
- victim->handshake_type);
+ victim->queue_idx);
/* XXX leaks */
return;
/* LCOV_EXCL_STOP */
}
- TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next);
+ TOR_TAILQ_REMOVE(&ol_list[victim->queue_idx], victim, next);
if (victim->circ)
victim->circ->onionqueue_entry = NULL;
if (victim->onionskin)
- --ol_entries[victim->handshake_type];
+ --ol_entries[victim->queue_idx];
tor_free(victim->onionskin);
tor_free(victim);
@@ -354,7 +418,7 @@ clear_pending_onions(void)
{
onion_queue_t *victim, *next;
int i;
- for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) {
+ for (i=0; i<=MAX_QUEUE_IDX; i++) {
for (victim = TOR_TAILQ_FIRST(&ol_list[i]); victim; victim = next) {
next = TOR_TAILQ_NEXT(victim,next);
onion_queue_entry_remove(victim);
@@ -363,3 +427,28 @@ clear_pending_onions(void)
}
memset(ol_entries, 0, sizeof(ol_entries));
}
+
+/** Consensus has changed, update the cached parameters. */
+void
+onion_consensus_has_changed(const networkstatus_t *ns)
+{
+ tor_assert(ns);
+
+ ns_onion_queue_max_delay =
+ networkstatus_get_param(ns, "MaxOnionQueueDelay",
+ ONION_QUEUE_MAX_DELAY_DEFAULT,
+ ONION_QUEUE_MAX_DELAY_MIN,
+ ONION_QUEUE_MAX_DELAY_MAX);
+
+ ns_onion_queue_wait_cutoff =
+ networkstatus_get_param(ns, "onion_queue_wait_cutoff",
+ ONION_QUEUE_WAIT_CUTOFF_DEFAULT,
+ ONION_QUEUE_WAIT_CUTOFF_MIN,
+ ONION_QUEUE_WAIT_CUTOFF_MAX);
+
+ ns_num_ntors_per_tap =
+ networkstatus_get_param(ns, "NumNTorsPerTAP",
+ NUM_NTORS_PER_TAP_DEFAULT,
+ NUM_NTORS_PER_TAP_MIN,
+ NUM_NTORS_PER_TAP_MAX);
+}
diff --git a/src/feature/relay/onion_queue.h b/src/feature/relay/onion_queue.h
index 08379b2c00..0c2b97c2b0 100644
--- a/src/feature/relay/onion_queue.h
+++ b/src/feature/relay/onion_queue.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,6 +14,8 @@
struct create_cell_t;
+void onion_consensus_has_changed(const networkstatus_t *ns);
+
int onion_pending_add(or_circuit_t *circ, struct create_cell_t *onionskin);
or_circuit_t *onion_next_task(struct create_cell_t **onionskin_out);
int onion_num_pending(uint16_t handshake_type);
diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c
index 8ea0ad8397..85ccfc18a7 100644
--- a/src/feature/relay/relay_config.c
+++ b/src/feature/relay/relay_config.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -190,7 +190,7 @@ describe_relay_port(const port_cfg_t *port)
/** Return true iff port p1 is equal to p2.
*
- * This does a field by field comparaison. */
+ * This does a field by field comparison. */
static bool
port_cfg_eq(const port_cfg_t *p1, const port_cfg_t *p2)
{
diff --git a/src/feature/relay/relay_config.h b/src/feature/relay/relay_config.h
index d36863a1a1..cb08531782 100644
--- a/src/feature/relay/relay_config.h
+++ b/src/feature/relay/relay_config.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -93,7 +93,7 @@ STATIC int have_enough_mem_for_dircache(const struct or_options_t *options,
struct port_cfg_t;
STATIC const char *describe_relay_port(const struct port_cfg_t *port);
-#endif /* TOR_UNIT_TESTS */
+#endif /* defined(TOR_UNIT_TESTS) */
#endif /* defined(RELAY_CONFIG_PRIVATE) */
diff --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c
index c43885af51..f4f9d40823 100644
--- a/src/feature/relay/relay_find_addr.c
+++ b/src/feature/relay/relay_find_addr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2001-2020, The Tor Project, Inc. */
+/* Copyright (c) 2001-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -221,7 +221,7 @@ relay_addr_learn_from_dirauth(void)
"learn for now our address from them.");
return;
}
- extend_info_t *ei = extend_info_from_node(node, 1);
+ extend_info_t *ei = extend_info_from_node(node, 1, false);
if (BUG(!ei)) {
return;
}
diff --git a/src/feature/relay/relay_find_addr.h b/src/feature/relay/relay_find_addr.h
index f049d1bd20..5bb7f8736e 100644
--- a/src/feature/relay/relay_find_addr.h
+++ b/src/feature/relay/relay_find_addr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2020, The Tor Project, Inc. */
+/* Copyright (c) 2020-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,5 +28,5 @@ void relay_addr_learn_from_dirauth(void);
#endif /* RELAY_FIND_ADDR_PRIVATE */
-#endif /* TOR_RELAY_FIND_ADDR_H */
+#endif /* !defined(TOR_RELAY_FIND_ADDR_H) */
diff --git a/src/feature/relay/relay_handshake.c b/src/feature/relay/relay_handshake.c
index 030dc94956..be7dba721a 100644
--- a/src/feature/relay/relay_handshake.c
+++ b/src/feature/relay/relay_handshake.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/relay_handshake.h b/src/feature/relay/relay_handshake.h
index 99a658cbcc..87199c1c2d 100644
--- a/src/feature/relay/relay_handshake.h
+++ b/src/feature/relay/relay_handshake.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/relay_metrics.c b/src/feature/relay/relay_metrics.c
new file mode 100644
index 0000000000..cdf34a3404
--- /dev/null
+++ b/src/feature/relay/relay_metrics.c
@@ -0,0 +1,1058 @@
+/* Copyright (c) 2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file relay_metrics.c
+ * @brief Relay metrics exposed through the MetricsPort
+ **/
+
+#define RELAY_METRICS_ENTRY_PRIVATE
+
+#include "orconfig.h"
+
+#include "core/or/or.h"
+#include "core/mainloop/connection.h"
+#include "core/mainloop/mainloop.h"
+#include "core/or/congestion_control_common.h"
+#include "core/or/congestion_control_vegas.h"
+#include "core/or/congestion_control_flow.h"
+#include "core/or/circuitlist.h"
+#include "core/or/dos.h"
+#include "core/or/relay.h"
+
+#include "app/config/config.h"
+
+#include "lib/container/smartlist.h"
+#include "lib/log/util_bug.h"
+#include "lib/malloc/malloc.h"
+#include "lib/math/fp.h"
+#include "lib/metrics/metrics_store.h"
+
+#include "feature/hs/hs_dos.h"
+#include "feature/nodelist/nodelist.h"
+#include "feature/nodelist/node_st.h"
+#include "feature/nodelist/routerstatus_st.h"
+#include "feature/relay/relay_metrics.h"
+#include "feature/relay/router.h"
+#include "feature/stats/rephist.h"
+
+#include <event2/dns.h>
+
+/** Declarations of each fill function for metrics defined in base_metrics. */
+static void fill_cc_counters_values(void);
+static void fill_cc_gauges_values(void);
+static void fill_circuits_values(void);
+static void fill_conn_counter_values(void);
+static void fill_conn_gauge_values(void);
+static void fill_dns_error_values(void);
+static void fill_dns_query_values(void);
+static void fill_dos_values(void);
+static void fill_global_bw_limit_values(void);
+static void fill_socket_values(void);
+static void fill_onionskins_values(void);
+static void fill_oom_values(void);
+static void fill_streams_values(void);
+static void fill_relay_flags(void);
+static void fill_tcp_exhaustion_values(void);
+static void fill_traffic_values(void);
+
+/** The base metrics that is a static array of metrics added to the metrics
+ * store.
+ *
+ * The key member MUST be also the index of the entry in the array. */
+static const relay_metrics_entry_t base_metrics[] =
+{
+ {
+ .key = RELAY_METRICS_NUM_OOM_BYTES,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_load_oom_bytes_total),
+ .help = "Total number of bytes the OOM has freed by subsystem",
+ .fill_fn = fill_oom_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_ONIONSKINS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_load_onionskins_total),
+ .help = "Total number of onionskins handled",
+ .fill_fn = fill_onionskins_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_SOCKETS,
+ .type = METRICS_TYPE_GAUGE,
+ .name = METRICS_NAME(relay_load_socket_total),
+ .help = "Total number of sockets",
+ .fill_fn = fill_socket_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_GLOBAL_RW_LIMIT,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_load_global_rate_limit_reached_total),
+ .help = "Total number of global connection bucket limit reached",
+ .fill_fn = fill_global_bw_limit_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_DNS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_exit_dns_query_total),
+ .help = "Total number of DNS queries done by this relay",
+ .fill_fn = fill_dns_query_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_DNS_ERRORS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_exit_dns_error_total),
+ .help = "Total number of DNS errors encountered by this relay",
+ .fill_fn = fill_dns_error_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_TCP_EXHAUSTION,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_load_tcp_exhaustion_total),
+ .help = "Total number of times we ran out of TCP ports",
+ .fill_fn = fill_tcp_exhaustion_values,
+ },
+ {
+ .key = RELAY_METRICS_CONN_COUNTERS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_connections_total),
+ .help = "Total number of created/rejected connections",
+ .fill_fn = fill_conn_counter_values,
+ },
+ {
+ .key = RELAY_METRICS_CONN_GAUGES,
+ .type = METRICS_TYPE_GAUGE,
+ .name = METRICS_NAME(relay_connections),
+ .help = "Total number of opened connections",
+ .fill_fn = fill_conn_gauge_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_STREAMS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_streams_total),
+ .help = "Total number of streams",
+ .fill_fn = fill_streams_values,
+ },
+ {
+ .key = RELAY_METRICS_CC_COUNTERS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_congestion_control_total),
+ .help = "Congestion control related counters",
+ .fill_fn = fill_cc_counters_values,
+ },
+ {
+ .key = RELAY_METRICS_CC_GAUGES,
+ .type = METRICS_TYPE_GAUGE,
+ .name = METRICS_NAME(relay_congestion_control),
+ .help = "Congestion control related gauges",
+ .fill_fn = fill_cc_gauges_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_DOS,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_dos_total),
+ .help = "Denial of Service defenses related counters",
+ .fill_fn = fill_dos_values,
+ },
+ {
+ .key = RELAY_METRICS_NUM_TRAFFIC,
+ .type = METRICS_TYPE_COUNTER,
+ .name = METRICS_NAME(relay_traffic_bytes),
+ .help = "Traffic related counters",
+ .fill_fn = fill_traffic_values,
+ },
+ {
+ .key = RELAY_METRICS_RELAY_FLAGS,
+ .type = METRICS_TYPE_GAUGE,
+ .name = METRICS_NAME(relay_flag),
+ .help = "Relay flags from consensus",
+ .fill_fn = fill_relay_flags,
+ },
+ {
+ .key = RELAY_METRICS_NUM_CIRCUITS,
+ .type = METRICS_TYPE_GAUGE,
+ .name = METRICS_NAME(relay_circuits_total),
+ .help = "Total number of circuits",
+ .fill_fn = fill_circuits_values,
+ },
+};
+static const size_t num_base_metrics = ARRAY_LENGTH(base_metrics);
+
+/** The only and single store of all the relay metrics. */
+static metrics_store_t *the_store;
+
+/** Helper function to convert an handshake type into a string. */
+static inline const char *
+handshake_type_to_str(const uint16_t type)
+{
+ switch (type) {
+ case ONION_HANDSHAKE_TYPE_TAP:
+ return "tap";
+ case ONION_HANDSHAKE_TYPE_FAST:
+ return "fast";
+ case ONION_HANDSHAKE_TYPE_NTOR:
+ return "ntor";
+ case ONION_HANDSHAKE_TYPE_NTOR_V3:
+ return "ntor_v3";
+ default:
+ // LCOV_EXCL_START
+ tor_assert_unreached();
+ // LCOV_EXCL_STOP
+ }
+}
+
+/** Helper function to convert a socket family type into a string. */
+static inline const char *
+af_to_string(const int af)
+{
+ switch (af) {
+ case AF_INET:
+ return "ipv4";
+ case AF_INET6:
+ return "ipv6";
+ case AF_UNIX:
+ return "unix";
+ default:
+ return "<unknown>";
+ }
+}
+
+/** Fill function for the RELAY_METRICS_NUM_CIRCUITS metric. */
+static void
+fill_circuits_values(void)
+{
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_CIRCUITS];
+ metrics_store_entry_t *sentry =
+ metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
+
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "opened"));
+ metrics_store_entry_update(sentry,
+ smartlist_len(circuit_get_global_list()));
+}
+
+/** Fill function for the RELAY_METRICS_RELAY_FLAGS metric. */
+static void
+fill_relay_flags(void)
+{
+ uint8_t is_fast = 0, is_exit = 0, is_authority = 0, is_stable = 0;
+ uint8_t is_running = 0, is_v2_dir = 0, is_guard = 0, is_sybil = 0;
+ uint8_t is_hs_dir = 0;
+
+ const node_t *me =
+ node_get_by_id((const char *) router_get_my_id_digest());
+ if (me && me->rs) {
+ is_fast = me->rs->is_fast;
+ is_exit = me->rs->is_exit;
+ is_authority = me->rs->is_authority;
+ is_stable = me->rs->is_stable;
+ is_running = me->rs->is_flagged_running;
+ is_v2_dir = me->rs->is_v2_dir;
+ is_guard = me->rs->is_possible_guard;
+ is_sybil = me->rs->is_sybil;
+ is_hs_dir = me->rs->is_hs_dir;
+ }
+
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_RELAY_FLAGS];
+ metrics_store_entry_t *sentry =
+ metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
+
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "Fast"));
+ metrics_store_entry_update(sentry, is_fast);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "Exit"));
+ metrics_store_entry_update(sentry, is_exit);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "Authority"));
+ metrics_store_entry_update(sentry, is_authority);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "Stable"));
+ metrics_store_entry_update(sentry, is_stable);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "HSDir"));
+ metrics_store_entry_update(sentry, is_hs_dir);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "Running"));
+ metrics_store_entry_update(sentry, is_running);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "V2Dir"));
+ metrics_store_entry_update(sentry, is_v2_dir);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "Sybil"));
+ metrics_store_entry_update(sentry, is_sybil);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "Guard"));
+ metrics_store_entry_update(sentry, is_guard);
+}
+
+/** Fill function for the RELAY_METRICS_NUM_TRAFFIC metric. */
+static void
+fill_traffic_values(void)
+{
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_TRAFFIC];
+ metrics_store_entry_t *sentry =
+ metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
+
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("direction", "read"));
+ metrics_store_entry_update(sentry, get_bytes_read());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("direction", "written"));
+ metrics_store_entry_update(sentry, get_bytes_written());
+}
+
+/** Fill function for the RELAY_METRICS_NUM_DOS metric. */
+static void
+fill_dos_values(void)
+{
+ const relay_metrics_entry_t *rentry = &base_metrics[RELAY_METRICS_NUM_DOS];
+ metrics_store_entry_t *sentry =
+ metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
+
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "circuit_rejected"));
+ metrics_store_entry_update(sentry, dos_get_num_cc_rejected());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "circuit_killed_max_cell"));
+ metrics_store_entry_update(sentry, stats_n_circ_max_cell_reached);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "circuit_killed_max_cell_outq"));
+ metrics_store_entry_update(sentry, stats_n_circ_max_cell_outq_reached);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "marked_address"));
+ metrics_store_entry_update(sentry, dos_get_num_cc_marked_addr());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "marked_address_maxq"));
+ metrics_store_entry_update(sentry, dos_get_num_cc_marked_addr_maxq());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "conn_rejected"));
+ metrics_store_entry_update(sentry, dos_get_num_conn_addr_connect_rejected());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "concurrent_conn_rejected"));
+ metrics_store_entry_update(sentry, dos_get_num_conn_addr_rejected());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "single_hop_refused"));
+ metrics_store_entry_update(sentry, dos_get_num_single_hop_refused());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", "introduce2_rejected"));
+ metrics_store_entry_update(sentry, hs_dos_get_intro2_rejected_count());
+}
+
+/** Fill function for the RELAY_METRICS_CC_COUNTERS metric. */
+static void
+fill_cc_counters_values(void)
+{
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_CC_COUNTERS];
+
+ metrics_store_entry_t *sentry =
+ metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "starvation"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "rtt_reset"));
+ metrics_store_entry_update(sentry, congestion_control_get_num_rtt_reset());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "clock_stalls"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "rtt_skipped"));
+ metrics_store_entry_update(sentry,
+ congestion_control_get_num_clock_stalls());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "flow_control"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "xoff_num_sent"));
+ metrics_store_entry_update(sentry,
+ cc_stats_flow_num_xoff_sent);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "flow_control"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "xon_num_sent"));
+ metrics_store_entry_update(sentry,
+ cc_stats_flow_num_xon_sent);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_limits"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "above_delta"));
+ metrics_store_entry_update(sentry, cc_stats_vegas_above_delta);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_limits"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "above_ss_cwnd_max"));
+ metrics_store_entry_update(sentry, cc_stats_vegas_above_ss_cwnd_max);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_limits"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "below_ss_inc_floor"));
+ metrics_store_entry_update(sentry, cc_stats_vegas_below_ss_inc_floor);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_circuits"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "circs_created"));
+ metrics_store_entry_update(sentry, cc_stats_circs_created);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_circuits"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "circs_closed"));
+ metrics_store_entry_update(sentry, cc_stats_circs_closed);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_circuits"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "circs_exited_ss"));
+ metrics_store_entry_update(sentry, cc_stats_vegas_circ_exited_ss);
+}
+
+/** Fill function for the RELAY_METRICS_CC_GAUGES metric. */
+static void
+fill_cc_gauges_values(void)
+{
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_CC_GAUGES];
+
+ metrics_store_entry_t *sentry =
+ metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "slow_start_exit"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "cwnd"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_exit_ss_cwnd_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "slow_start_exit"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "bdp"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_exit_ss_bdp_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "slow_start_exit"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "inc"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_exit_ss_inc_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "on_circ_close"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "cwnd"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_circ_close_cwnd_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "on_circ_close"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "ss_cwnd"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_circ_close_ss_cwnd_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "buffers"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "xon_outbuf"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_flow_xon_outbuf_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "buffers"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "xoff_outbuf"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_flow_xoff_outbuf_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_backoff"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "chan_blocked_pct"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_csig_blocked_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_backoff"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "gamma_drop"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_gamma_drop_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_backoff"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "delta_drop"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_delta_drop_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_backoff"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "ss_chan_blocked_pct"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_ss_csig_blocked_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_cwnd_update"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "alpha_pct"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_csig_alpha_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_cwnd_update"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "beta_pct"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_csig_beta_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_cwnd_update"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "delta_pct"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_csig_delta_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_estimates"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "ss_queue"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_ss_queue_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_estimates"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "queue"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_queue_ma));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "cc_estimates"));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "bdp"));
+ metrics_store_entry_update(sentry,
+ tor_llround(cc_stats_vegas_bdp_ma));
+}
+
+/** Helper: Fill in single stream metrics output. */
+static void
+fill_single_stream_value(metrics_store_entry_t *sentry, uint8_t cmd)
+{
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", relay_command_to_string(cmd)));
+ metrics_store_entry_update(sentry, rep_hist_get_exit_stream_seen(cmd));
+}
+
+/** Fill function for the RELAY_METRICS_NUM_STREAMS metric. */
+static void
+fill_streams_values(void)
+{
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_STREAMS];
+ metrics_store_entry_t *sentry =
+ metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
+ fill_single_stream_value(sentry, RELAY_COMMAND_BEGIN);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ fill_single_stream_value(sentry, RELAY_COMMAND_BEGIN_DIR);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ fill_single_stream_value(sentry, RELAY_COMMAND_RESOLVE);
+}
+
+/** Helper: Fill in single connection metrics output. */
+static void
+fill_single_connection_value(metrics_store_entry_t *sentry,
+ unsigned int conn_type,
+ const char* direction,
+ const char* state,
+ int socket_family,
+ uint64_t value)
+{
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("type", conn_type_to_string(conn_type)));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("direction", direction));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", state));
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("family", af_to_string(socket_family)));
+ metrics_store_entry_update(sentry, value);
+}
+
+/** Fill function for the RELAY_METRICS_CONN_COUNTERS metric. */
+static void
+fill_conn_counter_values(void)
+{
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_CONN_COUNTERS];
+
+ for (unsigned int i = CONN_TYPE_MIN_; i < CONN_TYPE_MAX_ ; i++) {
+ /* Type is unused. Ugly but else we clobber the output. */
+ if (i == 10) {
+ continue;
+ }
+ metrics_store_entry_t *sentry =
+ metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
+ fill_single_connection_value(sentry, i, "initiated", "created", AF_INET,
+ rep_hist_get_conn_created(false, i, AF_INET));
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ fill_single_connection_value(sentry, i, "initiated", "created", AF_INET6,
+ rep_hist_get_conn_created(false, i,
+ AF_INET6));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ fill_single_connection_value(sentry, i, "received", "created", AF_INET,
+ rep_hist_get_conn_created(true, i, AF_INET));
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ fill_single_connection_value(sentry, i, "received", "created", AF_INET6,
+ rep_hist_get_conn_created(true, i, AF_INET6));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ fill_single_connection_value(sentry, i, "received", "rejected", AF_INET,
+ rep_hist_get_conn_rejected(i, AF_INET));
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ fill_single_connection_value(sentry, i, "received", "rejected", AF_INET6,
+ rep_hist_get_conn_rejected(i, AF_INET6));
+
+ /* No counter for "initiated" + "rejected" connections exists. */
+ }
+}
+
+/** Fill function for the RELAY_METRICS_CONN_GAUGES metric. */
+static void
+fill_conn_gauge_values(void)
+{
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_CONN_GAUGES];
+
+ for (unsigned int i = CONN_TYPE_MIN_; i < CONN_TYPE_MAX_ ; i++) {
+ /* Type is unused. Ugly but else we clobber the output. */
+ if (i == 10) {
+ continue;
+ }
+ metrics_store_entry_t *sentry =
+ metrics_store_add(the_store, rentry->type, rentry->name, rentry->help);
+ fill_single_connection_value(sentry, i, "initiated", "opened", AF_INET,
+ rep_hist_get_conn_opened(false, i, AF_INET));
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ fill_single_connection_value(sentry, i, "initiated", "opened", AF_INET6,
+ rep_hist_get_conn_opened(false, i, AF_INET6));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ fill_single_connection_value(sentry, i, "received", "opened", AF_INET,
+ rep_hist_get_conn_opened(true, i, AF_INET));
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ fill_single_connection_value(sentry, i, "received", "opened", AF_INET6,
+ rep_hist_get_conn_opened(true, i, AF_INET6));
+ }
+}
+
+/** Fill function for the RELAY_METRICS_NUM_DNS metrics. */
+static void
+fill_tcp_exhaustion_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_TCP_EXHAUSTION];
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_update(sentry, rep_hist_get_n_tcp_exhaustion());
+}
+
+/* NOTE: Disable the record type label until libevent is fixed. */
+#if 0
+/** Helper array containing mapping for the name of the different DNS records
+ * and their corresponding libevent values. */
+static struct dns_type {
+ const char *name;
+ uint8_t type;
+} dns_types[] = {
+ { .name = "A", .type = DNS_IPv4_A },
+ { .name = "PTR", .type = DNS_PTR },
+ { .name = "AAAA", .type = DNS_IPv6_AAAA },
+};
+static const size_t num_dns_types = ARRAY_LENGTH(dns_types);
+#endif
+
+/** Fill function for the RELAY_METRICS_NUM_DNS_ERRORS metrics. */
+static void
+fill_dns_error_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_DNS_ERRORS];
+
+ /* Helper array to map libeven DNS errors to their names and so we can
+ * iterate over this array to add all metrics. */
+ static struct dns_error {
+ const char *name;
+ uint8_t key;
+ } errors[] = {
+ { .name = "success", .key = DNS_ERR_NONE },
+ { .name = "format", .key = DNS_ERR_FORMAT },
+ { .name = "serverfailed", .key = DNS_ERR_SERVERFAILED },
+ { .name = "notexist", .key = DNS_ERR_NOTEXIST },
+ { .name = "notimpl", .key = DNS_ERR_NOTIMPL },
+ { .name = "refused", .key = DNS_ERR_REFUSED },
+ { .name = "truncated", .key = DNS_ERR_TRUNCATED },
+ { .name = "unknown", .key = DNS_ERR_UNKNOWN },
+ { .name = "tor_timeout", .key = DNS_ERR_TIMEOUT },
+ { .name = "shutdown", .key = DNS_ERR_SHUTDOWN },
+ { .name = "cancel", .key = DNS_ERR_CANCEL },
+ { .name = "nodata", .key = DNS_ERR_NODATA },
+ };
+ static const size_t num_errors = ARRAY_LENGTH(errors);
+
+ /* NOTE: Disable the record type label until libevent is fixed. */
+#if 0
+ for (size_t i = 0; i < num_dns_types; i++) {
+ /* Dup the label because metrics_format_label() returns a pointer to a
+ * string on the stack and we need that label for all metrics. */
+ char *record_label =
+ tor_strdup(metrics_format_label("record", dns_types[i].name));
+
+ for (size_t j = 0; j < num_errors; j++) {
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry, record_label);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("reason", errors[j].name));
+ metrics_store_entry_update(sentry,
+ rep_hist_get_n_dns_error(dns_types[i].type, errors[j].key));
+ }
+ tor_free(record_label);
+ }
+#endif
+
+ /* Put in the DNS errors, unfortunately not per-type for now. */
+ for (size_t j = 0; j < num_errors; j++) {
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("reason", errors[j].name));
+ metrics_store_entry_update(sentry,
+ rep_hist_get_n_dns_error(0, errors[j].key));
+ }
+}
+
+/** Fill function for the RELAY_METRICS_NUM_DNS metrics. */
+static void
+fill_dns_query_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_DNS];
+
+ /* NOTE: Disable the record type label until libevent is fixed (#40490). */
+#if 0
+ for (size_t i = 0; i < num_dns_types; i++) {
+ /* Dup the label because metrics_format_label() returns a pointer to a
+ * string on the stack and we need that label for all metrics. */
+ char *record_label =
+ tor_strdup(metrics_format_label("record", dns_types[i].name));
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry, record_label);
+ metrics_store_entry_update(sentry,
+ rep_hist_get_n_dns_request(dns_types[i].type));
+ tor_free(record_label);
+ }
+#endif
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_update(sentry, rep_hist_get_n_dns_request(0));
+}
+
+/** Fill function for the RELAY_METRICS_NUM_GLOBAL_RW_LIMIT metrics. */
+static void
+fill_global_bw_limit_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_GLOBAL_RW_LIMIT];
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("side", "read"));
+ metrics_store_entry_update(sentry, rep_hist_get_n_read_limit_reached());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("side", "write"));
+ metrics_store_entry_update(sentry, rep_hist_get_n_write_limit_reached());
+}
+
+/** Fill function for the RELAY_METRICS_NUM_SOCKETS metrics. */
+static void
+fill_socket_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_SOCKETS];
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("state", "opened"));
+ metrics_store_entry_update(sentry, get_n_open_sockets());
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_update(sentry, get_max_sockets());
+}
+
+/** Fill function for the RELAY_METRICS_NUM_ONIONSKINS metrics. */
+static void
+fill_onionskins_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_ONIONSKINS];
+
+ for (uint16_t t = 0; t <= MAX_ONION_HANDSHAKE_TYPE; t++) {
+ /* Dup the label because metrics_format_label() returns a pointer to a
+ * string on the stack and we need that label for all metrics. */
+ char *type_label =
+ tor_strdup(metrics_format_label("type", handshake_type_to_str(t)));
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry, type_label);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "processed"));
+ metrics_store_entry_update(sentry,
+ rep_hist_get_circuit_n_handshake_assigned(t));
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry, type_label);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("action", "dropped"));
+ metrics_store_entry_update(sentry,
+ rep_hist_get_circuit_n_handshake_dropped(t));
+ tor_free(type_label);
+ }
+}
+
+/** Fill function for the RELAY_METRICS_NUM_OOM_BYTES metrics. */
+static void
+fill_oom_values(void)
+{
+ metrics_store_entry_t *sentry;
+ const relay_metrics_entry_t *rentry =
+ &base_metrics[RELAY_METRICS_NUM_OOM_BYTES];
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("subsys", "cell"));
+ metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_cell);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("subsys", "dns"));
+ metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_dns);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("subsys", "geoip"));
+ metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_geoip);
+
+ sentry = metrics_store_add(the_store, rentry->type, rentry->name,
+ rentry->help);
+ metrics_store_entry_add_label(sentry,
+ metrics_format_label("subsys", "hsdir"));
+ metrics_store_entry_update(sentry, oom_stats_n_bytes_removed_hsdir);
+}
+
+/** Reset the global store and fill it with all the metrics from base_metrics
+ * and their associated values.
+ *
+ * To pull this off, every metrics has a "fill" function that is called and in
+ * charge of adding the metrics to the store, appropriate labels and finally
+ * updating the value to report. */
+static void
+fill_store(void)
+{
+ /* Reset the current store, we are about to fill it with all the things. */
+ metrics_store_reset(the_store);
+
+ /* Call the fill function for each metrics. */
+ for (size_t i = 0; i < num_base_metrics; i++) {
+ if (BUG(!base_metrics[i].fill_fn)) {
+ continue;
+ }
+ base_metrics[i].fill_fn();
+ }
+}
+
+/** Return a list of all the relay metrics stores. This is the
+ * function attached to the .get_metrics() member of the subsys_t. */
+const smartlist_t *
+relay_metrics_get_stores(void)
+{
+ /* We can't have the caller to free the returned list so keep it static,
+ * simply update it. */
+ static smartlist_t *stores_list = NULL;
+
+ /* We dynamically fill the store with all the metrics upon a request. The
+ * reason for this is because the exposed metrics of a relay are often
+ * internal counters in the fast path and thus we fetch the value when a
+ * metrics port request arrives instead of keeping a local metrics store of
+ * those values. */
+ fill_store();
+
+ if (!stores_list) {
+ stores_list = smartlist_new();
+ smartlist_add(stores_list, the_store);
+ }
+
+ return stores_list;
+}
+
+/** Initialize the relay metrics. */
+void
+relay_metrics_init(void)
+{
+ if (BUG(the_store)) {
+ return;
+ }
+ the_store = metrics_store_new();
+}
+
+/** Free the relay metrics. */
+void
+relay_metrics_free(void)
+{
+ if (!the_store) {
+ return;
+ }
+ /* NULL is set with this call. */
+ metrics_store_free(the_store);
+}
diff --git a/src/feature/relay/relay_metrics.h b/src/feature/relay/relay_metrics.h
new file mode 100644
index 0000000000..1d2d649d8a
--- /dev/null
+++ b/src/feature/relay/relay_metrics.h
@@ -0,0 +1,73 @@
+/* Copyright (c) 2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file relay_metrics.h
+ * @brief Header for feature/relay/relay_metrics.c
+ **/
+
+#ifndef TOR_FEATURE_RELAY_RELAY_METRICS_H
+#define TOR_FEATURE_RELAY_RELAY_METRICS_H
+
+#include "lib/container/smartlist.h"
+#include "lib/metrics/metrics_common.h"
+
+/** Metrics key for each reported metrics. This key is also used as an index in
+ * the base_metrics array. */
+typedef enum {
+ /** Number of OOM invocation. */
+ RELAY_METRICS_NUM_OOM_BYTES,
+ /** Number of onionskines handled. */
+ RELAY_METRICS_NUM_ONIONSKINS,
+ /** Number of sockets. */
+ RELAY_METRICS_NUM_SOCKETS,
+ /** Number of global connection rate limit. */
+ RELAY_METRICS_NUM_GLOBAL_RW_LIMIT,
+ /** Number of DNS queries. */
+ RELAY_METRICS_NUM_DNS,
+ /** Number of DNS query errors. */
+ RELAY_METRICS_NUM_DNS_ERRORS,
+ /** Number of TCP exhaustion reached. */
+ RELAY_METRICS_NUM_TCP_EXHAUSTION,
+ /** Connections counters (always going up). */
+ RELAY_METRICS_CONN_COUNTERS,
+ /** Connections gauges. */
+ RELAY_METRICS_CONN_GAUGES,
+ /** Number of streams. */
+ RELAY_METRICS_NUM_STREAMS,
+ /** Congestion control counters. */
+ RELAY_METRICS_CC_COUNTERS,
+ /** Congestion control gauges. */
+ RELAY_METRICS_CC_GAUGES,
+ /** Denial of Service defenses subsystem. */
+ RELAY_METRICS_NUM_DOS,
+ /** Denial of Service defenses subsystem. */
+ RELAY_METRICS_NUM_TRAFFIC,
+ /** Relay flags. */
+ RELAY_METRICS_RELAY_FLAGS,
+ /** Numer of circuits. */
+ RELAY_METRICS_NUM_CIRCUITS,
+} relay_metrics_key_t;
+
+/** The metadata of a relay metric. */
+typedef struct relay_metrics_entry_t {
+ /* Metric key used as a static array index. */
+ relay_metrics_key_t key;
+ /* Metric type. */
+ metrics_type_t type;
+ /* Metrics output name. */
+ const char *name;
+ /* Metrics output help comment. */
+ const char *help;
+ /* Update value function. */
+ void (*fill_fn)(void);
+} relay_metrics_entry_t;
+
+/* Init. */
+void relay_metrics_init(void);
+void relay_metrics_free(void);
+
+/* Accessors. */
+const smartlist_t *relay_metrics_get_stores(void);
+
+#endif /* !defined(TOR_FEATURE_RELAY_RELAY_METRICS_H) */
diff --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c
index a917d90f1a..dd9be4e36f 100644
--- a/src/feature/relay/relay_periodic.c
+++ b/src/feature/relay/relay_periodic.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -164,9 +164,7 @@ check_for_reachability_bw_callback(time_t now, const or_options_t *options)
(have_completed_a_circuit() || !any_predicted_circuits(now)) &&
!net_is_disabled()) {
if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
- router_do_reachability_checks(1, dirport_reachability_count==0);
- if (++dirport_reachability_count > 5)
- dirport_reachability_count = 0;
+ router_do_reachability_checks();
return EARLY_CHECK_REACHABILITY_INTERVAL;
} else {
/* If we haven't checked for 12 hours and our bandwidth estimate is
@@ -221,7 +219,7 @@ reachability_warnings_callback(time_t now, const or_options_t *options)
tor_asprintf(&where4, "%s:%d", address4, me->ipv4_orport);
if (!v6_ok)
tor_asprintf(&where6, "[%s]:%d", address6, me->ipv6_orport);
- const char *opt_and = (!v4_ok && !v6_ok) ? "and" : "";
+ const char *opt_and = (!v4_ok && !v6_ok) ? " and " : "";
/* IPv4 reachability test worked but not the IPv6. We will _not_
* publish the descriptor if our IPv6 was configured. We will if it
@@ -264,20 +262,6 @@ reachability_warnings_callback(time_t now, const or_options_t *options)
tor_free(address4);
tor_free(address6);
}
-
- if (me && !router_dirport_seems_reachable(options)) {
- char *address4 = tor_addr_to_str_dup(&me->ipv4_addr);
- log_warn(LD_CONFIG,
- "Your server (%s:%d) has not managed to confirm that its "
- "DirPort is reachable. Relays do not publish descriptors "
- "until their ORPort and DirPort are reachable. Please check "
- "your firewalls, ports, address, /etc/hosts file, etc.",
- address4, me->ipv4_dirport);
- control_event_server_status(LOG_WARN,
- "REACHABILITY_FAILED DIRADDRESS=%s:%d",
- address4, me->ipv4_dirport);
- tor_free(address4);
- }
}
return TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT;
diff --git a/src/feature/relay/relay_periodic.h b/src/feature/relay/relay_periodic.h
index ccda9a440b..d3a13ec835 100644
--- a/src/feature/relay/relay_periodic.h
+++ b/src/feature/relay/relay_periodic.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/relay_stub.c b/src/feature/relay/relay_stub.c
index 283aaf6e49..c7ac9093fa 100644
--- a/src/feature/relay/relay_stub.c
+++ b/src/feature/relay/relay_stub.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/relay_sys.c b/src/feature/relay/relay_sys.c
index 2e90740925..9c43734b84 100644
--- a/src/feature/relay/relay_sys.c
+++ b/src/feature/relay/relay_sys.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,6 +14,7 @@
#include "feature/relay/dns.h"
#include "feature/relay/ext_orport.h"
+#include "feature/relay/relay_metrics.h"
#include "feature/relay/onion_queue.h"
#include "feature/relay/relay_periodic.h"
#include "feature/relay/relay_sys.h"
@@ -25,6 +26,7 @@
static int
subsys_relay_initialize(void)
{
+ relay_metrics_init();
relay_register_periodic_events();
return 0;
}
@@ -37,6 +39,7 @@ subsys_relay_shutdown(void)
clear_pending_onions();
routerkeys_free_all();
router_free_all();
+ relay_metrics_free();
}
const struct subsys_fns_t sys_relay = {
@@ -46,4 +49,6 @@ const struct subsys_fns_t sys_relay = {
.level = RELAY_SUBSYS_LEVEL,
.initialize = subsys_relay_initialize,
.shutdown = subsys_relay_shutdown,
+
+ .get_metrics = relay_metrics_get_stores,
};
diff --git a/src/feature/relay/relay_sys.h b/src/feature/relay/relay_sys.h
index 9bad93a6c9..2c5edb53dd 100644
--- a/src/feature/relay/relay_sys.h
+++ b/src/feature/relay/relay_sys.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index fb26309dfa..bc98fd985c 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTER_PRIVATE
@@ -1357,8 +1357,8 @@ decide_to_advertise_dir_impl(const or_options_t *options,
int
router_should_advertise_dirport(const or_options_t *options, uint16_t dir_port)
{
- /* supports_tunnelled_dir_requests is not relevant, pass 0 */
- return decide_to_advertise_dir_impl(options, dir_port, 0) ? dir_port : 0;
+ /* Only authorities should advertise a DirPort now. */
+ return authdir_mode(options) ? dir_port : 0;
}
/** Front-end to decide_to_advertise_dir_impl(): return 0 if we don't want to
@@ -3062,6 +3062,15 @@ router_dump_router_to_string(routerinfo_t *router,
smartlist_add_strdup(chunks, "tunnelled-dir-server\n");
}
+ /* Overload general information. */
+ if (options->OverloadStatistics) {
+ char *overload_general = rep_hist_get_overload_general_line();
+
+ if (overload_general) {
+ smartlist_add(chunks, overload_general);
+ }
+ }
+
/* Sign the descriptor with Ed25519 */
if (emit_ed_sigs) {
smartlist_add_strdup(chunks, "router-sig-ed25519 ");
@@ -3345,6 +3354,11 @@ extrainfo_dump_to_string_stats_helper(smartlist_t *chunks,
"hidserv-stats-end", now, &contents) > 0) {
smartlist_add(chunks, contents);
}
+ if (options->HiddenServiceStatistics &&
+ load_stats_file("stats"PATH_SEPARATOR"hidserv-v3-stats",
+ "hidserv-v3-stats-end", now, &contents) > 0) {
+ smartlist_add(chunks, contents);
+ }
if (options->EntryStatistics &&
load_stats_file("stats"PATH_SEPARATOR"entry-stats",
"entry-stats-end", now, &contents) > 0) {
@@ -3370,6 +3384,12 @@ extrainfo_dump_to_string_stats_helper(smartlist_t *chunks,
if (contents)
smartlist_add(chunks, contents);
}
+ if (options->OverloadStatistics) {
+ contents = rep_hist_get_overload_stats_lines();
+ if (contents) {
+ smartlist_add(chunks, contents);
+ }
+ }
/* bridge statistics */
if (should_record_bridge_info(options)) {
const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now);
diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h
index 9556a66e68..b5b5a1fffa 100644
--- a/src/feature/relay/router.h
+++ b/src/feature/relay/router.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c
index 116f0b4e3d..64ec38ed19 100644
--- a/src/feature/relay/routerkeys.c
+++ b/src/feature/relay/routerkeys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/routerkeys.h b/src/feature/relay/routerkeys.h
index 1fb5d724e9..7b6d80773c 100644
--- a/src/feature/relay/routerkeys.h
+++ b/src/feature/relay/routerkeys.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2020, The Tor Project, Inc. */
+/* Copyright (c) 2014-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/routermode.c b/src/feature/relay/routermode.c
index c4d8792b5b..15f66de8ba 100644
--- a/src/feature/relay/routermode.c
+++ b/src/feature/relay/routermode.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/routermode.h b/src/feature/relay/routermode.h
index 6d7404968d..2c22c23c0f 100644
--- a/src/feature/relay/routermode.h
+++ b/src/feature/relay/routermode.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c
index 46b4b20ffc..399b6bca6e 100644
--- a/src/feature/relay/selftest.c
+++ b/src/feature/relay/selftest.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -49,15 +49,12 @@
static bool have_orport_for_family(int family);
static void inform_testing_reachability(const tor_addr_t *addr,
- uint16_t port,
- bool is_dirport);
+ uint16_t port);
/** Whether we can reach our IPv4 ORPort from the outside. */
static bool can_reach_or_port_ipv4 = false;
/** Whether we can reach our IPv6 ORPort from the outside. */
static bool can_reach_or_port_ipv6 = false;
-/** Whether we can reach our DirPort from the outside. */
-static bool can_reach_dir_port = false;
/** Has informed_testing_reachable logged a message about testing our IPv4
* ORPort? */
@@ -65,18 +62,14 @@ static bool have_informed_testing_or_port_ipv4 = false;
/** Has informed_testing_reachable logged a message about testing our IPv6
* ORPort? */
static bool have_informed_testing_or_port_ipv6 = false;
-/** Has informed_testing_reachable logged a message about testing our
- * DirPort? */
-static bool have_informed_testing_dir_port = false;
/** Forget what we have learned about our reachability status. */
void
router_reset_reachability(void)
{
- can_reach_or_port_ipv4 = can_reach_or_port_ipv6 = can_reach_dir_port = false;
+ can_reach_or_port_ipv4 = can_reach_or_port_ipv6 = false;
have_informed_testing_or_port_ipv4 =
- have_informed_testing_or_port_ipv6 =
- have_informed_testing_dir_port = false;
+ have_informed_testing_or_port_ipv6 = false;
}
/** Return 1 if we won't do reachability checks, because:
@@ -137,31 +130,20 @@ router_orport_seems_reachable(const or_options_t *options,
return true;
}
-/** Return 0 if we need to do a DirPort reachability check, because:
- * - no reachability check has been done yet, or
- * - we've initiated reachability checks, but none have succeeded.
- * Return 1 if we don't need to do a DirPort reachability check, because:
- * - we've seen a successful reachability check, or
- * - there is no DirPort set, or
- * - AssumeReachable is set, or
- * - We're a dir auth (see ticket #40287), or
- * - the network is disabled.
- */
+/** Relay DirPorts are no longer used (though authorities are). In either case,
+ * reachability self test is done anymore, since network re-entry towards an
+ * authority DirPort is not allowed. Thus, consider it always reachable. */
int
router_dirport_seems_reachable(const or_options_t *options)
{
- int reach_checks_disabled = router_reachability_checks_disabled(options) ||
- authdir_mode(options) ||
- !options->DirPort_set;
- return reach_checks_disabled ||
- can_reach_dir_port;
+ (void) options;
+ return 1;
}
-/** See if we currently believe our ORPort or DirPort to be
- * unreachable. If so, return 1 else return 0.
- */
+/** See if we currently believe our ORPort to be unreachable. If so, return 1
+ * else return 0. */
static int
-router_should_check_reachability(int test_or, int test_dir)
+router_should_check_reachability(void)
{
const routerinfo_t *me = router_get_my_routerinfo();
const or_options_t *options = get_options();
@@ -174,15 +156,13 @@ router_should_check_reachability(int test_or, int test_dir)
options->StrictNodes) {
/* If we've excluded ourself, and StrictNodes is set, we can't test
* ourself. */
- if (test_or || test_dir) {
#define SELF_EXCLUDED_WARN_INTERVAL 3600
- static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL);
- log_fn_ratelim(&warning_limit, LOG_WARN, LD_CIRC,
- "Can't perform self-tests for this relay: we have "
- "listed ourself in ExcludeNodes, and StrictNodes is set. "
- "We cannot learn whether we are usable, and will not "
- "be able to advertise ourself.");
- }
+ static ratelim_t warning_limit=RATELIM_INIT(SELF_EXCLUDED_WARN_INTERVAL);
+ log_fn_ratelim(&warning_limit, LOG_WARN, LD_CIRC,
+ "Can't perform self-tests for this relay: we have "
+ "listed ourself in ExcludeNodes, and StrictNodes is set. "
+ "We cannot learn whether we are usable, and will not "
+ "be able to advertise ourself.");
return 0;
}
return 1;
@@ -248,7 +228,10 @@ extend_info_from_router(const routerinfo_t *r, int family)
info = extend_info_new(r->nickname, r->cache_info.identity_digest,
ed_id_key,
rsa_pubkey, r->onion_curve25519_pkey,
- &ap.addr, ap.port);
+ &ap.addr, ap.port,
+ /* TODO-324: Should self-test circuits use
+ * congestion control? */
+ NULL, false);
crypto_pk_free(rsa_pubkey);
return info;
}
@@ -274,6 +257,11 @@ router_do_orport_reachability_checks(const routerinfo_t *me,
if (ei) {
const char *family_name = fmt_af_family(family);
const tor_addr_port_t *ap = extend_info_get_orport(ei, family);
+ if (BUG(!ap)) {
+ /* Not much we can do here to recover apart from screaming loudly. */
+ extend_info_free(ei);
+ return;
+ }
log_info(LD_CIRC, "Testing %s of my %s ORPort: %s.",
!orport_reachable ? "reachability" : "bandwidth",
family_name, fmt_addrport_ap(ap));
@@ -281,8 +269,8 @@ router_do_orport_reachability_checks(const routerinfo_t *me,
if (!orport_reachable) {
/* Only log if we are actually doing a reachability test to learn if our
* ORPort is reachable. Else, this prints a log notice if we are simply
- * opening a bandwidth testing circuit even do we are reachable. */
- inform_testing_reachability(&ap->addr, ap->port, false);
+ * opening a bandwidth testing circuit even though we are reachable. */
+ inform_testing_reachability(&ap->addr, ap->port);
}
circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
@@ -293,53 +281,15 @@ router_do_orport_reachability_checks(const routerinfo_t *me,
}
}
-/** Launch a self-testing circuit, and ask an exit to connect to our DirPort.
- * <b>me</b> is our own routerinfo.
+/** Some time has passed, or we just got new directory information. See if we
+ * currently believe our ORPort to be unreachable. If so, launch a new test
+ * for it.
*
- * Relays don't advertise IPv6 DirPorts, so this function only supports IPv4.
- *
- * See router_do_reachability_checks() for details. */
-static void
-router_do_dirport_reachability_checks(const routerinfo_t *me)
-{
- tor_addr_port_t my_dirport;
- tor_addr_copy(&my_dirport.addr, &me->ipv4_addr);
- my_dirport.port = me->ipv4_dirport;
-
- /* If there is already a pending connection, don't open another one. */
- if (!connection_get_by_type_addr_port_purpose(
- CONN_TYPE_DIR,
- &my_dirport.addr, my_dirport.port,
- DIR_PURPOSE_FETCH_SERVERDESC)) {
- /* ask myself, via tor, for my server descriptor. */
- directory_request_t *req =
- directory_request_new(DIR_PURPOSE_FETCH_SERVERDESC);
- directory_request_set_dir_addr_port(req, &my_dirport);
- directory_request_set_directory_id_digest(req,
- me->cache_info.identity_digest);
- /* ask via an anon circuit, connecting to our dirport. */
- directory_request_set_indirection(req, DIRIND_ANON_DIRPORT);
- directory_request_set_resource(req, "authority.z");
- directory_initiate_request(req);
- directory_request_free(req);
-
- inform_testing_reachability(&my_dirport.addr, my_dirport.port, true);
- }
-}
-
-/** Some time has passed, or we just got new directory information.
- * See if we currently believe our ORPort or DirPort to be
- * unreachable. If so, launch a new test for it.
- *
- * For ORPort, we simply try making a circuit that ends at ourselves.
- * Success is noticed in onionskin_answer().
- *
- * For DirPort, we make a connection via Tor to our DirPort and ask
- * for our own server descriptor.
- * Success is noticed in connection_dir_client_reached_eof().
+ * For ORPort, we simply try making a circuit that ends at ourselves. Success
+ * is noticed in onionskin_answer().
*/
void
-router_do_reachability_checks(int test_or, int test_dir)
+router_do_reachability_checks(void)
{
const routerinfo_t *me = router_get_my_routerinfo();
const or_options_t *options = get_options();
@@ -348,45 +298,34 @@ router_do_reachability_checks(int test_or, int test_dir)
int orport_reachable_v6 =
router_orport_seems_reachable(options, AF_INET6);
- if (router_should_check_reachability(test_or, test_dir)) {
+ if (router_should_check_reachability()) {
bool need_testing = !circuit_enough_testing_circs();
/* At the moment, tor relays believe that they are reachable when they
* receive any create cell on an inbound connection, if the address
* family is correct.
*/
- if (test_or && (!orport_reachable_v4 || need_testing)) {
+ if (!orport_reachable_v4 || need_testing) {
router_do_orport_reachability_checks(me, AF_INET, orport_reachable_v4);
}
- if (test_or && (!orport_reachable_v6 || need_testing)) {
+ if (!orport_reachable_v6 || need_testing) {
router_do_orport_reachability_checks(me, AF_INET6, orport_reachable_v6);
}
-
- if (test_dir && !router_dirport_seems_reachable(options)) {
- router_do_dirport_reachability_checks(me);
- }
}
}
/** Log a message informing the user that we are testing a port for
* reachability, if we have not already logged such a message.
*
- * If @a is_dirport is true, then the port is a DirPort; otherwise it is an
- * ORPort.
- *
* Calls to router_reset_reachability() will reset our view of whether we have
* logged this message for a given port. */
static void
-inform_testing_reachability(const tor_addr_t *addr,
- uint16_t port,
- bool is_dirport)
+inform_testing_reachability(const tor_addr_t *addr, uint16_t port)
{
if (!router_get_my_routerinfo())
return;
bool *have_informed_ptr;
- if (is_dirport) {
- have_informed_ptr = &have_informed_testing_dir_port;
- } else if (tor_addr_family(addr) == AF_INET) {
+ if (tor_addr_family(addr) == AF_INET) {
have_informed_ptr = &have_informed_testing_or_port_ipv4;
} else {
have_informed_ptr = &have_informed_testing_or_port_ipv6;
@@ -401,18 +340,16 @@ inform_testing_reachability(const tor_addr_t *addr,
char addr_buf[TOR_ADDRPORT_BUF_LEN];
strlcpy(addr_buf, fmt_addrport(addr, port), sizeof(addr_buf));
- const char *control_addr_type = is_dirport ? "DIRADDRESS" : "ORADDRESS";
- const char *port_type = is_dirport ? "DirPort" : "ORPort";
const char *afname = fmt_af_family(tor_addr_family(addr));
control_event_server_status(LOG_NOTICE,
- "CHECKING_REACHABILITY %s=%s",
- control_addr_type, addr_buf);
+ "CHECKING_REACHABILITY ORADDRESS=%s",
+ addr_buf);
- log_notice(LD_OR, "Now checking whether %s %s %s is reachable... "
+ log_notice(LD_OR, "Now checking whether %s ORPort %s is reachable... "
"(this may take up to %d minutes -- look for log "
"messages indicating success)",
- afname, port_type, addr_buf,
+ afname, addr_buf,
TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
*have_informed_ptr = true;
@@ -426,8 +363,7 @@ static bool
ready_to_publish(const or_options_t *options)
{
return options->PublishServerDescriptor_ != NO_DIRINFO &&
- router_dirport_seems_reachable(options) &&
- router_all_orports_seem_reachable(options);
+ router_all_orports_seem_reachable(options);
}
/** Annotate that we found our ORPort reachable with a given address
@@ -481,40 +417,6 @@ router_orport_found_reachable(int family)
}
}
-/** Annotate that we found our DirPort reachable. */
-void
-router_dirport_found_reachable(void)
-{
- const routerinfo_t *me = router_get_my_routerinfo();
- const or_options_t *options = get_options();
-
- if (!can_reach_dir_port && me) {
- char *address = tor_addr_to_str_dup(&me->ipv4_addr);
-
- if (!address)
- return;
-
- can_reach_dir_port = true;
- log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
- "from the outside. Excellent.%s",
- ready_to_publish(options) ?
- " Publishing server descriptor." : "");
-
- if (router_should_advertise_dirport(options, me->ipv4_dirport)) {
- mark_my_descriptor_dirty("DirPort found reachable");
- /* This is a significant enough change to upload immediately,
- * at least in a test network */
- if (options->TestingTorNetwork == 1) {
- reschedule_descriptor_update_check();
- }
- }
- control_event_server_status(LOG_NOTICE,
- "REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d",
- address, me->ipv4_dirport);
- tor_free(address);
- }
-}
-
/** We have enough testing circuits open. Send a bunch of "drop"
* cells down each of them, to exercise our bandwidth.
*
@@ -530,8 +432,8 @@ router_perform_bandwidth_test(int num_circs, time_t now)
origin_circuit_t *circ = NULL;
log_notice(LD_OR,"Performing bandwidth self-test...done.");
- while ((circ = circuit_get_next_by_pk_and_purpose(circ, NULL,
- CIRCUIT_PURPOSE_TESTING))) {
+ while ((circ = circuit_get_next_by_purpose(circ,
+ CIRCUIT_PURPOSE_TESTING))) {
/* dump cells_per_circuit drop cells onto this circ */
int i = cells_per_circuit;
if (circ->base_.state != CIRCUIT_STATE_OPEN)
diff --git a/src/feature/relay/selftest.h b/src/feature/relay/selftest.h
index e09c0e7898..b662fe0fb0 100644
--- a/src/feature/relay/selftest.h
+++ b/src/feature/relay/selftest.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,11 +23,10 @@ int router_orport_seems_reachable(
int router_dirport_seems_reachable(
const struct or_options_t *options);
-void router_do_reachability_checks(int test_or, int test_dir);
+void router_do_reachability_checks(void);
void router_perform_bandwidth_test(int num_circs, time_t now);
void router_orport_found_reachable(int family);
-void router_dirport_found_reachable(void);
void router_reset_reachability(void);
@@ -41,10 +40,8 @@ void router_reset_reachability(void);
((void)(opts), 0)
static inline void
-router_do_reachability_checks(int test_or, int test_dir)
+router_do_reachability_checks(void)
{
- (void)test_or;
- (void)test_dir;
tor_assert_nonfatal_unreached();
}
static inline void
@@ -55,16 +52,16 @@ router_perform_bandwidth_test(int num_circs, time_t now)
tor_assert_nonfatal_unreached();
}
static inline int
-inform_testing_reachability(void)
+inform_testing_reachability(const tor_addr_t *addr, uint16_t port)
{
+ (void) addr;
+ (void) port;
tor_assert_nonfatal_unreached();
return 0;
}
#define router_orport_found_reachable() \
STMT_NIL
-#define router_dirport_found_reachable() \
- STMT_NIL
#define router_reset_reachability() \
STMT_NIL
diff --git a/src/feature/relay/transport_config.c b/src/feature/relay/transport_config.c
index 7dcce70e30..23e024fbee 100644
--- a/src/feature/relay/transport_config.c
+++ b/src/feature/relay/transport_config.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/feature/relay/transport_config.h b/src/feature/relay/transport_config.h
index 6d956d9af1..6cf3142fb0 100644
--- a/src/feature/relay/transport_config.h
+++ b/src/feature/relay/transport_config.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-2020, The Tor Project, Inc. */
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**