aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app/config/config.c14
-rw-r--r--src/app/config/or_options_st.h3
-rw-r--r--src/app/config/statefile.c2
-rw-r--r--src/app/main/shutdown.c3
-rw-r--r--src/app/main/subsystem_list.c18
-rw-r--r--src/core/crypto/hs_ntor.c44
-rw-r--r--src/core/crypto/hs_ntor.h21
-rw-r--r--src/core/mainloop/connection.c11
-rw-r--r--src/core/mainloop/mainloop.c1
-rw-r--r--src/core/or/channel.c10
-rw-r--r--src/core/or/channeltls.c1
-rw-r--r--src/core/or/circuitbuild.c4
-rw-r--r--src/core/or/circuitbuild.h3
-rw-r--r--src/core/or/circuitlist.c4
-rw-r--r--src/core/or/circuitmux.c4
-rw-r--r--src/core/or/circuitmux_ewma.c4
-rw-r--r--src/core/or/circuituse.c2
-rw-r--r--src/core/or/connection_edge.c19
-rw-r--r--src/core/or/connection_edge.h15
-rw-r--r--src/core/or/connection_or.c607
-rw-r--r--src/core/or/connection_or.h14
-rw-r--r--src/core/or/dos.c4
-rw-r--r--src/core/or/dos.h3
-rw-r--r--src/core/or/include.am2
-rw-r--r--src/core/or/ocirc_event.c11
-rw-r--r--src/core/or/ocirc_event_sys.h13
-rw-r--r--src/core/or/or_sys.c12
-rw-r--r--src/core/or/or_sys.h4
-rw-r--r--src/core/or/orconn_event.c11
-rw-r--r--src/core/or/orconn_event_sys.h12
-rw-r--r--src/core/or/policies.c21
-rw-r--r--src/core/or/policies.h1
-rw-r--r--src/core/or/protover.c8
-rw-r--r--src/core/or/scheduler.c75
-rw-r--r--src/core/or/scheduler_kist.c15
-rw-r--r--src/core/or/status.c3
-rw-r--r--src/core/proto/proto_ext_or.h7
-rw-r--r--src/ext/ht.h10
-rw-r--r--src/feature/client/addressmap.c3
-rw-r--r--src/feature/client/bridges.c3
-rw-r--r--src/feature/client/entrynodes.c2
-rw-r--r--src/feature/client/transports.c6
-rw-r--r--src/feature/control/btrack.c2
-rw-r--r--src/feature/control/btrack_orconn_maps.c9
-rw-r--r--src/feature/control/control_bootstrap.c6
-rw-r--r--src/feature/control/control_cmd.c4
-rw-r--r--src/feature/control/control_events.h7
-rw-r--r--src/feature/dirauth/dirauth_config.c4
-rw-r--r--src/feature/dirauth/dircollate.c5
-rw-r--r--src/feature/dirauth/dirvote.c100
-rw-r--r--src/feature/dirauth/dirvote.h37
-rw-r--r--src/feature/dirauth/include.am6
-rw-r--r--src/feature/dirauth/keypin.c8
-rw-r--r--src/feature/dirauth/shared_random.c4
-rw-r--r--src/feature/dirauth/shared_random_state.c8
-rw-r--r--src/feature/dirauth/voting_schedule.c (renamed from src/feature/dircommon/voting_schedule.c)113
-rw-r--r--src/feature/dirauth/voting_schedule.h (renamed from src/feature/dircommon/voting_schedule.h)39
-rw-r--r--src/feature/dircache/conscache.c15
-rw-r--r--src/feature/dircache/consdiffmgr.c4
-rw-r--r--src/feature/dircache/dircache.c2
-rw-r--r--src/feature/dirclient/dirclient.c56
-rw-r--r--src/feature/dirclient/dirclient.h2
-rw-r--r--src/feature/dircommon/fp_pair.c5
-rw-r--r--src/feature/dircommon/include.am6
-rw-r--r--src/feature/dirparse/authcert_members.h2
-rw-r--r--src/feature/dirparse/authcert_parse.c2
-rw-r--r--src/feature/dirparse/microdesc_parse.c2
-rw-r--r--src/feature/dirparse/ns_parse.c8
-rw-r--r--src/feature/dirparse/routerparse.c4
-rw-r--r--src/feature/hs/hs_cache.c64
-rw-r--r--src/feature/hs/hs_cell.c138
-rw-r--r--src/feature/hs/hs_cell.h15
-rw-r--r--src/feature/hs/hs_circuit.c57
-rw-r--r--src/feature/hs/hs_circuit.h11
-rw-r--r--src/feature/hs/hs_circuitmap.c4
-rw-r--r--src/feature/hs/hs_client.c11
-rw-r--r--src/feature/hs/hs_common.c50
-rw-r--r--src/feature/hs/hs_common.h7
-rw-r--r--src/feature/hs/hs_config.c25
-rw-r--r--src/feature/hs/hs_descriptor.c26
-rw-r--r--src/feature/hs/hs_descriptor.h7
-rw-r--r--src/feature/hs/hs_ob.c408
-rw-r--r--src/feature/hs/hs_ob.h40
-rw-r--r--src/feature/hs/hs_service.c130
-rw-r--r--src/feature/hs/hs_service.h18
-rw-r--r--src/feature/hs/include.am2
-rw-r--r--src/feature/hs_common/shared_random_client.c82
-rw-r--r--src/feature/hs_common/shared_random_client.h2
-rw-r--r--src/feature/nodelist/authcert.c2
-rw-r--r--src/feature/nodelist/microdesc.c4
-rw-r--r--src/feature/nodelist/networkstatus.c48
-rw-r--r--src/feature/nodelist/networkstatus.h3
-rw-r--r--src/feature/nodelist/nodefamily.c4
-rw-r--r--src/feature/nodelist/nodelist.c12
-rw-r--r--src/feature/nodelist/nodelist.h4
-rw-r--r--src/feature/nodelist/routerlist.c6
-rw-r--r--src/feature/relay/dns.c53
-rw-r--r--src/feature/relay/dns.h61
-rw-r--r--src/feature/relay/ext_orport.c71
-rw-r--r--src/feature/relay/ext_orport.h50
-rw-r--r--src/feature/relay/include.am12
-rw-r--r--src/feature/relay/onion_queue.c6
-rw-r--r--src/feature/relay/relay_handshake.c565
-rw-r--r--src/feature/relay/relay_handshake.h90
-rw-r--r--src/feature/relay/router.h1
-rw-r--r--src/feature/relay/routerkeys.h82
-rw-r--r--src/feature/relay/selftest.h33
-rw-r--r--src/feature/stats/geoip_stats.c8
-rw-r--r--src/feature/stats/rephist.c4
-rw-r--r--src/include.am1
-rw-r--r--src/lib/cc/compat_compiler.h4
-rw-r--r--src/lib/cc/torint.h7
-rw-r--r--src/lib/compress/compress.c2
-rw-r--r--src/lib/conf/conftypes.h4
-rw-r--r--src/lib/confmgt/unitparse.c6
-rw-r--r--src/lib/container/map.c12
-rw-r--r--src/lib/container/map.h112
-rw-r--r--src/lib/container/namemap.c4
-rw-r--r--src/lib/ctime/di_ops.c31
-rw-r--r--src/lib/ctime/di_ops.h2
-rw-r--r--src/lib/err/torerr.c26
-rw-r--r--src/lib/err/torerr.h2
-rw-r--r--src/lib/err/torerr_sys.c6
-rw-r--r--src/lib/llharden/.may_include3
-rw-r--r--src/lib/llharden/include.am19
-rw-r--r--src/lib/llharden/lib_llharden.md6
-rw-r--r--src/lib/llharden/winprocess_sys.c (renamed from src/lib/process/winprocess_sys.c)2
-rw-r--r--src/lib/llharden/winprocess_sys.h (renamed from src/lib/process/winprocess_sys.h)0
-rw-r--r--src/lib/log/log.c62
-rw-r--r--src/lib/log/log.h2
-rw-r--r--src/lib/log/util_bug.c4
-rw-r--r--src/lib/malloc/map_anon.c2
-rw-r--r--src/lib/math/prob_distr.c8
-rw-r--r--src/lib/memarea/memarea.c2
-rw-r--r--src/lib/net/.may_include3
-rw-r--r--src/lib/net/address.c2
-rw-r--r--src/lib/net/inaddr.c21
-rw-r--r--src/lib/net/network_sys.c2
-rw-r--r--src/lib/net/resolve.c4
-rw-r--r--src/lib/osinfo/uname.c59
-rw-r--r--src/lib/process/include.am6
-rw-r--r--src/lib/process/process_sys.c2
-rw-r--r--src/lib/process/waitpid.c4
-rw-r--r--src/lib/thread/compat_threads.c4
-rw-r--r--src/rust/protover/protover.rs8
-rw-r--r--src/test/conf_examples/large_1/expected1
-rw-r--r--src/test/conf_examples/large_1/expected_no_dirauth1
-rw-r--r--src/test/conf_examples/large_1/torrc1
-rw-r--r--src/test/fuzz/fuzz_hsdescv3.c7
-rw-r--r--src/test/hs_test_helpers.c51
-rw-r--r--src/test/hs_test_helpers.h15
-rw-r--r--src/test/include.am19
-rw-r--r--src/test/log_test_helpers.h16
-rw-r--r--src/test/test.c1
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_addr.c31
-rw-r--r--src/test/test_circuitbuild.c8
-rw-r--r--src/test/test_connection.c9
-rw-r--r--src/test/test_consdiff.c14
-rw-r--r--src/test/test_dir.c20
-rw-r--r--src/test/test_dir_common.c2
-rw-r--r--src/test/test_dir_handle_get.c211
-rw-r--r--src/test/test_dns.c8
-rw-r--r--src/test/test_dos.c24
-rw-r--r--src/test/test_hs_cache.c21
-rw-r--r--src/test/test_hs_client.c53
-rw-r--r--src/test/test_hs_common.c24
-rw-r--r--src/test/test_hs_descriptor.c28
-rw-r--r--src/test/test_hs_intropoint.c3
-rw-r--r--src/test/test_hs_ntor.c8
-rw-r--r--src/test/test_hs_ntor_cl.c16
-rw-r--r--src/test/test_hs_ob.c268
-rw-r--r--src/test/test_hs_service.c533
-rw-r--r--src/test/test_link_handshake.c1
-rw-r--r--src/test/test_policy.c54
-rw-r--r--src/test/test_prob_distr.c4
-rw-r--r--src/test/test_protover.c47
-rw-r--r--src/test/test_pt.c4
-rw-r--r--src/test/test_shared_random.c26
-rw-r--r--src/test/test_util.c48
-rw-r--r--src/test/test_util_process.c7
-rw-r--r--src/test/test_voting_schedule.c6
-rw-r--r--src/test/testing_common.c2
-rw-r--r--src/win32/orconfig.h2
184 files changed, 4147 insertions, 1598 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c
index bbf984ad08..0623389099 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -182,7 +182,7 @@ static const char unix_q_socket_prefix[] = "unix:\"";
* *DowloadInitialDelay . */
#ifndef COCCI
#define DOWNLOAD_SCHEDULE(name) \
- { #name "DownloadSchedule", #name "DownloadInitialDelay", 0, 1 }
+ { (#name "DownloadSchedule"), (#name "DownloadInitialDelay"), 0, 1 }
#else
#define DOWNLOAD_SCHEDULE(name) { NULL, NULL, 0, 1 }
#endif /* !defined(COCCI) */
@@ -366,7 +366,7 @@ static const config_var_t option_vars_[] = {
#endif /* defined(HAVE_MODULE_RELAY) || defined(TOR_UNIT_TESTS) */
V(ClientPreferIPv6ORPort, AUTOBOOL, "auto"),
V(ClientPreferIPv6DirPort, AUTOBOOL, "auto"),
- V(ClientAutoIPv6ORPort, BOOL, "0"),
+ OBSOLETE("ClientAutoIPv6ORPort"),
V(ClientRejectInternalAddresses, BOOL, "1"),
V(ClientTransportPlugin, LINELIST, NULL),
V(ClientUseIPv6, BOOL, "0"),
@@ -510,6 +510,8 @@ static const config_var_t option_vars_[] = {
LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceEnableIntroDoSBurstPerSec",
LINELIST_S, RendConfigLines, NULL),
+ VAR("HiddenServiceOnionBalanceInstance",
+ LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceStatistics", BOOL, HiddenServiceStatistics_option, "1"),
V(HidServAuth, LINELIST, NULL),
V(ClientOnionAuthDir, FILENAME, NULL),
@@ -5878,7 +5880,11 @@ parse_dir_fallback_line(const char *line,
return r;
}
-/** Allocate and return a new port_cfg_t with reasonable defaults. */
+/** Allocate and return a new port_cfg_t with reasonable defaults.
+ *
+ * <b>namelen</b> is the length of the unix socket name
+ * (typically the filesystem path), not including the trailing NUL.
+ * It should be 0 for ports that are not zunix sockets. */
port_cfg_t *
port_cfg_new(size_t namelen)
{
@@ -5998,7 +6004,7 @@ port_cfg_line_extract_addrport(const char *line,
size_t sz;
*is_unix_out = 1;
*addrport_out = NULL;
- line += strlen(unix_socket_prefix); /*No q: Keep the quote */
+ line += strlen(unix_socket_prefix); /* No 'unix:', but keep the quote */
*rest_out = unescape_string(line, addrport_out, &sz);
if (!*rest_out || (*addrport_out && sz != strlen(*addrport_out))) {
tor_free(*addrport_out);
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
index 35ba15a9e2..bf58205f89 100644
--- a/src/app/config/or_options_st.h
+++ b/src/app/config/or_options_st.h
@@ -662,9 +662,6 @@ struct or_options_t {
* accessing this value directly. */
int ClientPreferIPv6DirPort;
- /** If true, prefer an IPv4 or IPv6 OR port at random. */
- int ClientAutoIPv6ORPort;
-
/** The length of time that we think a consensus should be fresh. */
int V3AuthVotingInterval;
/** The length of time we think it will take to distribute votes. */
diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c
index d9667733cc..dcc55f1898 100644
--- a/src/app/config/statefile.c
+++ b/src/app/config/statefile.c
@@ -78,6 +78,7 @@ DUMMY_TYPECHECK_INSTANCE(or_state_t);
VAR(#member, conftype, member, initvalue)
/** Array of "state" variables saved to the ~/.tor/state file. */
+// clang-format off
static const config_var_t state_vars_[] = {
/* Remember to document these in state-contents.txt ! */
@@ -134,6 +135,7 @@ static const config_var_t state_vars_[] = {
END_OF_CONFIG_VARS
};
+// clang-format on
#undef VAR
#undef V
diff --git a/src/app/main/shutdown.c b/src/app/main/shutdown.c
index 27d92609eb..aac15246b9 100644
--- a/src/app/main/shutdown.c
+++ b/src/app/main/shutdown.c
@@ -75,7 +75,8 @@ tor_cleanup(void)
/* Remove Extended ORPort cookie authentication file */
{
char *cookie_fname = get_ext_or_auth_cookie_file_name();
- tor_remove_file(cookie_fname);
+ if (cookie_fname)
+ tor_remove_file(cookie_fname);
tor_free(cookie_fname);
}
if (accounting_is_enabled(options))
diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c
index b4439cdc7b..e32083537f 100644
--- a/src/app/main/subsystem_list.c
+++ b/src/app/main/subsystem_list.c
@@ -14,9 +14,7 @@
#include "lib/cc/torint.h"
#include "core/mainloop/mainloop_sys.h"
-#include "core/or/ocirc_event_sys.h"
#include "core/or/or_sys.h"
-#include "core/or/orconn_event_sys.h"
#include "feature/control/btrack_sys.h"
#include "lib/compress/compress_sys.h"
#include "lib/crypt_ops/crypto_sys.h"
@@ -24,7 +22,7 @@
#include "lib/log/log_sys.h"
#include "lib/net/network_sys.h"
#include "lib/process/process_sys.h"
-#include "lib/process/winprocess_sys.h"
+#include "lib/llharden/winprocess_sys.h"
#include "lib/thread/thread_sys.h"
#include "lib/time/time_sys.h"
#include "lib/tls/tortls_sys.h"
@@ -46,28 +44,26 @@ const subsys_fns_t *tor_subsystems[] = {
&sys_torerr,
&sys_wallclock,
- &sys_threads,
&sys_logging,
+ &sys_threads,
&sys_time,
- &sys_network,
- &sys_compress,
&sys_crypto,
+ &sys_compress,
+ &sys_network,
&sys_tortls,
- &sys_process,
-
- &sys_orconn_event,
- &sys_ocirc_event,
- &sys_btrack,
&sys_evloop,
+ &sys_process,
&sys_mainloop,
&sys_or,
&sys_relay,
+ &sys_btrack,
+
&sys_dirauth,
};
diff --git a/src/core/crypto/hs_ntor.c b/src/core/crypto/hs_ntor.c
index 2bd4c32446..07bcdc566c 100644
--- a/src/core/crypto/hs_ntor.c
+++ b/src/core/crypto/hs_ntor.c
@@ -170,7 +170,7 @@ get_rendezvous1_key_material(const uint8_t *rend_secret_hs_input,
* necessary key material, and return 0. */
static void
get_introduce1_key_material(const uint8_t *secret_input,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
{
uint8_t keystream[CIPHER256_KEY_LEN + DIGEST256_LEN];
@@ -181,7 +181,7 @@ get_introduce1_key_material(const uint8_t *secret_input,
/* Let's build info */
ptr = info_blob;
APPEND(ptr, M_HSEXPAND, strlen(M_HSEXPAND));
- APPEND(ptr, subcredential, DIGEST256_LEN);
+ APPEND(ptr, subcredential->subcred, SUBCRED_LEN);
tor_assert(ptr == info_blob + sizeof(info_blob));
/* Let's build the input to the KDF */
@@ -317,7 +317,7 @@ hs_ntor_client_get_introduce1_keys(
const ed25519_public_key_t *intro_auth_pubkey,
const curve25519_public_key_t *intro_enc_pubkey,
const curve25519_keypair_t *client_ephemeral_enc_keypair,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
{
int bad = 0;
@@ -450,9 +450,31 @@ hs_ntor_service_get_introduce1_keys(
const ed25519_public_key_t *intro_auth_pubkey,
const curve25519_keypair_t *intro_enc_keypair,
const curve25519_public_key_t *client_ephemeral_enc_pubkey,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
{
+ return hs_ntor_service_get_introduce1_keys_multi(
+ intro_auth_pubkey,
+ intro_enc_keypair,
+ client_ephemeral_enc_pubkey,
+ 1,
+ subcredential,
+ hs_ntor_intro_cell_keys_out);
+}
+
+/**
+ * As hs_ntor_service_get_introduce1_keys(), but take multiple subcredentials
+ * as input, and yield multiple sets of keys as output.
+ **/
+int
+hs_ntor_service_get_introduce1_keys_multi(
+ const struct ed25519_public_key_t *intro_auth_pubkey,
+ const struct curve25519_keypair_t *intro_enc_keypair,
+ const struct curve25519_public_key_t *client_ephemeral_enc_pubkey,
+ size_t n_subcredentials,
+ const hs_subcredential_t *subcredentials,
+ hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
+{
int bad = 0;
uint8_t secret_input[INTRO_SECRET_HS_INPUT_LEN];
uint8_t dh_result[CURVE25519_OUTPUT_LEN];
@@ -460,7 +482,8 @@ hs_ntor_service_get_introduce1_keys(
tor_assert(intro_auth_pubkey);
tor_assert(intro_enc_keypair);
tor_assert(client_ephemeral_enc_pubkey);
- tor_assert(subcredential);
+ tor_assert(n_subcredentials >= 1);
+ tor_assert(subcredentials);
tor_assert(hs_ntor_intro_cell_keys_out);
/* Compute EXP(X, b) */
@@ -476,13 +499,16 @@ hs_ntor_service_get_introduce1_keys(
secret_input);
bad |= safe_mem_is_zero(secret_input, CURVE25519_OUTPUT_LEN);
- /* Get ENC_KEY and MAC_KEY! */
- get_introduce1_key_material(secret_input, subcredential,
- hs_ntor_intro_cell_keys_out);
+ for (unsigned i = 0; i < n_subcredentials; ++i) {
+ /* Get ENC_KEY and MAC_KEY! */
+ get_introduce1_key_material(secret_input, &subcredentials[i],
+ &hs_ntor_intro_cell_keys_out[i]);
+ }
memwipe(secret_input, 0, sizeof(secret_input));
if (bad) {
- memwipe(hs_ntor_intro_cell_keys_out, 0, sizeof(hs_ntor_intro_cell_keys_t));
+ memwipe(hs_ntor_intro_cell_keys_out, 0,
+ sizeof(hs_ntor_intro_cell_keys_t) * n_subcredentials);
}
return bad ? -1 : 0;
diff --git a/src/core/crypto/hs_ntor.h b/src/core/crypto/hs_ntor.h
index 2bce5686cd..9a975dd83f 100644
--- a/src/core/crypto/hs_ntor.h
+++ b/src/core/crypto/hs_ntor.h
@@ -35,11 +35,20 @@ typedef struct hs_ntor_rend_cell_keys_t {
uint8_t ntor_key_seed[DIGEST256_LEN];
} hs_ntor_rend_cell_keys_t;
+#define SUBCRED_LEN DIGEST256_LEN
+
+/**
+ * A 'subcredential' used to prove knowledge of a hidden service.
+ **/
+typedef struct hs_subcredential_t {
+ uint8_t subcred[SUBCRED_LEN];
+} hs_subcredential_t;
+
int hs_ntor_client_get_introduce1_keys(
const struct ed25519_public_key_t *intro_auth_pubkey,
const struct curve25519_public_key_t *intro_enc_pubkey,
const struct curve25519_keypair_t *client_ephemeral_enc_keypair,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out);
int hs_ntor_client_get_rendezvous1_keys(
@@ -49,11 +58,19 @@ int hs_ntor_client_get_rendezvous1_keys(
const struct curve25519_public_key_t *service_ephemeral_rend_pubkey,
hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out);
+int hs_ntor_service_get_introduce1_keys_multi(
+ const struct ed25519_public_key_t *intro_auth_pubkey,
+ const struct curve25519_keypair_t *intro_enc_keypair,
+ const struct curve25519_public_key_t *client_ephemeral_enc_pubkey,
+ size_t n_subcredentials,
+ const hs_subcredential_t *subcredentials,
+ hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out);
+
int hs_ntor_service_get_introduce1_keys(
const struct ed25519_public_key_t *intro_auth_pubkey,
const struct curve25519_keypair_t *intro_enc_keypair,
const struct curve25519_public_key_t *client_ephemeral_enc_pubkey,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out);
int hs_ntor_service_get_rendezvous1_keys(
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c
index bfd850da86..4965c2a1f4 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -3347,8 +3347,17 @@ record_num_bytes_transferred_impl(connection_t *conn,
rep_hist_note_dir_bytes_written(num_written, now);
}
+ /* Linked connections and internal IPs aren't counted for statistics or
+ * accounting:
+ * - counting linked connections would double-count BEGINDIR bytes, because
+ * they are sent as Dir bytes on the linked connection, and OR bytes on
+ * the OR connection;
+ * - relays and clients don't connect to internal IPs, unless specifically
+ * configured to do so. If they are configured that way, we don't count
+ * internal bytes.
+ */
if (!connection_is_rate_limited(conn))
- return; /* local IPs are free */
+ return;
if (conn->type == CONN_TYPE_OR)
rep_hist_note_or_conn_bytes(conn->global_identifier, num_read,
diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c
index 260de181e5..e4e17f6b76 100644
--- a/src/core/mainloop/mainloop.c
+++ b/src/core/mainloop/mainloop.c
@@ -966,7 +966,6 @@ conn_close_if_marked(int i)
return 0; /* nothing to see here, move along */
now = time(NULL);
assert_connection_ok(conn, now);
- /* assert_all_pending_dns_resolves_ok(); */
log_debug(LD_NET,"Cleaning up connection (fd "TOR_SOCKET_T_FORMAT").",
conn->s);
diff --git a/src/core/or/channel.c b/src/core/or/channel.c
index d52dc14a32..160ab587f5 100644
--- a/src/core/or/channel.c
+++ b/src/core/or/channel.c
@@ -119,10 +119,10 @@ channel_id_eq(const channel_t *a, const channel_t *b)
return a->global_identifier == b->global_identifier;
}
HT_PROTOTYPE(channel_gid_map, channel_t, gidmap_node,
- channel_id_hash, channel_id_eq)
+ channel_id_hash, channel_id_eq);
HT_GENERATE2(channel_gid_map, channel_t, gidmap_node,
channel_id_hash, channel_id_eq,
- 0.6, tor_reallocarray_, tor_free_)
+ 0.6, tor_reallocarray_, tor_free_);
HANDLE_IMPL(channel, channel_t,)
@@ -160,9 +160,9 @@ channel_idmap_eq(const channel_idmap_entry_t *a,
}
HT_PROTOTYPE(channel_idmap, channel_idmap_entry_t, node, channel_idmap_hash,
- channel_idmap_eq)
+ channel_idmap_eq);
HT_GENERATE2(channel_idmap, channel_idmap_entry_t, node, channel_idmap_hash,
- channel_idmap_eq, 0.5, tor_reallocarray_, tor_free_)
+ channel_idmap_eq, 0.5, tor_reallocarray_, tor_free_);
/* Functions to maintain the digest map */
static void channel_remove_from_digest_map(channel_t *chan);
@@ -1859,7 +1859,7 @@ channel_do_open_actions(channel_t *chan)
tor_free(transport_name);
/* Notify the DoS subsystem of a new client. */
if (tlschan && tlschan->conn) {
- dos_new_client_conn(tlschan->conn);
+ dos_new_client_conn(tlschan->conn, transport_name);
}
}
/* Otherwise the underlying transport can't tell us this, so skip it */
diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c
index 7974da4832..2a35237d30 100644
--- a/src/core/or/channeltls.c
+++ b/src/core/or/channeltls.c
@@ -47,6 +47,7 @@
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_or.h"
+#include "feature/relay/relay_handshake.h"
#include "feature/control/control.h"
#include "feature/client/entrynodes.h"
#include "trunnel/link_handshake.h"
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index 03ed2c7d29..003b91af8d 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -2819,8 +2819,8 @@ extend_info_dup(extend_info_t *info)
* If there is no chosen exit, or if we don't know the node_t for
* the chosen exit, return NULL.
*/
-const node_t *
-build_state_get_exit_node(cpath_build_state_t *state)
+MOCK_IMPL(const node_t *,
+build_state_get_exit_node,(cpath_build_state_t *state))
{
if (!state || !state->chosen_exit)
return NULL;
diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h
index f5a3439064..48592dd346 100644
--- a/src/core/or/circuitbuild.h
+++ b/src/core/or/circuitbuild.h
@@ -66,7 +66,8 @@ int circuit_can_use_tap(const origin_circuit_t *circ);
int circuit_has_usable_onion_key(const origin_circuit_t *circ);
int extend_info_has_preferred_onion_key(const extend_info_t* ei);
const uint8_t *build_state_get_exit_rsa_id(cpath_build_state_t *state);
-const node_t *build_state_get_exit_node(cpath_build_state_t *state);
+MOCK_DECL(const node_t *,
+ build_state_get_exit_node,(cpath_build_state_t *state));
const char *build_state_get_exit_nickname(cpath_build_state_t *state);
struct circuit_guard_state_t;
diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c
index 6a712926a3..ca174c442c 100644
--- a/src/core/or/circuitlist.c
+++ b/src/core/or/circuitlist.c
@@ -215,10 +215,10 @@ chan_circid_entry_hash_(chan_circid_circuit_map_t *a)
static HT_HEAD(chan_circid_map, chan_circid_circuit_map_t)
chan_circid_map = HT_INITIALIZER();
HT_PROTOTYPE(chan_circid_map, chan_circid_circuit_map_t, node,
- chan_circid_entry_hash_, chan_circid_entries_eq_)
+ chan_circid_entry_hash_, chan_circid_entries_eq_);
HT_GENERATE2(chan_circid_map, chan_circid_circuit_map_t, node,
chan_circid_entry_hash_, chan_circid_entries_eq_, 0.6,
- tor_reallocarray_, tor_free_)
+ tor_reallocarray_, tor_free_);
/** The most recently returned entry from circuit_get_by_circid_chan;
* used to improve performance when many cells arrive in a row from the
diff --git a/src/core/or/circuitmux.c b/src/core/or/circuitmux.c
index da95e93657..b770e40bf2 100644
--- a/src/core/or/circuitmux.c
+++ b/src/core/or/circuitmux.c
@@ -176,10 +176,10 @@ chanid_circid_entry_hash(chanid_circid_muxinfo_t *a)
/* Emit a bunch of hash table stuff */
HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
- chanid_circid_entry_hash, chanid_circid_entries_eq)
+ chanid_circid_entry_hash, chanid_circid_entries_eq);
HT_GENERATE2(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6,
- tor_reallocarray_, tor_free_)
+ tor_reallocarray_, tor_free_);
/*
* Circuitmux alloc/free functions
diff --git a/src/core/or/circuitmux_ewma.c b/src/core/or/circuitmux_ewma.c
index b50f33528f..0dcd22e8a7 100644
--- a/src/core/or/circuitmux_ewma.c
+++ b/src/core/or/circuitmux_ewma.c
@@ -423,7 +423,7 @@ ewma_cmp_cmux(circuitmux_t *cmux_1, circuitmux_policy_data_t *pol_data_1,
/* Pick whichever one has the better best circuit */
return compare_cell_ewma_counts(ce1, ce2);
} else {
- if (ce1 != NULL ) {
+ if (ce1 != NULL) {
/* We only have a circuit on cmux_1, so prefer it */
return -1;
} else if (ce2 != NULL) {
@@ -609,7 +609,7 @@ cmux_ewma_set_options(const or_options_t *options,
/* convert halflife into halflife-per-tick. */
halflife /= EWMA_TICK_LEN;
/* compute per-tick scale factor. */
- ewma_scale_factor = exp( LOG_ONEHALF / halflife );
+ ewma_scale_factor = exp(LOG_ONEHALF / halflife);
log_info(LD_OR,
"Enabled cell_ewma algorithm because of value in %s; "
"scale factor is %f per %d seconds",
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
index 5d10cacc71..066d5d437a 100644
--- a/src/core/or/circuituse.c
+++ b/src/core/or/circuituse.c
@@ -732,7 +732,7 @@ circuit_expire_building(void)
circuit_build_times_enough_to_compute(get_circuit_build_times())) {
log_info(LD_CIRC,
- "Deciding to count the timeout for circuit %"PRIu32"\n",
+ "Deciding to count the timeout for circuit %"PRIu32,
TO_ORIGIN_CIRCUIT(victim)->global_identifier);
/* Circuits are allowed to last longer for measurement.
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
index aeb9ec6460..23c6e230cb 100644
--- a/src/core/or/connection_edge.c
+++ b/src/core/or/connection_edge.c
@@ -432,6 +432,21 @@ warn_if_hs_unreachable(const edge_connection_t *conn, uint8_t reason)
}
}
+/** Given a TTL (in seconds) from a DNS response or from a relay, determine
+ * what TTL clients and relays should actually use for caching it. */
+uint32_t
+clip_dns_ttl(uint32_t ttl)
+{
+ /* This logic is a defense against "DefectTor" DNS-based traffic
+ * confirmation attacks, as in https://nymity.ch/tor-dns/tor-dns.pdf .
+ * We only give two values: a "low" value and a "high" value.
+ */
+ if (ttl < MIN_DNS_TTL)
+ return MIN_DNS_TTL;
+ else
+ return MAX_DNS_TTL;
+}
+
/** Send a relay end cell from stream <b>conn</b> down conn's circuit, and
* remember that we've done so. If this is not a client connection, set the
* relay end cell's reason for closing as <b>reason</b>.
@@ -480,7 +495,7 @@ connection_edge_end(edge_connection_t *conn, uint8_t reason)
memcpy(payload+1, tor_addr_to_in6_addr8(&conn->base_.addr), 16);
addrlen = 16;
}
- set_uint32(payload+1+addrlen, htonl(dns_clip_ttl(conn->address_ttl)));
+ set_uint32(payload+1+addrlen, htonl(clip_dns_ttl(conn->address_ttl)));
payload_len += 4+addrlen;
}
@@ -845,7 +860,7 @@ connected_cell_format_payload(uint8_t *payload_out,
return -1;
}
- set_uint32(payload_out + connected_payload_len, htonl(dns_clip_ttl(ttl)));
+ set_uint32(payload_out + connected_payload_len, htonl(clip_dns_ttl(ttl)));
connected_payload_len += 4;
tor_assert(connected_payload_len <= MAX_CONNECTED_CELL_PAYLOAD_LEN);
diff --git a/src/core/or/connection_edge.h b/src/core/or/connection_edge.h
index 11cb252935..8c06af5664 100644
--- a/src/core/or/connection_edge.h
+++ b/src/core/or/connection_edge.h
@@ -182,6 +182,21 @@ void connection_ap_warn_and_unmark_if_pending_circ(
entry_connection_t *entry_conn,
const char *where);
+/** Lowest value for DNS ttl that a server should give or a client should
+ * believe. */
+#define MIN_DNS_TTL (5*60)
+/** Highest value for DNS ttl that a server should give or a client should
+ * believe. */
+#define MAX_DNS_TTL (60*60)
+/** How long do we keep DNS cache entries before purging them (regardless of
+ * their TTL)? */
+#define MAX_DNS_ENTRY_AGE (3*60*60)
+/** How long do we cache/tell clients to cache DNS records when no TTL is
+ * known? */
+#define DEFAULT_DNS_TTL (30*60)
+
+uint32_t clip_dns_ttl(uint32_t ttl);
+
int connection_half_edge_is_valid_data(const smartlist_t *half_conns,
streamid_t stream_id);
int connection_half_edge_is_valid_sendme(const smartlist_t *half_conns,
diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c
index 76bfbf0b30..6b11f33232 100644
--- a/src/core/or/connection_or.c
+++ b/src/core/or/connection_or.c
@@ -39,14 +39,13 @@
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_or.h"
+#include "feature/relay/relay_handshake.h"
#include "feature/control/control_events.h"
-#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "feature/dirauth/reachability.h"
#include "feature/client/entrynodes.h"
#include "lib/geoip/geoip.h"
#include "core/mainloop/mainloop.h"
-#include "trunnel/link_handshake.h"
#include "trunnel/netinfo.h"
#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
@@ -78,7 +77,6 @@
#include "lib/crypt_ops/crypto_format.h"
#include "lib/tls/tortls.h"
-#include "lib/tls/x509.h"
#include "core/or/orconn_event.h"
@@ -109,10 +107,6 @@ TO_OR_CONN(connection_t *c)
return DOWNCAST(or_connection_t, c);
}
-/** Global map between Extended ORPort identifiers and OR
- * connections. */
-static digestmap_t *orconn_ext_or_id_map = NULL;
-
/** Clear clear conn->identity_digest and update other data
* structures as appropriate.*/
void
@@ -198,71 +192,6 @@ connection_or_set_identity_digest(or_connection_t *conn,
channel_set_identity_digest(chan, rsa_digest, ed_id);
}
-/** 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);
-}
-
-/** 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);
-}
-
-/** 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);
-}
-
/**************************************************************/
/** Map from a string describing what a non-open OR connection was doing when
@@ -1283,11 +1212,11 @@ or_connect_failure_ht_hash(const or_connect_failure_entry_t *entry)
}
HT_PROTOTYPE(or_connect_failure_ht, or_connect_failure_entry_t, node,
- or_connect_failure_ht_hash, or_connect_failure_ht_eq)
+ or_connect_failure_ht_hash, or_connect_failure_ht_eq);
HT_GENERATE2(or_connect_failure_ht, or_connect_failure_entry_t, node,
or_connect_failure_ht_hash, or_connect_failure_ht_eq,
- 0.6, tor_reallocarray_, tor_free_)
+ 0.6, tor_reallocarray_, tor_free_);
/* Initialize a given connect failure entry with the given identity_digest,
* addr and port. All field are optional except ocf. */
@@ -2596,533 +2525,3 @@ connection_or_send_netinfo,(or_connection_t *conn))
return r;
}
-
-/** Helper used to add an encoded certs to a cert cell */
-static void
-add_certs_cell_cert_helper(certs_cell_t *certs_cell,
- uint8_t cert_type,
- const uint8_t *cert_encoded,
- size_t cert_len)
-{
- tor_assert(cert_len <= UINT16_MAX);
- certs_cell_cert_t *ccc = certs_cell_cert_new();
- ccc->cert_type = cert_type;
- ccc->cert_len = cert_len;
- certs_cell_cert_setlen_body(ccc, cert_len);
- memcpy(certs_cell_cert_getarray_body(ccc), cert_encoded, cert_len);
-
- certs_cell_add_certs(certs_cell, ccc);
-}
-
-/** Add an encoded X509 cert (stored as <b>cert_len</b> bytes at
- * <b>cert_encoded</b>) to the trunnel certs_cell_t object that we are
- * building in <b>certs_cell</b>. Set its type field to <b>cert_type</b>.
- * (If <b>cert</b> is NULL, take no action.) */
-static void
-add_x509_cert(certs_cell_t *certs_cell,
- uint8_t cert_type,
- const tor_x509_cert_t *cert)
-{
- if (NULL == cert)
- return;
-
- const uint8_t *cert_encoded = NULL;
- size_t cert_len;
- tor_x509_cert_get_der(cert, &cert_encoded, &cert_len);
-
- add_certs_cell_cert_helper(certs_cell, cert_type, cert_encoded, cert_len);
-}
-
-/** Add an Ed25519 cert from <b>cert</b> to the trunnel certs_cell_t object
- * that we are building in <b>certs_cell</b>. Set its type field to
- * <b>cert_type</b>. (If <b>cert</b> is NULL, take no action.) */
-static void
-add_ed25519_cert(certs_cell_t *certs_cell,
- uint8_t cert_type,
- const tor_cert_t *cert)
-{
- if (NULL == cert)
- return;
-
- add_certs_cell_cert_helper(certs_cell, cert_type,
- cert->encoded, cert->encoded_len);
-}
-
-#ifdef TOR_UNIT_TESTS
-int certs_cell_ed25519_disabled_for_testing = 0;
-#else
-#define certs_cell_ed25519_disabled_for_testing 0
-#endif
-
-/** Send a CERTS cell on the connection <b>conn</b>. Return 0 on success, -1
- * on failure. */
-int
-connection_or_send_certs_cell(or_connection_t *conn)
-{
- const tor_x509_cert_t *global_link_cert = NULL, *id_cert = NULL;
- tor_x509_cert_t *own_link_cert = NULL;
- var_cell_t *cell;
-
- certs_cell_t *certs_cell = NULL;
-
- tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
-
- if (! conn->handshake_state)
- return -1;
-
- const int conn_in_server_mode = ! conn->handshake_state->started_here;
-
- /* Get the encoded values of the X509 certificates */
- if (tor_tls_get_my_certs(conn_in_server_mode,
- &global_link_cert, &id_cert) < 0)
- return -1;
-
- if (conn_in_server_mode) {
- own_link_cert = tor_tls_get_own_cert(conn->tls);
- }
- tor_assert(id_cert);
-
- certs_cell = certs_cell_new();
-
- /* Start adding certs. First the link cert or auth1024 cert. */
- if (conn_in_server_mode) {
- tor_assert_nonfatal(own_link_cert);
- add_x509_cert(certs_cell,
- OR_CERT_TYPE_TLS_LINK, own_link_cert);
- } else {
- tor_assert(global_link_cert);
- add_x509_cert(certs_cell,
- OR_CERT_TYPE_AUTH_1024, global_link_cert);
- }
-
- /* Next the RSA->RSA ID cert */
- add_x509_cert(certs_cell,
- OR_CERT_TYPE_ID_1024, id_cert);
-
- /* Next the Ed25519 certs */
- add_ed25519_cert(certs_cell,
- CERTTYPE_ED_ID_SIGN,
- get_master_signing_key_cert());
- if (conn_in_server_mode) {
- tor_assert_nonfatal(conn->handshake_state->own_link_cert ||
- certs_cell_ed25519_disabled_for_testing);
- add_ed25519_cert(certs_cell,
- CERTTYPE_ED_SIGN_LINK,
- conn->handshake_state->own_link_cert);
- } else {
- add_ed25519_cert(certs_cell,
- CERTTYPE_ED_SIGN_AUTH,
- get_current_auth_key_cert());
- }
-
- /* And finally the crosscert. */
- {
- const uint8_t *crosscert=NULL;
- size_t crosscert_len;
- get_master_rsa_crosscert(&crosscert, &crosscert_len);
- if (crosscert) {
- add_certs_cell_cert_helper(certs_cell,
- CERTTYPE_RSA1024_ID_EDID,
- crosscert, crosscert_len);
- }
- }
-
- /* We've added all the certs; make the cell. */
- certs_cell->n_certs = certs_cell_getlen_certs(certs_cell);
-
- ssize_t alloc_len = certs_cell_encoded_len(certs_cell);
- tor_assert(alloc_len >= 0 && alloc_len <= UINT16_MAX);
- cell = var_cell_new(alloc_len);
- cell->command = CELL_CERTS;
- ssize_t enc_len = certs_cell_encode(cell->payload, alloc_len, certs_cell);
- tor_assert(enc_len > 0 && enc_len <= alloc_len);
- cell->payload_len = enc_len;
-
- connection_or_write_var_cell_to_buf(cell, conn);
- var_cell_free(cell);
- certs_cell_free(certs_cell);
- tor_x509_cert_free(own_link_cert);
-
- return 0;
-}
-
-#ifdef TOR_UNIT_TESTS
-int testing__connection_or_pretend_TLSSECRET_is_supported = 0;
-#else
-#define testing__connection_or_pretend_TLSSECRET_is_supported 0
-#endif
-
-/** Return true iff <b>challenge_type</b> is an AUTHCHALLENGE type that
- * we can send and receive. */
-int
-authchallenge_type_is_supported(uint16_t challenge_type)
-{
- switch (challenge_type) {
- case AUTHTYPE_RSA_SHA256_TLSSECRET:
-#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
- return 1;
-#else
- return testing__connection_or_pretend_TLSSECRET_is_supported;
-#endif
- case AUTHTYPE_ED25519_SHA256_RFC5705:
- return 1;
- case AUTHTYPE_RSA_SHA256_RFC5705:
- default:
- return 0;
- }
-}
-
-/** Return true iff <b>challenge_type_a</b> is one that we would rather
- * use than <b>challenge_type_b</b>. */
-int
-authchallenge_type_is_better(uint16_t challenge_type_a,
- uint16_t challenge_type_b)
-{
- /* Any supported type is better than an unsupported one;
- * all unsupported types are equally bad. */
- if (!authchallenge_type_is_supported(challenge_type_a))
- return 0;
- if (!authchallenge_type_is_supported(challenge_type_b))
- return 1;
- /* It happens that types are superior in numerically ascending order.
- * If that ever changes, this must change too. */
- return (challenge_type_a > challenge_type_b);
-}
-
-/** Send an AUTH_CHALLENGE cell on the connection <b>conn</b>. Return 0
- * on success, -1 on failure. */
-int
-connection_or_send_auth_challenge_cell(or_connection_t *conn)
-{
- var_cell_t *cell = NULL;
- int r = -1;
- tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
-
- if (! conn->handshake_state)
- return -1;
-
- auth_challenge_cell_t *ac = auth_challenge_cell_new();
-
- tor_assert(sizeof(ac->challenge) == 32);
- crypto_rand((char*)ac->challenge, sizeof(ac->challenge));
-
- if (authchallenge_type_is_supported(AUTHTYPE_RSA_SHA256_TLSSECRET))
- auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_TLSSECRET);
- /* Disabled, because everything that supports this method also supports
- * the much-superior ED25519_SHA256_RFC5705 */
- /* auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_RFC5705); */
- if (authchallenge_type_is_supported(AUTHTYPE_ED25519_SHA256_RFC5705))
- auth_challenge_cell_add_methods(ac, AUTHTYPE_ED25519_SHA256_RFC5705);
- auth_challenge_cell_set_n_methods(ac,
- auth_challenge_cell_getlen_methods(ac));
-
- cell = var_cell_new(auth_challenge_cell_encoded_len(ac));
- ssize_t len = auth_challenge_cell_encode(cell->payload, cell->payload_len,
- ac);
- if (len != cell->payload_len) {
- /* LCOV_EXCL_START */
- log_warn(LD_BUG, "Encoded auth challenge cell length not as expected");
- goto done;
- /* LCOV_EXCL_STOP */
- }
- cell->command = CELL_AUTH_CHALLENGE;
-
- connection_or_write_var_cell_to_buf(cell, conn);
- r = 0;
-
- done:
- var_cell_free(cell);
- auth_challenge_cell_free(ac);
-
- return r;
-}
-
-/** Compute the main body of an AUTHENTICATE cell that a client can use
- * to authenticate itself on a v3 handshake for <b>conn</b>. Return it
- * in a var_cell_t.
- *
- * If <b>server</b> is true, only calculate the first
- * V3_AUTH_FIXED_PART_LEN bytes -- the part of the authenticator that's
- * determined by the rest of the handshake, and which match the provided value
- * exactly.
- *
- * If <b>server</b> is false and <b>signing_key</b> is NULL, calculate the
- * first V3_AUTH_BODY_LEN bytes of the authenticator (that is, everything
- * that should be signed), but don't actually sign it.
- *
- * If <b>server</b> is false and <b>signing_key</b> is provided, calculate the
- * entire authenticator, signed with <b>signing_key</b>.
- *
- * Return the length of the cell body on success, and -1 on failure.
- */
-var_cell_t *
-connection_or_compute_authenticate_cell_body(or_connection_t *conn,
- const int authtype,
- crypto_pk_t *signing_key,
- const ed25519_keypair_t *ed_signing_key,
- int server)
-{
- auth1_t *auth = NULL;
- auth_ctx_t *ctx = auth_ctx_new();
- var_cell_t *result = NULL;
- int old_tlssecrets_algorithm = 0;
- const char *authtype_str = NULL;
-
- int is_ed = 0;
-
- /* assert state is reasonable XXXX */
- switch (authtype) {
- case AUTHTYPE_RSA_SHA256_TLSSECRET:
- authtype_str = "AUTH0001";
- old_tlssecrets_algorithm = 1;
- break;
- case AUTHTYPE_RSA_SHA256_RFC5705:
- authtype_str = "AUTH0002";
- break;
- case AUTHTYPE_ED25519_SHA256_RFC5705:
- authtype_str = "AUTH0003";
- is_ed = 1;
- break;
- default:
- tor_assert(0);
- break;
- }
-
- auth = auth1_new();
- ctx->is_ed = is_ed;
-
- /* Type: 8 bytes. */
- memcpy(auth1_getarray_type(auth), authtype_str, 8);
-
- {
- const tor_x509_cert_t *id_cert=NULL;
- const common_digests_t *my_digests, *their_digests;
- const uint8_t *my_id, *their_id, *client_id, *server_id;
- if (tor_tls_get_my_certs(server, NULL, &id_cert))
- goto err;
- my_digests = tor_x509_cert_get_id_digests(id_cert);
- their_digests =
- tor_x509_cert_get_id_digests(conn->handshake_state->certs->id_cert);
- tor_assert(my_digests);
- tor_assert(their_digests);
- my_id = (uint8_t*)my_digests->d[DIGEST_SHA256];
- their_id = (uint8_t*)their_digests->d[DIGEST_SHA256];
-
- client_id = server ? their_id : my_id;
- server_id = server ? my_id : their_id;
-
- /* Client ID digest: 32 octets. */
- memcpy(auth->cid, client_id, 32);
-
- /* Server ID digest: 32 octets. */
- memcpy(auth->sid, server_id, 32);
- }
-
- if (is_ed) {
- const ed25519_public_key_t *my_ed_id, *their_ed_id;
- if (!conn->handshake_state->certs->ed_id_sign) {
- log_warn(LD_OR, "Ed authenticate without Ed ID cert from peer.");
- goto err;
- }
- my_ed_id = get_master_identity_key();
- their_ed_id = &conn->handshake_state->certs->ed_id_sign->signing_key;
-
- const uint8_t *cid_ed = (server ? their_ed_id : my_ed_id)->pubkey;
- const uint8_t *sid_ed = (server ? my_ed_id : their_ed_id)->pubkey;
-
- memcpy(auth->u1_cid_ed, cid_ed, ED25519_PUBKEY_LEN);
- memcpy(auth->u1_sid_ed, sid_ed, ED25519_PUBKEY_LEN);
- }
-
- {
- crypto_digest_t *server_d, *client_d;
- if (server) {
- server_d = conn->handshake_state->digest_sent;
- client_d = conn->handshake_state->digest_received;
- } else {
- client_d = conn->handshake_state->digest_sent;
- server_d = conn->handshake_state->digest_received;
- }
-
- /* Server log digest : 32 octets */
- crypto_digest_get_digest(server_d, (char*)auth->slog, 32);
-
- /* Client log digest : 32 octets */
- crypto_digest_get_digest(client_d, (char*)auth->clog, 32);
- }
-
- {
- /* Digest of cert used on TLS link : 32 octets. */
- tor_x509_cert_t *cert = NULL;
- if (server) {
- cert = tor_tls_get_own_cert(conn->tls);
- } else {
- cert = tor_tls_get_peer_cert(conn->tls);
- }
- if (!cert) {
- log_warn(LD_OR, "Unable to find cert when making %s data.",
- authtype_str);
- goto err;
- }
-
- memcpy(auth->scert,
- tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32);
-
- tor_x509_cert_free(cert);
- }
-
- /* HMAC of clientrandom and serverrandom using master key : 32 octets */
- if (old_tlssecrets_algorithm) {
- if (tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets) < 0) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR, "Somebody asked us for an older TLS "
- "authentication method (AUTHTYPE_RSA_SHA256_TLSSECRET) "
- "which we don't support.");
- }
- } else {
- char label[128];
- tor_snprintf(label, sizeof(label),
- "EXPORTER FOR TOR TLS CLIENT BINDING %s", authtype_str);
- int r = tor_tls_export_key_material(conn->tls, auth->tlssecrets,
- auth->cid, sizeof(auth->cid),
- label);
- if (r < 0) {
- if (r != -2)
- log_warn(LD_BUG, "TLS key export failed for unknown reason.");
- // If r == -2, this was openssl bug 7712.
- goto err;
- }
- }
-
- /* 8 octets were reserved for the current time, but we're trying to get out
- * of the habit of sending time around willynilly. Fortunately, nothing
- * checks it. That's followed by 16 bytes of nonce. */
- crypto_rand((char*)auth->rand, 24);
-
- ssize_t maxlen = auth1_encoded_len(auth, ctx);
- if (ed_signing_key && is_ed) {
- maxlen += ED25519_SIG_LEN;
- } else if (signing_key && !is_ed) {
- maxlen += crypto_pk_keysize(signing_key);
- }
-
- const int AUTH_CELL_HEADER_LEN = 4; /* 2 bytes of type, 2 bytes of length */
- result = var_cell_new(AUTH_CELL_HEADER_LEN + maxlen);
- uint8_t *const out = result->payload + AUTH_CELL_HEADER_LEN;
- const size_t outlen = maxlen;
- ssize_t len;
-
- result->command = CELL_AUTHENTICATE;
- set_uint16(result->payload, htons(authtype));
-
- if ((len = auth1_encode(out, outlen, auth, ctx)) < 0) {
- /* LCOV_EXCL_START */
- log_warn(LD_BUG, "Unable to encode signed part of AUTH1 data.");
- goto err;
- /* LCOV_EXCL_STOP */
- }
-
- if (server) {
- auth1_t *tmp = NULL;
- ssize_t len2 = auth1_parse(&tmp, out, len, ctx);
- if (!tmp) {
- /* LCOV_EXCL_START */
- log_warn(LD_BUG, "Unable to parse signed part of AUTH1 data that "
- "we just encoded");
- goto err;
- /* LCOV_EXCL_STOP */
- }
- result->payload_len = (tmp->end_of_signed - result->payload);
-
- auth1_free(tmp);
- if (len2 != len) {
- /* LCOV_EXCL_START */
- log_warn(LD_BUG, "Mismatched length when re-parsing AUTH1 data.");
- goto err;
- /* LCOV_EXCL_STOP */
- }
- goto done;
- }
-
- if (ed_signing_key && is_ed) {
- ed25519_signature_t sig;
- if (ed25519_sign(&sig, out, len, ed_signing_key) < 0) {
- /* LCOV_EXCL_START */
- log_warn(LD_BUG, "Unable to sign ed25519 authentication data");
- goto err;
- /* LCOV_EXCL_STOP */
- }
- auth1_setlen_sig(auth, ED25519_SIG_LEN);
- memcpy(auth1_getarray_sig(auth), sig.sig, ED25519_SIG_LEN);
-
- } else if (signing_key && !is_ed) {
- auth1_setlen_sig(auth, crypto_pk_keysize(signing_key));
-
- char d[32];
- crypto_digest256(d, (char*)out, len, DIGEST_SHA256);
- int siglen = crypto_pk_private_sign(signing_key,
- (char*)auth1_getarray_sig(auth),
- auth1_getlen_sig(auth),
- d, 32);
- if (siglen < 0) {
- log_warn(LD_OR, "Unable to sign AUTH1 data.");
- goto err;
- }
-
- auth1_setlen_sig(auth, siglen);
- }
-
- len = auth1_encode(out, outlen, auth, ctx);
- if (len < 0) {
- /* LCOV_EXCL_START */
- log_warn(LD_BUG, "Unable to encode signed AUTH1 data.");
- goto err;
- /* LCOV_EXCL_STOP */
- }
- tor_assert(len + AUTH_CELL_HEADER_LEN <= result->payload_len);
- result->payload_len = len + AUTH_CELL_HEADER_LEN;
- set_uint16(result->payload+2, htons(len));
-
- goto done;
-
- err:
- var_cell_free(result);
- result = NULL;
- done:
- auth1_free(auth);
- auth_ctx_free(ctx);
- return result;
-}
-
-/** Send an AUTHENTICATE cell on the connection <b>conn</b>. Return 0 on
- * success, -1 on failure */
-MOCK_IMPL(int,
-connection_or_send_authenticate_cell,(or_connection_t *conn, int authtype))
-{
- var_cell_t *cell;
- crypto_pk_t *pk = tor_tls_get_my_client_auth_key();
- /* XXXX make sure we're actually supposed to send this! */
-
- if (!pk) {
- log_warn(LD_BUG, "Can't compute authenticate cell: no client auth key");
- return -1;
- }
- if (! authchallenge_type_is_supported(authtype)) {
- log_warn(LD_BUG, "Tried to send authenticate cell with unknown "
- "authentication type %d", authtype);
- return -1;
- }
-
- cell = connection_or_compute_authenticate_cell_body(conn,
- authtype,
- pk,
- get_current_auth_keypair(),
- 0 /* not server */);
- if (! cell) {
- log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unable to compute authenticate cell!");
- return -1;
- }
- connection_or_write_var_cell_to_buf(cell, conn);
- var_cell_free(cell);
-
- return 0;
-}
diff --git a/src/core/or/connection_or.h b/src/core/or/connection_or.h
index 90b21ad77b..02bc87a864 100644
--- a/src/core/or/connection_or.h
+++ b/src/core/or/connection_or.h
@@ -97,19 +97,6 @@ MOCK_DECL(void,connection_or_write_var_cell_to_buf,(const var_cell_t *cell,
or_connection_t *conn));
int connection_or_send_versions(or_connection_t *conn, int v3_plus);
MOCK_DECL(int,connection_or_send_netinfo,(or_connection_t *conn));
-int connection_or_send_certs_cell(or_connection_t *conn);
-int connection_or_send_auth_challenge_cell(or_connection_t *conn);
-int authchallenge_type_is_supported(uint16_t challenge_type);
-int authchallenge_type_is_better(uint16_t challenge_type_a,
- uint16_t challenge_type_b);
-var_cell_t *connection_or_compute_authenticate_cell_body(
- or_connection_t *conn,
- const int authtype,
- crypto_pk_t *signing_key,
- const struct ed25519_keypair_t *ed_signing_key,
- int server);
-MOCK_DECL(int,connection_or_send_authenticate_cell,
- (or_connection_t *conn, int type));
int is_or_protocol_version_known(uint16_t version);
@@ -144,7 +131,6 @@ MOCK_DECL(STATIC void,connection_or_change_state,
#endif /* defined(CONNECTION_OR_PRIVATE) */
#ifdef TOR_UNIT_TESTS
-extern int certs_cell_ed25519_disabled_for_testing;
extern int testing__connection_or_pretend_TLSSECRET_is_supported;
#endif
diff --git a/src/core/or/dos.c b/src/core/or/dos.c
index be64b6286e..5f99280030 100644
--- a/src/core/or/dos.c
+++ b/src/core/or/dos.c
@@ -680,7 +680,7 @@ dos_log_heartbeat(void)
/* Called when a new client connection has been established on the given
* address. */
void
-dos_new_client_conn(or_connection_t *or_conn)
+dos_new_client_conn(or_connection_t *or_conn, const char *transport_name)
{
clientmap_entry_t *entry;
@@ -701,7 +701,7 @@ dos_new_client_conn(or_connection_t *or_conn)
}
/* We are only interested in client connection from the geoip cache. */
- entry = geoip_lookup_client(&or_conn->real_addr, NULL,
+ entry = geoip_lookup_client(&or_conn->real_addr, transport_name,
GEOIP_CLIENT_CONNECT);
if (BUG(entry == NULL)) {
/* Should never happen because we note down the address in the geoip
diff --git a/src/core/or/dos.h b/src/core/or/dos.h
index b7b1d3f635..b3eca058b8 100644
--- a/src/core/or/dos.h
+++ b/src/core/or/dos.h
@@ -53,7 +53,8 @@ int dos_enabled(void);
void dos_log_heartbeat(void);
void dos_geoip_entry_about_to_free(const struct clientmap_entry_t *geoip_ent);
-void dos_new_client_conn(or_connection_t *or_conn);
+void dos_new_client_conn(or_connection_t *or_conn,
+ const char *transport_name);
void dos_close_client_conn(const or_connection_t *or_conn);
int dos_should_refuse_single_hop_client(void);
diff --git a/src/core/or/include.am b/src/core/or/include.am
index 4dd251d2e4..3626e76bed 100644
--- a/src/core/or/include.am
+++ b/src/core/or/include.am
@@ -74,13 +74,11 @@ noinst_HEADERS += \
src/core/or/or_periodic.h \
src/core/or/or_sys.h \
src/core/or/orconn_event.h \
- src/core/or/orconn_event_sys.h \
src/core/or/or_circuit_st.h \
src/core/or/or_connection_st.h \
src/core/or/or_handshake_certs_st.h \
src/core/or/or_handshake_state_st.h \
src/core/or/ocirc_event.h \
- src/core/or/ocirc_event_sys.h \
src/core/or/origin_circuit_st.h \
src/core/or/policies.h \
src/core/or/port_cfg_st.h \
diff --git a/src/core/or/ocirc_event.c b/src/core/or/ocirc_event.c
index 66992a0b5f..fa16459175 100644
--- a/src/core/or/ocirc_event.c
+++ b/src/core/or/ocirc_event.c
@@ -22,7 +22,7 @@
#include "core/or/cpath_build_state_st.h"
#include "core/or/ocirc_event.h"
-#include "core/or/ocirc_event_sys.h"
+#include "core/or/or_sys.h"
#include "core/or/origin_circuit_st.h"
#include "lib/subsys/subsys.h"
@@ -84,7 +84,7 @@ static dispatch_typefns_t ocirc_cevent_fns = {
.fmt_fn = ocirc_cevent_fmt,
};
-static int
+int
ocirc_add_pubsub(struct pubsub_connector_t *connector)
{
if (DISPATCH_REGISTER_TYPE(connector, ocirc_state, &ocirc_state_fns))
@@ -119,10 +119,3 @@ ocirc_cevent_publish(ocirc_cevent_msg_t *msg)
{
PUBLISH(ocirc_cevent, msg);
}
-
-const subsys_fns_t sys_ocirc_event = {
- .name = "ocirc_event",
- .supported = true,
- .level = -32,
- .add_pubsub = ocirc_add_pubsub,
-};
diff --git a/src/core/or/ocirc_event_sys.h b/src/core/or/ocirc_event_sys.h
deleted file mode 100644
index abb89b04a0..0000000000
--- a/src/core/or/ocirc_event_sys.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
-
-/**
- * \file ocirc_event_sys.h
- * \brief Declare subsystem object for the origin circuit event module.
- **/
-
-#ifndef TOR_OCIRC_EVENT_SYS_H
-#define TOR_OCIRC_EVENT_SYS_H
-
-extern const struct subsys_fns_t sys_ocirc_event;
-
-#endif /* !defined(TOR_OCIRC_EVENT_SYS_H) */
diff --git a/src/core/or/or_sys.c b/src/core/or/or_sys.c
index 394b7945e1..126f5448cf 100644
--- a/src/core/or/or_sys.c
+++ b/src/core/or/or_sys.c
@@ -34,10 +34,22 @@ subsys_or_shutdown(void)
policies_free_all();
}
+static int
+subsys_or_add_pubsub(struct pubsub_connector_t *connector)
+{
+ int rv = 0;
+ if (orconn_add_pubsub(connector) < 0)
+ rv = -1;
+ if (ocirc_add_pubsub(connector) < 0)
+ rv = -1;
+ return rv;
+}
+
const struct subsys_fns_t sys_or = {
.name = "or",
.supported = true,
.level = 20,
.initialize = subsys_or_initialize,
.shutdown = subsys_or_shutdown,
+ .add_pubsub = subsys_or_add_pubsub,
};
diff --git a/src/core/or/or_sys.h b/src/core/or/or_sys.h
index 3ae09f7b52..7ee56c8682 100644
--- a/src/core/or/or_sys.h
+++ b/src/core/or/or_sys.h
@@ -14,4 +14,8 @@
extern const struct subsys_fns_t sys_or;
+struct pubsub_connector_t;
+int ocirc_add_pubsub(struct pubsub_connector_t *connector);
+int orconn_add_pubsub(struct pubsub_connector_t *connector);
+
#endif /* !defined(TOR_CORE_OR_OR_SYS_H) */
diff --git a/src/core/or/orconn_event.c b/src/core/or/orconn_event.c
index d0a06aa040..c30e2dd22f 100644
--- a/src/core/or/orconn_event.c
+++ b/src/core/or/orconn_event.c
@@ -22,7 +22,7 @@
#define ORCONN_EVENT_PRIVATE
#include "core/or/orconn_event.h"
-#include "core/or/orconn_event_sys.h"
+#include "core/or/or_sys.h"
DECLARE_PUBLISH(orconn_state);
DECLARE_PUBLISH(orconn_status);
@@ -65,7 +65,7 @@ static dispatch_typefns_t orconn_status_fns = {
.fmt_fn = orconn_status_fmt,
};
-static int
+int
orconn_add_pubsub(struct pubsub_connector_t *connector)
{
if (DISPATCH_REGISTER_TYPE(connector, orconn_state, &orconn_state_fns))
@@ -90,10 +90,3 @@ orconn_status_publish(orconn_status_msg_t *msg)
{
PUBLISH(orconn_status, msg);
}
-
-const subsys_fns_t sys_orconn_event = {
- .name = "orconn_event",
- .supported = true,
- .level = -33,
- .add_pubsub = orconn_add_pubsub,
-};
diff --git a/src/core/or/orconn_event_sys.h b/src/core/or/orconn_event_sys.h
deleted file mode 100644
index 02f0b8116b..0000000000
--- a/src/core/or/orconn_event_sys.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Copyright (c) 2007-2020, The Tor Project, Inc. */
-
-/**
- * \file orconn_event_sys.h
- * \brief Declare subsystem object for the OR connection event module.
- **/
-#ifndef TOR_ORCONN_EVENT_SYS_H
-#define TOR_ORCONN_EVENT_SYS_H
-
-extern const struct subsys_fns_t sys_orconn_event;
-
-#endif /* !defined(TOR_ORCONN_EVENT_SYS_H) */
diff --git a/src/core/or/policies.c b/src/core/or/policies.c
index a82995fe12..dd4feaadfc 100644
--- a/src/core/or/policies.c
+++ b/src/core/or/policies.c
@@ -463,8 +463,7 @@ fascist_firewall_use_ipv6(const or_options_t *options)
* ClientPreferIPv6DirPort is deprecated, but check it anyway. */
return (options->ClientUseIPv6 == 1 || options->ClientUseIPv4 == 0 ||
options->ClientPreferIPv6ORPort == 1 ||
- options->ClientPreferIPv6DirPort == 1 || options->UseBridges == 1 ||
- options->ClientAutoIPv6ORPort == 1);
+ options->ClientPreferIPv6DirPort == 1 || options->UseBridges == 1);
}
/** Do we prefer to connect to IPv6, ignoring ClientPreferIPv6ORPort and
@@ -491,15 +490,6 @@ fascist_firewall_prefer_ipv6_impl(const or_options_t *options)
return -1;
}
-/* Choose whether we prefer IPv4 or IPv6 by randomly choosing an address
- * family. Return 0 for IPv4, and 1 for IPv6. */
-MOCK_IMPL(int,
-fascist_firewall_rand_prefer_ipv6_addr, (void))
-{
- /* TODO: Check for failures, and infer our preference based on this. */
- return crypto_rand_int(2);
-}
-
/** Do we prefer to connect to IPv6 ORPorts?
* Use node_ipv6_or_preferred() whenever possible: it supports bridge client
* per-node IPv6 preferences.
@@ -514,10 +504,7 @@ fascist_firewall_prefer_ipv6_orport(const or_options_t *options)
}
/* We can use both IPv4 and IPv6 - which do we prefer? */
- if (options->ClientAutoIPv6ORPort == 1) {
- /* If ClientAutoIPv6ORPort is 1, we prefer IPv4 or IPv6 at random. */
- return fascist_firewall_rand_prefer_ipv6_addr();
- } else if (options->ClientPreferIPv6ORPort == 1) {
+ if (options->ClientPreferIPv6ORPort == 1) {
return 1;
}
@@ -1405,9 +1392,9 @@ policy_hash(const policy_map_ent_t *ent)
}
HT_PROTOTYPE(policy_map, policy_map_ent_t, node, policy_hash,
- policy_eq)
+ policy_eq);
HT_GENERATE2(policy_map, policy_map_ent_t, node, policy_hash,
- policy_eq, 0.6, tor_reallocarray_, tor_free_)
+ policy_eq, 0.6, tor_reallocarray_, tor_free_);
/** Given a pointer to an addr_policy_t, return a copy of the pointer to the
* "canonical" copy of that addr_policy_t; the canonical copy is a single
diff --git a/src/core/or/policies.h b/src/core/or/policies.h
index b9477b2db1..72a37d62b0 100644
--- a/src/core/or/policies.h
+++ b/src/core/or/policies.h
@@ -70,7 +70,6 @@ typedef struct short_policy_t {
int firewall_is_fascist_or(void);
int firewall_is_fascist_dir(void);
int fascist_firewall_use_ipv6(const or_options_t *options);
-MOCK_DECL(int, fascist_firewall_rand_prefer_ipv6_addr, (void));
int fascist_firewall_prefer_ipv6_orport(const or_options_t *options);
int fascist_firewall_prefer_ipv6_dirport(const or_options_t *options);
diff --git a/src/core/or/protover.c b/src/core/or/protover.c
index 2a0a06f951..c3f443631b 100644
--- a/src/core/or/protover.c
+++ b/src/core/or/protover.c
@@ -40,8 +40,8 @@ static const struct {
protocol_type_t protover_type;
const char *name;
/* If you add a new protocol here, you probably also want to add
- * parsing for it in routerstatus_parse_entry_from_string() so that
- * it is set in routerstatus_t */
+ * parsing for it in summarize_protover_flags(), so that it has a
+ * summary flag in routerstatus_t */
} PROTOCOL_NAMES[] = {
{ PRT_LINK, "Link" },
{ PRT_LINKAUTH, "LinkAuth" },
@@ -391,6 +391,7 @@ protover_get_supported_protocols(void)
"Cons=1-2 "
"Desc=1-2 "
"DirCache=1-2 "
+ "FlowCtrl=1 "
"HSDir=1-2 "
"HSIntro=3-5 "
"HSRend=1-2 "
@@ -401,9 +402,8 @@ protover_get_supported_protocols(void)
"LinkAuth=3 "
#endif
"Microdesc=1-2 "
- "Relay=1-2 "
"Padding=2 "
- "FlowCtrl=1";
+ "Relay=1-2";
}
/** The protocols from protover_get_supported_protocols(), as parsed into a
diff --git a/src/core/or/scheduler.c b/src/core/or/scheduler.c
index cd9aa54642..6633ccfe1f 100644
--- a/src/core/or/scheduler.c
+++ b/src/core/or/scheduler.c
@@ -502,7 +502,12 @@ scheduler_free_all(void)
the_scheduler = NULL;
}
-/** Mark a channel as no longer ready to accept writes. */
+/** Mark a channel as no longer ready to accept writes.
+ *
+ * Possible state changes:
+ * - SCHED_CHAN_PENDING -> SCHED_CHAN_WAITING_TO_WRITE
+ * - SCHED_CHAN_WAITING_FOR_CELLS -> SCHED_CHAN_IDLE
+ */
MOCK_IMPL(void,
scheduler_channel_doesnt_want_writes,(channel_t *chan))
{
@@ -513,31 +518,32 @@ scheduler_channel_doesnt_want_writes,(channel_t *chan))
return;
}
- /* If it's already in pending, we can put it in waiting_to_write */
if (chan->scheduler_state == SCHED_CHAN_PENDING) {
/*
- * It's in channels_pending, so it shouldn't be in any of
- * the other lists. It can't write any more, so it goes to
- * channels_waiting_to_write.
+ * It has cells but no longer can write, so it becomes
+ * SCHED_CHAN_WAITING_TO_WRITE. It's in channels_pending, so we
+ * should remove it from the list.
*/
smartlist_pqueue_remove(channels_pending,
scheduler_compare_channels,
offsetof(channel_t, sched_heap_idx),
chan);
scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_TO_WRITE);
- } else {
+ } else if (chan->scheduler_state == SCHED_CHAN_WAITING_FOR_CELLS) {
/*
- * It's not in pending, so it can't become waiting_to_write; it's
- * either not in any of the lists (nothing to do) or it's already in
- * waiting_for_cells (remove it, can't write any more).
+ * It does not have cells and no longer can write, so it becomes
+ * SCHED_CHAN_IDLE.
*/
- if (chan->scheduler_state == SCHED_CHAN_WAITING_FOR_CELLS) {
- scheduler_set_channel_state(chan, SCHED_CHAN_IDLE);
- }
+ scheduler_set_channel_state(chan, SCHED_CHAN_IDLE);
}
}
-/** Mark a channel as having waiting cells. */
+/** Mark a channel as having waiting cells.
+ *
+ * Possible state changes:
+ * - SCHED_CHAN_WAITING_FOR_CELLS -> SCHED_CHAN_PENDING
+ * - SCHED_CHAN_IDLE -> SCHED_CHAN_WAITING_TO_WRITE
+ */
MOCK_IMPL(void,
scheduler_channel_has_waiting_cells,(channel_t *chan))
{
@@ -548,12 +554,11 @@ scheduler_channel_has_waiting_cells,(channel_t *chan))
return;
}
- /* First, check if it's also writeable */
if (chan->scheduler_state == SCHED_CHAN_WAITING_FOR_CELLS) {
/*
- * It's in channels_waiting_for_cells, so it shouldn't be in any of
- * the other lists. It has waiting cells now, so it goes to
- * channels_pending.
+ * It is able to write and now has cells, so it becomes
+ * SCHED_CHAN_PENDING. It must be added to the channels_pending
+ * list.
*/
scheduler_set_channel_state(chan, SCHED_CHAN_PENDING);
if (!SCHED_BUG(chan->sched_heap_idx != -1, chan)) {
@@ -565,16 +570,12 @@ scheduler_channel_has_waiting_cells,(channel_t *chan))
/* If we made a channel pending, we potentially have scheduling work to
* do. */
the_scheduler->schedule();
- } else {
+ } else if (chan->scheduler_state == SCHED_CHAN_IDLE) {
/*
- * It's not in waiting_for_cells, so it can't become pending; it's
- * either not in any of the lists (we add it to waiting_to_write)
- * or it's already in waiting_to_write or pending (we do nothing)
+ * It is not able to write but now has cells, so it becomes
+ * SCHED_CHAN_WAITING_TO_WRITE.
*/
- if (!(chan->scheduler_state == SCHED_CHAN_WAITING_TO_WRITE ||
- chan->scheduler_state == SCHED_CHAN_PENDING)) {
- scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_TO_WRITE);
- }
+ scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_TO_WRITE);
}
}
@@ -662,8 +663,12 @@ scheduler_release_channel,(channel_t *chan))
scheduler_set_channel_state(chan, SCHED_CHAN_IDLE);
}
-/** Mark a channel as ready to accept writes */
-
+/** Mark a channel as ready to accept writes.
+ * Possible state changes:
+ *
+ * - SCHED_CHAN_WAITING_TO_WRITE -> SCHED_CHAN_PENDING
+ * - SCHED_CHAN_IDLE -> SCHED_CHAN_WAITING_FOR_CELLS
+ */
void
scheduler_channel_wants_writes(channel_t *chan)
{
@@ -674,10 +679,11 @@ scheduler_channel_wants_writes(channel_t *chan)
return;
}
- /* If it's already in waiting_to_write, we can put it in pending */
if (chan->scheduler_state == SCHED_CHAN_WAITING_TO_WRITE) {
/*
- * It can write now, so it goes to channels_pending.
+ * It has cells and can now write, so it becomes
+ * SCHED_CHAN_PENDING. It must be added to the channels_pending
+ * list.
*/
scheduler_set_channel_state(chan, SCHED_CHAN_PENDING);
if (!SCHED_BUG(chan->sched_heap_idx != -1, chan)) {
@@ -688,15 +694,12 @@ scheduler_channel_wants_writes(channel_t *chan)
}
/* We just made a channel pending, we have scheduling work to do. */
the_scheduler->schedule();
- } else {
+ } else if (chan->scheduler_state == SCHED_CHAN_IDLE) {
/*
- * It's not in SCHED_CHAN_WAITING_TO_WRITE, so it can't become pending;
- * it's either idle and goes to WAITING_FOR_CELLS, or it's a no-op.
+ * It does not have cells but can now write, so it becomes
+ * SCHED_CHAN_WAITING_FOR_CELLS.
*/
- if (!(chan->scheduler_state == SCHED_CHAN_WAITING_FOR_CELLS ||
- chan->scheduler_state == SCHED_CHAN_PENDING)) {
- scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_FOR_CELLS);
- }
+ scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_FOR_CELLS);
}
}
diff --git a/src/core/or/scheduler_kist.c b/src/core/or/scheduler_kist.c
index e56942be09..c73d768f88 100644
--- a/src/core/or/scheduler_kist.c
+++ b/src/core/or/scheduler_kist.c
@@ -56,9 +56,9 @@ typedef HT_HEAD(socket_table_s, socket_table_ent_t) socket_table_t;
static socket_table_t socket_table = HT_INITIALIZER();
HT_PROTOTYPE(socket_table_s, socket_table_ent_t, node, socket_table_ent_hash,
- socket_table_ent_eq)
+ socket_table_ent_eq);
HT_GENERATE2(socket_table_s, socket_table_ent_t, node, socket_table_ent_hash,
- socket_table_ent_eq, 0.6, tor_reallocarray, tor_free_)
+ socket_table_ent_eq, 0.6, tor_reallocarray, tor_free_);
/* outbuf_table hash table stuff. The outbuf_table keeps track of which
* channels have data sitting in their outbuf so the kist scheduler can force
@@ -83,9 +83,9 @@ outbuf_table_ent_eq(const outbuf_table_ent_t *a, const outbuf_table_ent_t *b)
}
HT_PROTOTYPE(outbuf_table_s, outbuf_table_ent_t, node, outbuf_table_ent_hash,
- outbuf_table_ent_eq)
+ outbuf_table_ent_eq);
HT_GENERATE2(outbuf_table_s, outbuf_table_ent_t, node, outbuf_table_ent_hash,
- outbuf_table_ent_eq, 0.6, tor_reallocarray, tor_free_)
+ outbuf_table_ent_eq, 0.6, tor_reallocarray, tor_free_);
/*****************************************************************************
* Other internal data
@@ -463,6 +463,13 @@ MOCK_IMPL(void, channel_write_to_kernel, (channel_t *chan))
log_debug(LD_SCHED, "Writing %lu bytes to kernel for chan %" PRIu64,
(unsigned long)channel_outbuf_length(chan),
chan->global_identifier);
+ /* Note that 'connection_handle_write()' may change the scheduler state of
+ * the channel during the scheduling loop with
+ * 'connection_or_flushed_some()' -> 'scheduler_channel_wants_writes()'.
+ * This side-effect will only occur if the channel is currently in the
+ * 'SCHED_CHAN_WAITING_TO_WRITE' or 'SCHED_CHAN_IDLE' states, which KIST
+ * rarely uses, so it should be fine unless KIST begins using these states
+ * in the future. */
connection_handle_write(TO_CONN(BASE_CHAN_TO_TLS(chan)->conn), 0);
}
diff --git a/src/core/or/status.c b/src/core/or/status.c
index f9f603f3b7..ed8448883c 100644
--- a/src/core/or/status.c
+++ b/src/core/or/status.c
@@ -17,6 +17,7 @@
#include "core/or/or.h"
#include "core/or/circuituse.h"
#include "app/config/config.h"
+#include "feature/dirclient/dirclient.h"
#include "core/or/status.h"
#include "feature/nodelist/nodelist.h"
#include "core/or/relay.h"
@@ -146,6 +147,8 @@ log_heartbeat(time_t now)
uptime, count_circuits(), bw_sent, bw_rcvd,
hibernating?" We are currently hibernating.":"");
+ dirclient_dump_total_dls();
+
if (server_mode(options) && accounting_is_enabled(options) && !hibernating) {
log_accounting(now, options);
}
diff --git a/src/core/proto/proto_ext_or.h b/src/core/proto/proto_ext_or.h
index daac3e3eb7..3408599fb7 100644
--- a/src/core/proto/proto_ext_or.h
+++ b/src/core/proto/proto_ext_or.h
@@ -24,4 +24,11 @@ struct ext_or_cmd_t {
int fetch_ext_or_command_from_buf(struct buf_t *buf,
struct ext_or_cmd_t **out);
+ext_or_cmd_t *ext_or_cmd_new(uint16_t len);
+
+#define ext_or_cmd_free(cmd) \
+ FREE_AND_NULL(ext_or_cmd_t, ext_or_cmd_free_, (cmd))
+
+void ext_or_cmd_free_(ext_or_cmd_t *cmd);
+
#endif /* !defined(TOR_PROTO_EXT_OR_H) */
diff --git a/src/ext/ht.h b/src/ext/ht.h
index 9d4add1936..4bfce36903 100644
--- a/src/ext/ht.h
+++ b/src/ext/ht.h
@@ -232,6 +232,10 @@ ht_string_hash(const char *s)
#define HT_ASSERT_(x) (void)0
#endif
+/* Macro put at the end of the end of a macro definition so that it
+ * consumes the following semicolon at file scope. Used only inside ht.h. */
+#define HT_EAT_SEMICOLON__ struct ht_semicolon_eater
+
#define HT_PROTOTYPE(name, type, field, hashfn, eqfn) \
int name##_HT_GROW(struct name *ht, unsigned min_capacity); \
void name##_HT_CLEAR(struct name *ht); \
@@ -413,7 +417,8 @@ ht_string_hash(const char *s)
} \
return NULL; \
} \
- }
+ } \
+ HT_EAT_SEMICOLON__
#define HT_GENERATE2(name, type, field, hashfn, eqfn, load, reallocarrayfn, \
freefn) \
@@ -538,7 +543,8 @@ ht_string_hash(const char *s)
if (n != head->hth_n_entries) \
return 6; \
return 0; \
- }
+ } \
+ HT_EAT_SEMICOLON__
#define HT_GENERATE(name, type, field, hashfn, eqfn, load, mallocfn, \
reallocfn, freefn) \
diff --git a/src/feature/client/addressmap.c b/src/feature/client/addressmap.c
index 1a6958d38c..cc97166f36 100644
--- a/src/feature/client/addressmap.c
+++ b/src/feature/client/addressmap.c
@@ -23,7 +23,6 @@
#include "app/config/config.h"
#include "core/or/connection_edge.h"
#include "feature/control/control_events.h"
-#include "feature/relay/dns.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerset.h"
@@ -689,7 +688,7 @@ client_dns_set_addressmap_impl(entry_connection_t *for_conn,
if (ttl<0)
ttl = DEFAULT_DNS_TTL;
else
- ttl = dns_clip_ttl(ttl);
+ ttl = clip_dns_ttl(ttl);
if (exitname) {
/* XXXX fails to ever get attempts to get an exit address of
diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c
index 2b52a1173d..66b04f3bc2 100644
--- a/src/feature/client/bridges.c
+++ b/src/feature/client/bridges.c
@@ -844,8 +844,7 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
}
}
- if (options->ClientPreferIPv6ORPort == -1 ||
- options->ClientAutoIPv6ORPort == 0) {
+ if (options->ClientPreferIPv6ORPort == -1) {
/* Mark which address to use based on which bridge_t we got. */
node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 &&
!tor_addr_is_null(&node->ri->ipv6_addr));
diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c
index 8962f65006..2843558e93 100644
--- a/src/feature/client/entrynodes.c
+++ b/src/feature/client/entrynodes.c
@@ -1974,10 +1974,12 @@ get_retry_schedule(time_t failing_since, time_t now,
const struct {
time_t maximum; int primary_delay; int nonprimary_delay;
} delays[] = {
+ // clang-format off
{ SIX_HOURS, 10*60, 1*60*60 },
{ FOUR_DAYS, 90*60, 4*60*60 },
{ SEVEN_DAYS, 4*60*60, 18*60*60 },
{ TIME_MAX, 9*60*60, 36*60*60 }
+ // clang-format on
};
unsigned i;
diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c
index a8ea9781a4..55069bb60a 100644
--- a/src/feature/client/transports.c
+++ b/src/feature/client/transports.c
@@ -1420,8 +1420,10 @@ create_managed_proxy_environment(const managed_proxy_t *mp)
smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT=%s",
ext_or_addrport_tmp);
}
- smartlist_add_asprintf(envs, "TOR_PT_AUTH_COOKIE_FILE=%s",
- cookie_file_loc);
+ if (cookie_file_loc) {
+ smartlist_add_asprintf(envs, "TOR_PT_AUTH_COOKIE_FILE=%s",
+ cookie_file_loc);
+ }
tor_free(ext_or_addrport_tmp);
tor_free(cookie_file_loc);
diff --git a/src/feature/control/btrack.c b/src/feature/control/btrack.c
index 874150ee13..3595af0fcc 100644
--- a/src/feature/control/btrack.c
+++ b/src/feature/control/btrack.c
@@ -57,7 +57,7 @@ btrack_add_pubsub(pubsub_connector_t *connector)
const subsys_fns_t sys_btrack = {
.name = "btrack",
.supported = true,
- .level = -30,
+ .level = 55,
.initialize = btrack_init,
.shutdown = btrack_fini,
.add_pubsub = btrack_add_pubsub,
diff --git a/src/feature/control/btrack_orconn_maps.c b/src/feature/control/btrack_orconn_maps.c
index 0ef54237a8..a60dffb8c4 100644
--- a/src/feature/control/btrack_orconn_maps.c
+++ b/src/feature/control/btrack_orconn_maps.c
@@ -47,17 +47,18 @@ bto_chan_eq_(bt_orconn_t *a, bt_orconn_t *b)
}
HT_HEAD(bto_gid_ht, bt_orconn_t);
-HT_PROTOTYPE(bto_gid_ht, bt_orconn_t, node, bto_gid_hash_, bto_gid_eq_)
+HT_PROTOTYPE(bto_gid_ht, bt_orconn_t, node, bto_gid_hash_, bto_gid_eq_);
HT_GENERATE2(bto_gid_ht, bt_orconn_t, node,
bto_gid_hash_, bto_gid_eq_, 0.6,
- tor_reallocarray_, tor_free_)
+ tor_reallocarray_, tor_free_);
static struct bto_gid_ht *bto_gid_map;
HT_HEAD(bto_chan_ht, bt_orconn_t);
-HT_PROTOTYPE(bto_chan_ht, bt_orconn_t, chan_node, bto_chan_hash_, bto_chan_eq_)
+HT_PROTOTYPE(bto_chan_ht, bt_orconn_t, chan_node, bto_chan_hash_,
+ bto_chan_eq_);
HT_GENERATE2(bto_chan_ht, bt_orconn_t, chan_node,
bto_chan_hash_, bto_chan_eq_, 0.6,
- tor_reallocarray_, tor_free_)
+ tor_reallocarray_, tor_free_);
static struct bto_chan_ht *bto_chan_map;
/** Clear the GID hash map, freeing any bt_orconn_t objects that become
diff --git a/src/feature/control/control_bootstrap.c b/src/feature/control/control_bootstrap.c
index 2e78fad690..fee7612ba2 100644
--- a/src/feature/control/control_bootstrap.c
+++ b/src/feature/control/control_bootstrap.c
@@ -171,6 +171,12 @@ control_event_bootstrap_core(int loglevel, bootstrap_status_t status,
control_event_client_status(LOG_NOTICE, "%s", buf);
}
+int
+control_get_bootstrap_percent(void)
+{
+ return bootstrap_percent;
+}
+
/** Called when Tor has made progress at bootstrapping its directory
* information and initial circuits.
*
diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c
index c2d23243e5..cdefef97e1 100644
--- a/src/feature/control/control_cmd.c
+++ b/src/feature/control/control_cmd.c
@@ -2272,7 +2272,7 @@ typedef struct control_cmd_def_t {
**/
#define ONE_LINE(name, flags) \
{ \
- #name, \
+ (#name), \
handle_control_ ##name, \
flags, \
&name##_syntax, \
@@ -2283,7 +2283,7 @@ typedef struct control_cmd_def_t {
* flags.
**/
#define MULTLINE(name, flags) \
- { "+"#name, \
+ { ("+"#name), \
handle_control_ ##name, \
flags, \
&name##_syntax \
diff --git a/src/feature/control/control_events.h b/src/feature/control/control_events.h
index 74bbc0047d..4a5492b510 100644
--- a/src/feature/control/control_events.h
+++ b/src/feature/control/control_events.h
@@ -12,6 +12,7 @@
#ifndef TOR_CONTROL_EVENTS_H
#define TOR_CONTROL_EVENTS_H
+#include "lib/cc/ctassert.h"
#include "core/or/ocirc_event.h"
#include "core/or/orconn_event.h"
@@ -164,6 +165,7 @@ int control_event_buildtimeout_set(buildtimeout_set_event_t type,
int control_event_signal(uintptr_t signal);
void control_event_bootstrap(bootstrap_status_t status, int progress);
+int control_get_bootstrap_percent(void);
MOCK_DECL(void, control_event_bootstrap_prob_or,(const char *warn,
int reason,
or_connection_t *or_conn));
@@ -287,10 +289,7 @@ typedef uint64_t event_mask_t;
/* If EVENT_MAX_ ever hits 0x0040, we need to make the mask into a
* different structure, as it can only handle a maximum left shift of 1<<63. */
-
-#if EVENT_MAX_ >= EVENT_CAPACITY_
-#error control_connection_t.event_mask has an event greater than its capacity
-#endif
+CTASSERT(EVENT_MAX_ < EVENT_CAPACITY_);
#define EVENT_MASK_(e) (((uint64_t)1)<<(e))
diff --git a/src/feature/dirauth/dirauth_config.c b/src/feature/dirauth/dirauth_config.c
index ca16dc8424..38d2a8bc5a 100644
--- a/src/feature/dirauth/dirauth_config.c
+++ b/src/feature/dirauth/dirauth_config.c
@@ -21,7 +21,7 @@
#include "core/or/or.h"
#include "app/config/config.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/stats/rephist.h"
#include "feature/dirauth/authmode.h"
@@ -305,7 +305,7 @@ options_act_dirauth(const or_options_t *old_options)
/* We may need to reschedule some dirauth stuff if our status changed. */
if (old_options) {
if (options_transition_affects_dirauth_timing(old_options, options)) {
- voting_schedule_recalculate_timing(options, time(NULL));
+ dirauth_sched_recalculate_timing(options, time(NULL));
reschedule_dirvote(options);
}
}
diff --git a/src/feature/dirauth/dircollate.c b/src/feature/dirauth/dircollate.c
index b35cb021ff..2657f53853 100644
--- a/src/feature/dirauth/dircollate.c
+++ b/src/feature/dirauth/dircollate.c
@@ -90,9 +90,9 @@ ddmap_entry_set_digests(ddmap_entry_t *ent,
}
HT_PROTOTYPE(double_digest_map, ddmap_entry_t, node, ddmap_entry_hash,
- ddmap_entry_eq)
+ ddmap_entry_eq);
HT_GENERATE2(double_digest_map, ddmap_entry_t, node, ddmap_entry_hash,
- ddmap_entry_eq, 0.6, tor_reallocarray, tor_free_)
+ ddmap_entry_eq, 0.6, tor_reallocarray, tor_free_);
/** Helper: add a single vote_routerstatus_t <b>vrs</b> to the collator
* <b>dc</b>, indexing it by its RSA key digest, and by the 2-tuple of its RSA
@@ -324,4 +324,3 @@ dircollator_get_votes_for_router(dircollator_t *dc, int idx)
return digestmap_get(dc->by_collated_rsa_sha1,
smartlist_get(dc->all_rsa_sha1_lst, idx));
}
-
diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c
index e230815ca3..7eb2b720a6 100644
--- a/src/feature/dirauth/dirvote.c
+++ b/src/feature/dirauth/dirvote.c
@@ -36,7 +36,7 @@
#include "feature/stats/rephist.h"
#include "feature/client/entrynodes.h" /* needed for guardfraction methods */
#include "feature/nodelist/torcert.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/authmode.h"
@@ -886,7 +886,7 @@ dirvote_get_intermediate_param_value(const smartlist_t *param_list,
int ok;
value = (int32_t)
tor_parse_long(integer_str, 10, INT32_MIN, INT32_MAX, &ok, NULL);
- if (BUG(! ok))
+ if (BUG(!ok))
return default_val;
++n_found;
}
@@ -2853,7 +2853,7 @@ dirvote_act(const or_options_t *options, time_t now)
"Mine is %s.",
keys, hex_str(c->cache_info.identity_digest, DIGEST_LEN));
tor_free(keys);
- voting_schedule_recalculate_timing(options, now);
+ dirauth_sched_recalculate_timing(options, now);
}
#define IF_TIME_FOR_NEXT_ACTION(when_field, done_field) \
@@ -2899,7 +2899,7 @@ dirvote_act(const or_options_t *options, time_t now)
networkstatus_get_latest_consensus_by_flavor(FLAV_NS));
/* XXXX We will want to try again later if we haven't got enough
* signatures yet. Implement this if it turns out to ever happen. */
- voting_schedule_recalculate_timing(options, now);
+ dirauth_sched_recalculate_timing(options, now);
return voting_schedule.voting_starts;
} ENDIF
@@ -2966,7 +2966,7 @@ dirvote_perform_vote(void)
if (!contents)
return -1;
- pending_vote = dirvote_add_vote(contents, &msg, &status);
+ pending_vote = dirvote_add_vote(contents, 0, &msg, &status);
tor_free(contents);
if (!pending_vote) {
log_warn(LD_DIR, "Couldn't store my own vote! (I told myself, '%s'.)",
@@ -3122,13 +3122,45 @@ list_v3_auth_ids(void)
return keys;
}
+/* Check the voter information <b>vi</b>, and assert that at least one
+ * signature is good. Asserts on failure. */
+static void
+assert_any_sig_good(const networkstatus_voter_info_t *vi)
+{
+ int any_sig_good = 0;
+ SMARTLIST_FOREACH(vi->sigs, document_signature_t *, sig,
+ if (sig->good_signature)
+ any_sig_good = 1);
+ tor_assert(any_sig_good);
+}
+
+/* Add <b>cert</b> to our list of known authority certificates. */
+static void
+add_new_cert_if_needed(const struct authority_cert_t *cert)
+{
+ tor_assert(cert);
+ if (!authority_cert_get_by_digests(cert->cache_info.identity_digest,
+ cert->signing_key_digest)) {
+ /* Hey, it's a new cert! */
+ trusted_dirs_load_certs_from_string(
+ cert->cache_info.signed_descriptor_body,
+ TRUSTED_DIRS_CERTS_SRC_FROM_VOTE, 1 /*flush*/,
+ NULL);
+ if (!authority_cert_get_by_digests(cert->cache_info.identity_digest,
+ cert->signing_key_digest)) {
+ log_warn(LD_BUG, "We added a cert, but still couldn't find it.");
+ }
+ }
+}
+
/** Called when we have received a networkstatus vote in <b>vote_body</b>.
* Parse and validate it, and on success store it as a pending vote (which we
* then return). Return NULL on failure. Sets *<b>msg_out</b> and
* *<b>status_out</b> to an HTTP response and status code. (V3 authority
* only) */
pending_vote_t *
-dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
+dirvote_add_vote(const char *vote_body, time_t time_posted,
+ const char **msg_out, int *status_out)
{
networkstatus_t *vote;
networkstatus_voter_info_t *vi;
@@ -3159,13 +3191,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
}
tor_assert(smartlist_len(vote->voters) == 1);
vi = get_voter(vote);
- {
- int any_sig_good = 0;
- SMARTLIST_FOREACH(vi->sigs, document_signature_t *, sig,
- if (sig->good_signature)
- any_sig_good = 1);
- tor_assert(any_sig_good);
- }
+ assert_any_sig_good(vi);
ds = trusteddirserver_get_by_v3_auth_digest(vi->identity_digest);
if (!ds) {
char *keys = list_v3_auth_ids();
@@ -3178,19 +3204,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
*msg_out = "Vote not from a recognized v3 authority";
goto err;
}
- tor_assert(vote->cert);
- if (!authority_cert_get_by_digests(vote->cert->cache_info.identity_digest,
- vote->cert->signing_key_digest)) {
- /* Hey, it's a new cert! */
- trusted_dirs_load_certs_from_string(
- vote->cert->cache_info.signed_descriptor_body,
- TRUSTED_DIRS_CERTS_SRC_FROM_VOTE, 1 /*flush*/,
- NULL);
- if (!authority_cert_get_by_digests(vote->cert->cache_info.identity_digest,
- vote->cert->signing_key_digest)) {
- log_warn(LD_BUG, "We added a cert, but still couldn't find it.");
- }
- }
+ add_new_cert_if_needed(vote->cert);
/* Is it for the right period? */
if (vote->valid_after != voting_schedule.interval_starts) {
@@ -3203,6 +3217,23 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
goto err;
}
+ /* Check if we received it, as a post, after the cutoff when we
+ * start asking other dir auths for it. If we do, the best plan
+ * is to discard it, because using it greatly increases the chances
+ * of a split vote for this round (some dir auths got it in time,
+ * some didn't). */
+ if (time_posted && time_posted > voting_schedule.fetch_missing_votes) {
+ char tbuf1[ISO_TIME_LEN+1], tbuf2[ISO_TIME_LEN+1];
+ format_iso_time(tbuf1, time_posted);
+ format_iso_time(tbuf2, voting_schedule.fetch_missing_votes);
+ log_warn(LD_DIR, "Rejecting posted vote from %s received at %s; "
+ "our cutoff for received votes is %s. Check your clock, "
+ "CPU load, and network load. Also check the authority that "
+ "posted the vote.", vi->address, tbuf1, tbuf2);
+ *msg_out = "Posted vote received too late, would be dangerous to count it";
+ goto err;
+ }
+
/* Fetch any new router descriptors we just learned about */
update_consensus_router_descriptor_downloads(time(NULL), 1, vote);
@@ -4613,7 +4644,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
else
last_consensus_interval = options->TestingV3AuthInitialVotingInterval;
v3_out->valid_after =
- voting_schedule_get_start_of_next_interval(now,
+ voting_sched_get_start_of_interval_after(now,
(int)last_consensus_interval,
options->TestingV3AuthVotingStartOffset);
format_iso_time(tbuf, v3_out->valid_after);
@@ -4635,17 +4666,14 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
/* These are hardwired, to avoid disaster. */
v3_out->recommended_relay_protocols =
- tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
- "Link=4 Microdesc=1-2 Relay=2");
+ tor_strdup(DIRVOTE_RECCOMEND_RELAY_PROTO);
v3_out->recommended_client_protocols =
- tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
- "Link=4 Microdesc=1-2 Relay=2");
- v3_out->required_client_protocols =
- tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
- "Link=4 Microdesc=1-2 Relay=2");
+ tor_strdup(DIRVOTE_RECCOMEND_CLIENT_PROTO);
+
v3_out->required_relay_protocols =
- tor_strdup("Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 "
- "Link=3-4 Microdesc=1 Relay=1-2");
+ tor_strdup(DIRVOTE_REQUIRE_RELAY_PROTO);
+ v3_out->required_client_protocols =
+ tor_strdup(DIRVOTE_REQUIRE_CLIENT_PROTO);
/* We are not allowed to vote to require anything we don't have. */
tor_assert(protover_all_supported(v3_out->required_relay_protocols, NULL));
diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h
index 675f4ee148..fa7b1da4ab 100644
--- a/src/feature/dirauth/dirvote.h
+++ b/src/feature/dirauth/dirvote.h
@@ -94,6 +94,7 @@ void dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items,
/* Storing signatures and votes functions */
struct pending_vote_t * dirvote_add_vote(const char *vote_body,
+ time_t time_posted,
const char **msg_out,
int *status_out);
int dirvote_add_signatures(const char *detached_signatures_body,
@@ -142,9 +143,13 @@ dirvote_dirreq_get_status_vote(const char *url, smartlist_t *items,
}
static inline struct pending_vote_t *
-dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
+dirvote_add_vote(const char *vote_body,
+ time_t time_posted,
+ const char **msg_out,
+ int *status_out)
{
(void) vote_body;
+ (void) time_posted;
/* If the dirauth module is disabled, this should NEVER be called else we
* failed to safeguard the dirauth module. */
tor_assert_nonfatal_unreached();
@@ -230,6 +235,36 @@ char *networkstatus_get_detached_signatures(smartlist_t *consensuses);
STATIC microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri,
int consensus_method);
+/** The recommended relay protocols for this authority's votes.
+ * Recommending a new protocol causes old tor versions to log a warning.
+ */
+#define DIRVOTE_RECCOMEND_RELAY_PROTO \
+ "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " \
+ "Link=4 Microdesc=1-2 Relay=2"
+/** The recommended client protocols for this authority's votes.
+ * Recommending a new protocol causes old tor versions to log a warning.
+ */
+#define DIRVOTE_RECCOMEND_CLIENT_PROTO \
+ "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " \
+ "Link=4 Microdesc=1-2 Relay=2"
+
+/** The required relay protocols for this authority's votes.
+ * WARNING: Requiring a new protocol causes old tor versions to shut down.
+ * Requiring the wrong protocols can break the tor network.
+ * See Proposal 303: When and how to remove support for protocol versions.
+ */
+#define DIRVOTE_REQUIRE_RELAY_PROTO \
+ "Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " \
+ "Link=3-4 Microdesc=1 Relay=1-2"
+/** The required relay protocols for this authority's votes.
+ * WARNING: Requiring a new protocol causes old tor versions to shut down.
+ * Requiring the wrong protocols can break the tor network.
+ * See Proposal 303: When and how to remove support for protocol versions.
+ */
+#define DIRVOTE_REQUIRE_CLIENT_PROTO \
+ "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " \
+ "Link=4 Microdesc=1-2 Relay=2"
+
#endif /* defined(DIRVOTE_PRIVATE) */
#endif /* !defined(TOR_DIRVOTE_H) */
diff --git a/src/feature/dirauth/include.am b/src/feature/dirauth/include.am
index 2ef629ae35..e26f120d4e 100644
--- a/src/feature/dirauth/include.am
+++ b/src/feature/dirauth/include.am
@@ -19,7 +19,8 @@ MODULE_DIRAUTH_SOURCES = \
src/feature/dirauth/recommend_pkg.c \
src/feature/dirauth/shared_random.c \
src/feature/dirauth/shared_random_state.c \
- src/feature/dirauth/voteflags.c
+ src/feature/dirauth/voteflags.c \
+ src/feature/dirauth/voting_schedule.c
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
@@ -43,7 +44,8 @@ noinst_HEADERS += \
src/feature/dirauth/shared_random.h \
src/feature/dirauth/shared_random_state.h \
src/feature/dirauth/vote_microdesc_hash_st.h \
- src/feature/dirauth/voteflags.h
+ src/feature/dirauth/voteflags.h \
+ src/feature/dirauth/voting_schedule.h
if BUILD_MODULE_DIRAUTH
LIBTOR_APP_A_SOURCES += $(MODULE_DIRAUTH_SOURCES)
diff --git a/src/feature/dirauth/keypin.c b/src/feature/dirauth/keypin.c
index 6f6cfc01f1..98584a7d42 100644
--- a/src/feature/dirauth/keypin.c
+++ b/src/feature/dirauth/keypin.c
@@ -118,14 +118,14 @@ return (unsigned) siphash24g(a->ed25519_key, sizeof(a->ed25519_key));
}
HT_PROTOTYPE(rsamap, keypin_ent_st, rsamap_node, keypin_ent_hash_rsa,
- keypin_ents_eq_rsa)
+ keypin_ents_eq_rsa);
HT_GENERATE2(rsamap, keypin_ent_st, rsamap_node, keypin_ent_hash_rsa,
- keypin_ents_eq_rsa, 0.6, tor_reallocarray, tor_free_)
+ keypin_ents_eq_rsa, 0.6, tor_reallocarray, tor_free_);
HT_PROTOTYPE(edmap, keypin_ent_st, edmap_node, keypin_ent_hash_ed,
- keypin_ents_eq_ed)
+ keypin_ents_eq_ed);
HT_GENERATE2(edmap, keypin_ent_st, edmap_node, keypin_ent_hash_ed,
- keypin_ents_eq_ed, 0.6, tor_reallocarray, tor_free_)
+ keypin_ents_eq_ed, 0.6, tor_reallocarray, tor_free_);
/**
* Check whether we already have an entry in the key pinning table for a
diff --git a/src/feature/dirauth/shared_random.c b/src/feature/dirauth/shared_random.c
index 48e2147ea6..fd55008242 100644
--- a/src/feature/dirauth/shared_random.c
+++ b/src/feature/dirauth/shared_random.c
@@ -99,7 +99,7 @@
#include "feature/nodelist/dirlist.h"
#include "feature/hs_common/shared_random_client.h"
#include "feature/dirauth/shared_random_state.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/authmode.h"
@@ -1261,7 +1261,7 @@ sr_act_post_consensus(const networkstatus_t *consensus)
}
/* Prepare our state so that it's ready for the next voting period. */
- sr_state_update(voting_schedule_get_next_valid_after_time());
+ sr_state_update(dirauth_sched_get_next_valid_after_time());
}
/** Initialize shared random subsystem. This MUST be called early in the boot
diff --git a/src/feature/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c
index 1792d540c6..598d781557 100644
--- a/src/feature/dirauth/shared_random_state.c
+++ b/src/feature/dirauth/shared_random_state.c
@@ -20,7 +20,7 @@
#include "feature/dirauth/shared_random.h"
#include "feature/hs_common/shared_random_client.h"
#include "feature/dirauth/shared_random_state.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "lib/encoding/confline.h"
#include "lib/version/torversion.h"
@@ -60,6 +60,7 @@ DUMMY_TYPECHECK_INSTANCE(sr_disk_state_t);
#define SR_DISK_STATE_MAGIC 0x98AB1254
/** Array of variables that are saved to disk as a persistent state. */
+// clang-format off
static const config_var_t state_vars[] = {
V(Version, POSINT, "0"),
V(TorVersion, STRING, NULL),
@@ -73,6 +74,7 @@ static const config_var_t state_vars[] = {
VAR("SharedRandCurrentValue", LINELIST_S, SharedRandValues, NULL),
END_OF_CONFIG_VARS
};
+// clang-format on
/** "Extra" variable in the state that receives lines we can't parse. This
* lets us preserve options from versions of Tor newer than us. */
@@ -139,7 +141,7 @@ get_state_valid_until_time(time_t now)
voting_interval = get_voting_interval();
/* Find the time the current round started. */
- beginning_of_current_round = get_start_time_of_current_round();
+ beginning_of_current_round = dirauth_sched_get_cur_valid_after_time();
/* Find how many rounds are left till the end of the protocol run */
current_round = (now / voting_interval) % total_rounds;
@@ -1330,7 +1332,7 @@ sr_state_init(int save_to_disk, int read_from_disk)
/* We have a state in memory, let's make sure it's updated for the current
* and next voting round. */
{
- time_t valid_after = voting_schedule_get_next_valid_after_time();
+ time_t valid_after = dirauth_sched_get_next_valid_after_time();
sr_state_update(valid_after);
}
return 0;
diff --git a/src/feature/dircommon/voting_schedule.c b/src/feature/dirauth/voting_schedule.c
index 389f7f6b5d..efc4a0b316 100644
--- a/src/feature/dircommon/voting_schedule.c
+++ b/src/feature/dirauth/voting_schedule.c
@@ -3,12 +3,11 @@
/**
* \file voting_schedule.c
- * \brief This file contains functions that are from the directory authority
- * subsystem related to voting specifically but used by many part of
- * tor. The full feature is built as part of the dirauth module.
+ * \brief Compute information about our voting schedule as a directory
+ * authority.
**/
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "core/or/or.h"
#include "app/config/config.h"
@@ -20,55 +19,11 @@
* Vote scheduling
* ===== */
-/** Return the start of the next interval of size <b>interval</b> (in
- * seconds) after <b>now</b>, plus <b>offset</b>. Midnight always
- * starts a fresh interval, and if the last interval of a day would be
- * truncated to less than half its size, it is rolled into the
- * previous interval. */
-time_t
-voting_schedule_get_start_of_next_interval(time_t now, int interval,
- int offset)
-{
- struct tm tm;
- time_t midnight_today=0;
- time_t midnight_tomorrow;
- time_t next;
-
- tor_gmtime_r(&now, &tm);
- tm.tm_hour = 0;
- tm.tm_min = 0;
- tm.tm_sec = 0;
-
- if (tor_timegm(&tm, &midnight_today) < 0) {
- // LCOV_EXCL_START
- log_warn(LD_BUG, "Ran into an invalid time when trying to find midnight.");
- // LCOV_EXCL_STOP
- }
- midnight_tomorrow = midnight_today + (24*60*60);
-
- next = midnight_today + ((now-midnight_today)/interval + 1)*interval;
-
- /* Intervals never cross midnight. */
- if (next > midnight_tomorrow)
- next = midnight_tomorrow;
-
- /* If the interval would only last half as long as it's supposed to, then
- * skip over to the next day. */
- if (next + interval/2 > midnight_tomorrow)
- next = midnight_tomorrow;
-
- next += offset;
- if (next - interval > now)
- next -= interval;
-
- return next;
-}
-
/* Populate and return a new voting_schedule_t that can be used to schedule
* voting. The object is allocated on the heap and it's the responsibility of
* the caller to free it. Can't fail. */
static voting_schedule_t *
-get_voting_schedule(const or_options_t *options, time_t now, int severity)
+create_voting_schedule(const or_options_t *options, time_t now, int severity)
{
int interval, vote_delay, dist_delay;
time_t start;
@@ -95,14 +50,15 @@ get_voting_schedule(const or_options_t *options, time_t now, int severity)
}
tor_assert(interval > 0);
+ new_voting_schedule->interval = interval;
if (vote_delay + dist_delay > interval/2)
vote_delay = dist_delay = interval / 4;
start = new_voting_schedule->interval_starts =
- voting_schedule_get_start_of_next_interval(now,interval,
+ voting_sched_get_start_of_interval_after(now,interval,
options->TestingV3AuthVotingStartOffset);
- end = voting_schedule_get_start_of_next_interval(start+1, interval,
+ end = voting_sched_get_start_of_interval_after(start+1, interval,
options->TestingV3AuthVotingStartOffset);
tor_assert(end > start);
@@ -139,9 +95,13 @@ voting_schedule_free_(voting_schedule_t *voting_schedule_to_free)
voting_schedule_t voting_schedule;
-/* Using the time <b>now</b>, return the next voting valid-after time. */
-time_t
-voting_schedule_get_next_valid_after_time(void)
+/**
+ * Return the current voting schedule, recreating it if necessary.
+ *
+ * Dirauth only.
+ **/
+static const voting_schedule_t *
+dirauth_get_voting_schedule(void)
{
time_t now = approx_time();
bool need_to_recalculate_voting_schedule = false;
@@ -167,27 +127,62 @@ voting_schedule_get_next_valid_after_time(void)
done:
if (need_to_recalculate_voting_schedule) {
- voting_schedule_recalculate_timing(get_options(), approx_time());
+ dirauth_sched_recalculate_timing(get_options(), approx_time());
voting_schedule.created_on_demand = 1;
}
- return voting_schedule.interval_starts;
+ return &voting_schedule;
+}
+
+/** Return the next voting valid-after time.
+ *
+ * Dirauth only. */
+time_t
+dirauth_sched_get_next_valid_after_time(void)
+{
+ return dirauth_get_voting_schedule()->interval_starts;
+}
+
+/**
+ * Return our best idea of what the valid-after time for the _current_
+ * consensus, whether we have one or not.
+ *
+ * Dirauth only.
+ **/
+time_t
+dirauth_sched_get_cur_valid_after_time(void)
+{
+ const voting_schedule_t *sched = dirauth_get_voting_schedule();
+ time_t next_start = sched->interval_starts;
+ int interval = sched->interval;
+ int offset = get_options()->TestingV3AuthVotingStartOffset;
+ return voting_sched_get_start_of_interval_after(next_start - interval - 1,
+ interval,
+ offset);
+}
+
+/** Return the voting interval that we are configured to use.
+ *
+ * Dirauth only. */
+int
+dirauth_sched_get_configured_interval(void)
+{
+ return get_options()->V3AuthVotingInterval;
}
/** Set voting_schedule to hold the timing for the next vote we should be
* doing. All type of tor do that because HS subsystem needs the timing as
* well to function properly. */
void
-voting_schedule_recalculate_timing(const or_options_t *options, time_t now)
+dirauth_sched_recalculate_timing(const or_options_t *options, time_t now)
{
voting_schedule_t *new_voting_schedule;
/* get the new voting schedule */
- new_voting_schedule = get_voting_schedule(options, now, LOG_INFO);
+ new_voting_schedule = create_voting_schedule(options, now, LOG_INFO);
tor_assert(new_voting_schedule);
/* Fill in the global static struct now */
memcpy(&voting_schedule, new_voting_schedule, sizeof(voting_schedule));
voting_schedule_free(new_voting_schedule);
}
-
diff --git a/src/feature/dircommon/voting_schedule.h b/src/feature/dirauth/voting_schedule.h
index e4c6210087..9e2ac29c75 100644
--- a/src/feature/dircommon/voting_schedule.h
+++ b/src/feature/dirauth/voting_schedule.h
@@ -11,6 +11,8 @@
#include "core/or/or.h"
+#ifdef HAVE_MODULE_DIRAUTH
+
/** Scheduling information for a voting interval. */
typedef struct {
/** When do we generate and distribute our vote for this interval? */
@@ -26,6 +28,9 @@ typedef struct {
/** When do we publish the consensus? */
time_t interval_starts;
+ /** Our computed dirauth interval */
+ int interval;
+
/** True iff we have generated and distributed our vote. */
int have_voted;
/** True iff we've requested missing votes. */
@@ -53,12 +58,36 @@ typedef struct {
extern voting_schedule_t voting_schedule;
-void voting_schedule_recalculate_timing(const or_options_t *options,
+void dirauth_sched_recalculate_timing(const or_options_t *options,
time_t now);
-time_t voting_schedule_get_start_of_next_interval(time_t now,
- int interval,
- int offset);
-time_t voting_schedule_get_next_valid_after_time(void);
+time_t dirauth_sched_get_next_valid_after_time(void);
+time_t dirauth_sched_get_cur_valid_after_time(void);
+int dirauth_sched_get_configured_interval(void);
+
+#else /* !defined(HAVE_MODULE_DIRAUTH) */
+
+#define dirauth_sched_recalculate_timing(opt,now) \
+ ((void)(opt), (void)(now))
+
+static inline time_t
+dirauth_sched_get_next_valid_after_time(void)
+{
+ tor_assert_unreached();
+ return 0;
+}
+static inline time_t
+dirauth_sched_get_cur_valid_after_time(void)
+{
+ tor_assert_unreached();
+ return 0;
+}
+static inline int
+dirauth_sched_get_configured_interval(void)
+{
+ tor_assert_unreached();
+ return 1;
+}
+#endif /* defined(HAVE_MODULE_DIRAUTH) */
#endif /* !defined(TOR_VOTING_SCHEDULE_H) */
diff --git a/src/feature/dircache/conscache.c b/src/feature/dircache/conscache.c
index ceba410a5f..d9aaccddc1 100644
--- a/src/feature/dircache/conscache.c
+++ b/src/feature/dircache/conscache.c
@@ -132,6 +132,15 @@ consensus_cache_may_overallocate(consensus_cache_t *cache)
#endif
}
+// HACK: GCC on Appveyor hates that we may assert before returning. Work around
+// the error.
+#ifdef _WIN32
+#ifndef COCCI
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn"
+#endif
+#endif
+
/**
* Tell the sandbox (if any) configured by <b>cfg</b> to allow the
* operations that <b>cache</b> will need.
@@ -156,6 +165,12 @@ consensus_cache_register_with_sandbox(consensus_cache_t *cache,
return storage_dir_register_with_sandbox(cache->dir, cfg);
}
+#ifdef _WIN32
+#ifndef COCCI
+#pragma GCC diagnostic pop
+#endif
+#endif
+
/**
* Helper: clear all entries from <b>cache</b> (but do not delete
* any that aren't marked for removal
diff --git a/src/feature/dircache/consdiffmgr.c b/src/feature/dircache/consdiffmgr.c
index 8445b8f986..10590cd6d2 100644
--- a/src/feature/dircache/consdiffmgr.c
+++ b/src/feature/dircache/consdiffmgr.c
@@ -218,9 +218,9 @@ cdm_diff_eq(const cdm_diff_t *diff1, const cdm_diff_t *diff2)
diff1->compress_method == diff2->compress_method;
}
-HT_PROTOTYPE(cdm_diff_ht, cdm_diff_t, node, cdm_diff_hash, cdm_diff_eq)
+HT_PROTOTYPE(cdm_diff_ht, cdm_diff_t, node, cdm_diff_hash, cdm_diff_eq);
HT_GENERATE2(cdm_diff_ht, cdm_diff_t, node, cdm_diff_hash, cdm_diff_eq,
- 0.6, tor_reallocarray, tor_free_)
+ 0.6, tor_reallocarray, tor_free_);
#define cdm_diff_free(diff) \
FREE_AND_NULL(cdm_diff_t, cdm_diff_free_, (diff))
diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c
index 3b8775968a..4f7f209207 100644
--- a/src/feature/dircache/dircache.c
+++ b/src/feature/dircache/dircache.c
@@ -1695,7 +1695,7 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers,
!strcmp(url,"/tor/post/vote")) { /* v3 networkstatus vote */
const char *msg = "OK";
int status;
- if (dirvote_add_vote(body, &msg, &status)) {
+ if (dirvote_add_vote(body, approx_time(), &msg, &status)) {
write_short_http_response(conn, status, "Vote stored");
} else {
tor_assert(msg);
diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c
index 1b6eed12f0..e7bec89cad 100644
--- a/src/feature/dirclient/dirclient.c
+++ b/src/feature/dirclient/dirclient.c
@@ -21,6 +21,7 @@
#include "feature/client/entrynodes.h"
#include "feature/control/control_events.h"
#include "feature/dirauth/authmode.h"
+#include "feature/dirclient/dirclient.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/shared_random.h"
#include "feature/dircache/dirserv.h"
@@ -51,6 +52,7 @@
#include "feature/rend/rendservice.h"
#include "feature/stats/predict_ports.h"
+#include "lib/cc/ctassert.h"
#include "lib/compress/compress.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -1443,9 +1445,7 @@ compare_strs_(const void **a, const void **b)
}
#define CONDITIONAL_CONSENSUS_FPR_LEN 3
-#if (CONDITIONAL_CONSENSUS_FPR_LEN > DIGEST_LEN)
-#error "conditional consensus fingerprint length is larger than digest length"
-#endif
+CTASSERT(CONDITIONAL_CONSENSUS_FPR_LEN <= DIGEST_LEN);
/** Return the URL we should use for a consensus download.
*
@@ -1964,6 +1964,44 @@ dir_client_decompress_response_body(char **bodyp, size_t *bodylenp,
return rv;
}
+/**
+ * Total number of bytes downloaded of each directory purpose, when
+ * bootstrapped, and when not bootstrapped.
+ *
+ * (For example, the number of bytes downloaded of purpose p while
+ * not fully bootstrapped is total_dl[p][false].)
+ **/
+static uint64_t total_dl[DIR_PURPOSE_MAX_][2];
+
+/**
+ * Heartbeat: dump a summary of how many bytes of which purpose we've
+ * downloaded, when bootstrapping and when not bootstrapping.
+ **/
+void
+dirclient_dump_total_dls(void)
+{
+ const or_options_t *options = get_options();
+ for (int bootstrapped = 0; bootstrapped < 2; ++bootstrapped) {
+ bool first_time = true;
+ for (int i=0; i < DIR_PURPOSE_MAX_; ++i) {
+ uint64_t n = total_dl[i][0];
+ if (n == 0)
+ continue;
+ if (options->SafeLogging_ != SAFELOG_SCRUB_NONE &&
+ purpose_needs_anonymity(i, ROUTER_PURPOSE_GENERAL, NULL))
+ continue;
+ if (first_time) {
+ log_notice(LD_NET,
+ "While %sbootstrapping, fetched this many bytes: ",
+ bootstrapped?"not ":"");
+ first_time = false;
+ }
+ log_notice(LD_NET, " %"PRIu64" (%s)",
+ n, dir_conn_purpose_to_string(i));
+ }
+ }
+}
+
/** We are a client, and we've finished reading the server's
* response. Parse it and act appropriately.
*
@@ -1997,6 +2035,16 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
received_bytes = connection_get_inbuf_len(TO_CONN(conn));
+ log_debug(LD_DIR, "Downloaded %"TOR_PRIuSZ" bytes on connection of purpose "
+ "%s; bootstrap %d%%",
+ received_bytes,
+ dir_conn_purpose_to_string(conn->base_.purpose),
+ control_get_bootstrap_percent());
+ {
+ bool bootstrapped = control_get_bootstrap_percent() == 100;
+ total_dl[conn->base_.purpose][bootstrapped] += received_bytes;
+ }
+
switch (connection_fetch_from_buf_http(TO_CONN(conn),
&headers, MAX_HEADERS_SIZE,
&body, &body_len, MAX_DIR_DL_SIZE,
@@ -2364,7 +2412,7 @@ handle_response_fetch_status_vote(dir_connection_t *conn,
conn->base_.port, conn->requested_resource);
return -1;
}
- dirvote_add_vote(body, &msg, &st);
+ dirvote_add_vote(body, 0, &msg, &st);
if (st > 299) {
log_warn(LD_DIR, "Error adding retrieved vote: %s", msg);
} else {
diff --git a/src/feature/dirclient/dirclient.h b/src/feature/dirclient/dirclient.h
index 08209721bb..096b197526 100644
--- a/src/feature/dirclient/dirclient.h
+++ b/src/feature/dirclient/dirclient.h
@@ -14,6 +14,8 @@
#include "feature/hs/hs_ident.h"
+void dirclient_dump_total_dls(void);
+
int directories_have_accepted_server_descriptor(void);
void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
dirinfo_type_t type, const char *payload,
diff --git a/src/feature/dircommon/fp_pair.c b/src/feature/dircommon/fp_pair.c
index 8b55896ba8..87e1c253bd 100644
--- a/src/feature/dircommon/fp_pair.c
+++ b/src/feature/dircommon/fp_pair.c
@@ -57,10 +57,10 @@ fp_pair_map_entry_hash(const fp_pair_map_entry_t *a)
*/
HT_PROTOTYPE(fp_pair_map_impl, fp_pair_map_entry_t, node,
- fp_pair_map_entry_hash, fp_pair_map_entries_eq)
+ fp_pair_map_entry_hash, fp_pair_map_entries_eq);
HT_GENERATE2(fp_pair_map_impl, fp_pair_map_entry_t, node,
fp_pair_map_entry_hash, fp_pair_map_entries_eq,
- 0.6, tor_reallocarray_, tor_free_)
+ 0.6, tor_reallocarray_, tor_free_);
/** Constructor to create a new empty map from fp_pair_t to void *
*/
@@ -312,4 +312,3 @@ fp_pair_map_assert_ok(const fp_pair_map_t *map)
{
tor_assert(!fp_pair_map_impl_HT_REP_IS_BAD_(&(map->head)));
}
-
diff --git a/src/feature/dircommon/include.am b/src/feature/dircommon/include.am
index f0f0323d12..87850ce183 100644
--- a/src/feature/dircommon/include.am
+++ b/src/feature/dircommon/include.am
@@ -3,8 +3,7 @@
LIBTOR_APP_A_SOURCES += \
src/feature/dircommon/consdiff.c \
src/feature/dircommon/directory.c \
- src/feature/dircommon/fp_pair.c \
- src/feature/dircommon/voting_schedule.c
+ src/feature/dircommon/fp_pair.c
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
@@ -12,5 +11,4 @@ noinst_HEADERS += \
src/feature/dircommon/dir_connection_st.h \
src/feature/dircommon/directory.h \
src/feature/dircommon/fp_pair.h \
- src/feature/dircommon/vote_timing_st.h \
- src/feature/dircommon/voting_schedule.h
+ src/feature/dircommon/vote_timing_st.h
diff --git a/src/feature/dirparse/authcert_members.h b/src/feature/dirparse/authcert_members.h
index c6755bb629..53eab175d6 100644
--- a/src/feature/dirparse/authcert_members.h
+++ b/src/feature/dirparse/authcert_members.h
@@ -14,6 +14,7 @@
#ifndef TOR_AUTHCERT_MEMBERS_H
#define TOR_AUTHCERT_MEMBERS_H
+// clang-format off
#define AUTHCERT_MEMBERS \
T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, \
GE(1), NO_OBJ ), \
@@ -25,5 +26,6 @@
T1("dir-key-certification", K_DIR_KEY_CERTIFICATION,\
NO_ARGS, NEED_OBJ),\
T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ)
+// clang-format on
#endif /* !defined(TOR_AUTHCERT_MEMBERS_H) */
diff --git a/src/feature/dirparse/authcert_parse.c b/src/feature/dirparse/authcert_parse.c
index 3d42119b94..deb45c12de 100644
--- a/src/feature/dirparse/authcert_parse.c
+++ b/src/feature/dirparse/authcert_parse.c
@@ -21,11 +21,13 @@
#include "feature/dirparse/authcert_members.h"
/** List of tokens recognized in V3 authority certificates. */
+// clang-format off
static token_rule_t dir_key_certificate_table[] = {
AUTHCERT_MEMBERS,
T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
END_OF_TABLE
};
+// clang-format on
/** Parse a key certificate from <b>s</b>; point <b>end-of-string</b> to
* the first character after the certificate. */
diff --git a/src/feature/dirparse/microdesc_parse.c b/src/feature/dirparse/microdesc_parse.c
index c2eabeb404..9231080aaa 100644
--- a/src/feature/dirparse/microdesc_parse.c
+++ b/src/feature/dirparse/microdesc_parse.c
@@ -28,6 +28,7 @@
#include "feature/nodelist/microdesc_st.h"
/** List of tokens recognized in microdescriptors */
+// clang-format off
static token_rule_t microdesc_token_table[] = {
T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024),
T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
@@ -39,6 +40,7 @@ static token_rule_t microdesc_token_table[] = {
A01("@last-listed", A_LAST_LISTED, CONCAT_ARGS, NO_OBJ ),
END_OF_TABLE
};
+// clang-format on
/** Assuming that s starts with a microdesc, return the start of the
* *NEXT* one. Return NULL on "not found." */
diff --git a/src/feature/dirparse/ns_parse.c b/src/feature/dirparse/ns_parse.c
index 4d9b6e6e73..ac9325a608 100644
--- a/src/feature/dirparse/ns_parse.c
+++ b/src/feature/dirparse/ns_parse.c
@@ -43,6 +43,7 @@
/** List of tokens recognized in the body part of v3 networkstatus
* documents. */
+// clang-format off
static token_rule_t rtrstatus_token_table[] = {
T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
T1( "r", K_R, GE(7), NO_OBJ ),
@@ -56,8 +57,10 @@ static token_rule_t rtrstatus_token_table[] = {
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
END_OF_TABLE
};
+// clang-format on
/** List of tokens recognized in V3 networkstatus votes. */
+// clang-format off
static token_rule_t networkstatus_token_table[] = {
T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
GE(1), NO_OBJ ),
@@ -98,8 +101,10 @@ static token_rule_t networkstatus_token_table[] = {
END_OF_TABLE
};
+// clang-format on
/** List of tokens recognized in V3 networkstatus consensuses. */
+// clang-format off
static token_rule_t networkstatus_consensus_token_table[] = {
T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
GE(1), NO_OBJ ),
@@ -136,14 +141,17 @@ static token_rule_t networkstatus_consensus_token_table[] = {
END_OF_TABLE
};
+// clang-format on
/** List of tokens recognized in the footer of v1 directory footers. */
+// clang-format off
static token_rule_t networkstatus_vote_footer_token_table[] = {
T01("directory-footer", K_DIRECTORY_FOOTER, NO_ARGS, NO_OBJ ),
T01("bandwidth-weights", K_BW_WEIGHTS, ARGS, NO_OBJ ),
T( "directory-signature", K_DIRECTORY_SIGNATURE, GE(2), NEED_OBJ ),
END_OF_TABLE
};
+// clang-format on
/** Try to find the start and end of the signed portion of a networkstatus
* document in <b>s</b>. On success, set <b>start_out</b> to the first
diff --git a/src/feature/dirparse/routerparse.c b/src/feature/dirparse/routerparse.c
index f476beec66..8828a0f97a 100644
--- a/src/feature/dirparse/routerparse.c
+++ b/src/feature/dirparse/routerparse.c
@@ -81,6 +81,7 @@
/****************************************************************************/
/** List of tokens recognized in router descriptors */
+// clang-format off
const token_rule_t routerdesc_token_table[] = {
T0N("reject", K_REJECT, ARGS, NO_OBJ ),
T0N("accept", K_ACCEPT, ARGS, NO_OBJ ),
@@ -123,8 +124,10 @@ const token_rule_t routerdesc_token_table[] = {
END_OF_TABLE
};
+// clang-format on
/** List of tokens recognized in extra-info documents. */
+// clang-format off
static token_rule_t extrainfo_token_table[] = {
T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
@@ -162,6 +165,7 @@ static token_rule_t extrainfo_token_table[] = {
END_OF_TABLE
};
+// clang-format on
#undef T
diff --git a/src/feature/hs/hs_cache.c b/src/feature/hs/hs_cache.c
index 9cf408ca3e..44cd2505fd 100644
--- a/src/feature/hs/hs_cache.c
+++ b/src/feature/hs/hs_cache.c
@@ -27,6 +27,21 @@
static int cached_client_descriptor_has_expired(time_t now,
const hs_cache_client_descriptor_t *cached_desc);
+/** Helper function: Return true iff the cache entry has a decrypted
+ * descriptor.
+ *
+ * A NULL desc object in the entry means that we were not able to decrypt the
+ * descriptor because we are likely lacking client authorization. It is still
+ * a valid entry but some operations can't be done without the decrypted
+ * descriptor thus this function MUST be used to safe guard access to the
+ * decrypted desc object. */
+static inline bool
+entry_has_decrypted_descriptor(const hs_cache_client_descriptor_t *entry)
+{
+ tor_assert(entry);
+ return (entry->desc != NULL);
+}
+
/********************** Directory HS cache ******************/
/** Directory descriptor cache. Map indexed by blinded key. */
@@ -341,8 +356,23 @@ static digest256map_t *hs_cache_client_intro_state;
static size_t
cache_get_client_entry_size(const hs_cache_client_descriptor_t *entry)
{
- return sizeof(*entry) +
- strlen(entry->encoded_desc) + hs_desc_obj_size(entry->desc);
+ size_t size = 0;
+
+ if (entry == NULL) {
+ goto end;
+ }
+ size += sizeof(*entry);
+
+ if (entry->encoded_desc) {
+ size += strlen(entry->encoded_desc);
+ }
+
+ if (entry_has_decrypted_descriptor(entry)) {
+ size += hs_desc_obj_size(entry->desc);
+ }
+
+ end:
+ return size;
}
/** Remove a given descriptor from our cache. */
@@ -659,14 +689,20 @@ cache_store_as_client(hs_cache_client_descriptor_t *client_desc)
* client authorization. */
cache_entry = lookup_v3_desc_as_client(client_desc->key.pubkey);
if (cache_entry != NULL) {
- /* Signalling an undecrypted descriptor. We'll always replace the one we
- * have with the new one just fetched. */
- if (cache_entry->desc == NULL) {
+ /* If the current or the new cache entry don't have a decrypted descriptor
+ * (missing client authorization), we always replace the current one with
+ * the new one. Reason is that we can't inspect the revision counter
+ * within the plaintext data so we blindly replace. */
+ if (!entry_has_decrypted_descriptor(cache_entry) ||
+ !entry_has_decrypted_descriptor(client_desc)) {
remove_v3_desc_as_client(cache_entry);
cache_client_desc_free(cache_entry);
goto store;
}
+ /* From this point on, we know that the decrypted descriptor is in the
+ * current entry and new object thus safe to access. */
+
/* If we have an entry in our cache that has a revision counter greater
* than the one we just fetched, discard the one we fetched. */
if (cache_entry->desc->plaintext_data.revision_counter >
@@ -740,11 +776,15 @@ cache_clean_v3_as_client(time_t now)
MAP_DEL_CURRENT(key);
entry_size = cache_get_client_entry_size(entry);
bytes_removed += entry_size;
+
/* We just removed an old descriptor. We need to close all intro circuits
- * so we don't have leftovers that can be selected while lacking a
- * descriptor. We leave the rendezvous circuits opened because they could
- * be in use. */
- hs_client_close_intro_circuits_from_desc(entry->desc);
+ * if the descriptor is decrypted so we don't have leftovers that can be
+ * selected while lacking a descriptor. Circuits are selected by intro
+ * authentication key thus we need the descriptor. We leave the rendezvous
+ * circuits opened because they could be in use. */
+ if (entry_has_decrypted_descriptor(entry)) {
+ hs_client_close_intro_circuits_from_desc(entry->desc);
+ }
/* Entry is not in the cache anymore, destroy it. */
cache_client_desc_free(entry);
/* Update our OOM. We didn't use the remove() function because we are in
@@ -793,7 +833,7 @@ hs_cache_lookup_as_client(const ed25519_public_key_t *key)
tor_assert(key);
cached_desc = lookup_v3_desc_as_client(key->pubkey);
- if (cached_desc && cached_desc->desc) {
+ if (cached_desc && entry_has_decrypted_descriptor(cached_desc)) {
return cached_desc->desc;
}
@@ -866,7 +906,7 @@ hs_cache_remove_as_client(const ed25519_public_key_t *key)
/* If we have a decrypted/decoded descriptor, attempt to close its
* introduction circuit(s). We shouldn't have circuit(s) without a
* descriptor else it will lead to a failure. */
- if (cached_desc->desc) {
+ if (entry_has_decrypted_descriptor(cached_desc)) {
hs_client_close_intro_circuits_from_desc(cached_desc->desc);
}
/* Remove and free. */
@@ -995,7 +1035,7 @@ hs_cache_client_new_auth_parse(const ed25519_public_key_t *service_pk)
}
cached_desc = lookup_v3_desc_as_client(service_pk->pubkey);
- if (cached_desc == NULL || cached_desc->desc != NULL) {
+ if (cached_desc == NULL || entry_has_decrypted_descriptor(cached_desc)) {
/* No entry for that service or the descriptor is already decoded. */
goto end;
}
diff --git a/src/feature/hs/hs_cell.c b/src/feature/hs/hs_cell.c
index 52bd663200..fc9f4a2654 100644
--- a/src/feature/hs/hs_cell.c
+++ b/src/feature/hs/hs_cell.c
@@ -13,6 +13,7 @@
#include "feature/hs_common/replaycache.h"
#include "feature/hs/hs_cell.h"
+#include "feature/hs/hs_ob.h"
#include "core/crypto/hs_ntor.h"
#include "core/or/origin_circuit_st.h"
@@ -67,14 +68,17 @@ compute_introduce_mac(const uint8_t *encoded_cell, size_t encoded_cell_len,
memwipe(mac_msg, 0, sizeof(mac_msg));
}
-/** From a set of keys, subcredential and the ENCRYPTED section of an
- * INTRODUCE2 cell, return a newly allocated intro cell keys structure.
- * Finally, the client public key is copied in client_pk. On error, return
- * NULL. */
+/**
+ * From a set of keys, a list of subcredentials, and the ENCRYPTED section of
+ * an INTRODUCE2 cell, return an array of newly allocated intro cell keys
+ * structures. Finally, the client public key is copied in client_pk. On
+ * error, return NULL.
+ **/
static hs_ntor_intro_cell_keys_t *
get_introduce2_key_material(const ed25519_public_key_t *auth_key,
const curve25519_keypair_t *enc_key,
- const uint8_t *subcredential,
+ size_t n_subcredentials,
+ const hs_subcredential_t *subcredentials,
const uint8_t *encrypted_section,
curve25519_public_key_t *client_pk)
{
@@ -82,17 +86,19 @@ get_introduce2_key_material(const ed25519_public_key_t *auth_key,
tor_assert(auth_key);
tor_assert(enc_key);
- tor_assert(subcredential);
+ tor_assert(n_subcredentials > 0);
+ tor_assert(subcredentials);
tor_assert(encrypted_section);
tor_assert(client_pk);
- keys = tor_malloc_zero(sizeof(*keys));
+ keys = tor_calloc(n_subcredentials, sizeof(hs_ntor_intro_cell_keys_t));
/* First bytes of the ENCRYPTED section are the client public key. */
memcpy(client_pk->public_key, encrypted_section, CURVE25519_PUBKEY_LEN);
- if (hs_ntor_service_get_introduce1_keys(auth_key, enc_key, client_pk,
- subcredential, keys) < 0) {
+ if (hs_ntor_service_get_introduce1_keys_multi(auth_key, enc_key, client_pk,
+ n_subcredentials,
+ subcredentials, keys) < 0) {
/* Don't rely on the caller to wipe this on error. */
memwipe(client_pk, 0, sizeof(curve25519_public_key_t));
tor_free(keys);
@@ -747,6 +753,74 @@ hs_cell_parse_intro_established(const uint8_t *payload, size_t payload_len)
return ret;
}
+/** For the encrypted INTRO2 cell in <b>encrypted_section</b>, use the crypto
+ * material in <b>data</b> to compute the right ntor keys. Also validate the
+ * INTRO2 MAC to ensure that the keys are the right ones.
+ *
+ * Return NULL on failure to either produce the key material or on MAC
+ * validation. Else return a newly allocated intro keys object. */
+static hs_ntor_intro_cell_keys_t *
+get_introduce2_keys_and_verify_mac(hs_cell_introduce2_data_t *data,
+ const uint8_t *encrypted_section,
+ size_t encrypted_section_len)
+{
+ hs_ntor_intro_cell_keys_t *intro_keys = NULL;
+ hs_ntor_intro_cell_keys_t *intro_keys_result = NULL;
+
+ /* Build the key material out of the key material found in the cell. */
+ intro_keys = get_introduce2_key_material(data->auth_pk, data->enc_kp,
+ data->n_subcredentials,
+ data->subcredentials,
+ encrypted_section,
+ &data->client_pk);
+ if (intro_keys == NULL) {
+ log_info(LD_REND, "Invalid INTRODUCE2 encrypted data. Unable to "
+ "compute key material");
+ return NULL;
+ }
+
+ /* Make sure we are not about to underflow. */
+ if (BUG(encrypted_section_len < DIGEST256_LEN)) {
+ return NULL;
+ }
+
+ /* Validate MAC from the cell and our computed key material. The MAC field
+ * in the cell is at the end of the encrypted section. */
+ intro_keys_result = tor_malloc_zero(sizeof(*intro_keys_result));
+ for (unsigned i = 0; i < data->n_subcredentials; ++i) {
+ uint8_t mac[DIGEST256_LEN];
+
+ /* The MAC field is at the very end of the ENCRYPTED section. */
+ size_t mac_offset = encrypted_section_len - sizeof(mac);
+ /* Compute the MAC. Use the entire encoded payload with a length up to the
+ * ENCRYPTED section. */
+ compute_introduce_mac(data->payload,
+ data->payload_len - encrypted_section_len,
+ encrypted_section, encrypted_section_len,
+ intro_keys[i].mac_key,
+ sizeof(intro_keys[i].mac_key),
+ mac, sizeof(mac));
+ /* Time-invariant conditional copy: if the MAC is what we expected, then
+ * set intro_keys_result to intro_keys[i]. Otherwise, don't: but don't
+ * leak which one it was! */
+ bool equal = tor_memeq(mac, encrypted_section + mac_offset, sizeof(mac));
+ memcpy_if_true_timei(equal, intro_keys_result, &intro_keys[i],
+ sizeof(*intro_keys_result));
+ }
+
+ /* We no longer need intro_keys. */
+ memwipe(intro_keys, 0,
+ sizeof(hs_ntor_intro_cell_keys_t) * data->n_subcredentials);
+ tor_free(intro_keys);
+
+ if (safe_mem_is_zero(intro_keys_result, sizeof(*intro_keys_result))) {
+ log_info(LD_REND, "Invalid MAC validation for INTRODUCE2 cell");
+ tor_free(intro_keys_result); /* sets intro_keys_result to NULL */
+ }
+
+ return intro_keys_result;
+}
+
/** Parse the INTRODUCE2 cell using data which contains everything we need to
* do so and contains the destination buffers of information we extract and
* compute from the cell. Return 0 on success else a negative value. The
@@ -795,47 +869,29 @@ hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
/* Check our replay cache for this introduction point. */
if (replaycache_add_test_and_elapsed(data->replay_cache, encrypted_section,
encrypted_section_len, &elapsed)) {
- log_warn(LD_REND, "Possible replay detected! An INTRODUCE2 cell with the"
+ log_warn(LD_REND, "Possible replay detected! An INTRODUCE2 cell with the "
"same ENCRYPTED section was seen %ld seconds ago. "
"Dropping cell.", (long int) elapsed);
goto done;
}
- /* Build the key material out of the key material found in the cell. */
- intro_keys = get_introduce2_key_material(data->auth_pk, data->enc_kp,
- data->subcredential,
- encrypted_section,
- &data->client_pk);
- if (intro_keys == NULL) {
- log_info(LD_REND, "Invalid INTRODUCE2 encrypted data. Unable to "
- "compute key material on circuit %u for service %s",
- TO_CIRCUIT(circ)->n_circ_id,
+ /* First bytes of the ENCRYPTED section are the client public key (they are
+ * guaranteed to exist because of the length check above). We are gonna use
+ * the client public key to compute the ntor keys and decrypt the payload:
+ */
+ memcpy(&data->client_pk.public_key, encrypted_section,
+ CURVE25519_PUBKEY_LEN);
+
+ /* Get the right INTRODUCE2 ntor keys and verify the cell MAC */
+ intro_keys = get_introduce2_keys_and_verify_mac(data, encrypted_section,
+ encrypted_section_len);
+ if (!intro_keys) {
+ log_warn(LD_REND, "Could not get valid INTRO2 keys on circuit %u "
+ "for service %s", TO_CIRCUIT(circ)->n_circ_id,
safe_str_client(service->onion_address));
goto done;
}
- /* Validate MAC from the cell and our computed key material. The MAC field
- * in the cell is at the end of the encrypted section. */
- {
- uint8_t mac[DIGEST256_LEN];
- /* The MAC field is at the very end of the ENCRYPTED section. */
- size_t mac_offset = encrypted_section_len - sizeof(mac);
- /* Compute the MAC. Use the entire encoded payload with a length up to the
- * ENCRYPTED section. */
- compute_introduce_mac(data->payload,
- data->payload_len - encrypted_section_len,
- encrypted_section, encrypted_section_len,
- intro_keys->mac_key, sizeof(intro_keys->mac_key),
- mac, sizeof(mac));
- if (tor_memcmp(mac, encrypted_section + mac_offset, sizeof(mac))) {
- log_info(LD_REND, "Invalid MAC validation for INTRODUCE2 cell on "
- "circuit %u for service %s",
- TO_CIRCUIT(circ)->n_circ_id,
- safe_str_client(service->onion_address));
- goto done;
- }
- }
-
{
/* The ENCRYPTED_DATA section starts just after the CLIENT_PK. */
const uint8_t *encrypted_data =
diff --git a/src/feature/hs/hs_cell.h b/src/feature/hs/hs_cell.h
index 80f37057d2..2b28c44c50 100644
--- a/src/feature/hs/hs_cell.h
+++ b/src/feature/hs/hs_cell.h
@@ -16,6 +16,8 @@
* 3.2.2 of the specification). Below this value, the cell must be padded. */
#define HS_CELL_INTRODUCE1_MIN_SIZE 246
+struct hs_subcredential_t;
+
/** This data structure contains data that we need to build an INTRODUCE1 cell
* used by the INTRODUCE1 build function. */
typedef struct hs_cell_introduce1_data_t {
@@ -29,7 +31,7 @@ typedef struct hs_cell_introduce1_data_t {
/** Introduction point encryption public key. */
const curve25519_public_key_t *enc_pk;
/** Subcredentials of the service. */
- const uint8_t *subcredential;
+ const struct hs_subcredential_t *subcredential;
/** Onion public key for the ntor handshake. */
const curve25519_public_key_t *onion_pk;
/** Rendezvous cookie. */
@@ -55,9 +57,14 @@ typedef struct hs_cell_introduce2_data_t {
owned by the introduction point object through which we received the
INTRO2 cell*/
const curve25519_keypair_t *enc_kp;
- /** Subcredentials of the service. Pointer owned by the descriptor that owns
- the introduction point through which we received the INTRO2 cell. */
- const uint8_t *subcredential;
+ /**
+ * Length of the subcredentials array below.
+ **/
+ size_t n_subcredentials;
+ /** Array of <b>n_subcredentials</b> subcredentials for the service. Pointer
+ * owned by the descriptor that owns the introduction point through which we
+ * received the INTRO2 cell. */
+ const struct hs_subcredential_t *subcredentials;
/** Payload of the received encoded cell. */
const uint8_t *payload;
/** Size of the payload of the received encoded cell. */
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
index 90805a98b7..fdd226ba79 100644
--- a/src/feature/hs/hs_circuit.c
+++ b/src/feature/hs/hs_circuit.c
@@ -19,6 +19,7 @@
#include "feature/client/circpathbias.h"
#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_circuit.h"
+#include "feature/hs/hs_ob.h"
#include "feature/hs/hs_circuitmap.h"
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_ident.h"
@@ -367,10 +368,10 @@ get_service_anonymity_string(const hs_service_t *service)
* success, a circuit identifier is attached to the circuit with the needed
* data. This function will try to open a circuit for a maximum value of
* MAX_REND_FAILURES then it will give up. */
-static void
-launch_rendezvous_point_circuit(const hs_service_t *service,
- const hs_service_intro_point_t *ip,
- const hs_cell_introduce2_data_t *data)
+MOCK_IMPL(STATIC void,
+launch_rendezvous_point_circuit,(const hs_service_t *service,
+ const hs_service_intro_point_t *ip,
+ const hs_cell_introduce2_data_t *data))
{
int circ_needs_uptime;
time_t now = time(NULL);
@@ -578,7 +579,7 @@ retry_service_rendezvous_point(const origin_circuit_t *circ)
static int
setup_introduce1_data(const hs_desc_intro_point_t *ip,
const node_t *rp_node,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
hs_cell_introduce1_data_t *intro1_data)
{
int ret = -1;
@@ -958,6 +959,42 @@ hs_circ_handle_intro_established(const hs_service_t *service,
return ret;
}
+/**
+ * Go into <b>data</b> and add the right subcredential to be able to handle
+ * this incoming cell.
+ *
+ * <b>desc_subcred</b> is the subcredential of the descriptor that corresponds
+ * to the intro point that received this intro request. This subcredential
+ * should be used if we are not an onionbalance instance.
+ *
+ * Return 0 if everything went well, or -1 in case of internal error.
+ */
+static int
+get_subcredential_for_handling_intro2_cell(const hs_service_t *service,
+ hs_cell_introduce2_data_t *data,
+ const hs_subcredential_t *desc_subcred)
+{
+ /* Handle the simple case first: We are not an onionbalance instance and we
+ * should just use the regular descriptor subcredential */
+ if (!hs_ob_service_is_instance(service)) {
+ data->n_subcredentials = 1;
+ data->subcredentials = desc_subcred;
+ return 0;
+ }
+
+ /* This should not happen since we should have made onionbalance
+ * subcredentials when we created our descriptors. */
+ if (BUG(!service->ob_subcreds)) {
+ return -1;
+ }
+
+ /* We are an onionbalance instance: */
+ data->n_subcredentials = service->n_ob_subcreds;
+ data->subcredentials = service->ob_subcreds;
+
+ return 0;
+}
+
/** We just received an INTRODUCE2 cell on the established introduction circuit
* circ. Handle the INTRODUCE2 payload of size payload_len for the given
* circuit and service. This cell is associated with the intro point object ip
@@ -966,7 +1003,7 @@ int
hs_circ_handle_introduce2(const hs_service_t *service,
const origin_circuit_t *circ,
hs_service_intro_point_t *ip,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
const uint8_t *payload, size_t payload_len)
{
int ret = -1;
@@ -983,12 +1020,16 @@ hs_circ_handle_introduce2(const hs_service_t *service,
* parsed, decrypted and key material computed correctly. */
data.auth_pk = &ip->auth_key_kp.pubkey;
data.enc_kp = &ip->enc_key_kp;
- data.subcredential = subcredential;
data.payload = payload;
data.payload_len = payload_len;
data.link_specifiers = smartlist_new();
data.replay_cache = ip->replay_cache;
+ if (get_subcredential_for_handling_intro2_cell(service,
+ &data, subcredential)) {
+ goto done;
+ }
+
if (hs_cell_parse_introduce2(&data, circ, service) < 0) {
goto done;
}
@@ -1092,7 +1133,7 @@ int
hs_circ_send_introduce1(origin_circuit_t *intro_circ,
origin_circuit_t *rend_circ,
const hs_desc_intro_point_t *ip,
- const uint8_t *subcredential)
+ const hs_subcredential_t *subcredential)
{
int ret = -1;
ssize_t payload_len;
diff --git a/src/feature/hs/hs_circuit.h b/src/feature/hs/hs_circuit.h
index 92231369c6..22e936e685 100644
--- a/src/feature/hs/hs_circuit.h
+++ b/src/feature/hs/hs_circuit.h
@@ -46,15 +46,16 @@ int hs_circ_handle_intro_established(const hs_service_t *service,
origin_circuit_t *circ,
const uint8_t *payload,
size_t payload_len);
+struct hs_subcredential_t;
int hs_circ_handle_introduce2(const hs_service_t *service,
const origin_circuit_t *circ,
hs_service_intro_point_t *ip,
- const uint8_t *subcredential,
+ const struct hs_subcredential_t *subcredential,
const uint8_t *payload, size_t payload_len);
int hs_circ_send_introduce1(origin_circuit_t *intro_circ,
origin_circuit_t *rend_circ,
const hs_desc_intro_point_t *ip,
- const uint8_t *subcredential);
+ const struct hs_subcredential_t *subcredential);
int hs_circ_send_establish_rendezvous(origin_circuit_t *circ);
/* e2e circuit API. */
@@ -78,6 +79,12 @@ create_rp_circuit_identifier(const hs_service_t *service,
const curve25519_public_key_t *server_pk,
const struct hs_ntor_rend_cell_keys_t *keys);
+struct hs_cell_introduce2_data_t;
+MOCK_DECL(STATIC void,
+launch_rendezvous_point_circuit,(const hs_service_t *service,
+ const hs_service_intro_point_t *ip,
+ const struct hs_cell_introduce2_data_t *data));
+
#endif /* defined(HS_CIRCUIT_PRIVATE) */
#endif /* !defined(TOR_HS_CIRCUIT_H) */
diff --git a/src/feature/hs/hs_circuitmap.c b/src/feature/hs/hs_circuitmap.c
index 2343d729dd..466a02de39 100644
--- a/src/feature/hs/hs_circuitmap.c
+++ b/src/feature/hs/hs_circuitmap.c
@@ -76,11 +76,11 @@ hs_circuit_hash_token(const circuit_t *circuit)
HT_PROTOTYPE(hs_circuitmap_ht, // The name of the hashtable struct
circuit_t, // The name of the element struct,
hs_circuitmap_node, // The name of HT_ENTRY member
- hs_circuit_hash_token, hs_circuits_have_same_token)
+ hs_circuit_hash_token, hs_circuits_have_same_token);
HT_GENERATE2(hs_circuitmap_ht, circuit_t, hs_circuitmap_node,
hs_circuit_hash_token, hs_circuits_have_same_token,
- 0.6, tor_reallocarray, tor_free_)
+ 0.6, tor_reallocarray, tor_free_);
#ifdef TOR_UNIT_TESTS
diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c
index af8cb0b410..cc1b01d2ef 100644
--- a/src/feature/hs/hs_client.c
+++ b/src/feature/hs/hs_client.c
@@ -646,7 +646,7 @@ send_introduce1(origin_circuit_t *intro_circ,
/* Send the INTRODUCE1 cell. */
if (hs_circ_send_introduce1(intro_circ, rend_circ, ip,
- desc->subcredential) < 0) {
+ &desc->subcredential) < 0) {
if (TO_CIRCUIT(intro_circ)->marked_for_close) {
/* If the introduction circuit was closed, we were unable to send the
* cell for some reasons. In any case, the intro circuit has to be
@@ -1845,7 +1845,7 @@ hs_client_decode_descriptor(const char *desc_str,
hs_descriptor_t **desc)
{
hs_desc_decode_status_t ret;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
ed25519_public_key_t blinded_pubkey;
hs_client_service_authorization_t *client_auth = NULL;
curve25519_secret_key_t *client_auth_sk = NULL;
@@ -1865,13 +1865,13 @@ hs_client_decode_descriptor(const char *desc_str,
uint64_t current_time_period = hs_get_time_period_num(0);
hs_build_blinded_pubkey(service_identity_pk, NULL, 0, current_time_period,
&blinded_pubkey);
- hs_get_subcredential(service_identity_pk, &blinded_pubkey, subcredential);
+ hs_get_subcredential(service_identity_pk, &blinded_pubkey, &subcredential);
}
/* Parse descriptor */
- ret = hs_desc_decode_descriptor(desc_str, subcredential,
+ ret = hs_desc_decode_descriptor(desc_str, &subcredential,
client_auth_sk, desc);
- memwipe(subcredential, 0, sizeof(subcredential));
+ memwipe(&subcredential, 0, sizeof(subcredential));
if (ret != HS_DESC_DECODE_OK) {
goto err;
}
@@ -2486,4 +2486,3 @@ set_hs_client_auths_map(digest256map_t *map)
}
#endif /* defined(TOR_UNIT_TESTS) */
-
diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c
index f8b031cc26..4639cdb68a 100644
--- a/src/feature/hs/hs_common.c
+++ b/src/feature/hs/hs_common.c
@@ -22,6 +22,7 @@
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_dos.h"
+#include "feature/hs/hs_ob.h"
#include "feature/hs/hs_ident.h"
#include "feature/hs/hs_service.h"
#include "feature/hs_common/shared_random_client.h"
@@ -808,12 +809,12 @@ hs_parse_address_impl(const char *address, ed25519_public_key_t *key_out,
}
/** Using the given identity public key and a blinded public key, compute the
- * subcredential and put it in subcred_out (must be of size DIGEST256_LEN).
+ * subcredential and put it in subcred_out.
* This can't fail. */
void
hs_get_subcredential(const ed25519_public_key_t *identity_pk,
const ed25519_public_key_t *blinded_pk,
- uint8_t *subcred_out)
+ hs_subcredential_t *subcred_out)
{
uint8_t credential[DIGEST256_LEN];
crypto_digest_t *digest;
@@ -841,7 +842,8 @@ hs_get_subcredential(const ed25519_public_key_t *identity_pk,
sizeof(credential));
crypto_digest_add_bytes(digest, (const char *) blinded_pk->pubkey,
ED25519_PUBKEY_LEN);
- crypto_digest_get_digest(digest, (char *) subcred_out, DIGEST256_LEN);
+ crypto_digest_get_digest(digest, (char *) subcred_out->subcred,
+ SUBCRED_LEN);
crypto_digest_free(digest);
memwipe(credential, 0, sizeof(credential));
@@ -909,30 +911,35 @@ hs_set_conn_addr_port(const smartlist_t *ports, edge_connection_t *conn)
* case the caller would want only one field. checksum_out MUST at least be 2
* bytes long.
*
- * Return 0 if parsing went well; return -1 in case of error. */
+ * Return 0 if parsing went well; return -1 in case of error and if errmsg is
+ * non NULL, a human readable string message is set. */
int
-hs_parse_address(const char *address, ed25519_public_key_t *key_out,
- uint8_t *checksum_out, uint8_t *version_out)
+hs_parse_address_no_log(const char *address, ed25519_public_key_t *key_out,
+ uint8_t *checksum_out, uint8_t *version_out,
+ const char **errmsg)
{
char decoded[HS_SERVICE_ADDR_LEN];
tor_assert(address);
+ if (errmsg) {
+ *errmsg = NULL;
+ }
+
/* Obvious length check. */
if (strlen(address) != HS_SERVICE_ADDR_LEN_BASE32) {
- log_warn(LD_REND, "Service address %s has an invalid length. "
- "Expected %lu but got %lu.",
- escaped_safe_str(address),
- (unsigned long) HS_SERVICE_ADDR_LEN_BASE32,
- (unsigned long) strlen(address));
+ if (errmsg) {
+ *errmsg = "Invalid length";
+ }
goto invalid;
}
/* Decode address so we can extract needed fields. */
if (base32_decode(decoded, sizeof(decoded), address, strlen(address))
!= sizeof(decoded)) {
- log_warn(LD_REND, "Service address %s can't be decoded.",
- escaped_safe_str(address));
+ if (errmsg) {
+ *errmsg = "Unable to base32 decode";
+ }
goto invalid;
}
@@ -944,6 +951,22 @@ hs_parse_address(const char *address, ed25519_public_key_t *key_out,
return -1;
}
+/** Same has hs_parse_address_no_log() but emits a log warning on parsing
+ * failure. */
+int
+hs_parse_address(const char *address, ed25519_public_key_t *key_out,
+ uint8_t *checksum_out, uint8_t *version_out)
+{
+ const char *errmsg = NULL;
+ int ret = hs_parse_address_no_log(address, key_out, checksum_out,
+ version_out, &errmsg);
+ if (ret < 0) {
+ log_warn(LD_REND, "Service address %s failed to be parsed: %s",
+ escaped_safe_str(address), errmsg);
+ }
+ return ret;
+}
+
/** Validate a given onion address. The length, the base32 decoding, and
* checksum are validated. Return 1 if valid else 0. */
int
@@ -1807,6 +1830,7 @@ hs_free_all(void)
hs_service_free_all();
hs_cache_free_all();
hs_client_free_all();
+ hs_ob_free_all();
}
/** For the given origin circuit circ, decrement the number of rendezvous
diff --git a/src/feature/hs/hs_common.h b/src/feature/hs/hs_common.h
index 8f743d4d37..997b7298a6 100644
--- a/src/feature/hs/hs_common.h
+++ b/src/feature/hs/hs_common.h
@@ -179,6 +179,10 @@ void hs_build_address(const struct ed25519_public_key_t *key, uint8_t version,
int hs_address_is_valid(const char *address);
int hs_parse_address(const char *address, struct ed25519_public_key_t *key_out,
uint8_t *checksum_out, uint8_t *version_out);
+int hs_parse_address_no_log(const char *address,
+ struct ed25519_public_key_t *key_out,
+ uint8_t *checksum_out, uint8_t *version_out,
+ const char **errmsg);
void hs_build_blinded_pubkey(const struct ed25519_public_key_t *pubkey,
const uint8_t *secret, size_t secret_len,
@@ -210,9 +214,10 @@ const uint8_t *rend_data_get_pk_digest(const rend_data_t *rend_data,
routerstatus_t *pick_hsdir(const char *desc_id, const char *desc_id_base32);
+struct hs_subcredential_t;
void hs_get_subcredential(const struct ed25519_public_key_t *identity_pk,
const struct ed25519_public_key_t *blinded_pk,
- uint8_t *subcred_out);
+ struct hs_subcredential_t *subcred_out);
uint64_t hs_get_previous_time_period_num(time_t now);
uint64_t hs_get_time_period_num(time_t now);
diff --git a/src/feature/hs/hs_config.c b/src/feature/hs/hs_config.c
index 64656b1935..684f7bc975 100644
--- a/src/feature/hs/hs_config.c
+++ b/src/feature/hs/hs_config.c
@@ -26,6 +26,7 @@
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_config.h"
#include "feature/hs/hs_client.h"
+#include "feature/hs/hs_ob.h"
#include "feature/hs/hs_service.h"
#include "feature/rend/rendclient.h"
#include "feature/rend/rendservice.h"
@@ -219,6 +220,7 @@ config_has_invalid_options(const config_line_t *line_,
"HiddenServiceEnableIntroDoSDefense",
"HiddenServiceEnableIntroDoSRatePerSec",
"HiddenServiceEnableIntroDoSBurstPerSec",
+ "HiddenServiceOnionBalanceInstance",
NULL /* End marker. */
};
@@ -317,7 +319,7 @@ config_service_v3(const config_line_t *line_,
int have_num_ip = 0;
bool export_circuit_id = false; /* just to detect duplicate options */
bool dos_enabled = false, dos_rate_per_sec = false;
- bool dos_burst_per_sec = false;
+ bool dos_burst_per_sec = false, ob_instance = false;
const char *dup_opt_seen = NULL;
const config_line_t *line;
@@ -402,6 +404,27 @@ config_service_v3(const config_line_t *line_,
config->intro_dos_burst_per_sec);
continue;
}
+ if (!strcasecmp(line->key, "HiddenServiceOnionBalanceInstance")) {
+ bool enabled = !!helper_parse_uint64(line->key, line->value,
+ 0, 1, &ok);
+ if (!ok || ob_instance) {
+ if (ob_instance) {
+ dup_opt_seen = line->key;
+ }
+ goto err;
+ }
+ ob_instance = true;
+ if (!enabled) {
+ /* Skip if this is disabled. */
+ continue;
+ }
+ /* Option is enabled, parse config file. */
+ ok = hs_ob_parse_config_file(config);
+ if (!ok) {
+ goto err;
+ }
+ continue;
+ }
}
/* We do not load the key material for the service at this stage. This is
diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c
index 65d6c7a581..c274ed7581 100644
--- a/src/feature/hs/hs_descriptor.c
+++ b/src/feature/hs/hs_descriptor.c
@@ -211,7 +211,7 @@ build_secret_input(const hs_descriptor_t *desc,
memcpy(secret_input, secret_data, secret_data_len);
offset += secret_data_len;
/* Copy subcredential. */
- memcpy(secret_input + offset, desc->subcredential, DIGEST256_LEN);
+ memcpy(secret_input + offset, desc->subcredential.subcred, DIGEST256_LEN);
offset += DIGEST256_LEN;
/* Copy revision counter value. */
set_uint64(secret_input + offset,
@@ -1018,10 +1018,6 @@ desc_encode_v3(const hs_descriptor_t *desc,
tor_assert(encoded_out);
tor_assert(desc->plaintext_data.version == 3);
- if (BUG(desc->subcredential == NULL)) {
- goto err;
- }
-
/* Build the non-encrypted values. */
{
char *encoded_cert;
@@ -1366,8 +1362,7 @@ encrypted_data_length_is_valid(size_t len)
* and return the buffer's length. The caller should wipe and free its content
* once done with it. This function can't fail. */
static size_t
-build_descriptor_cookie_keys(const uint8_t *subcredential,
- size_t subcredential_len,
+build_descriptor_cookie_keys(const hs_subcredential_t *subcredential,
const curve25519_secret_key_t *sk,
const curve25519_public_key_t *pk,
uint8_t **keys_out)
@@ -1389,7 +1384,7 @@ build_descriptor_cookie_keys(const uint8_t *subcredential,
/* Calculate KEYS = KDF(subcredential | SECRET_SEED, 40) */
xof = crypto_xof_new();
- crypto_xof_add_bytes(xof, subcredential, subcredential_len);
+ crypto_xof_add_bytes(xof, subcredential->subcred, SUBCRED_LEN);
crypto_xof_add_bytes(xof, secret_seed, sizeof(secret_seed));
crypto_xof_squeeze_bytes(xof, keystream, keystream_len);
crypto_xof_free(xof);
@@ -1426,11 +1421,12 @@ decrypt_descriptor_cookie(const hs_descriptor_t *desc,
sizeof(desc->superencrypted_data.auth_ephemeral_pubkey)));
tor_assert(!fast_mem_is_zero((char *) client_auth_sk,
sizeof(*client_auth_sk)));
- tor_assert(!fast_mem_is_zero((char *) desc->subcredential, DIGEST256_LEN));
+ tor_assert(!fast_mem_is_zero((char *) desc->subcredential.subcred,
+ DIGEST256_LEN));
/* Get the KEYS component to derive the CLIENT-ID and COOKIE-KEY. */
keystream_length =
- build_descriptor_cookie_keys(desc->subcredential, DIGEST256_LEN,
+ build_descriptor_cookie_keys(&desc->subcredential,
client_auth_sk,
&desc->superencrypted_data.auth_ephemeral_pubkey,
&keystream);
@@ -2558,7 +2554,7 @@ hs_desc_decode_plaintext(const char *encoded,
* set to NULL. */
hs_desc_decode_status_t
hs_desc_decode_descriptor(const char *encoded,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
const curve25519_secret_key_t *client_auth_sk,
hs_descriptor_t **desc_out)
{
@@ -2576,7 +2572,7 @@ hs_desc_decode_descriptor(const char *encoded,
goto err;
}
- memcpy(desc->subcredential, subcredential, sizeof(desc->subcredential));
+ memcpy(&desc->subcredential, subcredential, sizeof(desc->subcredential));
ret = hs_desc_decode_plaintext(encoded, &desc->plaintext_data);
if (ret != HS_DESC_DECODE_OK) {
@@ -2666,7 +2662,7 @@ hs_desc_encode_descriptor,(const hs_descriptor_t *desc,
* symmetric only if the client auth is disabled. That is, the descriptor
* cookie will be NULL. */
if (!descriptor_cookie) {
- ret = hs_desc_decode_descriptor(*encoded_out, desc->subcredential,
+ ret = hs_desc_decode_descriptor(*encoded_out, &desc->subcredential,
NULL, NULL);
if (BUG(ret != HS_DESC_DECODE_OK)) {
ret = -1;
@@ -2870,7 +2866,7 @@ hs_desc_build_fake_authorized_client(void)
* key, and descriptor cookie, build the auth client so we can then encode the
* descriptor for publication. client_out must be already allocated. */
void
-hs_desc_build_authorized_client(const uint8_t *subcredential,
+hs_desc_build_authorized_client(const hs_subcredential_t *subcredential,
const curve25519_public_key_t *client_auth_pk,
const curve25519_secret_key_t *
auth_ephemeral_sk,
@@ -2898,7 +2894,7 @@ hs_desc_build_authorized_client(const uint8_t *subcredential,
/* Get the KEYS part so we can derive the CLIENT-ID and COOKIE-KEY. */
keystream_length =
- build_descriptor_cookie_keys(subcredential, DIGEST256_LEN,
+ build_descriptor_cookie_keys(subcredential,
auth_ephemeral_sk, client_auth_pk,
&keystream);
tor_assert(keystream_length > 0);
diff --git a/src/feature/hs/hs_descriptor.h b/src/feature/hs/hs_descriptor.h
index 639dd31c8f..08daa904b6 100644
--- a/src/feature/hs/hs_descriptor.h
+++ b/src/feature/hs/hs_descriptor.h
@@ -14,6 +14,7 @@
#include "core/or/or.h"
#include "trunnel/ed25519_cert.h" /* needed for trunnel */
#include "feature/nodelist/torcert.h"
+#include "core/crypto/hs_ntor.h" /* for hs_subcredential_t */
/* Trunnel */
struct link_specifier_t;
@@ -238,7 +239,7 @@ typedef struct hs_descriptor_t {
/** Subcredentials of a service, used by the client and service to decrypt
* the encrypted data. */
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
} hs_descriptor_t;
/** Return true iff the given descriptor format version is supported. */
@@ -277,7 +278,7 @@ MOCK_DECL(int,
char **encoded_out));
int hs_desc_decode_descriptor(const char *encoded,
- const uint8_t *subcredential,
+ const hs_subcredential_t *subcredential,
const curve25519_secret_key_t *client_auth_sk,
hs_descriptor_t **desc_out);
int hs_desc_decode_plaintext(const char *encoded,
@@ -302,7 +303,7 @@ void hs_desc_authorized_client_free_(hs_desc_authorized_client_t *client);
hs_desc_authorized_client_t *hs_desc_build_fake_authorized_client(void);
-void hs_desc_build_authorized_client(const uint8_t *subcredential,
+void hs_desc_build_authorized_client(const hs_subcredential_t *subcredential,
const curve25519_public_key_t *
client_auth_pk,
const curve25519_secret_key_t *
diff --git a/src/feature/hs/hs_ob.c b/src/feature/hs/hs_ob.c
new file mode 100644
index 0000000000..f135ecd3f4
--- /dev/null
+++ b/src/feature/hs/hs_ob.c
@@ -0,0 +1,408 @@
+/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_ob.c
+ * \brief Implement Onion Balance specific code.
+ **/
+
+#define HS_OB_PRIVATE
+
+#include "feature/hs/hs_service.h"
+
+#include "feature/nodelist/networkstatus.h"
+#include "feature/nodelist/networkstatus_st.h"
+
+#include "lib/confmgt/confmgt.h"
+#include "lib/encoding/confline.h"
+
+#include "feature/hs/hs_ob.h"
+
+/* Options config magic number. */
+#define OB_OPTIONS_MAGIC 0x631DE7EA
+
+/* Helper macros. */
+#define VAR(varname, conftype, member, initvalue) \
+ CONFIG_VAR_ETYPE(ob_options_t, varname, conftype, member, 0, initvalue)
+#define V(member,conftype,initvalue) \
+ VAR(#member, conftype, member, initvalue)
+
+/* Dummy instance of ob_options_t, used for type-checking its members with
+ * CONF_CHECK_VAR_TYPE. */
+DUMMY_TYPECHECK_INSTANCE(ob_options_t);
+
+/* Array of variables for the config file options. */
+static const config_var_t config_vars[] = {
+ V(MasterOnionAddress, LINELIST, NULL),
+
+ END_OF_CONFIG_VARS
+};
+
+/* "Extra" variable in the state that receives lines we can't parse. This
+ * lets us preserve options from versions of Tor newer than us. */
+static const struct_member_t config_extra_vars = {
+ .name = "__extra",
+ .type = CONFIG_TYPE_LINELIST,
+ .offset = offsetof(ob_options_t, ExtraLines),
+};
+
+/* Configuration format of ob_options_t. */
+static const config_format_t config_format = {
+ .size = sizeof(ob_options_t),
+ .magic = {
+ "ob_options_t",
+ OB_OPTIONS_MAGIC,
+ offsetof(ob_options_t, magic_),
+ },
+ .vars = config_vars,
+ .extra = &config_extra_vars,
+};
+
+/* Global configuration manager for the config file. */
+static config_mgr_t *config_options_mgr = NULL;
+
+/* Return the configuration manager for the config file. */
+static const config_mgr_t *
+get_config_options_mgr(void)
+{
+ if (PREDICT_UNLIKELY(config_options_mgr == NULL)) {
+ config_options_mgr = config_mgr_new(&config_format);
+ config_mgr_freeze(config_options_mgr);
+ }
+ return config_options_mgr;
+}
+
+#define ob_option_free(val) \
+ FREE_AND_NULL(ob_options_t, ob_option_free_, (val))
+
+/** Helper: Free a config options object. */
+static void
+ob_option_free_(ob_options_t *opts)
+{
+ if (opts == NULL) {
+ return;
+ }
+ config_free(get_config_options_mgr(), opts);
+}
+
+/** Return an allocated config options object. */
+static ob_options_t *
+ob_option_new(void)
+{
+ ob_options_t *opts = config_new(get_config_options_mgr());
+ config_init(get_config_options_mgr(), opts);
+ return opts;
+}
+
+/** Helper function: From the configuration line value which is an onion
+ * address with the ".onion" extension, find the public key and put it in
+ * pkey_out.
+ *
+ * On success, true is returned. Else, false and pkey is untouched. */
+static bool
+get_onion_public_key(const char *value, ed25519_public_key_t *pkey_out)
+{
+ char address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+
+ tor_assert(value);
+ tor_assert(pkey_out);
+
+ if (strcmpend(value, ".onion")) {
+ /* Not a .onion extension, bad format. */
+ return false;
+ }
+
+ /* Length validation. The -1 is because sizeof() counts the NUL byte. */
+ if (strlen(value) >
+ (HS_SERVICE_ADDR_LEN_BASE32 + sizeof(".onion") - 1)) {
+ /* Too long, bad format. */
+ return false;
+ }
+
+ /* We don't want the .onion so we add 2 because size - 1 is copied with
+ * strlcpy() in order to accomodate the NUL byte and sizeof() counts the NUL
+ * byte so we need to remove them from the equation. */
+ strlcpy(address, value, strlen(value) - sizeof(".onion") + 2);
+
+ if (hs_parse_address_no_log(address, pkey_out, NULL, NULL, NULL) < 0) {
+ return false;
+ }
+
+ /* Success. */
+ return true;
+}
+
+/** Parse the given ob options in opts and set the service config object
+ * accordingly.
+ *
+ * Return 1 on success else 0. */
+static int
+ob_option_parse(hs_service_config_t *config, const ob_options_t *opts)
+{
+ int ret = 0;
+ config_line_t *line;
+
+ tor_assert(config);
+ tor_assert(opts);
+
+ for (line = opts->MasterOnionAddress; line; line = line->next) {
+ /* Allocate config list if need be. */
+ if (!config->ob_master_pubkeys) {
+ config->ob_master_pubkeys = smartlist_new();
+ }
+ ed25519_public_key_t *pubkey = tor_malloc_zero(sizeof(*pubkey));
+
+ if (!get_onion_public_key(line->value, pubkey)) {
+ log_warn(LD_REND, "OnionBalance: MasterOnionAddress %s is invalid",
+ line->value);
+ tor_free(pubkey);
+ goto end;
+ }
+ smartlist_add(config->ob_master_pubkeys, pubkey);
+ log_info(LD_REND, "OnionBalance: MasterOnionAddress %s registered",
+ line->value);
+ }
+ /* Success. */
+ ret = 1;
+
+ end:
+ /* No keys added, we free the list since no list means no onion balance
+ * support for this tor instance. */
+ if (smartlist_len(config->ob_master_pubkeys) == 0) {
+ smartlist_free(config->ob_master_pubkeys);
+ }
+ return ret;
+}
+
+/** For the given master public key and time period, compute the subcredential
+ * and put them into subcredential. The subcredential parameter needs to be at
+ * least DIGEST256_LEN in size. */
+static void
+build_subcredential(const ed25519_public_key_t *pkey, uint64_t tp,
+ hs_subcredential_t *subcredential)
+{
+ ed25519_public_key_t blinded_pubkey;
+
+ tor_assert(pkey);
+ tor_assert(subcredential);
+
+ hs_build_blinded_pubkey(pkey, NULL, 0, tp, &blinded_pubkey);
+ hs_get_subcredential(pkey, &blinded_pubkey, subcredential);
+}
+
+/*
+ * Public API.
+ */
+
+/** Return true iff the given service is configured as an onion balance
+ * instance. To satisfy that condition, there must at least be one master
+ * ed25519 public key configured. */
+bool
+hs_ob_service_is_instance(const hs_service_t *service)
+{
+ if (BUG(service == NULL)) {
+ return false;
+ }
+
+ /* No list, we are not an instance. */
+ if (!service->config.ob_master_pubkeys) {
+ return false;
+ }
+
+ return smartlist_len(service->config.ob_master_pubkeys) > 0;
+}
+
+/** Read and parse the config file at fname on disk. The service config object
+ * is populated with the options if any.
+ *
+ * Return 1 on success else 0. This is to follow the "ok" convention in
+ * hs_config.c. */
+int
+hs_ob_parse_config_file(hs_service_config_t *config)
+{
+ static const char *fname = "ob_config";
+ int ret = 0;
+ char *content = NULL, *errmsg = NULL, *config_file_path = NULL;
+ ob_options_t *options = NULL;
+ config_line_t *lines = NULL;
+
+ tor_assert(config);
+
+ /* Read file from disk. */
+ config_file_path = hs_path_from_filename(config->directory_path, fname);
+ content = read_file_to_str(config_file_path, 0, NULL);
+ if (!content) {
+ log_warn(LD_FS, "OnionBalance: Unable to read config file %s",
+ escaped(config_file_path));
+ goto end;
+ }
+
+ /* Parse lines. */
+ if (config_get_lines(content, &lines, 0) < 0) {
+ goto end;
+ }
+
+ options = ob_option_new();
+ config_assign(get_config_options_mgr(), options, lines, 0, &errmsg);
+ if (errmsg) {
+ log_warn(LD_REND, "OnionBalance: Unable to parse config file: %s",
+ errmsg);
+ tor_free(errmsg);
+ goto end;
+ }
+
+ /* Parse the options and set the service config object with the details. */
+ ret = ob_option_parse(config, options);
+
+ end:
+ config_free_lines(lines);
+ ob_option_free(options);
+ tor_free(content);
+ tor_free(config_file_path);
+ return ret;
+}
+
+/** Compute all possible subcredentials for every onion master key in the given
+ * service config object. subcredentials_out is allocated and set as an
+ * continous array containing all possible values.
+ *
+ * On success, return the number of subcredential put in the array which will
+ * correspond to an arry of size: n * DIGEST256_LEN where DIGEST256_LEN is the
+ * length of a single subcredential.
+ *
+ * If the given configuration object has no OB master keys configured, 0 is
+ * returned and subcredentials_out is set to NULL.
+ *
+ * Otherwise, this can't fail. */
+STATIC size_t
+compute_subcredentials(const hs_service_t *service,
+ hs_subcredential_t **subcredentials_out)
+{
+ unsigned int num_pkeys, idx = 0;
+ hs_subcredential_t *subcreds = NULL;
+ const int steps[3] = {0, -1, 1};
+ const unsigned int num_steps = ARRAY_LENGTH(steps);
+ const uint64_t tp = hs_get_time_period_num(0);
+
+ tor_assert(service);
+ tor_assert(subcredentials_out);
+ /* Our caller has checked these too */
+ tor_assert(service->desc_current);
+ tor_assert(service->desc_next);
+
+ /* Make sure we are an OB instance, or bail out. */
+ num_pkeys = smartlist_len(service->config.ob_master_pubkeys);
+ if (!num_pkeys) {
+ *subcredentials_out = NULL;
+ return 0;
+ }
+
+ /* Time to build all the subcredentials for each time period: two for each
+ * instance descriptor plus three for the onionbalance frontend service: the
+ * previous one (-1), the current one (0) and the next one (1) for each
+ * configured key in order to accomodate client and service consensus skew.
+ *
+ * If the client consensus after_time is at 23:00 but the service one is at
+ * 01:00, the client will be using the previous time period where the
+ * service will think it is the client next time period. Thus why we have
+ * to try them all.
+ *
+ * The normal use case works because the service gets the descriptor object
+ * that corresponds to the intro point's request, and because each
+ * descriptor corresponds to a specific subcredential, we get the right
+ * subcredential out of it, and use that to do the decryption.
+ *
+ * As a slight optimization, statistically, the current time period (0) will
+ * be the one to work first so we'll put them first in the array to maximize
+ * our chance of success. */
+
+ /* We use a flat array, not a smartlist_t, in order to minimize memory
+ * allocation.
+ *
+ * Size of array is: length of a single subcredential multiplied by the
+ * number of time period we need to compute and finally multiplied by the
+ * total number of keys we are about to process. In other words, for each
+ * key, we allocate 3 subcredential slots. Then in the end we also add two
+ * subcredentials for this instance's active descriptors. */
+ subcreds =
+ tor_calloc((num_steps * num_pkeys) + 2, sizeof(hs_subcredential_t));
+
+ /* For each master pubkey we add 3 subcredentials: */
+ for (unsigned int i = 0; i < num_steps; i++) {
+ SMARTLIST_FOREACH_BEGIN(service->config.ob_master_pubkeys,
+ const ed25519_public_key_t *, pkey) {
+ build_subcredential(pkey, tp + steps[i], &subcreds[idx]);
+ idx++;
+ } SMARTLIST_FOREACH_END(pkey);
+ }
+
+ /* And then in the end we add the two subcredentials of the current active
+ * instance descriptors */
+ memcpy(&subcreds[idx++], &service->desc_current->desc->subcredential,
+ sizeof(hs_subcredential_t));
+ memcpy(&subcreds[idx++], &service->desc_next->desc->subcredential,
+ sizeof(hs_subcredential_t));
+
+ log_info(LD_REND, "Refreshing %u onionbalance keys (TP #%d).",
+ idx, (int)tp);
+
+ *subcredentials_out = subcreds;
+ return idx;
+}
+
+/**
+ * If we are an Onionbalance instance, refresh our keys.
+ *
+ * If we are not an Onionbalance instance or we are not ready to do so, this
+ * is a NOP.
+ *
+ * This function is called everytime we build a new descriptor. That's because
+ * we want our Onionbalance keys to always use up-to-date subcredentials both
+ * for the instance (ourselves) and for the onionbalance frontend.
+ */
+void
+hs_ob_refresh_keys(hs_service_t *service)
+{
+ hs_subcredential_t *ob_subcreds = NULL;
+ size_t num_subcreds;
+
+ tor_assert(service);
+
+ /* Don't do any of this if we are not configured as an OB instance */
+ if (!hs_ob_service_is_instance(service)) {
+ return;
+ }
+
+ /* We need both service descriptors created to make onionbalance keys.
+ *
+ * That's because we fetch our own (the instance's) subcredentials from our
+ * own descriptors which should always include the latest subcredentials that
+ * clients would use.
+ *
+ * This function is called with each descriptor build, so we will be
+ * eventually be called when both descriptors are created. */
+ if (!service->desc_current || !service->desc_next) {
+ return;
+ }
+
+ /* Get a new set of subcreds */
+ num_subcreds = compute_subcredentials(service, &ob_subcreds);
+ if (BUG(!num_subcreds)) {
+ return;
+ }
+
+ /* Delete old subcredentials if any */
+ if (service->ob_subcreds) {
+ tor_free(service->ob_subcreds);
+ }
+
+ service->ob_subcreds = ob_subcreds;
+ service->n_ob_subcreds = num_subcreds;
+}
+
+/** Free any memory allocated by the onionblance subsystem. */
+void
+hs_ob_free_all(void)
+{
+ config_mgr_free(config_options_mgr);
+}
diff --git a/src/feature/hs/hs_ob.h b/src/feature/hs/hs_ob.h
new file mode 100644
index 0000000000..d6e6e73a84
--- /dev/null
+++ b/src/feature/hs/hs_ob.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_ob.h
+ * \brief Header file for the specific code for onion balance.
+ **/
+
+#ifndef TOR_HS_OB_H
+#define TOR_HS_OB_H
+
+#include "feature/hs/hs_service.h"
+
+bool hs_ob_service_is_instance(const hs_service_t *service);
+
+int hs_ob_parse_config_file(hs_service_config_t *config);
+
+struct hs_subcredential_t;
+
+void hs_ob_free_all(void);
+
+void hs_ob_refresh_keys(hs_service_t *service);
+
+#ifdef HS_OB_PRIVATE
+
+STATIC size_t compute_subcredentials(const hs_service_t *service,
+ struct hs_subcredential_t **subcredentials);
+
+typedef struct ob_options_t {
+ /** Magic number to identify the structure in memory. */
+ uint32_t magic_;
+ /** Master Onion Address(es). */
+ struct config_line_t *MasterOnionAddress;
+ /** Extra Lines for configuration we might not know. */
+ struct config_line_t *ExtraLines;
+} ob_options_t;
+
+#endif /* defined(HS_OB_PRIVATE) */
+
+#endif /* !defined(TOR_HS_OB_H) */
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index b366ce83d9..3a2beb766f 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -41,6 +41,7 @@
#include "feature/hs/hs_intropoint.h"
#include "feature/hs/hs_service.h"
#include "feature/hs/hs_stats.h"
+#include "feature/hs/hs_ob.h"
#include "feature/dircommon/dir_connection_st.h"
#include "core/or/edge_connection_st.h"
@@ -151,11 +152,11 @@ HT_PROTOTYPE(hs_service_ht, /* Name of hashtable. */
hs_service_t, /* Object contained in the map. */
hs_service_node, /* The name of the HT_ENTRY member. */
hs_service_ht_hash, /* Hashing function. */
- hs_service_ht_eq) /* Compare function for objects. */
+ hs_service_ht_eq); /* Compare function for objects. */
HT_GENERATE2(hs_service_ht, hs_service_t, hs_service_node,
hs_service_ht_hash, hs_service_ht_eq,
- 0.6, tor_reallocarray, tor_free_)
+ 0.6, tor_reallocarray, tor_free_);
/** Query the given service map with a public key and return a service object
* if found else NULL. It is also possible to set a directory path in the
@@ -267,6 +268,11 @@ service_clear_config(hs_service_config_t *config)
service_authorized_client_free(p));
smartlist_free(config->clients);
}
+ if (config->ob_master_pubkeys) {
+ SMARTLIST_FOREACH(config->ob_master_pubkeys, ed25519_public_key_t *, k,
+ tor_free(k));
+ smartlist_free(config->ob_master_pubkeys);
+ }
memset(config, 0, sizeof(*config));
}
@@ -701,8 +707,8 @@ get_extend_info_from_intro_point(const hs_service_intro_point_t *ip,
/** Return the number of introduction points that are established for the
* given descriptor. */
-static unsigned int
-count_desc_circuit_established(const hs_service_descriptor_t *desc)
+MOCK_IMPL(STATIC unsigned int,
+count_desc_circuit_established, (const hs_service_descriptor_t *desc))
{
unsigned int count = 0;
@@ -1764,7 +1770,8 @@ build_service_desc_superencrypted(const hs_service_t *service,
sizeof(curve25519_public_key_t));
/* Test that subcred is not zero because we might use it below */
- if (BUG(fast_mem_is_zero((char*)desc->desc->subcredential, DIGEST256_LEN))) {
+ if (BUG(fast_mem_is_zero((char*)desc->desc->subcredential.subcred,
+ DIGEST256_LEN))) {
return -1;
}
@@ -1781,7 +1788,7 @@ build_service_desc_superencrypted(const hs_service_t *service,
/* Prepare the client for descriptor and then add to the list in the
* superencrypted part of the descriptor */
- hs_desc_build_authorized_client(desc->desc->subcredential,
+ hs_desc_build_authorized_client(&desc->desc->subcredential,
&client->client_pk,
&desc->auth_ephemeral_kp.seckey,
desc->descriptor_cookie, desc_client);
@@ -1837,7 +1844,7 @@ build_service_desc_plaintext(const hs_service_t *service,
/* Set the subcredential. */
hs_get_subcredential(&service->keys.identity_pk, &desc->blinded_kp.pubkey,
- desc->desc->subcredential);
+ &desc->desc->subcredential);
plaintext = &desc->desc->plaintext_data;
@@ -1980,9 +1987,15 @@ build_service_descriptor(hs_service_t *service, uint64_t time_period_num,
/* Assign newly built descriptor to the next slot. */
*desc_out = desc;
+
/* Fire a CREATED control port event. */
hs_control_desc_event_created(service->onion_address,
&desc->blinded_kp.pubkey);
+
+ /* If we are an onionbalance instance, we refresh our keys when we rotate
+ * descriptors. */
+ hs_ob_refresh_keys(service);
+
return;
err:
@@ -3042,13 +3055,85 @@ service_desc_hsdirs_changed(const hs_service_t *service,
return should_reupload;
}
+/** These are all the reasons why a descriptor upload can't occur. We use
+ * those to log the reason properly with the right rate limiting and for the
+ * right descriptor. */
+typedef enum {
+ LOG_DESC_UPLOAD_REASON_MISSING_IPS = 0,
+ LOG_DESC_UPLOAD_REASON_IP_NOT_ESTABLISHED = 1,
+ LOG_DESC_UPLOAD_REASON_NOT_TIME = 2,
+ LOG_DESC_UPLOAD_REASON_NO_LIVE_CONSENSUS = 3,
+ LOG_DESC_UPLOAD_REASON_NO_DIRINFO = 4,
+} log_desc_upload_reason_t;
+
+/** Maximum number of reasons. This is used to allocate the static array of
+ * all rate limiting objects. */
+#define LOG_DESC_UPLOAD_REASON_MAX LOG_DESC_UPLOAD_REASON_NO_DIRINFO
+
+/** Log the reason why we can't upload the given descriptor for the given
+ * service. This takes a message string (allocated by the caller) and a
+ * reason.
+ *
+ * Depending on the reason and descriptor, different rate limit applies. This
+ * is done because this function will basically be called every second. Each
+ * descriptor for each reason uses its own log rate limit object in order to
+ * avoid message suppression for different reasons and descriptors. */
+static void
+log_cant_upload_desc(const hs_service_t *service,
+ const hs_service_descriptor_t *desc, const char *msg,
+ const log_desc_upload_reason_t reason)
+{
+ /* Writing the log every minute shouldn't be too annoying for log rate limit
+ * since this can be emitted every second for each descriptor.
+ *
+ * However, for one specific case, we increase it to 10 minutes because it
+ * is hit constantly, as an expected behavior, which is the reason
+ * indicating that it is not the time to upload. */
+ static ratelim_t limits[2][LOG_DESC_UPLOAD_REASON_MAX + 1] =
+ { { RATELIM_INIT(60), RATELIM_INIT(60), RATELIM_INIT(60 * 10),
+ RATELIM_INIT(60), RATELIM_INIT(60) },
+ { RATELIM_INIT(60), RATELIM_INIT(60), RATELIM_INIT(60 * 10),
+ RATELIM_INIT(60), RATELIM_INIT(60) },
+ };
+ bool is_next_desc = false;
+ unsigned int rlim_pos = 0;
+ ratelim_t *rlim = NULL;
+
+ tor_assert(service);
+ tor_assert(desc);
+ tor_assert(msg);
+
+ /* Make sure the reason value is valid. It should never happen because we
+ * control that value in the code flow but will be apparent during
+ * development if a reason is added but LOG_DESC_UPLOAD_REASON_NUM_ is not
+ * updated. */
+ if (BUG(reason > LOG_DESC_UPLOAD_REASON_MAX || reason < 0)) {
+ return;
+ }
+
+ /* Ease our life. Flag that tells us if the descriptor is the next one. */
+ is_next_desc = (service->desc_next == desc);
+
+ /* Current descriptor is the first element in the ratelimit object array.
+ * The next descriptor is the second element. */
+ rlim_pos = (is_next_desc ? 1 : 0);
+ /* Get the ratelimit object for the reason _and_ right descriptor. */
+ rlim = &limits[rlim_pos][reason];
+
+ log_fn_ratelim(rlim, LOG_INFO, LD_REND,
+ "Service %s can't upload its %s descriptor: %s",
+ safe_str_client(service->onion_address),
+ (is_next_desc) ? "next" : "current", msg);
+}
+
/** Return 1 if the given descriptor from the given service can be uploaded
* else return 0 if it can not. */
static int
should_service_upload_descriptor(const hs_service_t *service,
const hs_service_descriptor_t *desc, time_t now)
{
- unsigned int num_intro_points;
+ char *msg = NULL;
+ unsigned int num_intro_points, count_ip_established;
tor_assert(service);
tor_assert(desc);
@@ -3068,34 +3153,54 @@ should_service_upload_descriptor(const hs_service_t *service,
* upload descriptor in this case. We need at least one for the service to
* be reachable. */
if (desc->missing_intro_points && num_intro_points == 0) {
+ msg = tor_strdup("Missing intro points");
+ log_cant_upload_desc(service, desc, msg,
+ LOG_DESC_UPLOAD_REASON_MISSING_IPS);
goto cannot;
}
/* Check if all our introduction circuit have been established for all the
* intro points we have selected. */
- if (count_desc_circuit_established(desc) != num_intro_points) {
+ count_ip_established = count_desc_circuit_established(desc);
+ if (count_ip_established != num_intro_points) {
+ tor_asprintf(&msg, "Intro circuits aren't yet all established (%d/%d).",
+ count_ip_established, num_intro_points);
+ log_cant_upload_desc(service, desc, msg,
+ LOG_DESC_UPLOAD_REASON_IP_NOT_ESTABLISHED);
goto cannot;
}
/* Is it the right time to upload? */
if (desc->next_upload_time > now) {
+ tor_asprintf(&msg, "Next upload time is %ld, it is now %ld.",
+ (long int) desc->next_upload_time, (long int) now);
+ log_cant_upload_desc(service, desc, msg,
+ LOG_DESC_UPLOAD_REASON_NOT_TIME);
goto cannot;
}
/* Don't upload desc if we don't have a live consensus */
if (!networkstatus_get_live_consensus(now)) {
+ msg = tor_strdup("No live consensus");
+ log_cant_upload_desc(service, desc, msg,
+ LOG_DESC_UPLOAD_REASON_NO_LIVE_CONSENSUS);
goto cannot;
}
/* Do we know enough router descriptors to have adequate vision of the HSDir
hash ring? */
if (!router_have_minimum_dir_info()) {
+ msg = tor_strdup("Not enough directory information");
+ log_cant_upload_desc(service, desc, msg,
+ LOG_DESC_UPLOAD_REASON_NO_DIRINFO);
goto cannot;
}
/* Can upload! */
return 1;
+
cannot:
+ tor_free(msg);
return 0;
}
@@ -3369,7 +3474,7 @@ service_handle_introduce2(origin_circuit_t *circ, const uint8_t *payload,
/* The following will parse, decode and launch the rendezvous point circuit.
* Both current and legacy cells are handled. */
- if (hs_circ_handle_introduce2(service, circ, ip, desc->desc->subcredential,
+ if (hs_circ_handle_introduce2(service, circ, ip, &desc->desc->subcredential,
payload, payload_len) < 0) {
goto err;
}
@@ -4048,6 +4153,11 @@ hs_service_free_(hs_service_t *service)
replaycache_free(service->state.replay_cache_rend_cookie);
}
+ /* Free onionbalance subcredentials (if any) */
+ if (service->ob_subcreds) {
+ tor_free(service->ob_subcreds);
+ }
+
/* Wipe service keys. */
memwipe(&service->keys.identity_sk, 0, sizeof(service->keys.identity_sk));
diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h
index 8809411e01..3fe14878ed 100644
--- a/src/feature/hs/hs_service.h
+++ b/src/feature/hs/hs_service.h
@@ -248,10 +248,14 @@ typedef struct hs_service_config_t {
/** Does this service export the circuit ID of its clients? */
hs_circuit_id_protocol_t circuit_id_protocol;
- /* DoS defenses. For the ESTABLISH_INTRO cell extension. */
+ /** DoS defenses. For the ESTABLISH_INTRO cell extension. */
unsigned int has_dos_defense_enabled : 1;
uint32_t intro_dos_rate_per_sec;
uint32_t intro_dos_burst_per_sec;
+
+ /** If set, contains the Onion Balance master ed25519 public key (taken from
+ * an .onion addresses) that this tor instance serves as backend. */
+ smartlist_t *ob_master_pubkeys;
} hs_service_config_t;
/** Service state. */
@@ -301,8 +305,13 @@ typedef struct hs_service_t {
/** Next descriptor. */
hs_service_descriptor_t *desc_next;
- /* XXX: Credential (client auth.) #20700. */
-
+ /* If this is an onionbalance instance, this is an array of subcredentials
+ * that should be used when decrypting an INTRO2 cell. If this is not an
+ * onionbalance instance, this is NULL.
+ * See [ONIONBALANCE] section in rend-spec-v3.txt for more details . */
+ hs_subcredential_t *ob_subcreds;
+ /* Number of OB subcredentials */
+ size_t n_ob_subcreds;
} hs_service_t;
/** For the service global hash map, we define a specific type for it which
@@ -375,6 +384,9 @@ STATIC hs_service_t *get_first_service(void);
STATIC hs_service_intro_point_t *service_intro_point_find_by_ident(
const hs_service_t *service,
const hs_ident_circuit_t *ident);
+
+MOCK_DECL(STATIC unsigned int, count_desc_circuit_established,
+ (const hs_service_descriptor_t *desc));
#endif /* defined(TOR_UNIT_TESTS) */
/* Service accessors. */
diff --git a/src/feature/hs/include.am b/src/feature/hs/include.am
index 5e69607e59..f83907c76b 100644
--- a/src/feature/hs/include.am
+++ b/src/feature/hs/include.am
@@ -13,6 +13,7 @@ LIBTOR_APP_A_SOURCES += \
src/feature/hs/hs_dos.c \
src/feature/hs/hs_ident.c \
src/feature/hs/hs_intropoint.c \
+ src/feature/hs/hs_ob.c \
src/feature/hs/hs_service.c \
src/feature/hs/hs_stats.c
@@ -30,6 +31,7 @@ noinst_HEADERS += \
src/feature/hs/hs_dos.h \
src/feature/hs/hs_ident.h \
src/feature/hs/hs_intropoint.h \
+ src/feature/hs/hs_ob.h \
src/feature/hs/hs_service.h \
src/feature/hs/hs_stats.h \
src/feature/hs/hsdir_index_st.h
diff --git a/src/feature/hs_common/shared_random_client.c b/src/feature/hs_common/shared_random_client.c
index a46666ab50..3f46321be4 100644
--- a/src/feature/hs_common/shared_random_client.c
+++ b/src/feature/hs_common/shared_random_client.c
@@ -11,7 +11,8 @@
#include "feature/hs_common/shared_random_client.h"
#include "app/config/config.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/authmode.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/nodelist/networkstatus.h"
#include "lib/encoding/binascii.h"
@@ -31,6 +32,24 @@ srv_to_control_string(const sr_srv_t *srv)
return srv_str;
}
+/**
+ * If we have no consensus and we are not an authority, assume that this is
+ * the voting interval. We should never actually use this: only authorities
+ * should be trying to figure out the schedule when they don't have a
+ * consensus.
+ **/
+#define DEFAULT_NETWORK_VOTING_INTERVAL (3600)
+
+/* This is an unpleasing workaround for tests. Our unit tests assume that we
+ * are scheduling all of our shared random stuff as if we were a directory
+ * authority, but they do not always set V3AuthoritativeDir.
+ */
+#ifdef TOR_UNIT_TESTS
+#define ASSUME_AUTHORITY_SCHEDULING 1
+#else
+#define ASSUME_AUTHORITY_SCHEDULING 0
+#endif
+
/** Return the voting interval of the tor vote subsystem. */
int
get_voting_interval(void)
@@ -39,40 +58,27 @@ get_voting_interval(void)
networkstatus_t *consensus = networkstatus_get_live_consensus(time(NULL));
if (consensus) {
+ /* Ideally we have a live consensus and we can just use that. */
+ interval = (int)(consensus->fresh_until - consensus->valid_after);
+ } else if (authdir_mode(get_options()) || ASSUME_AUTHORITY_SCHEDULING) {
+ /* If we don't have a live consensus and we're an authority,
+ * we should believe our own view of what the schedule ought to be. */
+ interval = dirauth_sched_get_configured_interval();
+ } else if ((consensus = networkstatus_get_latest_consensus())) {
+ /* If we're a client, then maybe a latest consensus is good enough?
+ * It's better than falling back to the non-consensus case. */
interval = (int)(consensus->fresh_until - consensus->valid_after);
} else {
- /* Same for both a testing and real network. We voluntarily ignore the
- * InitialVotingInterval since it complexifies things and it doesn't
- * affect the SR protocol. */
- interval = get_options()->V3AuthVotingInterval;
+ /* We should never be reaching this point, since a client should never
+ * call this code unless they have some kind of a consensus. All we can
+ * do is hope that this network is using the default voting interval. */
+ tor_assert_nonfatal_unreached_once();
+ interval = DEFAULT_NETWORK_VOTING_INTERVAL;
}
tor_assert(interval > 0);
return interval;
}
-/** Given the current consensus, return the start time of the current round of
- * the SR protocol. For example, if it's 23:47:08, the current round thus
- * started at 23:47:00 for a voting interval of 10 seconds.
- *
- * This function uses the consensus voting schedule to derive its results,
- * instead of the actual consensus we are currently using, so it should be used
- * for voting purposes. */
-time_t
-get_start_time_of_current_round(void)
-{
- const or_options_t *options = get_options();
- int voting_interval = get_voting_interval();
- /* First, get the start time of the next round */
- time_t next_start = voting_schedule_get_next_valid_after_time();
- /* Now roll back next_start by a voting interval to find the start time of
- the current round. */
- time_t curr_start = voting_schedule_get_start_of_next_interval(
- next_start - voting_interval - 1,
- voting_interval,
- options->TestingV3AuthVotingStartOffset);
- return curr_start;
-}
-
/*
* Public API
*/
@@ -237,13 +243,27 @@ sr_state_get_start_time_of_current_protocol_run(void)
time_t beginning_of_curr_round;
/* This function is not used for voting purposes, so if we have a live
- consensus, use its valid-after as the beginning of the current round,
- otherwise resort to the voting schedule which should always exist. */
+ consensus, use its valid-after as the beginning of the current round.
+ If we have no consensus but we're an authority, use our own
+ schedule. Otherwise, try using our view of the voting interval
+ to figure out when the current round _should_ be starting.
+ */
networkstatus_t *ns = networkstatus_get_live_consensus(approx_time());
if (ns) {
beginning_of_curr_round = ns->valid_after;
+ } else if (authdir_mode(get_options()) || ASSUME_AUTHORITY_SCHEDULING) {
+ beginning_of_curr_round = dirauth_sched_get_cur_valid_after_time();
} else {
- beginning_of_curr_round = get_start_time_of_current_round();
+ /* voting_interval comes from get_voting_interval(), so if we're in
+ * this case as a client, we already tried to get the voting interval
+ * from the latest_consensus and gave a bug warning if we couldn't.
+ *
+ * We wouldn't want to look at the latest consensus's valid_after time,
+ * since that would be out of date. */
+ beginning_of_curr_round = voting_sched_get_start_of_interval_after(
+ approx_time() - voting_interval,
+ voting_interval,
+ 0);
}
/* Get current SR protocol round */
diff --git a/src/feature/hs_common/shared_random_client.h b/src/feature/hs_common/shared_random_client.h
index 3031a2bb9a..37a086d590 100644
--- a/src/feature/hs_common/shared_random_client.h
+++ b/src/feature/hs_common/shared_random_client.h
@@ -38,11 +38,9 @@ time_t sr_state_get_start_time_of_current_protocol_run(void);
time_t sr_state_get_start_time_of_previous_protocol_run(void);
unsigned int sr_state_get_phase_duration(void);
unsigned int sr_state_get_protocol_run_duration(void);
-time_t get_start_time_of_current_round(void);
#ifdef TOR_UNIT_TESTS
#endif /* TOR_UNIT_TESTS */
#endif /* !defined(TOR_SHARED_RANDOM_CLIENT_H) */
-
diff --git a/src/feature/nodelist/authcert.c b/src/feature/nodelist/authcert.c
index 7bdfabaeab..9c7525b6e2 100644
--- a/src/feature/nodelist/authcert.c
+++ b/src/feature/nodelist/authcert.c
@@ -46,7 +46,7 @@
#include "feature/nodelist/networkstatus_voter_info_st.h"
#include "feature/nodelist/node_st.h"
-DECLARE_TYPED_DIGESTMAP_FNS(dsmap_, digest_ds_map_t, download_status_t)
+DECLARE_TYPED_DIGESTMAP_FNS(dsmap, digest_ds_map_t, download_status_t)
#define DSMAP_FOREACH(map, keyvar, valvar) \
DIGESTMAP_FOREACH(dsmap_to_digestmap(map), keyvar, download_status_t *, \
valvar)
diff --git a/src/feature/nodelist/microdesc.c b/src/feature/nodelist/microdesc.c
index d32a4ea61e..cf7732b8dc 100644
--- a/src/feature/nodelist/microdesc.c
+++ b/src/feature/nodelist/microdesc.c
@@ -90,10 +90,10 @@ microdesc_eq_(microdesc_t *a, microdesc_t *b)
}
HT_PROTOTYPE(microdesc_map, microdesc_t, node,
- microdesc_hash_, microdesc_eq_)
+ microdesc_hash_, microdesc_eq_);
HT_GENERATE2(microdesc_map, microdesc_t, node,
microdesc_hash_, microdesc_eq_, 0.6,
- tor_reallocarray_, tor_free_)
+ tor_reallocarray_, tor_free_);
/************************* md fetch fail cache *****************************/
diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c
index cc4b8e1c34..2188e47177 100644
--- a/src/feature/nodelist/networkstatus.c
+++ b/src/feature/nodelist/networkstatus.c
@@ -66,7 +66,7 @@
#include "feature/dirclient/dirclient_modes.h"
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/directory.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dirparse/ns_parse.h"
#include "feature/hibernate/hibernate.h"
#include "feature/hs/hs_dos.h"
@@ -2120,7 +2120,7 @@ networkstatus_set_current_consensus(const char *consensus,
* the first thing we need to do is recalculate the voting schedule static
* object so we can use the timings in there needed by some subsystems
* such as hidden service and shared random. */
- voting_schedule_recalculate_timing(options, now);
+ dirauth_sched_recalculate_timing(options, now);
reschedule_dirvote(options);
nodelist_set_consensus(c);
@@ -2765,3 +2765,47 @@ networkstatus_free_all(void)
}
}
}
+
+/** Return the start of the next interval of size <b>interval</b> (in
+ * seconds) after <b>now</b>, plus <b>offset</b>. Midnight always
+ * starts a fresh interval, and if the last interval of a day would be
+ * truncated to less than half its size, it is rolled into the
+ * previous interval. */
+time_t
+voting_sched_get_start_of_interval_after(time_t now, int interval,
+ int offset)
+{
+ struct tm tm;
+ time_t midnight_today=0;
+ time_t midnight_tomorrow;
+ time_t next;
+
+ tor_gmtime_r(&now, &tm);
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+
+ if (tor_timegm(&tm, &midnight_today) < 0) {
+ // LCOV_EXCL_START
+ log_warn(LD_BUG, "Ran into an invalid time when trying to find midnight.");
+ // LCOV_EXCL_STOP
+ }
+ midnight_tomorrow = midnight_today + (24*60*60);
+
+ next = midnight_today + ((now-midnight_today)/interval + 1)*interval;
+
+ /* Intervals never cross midnight. */
+ if (next > midnight_tomorrow)
+ next = midnight_tomorrow;
+
+ /* If the interval would only last half as long as it's supposed to, then
+ * skip over to the next day. */
+ if (next + interval/2 > midnight_tomorrow)
+ next = midnight_tomorrow;
+
+ next += offset;
+ if (next - interval > now)
+ next -= interval;
+
+ return next;
+}
diff --git a/src/feature/nodelist/networkstatus.h b/src/feature/nodelist/networkstatus.h
index 5e8c8a9e57..ce050aeadc 100644
--- a/src/feature/nodelist/networkstatus.h
+++ b/src/feature/nodelist/networkstatus.h
@@ -153,6 +153,9 @@ void vote_routerstatus_free_(vote_routerstatus_t *rs);
void set_routerstatus_from_routerinfo(routerstatus_t *rs,
const node_t *node,
const routerinfo_t *ri);
+time_t voting_sched_get_start_of_interval_after(time_t now,
+ int interval,
+ int offset);
#ifdef NETWORKSTATUS_PRIVATE
#ifdef TOR_UNIT_TESTS
diff --git a/src/feature/nodelist/nodefamily.c b/src/feature/nodelist/nodefamily.c
index 7ae8620749..feaa3730dc 100644
--- a/src/feature/nodelist/nodefamily.c
+++ b/src/feature/nodelist/nodefamily.c
@@ -69,9 +69,9 @@ static HT_HEAD(nodefamily_map, nodefamily_t) the_node_families
= HT_INITIALIZER();
HT_PROTOTYPE(nodefamily_map, nodefamily_t, ht_ent, nodefamily_hash,
- nodefamily_eq)
+ nodefamily_eq);
HT_GENERATE2(nodefamily_map, nodefamily_t, ht_ent, nodefamily_hash,
- node_family_eq, 0.6, tor_reallocarray_, tor_free_)
+ node_family_eq, 0.6, tor_reallocarray_, tor_free_);
/**
* Parse the family declaration in <b>s</b>, returning the canonical
diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c
index b7c7552561..fcf27b1a3a 100644
--- a/src/feature/nodelist/nodelist.c
+++ b/src/feature/nodelist/nodelist.c
@@ -153,9 +153,9 @@ node_id_eq(const node_t *node1, const node_t *node2)
return tor_memeq(node1->identity, node2->identity, DIGEST_LEN);
}
-HT_PROTOTYPE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq)
+HT_PROTOTYPE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq);
HT_GENERATE2(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq,
- 0.6, tor_reallocarray_, tor_free_)
+ 0.6, tor_reallocarray_, tor_free_);
static inline unsigned int
node_ed_id_hash(const node_t *node)
@@ -170,9 +170,9 @@ node_ed_id_eq(const node_t *node1, const node_t *node2)
}
HT_PROTOTYPE(nodelist_ed_map, node_t, ed_ht_ent, node_ed_id_hash,
- node_ed_id_eq)
+ node_ed_id_eq);
HT_GENERATE2(nodelist_ed_map, node_t, ed_ht_ent, node_ed_id_hash,
- node_ed_id_eq, 0.6, tor_reallocarray_, tor_free_)
+ node_ed_id_eq, 0.6, tor_reallocarray_, tor_free_);
/** The global nodelist. */
static nodelist_t *the_nodelist=NULL;
@@ -1240,8 +1240,8 @@ node_get_rsa_id_digest(const node_t *node)
* If node is NULL, returns an empty smartlist.
*
* The smartlist must be freed using link_specifier_smartlist_free(). */
-smartlist_t *
-node_get_link_specifier_smartlist(const node_t *node, bool direct_conn)
+MOCK_IMPL(smartlist_t *,
+node_get_link_specifier_smartlist,(const node_t *node, bool direct_conn))
{
link_specifier_t *ls;
tor_addr_port_t ap;
diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h
index 87020b81eb..6e854ec879 100644
--- a/src/feature/nodelist/nodelist.h
+++ b/src/feature/nodelist/nodelist.h
@@ -80,8 +80,8 @@ int node_supports_ed25519_hs_intro(const node_t *node);
int node_supports_v3_rendezvous_point(const node_t *node);
int node_supports_establish_intro_dos_extension(const node_t *node);
const uint8_t *node_get_rsa_id_digest(const node_t *node);
-smartlist_t *node_get_link_specifier_smartlist(const node_t *node,
- bool direct_conn);
+MOCK_DECL(smartlist_t *,node_get_link_specifier_smartlist,(const node_t *node,
+ bool direct_conn));
void link_specifier_smartlist_free_(smartlist_t *ls_list);
#define link_specifier_smartlist_free(ls_list) \
FREE_AND_NULL(smartlist_t, link_specifier_smartlist_free_, (ls_list))
diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c
index 42ce6f4c4e..f4e1215a40 100644
--- a/src/feature/nodelist/routerlist.c
+++ b/src/feature/nodelist/routerlist.c
@@ -117,9 +117,9 @@
/* Typed wrappers for different digestmap types; used to avoid type
* confusion. */
-DECLARE_TYPED_DIGESTMAP_FNS(sdmap_, digest_sd_map_t, signed_descriptor_t)
-DECLARE_TYPED_DIGESTMAP_FNS(rimap_, digest_ri_map_t, routerinfo_t)
-DECLARE_TYPED_DIGESTMAP_FNS(eimap_, digest_ei_map_t, extrainfo_t)
+DECLARE_TYPED_DIGESTMAP_FNS(sdmap, digest_sd_map_t, signed_descriptor_t)
+DECLARE_TYPED_DIGESTMAP_FNS(rimap, digest_ri_map_t, routerinfo_t)
+DECLARE_TYPED_DIGESTMAP_FNS(eimap, digest_ei_map_t, extrainfo_t)
#define SDMAP_FOREACH(map, keyvar, valvar) \
DIGESTMAP_FOREACH(sdmap_to_digestmap(map), keyvar, signed_descriptor_t *, \
valvar)
diff --git a/src/feature/relay/dns.c b/src/feature/relay/dns.c
index da0cbb1df4..5f868a9020 100644
--- a/src/feature/relay/dns.c
+++ b/src/feature/relay/dns.c
@@ -146,9 +146,9 @@ cached_resolve_hash(cached_resolve_t *a)
}
HT_PROTOTYPE(cache_map, cached_resolve_t, node, cached_resolve_hash,
- cached_resolves_eq)
+ cached_resolves_eq);
HT_GENERATE2(cache_map, cached_resolve_t, node, cached_resolve_hash,
- cached_resolves_eq, 0.6, tor_reallocarray_, tor_free_)
+ cached_resolves_eq, 0.6, tor_reallocarray_, tor_free_);
/** Initialize the DNS cache. */
static void
@@ -268,22 +268,6 @@ has_dns_init_failed(void)
return nameserver_config_failed;
}
-/** Helper: Given a TTL from a DNS response, determine what TTL to give the
- * OP that asked us to resolve it, and how long to cache that record
- * ourselves. */
-uint32_t
-dns_clip_ttl(uint32_t ttl)
-{
- /* This logic is a defense against "DefectTor" DNS-based traffic
- * confirmation attacks, as in https://nymity.ch/tor-dns/tor-dns.pdf .
- * We only give two values: a "low" value and a "high" value.
- */
- if (ttl < MIN_DNS_TTL_AT_EXIT)
- return MIN_DNS_TTL_AT_EXIT;
- else
- return MAX_DNS_TTL_AT_EXIT;
-}
-
/** Helper: free storage held by an entry in the DNS cache. */
static void
free_cached_resolve_(cached_resolve_t *r)
@@ -521,7 +505,7 @@ send_resolved_cell,(edge_connection_t *conn, uint8_t answer_type,
uint32_t ttl;
buf[0] = answer_type;
- ttl = dns_clip_ttl(conn->address_ttl);
+ ttl = clip_dns_ttl(conn->address_ttl);
switch (answer_type)
{
@@ -593,7 +577,7 @@ send_resolved_hostname_cell,(edge_connection_t *conn,
size_t namelen = strlen(hostname);
tor_assert(namelen < 256);
- ttl = dns_clip_ttl(conn->address_ttl);
+ ttl = clip_dns_ttl(conn->address_ttl);
buf[0] = RESOLVED_TYPE_HOSTNAME;
buf[1] = (uint8_t)namelen;
@@ -987,25 +971,6 @@ assert_connection_edge_not_dns_pending(edge_connection_t *conn)
#endif /* 1 */
}
-/** Log an error and abort if any connection waiting for a DNS resolve is
- * corrupted. */
-void
-assert_all_pending_dns_resolves_ok(void)
-{
- pending_connection_t *pend;
- cached_resolve_t **resolve;
-
- HT_FOREACH(resolve, cache_map, &cache_root) {
- for (pend = (*resolve)->pending_connections;
- pend;
- pend = pend->next) {
- assert_connection_ok(TO_CONN(pend->conn), 0);
- tor_assert(!SOCKET_OK(pend->conn->base_.s));
- tor_assert(!connection_in_array(TO_CONN(pend->conn)));
- }
- }
-}
-
/** Remove <b>conn</b> from the list of connections waiting for conn-\>address.
*/
void
@@ -1063,7 +1028,7 @@ connection_dns_remove(edge_connection_t *conn)
* the resolve for <b>address</b> itself, and remove any cached results for
* <b>address</b> from the cache.
*/
-MOCK_IMPL(void,
+MOCK_IMPL(STATIC void,
dns_cancel_pending_resolve,(const char *address))
{
pending_connection_t *pend;
@@ -1338,7 +1303,7 @@ make_pending_resolve_cached(cached_resolve_t *resolve)
resolve->ttl_hostname < ttl)
ttl = resolve->ttl_hostname;
- set_expiry(new_resolve, time(NULL) + dns_clip_ttl(ttl));
+ set_expiry(new_resolve, time(NULL) + clip_dns_ttl(ttl));
}
assert_cache_ok();
@@ -2051,12 +2016,12 @@ dns_launch_correctness_checks(void)
/* Wait a while before launching requests for test addresses, so we can
* get the results from checking for wildcarding. */
- if (! launch_event)
+ if (!launch_event)
launch_event = tor_evtimer_new(tor_libevent_get_base(),
launch_test_addresses, NULL);
timeout.tv_sec = 30;
timeout.tv_usec = 0;
- if (evtimer_add(launch_event, &timeout)<0) {
+ if (evtimer_add(launch_event, &timeout) < 0) {
log_warn(LD_BUG, "Couldn't add timer for checking for dns hijacking");
}
}
@@ -2188,7 +2153,7 @@ dns_cache_handle_oom(time_t now, size_t min_remove_bytes)
total_bytes_removed += bytes_removed;
/* Increase time_inc by a reasonable fraction. */
- time_inc += (MAX_DNS_TTL_AT_EXIT / 4);
+ time_inc += (MAX_DNS_TTL / 4);
} while (total_bytes_removed < min_remove_bytes);
return total_bytes_removed;
diff --git a/src/feature/relay/dns.h b/src/feature/relay/dns.h
index 2b1da8d126..120b75bf8d 100644
--- a/src/feature/relay/dns.h
+++ b/src/feature/relay/dns.h
@@ -12,29 +12,14 @@
#ifndef TOR_DNS_H
#define TOR_DNS_H
-/** Lowest value for DNS ttl that a server will give. */
-#define MIN_DNS_TTL_AT_EXIT (5*60)
-/** Highest value for DNS ttl that a server will give. */
-#define MAX_DNS_TTL_AT_EXIT (60*60)
-
-/** How long do we keep DNS cache entries before purging them (regardless of
- * their TTL)? */
-#define MAX_DNS_ENTRY_AGE (3*60*60)
-/** How long do we cache/tell clients to cache DNS records when no TTL is
- * known? */
-#define DEFAULT_DNS_TTL (30*60)
+#ifdef HAVE_MODULE_RELAY
int dns_init(void);
int has_dns_init_failed(void);
-void dns_free_all(void);
-uint32_t dns_clip_ttl(uint32_t ttl);
int dns_reset(void);
void connection_dns_remove(edge_connection_t *conn);
void assert_connection_edge_not_dns_pending(edge_connection_t *conn);
-void assert_all_pending_dns_resolves_ok(void);
-MOCK_DECL(void,dns_cancel_pending_resolve,(const char *question));
int dns_resolve(edge_connection_t *exitconn);
-void dns_launch_correctness_checks(void);
int dns_seems_to_be_broken(void);
int dns_seems_to_be_broken_for_ipv6(void);
void dns_reset_correctness_checks(void);
@@ -42,6 +27,48 @@ 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);
+/* These functions are only used within the feature/relay module, and don't
+ * need stubs. */
+void dns_free_all(void);
+void dns_launch_correctness_checks(void);
+
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+#define dns_init() (0)
+#define dns_seems_to_be_broken() (0)
+#define has_dns_init_failed() (0)
+#define dns_cache_total_allocation() (0)
+
+#define dns_reset_correctness_checks() STMT_NIL
+
+#define assert_connection_edge_not_dns_pending(conn) \
+ ((void)(conn))
+#define dump_dns_mem_usage(severity)\
+ ((void)(severity))
+#define dns_cache_handle_oom(now, bytes) \
+ ((void)(now), (void)(bytes), 0)
+
+#define connection_dns_remove(conn) \
+ STMT_BEGIN \
+ (void)(conn); \
+ tor_assert_nonfatal_unreached(); \
+ STMT_END
+
+static inline int
+dns_reset(void)
+{
+ return 0;
+}
+static inline int
+dns_resolve(edge_connection_t *exitconn)
+{
+ (void)exitconn;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
#ifdef DNS_PRIVATE
#include "feature/relay/dns_structs.h"
@@ -50,6 +77,7 @@ size_t number_of_configured_nameservers(void);
tor_addr_t *configured_nameserver_address(const size_t idx);
#endif
+MOCK_DECL(STATIC void,dns_cancel_pending_resolve,(const char *question));
MOCK_DECL(STATIC int,dns_resolve_impl,(edge_connection_t *exitconn,
int is_resolve,or_circuit_t *oncirc, char **hostname_out,
int *made_connection_pending_out, cached_resolve_t **resolve_out));
@@ -74,4 +102,3 @@ launch_resolve,(cached_resolve_t *resolve));
#endif /* defined(DNS_PRIVATE) */
#endif /* !defined(TOR_DNS_H) */
-
diff --git a/src/feature/relay/ext_orport.c b/src/feature/relay/ext_orport.c
index ce4e043dd7..5568dacf1a 100644
--- a/src/feature/relay/ext_orport.c
+++ b/src/feature/relay/ext_orport.c
@@ -652,6 +652,77 @@ 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 dbe89fce18..416c358397 100644
--- a/src/feature/relay/ext_orport.h
+++ b/src/feature/relay/ext_orport.h
@@ -31,26 +31,56 @@
#define EXT_OR_CONN_STATE_FLUSHING 5
#define EXT_OR_CONN_STATE_MAX_ 5
-int connection_ext_or_start_auth(or_connection_t *or_conn);
-
-ext_or_cmd_t *ext_or_cmd_new(uint16_t len);
+#ifdef HAVE_MODULE_RELAY
-#define ext_or_cmd_free(cmd) \
- FREE_AND_NULL(ext_or_cmd_t, ext_or_cmd_free_, (cmd))
+int connection_ext_or_start_auth(or_connection_t *or_conn);
-void ext_or_cmd_free_(ext_or_cmd_t *cmd);
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);
-or_connection_t *connection_or_get_by_ext_or_id(const char *id);
-
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);
+/* (No stub needed for these: they are only called within feature/relay.) */
int init_ext_or_cookie_authentication(int is_enabled);
-char *get_ext_or_auth_cookie_file_name(void);
void ext_orport_free_all(void);
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+static inline int
+connection_ext_or_start_auth(or_connection_t *conn)
+{
+ (void)conn;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+static inline int
+connection_ext_or_finished_flushing(or_connection_t *conn)
+{
+ (void)conn;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+static inline int
+connection_ext_or_process_inbuf(or_connection_t *conn)
+{
+ (void)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)
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
#ifdef EXT_ORPORT_PRIVATE
STATIC int connection_write_ext_or_command(connection_t *conn,
uint16_t command,
@@ -60,9 +90,11 @@ STATIC int handle_client_auth_nonce(const char *client_nonce,
size_t client_nonce_len,
char **client_hash_out,
char **reply_out, size_t *reply_len_out);
+
#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 a4c025ae12..813ddb8fb1 100644
--- a/src/feature/relay/include.am
+++ b/src/feature/relay/include.am
@@ -1,21 +1,22 @@
# Legacy shared relay code: migrate to the relay module over time
LIBTOR_APP_A_SOURCES += \
- src/feature/relay/dns.c \
- src/feature/relay/ext_orport.c \
src/feature/relay/onion_queue.c \
- src/feature/relay/router.c \
- src/feature/relay/routerkeys.c \
- src/feature/relay/selftest.c
+ src/feature/relay/router.c
# The Relay module.
# ADD_C_FILE: INSERT SOURCES HERE.
MODULE_RELAY_SOURCES = \
+ src/feature/relay/dns.c \
+ src/feature/relay/ext_orport.c \
src/feature/relay/routermode.c \
src/feature/relay/relay_config.c \
+ src/feature/relay/relay_handshake.c \
src/feature/relay/relay_periodic.c \
src/feature/relay/relay_sys.c \
+ src/feature/relay/routerkeys.c \
+ src/feature/relay/selftest.c \
src/feature/relay/transport_config.c
# ADD_C_FILE: INSERT HEADERS HERE.
@@ -25,6 +26,7 @@ noinst_HEADERS += \
src/feature/relay/ext_orport.h \
src/feature/relay/onion_queue.h \
src/feature/relay/relay_config.h \
+ src/feature/relay/relay_handshake.h \
src/feature/relay/relay_periodic.h \
src/feature/relay/relay_sys.h \
src/feature/relay/router.h \
diff --git a/src/feature/relay/onion_queue.c b/src/feature/relay/onion_queue.c
index ce2d41b7e1..3cbaa65d28 100644
--- a/src/feature/relay/onion_queue.c
+++ b/src/feature/relay/onion_queue.c
@@ -49,10 +49,12 @@ typedef struct 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;
+
/** Array of queues of circuits waiting for CPU workers. An element is NULL
* if that queue is empty.*/
-static TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t)
- ol_list[MAX_ONION_HANDSHAKE_TYPE+1] =
+static onion_queue_head_t ol_list[MAX_ONION_HANDSHAKE_TYPE+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 */
diff --git a/src/feature/relay/relay_handshake.c b/src/feature/relay/relay_handshake.c
new file mode 100644
index 0000000000..030dc94956
--- /dev/null
+++ b/src/feature/relay/relay_handshake.c
@@ -0,0 +1,565 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file relay_handshake.c
+ * @brief Functions to implement the relay-only parts of our
+ * connection handshake.
+ *
+ * Some parts of our TLS link handshake are only done by relays (including
+ * bridges). Specifically, only relays need to send CERTS cells; only
+ * relays need to send or receive AUTHCHALLENGE cells, and only relays need to
+ * send or receive AUTHENTICATE cells.
+ **/
+
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "feature/relay/relay_handshake.h"
+
+#include "app/config/config.h"
+#include "core/or/connection_or.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "trunnel/link_handshake.h"
+#include "feature/relay/routerkeys.h"
+#include "feature/nodelist/torcert.h"
+
+#include "core/or/or_connection_st.h"
+#include "core/or/or_handshake_certs_st.h"
+#include "core/or/or_handshake_state_st.h"
+#include "core/or/var_cell_st.h"
+
+#include "lib/tls/tortls.h"
+#include "lib/tls/x509.h"
+
+/** Helper used to add an encoded certs to a cert cell */
+static void
+add_certs_cell_cert_helper(certs_cell_t *certs_cell,
+ uint8_t cert_type,
+ const uint8_t *cert_encoded,
+ size_t cert_len)
+{
+ tor_assert(cert_len <= UINT16_MAX);
+ certs_cell_cert_t *ccc = certs_cell_cert_new();
+ ccc->cert_type = cert_type;
+ ccc->cert_len = cert_len;
+ certs_cell_cert_setlen_body(ccc, cert_len);
+ memcpy(certs_cell_cert_getarray_body(ccc), cert_encoded, cert_len);
+
+ certs_cell_add_certs(certs_cell, ccc);
+}
+
+/** Add an encoded X509 cert (stored as <b>cert_len</b> bytes at
+ * <b>cert_encoded</b>) to the trunnel certs_cell_t object that we are
+ * building in <b>certs_cell</b>. Set its type field to <b>cert_type</b>.
+ * (If <b>cert</b> is NULL, take no action.) */
+static void
+add_x509_cert(certs_cell_t *certs_cell,
+ uint8_t cert_type,
+ const tor_x509_cert_t *cert)
+{
+ if (NULL == cert)
+ return;
+
+ const uint8_t *cert_encoded = NULL;
+ size_t cert_len;
+ tor_x509_cert_get_der(cert, &cert_encoded, &cert_len);
+
+ add_certs_cell_cert_helper(certs_cell, cert_type, cert_encoded, cert_len);
+}
+
+/** Add an Ed25519 cert from <b>cert</b> to the trunnel certs_cell_t object
+ * that we are building in <b>certs_cell</b>. Set its type field to
+ * <b>cert_type</b>. (If <b>cert</b> is NULL, take no action.) */
+static void
+add_ed25519_cert(certs_cell_t *certs_cell,
+ uint8_t cert_type,
+ const tor_cert_t *cert)
+{
+ if (NULL == cert)
+ return;
+
+ add_certs_cell_cert_helper(certs_cell, cert_type,
+ cert->encoded, cert->encoded_len);
+}
+
+#ifdef TOR_UNIT_TESTS
+int certs_cell_ed25519_disabled_for_testing = 0;
+#else
+#define certs_cell_ed25519_disabled_for_testing 0
+#endif
+
+/** Send a CERTS cell on the connection <b>conn</b>. Return 0 on success, -1
+ * on failure. */
+int
+connection_or_send_certs_cell(or_connection_t *conn)
+{
+ const tor_x509_cert_t *global_link_cert = NULL, *id_cert = NULL;
+ tor_x509_cert_t *own_link_cert = NULL;
+ var_cell_t *cell;
+
+ certs_cell_t *certs_cell = NULL;
+
+ tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
+
+ if (! conn->handshake_state)
+ return -1;
+
+ const int conn_in_server_mode = ! conn->handshake_state->started_here;
+
+ /* Get the encoded values of the X509 certificates */
+ if (tor_tls_get_my_certs(conn_in_server_mode,
+ &global_link_cert, &id_cert) < 0)
+ return -1;
+
+ if (conn_in_server_mode) {
+ own_link_cert = tor_tls_get_own_cert(conn->tls);
+ }
+ tor_assert(id_cert);
+
+ certs_cell = certs_cell_new();
+
+ /* Start adding certs. First the link cert or auth1024 cert. */
+ if (conn_in_server_mode) {
+ tor_assert_nonfatal(own_link_cert);
+ add_x509_cert(certs_cell,
+ OR_CERT_TYPE_TLS_LINK, own_link_cert);
+ } else {
+ tor_assert(global_link_cert);
+ add_x509_cert(certs_cell,
+ OR_CERT_TYPE_AUTH_1024, global_link_cert);
+ }
+
+ /* Next the RSA->RSA ID cert */
+ add_x509_cert(certs_cell,
+ OR_CERT_TYPE_ID_1024, id_cert);
+
+ /* Next the Ed25519 certs */
+ add_ed25519_cert(certs_cell,
+ CERTTYPE_ED_ID_SIGN,
+ get_master_signing_key_cert());
+ if (conn_in_server_mode) {
+ tor_assert_nonfatal(conn->handshake_state->own_link_cert ||
+ certs_cell_ed25519_disabled_for_testing);
+ add_ed25519_cert(certs_cell,
+ CERTTYPE_ED_SIGN_LINK,
+ conn->handshake_state->own_link_cert);
+ } else {
+ add_ed25519_cert(certs_cell,
+ CERTTYPE_ED_SIGN_AUTH,
+ get_current_auth_key_cert());
+ }
+
+ /* And finally the crosscert. */
+ {
+ const uint8_t *crosscert=NULL;
+ size_t crosscert_len;
+ get_master_rsa_crosscert(&crosscert, &crosscert_len);
+ if (crosscert) {
+ add_certs_cell_cert_helper(certs_cell,
+ CERTTYPE_RSA1024_ID_EDID,
+ crosscert, crosscert_len);
+ }
+ }
+
+ /* We've added all the certs; make the cell. */
+ certs_cell->n_certs = certs_cell_getlen_certs(certs_cell);
+
+ ssize_t alloc_len = certs_cell_encoded_len(certs_cell);
+ tor_assert(alloc_len >= 0 && alloc_len <= UINT16_MAX);
+ cell = var_cell_new(alloc_len);
+ cell->command = CELL_CERTS;
+ ssize_t enc_len = certs_cell_encode(cell->payload, alloc_len, certs_cell);
+ tor_assert(enc_len > 0 && enc_len <= alloc_len);
+ cell->payload_len = enc_len;
+
+ connection_or_write_var_cell_to_buf(cell, conn);
+ var_cell_free(cell);
+ certs_cell_free(certs_cell);
+ tor_x509_cert_free(own_link_cert);
+
+ return 0;
+}
+
+#ifdef TOR_UNIT_TESTS
+int testing__connection_or_pretend_TLSSECRET_is_supported = 0;
+#else
+#define testing__connection_or_pretend_TLSSECRET_is_supported 0
+#endif
+
+/** Return true iff <b>challenge_type</b> is an AUTHCHALLENGE type that
+ * we can send and receive. */
+int
+authchallenge_type_is_supported(uint16_t challenge_type)
+{
+ switch (challenge_type) {
+ case AUTHTYPE_RSA_SHA256_TLSSECRET:
+#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
+ return 1;
+#else
+ return testing__connection_or_pretend_TLSSECRET_is_supported;
+#endif
+ case AUTHTYPE_ED25519_SHA256_RFC5705:
+ return 1;
+ case AUTHTYPE_RSA_SHA256_RFC5705:
+ default:
+ return 0;
+ }
+}
+
+/** Return true iff <b>challenge_type_a</b> is one that we would rather
+ * use than <b>challenge_type_b</b>. */
+int
+authchallenge_type_is_better(uint16_t challenge_type_a,
+ uint16_t challenge_type_b)
+{
+ /* Any supported type is better than an unsupported one;
+ * all unsupported types are equally bad. */
+ if (!authchallenge_type_is_supported(challenge_type_a))
+ return 0;
+ if (!authchallenge_type_is_supported(challenge_type_b))
+ return 1;
+ /* It happens that types are superior in numerically ascending order.
+ * If that ever changes, this must change too. */
+ return (challenge_type_a > challenge_type_b);
+}
+
+/** Send an AUTH_CHALLENGE cell on the connection <b>conn</b>. Return 0
+ * on success, -1 on failure. */
+int
+connection_or_send_auth_challenge_cell(or_connection_t *conn)
+{
+ var_cell_t *cell = NULL;
+ int r = -1;
+ tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
+
+ if (! conn->handshake_state)
+ return -1;
+
+ auth_challenge_cell_t *ac = auth_challenge_cell_new();
+
+ tor_assert(sizeof(ac->challenge) == 32);
+ crypto_rand((char*)ac->challenge, sizeof(ac->challenge));
+
+ if (authchallenge_type_is_supported(AUTHTYPE_RSA_SHA256_TLSSECRET))
+ auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_TLSSECRET);
+ /* Disabled, because everything that supports this method also supports
+ * the much-superior ED25519_SHA256_RFC5705 */
+ /* auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_RFC5705); */
+ if (authchallenge_type_is_supported(AUTHTYPE_ED25519_SHA256_RFC5705))
+ auth_challenge_cell_add_methods(ac, AUTHTYPE_ED25519_SHA256_RFC5705);
+ auth_challenge_cell_set_n_methods(ac,
+ auth_challenge_cell_getlen_methods(ac));
+
+ cell = var_cell_new(auth_challenge_cell_encoded_len(ac));
+ ssize_t len = auth_challenge_cell_encode(cell->payload, cell->payload_len,
+ ac);
+ if (len != cell->payload_len) {
+ /* LCOV_EXCL_START */
+ log_warn(LD_BUG, "Encoded auth challenge cell length not as expected");
+ goto done;
+ /* LCOV_EXCL_STOP */
+ }
+ cell->command = CELL_AUTH_CHALLENGE;
+
+ connection_or_write_var_cell_to_buf(cell, conn);
+ r = 0;
+
+ done:
+ var_cell_free(cell);
+ auth_challenge_cell_free(ac);
+
+ return r;
+}
+
+/** Compute the main body of an AUTHENTICATE cell that a client can use
+ * to authenticate itself on a v3 handshake for <b>conn</b>. Return it
+ * in a var_cell_t.
+ *
+ * If <b>server</b> is true, only calculate the first
+ * V3_AUTH_FIXED_PART_LEN bytes -- the part of the authenticator that's
+ * determined by the rest of the handshake, and which match the provided value
+ * exactly.
+ *
+ * If <b>server</b> is false and <b>signing_key</b> is NULL, calculate the
+ * first V3_AUTH_BODY_LEN bytes of the authenticator (that is, everything
+ * that should be signed), but don't actually sign it.
+ *
+ * If <b>server</b> is false and <b>signing_key</b> is provided, calculate the
+ * entire authenticator, signed with <b>signing_key</b>.
+ *
+ * Return the length of the cell body on success, and -1 on failure.
+ */
+var_cell_t *
+connection_or_compute_authenticate_cell_body(or_connection_t *conn,
+ const int authtype,
+ crypto_pk_t *signing_key,
+ const ed25519_keypair_t *ed_signing_key,
+ int server)
+{
+ auth1_t *auth = NULL;
+ auth_ctx_t *ctx = auth_ctx_new();
+ var_cell_t *result = NULL;
+ int old_tlssecrets_algorithm = 0;
+ const char *authtype_str = NULL;
+
+ int is_ed = 0;
+
+ /* assert state is reasonable XXXX */
+ switch (authtype) {
+ case AUTHTYPE_RSA_SHA256_TLSSECRET:
+ authtype_str = "AUTH0001";
+ old_tlssecrets_algorithm = 1;
+ break;
+ case AUTHTYPE_RSA_SHA256_RFC5705:
+ authtype_str = "AUTH0002";
+ break;
+ case AUTHTYPE_ED25519_SHA256_RFC5705:
+ authtype_str = "AUTH0003";
+ is_ed = 1;
+ break;
+ default:
+ tor_assert(0);
+ break;
+ }
+
+ auth = auth1_new();
+ ctx->is_ed = is_ed;
+
+ /* Type: 8 bytes. */
+ memcpy(auth1_getarray_type(auth), authtype_str, 8);
+
+ {
+ const tor_x509_cert_t *id_cert=NULL;
+ const common_digests_t *my_digests, *their_digests;
+ const uint8_t *my_id, *their_id, *client_id, *server_id;
+ if (tor_tls_get_my_certs(server, NULL, &id_cert))
+ goto err;
+ my_digests = tor_x509_cert_get_id_digests(id_cert);
+ their_digests =
+ tor_x509_cert_get_id_digests(conn->handshake_state->certs->id_cert);
+ tor_assert(my_digests);
+ tor_assert(their_digests);
+ my_id = (uint8_t*)my_digests->d[DIGEST_SHA256];
+ their_id = (uint8_t*)their_digests->d[DIGEST_SHA256];
+
+ client_id = server ? their_id : my_id;
+ server_id = server ? my_id : their_id;
+
+ /* Client ID digest: 32 octets. */
+ memcpy(auth->cid, client_id, 32);
+
+ /* Server ID digest: 32 octets. */
+ memcpy(auth->sid, server_id, 32);
+ }
+
+ if (is_ed) {
+ const ed25519_public_key_t *my_ed_id, *their_ed_id;
+ if (!conn->handshake_state->certs->ed_id_sign) {
+ log_warn(LD_OR, "Ed authenticate without Ed ID cert from peer.");
+ goto err;
+ }
+ my_ed_id = get_master_identity_key();
+ their_ed_id = &conn->handshake_state->certs->ed_id_sign->signing_key;
+
+ const uint8_t *cid_ed = (server ? their_ed_id : my_ed_id)->pubkey;
+ const uint8_t *sid_ed = (server ? my_ed_id : their_ed_id)->pubkey;
+
+ memcpy(auth->u1_cid_ed, cid_ed, ED25519_PUBKEY_LEN);
+ memcpy(auth->u1_sid_ed, sid_ed, ED25519_PUBKEY_LEN);
+ }
+
+ {
+ crypto_digest_t *server_d, *client_d;
+ if (server) {
+ server_d = conn->handshake_state->digest_sent;
+ client_d = conn->handshake_state->digest_received;
+ } else {
+ client_d = conn->handshake_state->digest_sent;
+ server_d = conn->handshake_state->digest_received;
+ }
+
+ /* Server log digest : 32 octets */
+ crypto_digest_get_digest(server_d, (char*)auth->slog, 32);
+
+ /* Client log digest : 32 octets */
+ crypto_digest_get_digest(client_d, (char*)auth->clog, 32);
+ }
+
+ {
+ /* Digest of cert used on TLS link : 32 octets. */
+ tor_x509_cert_t *cert = NULL;
+ if (server) {
+ cert = tor_tls_get_own_cert(conn->tls);
+ } else {
+ cert = tor_tls_get_peer_cert(conn->tls);
+ }
+ if (!cert) {
+ log_warn(LD_OR, "Unable to find cert when making %s data.",
+ authtype_str);
+ goto err;
+ }
+
+ memcpy(auth->scert,
+ tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32);
+
+ tor_x509_cert_free(cert);
+ }
+
+ /* HMAC of clientrandom and serverrandom using master key : 32 octets */
+ if (old_tlssecrets_algorithm) {
+ if (tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets) < 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR, "Somebody asked us for an older TLS "
+ "authentication method (AUTHTYPE_RSA_SHA256_TLSSECRET) "
+ "which we don't support.");
+ }
+ } else {
+ char label[128];
+ tor_snprintf(label, sizeof(label),
+ "EXPORTER FOR TOR TLS CLIENT BINDING %s", authtype_str);
+ int r = tor_tls_export_key_material(conn->tls, auth->tlssecrets,
+ auth->cid, sizeof(auth->cid),
+ label);
+ if (r < 0) {
+ if (r != -2)
+ log_warn(LD_BUG, "TLS key export failed for unknown reason.");
+ // If r == -2, this was openssl bug 7712.
+ goto err;
+ }
+ }
+
+ /* 8 octets were reserved for the current time, but we're trying to get out
+ * of the habit of sending time around willynilly. Fortunately, nothing
+ * checks it. That's followed by 16 bytes of nonce. */
+ crypto_rand((char*)auth->rand, 24);
+
+ ssize_t maxlen = auth1_encoded_len(auth, ctx);
+ if (ed_signing_key && is_ed) {
+ maxlen += ED25519_SIG_LEN;
+ } else if (signing_key && !is_ed) {
+ maxlen += crypto_pk_keysize(signing_key);
+ }
+
+ const int AUTH_CELL_HEADER_LEN = 4; /* 2 bytes of type, 2 bytes of length */
+ result = var_cell_new(AUTH_CELL_HEADER_LEN + maxlen);
+ uint8_t *const out = result->payload + AUTH_CELL_HEADER_LEN;
+ const size_t outlen = maxlen;
+ ssize_t len;
+
+ result->command = CELL_AUTHENTICATE;
+ set_uint16(result->payload, htons(authtype));
+
+ if ((len = auth1_encode(out, outlen, auth, ctx)) < 0) {
+ /* LCOV_EXCL_START */
+ log_warn(LD_BUG, "Unable to encode signed part of AUTH1 data.");
+ goto err;
+ /* LCOV_EXCL_STOP */
+ }
+
+ if (server) {
+ auth1_t *tmp = NULL;
+ ssize_t len2 = auth1_parse(&tmp, out, len, ctx);
+ if (!tmp) {
+ /* LCOV_EXCL_START */
+ log_warn(LD_BUG, "Unable to parse signed part of AUTH1 data that "
+ "we just encoded");
+ goto err;
+ /* LCOV_EXCL_STOP */
+ }
+ result->payload_len = (tmp->end_of_signed - result->payload);
+
+ auth1_free(tmp);
+ if (len2 != len) {
+ /* LCOV_EXCL_START */
+ log_warn(LD_BUG, "Mismatched length when re-parsing AUTH1 data.");
+ goto err;
+ /* LCOV_EXCL_STOP */
+ }
+ goto done;
+ }
+
+ if (ed_signing_key && is_ed) {
+ ed25519_signature_t sig;
+ if (ed25519_sign(&sig, out, len, ed_signing_key) < 0) {
+ /* LCOV_EXCL_START */
+ log_warn(LD_BUG, "Unable to sign ed25519 authentication data");
+ goto err;
+ /* LCOV_EXCL_STOP */
+ }
+ auth1_setlen_sig(auth, ED25519_SIG_LEN);
+ memcpy(auth1_getarray_sig(auth), sig.sig, ED25519_SIG_LEN);
+
+ } else if (signing_key && !is_ed) {
+ auth1_setlen_sig(auth, crypto_pk_keysize(signing_key));
+
+ char d[32];
+ crypto_digest256(d, (char*)out, len, DIGEST_SHA256);
+ int siglen = crypto_pk_private_sign(signing_key,
+ (char*)auth1_getarray_sig(auth),
+ auth1_getlen_sig(auth),
+ d, 32);
+ if (siglen < 0) {
+ log_warn(LD_OR, "Unable to sign AUTH1 data.");
+ goto err;
+ }
+
+ auth1_setlen_sig(auth, siglen);
+ }
+
+ len = auth1_encode(out, outlen, auth, ctx);
+ if (len < 0) {
+ /* LCOV_EXCL_START */
+ log_warn(LD_BUG, "Unable to encode signed AUTH1 data.");
+ goto err;
+ /* LCOV_EXCL_STOP */
+ }
+ tor_assert(len + AUTH_CELL_HEADER_LEN <= result->payload_len);
+ result->payload_len = len + AUTH_CELL_HEADER_LEN;
+ set_uint16(result->payload+2, htons(len));
+
+ goto done;
+
+ err:
+ var_cell_free(result);
+ result = NULL;
+ done:
+ auth1_free(auth);
+ auth_ctx_free(ctx);
+ return result;
+}
+
+/** Send an AUTHENTICATE cell on the connection <b>conn</b>. Return 0 on
+ * success, -1 on failure */
+MOCK_IMPL(int,
+connection_or_send_authenticate_cell,(or_connection_t *conn, int authtype))
+{
+ var_cell_t *cell;
+ crypto_pk_t *pk = tor_tls_get_my_client_auth_key();
+ /* XXXX make sure we're actually supposed to send this! */
+
+ if (!pk) {
+ log_warn(LD_BUG, "Can't compute authenticate cell: no client auth key");
+ return -1;
+ }
+ if (! authchallenge_type_is_supported(authtype)) {
+ log_warn(LD_BUG, "Tried to send authenticate cell with unknown "
+ "authentication type %d", authtype);
+ return -1;
+ }
+
+ cell = connection_or_compute_authenticate_cell_body(conn,
+ authtype,
+ pk,
+ get_current_auth_keypair(),
+ 0 /* not server */);
+ if (! cell) {
+ log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unable to compute authenticate cell!");
+ return -1;
+ }
+ connection_or_write_var_cell_to_buf(cell, conn);
+ var_cell_free(cell);
+
+ return 0;
+}
diff --git a/src/feature/relay/relay_handshake.h b/src/feature/relay/relay_handshake.h
new file mode 100644
index 0000000000..99a658cbcc
--- /dev/null
+++ b/src/feature/relay/relay_handshake.h
@@ -0,0 +1,90 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file relay_handshake.h
+ * @brief Header for feature/relay/relay_handshake.c
+ **/
+
+#ifndef TOR_CORE_OR_RELAY_HANDSHAKE_H
+#define TOR_CORE_OR_RELAY_HANDSHAKE_H
+
+#ifdef HAVE_MODULE_RELAY
+struct ed25519_keypair_t;
+
+int connection_or_send_certs_cell(or_connection_t *conn);
+int connection_or_send_auth_challenge_cell(or_connection_t *conn);
+
+var_cell_t *connection_or_compute_authenticate_cell_body(
+ or_connection_t *conn,
+ const int authtype,
+ crypto_pk_t *signing_key,
+ const struct ed25519_keypair_t *ed_signing_key,
+ int server);
+
+int authchallenge_type_is_supported(uint16_t challenge_type);
+int authchallenge_type_is_better(uint16_t challenge_type_a,
+ uint16_t challenge_type_b);
+
+MOCK_DECL(int,connection_or_send_authenticate_cell,
+ (or_connection_t *conn, int type));
+
+#ifdef TOR_UNIT_TESTS
+extern int certs_cell_ed25519_disabled_for_testing;
+#endif
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+static inline int
+connection_or_send_certs_cell(or_connection_t *conn)
+{
+ (void)conn;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+static inline int
+connection_or_send_auth_challenge_cell(or_connection_t *conn)
+{
+ (void)conn;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+
+static inline var_cell_t *
+connection_or_compute_authenticate_cell_body(
+ or_connection_t *conn,
+ const int authtype,
+ crypto_pk_t *signing_key,
+ const struct ed25519_keypair_t *ed_signing_key,
+ int server)
+{
+ (void)conn;
+ (void)authtype;
+ (void)signing_key;
+ (void)ed_signing_key;
+ (void)server;
+ tor_assert_nonfatal_unreached();
+ return NULL;
+}
+
+#define authchallenge_type_is_supported(t) (0)
+#define authchallenge_type_is_better(a, b) (0)
+
+static inline int
+connection_or_send_authenticate_cell(or_connection_t *conn, int type)
+{
+ (void)conn;
+ (void)type;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+
+#ifdef TOR_UNIT_TESTS
+extern int certs_cell_ed25519_disabled_for_testing;
+#endif
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
+#endif /* !defined(TOR_CORE_OR_RELAY_HANDSHAKE_H) */
diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h
index 782609d8ab..2e07df2e88 100644
--- a/src/feature/relay/router.h
+++ b/src/feature/relay/router.h
@@ -117,7 +117,6 @@ const char *routerinfo_err_to_string(int err);
int routerinfo_err_is_transient(int err);
void router_reset_warnings(void);
-void router_reset_reachability(void);
void router_free_all(void);
#ifdef ROUTER_PRIVATE
diff --git a/src/feature/relay/routerkeys.h b/src/feature/relay/routerkeys.h
index c2475f195f..2b5f03a2a3 100644
--- a/src/feature/relay/routerkeys.h
+++ b/src/feature/relay/routerkeys.h
@@ -11,6 +11,8 @@
#include "lib/crypt_ops/crypto_ed25519.h"
+#ifdef HAVE_MODULE_RELAY
+
const ed25519_public_key_t *get_master_identity_key(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));
@@ -24,6 +26,7 @@ void get_master_rsa_crosscert(const uint8_t **cert_out,
int router_ed25519_id_is_me(const ed25519_public_key_t *id);
+/* These are only used by router.c */
struct tor_cert_st *make_ntor_onion_key_crosscert(
const curve25519_keypair_t *onion_key,
const ed25519_public_key_t *master_id_key,
@@ -42,6 +45,85 @@ int generate_ed_link_cert(const or_options_t *options, time_t now, int force);
void routerkeys_free_all(void);
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+#define router_ed25519_id_is_me(id) \
+ ((void)(id), 0)
+
+static inline void *
+relay_key_is_unavailable_(void)
+{
+ tor_assert_nonfatal_unreached();
+ return NULL;
+}
+#define relay_key_is_unavailable(type) \
+ ((type)(relay_key_is_unavailable_()))
+
+// Many of these can be removed once relay_handshake.c is relay-only.
+#define get_current_auth_keypair() \
+ relay_key_is_unavailable(const ed25519_keypair_t *)
+#define get_master_signing_keypair() \
+ relay_key_is_unavailable(const ed25519_keypair_t *)
+#define get_current_link_cert_cert() \
+ relay_key_is_unavailable(const struct tor_cert_st *)
+#define get_current_auth_key_cert() \
+ relay_key_is_unavailable(const struct tor_cert_st *)
+#define get_master_signing_key_cert() \
+ relay_key_is_unavailable(const struct tor_cert_st *)
+#define get_master_rsa_crosscert(cert_out, size_out) \
+ STMT_BEGIN \
+ tor_assert_nonfatal_unreached(); \
+ *(cert_out) = NULL; \
+ *(size_out) = 0; \
+ STMT_END
+#define get_master_identity_key() \
+ relay_key_is_unavailable(const ed25519_public_key_t *)
+
+#define generate_ed_link_cert(options, now, force) \
+ ((void)(options), (void)(now), (void)(force), 0)
+#define should_make_new_ed_keys(options, now) \
+ ((void)(options), (void)(now), 0)
+
+// These can get removed once router.c becomes relay-only.
+static inline struct tor_cert_st *
+make_ntor_onion_key_crosscert(const curve25519_keypair_t *onion_key,
+ const ed25519_public_key_t *master_id_key,
+ time_t now, time_t lifetime,
+ int *sign_out)
+{
+ (void)onion_key;
+ (void)master_id_key;
+ (void)now;
+ (void)lifetime;
+ (void)sign_out;
+ tor_assert_nonfatal_unreached();
+ return NULL;
+}
+static inline uint8_t *
+make_tap_onion_key_crosscert(const crypto_pk_t *onion_key,
+ const ed25519_public_key_t *master_id_key,
+ const crypto_pk_t *rsa_id_key,
+ int *len_out)
+{
+ (void)onion_key;
+ (void)master_id_key;
+ (void)rsa_id_key;
+ (void)len_out;
+ tor_assert_nonfatal_unreached();
+ return NULL;
+}
+
+/* This calls is used outside of relay mode, but only to implement
+ * CMD_KEY_EXPIRATION */
+#define log_cert_expiration() \
+ (puts("Not available: Tor has been compiled without relay support"), 0)
+/* This calls is used outside of relay mode, but only to implement
+ * CMD_KEYGEN. */
+#define load_ed_keys(x,y) \
+ (puts("Not available: Tor has been compiled without relay support"), 0)
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
#ifdef TOR_UNIT_TESTS
const ed25519_keypair_t *get_master_identity_keypair(void);
void init_mock_ed_keys(const crypto_pk_t *rsa_identity_key);
diff --git a/src/feature/relay/selftest.h b/src/feature/relay/selftest.h
index 94f305f203..f3dd698bb7 100644
--- a/src/feature/relay/selftest.h
+++ b/src/feature/relay/selftest.h
@@ -12,6 +12,7 @@
#ifndef TOR_SELFTEST_H
#define TOR_SELFTEST_H
+#ifdef HAVE_MODULE_RELAY
struct or_options_t;
int check_whether_orport_reachable(const struct or_options_t *options);
int check_whether_dirport_reachable(const struct or_options_t *options);
@@ -20,5 +21,37 @@ void router_do_reachability_checks(int test_or, int test_dir);
void router_orport_found_reachable(void);
void router_dirport_found_reachable(void);
void router_perform_bandwidth_test(int num_circs, time_t now);
+void router_reset_reachability(void);
+
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+#define check_whether_orport_reachable(opts) \
+ ((void)(opts), 0)
+#define check_whether_dirport_reachable(opts) \
+ ((void)(opts), 0)
+
+#define router_orport_found_reachable() \
+ STMT_NIL
+#define router_dirport_found_reachable() \
+ STMT_NIL
+#define router_reset_reachability() \
+ STMT_NIL
+
+static inline void
+router_do_reachability_checks(int test_or, int test_dir)
+{
+ (void)test_or;
+ (void)test_dir;
+ tor_assert_nonfatal_unreached();
+}
+static inline void
+router_perform_bandwidth_test(int num_circs, time_t now)
+{
+ (void)num_circs;
+ (void)now;
+ tor_assert_nonfatal_unreached();
+}
+
+#endif /* defined(HAVE_MODULE_RELAY) */
#endif /* !defined(TOR_SELFTEST_H) */
diff --git a/src/feature/stats/geoip_stats.c b/src/feature/stats/geoip_stats.c
index 3228b18973..f9a2f19d2e 100644
--- a/src/feature/stats/geoip_stats.c
+++ b/src/feature/stats/geoip_stats.c
@@ -146,9 +146,9 @@ clientmap_entries_eq(const clientmap_entry_t *a, const clientmap_entry_t *b)
}
HT_PROTOTYPE(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
- clientmap_entries_eq)
+ clientmap_entries_eq);
HT_GENERATE2(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
- clientmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
+ clientmap_entries_eq, 0.6, tor_reallocarray_, tor_free_);
#define clientmap_entry_free(ent) \
FREE_AND_NULL(clientmap_entry_t, clientmap_entry_free_, ent)
@@ -484,9 +484,9 @@ dirreq_map_ent_hash(const dirreq_map_entry_t *entry)
}
HT_PROTOTYPE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash,
- dirreq_map_ent_eq)
+ dirreq_map_ent_eq);
HT_GENERATE2(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash,
- dirreq_map_ent_eq, 0.6, tor_reallocarray_, tor_free_)
+ dirreq_map_ent_eq, 0.6, tor_reallocarray_, tor_free_);
/** Helper: Put <b>entry</b> into map of directory requests using
* <b>type</b> and <b>dirreq_id</b> as key parts. If there is
diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c
index d229c755b4..71e2e00086 100644
--- a/src/feature/stats/rephist.c
+++ b/src/feature/stats/rephist.c
@@ -2285,9 +2285,9 @@ bidi_map_ent_hash(const bidi_map_entry_t *entry)
}
HT_PROTOTYPE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
- bidi_map_ent_eq)
+ bidi_map_ent_eq);
HT_GENERATE2(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
- bidi_map_ent_eq, 0.6, tor_reallocarray_, tor_free_)
+ bidi_map_ent_eq, 0.6, tor_reallocarray_, tor_free_);
/* DOCDOC bidi_map_free */
static void
diff --git a/src/include.am b/src/include.am
index f5f868d23f..657f6e823a 100644
--- a/src/include.am
+++ b/src/include.am
@@ -19,6 +19,7 @@ include src/lib/fs/include.am
include src/lib/geoip/include.am
include src/lib/include.libdonna.am
include src/lib/intmath/include.am
+include src/lib/llharden/include.am
include src/lib/lock/include.am
include src/lib/log/include.am
include src/lib/math/include.am
diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h
index 1bb8c54a0c..e4b0ea61ca 100644
--- a/src/lib/cc/compat_compiler.h
+++ b/src/lib/cc/compat_compiler.h
@@ -25,11 +25,11 @@
#endif /* defined(__has_feature) */
#ifndef NULL_REP_IS_ZERO_BYTES
-#error "It seems your platform does not represent NULL as zero. We can't cope."
+#error "Your platform does not represent NULL as zero. We can't cope."
#endif
#ifndef DOUBLE_0_REP_IS_ZERO_BYTES
-#error "It seems your platform does not represent 0.0 as zeros. We can't cope."
+#error "Your platform does not represent 0.0 as zeros. We can't cope."
#endif
#if 'a'!=97 || 'z'!=122 || 'A'!=65 || ' '!=32
diff --git a/src/lib/cc/torint.h b/src/lib/cc/torint.h
index cef1482bdc..af7a90431c 100644
--- a/src/lib/cc/torint.h
+++ b/src/lib/cc/torint.h
@@ -49,7 +49,7 @@ typedef int32_t ssize_t;
* aren't 2's complement, and you don't define LONG_MAX, then you're so
* bizarre that I want nothing to do with you. */
#ifndef USING_TWOS_COMPLEMENT
-#error "Seems that your platform doesn't use 2's complement arithmetic. Argh."
+#error "Your platform doesn't use 2's complement arithmetic."
#endif
#ifndef TIME_MAX
@@ -126,12 +126,11 @@ typedef int32_t ssize_t;
#define SIZE_T_CEILING ((size_t)(SSIZE_MAX-16))
#if SIZEOF_INT > SIZEOF_VOID_P
-#error "sizeof(int) > sizeof(void *) - Tor cannot be built on this platform!"
+#error "sizeof(int) > sizeof(void *) - Can't build Tor here."
#endif
#if SIZEOF_UNSIGNED_INT > SIZEOF_VOID_P
-#error "sizeof(unsigned int) > sizeof(void *) - Tor cannot be built on this \
-platform!"
+#error "sizeof(unsigned int) > sizeof(void *) - Can't build Tor here."
#endif
#endif /* !defined(TOR_TORINT_H) */
diff --git a/src/lib/compress/compress.c b/src/lib/compress/compress.c
index c62d7d5d2a..84e9601920 100644
--- a/src/lib/compress/compress.c
+++ b/src/lib/compress/compress.c
@@ -695,6 +695,6 @@ subsys_compress_initialize(void)
const subsys_fns_t sys_compress = {
.name = "compress",
.supported = true,
- .level = -70,
+ .level = -55,
.initialize = subsys_compress_initialize,
};
diff --git a/src/lib/conf/conftypes.h b/src/lib/conf/conftypes.h
index ebc2736aaa..081ebf397f 100644
--- a/src/lib/conf/conftypes.h
+++ b/src/lib/conf/conftypes.h
@@ -260,6 +260,7 @@ typedef struct config_deprecation_t {
const char *why_deprecated;
} config_deprecation_t;
+#ifndef COCCI
/**
* Handy macro for declaring "In the config file or on the command line, you
* can abbreviate <b>tok</b>s as <b>tok</b>". Used inside an array of
@@ -268,7 +269,8 @@ typedef struct config_deprecation_t {
* For example, to declare "NumCpu" as an abbreviation for "NumCPUs",
* you can say PLURAL(NumCpu).
**/
-#define PLURAL(tok) { #tok, #tok "s", 0, 0 }
+#define PLURAL(tok) { (#tok), (#tok "s"), 0, 0 }
+#endif /* !defined(COCCI) */
/**
* Validation function: verify whether a configuation object is well-formed
diff --git a/src/lib/confmgt/unitparse.c b/src/lib/confmgt/unitparse.c
index 61edc60694..99716e8d9d 100644
--- a/src/lib/confmgt/unitparse.c
+++ b/src/lib/confmgt/unitparse.c
@@ -23,6 +23,7 @@
/** Table to map the names of memory units to the number of bytes they
* contain. */
+// clang-format off
const struct unit_table_t memory_units[] = {
{ "", 1 },
{ "b", 1<< 0 },
@@ -67,9 +68,11 @@ const struct unit_table_t memory_units[] = {
{ "tbit", UINT64_C(1)<<37 },
{ NULL, 0 },
};
+// clang-format on
/** Table to map the names of time units to the number of seconds they
* contain. */
+// clang-format off
const struct unit_table_t time_units[] = {
{ "", 1 },
{ "second", 1 },
@@ -86,9 +89,11 @@ const struct unit_table_t time_units[] = {
{ "months", 2629728, },
{ NULL, 0 },
};
+// clang-format on
/** Table to map the names of time units to the number of milliseconds
* they contain. */
+// clang-format off
const struct unit_table_t time_msec_units[] = {
{ "", 1 },
{ "msec", 1 },
@@ -106,6 +111,7 @@ const struct unit_table_t time_msec_units[] = {
{ "weeks", 7*24*60*60*1000 },
{ NULL, 0 },
};
+// clang-format on
/** Parse a string <b>val</b> containing a number, zero or more
* spaces, and an optional unit string. If the unit appears in the
diff --git a/src/lib/container/map.c b/src/lib/container/map.c
index c3fb0b5c8a..7db84313ea 100644
--- a/src/lib/container/map.c
+++ b/src/lib/container/map.c
@@ -85,21 +85,21 @@ digest256map_entry_hash(const digest256map_entry_t *a)
}
HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
- strmap_entries_eq)
+ strmap_entries_eq);
HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
- strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
+ strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_);
HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
- digestmap_entries_eq)
+ digestmap_entries_eq);
HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
- digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
+ digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_);
HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node,
digest256map_entry_hash,
- digest256map_entries_eq)
+ digest256map_entries_eq);
HT_GENERATE2(digest256map_impl, digest256map_entry_t, node,
digest256map_entry_hash,
- digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_)
+ digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_);
#define strmap_entry_free(ent) \
FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent))
diff --git a/src/lib/container/map.h b/src/lib/container/map.h
index 989ecfad80..dbc1967247 100644
--- a/src/lib/container/map.h
+++ b/src/lib/container/map.h
@@ -19,29 +19,29 @@
#define DECLARE_MAP_FNS(mapname_t, keytype, prefix) \
typedef struct mapname_t mapname_t; \
- typedef struct prefix##entry_t *prefix##iter_t; \
- MOCK_DECL(mapname_t*, prefix##new, (void)); \
- void* prefix##set(mapname_t *map, keytype key, void *val); \
- void* prefix##get(const mapname_t *map, keytype key); \
- void* prefix##remove(mapname_t *map, keytype key); \
- MOCK_DECL(void, prefix##free_, (mapname_t *map, void (*free_val)(void*))); \
- int prefix##isempty(const mapname_t *map); \
- int prefix##size(const mapname_t *map); \
- prefix##iter_t *prefix##iter_init(mapname_t *map); \
- prefix##iter_t *prefix##iter_next(mapname_t *map, prefix##iter_t *iter); \
- prefix##iter_t *prefix##iter_next_rmv(mapname_t *map, \
- prefix##iter_t *iter); \
- void prefix##iter_get(prefix##iter_t *iter, keytype *keyp, void **valp); \
- int prefix##iter_done(prefix##iter_t *iter); \
- void prefix##assert_ok(const mapname_t *map)
+ typedef struct prefix##_entry_t *prefix##_iter_t; \
+ MOCK_DECL(mapname_t*, prefix##_new, (void)); \
+ void* prefix##_set(mapname_t *map, keytype key, void *val); \
+ void* prefix##_get(const mapname_t *map, keytype key); \
+ void* prefix##_remove(mapname_t *map, keytype key); \
+ MOCK_DECL(void, prefix##_free_, (mapname_t *map, void (*free_val)(void*))); \
+ int prefix##_isempty(const mapname_t *map); \
+ int prefix##_size(const mapname_t *map); \
+ prefix##_iter_t *prefix##_iter_init(mapname_t *map); \
+ prefix##_iter_t *prefix##_iter_next(mapname_t *map, prefix##_iter_t *iter); \
+ prefix##_iter_t *prefix##_iter_next_rmv(mapname_t *map, \
+ prefix##_iter_t *iter); \
+ void prefix##_iter_get(prefix##_iter_t *iter, keytype *keyp, void **valp); \
+ int prefix##_iter_done(prefix##_iter_t *iter); \
+ void prefix##_assert_ok(const mapname_t *map)
/* Map from const char * to void *. Implemented with a hash table. */
-DECLARE_MAP_FNS(strmap_t, const char *, strmap_);
+DECLARE_MAP_FNS(strmap_t, const char *, strmap);
/* Map from const char[DIGEST_LEN] to void *. Implemented with a hash table. */
-DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_);
+DECLARE_MAP_FNS(digestmap_t, const char *, digestmap);
/* Map from const uint8_t[DIGEST256_LEN] to void *. Implemented with a hash
* table. */
-DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
+DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map);
#define MAP_FREE_AND_NULL(mapname_t, map, fn) \
do { \
@@ -56,12 +56,12 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
#undef DECLARE_MAP_FNS
/** Iterates over the key-value pairs in a map <b>map</b> in order.
- * <b>prefix</b> is as for DECLARE_MAP_FNS (i.e., strmap_ or digestmap_).
+ * <b>prefix</b> is as for DECLARE_MAP_FNS (i.e., strmap or digestmap).
* The map's keys and values are of type keytype and valtype respectively;
* each iteration assigns them to keyvar and valvar.
*
* Example use:
- * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) {
+ * MAP_FOREACH(digestmap, m, const char *, k, routerinfo_t *, r) {
* // use k and r
* } MAP_FOREACH_END.
*/
@@ -81,21 +81,21 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
*/
#define MAP_FOREACH(prefix, map, keytype, keyvar, valtype, valvar) \
STMT_BEGIN \
- prefix##iter_t *keyvar##_iter; \
- for (keyvar##_iter = prefix##iter_init(map); \
- !prefix##iter_done(keyvar##_iter); \
- keyvar##_iter = prefix##iter_next(map, keyvar##_iter)) { \
+ prefix##_iter_t *keyvar##_iter; \
+ for (keyvar##_iter = prefix##_iter_init(map); \
+ !prefix##_iter_done(keyvar##_iter); \
+ keyvar##_iter = prefix##_iter_next(map, keyvar##_iter)) { \
keytype keyvar; \
void *valvar##_voidp; \
valtype valvar; \
- prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \
+ prefix##_iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \
valvar = valvar##_voidp;
/** As MAP_FOREACH, except allows members to be removed from the map
* during the iteration via MAP_DEL_CURRENT. Example use:
*
* Example use:
- * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) {
+ * MAP_FOREACH(digestmap, m, const char *, k, routerinfo_t *, r) {
* if (is_very_old(r))
* MAP_DEL_CURRENT(k);
* } MAP_FOREACH_END.
@@ -121,18 +121,18 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
*/
#define MAP_FOREACH_MODIFY(prefix, map, keytype, keyvar, valtype, valvar) \
STMT_BEGIN \
- prefix##iter_t *keyvar##_iter; \
+ prefix##_iter_t *keyvar##_iter; \
int keyvar##_del=0; \
- for (keyvar##_iter = prefix##iter_init(map); \
- !prefix##iter_done(keyvar##_iter); \
+ for (keyvar##_iter = prefix##_iter_init(map); \
+ !prefix##_iter_done(keyvar##_iter); \
keyvar##_iter = keyvar##_del ? \
- prefix##iter_next_rmv(map, keyvar##_iter) : \
- prefix##iter_next(map, keyvar##_iter)) { \
+ prefix##_iter_next_rmv(map, keyvar##_iter) : \
+ prefix##_iter_next(map, keyvar##_iter)) { \
keytype keyvar; \
void *valvar##_voidp; \
valtype valvar; \
keyvar##_del=0; \
- prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \
+ prefix##_iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \
valvar = valvar##_voidp;
/** Used with MAP_FOREACH_MODIFY to remove the currently-iterated-upon
@@ -152,7 +152,7 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
* } DIGESTMAP_FOREACH_END.
*/
#define DIGESTMAP_FOREACH(map, keyvar, valtype, valvar) \
- MAP_FOREACH(digestmap_, map, const char *, keyvar, valtype, valvar)
+ MAP_FOREACH(digestmap, map, const char *, keyvar, valtype, valvar)
/** As MAP_FOREACH_MODIFY, but does not require declaration of prefix or
* keytype.
@@ -163,21 +163,21 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
* } DIGESTMAP_FOREACH_END.
*/
#define DIGESTMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \
- MAP_FOREACH_MODIFY(digestmap_, map, const char *, keyvar, valtype, valvar)
+ MAP_FOREACH_MODIFY(digestmap, map, const char *, keyvar, valtype, valvar)
/** Used to end a DIGESTMAP_FOREACH() block. */
#define DIGESTMAP_FOREACH_END MAP_FOREACH_END
#define DIGEST256MAP_FOREACH(map, keyvar, valtype, valvar) \
- MAP_FOREACH(digest256map_, map, const uint8_t *, keyvar, valtype, valvar)
+ MAP_FOREACH(digest256map, map, const uint8_t *, keyvar, valtype, valvar)
#define DIGEST256MAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \
- MAP_FOREACH_MODIFY(digest256map_, map, const uint8_t *, \
+ MAP_FOREACH_MODIFY(digest256map, map, const uint8_t *, \
keyvar, valtype, valvar)
#define DIGEST256MAP_FOREACH_END MAP_FOREACH_END
#define STRMAP_FOREACH(map, keyvar, valtype, valvar) \
- MAP_FOREACH(strmap_, map, const char *, keyvar, valtype, valvar)
+ MAP_FOREACH(strmap, map, const char *, keyvar, valtype, valvar)
#define STRMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \
- MAP_FOREACH_MODIFY(strmap_, map, const char *, keyvar, valtype, valvar)
+ MAP_FOREACH_MODIFY(strmap, map, const char *, keyvar, valtype, valvar)
#define STRMAP_FOREACH_END MAP_FOREACH_END
void* strmap_set_lc(strmap_t *map, const char *key, void *val);
@@ -186,66 +186,66 @@ void* strmap_remove_lc(strmap_t *map, const char *key);
#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, mapname_t, valtype) \
typedef struct mapname_t mapname_t; \
- typedef struct prefix##iter_t *prefix##iter_t; \
+ typedef struct prefix##_iter_t *prefix##_iter_t; \
ATTR_UNUSED static inline mapname_t* \
- prefix##new(void) \
+ prefix##_new(void) \
{ \
return (mapname_t*)digestmap_new(); \
} \
ATTR_UNUSED static inline digestmap_t* \
- prefix##to_digestmap(mapname_t *map) \
+ prefix##_to_digestmap(mapname_t *map) \
{ \
return (digestmap_t*)map; \
} \
ATTR_UNUSED static inline valtype* \
- prefix##get(mapname_t *map, const char *key) \
+ prefix##_get(mapname_t *map, const char *key) \
{ \
return (valtype*)digestmap_get((digestmap_t*)map, key); \
} \
ATTR_UNUSED static inline valtype* \
- prefix##set(mapname_t *map, const char *key, valtype *val) \
+ prefix##_set(mapname_t *map, const char *key, valtype *val) \
{ \
return (valtype*)digestmap_set((digestmap_t*)map, key, val); \
} \
ATTR_UNUSED static inline valtype* \
- prefix##remove(mapname_t *map, const char *key) \
+ prefix##_remove(mapname_t *map, const char *key) \
{ \
return (valtype*)digestmap_remove((digestmap_t*)map, key); \
} \
ATTR_UNUSED static inline void \
- prefix##f##ree_(mapname_t *map, void (*free_val)(void*)) \
+ prefix##_f##ree_(mapname_t *map, void (*free_val)(void*)) \
{ \
digestmap_free_((digestmap_t*)map, free_val); \
} \
ATTR_UNUSED static inline int \
- prefix##isempty(mapname_t *map) \
+ prefix##_isempty(mapname_t *map) \
{ \
return digestmap_isempty((digestmap_t*)map); \
} \
ATTR_UNUSED static inline int \
- prefix##size(mapname_t *map) \
+ prefix##_size(mapname_t *map) \
{ \
return digestmap_size((digestmap_t*)map); \
} \
ATTR_UNUSED static inline \
- prefix##iter_t *prefix##iter_init(mapname_t *map) \
+ prefix##_iter_t *prefix##_iter_init(mapname_t *map) \
{ \
- return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map); \
+ return (prefix##_iter_t*) digestmap_iter_init((digestmap_t*)map); \
} \
ATTR_UNUSED static inline \
- prefix##iter_t *prefix##iter_next(mapname_t *map, prefix##iter_t *iter) \
+ prefix##_iter_t *prefix##_iter_next(mapname_t *map, prefix##_iter_t *iter) \
{ \
- return (prefix##iter_t*) digestmap_iter_next( \
+ return (prefix##_iter_t*) digestmap_iter_next( \
(digestmap_t*)map, (digestmap_iter_t*)iter); \
} \
- ATTR_UNUSED static inline prefix##iter_t* \
- prefix##iter_next_rmv(mapname_t *map, prefix##iter_t *iter) \
+ ATTR_UNUSED static inline prefix##_iter_t* \
+ prefix##_iter_next_rmv(mapname_t *map, prefix##_iter_t *iter) \
{ \
- return (prefix##iter_t*) digestmap_iter_next_rmv( \
+ return (prefix##_iter_t*) digestmap_iter_next_rmv( \
(digestmap_t*)map, (digestmap_iter_t*)iter); \
} \
ATTR_UNUSED static inline void \
- prefix##iter_get(prefix##iter_t *iter, \
+ prefix##_iter_get(prefix##_iter_t *iter, \
const char **keyp, \
valtype **valp) \
{ \
@@ -254,7 +254,7 @@ void* strmap_remove_lc(strmap_t *map, const char *key);
*valp = v; \
} \
ATTR_UNUSED static inline int \
- prefix##iter_done(prefix##iter_t *iter) \
+ prefix##_iter_done(prefix##_iter_t *iter) \
{ \
return digestmap_iter_done((digestmap_iter_t*)iter); \
}
diff --git a/src/lib/container/namemap.c b/src/lib/container/namemap.c
index 28695ee3a1..e286cad947 100644
--- a/src/lib/container/namemap.c
+++ b/src/lib/container/namemap.c
@@ -35,9 +35,9 @@ mapped_name_hash(const mapped_name_t *a)
}
HT_PROTOTYPE(namemap_ht, mapped_name_t, node, mapped_name_hash,
- mapped_name_eq)
+ mapped_name_eq);
HT_GENERATE2(namemap_ht, mapped_name_t, node, mapped_name_hash,
- mapped_name_eq, 0.6, tor_reallocarray_, tor_free_)
+ mapped_name_eq, 0.6, tor_reallocarray_, tor_free_);
/** Set up an uninitialized <b>map</b>. */
void
diff --git a/src/lib/ctime/di_ops.c b/src/lib/ctime/di_ops.c
index 7448a9973e..d57d286990 100644
--- a/src/lib/ctime/di_ops.c
+++ b/src/lib/ctime/di_ops.c
@@ -72,10 +72,10 @@ tor_memcmp(const void *a, const void *b, size_t len)
* actually implementation-defined in standard C. So how do we
* get away with assuming it? Easy. We check.) */
#if ((-60 >> 8) != -1)
-#error "According to cpp, right-shift doesn't perform sign-extension."
+#error "cpp says right-shift doesn't perform sign-extension."
#endif
#ifndef RSHIFT_DOES_SIGN_EXTEND
-#error "According to configure, right-shift doesn't perform sign-extension."
+#error "configure says right-shift doesn't perform sign-extension."
#endif
/* If v1 == v2, equal_p is ~0, so this will leave retval
@@ -279,3 +279,30 @@ select_array_member_cumulative_timei(const uint64_t *entries, int n_entries,
return i_chosen;
}
+
+/**
+ * If <b>s</b> is true, then copy <b>n</b> bytes from <b>src</b> to
+ * <b>dest</b>. Otherwise leave <b>dest</b> alone.
+ *
+ * This function behaves the same as
+ *
+ * if (s)
+ * memcpy(dest, src, n);
+ *
+ * except that it tries to run in the same amount of time whether <b>s</b> is
+ * true or not.
+ **/
+void
+memcpy_if_true_timei(bool s, void *dest, const void *src, size_t n)
+{
+ // If s is true, mask will be ~0. If s is false, mask will be 0.
+ const char mask = (char) -(signed char)s;
+
+ char *destp = dest;
+ const char *srcp = src;
+ for (size_t i = 0; i < n; ++i) {
+ *destp = (*destp & ~mask) | (*srcp & mask);
+ ++destp;
+ ++srcp;
+ }
+}
diff --git a/src/lib/ctime/di_ops.h b/src/lib/ctime/di_ops.h
index 4ff8f03165..9fe2884ecc 100644
--- a/src/lib/ctime/di_ops.h
+++ b/src/lib/ctime/di_ops.h
@@ -73,4 +73,6 @@ int select_array_member_cumulative_timei(const uint64_t *entries,
int n_entries,
uint64_t total, uint64_t rand_val);
+void memcpy_if_true_timei(bool s, void *dest, const void *src, size_t n);
+
#endif /* !defined(TOR_DI_OPS_H) */
diff --git a/src/lib/err/torerr.c b/src/lib/err/torerr.c
index 92ef80e56a..2de75c0be4 100644
--- a/src/lib/err/torerr.c
+++ b/src/lib/err/torerr.c
@@ -151,29 +151,27 @@ tor_log_reset_sigsafe_err_fds(void)
}
/**
- * Close the list of fds that get errors from inside a signal handler or
+ * Flush the list of fds that get errors from inside a signal handler or
* other emergency condition. These fds are shared with the logging code:
- * closing them flushes the log buffers, and prevents any further logging.
+ * flushing them also flushes the log buffers.
*
- * This function closes stderr, so it should only be called immediately before
- * process shutdown.
+ * This function is safe to call during signal handlers.
*/
void
-tor_log_close_sigsafe_err_fds(void)
+tor_log_flush_sigsafe_err_fds(void)
{
+ /* If we don't have fsync() in unistd.h, we can't flush the logs. */
+#ifdef HAVE_FSYNC
int n_fds, i;
const int *fds = NULL;
n_fds = tor_log_get_sigsafe_err_fds(&fds);
for (i = 0; i < n_fds; ++i) {
- /* tor_log_close_sigsafe_err_fds_on_error() is called on error and on
- * shutdown, so we can't log or take any useful action if close()
- * fails. */
- (void)close(fds[i]);
+ /* This function is called on error and on shutdown, so we don't log, or
+ * take any other action, if fsync() fails. */
+ (void)fsync(fds[i]);
}
-
- /* Don't even try logging, we've closed all the log fds. */
- tor_log_set_sigsafe_err_fds(NULL, 0);
+#endif /* defined(HAVE_FSYNC) */
}
/**
@@ -217,13 +215,13 @@ tor_raw_assertion_failed_msg_(const char *file, int line, const char *expr,
/**
* Call the abort() function to kill the current process with a fatal
- * error. But first, close the raw error file descriptors, so error messages
+ * error. But first, flush the raw error file descriptors, so error messages
* are written before process termination.
**/
void
tor_raw_abort_(void)
{
- tor_log_close_sigsafe_err_fds();
+ tor_log_flush_sigsafe_err_fds();
abort();
}
diff --git a/src/lib/err/torerr.h b/src/lib/err/torerr.h
index f5b36eef9c..ce1b049c47 100644
--- a/src/lib/err/torerr.h
+++ b/src/lib/err/torerr.h
@@ -40,7 +40,7 @@ void tor_log_err_sigsafe(const char *m, ...);
int tor_log_get_sigsafe_err_fds(const int **out);
void tor_log_set_sigsafe_err_fds(const int *fds, int n);
void tor_log_reset_sigsafe_err_fds(void);
-void tor_log_close_sigsafe_err_fds(void);
+void tor_log_flush_sigsafe_err_fds(void);
void tor_log_sigsafe_err_set_granularity(int ms);
void tor_raw_abort_(void) ATTR_NORETURN;
diff --git a/src/lib/err/torerr_sys.c b/src/lib/err/torerr_sys.c
index aa49ba36bd..46fc853550 100644
--- a/src/lib/err/torerr_sys.c
+++ b/src/lib/err/torerr_sys.c
@@ -27,11 +27,9 @@ subsys_torerr_initialize(void)
static void
subsys_torerr_shutdown(void)
{
- /* Stop handling signals with backtraces, then close the logs. */
+ /* Stop handling signals with backtraces, then flush the logs. */
clean_up_backtrace_handler();
- /* We can't log any log messages after this point: we've closed all the log
- * fds, including stdio. */
- tor_log_close_sigsafe_err_fds();
+ tor_log_flush_sigsafe_err_fds();
}
const subsys_fns_t sys_torerr = {
diff --git a/src/lib/llharden/.may_include b/src/lib/llharden/.may_include
new file mode 100644
index 0000000000..038237dadf
--- /dev/null
+++ b/src/lib/llharden/.may_include
@@ -0,0 +1,3 @@
+lib/llharden/*.h
+lib/subsys/*.h
+orconfig.h
diff --git a/src/lib/llharden/include.am b/src/lib/llharden/include.am
new file mode 100644
index 0000000000..0a4788c7dc
--- /dev/null
+++ b/src/lib/llharden/include.am
@@ -0,0 +1,19 @@
+
+noinst_LIBRARIES += src/lib/libtor-llharden.a
+
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += src/lib/libtor-llharden-testing.a
+endif
+
+# ADD_C_FILE: INSERT SOURCES HERE.
+src_lib_libtor_llharden_a_SOURCES = \
+ src/lib/llharden/winprocess_sys.c
+
+src_lib_libtor_llharden_testing_a_SOURCES = \
+ $(src_lib_libtor_llharden_a_SOURCES)
+src_lib_libtor_llharden_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
+src_lib_libtor_llharden_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
+# ADD_C_FILE: INSERT HEADERS HERE.
+noinst_HEADERS += \
+ src/lib/llharden/winprocess_sys.h
diff --git a/src/lib/llharden/lib_llharden.md b/src/lib/llharden/lib_llharden.md
new file mode 100644
index 0000000000..69e9af5327
--- /dev/null
+++ b/src/lib/llharden/lib_llharden.md
@@ -0,0 +1,6 @@
+@dir /lib/llharden
+@brief lib/llharden: low-level unconditional process hardening
+
+This module contains process hardening code that we want to run before any
+other code, including configuration. It needs to be self-contained, since
+nothing else will be initialized at this point.
diff --git a/src/lib/process/winprocess_sys.c b/src/lib/llharden/winprocess_sys.c
index e43a77e467..a5f22c182b 100644
--- a/src/lib/process/winprocess_sys.c
+++ b/src/lib/llharden/winprocess_sys.c
@@ -8,7 +8,7 @@
#include "orconfig.h"
#include "lib/subsys/subsys.h"
-#include "lib/process/winprocess_sys.h"
+#include "lib/llharden/winprocess_sys.h"
#include <stdbool.h>
#include <stddef.h>
diff --git a/src/lib/process/winprocess_sys.h b/src/lib/llharden/winprocess_sys.h
index bece1b3da9..bece1b3da9 100644
--- a/src/lib/process/winprocess_sys.h
+++ b/src/lib/llharden/winprocess_sys.h
diff --git a/src/lib/log/log.c b/src/lib/log/log.c
index 75f8f79da2..9ee87c0668 100644
--- a/src/lib/log/log.c
+++ b/src/lib/log/log.c
@@ -523,7 +523,7 @@ logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len,
* pass them, and some very old ones do not detect overflow so well.
* Regrettably, they call their maximum line length MAXLINE. */
#if MAXLINE < 64
-#warning "MAXLINE is a very low number; it might not be from syslog.h."
+#warning "MAXLINE is very low; it might not be from syslog.h."
#endif
char *m = msg_after_prefix;
if (msg_len >= MAXLINE)
@@ -665,24 +665,15 @@ tor_log_update_sigsafe_err_fds(void)
const logfile_t *lf;
int found_real_stderr = 0;
- /* log_fds and err_fds contain matching entries: log_fds are the fds used by
- * the log module, and err_fds are the fds used by the err module.
- * For stdio logs, the log_fd and err_fd values are identical,
- * and the err module closes the fd on shutdown.
- * For file logs, the err_fd is a dup() of the log_fd,
- * and the log and err modules both close their respective fds on shutdown.
- * (Once all fds representing a file are closed, the underlying file is
- * closed.)
- */
- int log_fds[TOR_SIGSAFE_LOG_MAX_FDS];
- int err_fds[TOR_SIGSAFE_LOG_MAX_FDS];
+ /* The fds are the file descriptors of tor's stdout, stderr, and file
+ * logs. The log and err modules flush these fds during their shutdowns. */
+ int fds[TOR_SIGSAFE_LOG_MAX_FDS];
int n_fds;
LOCK_LOGS();
/* Reserve the first one for stderr. This is safe because when we daemonize,
- * we dup2 /dev/null to stderr.
- * For stderr, log_fds and err_fds are the same. */
- log_fds[0] = err_fds[0] = STDERR_FILENO;
+ * we dup2 /dev/null to stderr. */
+ fds[0] = STDERR_FILENO;
n_fds = 1;
for (lf = logfiles; lf; lf = lf->next) {
@@ -697,21 +688,11 @@ tor_log_update_sigsafe_err_fds(void)
(LD_BUG|LD_GENERAL)) {
if (lf->fd == STDERR_FILENO)
found_real_stderr = 1;
- /* Avoid duplicates by checking the log module fd against log_fds */
- if (int_array_contains(log_fds, n_fds, lf->fd))
+ /* Avoid duplicates by checking the log module fd against fds */
+ if (int_array_contains(fds, n_fds, lf->fd))
continue;
- /* Update log_fds using the log module's fd */
- log_fds[n_fds] = lf->fd;
- if (lf->needs_close) {
- /* File log fds are duplicated, because close_log() closes the log
- * module's fd, and tor_log_close_sigsafe_err_fds() closes the err
- * module's fd. Both refer to the same file. */
- err_fds[n_fds] = dup(lf->fd);
- } else {
- /* stdio log fds are not closed by the log module.
- * tor_log_close_sigsafe_err_fds() closes stdio logs. */
- err_fds[n_fds] = lf->fd;
- }
+ /* Update fds using the log module's fd */
+ fds[n_fds] = lf->fd;
n_fds++;
if (n_fds == TOR_SIGSAFE_LOG_MAX_FDS)
break;
@@ -719,20 +700,19 @@ tor_log_update_sigsafe_err_fds(void)
}
if (!found_real_stderr &&
- int_array_contains(log_fds, n_fds, STDOUT_FILENO)) {
+ int_array_contains(fds, n_fds, STDOUT_FILENO)) {
/* Don't use a virtual stderr when we're also logging to stdout.
* If we reached max_fds logs, we'll now have (max_fds - 1) logs.
* That's ok, max_fds is large enough that most tor instances don't exceed
* it. */
raw_assert(n_fds >= 2); /* Don't tor_assert inside log fns */
--n_fds;
- log_fds[0] = log_fds[n_fds];
- err_fds[0] = err_fds[n_fds];
+ fds[0] = fds[n_fds];
}
UNLOCK_LOGS();
- tor_log_set_sigsafe_err_fds(err_fds, n_fds);
+ tor_log_set_sigsafe_err_fds(fds, n_fds);
}
/** Add to <b>out</b> a copy of every currently configured log file name. Used
@@ -841,16 +821,16 @@ logs_free_all(void)
* log mutex. */
}
-/** Close signal-safe log files.
- * Closing the log files makes the process and OS flush log buffers.
+/** Flush the signal-safe log files.
*
- * This function is safe to call from a signal handler. It should only be
- * called when shutting down the log or err modules. It is currenly called
- * by the err module, when terminating the process on an abnormal condition.
+ * This function is safe to call from a signal handler. It is currenly called
+ * by the BUG() macros, when terminating the process on an abnormal condition.
*/
void
-logs_close_sigsafe(void)
+logs_flush_sigsafe(void)
{
+ /* If we don't have fsync() in unistd.h, we can't flush the logs. */
+#ifdef HAVE_FSYNC
logfile_t *victim, *next;
/* We can't LOCK_LOGS() in a signal handler, because it may call
* signal-unsafe functions. And we can't deallocate memory, either. */
@@ -860,9 +840,11 @@ logs_close_sigsafe(void)
victim = next;
next = next->next;
if (victim->needs_close) {
- close_log_sigsafe(victim);
+ /* We can't do anything useful if the flush fails. */
+ (void)fsync(victim->fd);
}
}
+#endif /* defined(HAVE_FSYNC) */
}
/** Remove and free the log entry <b>victim</b> from the linked-list
diff --git a/src/lib/log/log.h b/src/lib/log/log.h
index cb588635d7..aafbf9be2f 100644
--- a/src/lib/log/log.h
+++ b/src/lib/log/log.h
@@ -186,7 +186,7 @@ void logs_set_domain_logging(int enabled);
int get_min_log_level(void);
void switch_logs_debug(void);
void logs_free_all(void);
-void logs_close_sigsafe(void);
+void logs_flush_sigsafe(void);
void add_default_log(int min_severity);
void close_temp_logs(void);
void rollback_log_changes(void);
diff --git a/src/lib/log/util_bug.c b/src/lib/log/util_bug.c
index de44d30e4e..d698ddd8a6 100644
--- a/src/lib/log/util_bug.c
+++ b/src/lib/log/util_bug.c
@@ -71,7 +71,6 @@ tor_set_failed_assertion_callback(void (*fn)(void))
/** Helper for tor_assert: report the assertion failure. */
void
-CHECK_PRINTF(5, 6)
tor_assertion_failed_(const char *fname, unsigned int line,
const char *func, const char *expr,
const char *fmt, ...)
@@ -104,7 +103,6 @@ tor_assertion_failed_(const char *fname, unsigned int line,
/** Helper for tor_assert_nonfatal: report the assertion failure. */
void
-CHECK_PRINTF(6, 7)
tor_bug_occurred_(const char *fname, unsigned int line,
const char *func, const char *expr,
int once, const char *fmt, ...)
@@ -172,7 +170,7 @@ tor_bug_occurred_(const char *fname, unsigned int line,
void
tor_abort_(void)
{
- logs_close_sigsafe();
+ logs_flush_sigsafe();
tor_raw_abort_();
}
diff --git a/src/lib/malloc/map_anon.c b/src/lib/malloc/map_anon.c
index 1926b61f07..628966012a 100644
--- a/src/lib/malloc/map_anon.c
+++ b/src/lib/malloc/map_anon.c
@@ -78,7 +78,7 @@
#endif /* defined(HAVE_MINHERIT) || ... */
#if defined(HAVE_MINHERIT) && !defined(FLAG_ZERO) && !defined(FLAG_NOINHERIT)
-#warning "minherit() is defined, but we couldn't find the right flag for it."
+#warning "minherit() is defined, but FLAG_ZERO/NOINHERIT are not."
#warning "This is probably a bug in Tor's support for this platform."
#endif
diff --git a/src/lib/math/prob_distr.c b/src/lib/math/prob_distr.c
index 548d256023..31d485120e 100644
--- a/src/lib/math/prob_distr.c
+++ b/src/lib/math/prob_distr.c
@@ -1284,15 +1284,16 @@ sample_genpareto_locscale(uint32_t s, double p0, double mu, double sigma,
/**
* Deterministically sample from the geometric distribution with
* per-trial success probability p.
- *
+ **/
+// clang-format off
+/*
* XXX Quantify the error (KL divergence?) of this
* ceiling-of-exponential sampler from a true geometric distribution,
* which we could get by rejection sampling. Relevant papers:
*
* John F. Monahan, `Accuracy in Random Number Generation',
* Mathematics of Computation 45(172), October 1984, pp. 559--568.
-*https://pdfs.semanticscholar.org/aca6/74b96da1df77b2224e8cfc5dd6d61a471632.pdf
- *
+https://pdfs.semanticscholar.org/aca6/74b96da1df77b2224e8cfc5dd6d61a471632.pdf
* Karl Bringmann and Tobias Friedrich, `Exact and Efficient
* Generation of Geometric Random Variates and Random Graphs', in
* Proceedings of the 40th International Colloaquium on Automata,
@@ -1301,6 +1302,7 @@ sample_genpareto_locscale(uint32_t s, double p0, double mu, double sigma,
* https://doi.org/10.1007/978-3-642-39206-1_23
* https://people.mpi-inf.mpg.de/~kbringma/paper/2013ICALP-1.pdf
*/
+// clang-format on
static double
sample_geometric(uint32_t s, double p0, double p)
{
diff --git a/src/lib/memarea/memarea.c b/src/lib/memarea/memarea.c
index d677c364a4..4d26c20eeb 100644
--- a/src/lib/memarea/memarea.c
+++ b/src/lib/memarea/memarea.c
@@ -39,7 +39,7 @@
#elif MEMAREA_ALIGN == 8
#define MEMAREA_ALIGN_MASK ((uintptr_t)7)
#else
-#error "void* is neither 4 nor 8 bytes long. I don't know how to align stuff."
+#error "void* is neither 4 nor 8 bytes long."
#endif /* MEMAREA_ALIGN == 4 || ... */
#if defined(__GNUC__) && defined(FLEXIBLE_ARRAY_MEMBER)
diff --git a/src/lib/net/.may_include b/src/lib/net/.may_include
index e4368f799b..6e9af9737a 100644
--- a/src/lib/net/.may_include
+++ b/src/lib/net/.may_include
@@ -14,4 +14,5 @@ lib/net/*.h
lib/string/*.h
lib/subsys/*.h
lib/testsupport/*.h
-lib/malloc/*.h \ No newline at end of file
+lib/malloc/*.h
+lib/smartlist_core/*.h
diff --git a/src/lib/net/address.c b/src/lib/net/address.c
index ac4350b8fe..e968d8a7f7 100644
--- a/src/lib/net/address.c
+++ b/src/lib/net/address.c
@@ -97,7 +97,7 @@
* work correctly. Bail out here if we've found a platform where AF_UNSPEC
* isn't 0. */
#if AF_UNSPEC != 0
-#error We rely on AF_UNSPEC being 0. Let us know about your platform, please!
+#error "We rely on AF_UNSPEC being 0. Yours isn't. Please tell us more!"
#endif
CTASSERT(AF_UNSPEC == 0);
diff --git a/src/lib/net/inaddr.c b/src/lib/net/inaddr.c
index 0d20d88901..d50ac2440c 100644
--- a/src/lib/net/inaddr.c
+++ b/src/lib/net/inaddr.c
@@ -11,7 +11,9 @@
#include "lib/net/inaddr.h"
#include "lib/cc/torint.h"
+#include "lib/container/smartlist.h"
#include "lib/log/util_bug.h"
+#include "lib/malloc/malloc.h"
#include "lib/net/inaddr_st.h"
#include "lib/string/compat_ctype.h"
#include "lib/string/compat_string.h"
@@ -39,8 +41,27 @@ tor_inet_aton(const char *str, struct in_addr *addr)
{
unsigned a, b, c, d;
char more;
+ bool is_octal = false;
+ smartlist_t *sl = NULL;
+
if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a, &b, &c, &d, &more) != 4)
return 0;
+
+ /* Parse the octets and check them for leading zeros. */
+ sl = smartlist_new();
+ smartlist_split_string(sl, str, ".", 0, 0);
+ SMARTLIST_FOREACH(sl, const char *, octet, {
+ is_octal = (strlen(octet) > 1 && octet[0] == '0');
+ if (is_octal) {
+ break;
+ }
+ });
+ SMARTLIST_FOREACH(sl, char *, octet, tor_free(octet));
+ smartlist_free(sl);
+
+ if (is_octal)
+ return 0;
+
if (a > 255) return 0;
if (b > 255) return 0;
if (c > 255) return 0;
diff --git a/src/lib/net/network_sys.c b/src/lib/net/network_sys.c
index 012fc56bba..f0421385b7 100644
--- a/src/lib/net/network_sys.c
+++ b/src/lib/net/network_sys.c
@@ -39,7 +39,7 @@ const subsys_fns_t sys_network = {
.name = "network",
/* Network depends on logging, and a lot of other modules depend on network.
*/
- .level = -80,
+ .level = -55,
.supported = true,
.initialize = subsys_network_initialize,
.shutdown = subsys_network_shutdown,
diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c
index df079d5db3..68a8c01ef4 100644
--- a/src/lib/net/resolve.c
+++ b/src/lib/net/resolve.c
@@ -372,11 +372,11 @@ static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t)
HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
cached_getaddrinfo_item_hash,
- cached_getaddrinfo_items_eq)
+ cached_getaddrinfo_items_eq);
HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
cached_getaddrinfo_item_hash,
cached_getaddrinfo_items_eq,
- 0.6, tor_reallocarray_, tor_free_)
+ 0.6, tor_reallocarray_, tor_free_);
/** If true, don't try to cache getaddrinfo results. */
static int sandbox_getaddrinfo_cache_disabled = 0;
diff --git a/src/lib/osinfo/uname.c b/src/lib/osinfo/uname.c
index ac99726f51..f7f5ede307 100644
--- a/src/lib/osinfo/uname.c
+++ b/src/lib/osinfo/uname.c
@@ -27,6 +27,40 @@ static char uname_result[256];
/** True iff uname_result is set. */
static int uname_result_is_set = 0;
+#ifdef _WIN32
+/** Table to map claimed windows versions into human-readable windows
+ * versions. */
+static struct {
+ unsigned major;
+ unsigned minor;
+ const char *client_version;
+ const char *server_version;
+} win_version_table[] = {
+ /* This table must be sorted in descending order.
+ * Sources:
+ * https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions
+ * https://docs.microsoft.com/en-us/windows/desktop/api/winnt/
+ * ns-winnt-_osversioninfoexa#remarks
+ */
+ /* Windows Server 2019 is indistinguishable from Windows Server 2016
+ * using GetVersionEx().
+ { 10, 0, NULL, "Windows Server 2019" }, */
+ // clang-format off
+ { 10, 0, "Windows 10", "Windows Server 2016" },
+ { 6, 3, "Windows 8.1", "Windows Server 2012 R2" },
+ { 6, 2, "Windows 8", "Windows Server 2012" },
+ { 6, 1, "Windows 7", "Windows Server 2008 R2" },
+ { 6, 0, "Windows Vista", "Windows Server 2008" },
+ { 5, 2, "Windows XP Professional", "Windows Server 2003" },
+ /* Windows XP did not have a server version, but we need something here */
+ { 5, 1, "Windows XP", "Windows XP Server" },
+ { 5, 0, "Windows 2000 Professional", "Windows 2000 Server" },
+ /* Earlier versions are not supported by GetVersionEx(). */
+ { 0, 0, NULL, NULL }
+ // clang-format on
+};
+#endif /* defined(_WIN32) */
+
/** Return a pointer to a description of our platform.
*/
MOCK_IMPL(const char *,
@@ -49,31 +83,6 @@ get_uname,(void))
int is_client = 0;
int is_server = 0;
const char *plat = NULL;
- static struct {
- unsigned major; unsigned minor;
- const char *client_version; const char *server_version;
- } win_version_table[] = {
- /* This table must be sorted in descending order.
- * Sources:
- * https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions
- * https://docs.microsoft.com/en-us/windows/desktop/api/winnt/
- * ns-winnt-_osversioninfoexa#remarks
- */
- /* Windows Server 2019 is indistinguishable from Windows Server 2016
- * using GetVersionEx().
- { 10, 0, NULL, "Windows Server 2019" }, */
- { 10, 0, "Windows 10", "Windows Server 2016" },
- { 6, 3, "Windows 8.1", "Windows Server 2012 R2" },
- { 6, 2, "Windows 8", "Windows Server 2012" },
- { 6, 1, "Windows 7", "Windows Server 2008 R2" },
- { 6, 0, "Windows Vista", "Windows Server 2008" },
- { 5, 2, "Windows XP Professional", "Windows Server 2003" },
- /* Windows XP did not have a server version, but we need something here */
- { 5, 1, "Windows XP", "Windows XP Server" },
- { 5, 0, "Windows 2000 Professional", "Windows 2000 Server" },
- /* Earlier versions are not supported by GetVersionEx(). */
- { 0, 0, NULL, NULL }
- };
memset(&info, 0, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
diff --git a/src/lib/process/include.am b/src/lib/process/include.am
index af5f99617b..18876b3f54 100644
--- a/src/lib/process/include.am
+++ b/src/lib/process/include.am
@@ -16,8 +16,7 @@ src_lib_libtor_process_a_SOURCES = \
src/lib/process/process_win32.c \
src/lib/process/restrict.c \
src/lib/process/setuid.c \
- src/lib/process/waitpid.c \
- src/lib/process/winprocess_sys.c
+ src/lib/process/waitpid.c
src_lib_libtor_process_testing_a_SOURCES = \
$(src_lib_libtor_process_a_SOURCES)
@@ -35,5 +34,4 @@ noinst_HEADERS += \
src/lib/process/process_win32.h \
src/lib/process/restrict.h \
src/lib/process/setuid.h \
- src/lib/process/waitpid.h \
- src/lib/process/winprocess_sys.h
+ src/lib/process/waitpid.h
diff --git a/src/lib/process/process_sys.c b/src/lib/process/process_sys.c
index 283064cbfe..015ffadead 100644
--- a/src/lib/process/process_sys.c
+++ b/src/lib/process/process_sys.c
@@ -26,7 +26,7 @@ subsys_process_shutdown(void)
const subsys_fns_t sys_process = {
.name = "process",
- .level = -35,
+ .level = -18,
.supported = true,
.initialize = subsys_process_initialize,
.shutdown = subsys_process_shutdown
diff --git a/src/lib/process/waitpid.c b/src/lib/process/waitpid.c
index 89ffe9fcfe..33798f65f0 100644
--- a/src/lib/process/waitpid.c
+++ b/src/lib/process/waitpid.c
@@ -58,9 +58,9 @@ process_map_entries_eq_(const waitpid_callback_t *a,
static HT_HEAD(process_map, waitpid_callback_t) process_map = HT_INITIALIZER();
HT_PROTOTYPE(process_map, waitpid_callback_t, node, process_map_entry_hash_,
- process_map_entries_eq_)
+ process_map_entries_eq_);
HT_GENERATE2(process_map, waitpid_callback_t, node, process_map_entry_hash_,
- process_map_entries_eq_, 0.6, tor_reallocarray_, tor_free_)
+ process_map_entries_eq_, 0.6, tor_reallocarray_, tor_free_);
/**
* Begin monitoring the child pid <b>pid</b> to see if we get a SIGCHLD for
diff --git a/src/lib/thread/compat_threads.c b/src/lib/thread/compat_threads.c
index d56e8a3f76..21125bddad 100644
--- a/src/lib/thread/compat_threads.c
+++ b/src/lib/thread/compat_threads.c
@@ -130,8 +130,6 @@ subsys_threads_initialize(void)
const subsys_fns_t sys_threads = {
.name = "threads",
.supported = true,
- /* Threads is used by logging, which is a diagnostic feature, we want it to
- * init right after low-level error handling and approx time. */
- .level = -95,
+ .level = -89,
.initialize = subsys_threads_initialize,
};
diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs
index 0ca960bd69..6d2ef33eec 100644
--- a/src/rust/protover/protover.rs
+++ b/src/rust/protover/protover.rs
@@ -161,30 +161,30 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
"Cons=1-2 \
Desc=1-2 \
DirCache=1-2 \
+ FlowCtrl=1 \
HSDir=1-2 \
HSIntro=3-4 \
HSRend=1-2 \
Link=1-5 \
LinkAuth=3 \
Microdesc=1-2 \
- Relay=1-2 \
Padding=2 \
- FlowCtrl=1"
+ Relay=1-2"
)
} else {
cstr!(
"Cons=1-2 \
Desc=1-2 \
DirCache=1-2 \
+ FlowCtrl=1 \
HSDir=1-2 \
HSIntro=3-4 \
HSRend=1-2 \
Link=1-5 \
LinkAuth=1,3 \
Microdesc=1-2 \
- Relay=1-2 \
Padding=2 \
- FlowCtrl=1"
+ Relay=1-2"
)
}
}
diff --git a/src/test/conf_examples/large_1/expected b/src/test/conf_examples/large_1/expected
index 5866f5823e..99a12ffc84 100644
--- a/src/test/conf_examples/large_1/expected
+++ b/src/test/conf_examples/large_1/expected
@@ -15,7 +15,6 @@ CellStatistics 1
CircuitBuildTimeout 200
CircuitsAvailableTimeout 10
CircuitStreamTimeout 20
-ClientAutoIPv6ORPort 1
ClientOnly 1
ClientPreferIPv6DirPort 1
ClientPreferIPv6ORPort 1
diff --git a/src/test/conf_examples/large_1/expected_no_dirauth b/src/test/conf_examples/large_1/expected_no_dirauth
index 17c11f85fc..26a33bdc7c 100644
--- a/src/test/conf_examples/large_1/expected_no_dirauth
+++ b/src/test/conf_examples/large_1/expected_no_dirauth
@@ -15,7 +15,6 @@ CellStatistics 1
CircuitBuildTimeout 200
CircuitsAvailableTimeout 10
CircuitStreamTimeout 20
-ClientAutoIPv6ORPort 1
ClientOnly 1
ClientPreferIPv6DirPort 1
ClientPreferIPv6ORPort 1
diff --git a/src/test/conf_examples/large_1/torrc b/src/test/conf_examples/large_1/torrc
index e99acd9fb7..20ddf00e16 100644
--- a/src/test/conf_examples/large_1/torrc
+++ b/src/test/conf_examples/large_1/torrc
@@ -16,7 +16,6 @@ CircuitBuildTimeout 200
CircuitPadding 1
CircuitsAvailableTimeout 10
CircuitStreamTimeout 20
-ClientAutoIPv6ORPort 1
ClientOnly 1
ClientPreferIPv6DirPort 1
ClientPreferIPv6ORPort 1
diff --git a/src/test/fuzz/fuzz_hsdescv3.c b/src/test/fuzz/fuzz_hsdescv3.c
index 3955241389..8d7eab1a8d 100644
--- a/src/test/fuzz/fuzz_hsdescv3.c
+++ b/src/test/fuzz/fuzz_hsdescv3.c
@@ -85,12 +85,12 @@ int
fuzz_main(const uint8_t *data, size_t sz)
{
hs_descriptor_t *desc = NULL;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
char *fuzzing_data = tor_memdup_nulterm(data, sz);
- memset(subcredential, 'A', sizeof(subcredential));
+ memset(&subcredential, 'A', sizeof(subcredential));
- hs_desc_decode_descriptor(fuzzing_data, subcredential, NULL, &desc);
+ hs_desc_decode_descriptor(fuzzing_data, &subcredential, NULL, &desc);
if (desc) {
log_debug(LD_GENERAL, "Decoding okay");
hs_descriptor_free(desc);
@@ -101,4 +101,3 @@ fuzz_main(const uint8_t *data, size_t sz)
tor_free(fuzzing_data);
return 0;
}
-
diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c
index e8b99aaac8..5116fc7169 100644
--- a/src/test/hs_test_helpers.c
+++ b/src/test/hs_test_helpers.c
@@ -13,9 +13,22 @@
#include "feature/hs/hs_service.h"
#include "test/hs_test_helpers.h"
+/**
+ * Create an introduction point taken straight out of an HSv3 descriptor.
+ *
+ * Use 'signing_kp' to sign the introduction point certificates.
+ *
+ * If 'intro_auth_kp' is provided use that as the introduction point
+ * authentication keypair, otherwise generate one on the fly.
+ *
+ * If 'intro_enc_kp' is provided use that as the introduction point encryption
+ * keypair, otherwise generate one on the fly.
+ */
hs_desc_intro_point_t *
hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
- const char *addr, int legacy)
+ const char *addr, int legacy,
+ const ed25519_keypair_t *intro_auth_kp,
+ const curve25519_keypair_t *intro_enc_kp)
{
int ret;
ed25519_keypair_t auth_kp;
@@ -56,8 +69,12 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
smartlist_add(ip->link_specifiers, ls_ip);
}
- ret = ed25519_keypair_generate(&auth_kp, 0);
- tt_int_op(ret, OP_EQ, 0);
+ if (intro_auth_kp) {
+ memcpy(&auth_kp, intro_auth_kp, sizeof(ed25519_keypair_t));
+ } else {
+ ret = ed25519_keypair_generate(&auth_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ }
ip->auth_key_cert = tor_cert_create(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY,
&auth_kp.pubkey, now,
HS_DESC_CERT_LIFETIME,
@@ -85,8 +102,12 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
ed25519_keypair_t ed25519_kp;
tor_cert_t *cross_cert;
- ret = curve25519_keypair_generate(&curve25519_kp, 0);
- tt_int_op(ret, OP_EQ, 0);
+ if (intro_enc_kp) {
+ memcpy(&curve25519_kp, intro_enc_kp, sizeof(curve25519_keypair_t));
+ } else {
+ ret = curve25519_keypair_generate(&curve25519_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ }
ed25519_keypair_from_curve25519_keypair(&ed25519_kp, &signbit,
&curve25519_kp);
cross_cert = tor_cert_create(signing_kp, CERT_TYPE_CROSS_HS_IP_KEYS,
@@ -95,6 +116,8 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
CERT_FLAG_INCLUDE_SIGNING_KEY);
tt_assert(cross_cert);
ip->enc_key_cert = cross_cert;
+ memcpy(ip->enc_key.public_key, curve25519_kp.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN);
}
intro_point = ip;
@@ -140,7 +163,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
desc->plaintext_data.lifetime_sec = 3 * 60 * 60;
hs_get_subcredential(&signing_kp->pubkey, &blinded_kp.pubkey,
- desc->subcredential);
+ &desc->subcredential);
/* Setup superencrypted data section. */
ret = curve25519_keypair_generate(&auth_ephemeral_kp, 0);
@@ -165,13 +188,17 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
if (!no_ip) {
/* Add four intro points. */
smartlist_add(desc->encrypted_data.intro_points,
- hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0));
+ hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0,
+ NULL, NULL));
smartlist_add(desc->encrypted_data.intro_points,
- hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0));
+ hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0,
+ NULL, NULL));
smartlist_add(desc->encrypted_data.intro_points,
- hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1));
+ hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1,
+ NULL, NULL));
smartlist_add(desc->encrypted_data.intro_points,
- hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1));
+ hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1,
+ NULL, NULL));
}
descp = desc;
@@ -186,7 +213,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
* an HS. Used to decrypt descriptors in unittests. */
void
hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp,
- uint8_t *subcred_out)
+ hs_subcredential_t *subcred_out)
{
ed25519_keypair_t blinded_kp;
uint64_t current_time_period = hs_get_time_period_num(approx_time());
@@ -233,7 +260,7 @@ hs_helper_build_hs_desc_with_client_auth(
memcpy(&desc->superencrypted_data.auth_ephemeral_pubkey,
&auth_ephemeral_kp.pubkey, sizeof(curve25519_public_key_t));
- hs_desc_build_authorized_client(desc->subcredential, client_pk,
+ hs_desc_build_authorized_client(&desc->subcredential, client_pk,
&auth_ephemeral_kp.seckey,
descriptor_cookie, desc_client);
smartlist_add(desc->superencrypted_data.clients, desc_client);
diff --git a/src/test/hs_test_helpers.h b/src/test/hs_test_helpers.h
index a01fd45d63..23d11f2a4a 100644
--- a/src/test/hs_test_helpers.h
+++ b/src/test/hs_test_helpers.h
@@ -8,9 +8,11 @@
#include "feature/hs/hs_descriptor.h"
/* Set of functions to help build and test descriptors. */
-hs_desc_intro_point_t *hs_helper_build_intro_point(
- const ed25519_keypair_t *signing_kp, time_t now,
- const char *addr, int legacy);
+hs_desc_intro_point_t *
+hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
+ const char *addr, int legacy,
+ const ed25519_keypair_t *intro_auth_kp,
+ const curve25519_keypair_t *intro_enc_kp);
hs_descriptor_t *hs_helper_build_hs_desc_no_ip(
const ed25519_keypair_t *signing_kp);
hs_descriptor_t *hs_helper_build_hs_desc_with_ip(
@@ -21,12 +23,11 @@ hs_descriptor_t *hs_helper_build_hs_desc_with_client_auth(
const ed25519_keypair_t *signing_kp);
void hs_helper_desc_equal(const hs_descriptor_t *desc1,
const hs_descriptor_t *desc2);
-void
-hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp,
- uint8_t *subcred_out);
+struct hs_subcredential_t;
+void hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp,
+ struct hs_subcredential_t *subcred_out);
void hs_helper_add_client_auth(const ed25519_public_key_t *service_pk,
const curve25519_secret_key_t *client_sk);
#endif /* !defined(TOR_HS_TEST_HELPERS_H) */
-
diff --git a/src/test/include.am b/src/test/include.am
index 90e50752ce..de927836d6 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -61,13 +61,25 @@ TESTS += src/test/test src/test/test-slow src/test/test-memwipe \
$(TESTSCRIPTS)
# These flavors are run using automake's test-driver and test-network.sh
-TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v2-min hs-v3-min \
- single-onion-v23
+
+# run a quick test or two
+# this test only uses IPv4
+TEST_CHUTNEY_FLAVOR_QUICK = bridges+hs-v23
# only run if we can ping6 ::1 (localhost)
+TEST_CHUTNEY_FLAVOR_QUICK_IPV6 = single-onion-v23-ipv6-md
+
+# run a basic set of tests, which only use IPv4
+TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v23-min single-onion-v23
+
+# only run if we can ping ::1 (localhost)
TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v23-ipv6-md \
single-onion-v23-ipv6-md
+
# only run if we can find a stable (or simply another) version of tor
-TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v2
+TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v23
+
+# only run if IPv6 and mixed networks are run
+TEST_CHUTNEY_FLAVORS_IPV6_MIXED = mixed+hs-v23-ipv6
### This is a lovely feature, but it requires automake >= 1.12, and Tor
### doesn't require that yet.
@@ -167,6 +179,7 @@ src_test_test_SOURCES += \
src/test/test_hs_client.c \
src/test/test_hs_intropoint.c \
src/test/test_hs_control.c \
+ src/test/test_hs_ob.c \
src/test/test_handles.c \
src/test/test_hs_cache.c \
src/test/test_hs_descriptor.c \
diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h
index e2ddf09466..c2d71c6bcd 100644
--- a/src/test/log_test_helpers.h
+++ b/src/test/log_test_helpers.h
@@ -78,7 +78,7 @@ void mock_dump_saved_logs(void);
mock_saved_log_n_entries() == 1, \
("expected log to contain exactly 1 message \"%s\"", \
str)); \
- } while (0);
+ } while (0)
#define expect_single_log_msg_containing(str) \
do { \
@@ -86,30 +86,30 @@ void mock_dump_saved_logs(void);
mock_saved_log_n_entries() == 1 , \
("expected log to contain 1 message, containing \"%s\"",\
str)); \
- } while (0);
+ } while (0)
#define expect_no_log_msg(str) \
assert_log_predicate(!mock_saved_log_has_message(str), \
- ("expected log to not contain \"%s\"",str));
+ ("expected log to not contain \"%s\"",str))
#define expect_no_log_msg_containing(str) \
assert_log_predicate(!mock_saved_log_has_message_containing(str), \
- ("expected log to not contain \"%s\"", str));
+ ("expected log to not contain \"%s\"", str))
#define expect_log_severity(severity) \
assert_log_predicate(mock_saved_log_has_severity(severity), \
- ("expected log to contain severity " # severity));
+ ("expected log to contain severity " # severity))
#define expect_no_log_severity(severity) \
assert_log_predicate(!mock_saved_log_has_severity(severity), \
- ("expected log to not contain severity " # severity));
+ ("expected log to not contain severity " # severity))
#define expect_log_entry() \
assert_log_predicate(mock_saved_log_has_entry(), \
- ("expected log to contain entries"));
+ ("expected log to contain entries"))
#define expect_no_log_entry() \
assert_log_predicate(!mock_saved_log_has_entry(), \
- ("expected log to not contain entries"));
+ ("expected log to not contain entries"))
#endif /* !defined(TOR_LOG_TEST_HELPERS_H) */
diff --git a/src/test/test.c b/src/test/test.c
index 1742f1d952..4b6082ce4f 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -721,6 +721,7 @@ struct testgroup_t testgroups[] = {
{ "hs_dos/", hs_dos_tests },
{ "hs_intropoint/", hs_intropoint_tests },
{ "hs_ntor/", hs_ntor_tests },
+ { "hs_ob/", hs_ob_tests },
{ "hs_service/", hs_service_tests },
{ "introduce/", introduce_tests },
{ "keypin/", keypin_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 63e2faff95..18987719d0 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -141,6 +141,7 @@ extern struct testcase_t hs_descriptor[];
extern struct testcase_t hs_dos_tests[];
extern struct testcase_t hs_intropoint_tests[];
extern struct testcase_t hs_ntor_tests[];
+extern struct testcase_t hs_ob_tests[];
extern struct testcase_t hs_service_tests[];
extern struct testcase_t hs_tests[];
extern struct testcase_t introduce_tests[];
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index af3c125a20..1a19e405ed 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -659,12 +659,7 @@ test_addr_ip6_helpers(void *arg)
tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x01010202);
r=tor_addr_parse_mask_ports("3.4.16.032:1-2",0,&t1, &mask, &port1, &port2);
- tt_int_op(r, OP_EQ, AF_INET);
- tt_int_op(mask,OP_EQ,32);
- tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
- tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x03041020);
- tt_uint_op(port1, OP_EQ, 1);
- tt_uint_op(port2, OP_EQ, 2);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("1.1.2.3/255.255.128.0",0,&t1, &mask,NULL,NULL);
tt_int_op(r, OP_EQ, AF_INET);
tt_int_op(mask,OP_EQ,17);
@@ -1653,6 +1648,29 @@ test_addr_rfc6598(void *arg)
;
}
+#define TEST_ADDR_ATON(a, rv) STMT_BEGIN \
+ struct in_addr addr; \
+ tt_int_op(tor_inet_aton(a, &addr), OP_EQ, rv); \
+ STMT_END;
+
+static void
+test_addr_octal(void *arg)
+{
+ (void)arg;
+
+ /* Test non-octal IP addresses. */
+ TEST_ADDR_ATON("0.1.2.3", 1);
+ TEST_ADDR_ATON("1.0.2.3", 1);
+ TEST_ADDR_ATON("1.2.3.0", 1);
+
+ /* Test octal IP addresses. */
+ TEST_ADDR_ATON("01.1.2.3", 0);
+ TEST_ADDR_ATON("1.02.3.4", 0);
+ TEST_ADDR_ATON("1.2.3.04", 0);
+ done:
+ ;
+}
+
#ifndef COCCI
#define ADDR_LEGACY(name) \
{ #name, test_addr_ ## name , 0, NULL, NULL }
@@ -1671,5 +1689,6 @@ struct testcase_t addr_tests[] = {
{ "is_loopback", test_addr_is_loopback, 0, NULL, NULL },
{ "make_null", test_addr_make_null, 0, NULL, NULL },
{ "rfc6598", test_addr_rfc6598, 0, NULL, NULL },
+ { "octal", test_addr_octal, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c
index 70920c0c52..10d78abc35 100644
--- a/src/test/test_circuitbuild.c
+++ b/src/test/test_circuitbuild.c
@@ -114,6 +114,14 @@ test_new_route_len_unhandled_exit(void *arg)
int r;
(void)arg;
+#ifdef ALL_BUGS_ARE_FATAL
+ /* Coverity (and maybe clang analyser) complain that the code following
+ * tt_skip() is unconditionally unreachable. */
+#if !defined(__COVERITY__) && !defined(__clang_analyzer__)
+ tt_skip();
+#endif
+#endif
+
MOCK(count_acceptable_nodes, mock_count_acceptable_nodes);
tor_capture_bugs_(1);
diff --git a/src/test/test_connection.c b/src/test/test_connection.c
index 7ed831f7d8..fca4d884bb 100644
--- a/src/test/test_connection.c
+++ b/src/test/test_connection.c
@@ -967,9 +967,14 @@ test_failed_orconn_tracker(void *arg)
#define CONNECTION_TESTCASE(name, fork, setup) \
{ #name, test_conn_##name, fork, &setup, NULL }
+#define STR(x) #x
/* where arg is an expression (constant, variable, compound expression) */
-#define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \
- { #name "_" #arg, test_conn_##name, fork, &setup, (void *)arg }
+#define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \
+ { #name "_" STR(x), \
+ test_conn_##name, \
+ fork, \
+ &setup, \
+ (void *)arg }
#endif /* !defined(COCCI) */
static const unsigned int PROXY_CONNECT_ARG = PROXY_CONNECT;
diff --git a/src/test/test_consdiff.c b/src/test/test_consdiff.c
index e4cfece9c3..242e2f7818 100644
--- a/src/test/test_consdiff.c
+++ b/src/test/test_consdiff.c
@@ -1030,7 +1030,7 @@ test_consdiff_apply_diff(void *arg)
/* diff doesn't have enough lines. */
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
- expect_single_log_msg_containing("too short")
+ expect_single_log_msg_containing("too short");
/* first line doesn't match format-version string. */
smartlist_add_linecpy(diff, area, "foo-bar");
@@ -1038,7 +1038,7 @@ test_consdiff_apply_diff(void *arg)
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
- expect_single_log_msg_containing("format is not known")
+ expect_single_log_msg_containing("format is not known");
/* The first word of the second header line is not "hash". */
smartlist_clear(diff);
@@ -1048,7 +1048,7 @@ test_consdiff_apply_diff(void *arg)
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
- expect_single_log_msg_containing("does not include the necessary digests")
+ expect_single_log_msg_containing("does not include the necessary digests");
/* Wrong number of words after "hash". */
smartlist_clear(diff);
@@ -1057,7 +1057,7 @@ test_consdiff_apply_diff(void *arg)
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
- expect_single_log_msg_containing("does not include the necessary digests")
+ expect_single_log_msg_containing("does not include the necessary digests");
/* base16 digests do not have the expected length. */
smartlist_clear(diff);
@@ -1067,7 +1067,7 @@ test_consdiff_apply_diff(void *arg)
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
expect_single_log_msg_containing("includes base16-encoded digests of "
- "incorrect size")
+ "incorrect size");
/* base16 digests contain non-base16 characters. */
smartlist_clear(diff);
@@ -1078,7 +1078,7 @@ test_consdiff_apply_diff(void *arg)
mock_clean_saved_logs();
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
- expect_single_log_msg_containing("includes malformed digests")
+ expect_single_log_msg_containing("includes malformed digests");
/* Invalid ed diff.
* As tested in apply_ed_diff, but check that apply_diff does return NULL if
@@ -1095,7 +1095,7 @@ test_consdiff_apply_diff(void *arg)
cons2 = consdiff_apply_diff(cons1, diff, &digests1);
tt_ptr_op(NULL, OP_EQ, cons2);
expect_single_log_msg_containing("because an ed command was missing a line "
- "number")
+ "number");
/* Base consensus doesn't match its digest as found in the diff. */
smartlist_clear(diff);
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 3b2ba64d2c..bf9a04b079 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -47,7 +47,7 @@
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/directory.h"
#include "feature/dircommon/fp_pair.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/hibernate/hibernate.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/dirlist.h"
@@ -3005,6 +3005,7 @@ test_dir_param_voting_lookup(void *arg)
tt_int_op(99, OP_EQ,
dirvote_get_intermediate_param_value(lst, "abcd", 1000));
+#ifndef ALL_BUGS_ARE_FATAL
/* moomin appears twice. That's a bug. */
tor_capture_bugs_(1);
tt_int_op(-100, OP_EQ,
@@ -3022,7 +3023,7 @@ test_dir_param_voting_lookup(void *arg)
dirvote_get_intermediate_param_value(lst, "jack", -100));
tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
- "!(! ok)");
+ "!(!ok)");
tor_end_capture_bugs_();
/* electricity and opa aren't integers. */
tor_capture_bugs_(1);
@@ -3030,7 +3031,7 @@ test_dir_param_voting_lookup(void *arg)
dirvote_get_intermediate_param_value(lst, "electricity", -100));
tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
- "!(! ok)");
+ "!(!ok)");
tor_end_capture_bugs_();
tor_capture_bugs_(1);
@@ -3038,8 +3039,9 @@ test_dir_param_voting_lookup(void *arg)
dirvote_get_intermediate_param_value(lst, "opa", -100));
tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
- "!(! ok)");
+ "!(!ok)");
tor_end_capture_bugs_();
+#endif
done:
SMARTLIST_FOREACH(lst, char *, cp, tor_free(cp));
@@ -3610,7 +3612,7 @@ test_a_networkstatus(
sign_skey_2 = crypto_pk_new();
sign_skey_3 = crypto_pk_new();
sign_skey_leg1 = pk_generate(4);
- voting_schedule_recalculate_timing(get_options(), now);
+ dirauth_sched_recalculate_timing(get_options(), now);
sr_state_init(0, 0);
tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_1,
@@ -4989,6 +4991,14 @@ test_dir_purpose_needs_anonymity_returns_true_by_default(void *arg)
{
(void)arg;
+#ifdef ALL_BUGS_ARE_FATAL
+ /* Coverity (and maybe clang analyser) complain that the code following
+ * tt_skip() is unconditionally unreachable. */
+#if !defined(__COVERITY__) && !defined(__clang_analyzer__)
+ tt_skip();
+#endif
+#endif
+
tor_capture_bugs_(1);
setup_full_capture_of_logs(LOG_WARN);
tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, 0, NULL));
diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c
index 4533ad5c03..f2b4e8724b 100644
--- a/src/test/test_dir_common.c
+++ b/src/test/test_dir_common.c
@@ -13,7 +13,7 @@
#include "feature/dirparse/authcert_parse.h"
#include "feature/dirparse/ns_parse.h"
#include "test/test_dir_common.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/nodelist/authority_cert_st.h"
#include "feature/nodelist/networkstatus_st.h"
diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c
index 6293839b0d..f446bbb5eb 100644
--- a/src/test/test_dir_handle_get.c
+++ b/src/test/test_dir_handle_get.c
@@ -38,7 +38,7 @@
#include "feature/dircache/dirserv.h"
#include "feature/dirauth/dirvote.h"
#include "test/log_test_helpers.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dircommon/dir_connection_st.h"
#include "feature/dirclient/dir_server_st.h"
@@ -2080,12 +2080,12 @@ test_dir_handle_get_status_vote_d(void* data)
mock_options->TestingV3AuthInitialDistDelay = 1;
time_t now = 1441223455 -1;
- voting_schedule_recalculate_timing(mock_options, now);
+ dirauth_sched_recalculate_timing(mock_options, now);
const char *msg_out = NULL;
int status_out = 0;
- struct pending_vote_t *pv = dirvote_add_vote(VOTE_BODY_V3, &msg_out,
- &status_out);
+ struct pending_vote_t *pv = dirvote_add_vote(VOTE_BODY_V3, 0,
+ &msg_out, &status_out);
tt_assert(pv);
status_vote_current_d_test(&header, &body, &body_used);
@@ -2457,10 +2457,10 @@ test_dir_handle_get_status_vote_next_authority(void* data)
mock_options->TestingV3AuthInitialDistDelay = 1;
time_t now = 1441223455 -1;
- voting_schedule_recalculate_timing(mock_options, now);
+ dirauth_sched_recalculate_timing(mock_options, now);
- struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, &msg_out,
- &status_out);
+ struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, 0,
+ &msg_out, &status_out);
tt_assert(vote);
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
@@ -2617,10 +2617,10 @@ test_dir_handle_get_status_vote_current_authority(void* data)
mock_options->TestingV3AuthInitialDistDelay = 1;
time_t now = 1441223455;
- voting_schedule_recalculate_timing(mock_options, now-1);
+ dirauth_sched_recalculate_timing(mock_options, now-1);
- struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, &msg_out,
- &status_out);
+ struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, 0,
+ &msg_out, &status_out);
tt_assert(vote);
// move the pending vote to previous vote
@@ -2658,6 +2658,183 @@ test_dir_handle_get_status_vote_current_authority(void* data)
dirvote_free_all();
}
+/* Test that a late vote is rejected, but an on-time vote is accepted. */
+static void
+test_dir_handle_get_status_vote_too_late(void* data)
+{
+ dir_connection_t *conn = NULL;
+ char *header = NULL, *body = NULL;
+ const char *msg_out = NULL;
+ int status_out = 0;
+ size_t body_used = 0;
+ const char digest[DIGEST_LEN] = "";
+
+ dir_server_t *ds = NULL;
+ const char* mode = (const char *)data;
+
+ clear_dir_servers();
+ routerlist_free_all();
+ dirvote_free_all();
+
+ mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE,
+ strlen(TEST_CERTIFICATE),
+ NULL);
+
+ /* create a trusted ds */
+ ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, NULL, digest,
+ NULL, V3_DIRINFO, 1.0);
+ tt_assert(ds);
+ dir_server_add(ds);
+
+ /* ds v3_identity_digest is the certificate's identity_key */
+ base16_decode(ds->v3_identity_digest, DIGEST_LEN,
+ TEST_CERT_IDENT_KEY, HEX_DIGEST_LEN);
+
+ tt_int_op(0, OP_EQ, trusted_dirs_load_certs_from_string(TEST_CERTIFICATE,
+ TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1, NULL));
+
+ init_mock_options();
+ mock_options->AuthoritativeDir = 1;
+ mock_options->V3AuthoritativeDir = 1;
+
+ int base_delay = 0;
+ int vote_interval = 0;
+ int start_offset = 0;
+
+ tt_assert(mode);
+ /* Set the required timings, see below for details */
+ if (strcmp(mode, "min") == 0) {
+ /* The minimum valid test network timing */
+ base_delay = 2;
+ vote_interval = 10;
+ start_offset = vote_interval - 5;
+ } else if (strcmp(mode, "chutney") == 0) {
+ /* The test network timing used by chutney */
+ base_delay = 4;
+ vote_interval = 20;
+ start_offset = vote_interval - 5;
+ } else if (strcmp(mode, "half-public") == 0) {
+ /* The short consensus failure timing used in the public network */
+ base_delay = 5*60;
+ vote_interval = 30*60;
+ start_offset = vote_interval - 9*60 - 5;
+ } else if (strcmp(mode, "public") == 0) {
+ /* The standard timing used in the public network */
+ base_delay = 5*60;
+ vote_interval = 60*60;
+ start_offset = vote_interval - 9*60 - 5;
+ }
+
+ tt_assert(base_delay > 0);
+ tt_assert(vote_interval > 0);
+ tt_assert(start_offset > 0);
+
+ /* Skew the time to fit the fixed time in the vote */
+ mock_options->TestingV3AuthVotingStartOffset = start_offset;
+ /* Calculate the rest of the timings */
+ mock_options->TestingV3AuthInitialVotingInterval = vote_interval;
+ mock_options->TestingV3AuthInitialVoteDelay = base_delay;
+ mock_options->TestingV3AuthInitialDistDelay = base_delay;
+
+ time_t now = 1441223455;
+ dirauth_sched_recalculate_timing(mock_options, now-1);
+ const time_t voting_starts = voting_schedule.voting_starts;
+ const time_t fetch_missing = voting_schedule.fetch_missing_votes;
+
+ struct pending_vote_t *vote = NULL;
+
+ /* Next voting interval */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ fetch_missing + vote_interval,
+ &msg_out, &status_out);
+ tt_assert(!vote);
+ tt_int_op(status_out, OP_EQ, 400);
+ tt_str_op(msg_out, OP_EQ,
+ "Posted vote received too late, would be dangerous to count it");
+
+ /* Just after fetch missing */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ fetch_missing + 1,
+ &msg_out, &status_out);
+ tt_assert(!vote);
+ tt_int_op(status_out, OP_EQ, 400);
+ tt_str_op(msg_out, OP_EQ,
+ "Posted vote received too late, would be dangerous to count it");
+
+ /* On fetch missing */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ fetch_missing,
+ &msg_out, &status_out);
+ tt_assert(vote);
+
+ /* Move the pending vote to previous vote */
+ dirvote_act(mock_options, now+1);
+ /* And reset the timing */
+ dirauth_sched_recalculate_timing(mock_options, now-1);
+
+ /* Between voting starts and fetch missing */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ voting_starts + 1,
+ &msg_out, &status_out);
+ tt_assert(vote);
+
+ /* Move the pending vote to previous vote */
+ dirvote_act(mock_options, now+1);
+ /* And reset the timing */
+ dirauth_sched_recalculate_timing(mock_options, now-1);
+
+ /* On voting starts */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ voting_starts,
+ &msg_out, &status_out);
+ tt_assert(vote);
+
+ /* Move the pending vote to previous vote */
+ dirvote_act(mock_options, now+1);
+ /* And reset the timing */
+ dirauth_sched_recalculate_timing(mock_options, now-1);
+
+ /* Just before voting starts */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ voting_starts - 1,
+ &msg_out, &status_out);
+ tt_assert(vote);
+
+ /* Move the pending vote to previous vote */
+ dirvote_act(mock_options, now+1);
+
+ MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
+ MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+
+ conn = new_dir_conn();
+ tt_int_op(0, OP_EQ, directory_handle_command_get(conn,
+ GET("/tor/status-vote/current/authority"), NULL, 0));
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
+ &body, &body_used, strlen(VOTE_BODY_V3)+1, 0);
+
+ tt_assert(header);
+ tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header);
+ tt_assert(strstr(header, "Content-Type: text/plain\r\n"));
+ tt_assert(strstr(header, "Content-Encoding: identity\r\n"));
+ tt_assert(strstr(header, "Content-Length: 4135\r\n"));
+
+ tt_str_op(VOTE_BODY_V3, OP_EQ, body);
+
+ done:
+ UNMOCK(connection_write_to_buf_impl_);
+ UNMOCK(get_my_v3_authority_cert);
+ connection_free_minimal(TO_CONN(conn));
+ tor_free(header);
+ tor_free(body);
+ authority_cert_free(mock_cert); mock_cert = NULL;
+ or_options_free(mock_options); mock_options = NULL;
+
+ clear_dir_servers();
+ routerlist_free_all();
+ dirvote_free_all();
+}
+
static void
test_dir_handle_get_parse_accept_encoding(void *arg)
{
@@ -2708,6 +2885,16 @@ test_dir_handle_get_parse_accept_encoding(void *arg)
#define DIR_HANDLE_CMD(name,flags) \
{ #name, test_dir_handle_get_##name, (flags), NULL, NULL }
+#ifdef COCCI
+/* Coccinelle doesn't like the stringification in this macro */
+#define DIR_HANDLE_CMD_ARG(name,flags,arg) \
+ DIR_HANDLE_CMD(name,flags)
+#else
+#define DIR_HANDLE_CMD_ARG(name,flags,arg) \
+ { #name "/" arg, test_dir_handle_get_##name, (flags), \
+ &passthrough_setup, (void *)(arg) }
+#endif /* defined(COCCI) */
+
struct testcase_t dir_handle_get_tests[] = {
DIR_HANDLE_CMD(not_found, 0),
DIR_HANDLE_CMD(bad_request, 0),
@@ -2747,6 +2934,10 @@ struct testcase_t dir_handle_get_tests[] = {
DIR_HANDLE_CMD(status_vote_next_not_found, 0),
DIR_HANDLE_CMD(status_vote_current_authority_not_found, 0),
DIR_HANDLE_CMD(status_vote_current_authority, 0),
+ DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "min"),
+ DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "chutney"),
+ DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "half-public"),
+ DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "public"),
DIR_HANDLE_CMD(status_vote_next_authority_not_found, 0),
DIR_HANDLE_CMD(status_vote_next_authority, 0),
DIR_HANDLE_CMD(status_vote_next_bandwidth_not_found, 0),
diff --git a/src/test/test_dns.c b/src/test/test_dns.c
index ec17e9e91e..299321ab64 100644
--- a/src/test/test_dns.c
+++ b/src/test/test_dns.c
@@ -80,11 +80,11 @@ test_dns_clip_ttl(void *arg)
{
(void)arg;
- uint32_t ttl_mid = MIN_DNS_TTL_AT_EXIT / 2 + MAX_DNS_TTL_AT_EXIT / 2;
+ uint32_t ttl_mid = MIN_DNS_TTL / 2 + MAX_DNS_TTL / 2;
- tt_int_op(dns_clip_ttl(MIN_DNS_TTL_AT_EXIT - 1),OP_EQ,MIN_DNS_TTL_AT_EXIT);
- tt_int_op(dns_clip_ttl(ttl_mid),OP_EQ,MAX_DNS_TTL_AT_EXIT);
- tt_int_op(dns_clip_ttl(MAX_DNS_TTL_AT_EXIT + 1),OP_EQ,MAX_DNS_TTL_AT_EXIT);
+ tt_int_op(clip_dns_ttl(MIN_DNS_TTL - 1),OP_EQ,MIN_DNS_TTL);
+ tt_int_op(clip_dns_ttl(ttl_mid),OP_EQ,MAX_DNS_TTL);
+ tt_int_op(clip_dns_ttl(MAX_DNS_TTL + 1),OP_EQ,MAX_DNS_TTL);
done:
return;
diff --git a/src/test/test_dos.c b/src/test/test_dos.c
index b6a83210b7..527e5bbe7f 100644
--- a/src/test/test_dos.c
+++ b/src/test/test_dos.c
@@ -79,7 +79,7 @@ test_dos_conn_creation(void *arg)
{ /* Register many conns from this client but not enough to get it blocked */
unsigned int i;
for (i = 0; i < max_concurrent_conns; i++) {
- dos_new_client_conn(&or_conn);
+ dos_new_client_conn(&or_conn, NULL);
}
}
@@ -88,7 +88,7 @@ test_dos_conn_creation(void *arg)
dos_conn_addr_get_defense_type(addr));
/* Register another conn and check that new conns are not allowed anymore */
- dos_new_client_conn(&or_conn);
+ dos_new_client_conn(&or_conn, NULL);
tt_int_op(DOS_CONN_DEFENSE_CLOSE, OP_EQ,
dos_conn_addr_get_defense_type(addr));
@@ -98,7 +98,7 @@ test_dos_conn_creation(void *arg)
dos_conn_addr_get_defense_type(addr));
/* Register another conn and see that defense measures get reactivated */
- dos_new_client_conn(&or_conn);
+ dos_new_client_conn(&or_conn, NULL);
tt_int_op(DOS_CONN_DEFENSE_CLOSE, OP_EQ,
dos_conn_addr_get_defense_type(addr));
@@ -153,7 +153,7 @@ test_dos_circuit_creation(void *arg)
* circuit counting subsystem */
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, addr, NULL, now);
for (i = 0; i < min_conc_conns_for_cc ; i++) {
- dos_new_client_conn(&or_conn);
+ dos_new_client_conn(&or_conn, NULL);
}
/* Register new circuits for this client and conn, but not enough to get
@@ -217,7 +217,7 @@ test_dos_bucket_refill(void *arg)
/* Register this client */
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, addr, NULL, now);
- dos_new_client_conn(&or_conn);
+ dos_new_client_conn(&or_conn, NULL);
/* Fetch this client from the geoip cache and get its DoS structs */
clientmap_entry_t *entry = geoip_lookup_client(addr, NULL,
@@ -460,11 +460,11 @@ test_known_relay(void *arg)
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &or_conn.real_addr, NULL, 0);
/* Suppose we have 5 connections in rapid succession, the counter should
* always be 0 because we should ignore this. */
- dos_new_client_conn(&or_conn);
- dos_new_client_conn(&or_conn);
- dos_new_client_conn(&or_conn);
- dos_new_client_conn(&or_conn);
- dos_new_client_conn(&or_conn);
+ dos_new_client_conn(&or_conn, NULL);
+ dos_new_client_conn(&or_conn, NULL);
+ dos_new_client_conn(&or_conn, NULL);
+ dos_new_client_conn(&or_conn, NULL);
+ dos_new_client_conn(&or_conn, NULL);
entry = geoip_lookup_client(&or_conn.real_addr, NULL, GEOIP_CLIENT_CONNECT);
tt_assert(entry);
/* We should have a count of 0. */
@@ -474,8 +474,8 @@ test_known_relay(void *arg)
* connection and see if we do get it. */
tor_addr_parse(&or_conn.real_addr, "42.42.42.43");
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &or_conn.real_addr, NULL, 0);
- dos_new_client_conn(&or_conn);
- dos_new_client_conn(&or_conn);
+ dos_new_client_conn(&or_conn, NULL);
+ dos_new_client_conn(&or_conn, NULL);
entry = geoip_lookup_client(&or_conn.real_addr, NULL, GEOIP_CLIENT_CONNECT);
tt_assert(entry);
/* We should have a count of 2. */
diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c
index 8ea550b65f..f25bba3584 100644
--- a/src/test/test_hs_cache.c
+++ b/src/test/test_hs_cache.c
@@ -370,7 +370,7 @@ test_hsdir_revision_counter_check(void *arg)
hs_descriptor_t *published_desc = NULL;
char *published_desc_str = NULL;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
char *received_desc_str = NULL;
hs_descriptor_t *received_desc = NULL;
@@ -407,11 +407,11 @@ test_hsdir_revision_counter_check(void *arg)
const ed25519_public_key_t *blinded_key;
blinded_key = &published_desc->plaintext_data.blinded_pubkey;
- hs_get_subcredential(&signing_kp.pubkey, blinded_key, subcredential);
+ hs_get_subcredential(&signing_kp.pubkey, blinded_key, &subcredential);
received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
retval = hs_desc_decode_descriptor(received_desc_str,
- subcredential, NULL, &received_desc);
+ &subcredential, NULL, &received_desc);
tt_int_op(retval, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(received_desc);
@@ -444,7 +444,7 @@ test_hsdir_revision_counter_check(void *arg)
received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
retval = hs_desc_decode_descriptor(received_desc_str,
- subcredential, NULL, &received_desc);
+ &subcredential, NULL, &received_desc);
tt_int_op(retval, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(received_desc);
@@ -476,7 +476,7 @@ test_client_cache(void *arg)
ed25519_keypair_t signing_kp;
hs_descriptor_t *published_desc = NULL;
char *published_desc_str = NULL;
- uint8_t wanted_subcredential[DIGEST256_LEN];
+ hs_subcredential_t wanted_subcredential;
response_handler_args_t *args = NULL;
dir_connection_t *conn = NULL;
@@ -505,8 +505,10 @@ test_client_cache(void *arg)
retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
NULL, &published_desc_str);
tt_int_op(retval, OP_EQ, 0);
- memcpy(wanted_subcredential, published_desc->subcredential, DIGEST256_LEN);
- tt_assert(!fast_mem_is_zero((char*)wanted_subcredential, DIGEST256_LEN));
+ memcpy(&wanted_subcredential, &published_desc->subcredential,
+ sizeof(hs_subcredential_t));
+ tt_assert(!fast_mem_is_zero((char*)wanted_subcredential.subcred,
+ DIGEST256_LEN));
}
/* Test handle_response_fetch_hsdesc_v3() */
@@ -540,8 +542,9 @@ test_client_cache(void *arg)
const hs_descriptor_t *cached_desc = NULL;
cached_desc = hs_cache_lookup_as_client(&signing_kp.pubkey);
tt_assert(cached_desc);
- tt_mem_op(cached_desc->subcredential, OP_EQ, wanted_subcredential,
- DIGEST256_LEN);
+ tt_mem_op(cached_desc->subcredential.subcred,
+ OP_EQ, wanted_subcredential.subcred,
+ SUBCRED_LEN);
}
/* Progress time to next TP and check that desc was cleaned */
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index 5f7fe9c404..3d6422a83c 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -433,9 +433,10 @@ test_client_pick_intro(void *arg)
const hs_descriptor_t *fetched_desc =
hs_cache_lookup_as_client(&service_kp.pubkey);
tt_assert(fetched_desc);
- tt_mem_op(fetched_desc->subcredential, OP_EQ, desc->subcredential,
- DIGEST256_LEN);
- tt_assert(!fast_mem_is_zero((char*)fetched_desc->subcredential,
+ tt_mem_op(fetched_desc->subcredential.subcred,
+ OP_EQ, desc->subcredential.subcred,
+ SUBCRED_LEN);
+ tt_assert(!fast_mem_is_zero((char*)fetched_desc->subcredential.subcred,
DIGEST256_LEN));
tor_free(encoded);
}
@@ -965,6 +966,7 @@ test_close_intro_circuits_new_desc(void *arg)
(void) arg;
hs_init();
+ rend_cache_init();
/* This is needed because of the client cache expiration timestamp is based
* on having a consensus. See cached_client_descriptor_has_expired(). */
@@ -989,6 +991,51 @@ test_close_intro_circuits_new_desc(void *arg)
circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
ocirc = TO_ORIGIN_CIRCUIT(circ);
+ /* Build a descriptor _without_ client authorization and thus not
+ * decryptable. Make sure the close circuit code path is not triggered. */
+ {
+ char *desc_encoded = NULL;
+ uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
+ curve25519_keypair_t client_kp;
+ hs_descriptor_t *desc = NULL;
+
+ tt_int_op(0, OP_EQ, curve25519_keypair_generate(&client_kp, 0));
+ crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie));
+
+ desc = hs_helper_build_hs_desc_with_client_auth(descriptor_cookie,
+ &client_kp.pubkey,
+ &service_kp);
+ tt_assert(desc);
+ ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie,
+ &desc_encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Associate descriptor intro key with the dummy circuit. */
+ const hs_desc_intro_point_t *ip =
+ smartlist_get(desc->encrypted_data.intro_points, 0);
+ tt_assert(ip);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
+ ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk,
+ &ip->auth_key_cert->signed_key);
+ hs_descriptor_free(desc);
+ tt_assert(desc_encoded);
+ /* Put it in the cache. Should not be decrypted since the client
+ * authorization creds were not added to the global map. */
+ ret = hs_cache_store_as_client(desc_encoded, &service_kp.pubkey);
+ tor_free(desc_encoded);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
+
+ /* Clean cache with a future timestamp. It will trigger the clean up and
+ * attempt to close the circuit but only if the descriptor is decryptable.
+ * Cache object should be removed and circuit untouched. */
+ hs_cache_clean_as_client(mock_ns.valid_after + (60 * 60 * 24));
+ tt_assert(!hs_cache_lookup_as_client(&service_kp.pubkey));
+
+ /* Make sure the circuit still there. */
+ tt_assert(circuit_get_next_intro_circ(NULL, true));
+ /* Get rid of the ident, it will be replaced in the next tests. */
+ hs_ident_circuit_free(ocirc->hs_ident);
+ }
+
/* Build the first descriptor and cache it. */
{
char *encoded;
diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c
index 61306778d4..4a161db334 100644
--- a/src/test/test_hs_common.c
+++ b/src/test/test_hs_common.c
@@ -32,7 +32,7 @@
#include "app/config/statefile.h"
#include "core/or/circuitlist.h"
#include "feature/dirauth/shared_random.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/nodelist/microdesc_st.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -53,14 +53,14 @@ test_validate_address(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = hs_address_is_valid("blah");
tt_int_op(ret, OP_EQ, 0);
- expect_log_msg_containing("has an invalid length");
+ expect_log_msg_containing("Invalid length");
teardown_capture_of_logs();
setup_full_capture_of_logs(LOG_WARN);
ret = hs_address_is_valid(
"p3xnclpu4mu22dwaurjtsybyqk4xfjmcfz6z62yl24uwmhjatiwnlnadb");
tt_int_op(ret, OP_EQ, 0);
- expect_log_msg_containing("has an invalid length");
+ expect_log_msg_containing("Invalid length");
teardown_capture_of_logs();
/* Invalid checksum (taken from prop224) */
@@ -83,7 +83,7 @@ test_validate_address(void *arg)
ret = hs_address_is_valid(
"????????????????????????????????????????????????????????");
tt_int_op(ret, OP_EQ, 0);
- expect_log_msg_containing("can't be decoded");
+ expect_log_msg_containing("Unable to base32 decode");
teardown_capture_of_logs();
/* Valid address. */
@@ -853,7 +853,7 @@ test_time_between_tp_and_srv(void *arg)
tt_int_op(ret, OP_EQ, 0);
ret = parse_rfc1123_time("Sat, 26 Oct 1985 01:00:00 UTC", &ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -861,7 +861,7 @@ test_time_between_tp_and_srv(void *arg)
tt_int_op(ret, OP_EQ, 0);
ret = parse_rfc1123_time("Sat, 26 Oct 1985 12:00:00 UTC", &ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -869,7 +869,7 @@ test_time_between_tp_and_srv(void *arg)
tt_int_op(ret, OP_EQ, 0);
ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", &ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 1);
@@ -877,7 +877,7 @@ test_time_between_tp_and_srv(void *arg)
tt_int_op(ret, OP_EQ, 0);
ret = parse_rfc1123_time("Sat, 27 Oct 1985 00:00:00 UTC", &ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 1);
@@ -885,7 +885,7 @@ test_time_between_tp_and_srv(void *arg)
tt_int_op(ret, OP_EQ, 0);
ret = parse_rfc1123_time("Sat, 27 Oct 1985 01:00:00 UTC", &ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -1372,7 +1372,7 @@ run_reachability_scenario(const reachability_cfg_t *cfg, int num_scenario)
&mock_service_ns->valid_until);
set_consensus_times(cfg->service_valid_until,
&mock_service_ns->fresh_until);
- voting_schedule_recalculate_timing(get_options(),
+ dirauth_sched_recalculate_timing(get_options(),
mock_service_ns->valid_after);
/* Check that service is in the right time period point */
tt_int_op(hs_in_period_between_tp_and_srv(mock_service_ns, 0), OP_EQ,
@@ -1385,7 +1385,7 @@ run_reachability_scenario(const reachability_cfg_t *cfg, int num_scenario)
&mock_client_ns->valid_until);
set_consensus_times(cfg->client_valid_until,
&mock_client_ns->fresh_until);
- voting_schedule_recalculate_timing(get_options(),
+ dirauth_sched_recalculate_timing(get_options(),
mock_client_ns->valid_after);
/* Check that client is in the right time period point */
tt_int_op(hs_in_period_between_tp_and_srv(mock_client_ns, 0), OP_EQ,
@@ -1608,7 +1608,7 @@ helper_set_consensus_and_system_time(networkstatus_t *ns, int position)
} else {
tt_assert(0);
}
- voting_schedule_recalculate_timing(get_options(), ns->valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns->valid_after);
/* Set system time: pretend to be just 2 minutes before consensus expiry */
real_time = ns->valid_until - 120;
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index 43ac5490a1..61ccd3f919 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -221,7 +221,7 @@ test_decode_descriptor(void *arg)
hs_descriptor_t *desc = NULL;
hs_descriptor_t *decoded = NULL;
hs_descriptor_t *desc_no_ip = NULL;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
(void) arg;
@@ -230,10 +230,10 @@ test_decode_descriptor(void *arg)
desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
hs_helper_get_subcred_from_identity_keypair(&signing_kp,
- subcredential);
+ &subcredential);
/* Give some bad stuff to the decoding function. */
- ret = hs_desc_decode_descriptor("hladfjlkjadf", subcredential,
+ ret = hs_desc_decode_descriptor("hladfjlkjadf", &subcredential,
NULL, &decoded);
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
@@ -241,7 +241,7 @@ test_decode_descriptor(void *arg)
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(encoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential, NULL, &decoded);
+ ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded);
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(decoded);
@@ -253,7 +253,7 @@ test_decode_descriptor(void *arg)
ret = ed25519_keypair_generate(&signing_kp_no_ip, 0);
tt_int_op(ret, OP_EQ, 0);
hs_helper_get_subcred_from_identity_keypair(&signing_kp_no_ip,
- subcredential);
+ &subcredential);
desc_no_ip = hs_helper_build_hs_desc_no_ip(&signing_kp_no_ip);
tt_assert(desc_no_ip);
tor_free(encoded);
@@ -262,7 +262,7 @@ test_decode_descriptor(void *arg)
tt_int_op(ret, OP_EQ, 0);
tt_assert(encoded);
hs_descriptor_free(decoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential, NULL, &decoded);
+ ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded);
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(decoded);
}
@@ -286,14 +286,14 @@ test_decode_descriptor(void *arg)
&auth_ephemeral_kp.pubkey, CURVE25519_PUBKEY_LEN);
hs_helper_get_subcred_from_identity_keypair(&signing_kp,
- subcredential);
+ &subcredential);
/* Build and add the auth client to the descriptor. */
clients = desc->superencrypted_data.clients;
if (!clients) {
clients = smartlist_new();
}
- hs_desc_build_authorized_client(subcredential,
+ hs_desc_build_authorized_client(&subcredential,
&client_kp.pubkey,
&auth_ephemeral_kp.seckey,
descriptor_cookie, client);
@@ -315,21 +315,21 @@ test_decode_descriptor(void *arg)
/* If we do not have the client secret key, the decoding must fail. */
hs_descriptor_free(decoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential,
+ ret = hs_desc_decode_descriptor(encoded, &subcredential,
NULL, &decoded);
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
tt_assert(!decoded);
/* If we have an invalid client secret key, the decoding must fail. */
hs_descriptor_free(decoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential,
+ ret = hs_desc_decode_descriptor(encoded, &subcredential,
&invalid_client_kp.seckey, &decoded);
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_BAD_CLIENT_AUTH);
tt_assert(!decoded);
/* If we have the client secret key, the decoding must succeed and the
* decoded descriptor must be correct. */
- ret = hs_desc_decode_descriptor(encoded, subcredential,
+ ret = hs_desc_decode_descriptor(encoded, &subcredential,
&client_kp.seckey, &decoded);
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(decoded);
@@ -762,7 +762,7 @@ test_build_authorized_client(void *arg)
"07d087f1d8c68393721f6e70316d3b29";
const char client_pubkey_b16[] =
"8c1298fa6050e372f8598f6deca32e27b0ad457741422c2629ebb132cf7fae37";
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
char *mem_op_hex_tmp=NULL;
(void) arg;
@@ -774,7 +774,7 @@ test_build_authorized_client(void *arg)
tt_int_op(ret, OP_EQ, 0);
curve25519_public_key_generate(&client_auth_pk, &client_auth_sk);
- memset(subcredential, 42, sizeof(subcredential));
+ memset(subcredential.subcred, 42, sizeof(subcredential));
desc_client = tor_malloc_zero(sizeof(hs_desc_authorized_client_t));
@@ -795,7 +795,7 @@ test_build_authorized_client(void *arg)
testing_enable_prefilled_rng("\x01", 1);
- hs_desc_build_authorized_client(subcredential,
+ hs_desc_build_authorized_client(&subcredential,
&client_auth_pk, &auth_ephemeral_sk,
descriptor_cookie, desc_client);
diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c
index 5337188427..3b6e3fd213 100644
--- a/src/test/test_hs_intropoint.c
+++ b/src/test/test_hs_intropoint.c
@@ -757,12 +757,15 @@ test_introduce1_validation(void *arg)
cell = helper_create_introduce1_cell();
tt_assert(cell);
+#ifndef ALL_BUGS_ARE_FATAL
/* It should NOT be a legacy cell which will trigger a BUG(). */
memset(cell->legacy_key_id, 'a', sizeof(cell->legacy_key_id));
tor_capture_bugs_(1);
ret = validate_introduce1_parsed_cell(cell);
tor_end_capture_bugs_();
tt_int_op(ret, OP_EQ, -1);
+#endif
+
/* Reset legacy ID and make sure it's correct. */
memset(cell->legacy_key_id, 0, sizeof(cell->legacy_key_id));
ret = validate_introduce1_parsed_cell(cell);
diff --git a/src/test/test_hs_ntor.c b/src/test/test_hs_ntor.c
index 4f98bc85dc..7867740a1a 100644
--- a/src/test/test_hs_ntor.c
+++ b/src/test/test_hs_ntor.c
@@ -23,7 +23,7 @@ test_hs_ntor(void *arg)
{
int retval;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
ed25519_keypair_t service_intro_auth_keypair;
curve25519_keypair_t service_intro_enc_keypair;
@@ -42,7 +42,7 @@ test_hs_ntor(void *arg)
/* Generate fake data for this unittest */
{
/* Generate fake subcredential */
- memset(subcredential, 'Z', DIGEST256_LEN);
+ memset(subcredential.subcred, 'Z', DIGEST256_LEN);
/* service */
curve25519_keypair_generate(&service_intro_enc_keypair, 0);
@@ -57,7 +57,7 @@ test_hs_ntor(void *arg)
hs_ntor_client_get_introduce1_keys(&service_intro_auth_keypair.pubkey,
&service_intro_enc_keypair.pubkey,
&client_ephemeral_enc_keypair,
- subcredential,
+ &subcredential,
&client_hs_ntor_intro_cell_keys);
tt_int_op(retval, OP_EQ, 0);
@@ -66,7 +66,7 @@ test_hs_ntor(void *arg)
hs_ntor_service_get_introduce1_keys(&service_intro_auth_keypair.pubkey,
&service_intro_enc_keypair,
&client_ephemeral_enc_keypair.pubkey,
- subcredential,
+ &subcredential,
&service_hs_ntor_intro_cell_keys);
tt_int_op(retval, OP_EQ, 0);
diff --git a/src/test/test_hs_ntor_cl.c b/src/test/test_hs_ntor_cl.c
index a7cebc6af4..3acd7ef0bc 100644
--- a/src/test/test_hs_ntor_cl.c
+++ b/src/test/test_hs_ntor_cl.c
@@ -53,7 +53,7 @@ client1(int argc, char **argv)
curve25519_public_key_t intro_enc_pubkey;
ed25519_public_key_t intro_auth_pubkey;
curve25519_keypair_t client_ephemeral_enc_keypair;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
/* Output */
hs_ntor_intro_cell_keys_t hs_ntor_intro_cell_keys;
@@ -65,7 +65,7 @@ client1(int argc, char **argv)
BASE16(3, intro_enc_pubkey.public_key, CURVE25519_PUBKEY_LEN);
BASE16(4, client_ephemeral_enc_keypair.seckey.secret_key,
CURVE25519_SECKEY_LEN);
- BASE16(5, subcredential, DIGEST256_LEN);
+ BASE16(5, subcredential.subcred, DIGEST256_LEN);
/* Generate keypair */
curve25519_public_key_generate(&client_ephemeral_enc_keypair.pubkey,
@@ -74,7 +74,7 @@ client1(int argc, char **argv)
retval = hs_ntor_client_get_introduce1_keys(&intro_auth_pubkey,
&intro_enc_pubkey,
&client_ephemeral_enc_keypair,
- subcredential,
+ &subcredential,
&hs_ntor_intro_cell_keys);
if (retval < 0) {
goto done;
@@ -106,7 +106,7 @@ server1(int argc, char **argv)
curve25519_keypair_t intro_enc_keypair;
ed25519_public_key_t intro_auth_pubkey;
curve25519_public_key_t client_ephemeral_enc_pubkey;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
/* Output */
hs_ntor_intro_cell_keys_t hs_ntor_intro_cell_keys;
@@ -119,7 +119,7 @@ server1(int argc, char **argv)
BASE16(2, intro_auth_pubkey.pubkey, ED25519_PUBKEY_LEN);
BASE16(3, intro_enc_keypair.seckey.secret_key, CURVE25519_SECKEY_LEN);
BASE16(4, client_ephemeral_enc_pubkey.public_key, CURVE25519_PUBKEY_LEN);
- BASE16(5, subcredential, DIGEST256_LEN);
+ BASE16(5, subcredential.subcred, DIGEST256_LEN);
/* Generate keypair */
curve25519_public_key_generate(&intro_enc_keypair.pubkey,
@@ -130,7 +130,7 @@ server1(int argc, char **argv)
retval = hs_ntor_service_get_introduce1_keys(&intro_auth_pubkey,
&intro_enc_keypair,
&client_ephemeral_enc_pubkey,
- subcredential,
+ &subcredential,
&hs_ntor_intro_cell_keys);
if (retval < 0) {
goto done;
@@ -188,7 +188,7 @@ client2(int argc, char **argv)
ed25519_public_key_t intro_auth_pubkey;
curve25519_keypair_t client_ephemeral_enc_keypair;
curve25519_public_key_t service_ephemeral_rend_pubkey;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
/* Output */
hs_ntor_rend_cell_keys_t hs_ntor_rend_cell_keys;
@@ -201,7 +201,7 @@ client2(int argc, char **argv)
CURVE25519_SECKEY_LEN);
BASE16(4, intro_enc_pubkey.public_key, CURVE25519_PUBKEY_LEN);
BASE16(5, service_ephemeral_rend_pubkey.public_key, CURVE25519_PUBKEY_LEN);
- BASE16(6, subcredential, DIGEST256_LEN);
+ BASE16(6, subcredential.subcred, DIGEST256_LEN);
/* Generate keypair */
curve25519_public_key_generate(&client_ephemeral_enc_keypair.pubkey,
diff --git a/src/test/test_hs_ob.c b/src/test/test_hs_ob.c
new file mode 100644
index 0000000000..7f40187b5f
--- /dev/null
+++ b/src/test/test_hs_ob.c
@@ -0,0 +1,268 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_ob.c
+ * \brief Test hidden service onion balance functionality.
+ */
+
+#define CONFIG_PRIVATE
+#define HS_SERVICE_PRIVATE
+#define HS_OB_PRIVATE
+
+#include "test/test.h"
+#include "test/test_helpers.h"
+#include "test/log_test_helpers.h"
+
+#include "app/config/config.h"
+#include "feature/hs/hs_config.h"
+#include "feature/hs/hs_ob.h"
+#include "feature/hs/hs_service.h"
+#include "feature/nodelist/networkstatus.h"
+#include "feature/nodelist/networkstatus_st.h"
+
+static ed25519_keypair_t onion_addr_kp_1;
+static char onion_addr_1[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+
+static ed25519_keypair_t onion_addr_kp_2;
+static char onion_addr_2[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+
+static bool config_is_good = true;
+
+static int
+helper_tor_config(const char *conf)
+{
+ int ret = -1;
+ or_options_t *options = helper_parse_options(conf);
+ tt_assert(options);
+ ret = hs_config_service_all(options, 0);
+ done:
+ or_options_free(options);
+ return ret;
+}
+
+static networkstatus_t mock_ns;
+
+static networkstatus_t *
+mock_networkstatus_get_live_consensus(time_t now)
+{
+ (void) now;
+ return &mock_ns;
+}
+
+static char *
+mock_read_file_to_str(const char *filename, int flags, struct stat *stat_out)
+{
+ char *ret = NULL;
+
+ (void) flags;
+ (void) stat_out;
+
+ if (!strcmp(filename, get_fname("hs3" PATH_SEPARATOR "ob_config"))) {
+ if (config_is_good) {
+ tor_asprintf(&ret, "MasterOnionAddress %s.onion\n"
+ "MasterOnionAddress %s.onion\n",
+ onion_addr_1, onion_addr_2);
+ } else {
+ tor_asprintf(&ret, "MasterOnionAddress JUNKJUNKJUNK.onion\n"
+ "UnknownOption BLAH\n");
+ }
+ goto done;
+ }
+
+ done:
+ return ret;
+}
+
+static void
+test_parse_config_file(void *arg)
+{
+ int ret;
+ char *conf = NULL;
+ const ed25519_public_key_t *pkey;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(read_file_to_str, mock_read_file_to_str);
+
+#define fmt_conf \
+ "HiddenServiceDir %s\n" \
+ "HiddenServicePort 22\n" \
+ "HiddenServiceOnionBalanceInstance 1\n"
+ tor_asprintf(&conf, fmt_conf, get_fname("hs3"));
+#undef fmt_conf
+
+ /* Build the OB frontend onion addresses. */
+ ed25519_keypair_generate(&onion_addr_kp_1, 0);
+ hs_build_address(&onion_addr_kp_1.pubkey, HS_VERSION_THREE, onion_addr_1);
+ ed25519_keypair_generate(&onion_addr_kp_2, 0);
+ hs_build_address(&onion_addr_kp_2.pubkey, HS_VERSION_THREE, onion_addr_2);
+
+ ret = helper_tor_config(conf);
+ tor_free(conf);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Load the keys for the service. After that, the v3 service should be
+ * registered in the global map and we'll be able to access it. */
+ tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
+ hs_service_load_all_keys();
+ tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
+ const hs_service_t *s = get_first_service();
+ tt_assert(s);
+ tt_assert(s->config.ob_master_pubkeys);
+ tt_assert(hs_ob_service_is_instance(s));
+ tt_assert(smartlist_len(s->config.ob_master_pubkeys) == 2);
+
+ /* Test the public keys we've added. */
+ pkey = smartlist_get(s->config.ob_master_pubkeys, 0);
+ tt_mem_op(&onion_addr_kp_1.pubkey, OP_EQ, pkey, ED25519_PUBKEY_LEN);
+ pkey = smartlist_get(s->config.ob_master_pubkeys, 1);
+ tt_mem_op(&onion_addr_kp_2.pubkey, OP_EQ, pkey, ED25519_PUBKEY_LEN);
+
+ done:
+ hs_free_all();
+
+ UNMOCK(read_file_to_str);
+}
+
+static void
+test_parse_config_file_bad(void *arg)
+{
+ int ret;
+ char *conf = NULL;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(read_file_to_str, mock_read_file_to_str);
+
+ /* Indicate mock_read_file_to_str() to use the bad config. */
+ config_is_good = false;
+
+#define fmt_conf \
+ "HiddenServiceDir %s\n" \
+ "HiddenServicePort 22\n" \
+ "HiddenServiceOnionBalanceInstance 1\n"
+ tor_asprintf(&conf, fmt_conf, get_fname("hs3"));
+#undef fmt_conf
+
+ setup_full_capture_of_logs(LOG_INFO);
+ ret = helper_tor_config(conf);
+ tor_free(conf);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("OnionBalance: MasterOnionAddress "
+ "JUNKJUNKJUNK.onion is invalid");
+ expect_log_msg_containing("Found unrecognized option \'UnknownOption\'; "
+ "saving it.");
+ teardown_capture_of_logs();
+
+ done:
+ hs_free_all();
+
+ UNMOCK(read_file_to_str);
+}
+
+static void
+test_get_subcredentials(void *arg)
+{
+ int ret;
+ hs_service_t *service = NULL;
+ hs_service_config_t config;
+ hs_subcredential_t *subcreds = NULL;
+
+ (void) arg;
+
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ /* Setup consensus with proper time so we can compute the time period. */
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+
+ config.ob_master_pubkeys = smartlist_new();
+ tt_assert(config.ob_master_pubkeys);
+
+ /* Set up an instance */
+ service = tor_malloc_zero(sizeof(hs_service_t));
+ service->config = config;
+ /* Setup the service descriptors */
+ service->desc_current = service_descriptor_new();
+ service->desc_next = service_descriptor_new();
+
+ /* First try to compute subcredentials but with no OB keys. Make sure that
+ * subcreds get NULLed. To do this check we first poison subcreds. */
+ subcreds = (void*)999;
+ tt_ptr_op(subcreds, OP_NE, NULL);
+ size_t num = compute_subcredentials(service, &subcreds);
+ tt_ptr_op(subcreds, OP_EQ, NULL);
+
+ /* Generate a keypair to add to the OB keys list. */
+ ed25519_keypair_generate(&onion_addr_kp_1, 0);
+ smartlist_add(config.ob_master_pubkeys, &onion_addr_kp_1.pubkey);
+
+ /* Set up the instance subcredentials */
+ char current_subcred[SUBCRED_LEN];
+ char next_subcred[SUBCRED_LEN];
+ memset(current_subcred, 'C', SUBCRED_LEN);
+ memset(next_subcred, 'N', SUBCRED_LEN);
+ memcpy(service->desc_current->desc->subcredential.subcred, current_subcred,
+ SUBCRED_LEN);
+ memcpy(service->desc_next->desc->subcredential.subcred, next_subcred,
+ SUBCRED_LEN);
+
+ /* See that subcreds are computed properly */
+ num = compute_subcredentials(service, &subcreds);
+ /* 5 subcredentials: 3 for the frontend, 2 for the instance */
+ tt_uint_op(num, OP_EQ, 5);
+ tt_ptr_op(subcreds, OP_NE, NULL);
+
+ /* Validate the subcredentials we just got. We'll build them oursevles with
+ * the right time period steps and compare. */
+ const uint64_t tp = hs_get_time_period_num(0);
+ const int steps[3] = {0, -1, 1};
+
+ unsigned int i;
+ for (i = 0; i < 3; i++) {
+ hs_subcredential_t subcredential;
+ ed25519_public_key_t blinded_pubkey;
+ hs_build_blinded_pubkey(&onion_addr_kp_1.pubkey, NULL, 0, tp + steps[i],
+ &blinded_pubkey);
+ hs_get_subcredential(&onion_addr_kp_1.pubkey, &blinded_pubkey,
+ &subcredential);
+ tt_mem_op(subcreds[i].subcred, OP_EQ, subcredential.subcred,
+ SUBCRED_LEN);
+ }
+
+ tt_mem_op(subcreds[i++].subcred, OP_EQ, current_subcred, SUBCRED_LEN);
+ tt_mem_op(subcreds[i++].subcred, OP_EQ, next_subcred, SUBCRED_LEN);
+
+ done:
+ tor_free(subcreds);
+
+ smartlist_free(config.ob_master_pubkeys);
+ if (service) {
+ memset(&service->config, 0, sizeof(hs_service_config_t));
+ hs_service_free(service);
+ }
+
+ UNMOCK(networkstatus_get_live_consensus);
+}
+
+struct testcase_t hs_ob_tests[] = {
+ { "parse_config_file", test_parse_config_file, TT_FORK,
+ NULL, NULL },
+ { "parse_config_file_bad", test_parse_config_file_bad, TT_FORK,
+ NULL, NULL },
+
+ { "get_subcredentials", test_get_subcredentials, TT_FORK,
+ NULL, NULL },
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index e33d593d94..9966bd108d 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -44,13 +44,15 @@
#include "core/or/versions.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/shared_random_state.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/hs/hs_circuit.h"
#include "feature/hs/hs_circuitmap.h"
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_config.h"
#include "feature/hs/hs_ident.h"
+#include "feature/hs/hs_ob.h"
+#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_intropoint.h"
#include "feature/hs/hs_service.h"
#include "feature/nodelist/networkstatus.h"
@@ -87,6 +89,13 @@ mock_networkstatus_get_live_consensus(time_t now)
return &mock_ns;
}
+static networkstatus_t *
+mock_networkstatus_get_live_consensus_null(time_t now)
+{
+ (void) now;
+ return NULL;
+}
+
static or_state_t *dummy_state = NULL;
/* Mock function to get fake or state (used for rev counters) */
@@ -109,6 +118,9 @@ mock_circuit_mark_for_close(circuit_t *circ, int reason, int line,
return;
}
+static size_t relay_payload_len;
+static char relay_payload[RELAY_PAYLOAD_SIZE];
+
static int
mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
uint8_t relay_command, const char *payload,
@@ -124,6 +136,24 @@ mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
(void) cpath_layer;
(void) filename;
(void) lineno;
+
+ memcpy(relay_payload, payload, payload_len);
+ relay_payload_len = payload_len;
+
+ return 0;
+}
+
+static unsigned int num_intro_points = 0;
+static unsigned int
+mock_count_desc_circuit_established(const hs_service_descriptor_t *desc)
+{
+ (void) desc;
+ return num_intro_points;
+}
+
+static int
+mock_router_have_minimum_dir_info_false(void)
+{
return 0;
}
@@ -1160,7 +1190,7 @@ test_closing_intro_circs(void *arg)
/** Test sending and receiving introduce2 cells */
static void
-test_introduce2(void *arg)
+test_bad_introduce2(void *arg)
{
int ret;
int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
@@ -1356,7 +1386,7 @@ test_rotate_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
update_approx_time(mock_ns.valid_after+1);
now = mock_ns.valid_after+1;
@@ -1397,7 +1427,7 @@ test_rotate_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 27 Oct 1985 02:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
update_approx_time(mock_ns.valid_after+1);
now = mock_ns.valid_after+1;
@@ -1465,7 +1495,7 @@ test_build_update_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 26 Oct 1985 04:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
update_approx_time(mock_ns.valid_after+1);
@@ -1696,7 +1726,7 @@ test_build_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 26 Oct 1985 04:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
/* Generate a valid number of fake auth clients when a client authorization
* is disabled. */
@@ -1797,7 +1827,7 @@ test_upload_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
update_approx_time(mock_ns.valid_after+1);
now = mock_ns.valid_after+1;
@@ -2169,6 +2199,490 @@ test_export_client_circuit_id(void *arg)
tor_free(cp2);
}
+static smartlist_t *
+mock_node_get_link_specifier_smartlist(const node_t *node, bool direct_conn)
+{
+ (void) node;
+ (void) direct_conn;
+
+ smartlist_t *lspecs = smartlist_new();
+ link_specifier_t *ls_legacy = link_specifier_new();
+ smartlist_add(lspecs, ls_legacy);
+
+ return lspecs;
+}
+
+static node_t *fake_node = NULL;
+
+static const node_t *
+mock_build_state_get_exit_node(cpath_build_state_t *state)
+{
+ (void) state;
+
+ if (!fake_node) {
+ curve25519_secret_key_t seckey;
+ curve25519_secret_key_generate(&seckey, 0);
+
+ fake_node = tor_malloc_zero(sizeof(node_t));
+ fake_node->ri = tor_malloc_zero(sizeof(routerinfo_t));
+ fake_node->ri->onion_curve25519_pkey =
+ tor_malloc_zero(sizeof(curve25519_public_key_t));
+ curve25519_public_key_generate(fake_node->ri->onion_curve25519_pkey,
+ &seckey);
+ }
+
+ return fake_node;
+}
+
+static void
+mock_launch_rendezvous_point_circuit(const hs_service_t *service,
+ const hs_service_intro_point_t *ip,
+ const hs_cell_introduce2_data_t *data)
+{
+ (void) service;
+ (void) ip;
+ (void) data;
+ return;
+}
+
+/**
+ * Test that INTRO2 cells are handled well by onion services in the normal
+ * case and also when onionbalance is enabled.
+ */
+static void
+test_intro2_handling(void *arg)
+{
+ (void)arg;
+
+ MOCK(build_state_get_exit_node, mock_build_state_get_exit_node);
+ MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);
+ MOCK(node_get_link_specifier_smartlist,
+ mock_node_get_link_specifier_smartlist);
+ MOCK(launch_rendezvous_point_circuit, mock_launch_rendezvous_point_circuit);
+
+ memset(relay_payload, 0, sizeof(relay_payload));
+
+ int retval;
+ time_t now = 0101010101;
+ update_approx_time(now);
+
+ /** OK this is the play:
+ *
+ * In Act I, we have a standalone onion service X (without onionbalance
+ * enabled). We test that X can properly handle INTRO2 cells sent by a
+ * client Alice.
+ *
+ * In Act II, we create an onionbalance setup with frontend being Z which
+ * includes instances X and Y. We then setup onionbalance on X and test that
+ * Alice who addresses Z can communicate with X through INTRO2 cells.
+ *
+ * In Act III, we test that Alice can also communicate with X
+ * directly even tho onionbalance is enabled.
+ *
+ * And finally in Act IV, we check various cases where the INTRO2 cell
+ * should not go through because the subcredentials don't line up
+ * (e.g. Alice sends INTRO2 to X using Y's subcredential).
+ */
+
+ /** Let's start with some setup! Create the instances and the frontend
+ service, create Alice, etc: */
+
+ /* Create instance X */
+ hs_service_t x_service;
+ memset(&x_service, 0, sizeof(hs_service_t));
+ /* Disable onionbalance */
+ x_service.config.ob_master_pubkeys = NULL;
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0,0);
+
+ /* Create subcredential for x: */
+ ed25519_keypair_t x_identity_keypair;
+ hs_subcredential_t x_subcred;
+ ed25519_keypair_generate(&x_identity_keypair, 0);
+ hs_helper_get_subcred_from_identity_keypair(&x_identity_keypair,
+ &x_subcred);
+
+ /* Create the x instance's intro point */
+ hs_service_intro_point_t *x_ip = NULL;
+ {
+ curve25519_secret_key_t seckey;
+ curve25519_public_key_t pkey;
+ curve25519_secret_key_generate(&seckey, 0);
+ curve25519_public_key_generate(&pkey, &seckey);
+
+ node_t intro_node;
+ memset(&intro_node, 0, sizeof(intro_node));
+ routerinfo_t ri;
+ memset(&ri, 0, sizeof(routerinfo_t));
+ ri.onion_curve25519_pkey = &pkey;
+ intro_node.ri = &ri;
+
+ x_ip = service_intro_point_new(&intro_node);
+ }
+
+ /* Create z frontend's subcredential */
+ ed25519_keypair_t z_identity_keypair;
+ hs_subcredential_t z_subcred;
+ ed25519_keypair_generate(&z_identity_keypair, 0);
+ hs_helper_get_subcred_from_identity_keypair(&z_identity_keypair,
+ &z_subcred);
+
+ /* Create y instance's subcredential */
+ ed25519_keypair_t y_identity_keypair;
+ hs_subcredential_t y_subcred;
+ ed25519_keypair_generate(&y_identity_keypair, 0);
+ hs_helper_get_subcred_from_identity_keypair(&y_identity_keypair,
+ &y_subcred);
+
+ /* Create Alice's intro point */
+ hs_desc_intro_point_t *alice_ip;
+ ed25519_keypair_t signing_kp;
+ ed25519_keypair_generate(&signing_kp, 0);
+ alice_ip = hs_helper_build_intro_point(&signing_kp, now, "1.2.3.4", 0,
+ &x_ip->auth_key_kp,
+ &x_ip->enc_key_kp);
+
+ /* Create Alice's intro and rend circuits */
+ origin_circuit_t *intro_circ = origin_circuit_new();
+ intro_circ->cpath = tor_malloc_zero(sizeof(crypt_path_t));
+ intro_circ->cpath->prev = intro_circ->cpath;
+ intro_circ->hs_ident = tor_malloc_zero(sizeof(*intro_circ->hs_ident));
+ origin_circuit_t rend_circ;
+ rend_circ.hs_ident = tor_malloc_zero(sizeof(*rend_circ.hs_ident));
+ curve25519_keypair_generate(&rend_circ.hs_ident->rendezvous_client_kp, 0);
+ memset(rend_circ.hs_ident->rendezvous_cookie, 'r', HS_REND_COOKIE_LEN);
+
+ /* ************************************************************ */
+
+ /* Act I:
+ *
+ * Where Alice connects to X without onionbalance in the picture */
+
+ /* Create INTRODUCE1 */
+ tt_assert(fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
+ alice_ip, &x_subcred);
+
+ /* Check that the payload was written successfully */
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ tt_int_op(relay_payload_len, OP_NE, 0);
+
+ /* Handle the cell */
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload,relay_payload_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* ************************************************************ */
+
+ /* Act II:
+ *
+ * We now create an onionbalance setup with Z being the frontend and X and Y
+ * being the backend instances. Make sure that Alice can talk with the
+ * backend instance X even tho she thinks she is talking to the frontend Z.
+ */
+
+ /* Now configure the X instance to do onionbalance with Z as the frontend */
+ x_service.config.ob_master_pubkeys = smartlist_new();
+ smartlist_add(x_service.config.ob_master_pubkeys,
+ &z_identity_keypair.pubkey);
+
+ /* Create descriptors for x and load next descriptor with the x's
+ * subcredential so that it can accept connections for itself. */
+ x_service.desc_current = service_descriptor_new();
+ memset(x_service.desc_current->desc->subcredential.subcred, 'C',SUBCRED_LEN);
+ x_service.desc_next = service_descriptor_new();
+ memcpy(&x_service.desc_next->desc->subcredential, &x_subcred, SUBCRED_LEN);
+
+ /* Refresh OB keys */
+ hs_ob_refresh_keys(&x_service);
+
+ /* Create INTRODUCE1 from Alice to X through Z */
+ memset(relay_payload, 0, sizeof(relay_payload));
+ retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
+ alice_ip, &z_subcred);
+
+ /* Check that the payload was written successfully */
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ tt_int_op(relay_payload_len, OP_NE, 0);
+
+ /* Deliver INTRODUCE1 to X even tho it carries Z's subcredential */
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
+
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &z_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ replaycache_free(x_ip->replay_cache);
+ x_ip->replay_cache = replaycache_new(0, 0);
+
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
+
+ /* ************************************************************ */
+
+ /* Act III:
+ *
+ * Now send a direct INTRODUCE cell from Alice to X using X's subcredential
+ * and check that it succeeds even with onionbalance enabled.
+ */
+
+ /* Refresh OB keys (just to check for memleaks) */
+ hs_ob_refresh_keys(&x_service);
+
+ /* Create INTRODUCE1 from Alice to X using X's subcred. */
+ memset(relay_payload, 0, sizeof(relay_payload));
+ retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
+ alice_ip, &x_subcred);
+
+ /* Check that the payload was written successfully */
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ tt_int_op(relay_payload_len, OP_NE, 0);
+
+ /* Send INTRODUCE1 to X with X's subcredential (should succeed) */
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
+
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* ************************************************************ */
+
+ /* Act IV:
+ *
+ * Test cases where the INTRO2 cell should not be able to decode.
+ */
+
+ /* Try sending the exact same INTRODUCE2 cell again and see that the intro
+ * point replay cache triggers: */
+ setup_full_capture_of_logs(LOG_WARN);
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, -1);
+ expect_log_msg_containing("with the same ENCRYPTED section");
+ teardown_capture_of_logs();
+
+ /* Now cleanup the intro point replay cache but not the service replay cache
+ and see that this one triggers this time. */
+ replaycache_free(x_ip->replay_cache);
+ x_ip->replay_cache = replaycache_new(0, 0);
+ setup_full_capture_of_logs(LOG_INFO);
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, -1);
+ expect_log_msg_containing("with same REND_COOKIE");
+ teardown_capture_of_logs();
+
+ /* Now just to make sure cleanup both replay caches and make sure that the
+ cell gets through */
+ replaycache_free(x_ip->replay_cache);
+ x_ip->replay_cache = replaycache_new(0, 0);
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* As a final thing, create an INTRODUCE1 cell from Alice to X using Y's
+ * subcred (should fail since Y is just another instance and not the frontend
+ * service!) */
+ memset(relay_payload, 0, sizeof(relay_payload));
+ retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
+ alice_ip, &y_subcred);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check that the payload was written successfully */
+ tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ tt_int_op(relay_payload_len, OP_NE, 0);
+
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &y_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ /* Start cleaning up X */
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ smartlist_free(x_service.config.ob_master_pubkeys);
+ tor_free(x_service.ob_subcreds);
+ service_descriptor_free(x_service.desc_current);
+ service_descriptor_free(x_service.desc_next);
+ service_intro_point_free(x_ip);
+
+ /* Clean up Alice */
+ hs_desc_intro_point_free(alice_ip);
+ tor_free(rend_circ.hs_ident);
+
+ if (fake_node) {
+ tor_free(fake_node->ri->onion_curve25519_pkey);
+ tor_free(fake_node->ri);
+ tor_free(fake_node);
+ }
+
+ UNMOCK(build_state_get_exit_node);
+ UNMOCK(relay_send_command_from_edge_);
+ UNMOCK(node_get_link_specifier_smartlist);
+ UNMOCK(launch_rendezvous_point_circuit);
+}
+
+static void
+test_cannot_upload_descriptors(void *arg)
+{
+ int ret;
+ time_t now;
+ hs_service_t *service;
+
+ (void) arg;
+
+ hs_init();
+ MOCK(get_or_state,
+ get_or_state_replacement);
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ dummy_state = or_state_new();
+
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
+
+ update_approx_time(mock_ns.valid_after + 1);
+ now = mock_ns.valid_after + 1;
+
+ /* Create a service with no descriptor. It's added to the global map. */
+ service = hs_service_new(get_options());
+ tt_assert(service);
+ service->config.version = HS_VERSION_THREE;
+ ed25519_secret_key_generate(&service->keys.identity_sk, 0);
+ ed25519_public_key_generate(&service->keys.identity_pk,
+ &service->keys.identity_sk);
+ /* Register service to global map. */
+ ret = register_service(get_hs_service_map(), service);
+ tt_int_op(ret, OP_EQ, 0);
+ /* But first, build our descriptor. */
+ build_all_descriptors(now);
+
+ /* 1. Testing missing intro points reason. */
+ {
+ digest256map_t *cur = service->desc_current->intro_points.map;
+ digest256map_t *tmp = digest256map_new();
+ service->desc_current->intro_points.map = tmp;
+ service->desc_current->missing_intro_points = 1;
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ digest256map_free(tmp, tor_free_);
+ service->desc_current->intro_points.map = cur;
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Missing intro points");
+ teardown_capture_of_logs();
+ /* Reset. */
+ service->desc_current->missing_intro_points = 0;
+ }
+
+ /* 2. Testing non established intro points. */
+ {
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Intro circuits aren't yet all established (0/3).");
+ teardown_capture_of_logs();
+ }
+
+ /* We need to pass the established circuit tests and thus from now on, we
+ * MOCK this to return 3 intro points. */
+ MOCK(count_desc_circuit_established, mock_count_desc_circuit_established);
+ num_intro_points = 3;
+
+ /* 3. Testing non established intro points. */
+ {
+ service->desc_current->next_upload_time = now + 1000;
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Next upload time is");
+ teardown_capture_of_logs();
+ /* Reset. */
+ service->desc_current->next_upload_time = 0;
+ }
+
+ /* 4. Testing missing live consensus. */
+ {
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus_null);
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "No live consensus");
+ teardown_capture_of_logs();
+ /* Reset. */
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+ }
+
+ /* 5. Test missing minimum directory information. */
+ {
+ MOCK(router_have_minimum_dir_info,
+ mock_router_have_minimum_dir_info_false);
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Not enough directory information");
+ teardown_capture_of_logs();
+
+ /* Running it again shouldn't trigger anything due to rate limitation. */
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_no_log_entry();
+ teardown_capture_of_logs();
+ UNMOCK(router_have_minimum_dir_info);
+ }
+
+ /* Increase time and redo test (5) in order to test the rate limiting. */
+ update_approx_time(mock_ns.valid_after + 61);
+ {
+ MOCK(router_have_minimum_dir_info,
+ mock_router_have_minimum_dir_info_false);
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Not enough directory information");
+ teardown_capture_of_logs();
+ UNMOCK(router_have_minimum_dir_info);
+ }
+
+ done:
+ hs_free_all();
+ UNMOCK(count_desc_circuit_established);
+ UNMOCK(networkstatus_get_live_consensus);
+ UNMOCK(get_or_state);
+}
+
struct testcase_t hs_service_tests[] = {
{ "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, TT_FORK,
NULL, NULL },
@@ -2194,7 +2708,7 @@ struct testcase_t hs_service_tests[] = {
NULL, NULL },
{ "rdv_circuit_opened", test_rdv_circuit_opened, TT_FORK,
NULL, NULL },
- { "introduce2", test_introduce2, TT_FORK,
+ { "bad_introduce2", test_bad_introduce2, TT_FORK,
NULL, NULL },
{ "service_event", test_service_event, TT_FORK,
NULL, NULL },
@@ -2206,12 +2720,15 @@ struct testcase_t hs_service_tests[] = {
NULL, NULL },
{ "upload_descriptors", test_upload_descriptors, TT_FORK,
NULL, NULL },
+ { "cannot_upload_descriptors", test_cannot_upload_descriptors, TT_FORK,
+ NULL, NULL },
{ "rendezvous1_parsing", test_rendezvous1_parsing, TT_FORK,
NULL, NULL },
{ "authorized_client_config_equal", test_authorized_client_config_equal,
TT_FORK, NULL, NULL },
{ "export_client_circuit_id", test_export_client_circuit_id, TT_FORK,
NULL, NULL },
+ { "intro2_handling", test_intro2_handling, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
index 96542ce7ac..1566b349ed 100644
--- a/src/test/test_link_handshake.c
+++ b/src/test/test_link_handshake.c
@@ -18,6 +18,7 @@
#include "feature/relay/routerkeys.h"
#include "core/or/scheduler.h"
#include "feature/nodelist/torcert.h"
+#include "feature/relay/relay_handshake.h"
#include "core/or/or_connection_st.h"
#include "core/or/or_handshake_certs_st.h"
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index 762241249c..7949e90e9e 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -62,8 +62,8 @@ test_policy_summary_helper_family_flags(const char *policy_str,
short_policy_t *short_policy = NULL;
int success = 0;
- line.key = (char*)"foo";
- line.value = (char *)policy_str;
+ line.key = (char *) "foo";
+ line.value = (char *) policy_str;
line.next = NULL;
r = policies_parse_exit_policy(&line, &policy,
@@ -2124,20 +2124,6 @@ test_policies_fascist_firewall_allows_address(void *arg)
teardown_capture_of_logs(); \
STMT_END
-/** Mock the preferred address function to return zero (prefer IPv4). */
-static int
-mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv4(void)
-{
- return 0;
-}
-
-/** Mock the preferred address function to return one (prefer IPv6). */
-static int
-mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv6(void)
-{
- return 1;
-}
-
/** Run unit tests for fascist_firewall_choose_address */
static void
test_policies_fascist_firewall_choose_address(void *arg)
@@ -2536,42 +2522,6 @@ test_policies_fascist_firewall_choose_address(void *arg)
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
ipv4_dir_ap);
- /* Test ClientAutoIPv6ORPort and pretend we prefer IPv4. */
- memset(&mock_options, 0, sizeof(or_options_t));
- mock_options.ClientAutoIPv6ORPort = 1;
- mock_options.ClientUseIPv4 = 1;
- mock_options.ClientUseIPv6 = 1;
- MOCK(fascist_firewall_rand_prefer_ipv6_addr,
- mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv4);
- /* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
- &mock_options);
-
- CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
- ipv4_or_ap);
- CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
- ipv4_or_ap);
-
- UNMOCK(fascist_firewall_rand_prefer_ipv6_addr);
-
- /* Test ClientAutoIPv6ORPort and pretend we prefer IPv6. */
- memset(&mock_options, 0, sizeof(or_options_t));
- mock_options.ClientAutoIPv6ORPort = 1;
- mock_options.ClientUseIPv4 = 1;
- mock_options.ClientUseIPv6 = 1;
- MOCK(fascist_firewall_rand_prefer_ipv6_addr,
- mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv6);
- /* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
- &mock_options);
-
- CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
- ipv6_or_ap);
- CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
- ipv6_or_ap);
-
- UNMOCK(fascist_firewall_rand_prefer_ipv6_addr);
-
/* Test firewall_choose_address_ls(). To do this, we make a fake link
* specifier. */
smartlist_t *lspecs = smartlist_new(),
diff --git a/src/test/test_prob_distr.c b/src/test/test_prob_distr.c
index c3d1c80d70..c5423ce14a 100644
--- a/src/test/test_prob_distr.c
+++ b/src/test/test_prob_distr.c
@@ -1223,14 +1223,16 @@ test_stochastic_weibull_impl(double lambda, double k)
.k = k,
};
+// clang-format off
/*
* XXX Consider applying a Tiku-Singh test:
*
* M.L. Tiku and M. Singh, `Testing the two-parameter
* Weibull distribution', Communications in Statistics --
* Theory and Methods A10(9), 1981, 907--918.
- *https://www.tandfonline.com/doi/pdf/10.1080/03610928108828082?needAccess=true
+https://www.tandfonline.com/doi/pdf/10.1080/03610928108828082?needAccess=true
*/
+// clang-format on
return test_psi_dist_sample(&dist.base);
}
diff --git a/src/test/test_protover.c b/src/test/test_protover.c
index f1d1ef0d4a..c33fbcae2c 100644
--- a/src/test/test_protover.c
+++ b/src/test/test_protover.c
@@ -2,6 +2,7 @@
/* See LICENSE for licensing information */
#define PROTOVER_PRIVATE
+#define DIRVOTE_PRIVATE
#include "orconfig.h"
#include "test/test.h"
@@ -12,6 +13,8 @@
#include "core/or/connection_or.h"
#include "lib/tls/tortls.h"
+#include "feature/dirauth/dirvote.h"
+
static void
test_protover_parse(void *arg)
{
@@ -314,6 +317,7 @@ test_protover_all_supported(void *arg)
tt_assert(protover_all_supported("Fribble=", &msg));
tt_ptr_op(msg, OP_EQ, NULL);
+#ifndef ALL_BUGS_ARE_FATAL
/* If we get a completely unparseable list, protover_all_supported should
* hit a fatal assertion for BUG(entries == NULL). */
tor_capture_bugs_(1);
@@ -325,9 +329,10 @@ test_protover_all_supported(void *arg)
tor_capture_bugs_(1);
tt_assert(protover_all_supported("Sleen=1-4294967295", &msg));
tor_end_capture_bugs_();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* Protocol name too long */
-#ifndef HAVE_RUST // XXXXXX ?????
+#if !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL)
tor_capture_bugs_(1);
tt_assert(protover_all_supported(
"DoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
@@ -335,7 +340,7 @@ test_protover_all_supported(void *arg)
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaa=1-65536", &msg));
tor_end_capture_bugs_();
-#endif /* !defined(HAVE_RUST) */
+#endif /* !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL) */
done:
tor_end_capture_bugs_();
@@ -634,6 +639,43 @@ test_protover_vote_roundtrip(void *args)
tor_free(result);
}
+static void
+test_protover_vote_roundtrip_ours(void *args)
+{
+ (void) args;
+ const char *examples[] = {
+ protover_get_supported_protocols(),
+ DIRVOTE_RECCOMEND_RELAY_PROTO,
+ DIRVOTE_RECCOMEND_CLIENT_PROTO,
+ DIRVOTE_REQUIRE_RELAY_PROTO,
+ DIRVOTE_REQUIRE_CLIENT_PROTO,
+ };
+ unsigned u;
+ smartlist_t *votes = smartlist_new();
+ char *result = NULL;
+
+ for (u = 0; u < ARRAY_LENGTH(examples); ++u) {
+ tt_assert(examples[u]);
+ const char *input = examples[u];
+ const char *expected_output = examples[u];
+
+ smartlist_add(votes, (void*)input);
+ result = protover_compute_vote(votes, 1);
+ if (expected_output != NULL) {
+ tt_str_op(result, OP_EQ, expected_output);
+ } else {
+ tt_str_op(result, OP_EQ, "");
+ }
+
+ smartlist_clear(votes);
+ tor_free(result);
+ }
+
+ done:
+ smartlist_free(votes);
+ tor_free(result);
+}
+
#define PV_TEST(name, flags) \
{ #name, test_protover_ ##name, (flags), NULL, NULL }
@@ -647,5 +689,6 @@ struct testcase_t protover_tests[] = {
PV_TEST(supports_version, 0),
PV_TEST(supported_protocols, 0),
PV_TEST(vote_roundtrip, 0),
+ PV_TEST(vote_roundtrip_ours, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index 26eaf7b7e7..893fec3674 100644
--- a/src/test/test_pt.c
+++ b/src/test/test_pt.c
@@ -579,8 +579,10 @@ test_get_pt_proxy_uri(void *arg)
tor_free(uri);
}
+#ifndef COCCI
#define PT_LEGACY(name) \
- { #name, test_pt_ ## name , 0, NULL, NULL }
+ { (#name), test_pt_ ## name , 0, NULL, NULL }
+#endif
struct testcase_t pt_tests[] = {
PT_LEGACY(parsing),
diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c
index f2accb2376..148eb5cf90 100644
--- a/src/test/test_shared_random.c
+++ b/src/test/test_shared_random.c
@@ -21,7 +21,7 @@
#include "feature/nodelist/dirlist.h"
#include "feature/dirparse/authcert_parse.h"
#include "feature/hs_common/shared_random_client.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dirclient/dir_server_st.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -193,7 +193,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
/* Compare it with the correct result */
@@ -205,7 +205,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 19:22:00 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
format_iso_time(tbuf, valid_until_time);
@@ -216,7 +216,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:59:00 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
format_iso_time(tbuf, valid_until_time);
@@ -227,7 +227,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
format_iso_time(tbuf, valid_until_time);
@@ -265,7 +265,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
/* Compare it with the correct result */
@@ -277,7 +277,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:59:59 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
/* Compare it with the correct result */
@@ -289,7 +289,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
/* Compare it with the correct result */
@@ -319,7 +319,7 @@ test_get_start_time_of_current_run(void *arg)
&current_time);
tt_int_op(retval, OP_EQ, 0);
update_approx_time(current_time);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
@@ -327,7 +327,7 @@ test_get_start_time_of_current_run(void *arg)
format_iso_time(tbuf, run_start_time);
tt_str_op("2015-04-19 00:00:00", OP_EQ, tbuf);
/* Check that voting_schedule.interval_starts is at 01:00 (see above) */
- time_t interval_starts = voting_schedule_get_next_valid_after_time();
+ time_t interval_starts = dirauth_sched_get_next_valid_after_time();
format_iso_time(tbuf, interval_starts);
tt_str_op("2015-04-20 01:00:00", OP_EQ, tbuf);
}
@@ -346,7 +346,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:15:32 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
/* Compare it with the correct result */
@@ -378,13 +378,13 @@ test_get_start_time_functions(void *arg)
tt_int_op(retval, OP_EQ, 0);
time_t now = mock_consensus.valid_after;
- voting_schedule_recalculate_timing(get_options(), now);
+ dirauth_sched_recalculate_timing(get_options(), now);
time_t start_time_of_protocol_run =
sr_state_get_start_time_of_current_protocol_run();
tt_assert(start_time_of_protocol_run);
/* Check that the round start time of the beginning of the run, is itself */
- tt_int_op(get_start_time_of_current_round(), OP_EQ,
+ tt_int_op(dirauth_sched_get_cur_valid_after_time(), OP_EQ,
start_time_of_protocol_run);
done:
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 0d86a5ab5d..a9cc54d8f6 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -4572,6 +4572,35 @@ test_util_di_ops(void *arg)
}
static void
+test_util_memcpy_iftrue_timei(void *arg)
+{
+ (void)arg;
+ char buf1[25];
+ char buf2[25];
+ char buf3[25];
+
+ for (int i = 0; i < 100; ++i) {
+ crypto_rand(buf1, sizeof(buf1));
+ crypto_rand(buf2, sizeof(buf2));
+ memcpy(buf3, buf1, sizeof(buf1));
+
+ /* We just copied buf1 into buf3. Now we're going to copy buf2 into buf2,
+ iff our coin flip comes up heads. */
+ bool coinflip = crypto_rand_int(2) == 0;
+
+ memcpy_if_true_timei(coinflip, buf3, buf2, sizeof(buf3));
+
+ if (coinflip) {
+ tt_mem_op(buf3, OP_EQ, buf2, sizeof(buf2));
+ } else {
+ tt_mem_op(buf3, OP_EQ, buf1, sizeof(buf1));
+ }
+ }
+ done:
+ ;
+}
+
+static void
test_util_di_map(void *arg)
{
(void)arg;
@@ -6305,42 +6334,42 @@ test_util_map_anon_nofork(void *arg)
#ifndef COCCI
#define UTIL_LEGACY(name) \
- { #name, test_util_ ## name , 0, NULL, NULL }
+ { (#name), test_util_ ## name , 0, NULL, NULL }
#define UTIL_TEST(name, flags) \
- { #name, test_util_ ## name, flags, NULL, NULL }
+ { (#name), test_util_ ## name, flags, NULL, NULL }
#define COMPRESS(name, identifier) \
- { "compress/" #name, test_util_compress, 0, &compress_setup, \
+ { ("compress/" #name), test_util_compress, 0, &compress_setup, \
(char*)(identifier) }
#define COMPRESS_CONCAT(name, identifier) \
- { "compress_concat/" #name, test_util_decompress_concatenated, 0, \
+ { ("compress_concat/" #name), test_util_decompress_concatenated, 0, \
&compress_setup, \
(char*)(identifier) }
#define COMPRESS_JUNK(name, identifier) \
- { "compress_junk/" #name, test_util_decompress_junk, 0, \
+ { ("compress_junk/" #name), test_util_decompress_junk, 0, \
&compress_setup, \
(char*)(identifier) }
#define COMPRESS_DOS(name, identifier) \
- { "compress_dos/" #name, test_util_decompress_dos, 0, \
+ { ("compress_dos/" #name), test_util_decompress_dos, 0, \
&compress_setup, \
(char*)(identifier) }
-#endif /* !defined(COCCI) */
#ifdef _WIN32
#define UTIL_TEST_WIN_ONLY(n, f) UTIL_TEST(n, (f))
#else
-#define UTIL_TEST_WIN_ONLY(n, f) { #n, NULL, TT_SKIP, NULL, NULL }
+#define UTIL_TEST_WIN_ONLY(n, f) { (#n), NULL, TT_SKIP, NULL, NULL }
#endif
#ifdef DISABLE_PWDB_TESTS
-#define UTIL_TEST_PWDB(n, f) { #n, NULL, TT_SKIP, NULL, NULL }
+#define UTIL_TEST_PWDB(n, f) { (#n), NULL, TT_SKIP, NULL, NULL }
#else
#define UTIL_TEST_PWDB(n, f) UTIL_TEST(n, (f))
#endif
+#endif /* !defined(COCCI) */
struct testcase_t util_tests[] = {
UTIL_LEGACY(time),
@@ -6386,6 +6415,7 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(path_is_relative),
UTIL_LEGACY(strtok),
UTIL_LEGACY(di_ops),
+ UTIL_TEST(memcpy_iftrue_timei, 0),
UTIL_TEST(di_map, 0),
UTIL_TEST(round_to_next_multiple_of, 0),
UTIL_TEST(laplace, 0),
diff --git a/src/test/test_util_process.c b/src/test/test_util_process.c
index 0e17e009f3..fc79fe9b1f 100644
--- a/src/test/test_util_process.c
+++ b/src/test/test_util_process.c
@@ -67,15 +67,16 @@ test_util_process_clear_waitpid_callback(void *ignored)
}
#endif /* !defined(_WIN32) */
+#ifndef COCCI
#ifndef _WIN32
-#define TEST(name) { #name, test_util_process_##name, 0, NULL, NULL }
+#define TEST(name) { (#name), test_util_process_##name, 0, NULL, NULL }
#else
-#define TEST(name) { #name, NULL, TT_SKIP, NULL, NULL }
+#define TEST(name) { (#name), NULL, TT_SKIP, NULL, NULL }
#endif
+#endif /* !defined(COCCI) */
struct testcase_t util_process_tests[] = {
TEST(set_waitpid_callback),
TEST(clear_waitpid_callback),
END_OF_TESTCASES
};
-
diff --git a/src/test/test_voting_schedule.c b/src/test/test_voting_schedule.c
index 54d1815a77..df64b79167 100644
--- a/src/test/test_voting_schedule.c
+++ b/src/test/test_voting_schedule.c
@@ -4,14 +4,15 @@
#include "orconfig.h"
#include "core/or/or.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
+#include "feature/nodelist/networkstatus.h"
#include "test/test.h"
static void
test_voting_schedule_interval_start(void *arg)
{
-#define next_interval voting_schedule_get_start_of_next_interval
+#define next_interval voting_sched_get_start_of_interval_after
(void)arg;
char buf[ISO_TIME_LEN+1];
@@ -61,4 +62,3 @@ struct testcase_t voting_schedule_tests[] = {
VS(interval_start, 0),
END_OF_TESTCASES
};
-
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index e9aa4112c0..b3337f24b0 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -273,7 +273,7 @@ main(int c, const char **v)
int loglevel = LOG_ERR;
int accel_crypto = 0;
- subsystems_init_upto(SUBSYS_LEVEL_LIBS);
+ subsystems_init();
options = options_new();
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index 47ca863ce8..3c8f91d53b 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -217,7 +217,7 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.4.3.3-alpha"
+#define VERSION "0.4.4.0-alpha-dev"
#define HAVE_STRUCT_SOCKADDR_IN6
#define HAVE_STRUCT_IN6_ADDR