aboutsummaryrefslogtreecommitdiff
path: root/src/feature/relay
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature/relay')
-rw-r--r--src/feature/relay/dns.c4
-rw-r--r--src/feature/relay/ext_orport.c3
-rw-r--r--src/feature/relay/onion_queue.c10
-rw-r--r--src/feature/relay/onion_queue.h2
-rw-r--r--src/feature/relay/relay_periodic.c308
-rw-r--r--src/feature/relay/relay_periodic.h18
-rw-r--r--src/feature/relay/relay_sys.c48
-rw-r--r--src/feature/relay/relay_sys.h17
-rw-r--r--src/feature/relay/router.c407
-rw-r--r--src/feature/relay/router.h23
-rw-r--r--src/feature/relay/routerkeys.c18
-rw-r--r--src/feature/relay/routerkeys.h4
-rw-r--r--src/feature/relay/selftest.c3
-rw-r--r--src/feature/relay/selftest.h2
14 files changed, 736 insertions, 131 deletions
diff --git a/src/feature/relay/dns.c b/src/feature/relay/dns.c
index feaf18e764..05b97e0ae2 100644
--- a/src/feature/relay/dns.c
+++ b/src/feature/relay/dns.c
@@ -59,7 +59,7 @@
#include "core/or/connection_edge.h"
#include "core/or/policies.h"
#include "core/or/relay.h"
-#include "feature/control/control.h"
+#include "feature/control/control_events.h"
#include "feature/relay/dns.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
@@ -1394,7 +1394,7 @@ configured_nameserver_address(const size_t idx)
return NULL;
}
-#endif
+#endif /* defined(HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR) */
/** 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
diff --git a/src/feature/relay/ext_orport.c b/src/feature/relay/ext_orport.c
index 8589efb48d..c343d19b8d 100644
--- a/src/feature/relay/ext_orport.c
+++ b/src/feature/relay/ext_orport.c
@@ -20,7 +20,7 @@
#include "core/or/or.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_or.h"
-#include "feature/control/control.h"
+#include "feature/control/control_events.h"
#include "app/config/config.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -659,4 +659,3 @@ ext_orport_free_all(void)
if (ext_or_auth_cookie) /* Free the auth cookie */
tor_free(ext_or_auth_cookie);
}
-
diff --git a/src/feature/relay/onion_queue.c b/src/feature/relay/onion_queue.c
index 696905cf5e..c37745cf33 100644
--- a/src/feature/relay/onion_queue.c
+++ b/src/feature/relay/onion_queue.c
@@ -212,10 +212,12 @@ num_ntors_per_tap(void)
#define MIN_NUM_NTORS_PER_TAP 1
#define MAX_NUM_NTORS_PER_TAP 100000
- return networkstatus_get_param(NULL, "NumNTorsPerTAP",
- DEFAULT_NUM_NTORS_PER_TAP,
- MIN_NUM_NTORS_PER_TAP,
- MAX_NUM_NTORS_PER_TAP);
+ 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
diff --git a/src/feature/relay/onion_queue.h b/src/feature/relay/onion_queue.h
index 0df921e057..cf478bc1a0 100644
--- a/src/feature/relay/onion_queue.h
+++ b/src/feature/relay/onion_queue.h
@@ -20,4 +20,4 @@ int onion_num_pending(uint16_t handshake_type);
void onion_pending_remove(or_circuit_t *circ);
void clear_pending_onions(void);
-#endif
+#endif /* !defined(TOR_ONION_QUEUE_H) */
diff --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c
new file mode 100644
index 0000000000..b48b495895
--- /dev/null
+++ b/src/feature/relay/relay_periodic.c
@@ -0,0 +1,308 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file relay_periodic.c
+ * @brief Periodic functions for the relay subsytem
+ **/
+
+#include "orconfig.h"
+#include "core/or/or.h"
+
+#include "core/mainloop/periodic.h"
+#include "core/mainloop/cpuworker.h" // XXXX use a pubsub event.
+#include "core/mainloop/mainloop.h"
+#include "core/mainloop/netstatus.h"
+#include "core/or/circuituse.h" // XXXX move have_performed_bandwidth_test
+
+#include "feature/relay/dns.h"
+#include "feature/relay/relay_periodic.h"
+#include "feature/relay/router.h"
+#include "feature/relay/routerkeys.h"
+#include "feature/relay/routermode.h"
+#include "feature/relay/selftest.h"
+#include "feature/stats/predict_ports.h"
+
+#include "lib/crypt_ops/crypto_rand.h"
+
+#include "feature/nodelist/routerinfo_st.h"
+#include "feature/control/control_events.h"
+
+#define DECLARE_EVENT(name, roles, flags) \
+ static periodic_event_item_t name ## _event = \
+ PERIODIC_EVENT(name, \
+ PERIODIC_EVENT_ROLE_##roles, \
+ flags)
+
+#define FL(name) (PERIODIC_EVENT_FLAG_##name)
+
+/**
+ * Periodic callback: If we're a server and initializing dns failed, retry.
+ */
+static int
+retry_dns_callback(time_t now, const or_options_t *options)
+{
+ (void)now;
+#define RETRY_DNS_INTERVAL (10*60)
+ if (server_mode(options) && has_dns_init_failed())
+ dns_init();
+ return RETRY_DNS_INTERVAL;
+}
+
+DECLARE_EVENT(retry_dns, ROUTER, 0);
+
+static int dns_honesty_first_time = 1;
+
+/**
+ * Periodic event: if we're an exit, see if our DNS server is telling us
+ * obvious lies.
+ */
+static int
+check_dns_honesty_callback(time_t now, const or_options_t *options)
+{
+ (void)now;
+ /* 9. and if we're an exit node, check whether our DNS is telling stories
+ * to us. */
+ if (net_is_disabled() ||
+ ! public_server_mode(options) ||
+ router_my_exit_policy_is_reject_star())
+ return PERIODIC_EVENT_NO_UPDATE;
+
+ if (dns_honesty_first_time) {
+ /* Don't launch right when we start */
+ dns_honesty_first_time = 0;
+ return crypto_rand_int_range(60, 180);
+ }
+
+ dns_launch_correctness_checks();
+ return 12*3600 + crypto_rand_int(12*3600);
+}
+
+DECLARE_EVENT(check_dns_honesty, RELAY, FL(NEED_NET));
+
+/* Periodic callback: rotate the onion keys after the period defined by the
+ * "onion-key-rotation-days" consensus parameter, shut down and restart all
+ * cpuworkers, and update our descriptor if necessary.
+ */
+static int
+rotate_onion_key_callback(time_t now, const or_options_t *options)
+{
+ if (server_mode(options)) {
+ int onion_key_lifetime = get_onion_key_lifetime();
+ time_t rotation_time = get_onion_key_set_at()+onion_key_lifetime;
+ if (rotation_time > now) {
+ return ONION_KEY_CONSENSUS_CHECK_INTERVAL;
+ }
+
+ log_info(LD_GENERAL,"Rotating onion key.");
+ rotate_onion_key();
+ cpuworkers_rotate_keyinfo();
+ if (router_rebuild_descriptor(1)<0) {
+ log_info(LD_CONFIG, "Couldn't rebuild router descriptor");
+ }
+ if (advertised_server_mode() && !net_is_disabled())
+ router_upload_dir_desc_to_dirservers(0);
+ return ONION_KEY_CONSENSUS_CHECK_INTERVAL;
+ }
+ return PERIODIC_EVENT_NO_UPDATE;
+}
+
+DECLARE_EVENT(rotate_onion_key, ROUTER, 0);
+
+/** Periodic callback: consider rebuilding or and re-uploading our descriptor
+ * (if we've passed our internal checks). */
+static int
+check_descriptor_callback(time_t now, const or_options_t *options)
+{
+/** How often do we check whether part of our router info has changed in a
+ * way that would require an upload? That includes checking whether our IP
+ * address has changed. */
+#define CHECK_DESCRIPTOR_INTERVAL (60)
+
+ (void)options;
+
+ /* 2b. Once per minute, regenerate and upload the descriptor if the old
+ * one is inaccurate. */
+ if (!net_is_disabled()) {
+ check_descriptor_bandwidth_changed(now);
+ check_descriptor_ipaddress_changed(now);
+ mark_my_descriptor_dirty_if_too_old(now);
+ consider_publishable_server(0);
+ }
+
+ return CHECK_DESCRIPTOR_INTERVAL;
+}
+
+DECLARE_EVENT(check_descriptor, ROUTER, FL(NEED_NET));
+
+static int dirport_reachability_count = 0;
+
+/**
+ * Periodic callback: check whether we're reachable (as a relay), and
+ * whether our bandwidth has changed enough that we need to
+ * publish a new descriptor.
+ */
+static int
+check_for_reachability_bw_callback(time_t now, const or_options_t *options)
+{
+ /* XXXX This whole thing was stuck in the middle of what is now
+ * XXXX check_descriptor_callback. I'm not sure it's right. */
+
+ /* also, check religiously for reachability, if it's within the first
+ * 20 minutes of our uptime. */
+ if (server_mode(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;
+ return 1;
+ } else {
+ /* If we haven't checked for 12 hours and our bandwidth estimate is
+ * low, do another bandwidth test. This is especially important for
+ * bridges, since they might go long periods without much use. */
+ const routerinfo_t *me = router_get_my_routerinfo();
+ static int first_time = 1;
+ if (!first_time && me &&
+ me->bandwidthcapacity < me->bandwidthrate &&
+ me->bandwidthcapacity < 51200) {
+ reset_bandwidth_test();
+ }
+ first_time = 0;
+#define BANDWIDTH_RECHECK_INTERVAL (12*60*60)
+ return BANDWIDTH_RECHECK_INTERVAL;
+ }
+ }
+ return CHECK_DESCRIPTOR_INTERVAL;
+}
+
+DECLARE_EVENT(check_for_reachability_bw, ROUTER, FL(NEED_NET));
+
+/**
+ * Callback: Send warnings if Tor doesn't find its ports reachable.
+ */
+static int
+reachability_warnings_callback(time_t now, const or_options_t *options)
+{
+ (void) now;
+
+ if (get_uptime() < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
+ return (int)(TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT - get_uptime());
+ }
+
+ if (server_mode(options) &&
+ !net_is_disabled() &&
+ have_completed_a_circuit()) {
+ /* every 20 minutes, check and complain if necessary */
+ const routerinfo_t *me = router_get_my_routerinfo();
+ if (me && !check_whether_orport_reachable(options)) {
+ char *address = tor_dup_ip(me->addr);
+ log_warn(LD_CONFIG,"Your server (%s:%d) has not managed to confirm that "
+ "its ORPort is reachable. Relays do not publish descriptors "
+ "until their ORPort and DirPort are reachable. Please check "
+ "your firewalls, ports, address, /etc/hosts file, etc.",
+ address, me->or_port);
+ control_event_server_status(LOG_WARN,
+ "REACHABILITY_FAILED ORADDRESS=%s:%d",
+ address, me->or_port);
+ tor_free(address);
+ }
+
+ if (me && !check_whether_dirport_reachable(options)) {
+ char *address = tor_dup_ip(me->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.",
+ address, me->dir_port);
+ control_event_server_status(LOG_WARN,
+ "REACHABILITY_FAILED DIRADDRESS=%s:%d",
+ address, me->dir_port);
+ tor_free(address);
+ }
+ }
+
+ return TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT;
+}
+
+DECLARE_EVENT(reachability_warnings, ROUTER, FL(NEED_NET));
+
+/* Periodic callback: Every 30 seconds, check whether it's time to make new
+ * Ed25519 subkeys.
+ */
+static int
+check_ed_keys_callback(time_t now, const or_options_t *options)
+{
+ if (server_mode(options)) {
+ if (should_make_new_ed_keys(options, now)) {
+ int new_signing_key = load_ed_keys(options, now);
+ if (new_signing_key < 0 ||
+ generate_ed_link_cert(options, now, new_signing_key > 0)) {
+ log_err(LD_OR, "Unable to update Ed25519 keys! Exiting.");
+ tor_shutdown_event_loop_and_exit(1);
+ }
+ }
+ return 30;
+ }
+ return PERIODIC_EVENT_NO_UPDATE;
+}
+
+DECLARE_EVENT(check_ed_keys, ROUTER, 0);
+
+/* Period callback: Check if our old onion keys are still valid after the
+ * period of time defined by the consensus parameter
+ * "onion-key-grace-period-days", otherwise expire them by setting them to
+ * NULL.
+ */
+static int
+check_onion_keys_expiry_time_callback(time_t now, const or_options_t *options)
+{
+ if (server_mode(options)) {
+ int onion_key_grace_period = get_onion_key_grace_period();
+ time_t expiry_time = get_onion_key_set_at()+onion_key_grace_period;
+ if (expiry_time > now) {
+ return ONION_KEY_CONSENSUS_CHECK_INTERVAL;
+ }
+
+ log_info(LD_GENERAL, "Expiring old onion keys.");
+ expire_old_onion_keys();
+ cpuworkers_rotate_keyinfo();
+ return ONION_KEY_CONSENSUS_CHECK_INTERVAL;
+ }
+
+ return PERIODIC_EVENT_NO_UPDATE;
+}
+
+DECLARE_EVENT(check_onion_keys_expiry_time, ROUTER, 0);
+
+void
+relay_register_periodic_events(void)
+{
+ periodic_events_register(&retry_dns_event);
+ periodic_events_register(&check_dns_honesty_event);
+ periodic_events_register(&rotate_onion_key_event);
+ periodic_events_register(&check_descriptor_event);
+ periodic_events_register(&check_for_reachability_bw_event);
+ periodic_events_register(&reachability_warnings_event);
+ periodic_events_register(&check_ed_keys_event);
+ periodic_events_register(&check_onion_keys_expiry_time_event);
+
+ dns_honesty_first_time = 1;
+ dirport_reachability_count = 0;
+}
+
+/**
+ * Update our schedule so that we'll check whether we need to update our
+ * descriptor immediately, rather than after up to CHECK_DESCRIPTOR_INTERVAL
+ * seconds.
+ */
+void
+reschedule_descriptor_update_check(void)
+{
+ periodic_event_reschedule(&check_descriptor_event);
+}
diff --git a/src/feature/relay/relay_periodic.h b/src/feature/relay/relay_periodic.h
new file mode 100644
index 0000000000..b6ea83c749
--- /dev/null
+++ b/src/feature/relay/relay_periodic.h
@@ -0,0 +1,18 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file relay_periodic.h
+ * @brief Header for feature/relay/relay_periodic.c
+ **/
+
+#ifndef TOR_FEATURE_RELAY_RELAY_PERIODIC_H
+#define TOR_FEATURE_RELAY_RELAY_PERIODIC_H
+
+void relay_register_periodic_events(void);
+void reschedule_descriptor_update_check(void);
+
+#endif /* !defined(TOR_FEATURE_RELAY_RELAY_PERIODIC_H) */
diff --git a/src/feature/relay/relay_sys.c b/src/feature/relay/relay_sys.c
new file mode 100644
index 0000000000..106e88b2a5
--- /dev/null
+++ b/src/feature/relay/relay_sys.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file relay_sys.c
+ * @brief Subsystem definitions for the relay module.
+ **/
+
+#include "orconfig.h"
+#include "core/or/or.h"
+
+#include "feature/relay/dns.h"
+#include "feature/relay/ext_orport.h"
+#include "feature/relay/onion_queue.h"
+#include "feature/relay/relay_periodic.h"
+#include "feature/relay/relay_sys.h"
+#include "feature/relay/routerkeys.h"
+#include "feature/relay/router.h"
+
+#include "lib/subsys/subsys.h"
+
+static int
+subsys_relay_initialize(void)
+{
+ relay_register_periodic_events();
+ return 0;
+}
+
+static void
+subsys_relay_shutdown(void)
+{
+ dns_free_all();
+ ext_orport_free_all();
+ clear_pending_onions();
+ routerkeys_free_all();
+ router_free_all();
+}
+
+const struct subsys_fns_t sys_relay = {
+ .name = "relay",
+ .supported = true,
+ .level = 50,
+ .initialize = subsys_relay_initialize,
+ .shutdown = subsys_relay_shutdown,
+};
diff --git a/src/feature/relay/relay_sys.h b/src/feature/relay/relay_sys.h
new file mode 100644
index 0000000000..32e21d90d8
--- /dev/null
+++ b/src/feature/relay/relay_sys.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file relay_sys.h
+ * @brief Header for feature/relay/relay_sys.c
+ **/
+
+#ifndef TOR_FEATURE_RELAY_RELAY_SYS_H
+#define TOR_FEATURE_RELAY_RELAY_SYS_H
+
+extern const struct subsys_fns_t sys_relay;
+
+#endif /* !defined(TOR_FEATURE_RELAY_RELAY_SYS_H) */
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index 12ee1dd6e2..29a8ffaa39 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -16,7 +16,7 @@
#include "core/or/policies.h"
#include "core/or/protover.h"
#include "feature/client/transports.h"
-#include "feature/control/control.h"
+#include "feature/control/control_events.h"
#include "feature/dirauth/process_descs.h"
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dirclient.h"
@@ -152,6 +152,8 @@ routerinfo_err_to_string(int err)
return "Cannot generate descriptor";
case TOR_ROUTERINFO_ERROR_DESC_REBUILDING:
return "Descriptor still rebuilding - not ready yet";
+ case TOR_ROUTERINFO_ERROR_INTERNAL_BUG:
+ return "Internal bug, see logs for details";
}
log_warn(LD_BUG, "unknown routerinfo error %d - shouldn't happen", err);
@@ -194,8 +196,8 @@ set_onion_key(crypto_pk_t *k)
/** Return the current onion key. Requires that the onion key has been
* loaded or generated. */
-crypto_pk_t *
-get_onion_key(void)
+MOCK_IMPL(crypto_pk_t *,
+get_onion_key,(void))
{
tor_assert(onionkey);
return onionkey;
@@ -242,7 +244,7 @@ expire_old_onion_keys(void)
lastonionkey = NULL;
}
- /* We zero out the keypair. See the tor_mem_is_zero() check made in
+ /* We zero out the keypair. See the fast_mem_is_zero() check made in
* construct_ntor_key_map() below. */
memset(&last_curve25519_onion_key, 0, sizeof(last_curve25519_onion_key));
@@ -269,11 +271,12 @@ expire_old_onion_keys(void)
/** Return the current secret onion key for the ntor handshake. Must only
* be called from the main thread. */
-static const curve25519_keypair_t *
-get_current_curve25519_keypair(void)
+MOCK_IMPL(STATIC const struct curve25519_keypair_t *,
+get_current_curve25519_keypair,(void))
{
return &curve25519_onion_key;
}
+
/** Return a map from KEYID (the key itself) to keypairs for use in the ntor
* handshake. Must only be called from the main thread. */
di_digest256_map_t *
@@ -284,12 +287,12 @@ construct_ntor_key_map(void)
const uint8_t *cur_pk = curve25519_onion_key.pubkey.public_key;
const uint8_t *last_pk = last_curve25519_onion_key.pubkey.public_key;
- if (!tor_mem_is_zero((const char *)cur_pk, CURVE25519_PUBKEY_LEN)) {
+ if (!fast_mem_is_zero((const char *)cur_pk, CURVE25519_PUBKEY_LEN)) {
dimap_add_entry(&m, cur_pk,
tor_memdup(&curve25519_onion_key,
sizeof(curve25519_keypair_t)));
}
- if (!tor_mem_is_zero((const char*)last_pk, CURVE25519_PUBKEY_LEN) &&
+ if (!fast_mem_is_zero((const char*)last_pk, CURVE25519_PUBKEY_LEN) &&
tor_memneq(cur_pk, last_pk, CURVE25519_PUBKEY_LEN)) {
dimap_add_entry(&m, last_pk,
tor_memdup(&last_curve25519_onion_key,
@@ -348,7 +351,7 @@ set_server_identity_key_digest_testing(const uint8_t *digest)
{
memcpy(server_identitykey_digest, digest, DIGEST_LEN);
}
-#endif
+#endif /* defined(TOR_UNIT_TESTS) */
/** Make sure that we have set up our identity keys to match or not match as
* appropriate, and die with an assertion if we have not. */
@@ -372,8 +375,8 @@ assert_identity_keys_ok(void)
/** Returns the current server identity key; requires that the key has
* been set, and that we are running as a Tor server.
*/
-crypto_pk_t *
-get_server_identity_key(void)
+MOCK_IMPL(crypto_pk_t *,
+get_server_identity_key,(void))
{
tor_assert(server_identitykey);
tor_assert(server_mode(get_options()));
@@ -1044,7 +1047,7 @@ init_keys(void)
return -1;
keydir = get_keydir_fname("secret_onion_key_ntor.old");
- if (tor_mem_is_zero((const char *)
+ if (fast_mem_is_zero((const char *)
last_curve25519_onion_key.pubkey.public_key,
CURVE25519_PUBKEY_LEN) &&
file_status(keydir) == FN_FILE) {
@@ -1939,26 +1942,33 @@ get_my_declared_family(const or_options_t *options)
return result;
}
-/** Build a fresh routerinfo, signed server descriptor, and extra-info document
- * for this OR. Set r to the generated routerinfo, e to the generated
- * extra-info document. Return 0 on success, -1 on temporary error. Failure to
- * generate an extra-info document is not an error and is indicated by setting
- * e to NULL. Caller is responsible for freeing generated documents if 0 is
- * returned.
+/** Allocate a fresh, unsigned routerinfo for this OR, without any of the
+ * fields that depend on the corresponding extrainfo.
+ *
+ * On success, set ri_out to the new routerinfo, and return 0.
+ * Caller is responsible for freeing the generated routerinfo.
+ *
+ * Returns a negative value and sets ri_out to NULL on temporary error.
*/
-int
-router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
+MOCK_IMPL(STATIC int,
+router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
{
- routerinfo_t *ri;
- extrainfo_t *ei;
+ routerinfo_t *ri = NULL;
uint32_t addr;
char platform[256];
int hibernating = we_are_hibernating();
const or_options_t *options = get_options();
+ int result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+
+ if (BUG(!ri_out)) {
+ result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+ goto err;
+ }
if (router_pick_published_address(options, &addr, 0) < 0) {
log_warn(LD_CONFIG, "Don't know my address while generating descriptor");
- return TOR_ROUTERINFO_ERROR_NO_EXT_ADDR;
+ result = TOR_ROUTERINFO_ERROR_NO_EXT_ADDR;
+ goto err;
}
/* Log a message if the address in the descriptor doesn't match the ORPort
@@ -2015,8 +2025,8 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key());
if (BUG(crypto_pk_get_digest(ri->identity_pkey,
ri->cache_info.identity_digest) < 0)) {
- routerinfo_free(ri);
- return TOR_ROUTERINFO_ERROR_DIGEST_FAILED;
+ result = TOR_ROUTERINFO_ERROR_DIGEST_FAILED;
+ goto err;
}
ri->cache_info.signing_key_cert =
tor_cert_dup(get_master_signing_key_cert());
@@ -2055,85 +2065,258 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
ri->declared_family = get_my_declared_family(options);
+ if (options->BridgeRelay) {
+ ri->purpose = ROUTER_PURPOSE_BRIDGE;
+ /* Bridges shouldn't be able to send their descriptors unencrypted,
+ anyway, since they don't have a DirPort, and always connect to the
+ bridge authority anonymously. But just in case they somehow think of
+ sending them on an unencrypted connection, don't allow them to try. */
+ ri->cache_info.send_unencrypted = 0;
+ } else {
+ ri->purpose = ROUTER_PURPOSE_GENERAL;
+ ri->cache_info.send_unencrypted = 1;
+ }
+
+ goto done;
+
+ err:
+ routerinfo_free(ri);
+ *ri_out = NULL;
+ return result;
+
+ done:
+ *ri_out = ri;
+ return 0;
+}
+
+/** Allocate and return a fresh, unsigned extrainfo for this OR, based on the
+ * routerinfo ri.
+ *
+ * Uses options->Nickname to set the nickname, and options->BridgeRelay to set
+ * ei->cache_info.send_unencrypted.
+ *
+ * If ri is NULL, logs a BUG() warning and returns NULL.
+ * Caller is responsible for freeing the generated extrainfo.
+ */
+static extrainfo_t *
+router_build_fresh_unsigned_extrainfo(const routerinfo_t *ri)
+{
+ extrainfo_t *ei = NULL;
+ const or_options_t *options = get_options();
+
+ if (BUG(!ri))
+ return NULL;
+
/* Now generate the extrainfo. */
ei = tor_malloc_zero(sizeof(extrainfo_t));
ei->cache_info.is_extrainfo = 1;
- strlcpy(ei->nickname, get_options()->Nickname, sizeof(ei->nickname));
+ strlcpy(ei->nickname, options->Nickname, sizeof(ei->nickname));
ei->cache_info.published_on = ri->cache_info.published_on;
ei->cache_info.signing_key_cert =
tor_cert_dup(get_master_signing_key_cert());
memcpy(ei->cache_info.identity_digest, ri->cache_info.identity_digest,
DIGEST_LEN);
+
+ if (options->BridgeRelay) {
+ /* See note in router_build_fresh_routerinfo(). */
+ ei->cache_info.send_unencrypted = 0;
+ } else {
+ ei->cache_info.send_unencrypted = 1;
+ }
+
+ return ei;
+}
+
+/** Dump the extrainfo descriptor body for ei, sign it, and add the body and
+ * signature to ei->cache_info. Note that the extrainfo body is determined by
+ * ei, and some additional config and statistics state: see
+ * extrainfo_dump_to_string() for details.
+ *
+ * Return 0 on success, -1 on temporary error.
+ * If ei is NULL, logs a BUG() warning and returns -1.
+ * On error, ei->cache_info is not modified.
+ */
+static int
+router_dump_and_sign_extrainfo_descriptor_body(extrainfo_t *ei)
+{
+ if (BUG(!ei))
+ return -1;
+
if (extrainfo_dump_to_string(&ei->cache_info.signed_descriptor_body,
ei, get_server_identity_key(),
get_master_signing_keypair()) < 0) {
log_warn(LD_BUG, "Couldn't generate extra-info descriptor.");
- extrainfo_free(ei);
- ei = NULL;
- } else {
- ei->cache_info.signed_descriptor_len =
- strlen(ei->cache_info.signed_descriptor_body);
- router_get_extrainfo_hash(ei->cache_info.signed_descriptor_body,
- ei->cache_info.signed_descriptor_len,
- ei->cache_info.signed_descriptor_digest);
- crypto_digest256((char*) ei->digest256,
- ei->cache_info.signed_descriptor_body,
- ei->cache_info.signed_descriptor_len,
- DIGEST_SHA256);
+ return -1;
}
- /* Now finish the router descriptor. */
- if (ei) {
- memcpy(ri->cache_info.extra_info_digest,
- ei->cache_info.signed_descriptor_digest,
- DIGEST_LEN);
- memcpy(ri->cache_info.extra_info_digest256,
- ei->digest256,
- DIGEST256_LEN);
- } else {
- /* ri was allocated with tor_malloc_zero, so there is no need to
- * zero ri->cache_info.extra_info_digest here. */
+ ei->cache_info.signed_descriptor_len =
+ strlen(ei->cache_info.signed_descriptor_body);
+
+ router_get_extrainfo_hash(ei->cache_info.signed_descriptor_body,
+ ei->cache_info.signed_descriptor_len,
+ ei->cache_info.signed_descriptor_digest);
+ crypto_digest256((char*) ei->digest256,
+ ei->cache_info.signed_descriptor_body,
+ ei->cache_info.signed_descriptor_len,
+ DIGEST_SHA256);
+
+ return 0;
+}
+
+/** Allocate and return a fresh, signed extrainfo for this OR, based on the
+ * routerinfo ri.
+ *
+ * If ri is NULL, logs a BUG() warning and returns NULL.
+ * Caller is responsible for freeing the generated extrainfo.
+ */
+STATIC extrainfo_t *
+router_build_fresh_signed_extrainfo(const routerinfo_t *ri)
+{
+ int result = -1;
+ extrainfo_t *ei = NULL;
+
+ if (BUG(!ri))
+ return NULL;
+
+ ei = router_build_fresh_unsigned_extrainfo(ri);
+ /* router_build_fresh_unsigned_extrainfo() should not fail. */
+ if (BUG(!ei))
+ goto err;
+
+ result = router_dump_and_sign_extrainfo_descriptor_body(ei);
+ if (result < 0)
+ goto err;
+
+ goto done;
+
+ err:
+ extrainfo_free(ei);
+ return NULL;
+
+ done:
+ return ei;
+}
+
+/** Set the fields in ri that depend on ei.
+ *
+ * If ei is NULL, logs a BUG() warning and zeroes the relevant fields.
+ */
+STATIC void
+router_update_routerinfo_from_extrainfo(routerinfo_t *ri,
+ const extrainfo_t *ei)
+{
+ if (BUG(!ei)) {
+ /* Just to be safe, zero ri->cache_info.extra_info_digest here. */
+ memset(ri->cache_info.extra_info_digest, 0, DIGEST_LEN);
+ memset(ri->cache_info.extra_info_digest256, 0, DIGEST256_LEN);
+ return;
}
+
+ /* Now finish the router descriptor. */
+ memcpy(ri->cache_info.extra_info_digest,
+ ei->cache_info.signed_descriptor_digest,
+ DIGEST_LEN);
+ memcpy(ri->cache_info.extra_info_digest256,
+ ei->digest256,
+ DIGEST256_LEN);
+}
+
+/** Dump the descriptor body for ri, sign it, and add the body and signature to
+ * ri->cache_info. Note that the descriptor body is determined by ri, and some
+ * additional config and state: see router_dump_router_to_string() for details.
+ *
+ * Return 0 on success, and a negative value on temporary error.
+ * If ri is NULL, logs a BUG() warning and returns a negative value.
+ * On error, ri->cache_info is not modified.
+ */
+STATIC int
+router_dump_and_sign_routerinfo_descriptor_body(routerinfo_t *ri)
+{
+ if (BUG(!ri))
+ return TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+
if (! (ri->cache_info.signed_descriptor_body =
router_dump_router_to_string(ri, get_server_identity_key(),
get_onion_key(),
get_current_curve25519_keypair(),
get_master_signing_keypair())) ) {
log_warn(LD_BUG, "Couldn't generate router descriptor.");
- routerinfo_free(ri);
- extrainfo_free(ei);
return TOR_ROUTERINFO_ERROR_CANNOT_GENERATE;
}
+
ri->cache_info.signed_descriptor_len =
strlen(ri->cache_info.signed_descriptor_body);
- ri->purpose =
- options->BridgeRelay ? ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL;
- if (options->BridgeRelay) {
- /* Bridges shouldn't be able to send their descriptors unencrypted,
- anyway, since they don't have a DirPort, and always connect to the
- bridge authority anonymously. But just in case they somehow think of
- sending them on an unencrypted connection, don't allow them to try. */
- ri->cache_info.send_unencrypted = 0;
- if (ei)
- ei->cache_info.send_unencrypted = 0;
- } else {
- ri->cache_info.send_unencrypted = 1;
- if (ei)
- ei->cache_info.send_unencrypted = 1;
- }
-
router_get_router_hash(ri->cache_info.signed_descriptor_body,
strlen(ri->cache_info.signed_descriptor_body),
ri->cache_info.signed_descriptor_digest);
+ return 0;
+}
+
+/** Build a fresh routerinfo, signed server descriptor, and signed extrainfo
+ * document for this OR.
+ *
+ * Set r to the generated routerinfo, e to the generated extrainfo document.
+ * Failure to generate an extra-info document is not an error and is indicated
+ * by setting e to NULL.
+ * Return 0 on success, and a negative value on temporary error.
+ * Caller is responsible for freeing generated documents on success.
+ */
+int
+router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
+{
+ int result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+ routerinfo_t *ri = NULL;
+ extrainfo_t *ei = NULL;
+
+ if (BUG(!r))
+ goto err;
+
+ if (BUG(!e))
+ goto err;
+
+ result = router_build_fresh_unsigned_routerinfo(&ri);
+ if (result < 0) {
+ goto err;
+ }
+ /* If ri is NULL, then result should be negative. So this check should be
+ * unreachable. */
+ if (BUG(!ri)) {
+ result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+ goto err;
+ }
+
+ ei = router_build_fresh_signed_extrainfo(ri);
+
+ /* Failing to create an ei is not an error. */
+ if (ei) {
+ router_update_routerinfo_from_extrainfo(ri, ei);
+ }
+
+ result = router_dump_and_sign_routerinfo_descriptor_body(ri);
+ if (result < 0)
+ goto err;
+
if (ei) {
- tor_assert(!
- routerinfo_incompatible_with_extrainfo(ri->identity_pkey, ei,
- &ri->cache_info, NULL));
+ if (BUG(routerinfo_incompatible_with_extrainfo(ri->identity_pkey, ei,
+ &ri->cache_info, NULL))) {
+ result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+ goto err;
+ }
}
+ goto done;
+
+ err:
+ routerinfo_free(ri);
+ extrainfo_free(ei);
+ *r = NULL;
+ *e = NULL;
+ return result;
+
+ done:
*r = ri;
*e = ei;
return 0;
@@ -2476,6 +2659,10 @@ get_platform_str(char *platform, size_t len)
/** OR only: Given a routerinfo for this router, and an identity key to sign
* with, encode the routerinfo as a signed server descriptor and return a new
* string encoding the result, or NULL on failure.
+ *
+ * In addition to the fields in router, this function calls
+ * onion_key_lifetime(), get_options(), and we_are_hibernating(), and uses the
+ * results to populate some fields in the descriptor.
*/
char *
router_dump_router_to_string(routerinfo_t *router,
@@ -2539,11 +2726,8 @@ router_dump_router_to_string(routerinfo_t *router,
log_err(LD_BUG,"Couldn't base64-encode signing key certificate!");
goto err;
}
- if (ed25519_public_to_base64(ed_fp_base64,
- &router->cache_info.signing_key_cert->signing_key)<0) {
- log_err(LD_BUG,"Couldn't base64-encode identity key\n");
- goto err;
- }
+ ed25519_public_to_base64(ed_fp_base64,
+ &router->cache_info.signing_key_cert->signing_key);
tor_asprintf(&ed_cert_line, "identity-ed25519\n"
"-----BEGIN ED25519 CERT-----\n"
"%s"
@@ -2788,8 +2972,7 @@ router_dump_router_to_string(routerinfo_t *router,
if (ed25519_sign(&sig, (const uint8_t*)digest, DIGEST256_LEN,
signing_keypair) < 0)
goto err;
- if (ed25519_signature_to_base64(buf, &sig) < 0)
- goto err;
+ ed25519_signature_to_base64(buf, &sig);
smartlist_add_asprintf(chunks, "%s\n", buf);
}
@@ -2928,9 +3111,14 @@ load_stats_file(const char *filename, const char *end_line, time_t now,
return r;
}
-/** Write the contents of <b>extrainfo</b> and aggregated statistics to
- * *<b>s_out</b>, signing them with <b>ident_key</b>. Return 0 on
- * success, negative on failure. */
+/** Write the contents of <b>extrainfo</b>, to * *<b>s_out</b>, signing them
+ * with <b>ident_key</b>.
+ *
+ * If ExtraInfoStatistics is 1, also write aggregated statistics and related
+ * configuration data before signing. Most statistics also have an option that
+ * enables or disables that particular statistic.
+ *
+ * Return 0 on success, negative on failure. */
int
extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
crypto_pk_t *ident_key,
@@ -2940,7 +3128,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
char identity[HEX_DIGEST_LEN+1];
char published[ISO_TIME_LEN+1];
char digest[DIGEST_LEN];
- char *bandwidth_usage;
int result;
static int write_stats_to_extrainfo = 1;
char sig[DIROBJ_MAX_SIG_LEN+1];
@@ -2955,7 +3142,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
base16_encode(identity, sizeof(identity),
extrainfo->cache_info.identity_digest, DIGEST_LEN);
format_iso_time(published, extrainfo->cache_info.published_on);
- bandwidth_usage = rep_hist_get_bandwidth_lines();
if (emit_ed_sigs) {
if (!extrainfo->cache_info.signing_key_cert->signing_key_included ||
!ed25519_pubkey_eq(&extrainfo->cache_info.signing_key_cert->signed_key,
@@ -2981,21 +3167,35 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
ed_cert_line = tor_strdup("");
}
- tor_asprintf(&pre, "extra-info %s %s\n%spublished %s\n%s",
+ tor_asprintf(&pre, "extra-info %s %s\n%spublished %s\n",
extrainfo->nickname, identity,
ed_cert_line,
- published, bandwidth_usage);
+ published);
smartlist_add(chunks, pre);
- if (geoip_is_loaded(AF_INET))
- smartlist_add_asprintf(chunks, "geoip-db-digest %s\n",
- geoip_db_digest(AF_INET));
- if (geoip_is_loaded(AF_INET6))
- smartlist_add_asprintf(chunks, "geoip6-db-digest %s\n",
- geoip_db_digest(AF_INET6));
+ /* Add information about the pluggable transports we support, even if we
+ * are not publishing statistics. This information is needed by BridgeDB
+ * to distribute bridges. */
+ if (options->ServerTransportPlugin) {
+ char *pluggable_transports = pt_get_extra_info_descriptor_string();
+ if (pluggable_transports)
+ smartlist_add(chunks, pluggable_transports);
+ }
if (options->ExtraInfoStatistics && write_stats_to_extrainfo) {
log_info(LD_GENERAL, "Adding stats to extra-info descriptor.");
+ /* Bandwidth usage stats don't have their own option */
+ {
+ contents = rep_hist_get_bandwidth_lines();
+ smartlist_add(chunks, contents);
+ }
+ /* geoip hashes aren't useful unless we are publishing other stats */
+ if (geoip_is_loaded(AF_INET))
+ smartlist_add_asprintf(chunks, "geoip-db-digest %s\n",
+ geoip_db_digest(AF_INET));
+ if (geoip_is_loaded(AF_INET6))
+ smartlist_add_asprintf(chunks, "geoip6-db-digest %s\n",
+ geoip_db_digest(AF_INET6));
if (options->DirReqStatistics &&
load_stats_file("stats"PATH_SEPARATOR"dirreq-stats",
"dirreq-stats-end", now, &contents) > 0) {
@@ -3031,19 +3231,12 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
if (contents)
smartlist_add(chunks, contents);
}
- }
-
- /* Add information about the pluggable transports we support. */
- if (options->ServerTransportPlugin) {
- char *pluggable_transports = pt_get_extra_info_descriptor_string();
- if (pluggable_transports)
- smartlist_add(chunks, pluggable_transports);
- }
-
- if (should_record_bridge_info(options) && write_stats_to_extrainfo) {
- const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now);
- if (bridge_stats) {
- smartlist_add_strdup(chunks, bridge_stats);
+ /* bridge statistics */
+ if (should_record_bridge_info(options)) {
+ const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now);
+ if (bridge_stats) {
+ smartlist_add_strdup(chunks, bridge_stats);
+ }
}
}
@@ -3058,8 +3251,7 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
if (ed25519_sign(&ed_sig, (const uint8_t*)sha256_digest, DIGEST256_LEN,
signing_keypair) < 0)
goto err;
- if (ed25519_signature_to_base64(buf, &ed_sig) < 0)
- goto err;
+ ed25519_signature_to_base64(buf, &ed_sig);
smartlist_add_asprintf(chunks, "%s\n", buf);
}
@@ -3137,7 +3329,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
tor_free(s_dup);
tor_free(ed_cert_line);
extrainfo_free(ei_tmp);
- tor_free(bandwidth_usage);
return result;
}
@@ -3162,6 +3353,10 @@ router_free_all(void)
crypto_pk_free(server_identitykey);
crypto_pk_free(client_identitykey);
+ /* Destroying a locked mutex is undefined behaviour. This mutex may be
+ * locked, because multiple threads can access it. But we need to destroy
+ * it, otherwise re-initialisation will trigger undefined behaviour.
+ * See #31735 for details. */
tor_mutex_free(key_lock);
routerinfo_free(desc_routerinfo);
extrainfo_free(desc_extrainfo);
diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h
index 60bc857ceb..55b9ef9e68 100644
--- a/src/feature/relay/router.h
+++ b/src/feature/relay/router.h
@@ -23,11 +23,12 @@ struct ed25519_keypair_t;
#define TOR_ROUTERINFO_ERROR_DIGEST_FAILED (-4)
#define TOR_ROUTERINFO_ERROR_CANNOT_GENERATE (-5)
#define TOR_ROUTERINFO_ERROR_DESC_REBUILDING (-6)
+#define TOR_ROUTERINFO_ERROR_INTERNAL_BUG (-7)
-crypto_pk_t *get_onion_key(void);
+MOCK_DECL(crypto_pk_t *,get_onion_key,(void));
time_t get_onion_key_set_at(void);
void set_server_identity_key(crypto_pk_t *k);
-crypto_pk_t *get_server_identity_key(void);
+MOCK_DECL(crypto_pk_t *,get_server_identity_key,(void));
int server_identity_key_is_set(void);
void set_client_identity_key(crypto_pk_t *k);
crypto_pk_t *get_tlsclient_identity_key(void);
@@ -114,7 +115,7 @@ void router_reset_reachability(void);
void router_free_all(void);
#ifdef ROUTER_PRIVATE
-/* Used only by router.c and test.c */
+/* Used only by router.c and the unit tests */
STATIC void get_platform_str(char *platform, size_t len);
STATIC int router_write_fingerprint(int hashed);
STATIC smartlist_t *get_my_declared_family(const or_options_t *options);
@@ -123,8 +124,18 @@ STATIC smartlist_t *get_my_declared_family(const or_options_t *options);
extern time_t desc_clean_since;
extern const char *desc_dirty_reason;
void set_server_identity_key_digest_testing(const uint8_t *digest);
-#endif
-
-#endif
+MOCK_DECL(STATIC const struct curve25519_keypair_t *,
+ get_current_curve25519_keypair,(void));
+
+MOCK_DECL(STATIC int,
+ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out));
+STATIC extrainfo_t *router_build_fresh_signed_extrainfo(
+ const routerinfo_t *ri);
+STATIC void router_update_routerinfo_from_extrainfo(routerinfo_t *ri,
+ const extrainfo_t *ei);
+STATIC int router_dump_and_sign_routerinfo_descriptor_body(routerinfo_t *ri);
+#endif /* defined(TOR_UNIT_TESTS) */
+
+#endif /* defined(ROUTER_PRIVATE) */
#endif /* !defined(TOR_ROUTER_H) */
diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c
index f639fc91e7..a9190b2e13 100644
--- a/src/feature/relay/routerkeys.c
+++ b/src/feature/relay/routerkeys.c
@@ -226,7 +226,7 @@ load_ed_keys(const or_options_t *options, time_t now)
tor_free(fname);
}
}
- if (tor_mem_is_zero((char*)id->seckey.seckey, sizeof(id->seckey)))
+ if (safe_mem_is_zero((char*)id->seckey.seckey, sizeof(id->seckey)))
sign_signing_key_with_id = NULL;
else
sign_signing_key_with_id = id;
@@ -631,14 +631,14 @@ get_master_identity_keypair(void)
}
#endif /* defined(TOR_UNIT_TESTS) */
-const ed25519_keypair_t *
-get_master_signing_keypair(void)
+MOCK_IMPL(const ed25519_keypair_t *,
+get_master_signing_keypair,(void))
{
return master_signing_key;
}
-const struct tor_cert_st *
-get_master_signing_key_cert(void)
+MOCK_IMPL(const struct tor_cert_st *,
+get_master_signing_key_cert,(void))
{
return signing_key_cert;
}
@@ -706,6 +706,8 @@ make_tap_onion_key_crosscert(const crypto_pk_t *onion_key,
*len_out = 0;
if (crypto_pk_get_digest(rsa_id_key, (char*)signed_data) < 0) {
+ log_info(LD_OR, "crypto_pk_get_digest failed in "
+ "make_tap_onion_key_crosscert!");
return NULL;
}
memcpy(signed_data + DIGEST_LEN, master_id_key->pubkey, ED25519_PUBKEY_LEN);
@@ -713,8 +715,12 @@ make_tap_onion_key_crosscert(const crypto_pk_t *onion_key,
int r = crypto_pk_private_sign(onion_key,
(char*)signature, sizeof(signature),
(const char*)signed_data, sizeof(signed_data));
- if (r < 0)
+ if (r < 0) {
+ /* It's probably missing the private key */
+ log_info(LD_OR, "crypto_pk_private_sign failed in "
+ "make_tap_onion_key_crosscert!");
return NULL;
+ }
*len_out = r;
diff --git a/src/feature/relay/routerkeys.h b/src/feature/relay/routerkeys.h
index 0badd34191..cde07b52c3 100644
--- a/src/feature/relay/routerkeys.h
+++ b/src/feature/relay/routerkeys.h
@@ -7,8 +7,8 @@
#include "lib/crypt_ops/crypto_ed25519.h"
const ed25519_public_key_t *get_master_identity_key(void);
-const ed25519_keypair_t *get_master_signing_keypair(void);
-const struct tor_cert_st *get_master_signing_key_cert(void);
+MOCK_DECL(const ed25519_keypair_t *, get_master_signing_keypair,(void));
+MOCK_DECL(const struct tor_cert_st *, get_master_signing_key_cert,(void));
const ed25519_keypair_t *get_current_auth_keypair(void);
const struct tor_cert_st *get_current_link_cert_cert(void);
diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c
index 064eea6c46..f8b54ff45d 100644
--- a/src/feature/relay/selftest.c
+++ b/src/feature/relay/selftest.c
@@ -26,7 +26,7 @@
#include "core/or/crypt_path_st.h"
#include "core/or/origin_circuit_st.h"
#include "core/or/relay.h"
-#include "feature/control/control.h"
+#include "feature/control/control_events.h"
#include "feature/dirclient/dirclient.h"
#include "feature/dircommon/directory.h"
#include "feature/nodelist/authority_cert_st.h"
@@ -35,6 +35,7 @@
#include "feature/nodelist/routerlist.h" // but...
#include "feature/nodelist/routerset.h"
#include "feature/nodelist/torcert.h"
+#include "feature/relay/relay_periodic.h"
#include "feature/relay/router.h"
#include "feature/relay/selftest.h"
diff --git a/src/feature/relay/selftest.h b/src/feature/relay/selftest.h
index a80ec8936e..aea77ec791 100644
--- a/src/feature/relay/selftest.h
+++ b/src/feature/relay/selftest.h
@@ -21,4 +21,4 @@ void router_orport_found_reachable(void);
void router_dirport_found_reachable(void);
void router_perform_bandwidth_test(int num_circs, time_t now);
-#endif
+#endif /* !defined(TOR_SELFTEST_H) */