aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app/app.md5
-rw-r--r--src/app/config/app_config.md3
-rw-r--r--src/app/config/config.c368
-rw-r--r--src/app/config/config.h15
-rw-r--r--src/app/config/or_options_st.h30
-rw-r--r--src/app/config/or_state_st.h8
-rw-r--r--src/app/config/resolve_addr.c1009
-rw-r--r--src/app/config/resolve_addr.h51
-rw-r--r--src/app/config/statefile.c14
-rw-r--r--src/app/config/testnet.inc3
-rw-r--r--src/app/include.am8
-rw-r--r--src/app/main/main.c36
-rw-r--r--src/app/main/shutdown.c2
-rw-r--r--src/app/main/subsystem_list.c3
-rw-r--r--src/config/torrc.sample.in13
-rw-r--r--src/core/crypto/onion_crypto.c2
-rw-r--r--src/core/mainloop/connection.c369
-rw-r--r--src/core/mainloop/connection.h5
-rw-r--r--src/core/mainloop/mainloop.c21
-rw-r--r--src/core/or/channel.c84
-rw-r--r--src/core/or/channel.h34
-rw-r--r--src/core/or/channelpadding.c6
-rw-r--r--src/core/or/channelpadding.h3
-rw-r--r--src/core/or/channeltls.c370
-rw-r--r--src/core/or/channeltls.h4
-rw-r--r--src/core/or/circuit_st.h6
-rw-r--r--src/core/or/circuitbuild.c453
-rw-r--r--src/core/or/circuitbuild.h27
-rw-r--r--src/core/or/circuitlist.c27
-rw-r--r--src/core/or/circuitpadding.c152
-rw-r--r--src/core/or/circuitpadding.h27
-rw-r--r--src/core/or/circuitpadding_machines.c25
-rw-r--r--src/core/or/circuitstats.c67
-rw-r--r--src/core/or/circuitstats.h6
-rw-r--r--src/core/or/circuituse.c53
-rw-r--r--src/core/or/circuituse.h16
-rw-r--r--src/core/or/command.c12
-rw-r--r--src/core/or/connection_edge.c105
-rw-r--r--src/core/or/connection_edge.h6
-rw-r--r--src/core/or/connection_or.c156
-rw-r--r--src/core/or/connection_or.h1
-rw-r--r--src/core/or/connection_st.h57
-rw-r--r--src/core/or/cpath_build_state_st.h2
-rw-r--r--src/core/or/crypt_path.c2
-rw-r--r--src/core/or/dos.c12
-rw-r--r--src/core/or/extend_info_st.h16
-rw-r--r--src/core/or/extendinfo.c330
-rw-r--r--src/core/or/extendinfo.h40
-rw-r--r--src/core/or/include.am9
-rw-r--r--src/core/or/lttng_circuit.inc322
-rw-r--r--src/core/or/onion.h3
-rw-r--r--src/core/or/or.h21
-rw-r--r--src/core/or/or_connection_st.h17
-rw-r--r--src/core/or/policies.c266
-rw-r--r--src/core/or/policies.h34
-rw-r--r--src/core/or/port_cfg_st.h2
-rw-r--r--src/core/or/protover.c26
-rw-r--r--src/core/or/protover.h26
-rw-r--r--src/core/or/protover_rust.c2
-rw-r--r--src/core/or/relay.c1
-rw-r--r--src/core/or/scheduler.c2
-rw-r--r--src/core/or/scheduler_kist.c7
-rw-r--r--src/core/or/sendme.c2
-rw-r--r--src/core/or/status.c41
-rw-r--r--src/core/or/status.h1
-rw-r--r--src/core/or/trace_probes_circuit.c30
-rw-r--r--src/core/or/trace_probes_circuit.h22
-rw-r--r--src/core/or/versions.c59
-rw-r--r--src/core/proto/proto_socks.c4
-rw-r--r--src/core/stA1RajU0
-rw-r--r--src/core/stiysZNDbin19083264 -> 0 bytes
-rw-r--r--src/ext/README79
-rw-r--r--src/ext/ed25519/donna/ed25519_tor.c1
-rw-r--r--src/ext/ext.md88
-rw-r--r--src/ext/include.am2
-rw-r--r--src/feature/client/bridges.c127
-rw-r--r--src/feature/client/entrynodes.c10
-rw-r--r--src/feature/client/transports.c21
-rw-r--r--src/feature/control/control.c20
-rw-r--r--src/feature/control/control.h1
-rw-r--r--src/feature/control/control_bootstrap.c4
-rw-r--r--src/feature/control/control_cmd.c38
-rw-r--r--src/feature/control/control_events.c60
-rw-r--r--src/feature/control/control_events.h7
-rw-r--r--src/feature/control/control_getinfo.c83
-rw-r--r--src/feature/control/control_getinfo.h4
-rw-r--r--src/feature/dirauth/dirauth_config.c4
-rw-r--r--src/feature/dirauth/dirauth_options.inc7
-rw-r--r--src/feature/dirauth/dirvote.c66
-rw-r--r--src/feature/dirauth/dirvote.h6
-rw-r--r--src/feature/dirauth/process_descs.c45
-rw-r--r--src/feature/dirauth/reachability.c14
-rw-r--r--src/feature/dirauth/voteflags.c6
-rw-r--r--src/feature/dircache/dircache.c21
-rw-r--r--src/feature/dirclient/dir_server_st.h6
-rw-r--r--src/feature/dirclient/dirclient.c241
-rw-r--r--src/feature/dirclient/dirclient_modes.c12
-rw-r--r--src/feature/dircommon/directory.c30
-rw-r--r--src/feature/dircommon/directory.h1
-rw-r--r--src/feature/dirparse/authcert_parse.c4
-rw-r--r--src/feature/dirparse/ns_parse.c63
-rw-r--r--src/feature/dirparse/routerparse.c11
-rw-r--r--src/feature/feature.md23
-rw-r--r--src/feature/hs/hs_circuit.c1
-rw-r--r--src/feature/hs/hs_client.c7
-rw-r--r--src/feature/hs/hs_common.c5
-rw-r--r--src/feature/hs/hs_descriptor.c7
-rw-r--r--src/feature/hs/hs_service.c17
-rw-r--r--src/feature/keymgt/loadkey.c4
-rw-r--r--src/feature/nodelist/authcert.c26
-rw-r--r--src/feature/nodelist/authcert.h2
-rw-r--r--src/feature/nodelist/authority_cert_st.h6
-rw-r--r--src/feature/nodelist/describe.c81
-rw-r--r--src/feature/nodelist/describe.h4
-rw-r--r--src/feature/nodelist/dirlist.c102
-rw-r--r--src/feature/nodelist/dirlist.h5
-rw-r--r--src/feature/nodelist/fmt_routerstatus.c8
-rw-r--r--src/feature/nodelist/networkstatus.c81
-rw-r--r--src/feature/nodelist/networkstatus_voter_info_st.h6
-rw-r--r--src/feature/nodelist/node_select.c186
-rw-r--r--src/feature/nodelist/node_select.h28
-rw-r--r--src/feature/nodelist/node_st.h5
-rw-r--r--src/feature/nodelist/nodelist.c262
-rw-r--r--src/feature/nodelist/nodelist.h27
-rw-r--r--src/feature/nodelist/routerinfo.c39
-rw-r--r--src/feature/nodelist/routerinfo.h5
-rw-r--r--src/feature/nodelist/routerinfo_st.h7
-rw-r--r--src/feature/nodelist/routerlist.c185
-rw-r--r--src/feature/nodelist/routerlist.h14
-rw-r--r--src/feature/nodelist/routerset.c60
-rw-r--r--src/feature/nodelist/routerstatus_st.h6
-rw-r--r--src/feature/nodelist/torcert.c12
-rw-r--r--src/feature/nodelist/torcert.h12
-rw-r--r--src/feature/relay/circuitbuild_relay.c83
-rw-r--r--src/feature/relay/circuitbuild_relay.h2
-rw-r--r--src/feature/relay/relay_config.c147
-rw-r--r--src/feature/relay/relay_config.h1
-rw-r--r--src/feature/relay/relay_find_addr.c194
-rw-r--r--src/feature/relay/relay_find_addr.h17
-rw-r--r--src/feature/relay/relay_periodic.c97
-rw-r--r--src/feature/relay/router.c510
-rw-r--r--src/feature/relay/router.h17
-rw-r--r--src/feature/relay/routerkeys.c41
-rw-r--r--src/feature/relay/selftest.c397
-rw-r--r--src/feature/relay/selftest.h18
-rw-r--r--src/feature/rend/rendcache.c5
-rw-r--r--src/feature/rend/rendclient.c11
-rw-r--r--src/feature/rend/rendcommon.c10
-rw-r--r--src/feature/rend/rendparse.c17
-rw-r--r--src/feature/rend/rendservice.c30
-rw-r--r--src/feature/stats/bw_array_st.h57
-rw-r--r--src/feature/stats/bwhist.c548
-rw-r--r--src/feature/stats/bwhist.h47
-rw-r--r--src/feature/stats/connstats.c283
-rw-r--r--src/feature/stats/connstats.h25
-rw-r--r--src/feature/stats/include.am5
-rw-r--r--src/feature/stats/predict_ports.c4
-rw-r--r--src/feature/stats/rephist.c820
-rw-r--r--src/feature/stats/rephist.h28
-rw-r--r--src/lib/buf/buffers.c15
-rw-r--r--src/lib/buf/buffers.h2
-rw-r--r--src/lib/crypt_ops/crypto_curve25519.h4
-rw-r--r--src/lib/crypt_ops/crypto_format.c35
-rw-r--r--src/lib/defs/x25519_sizes.h3
-rw-r--r--src/lib/fs/conffile.c141
-rw-r--r--src/lib/fs/files.c44
-rw-r--r--src/lib/fs/files.h4
-rw-r--r--src/lib/fs/path.c373
-rw-r--r--src/lib/fs/path.h7
-rw-r--r--src/lib/log/log.c2
-rw-r--r--src/lib/log/ratelim.c12
-rw-r--r--src/lib/log/ratelim.h8
-rw-r--r--src/lib/net/address.c57
-rw-r--r--src/lib/net/address.h14
-rw-r--r--src/lib/net/buffers_net.c33
-rw-r--r--src/lib/net/buffers_net.h6
-rw-r--r--src/lib/osinfo/include.am6
-rw-r--r--src/lib/osinfo/libc.c66
-rw-r--r--src/lib/osinfo/libc.h19
-rw-r--r--src/lib/process/process_unix.c2
-rw-r--r--src/lib/sandbox/sandbox.c4
-rw-r--r--src/lib/string/compat_string.h2
-rw-r--r--src/lib/string/util_string.c9
-rw-r--r--src/lib/string/util_string.h1
-rw-r--r--src/lib/tls/buffers_tls.c29
-rw-r--r--src/lib/tls/buffers_tls.h2
-rw-r--r--src/lib/trace/.may_include1
-rw-r--r--src/lib/trace/debug.h30
-rw-r--r--src/lib/trace/events.h84
-rw-r--r--src/lib/trace/include.am26
-rw-r--r--src/lib/trace/lttng/include.am3
-rw-r--r--src/lib/trace/lttng/lttng.h28
-rw-r--r--src/lib/trace/trace.c8
-rw-r--r--src/lib/trace/trace.h30
-rw-r--r--src/lib/trace/trace_stub.c19
-rw-r--r--src/lib/trace/trace_sys.c36
-rw-r--r--src/lib/trace/trace_sys.h22
-rw-r--r--src/lib/trace/usdt/include.am3
-rw-r--r--src/lib/trace/usdt/usdt.h33
-rw-r--r--src/mainpage.md5
-rw-r--r--src/rust/protover/ffi.rs10
-rw-r--r--src/rust/protover/protover.rs25
-rw-r--r--src/rust/protover/tests/protover.rs13
-rw-r--r--src/test/conf_examples/crypto_accel/expected_log_nss2
-rw-r--r--src/test/conf_examples/crypto_accel_req/expected_log_nss2
-rw-r--r--src/test/conf_examples/dirauth_3/error_no_dirauth1
-rw-r--r--src/test/conf_examples/dirauth_3/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/dirauth_3/expected9
-rw-r--r--src/test/conf_examples/dirauth_3/expected_log1
-rw-r--r--src/test/conf_examples/dirauth_3/torrc13
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_log2
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_log_lzma2
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd2
-rw-r--r--src/test/conf_examples/lzma_zstd_1/expected_log_zstd2
-rw-r--r--src/test/conf_examples/nss_1/expected_log2
-rw-r--r--src/test/conf_examples/nss_1/expected_log_nss2
-rw-r--r--src/test/fuzz/include.am4
-rw-r--r--src/test/hs_test_helpers.c8
-rw-r--r--src/test/include.am34
-rw-r--r--src/test/rend_test_helpers.c13
-rw-r--r--src/test/test-memwipe.c23
-rw-r--r--src/test/test.c21
-rw-r--r--src/test/test_addr.c1
-rw-r--r--src/test/test_address.c28
-rw-r--r--src/test/test_address_set.c5
-rw-r--r--src/test/test_bridges.c12
-rw-r--r--src/test/test_bwmgt.c4
-rw-r--r--src/test/test_channel.c70
-rw-r--r--src/test/test_channeltls.c34
-rw-r--r--src/test/test_circuitbuild.c462
-rw-r--r--src/test/test_circuitpadding.c21
-rw-r--r--src/test/test_circuitstats.c95
-rw-r--r--src/test/test_config.c1498
-rw-r--r--src/test/test_connection.c119
-rw-r--r--src/test/test_controller.c87
-rw-r--r--src/test/test_crypto.c10
-rw-r--r--src/test/test_dir.c128
-rw-r--r--src/test/test_dir_common.c42
-rw-r--r--src/test/test_dos.c32
-rw-r--r--src/test/test_entrynodes.c22
-rw-r--r--src/test/test_guardfraction.c6
-rw-r--r--src/test/test_helpers.c145
-rw-r--r--src/test/test_helpers.h7
-rw-r--r--src/test/test_hs_client.c6
-rw-r--r--src/test/test_hs_common.c6
-rw-r--r--src/test/test_hs_descriptor.c9
-rw-r--r--src/test/test_hs_service.c8
-rw-r--r--src/test/test_include.py196
-rwxr-xr-xsrc/test/test_include.sh111
-rwxr-xr-xsrc/test/test_key_expiration.sh70
-rw-r--r--src/test/test_link_handshake.c2
-rw-r--r--src/test/test_logging.c6
-rw-r--r--src/test/test_nodelist.c63
-rw-r--r--src/test/test_options.c2
-rwxr-xr-xsrc/test/test_parseconf.sh2
-rw-r--r--src/test/test_policy.c215
-rw-r--r--src/test/test_process_descs.c2
-rw-r--r--src/test/test_protover.c331
-rw-r--r--src/test/test_rebind.py2
-rw-r--r--src/test/test_relay.c176
-rw-r--r--src/test/test_relaycell.c22
-rw-r--r--src/test/test_router.c49
-rw-r--r--src/test/test_routerkeys.c54
-rw-r--r--src/test/test_routerlist.c42
-rw-r--r--src/test/test_routerset.c56
-rw-r--r--src/test/test_stats.c293
-rw-r--r--src/test/test_status.c341
-rw-r--r--src/test/test_util.c582
-rw-r--r--src/test/test_voting_flags.c14
-rw-r--r--src/test/testing_common.c2
-rw-r--r--src/tools/include.am8
-rw-r--r--src/trunnel/circpad_negotiation.c52
-rw-r--r--src/trunnel/circpad_negotiation.h27
-rw-r--r--src/trunnel/circpad_negotiation.trunnel17
-rw-r--r--src/win32/orconfig.h2
275 files changed, 12360 insertions, 5346 deletions
diff --git a/src/app/app.md b/src/app/app.md
index 138e75b127..298bde75f5 100644
--- a/src/app/app.md
+++ b/src/app/app.md
@@ -4,3 +4,8 @@
The "app" directory has Tor's main entry point and configuration logic,
and is responsible for initializing and managing the other modules in
Tor.
+
+The modules in "app" are:
+
+ - \refdir{app/config} -- configuration and state for Tor
+ - \refdir{app/main} -- Top-level functions to invoke the rest or Tor.
diff --git a/src/app/config/app_config.md b/src/app/config/app_config.md
index b359ce77f6..96a55494ff 100644
--- a/src/app/config/app_config.md
+++ b/src/app/config/app_config.md
@@ -2,5 +2,4 @@
@brief app/config: Top-level configuration code
Refactoring this module is a work in progress, see
-[ticket 29211](https://trac.torproject.org/projects/tor/ticket/29211).
-
+[ticket 29211](https://bugs.torproject.org/tpo/core/tor/29211)
diff --git a/src/app/config/config.c b/src/app/config/config.c
index a0c188adc4..5c8a3792ee 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -27,7 +27,7 @@
* <li>The option_vars_ array below in this module, which configures
* the names of the torrc options, their types, their multiplicities,
* and their mappings to fields in or_options_t.
- * <li>The manual in doc/tor.1.txt, to document what the new option
+ * <li>The manual in doc/man/tor.1.txt, to document what the new option
* is, and how it works.
* </ul>
*
@@ -140,6 +140,7 @@
#include "lib/meminfo/meminfo.h"
#include "lib/osinfo/uname.h"
+#include "lib/osinfo/libc.h"
#include "lib/process/daemon.h"
#include "lib/process/pidfile.h"
#include "lib/process/restrict.h"
@@ -313,7 +314,8 @@ static const config_var_t option_vars_[] = {
V(AccountingMax, MEMUNIT, "0 bytes"),
VAR("AccountingRule", STRING, AccountingRule_option, "max"),
V(AccountingStart, STRING, NULL),
- V(Address, STRING, NULL),
+ V(Address, LINELIST, NULL),
+ V(AddressDisableIPv6, BOOL, "0"),
OBSOLETE("AllowDotExit"),
OBSOLETE("AllowInvalidNodes"),
V(AllowNonRFC953Hostnames, BOOL, "0"),
@@ -323,6 +325,7 @@ static const config_var_t option_vars_[] = {
V(AlternateDirAuthority, LINELIST, NULL),
OBSOLETE("AlternateHSAuthority"),
V(AssumeReachable, BOOL, "0"),
+ V(AssumeReachableIPv6, AUTOBOOL, "auto"),
OBSOLETE("AuthDirBadDir"),
OBSOLETE("AuthDirBadDirCCs"),
V(AuthDirBadExit, LINELIST, NULL),
@@ -1735,8 +1738,8 @@ options_rollback_listener_transaction(listener_transaction_t *xn)
SMARTLIST_FOREACH(xn->new_listeners, connection_t *, conn,
{
- log_notice(LD_NET, "Closing partially-constructed %s on %s:%d",
- conn_type_to_string(conn->type), conn->address, conn->port);
+ log_notice(LD_NET, "Closing partially-constructed %s",
+ connection_describe(conn));
connection_close_immediate(conn);
connection_mark_for_close(conn);
});
@@ -2465,6 +2468,8 @@ static const struct {
{ .name="--key-expiration",
.takes_argument=ARGUMENT_OPTIONAL,
.command=CMD_KEY_EXPIRATION },
+ { .name="--format",
+ .takes_argument=ARGUMENT_NECESSARY },
{ .name="--newpass" },
{ .name="--no-passphrase" },
{ .name="--passphrase-fd",
@@ -2722,6 +2727,140 @@ list_enabled_modules(void)
// test variants in test_parseconf.sh to no useful purpose.
}
+/** Prints compile-time and runtime library versions. */
+static void
+print_library_versions(void)
+{
+ printf("Tor version %s. \n", get_version());
+ printf("Library versions\tCompiled\t\tRuntime\n");
+ printf("Libevent\t\t%-15s\t\t%s\n",
+ tor_libevent_get_header_version_str(),
+ tor_libevent_get_version_str());
+#ifdef ENABLE_OPENSSL
+ printf("OpenSSL \t\t%-15s\t\t%s\n",
+ crypto_openssl_get_header_version_str(),
+ crypto_openssl_get_version_str());
+#endif
+#ifdef ENABLE_NSS
+ printf("NSS \t\t%-15s\t\t%s\n",
+ crypto_nss_get_header_version_str(),
+ crypto_nss_get_version_str());
+#endif
+ if (tor_compress_supports_method(ZLIB_METHOD)) {
+ printf("Zlib \t\t%-15s\t\t%s\n",
+ tor_compress_version_str(ZLIB_METHOD),
+ tor_compress_header_version_str(ZLIB_METHOD));
+ }
+ if (tor_compress_supports_method(LZMA_METHOD)) {
+ printf("Liblzma \t\t%-15s\t\t%s\n",
+ tor_compress_version_str(LZMA_METHOD),
+ tor_compress_header_version_str(LZMA_METHOD));
+ }
+ if (tor_compress_supports_method(ZSTD_METHOD)) {
+ printf("Libzstd \t\t%-15s\t\t%s\n",
+ tor_compress_version_str(ZSTD_METHOD),
+ tor_compress_header_version_str(ZSTD_METHOD));
+ }
+ if (tor_libc_get_name()) {
+ printf("%-7s \t\t%-15s\t\t%s\n",
+ tor_libc_get_name(),
+ tor_libc_get_header_version_str(),
+ tor_libc_get_version_str());
+ }
+ //TODO: Hex versions?
+}
+
+/** Handles the --no-passphrase command line option. */
+static int
+handle_cmdline_no_passphrase(tor_cmdline_mode_t command)
+{
+ if (command == CMD_KEYGEN) {
+ get_options_mutable()->keygen_force_passphrase = FORCE_PASSPHRASE_OFF;
+ return 0;
+ } else {
+ log_err(LD_CONFIG, "--no-passphrase specified without --keygen!");
+ return -1;
+ }
+}
+
+/** Handles the --format command line option. */
+static int
+handle_cmdline_format(tor_cmdline_mode_t command, const char *value)
+{
+ if (command == CMD_KEY_EXPIRATION) {
+ // keep the same order as enum key_expiration_format
+ const char *formats[] = { "iso8601", "timestamp" };
+ int format = -1;
+ for (unsigned i = 0; i < ARRAY_LENGTH(formats); i++) {
+ if (!strcmp(value, formats[i])) {
+ format = i;
+ break;
+ }
+ }
+
+ if (format < 0) {
+ log_err(LD_CONFIG, "Invalid --format value %s", escaped(value));
+ return -1;
+ } else {
+ get_options_mutable()->key_expiration_format = format;
+ }
+ return 0;
+ } else {
+ log_err(LD_CONFIG, "--format specified without --key-expiration!");
+ return -1;
+ }
+}
+
+/** Handles the --newpass command line option. */
+static int
+handle_cmdline_newpass(tor_cmdline_mode_t command)
+{
+ if (command == CMD_KEYGEN) {
+ get_options_mutable()->change_key_passphrase = 1;
+ return 0;
+ } else {
+ log_err(LD_CONFIG, "--newpass specified without --keygen!");
+ return -1;
+ }
+}
+
+/** Handles the --passphrase-fd command line option. */
+static int
+handle_cmdline_passphrase_fd(tor_cmdline_mode_t command, const char *value)
+{
+ if (get_options()->keygen_force_passphrase == FORCE_PASSPHRASE_OFF) {
+ log_err(LD_CONFIG, "--no-passphrase specified with --passphrase-fd!");
+ return -1;
+ } else if (command != CMD_KEYGEN) {
+ log_err(LD_CONFIG, "--passphrase-fd specified without --keygen!");
+ return -1;
+ } else {
+ int ok = 1;
+ long fd = tor_parse_long(value, 10, 0, INT_MAX, &ok, NULL);
+ if (fd < 0 || ok == 0) {
+ log_err(LD_CONFIG, "Invalid --passphrase-fd value %s", escaped(value));
+ return -1;
+ }
+ get_options_mutable()->keygen_passphrase_fd = (int)fd;
+ get_options_mutable()->use_keygen_passphrase_fd = 1;
+ get_options_mutable()->keygen_force_passphrase = FORCE_PASSPHRASE_ON;
+ return 0;
+ }
+}
+
+/** Handles the --master-key command line option. */
+static int
+handle_cmdline_master_key(tor_cmdline_mode_t command, const char *value)
+{
+ if (command != CMD_KEYGEN) {
+ log_err(LD_CONFIG, "--master-key without --keygen!");
+ return -1;
+ } else {
+ get_options_mutable()->master_key_fname = tor_strdup(value);
+ return 0;
+ }
+}
+
/* Return true if <b>options</b> is using the default authorities, and false
* if any authority-related option has been overridden. */
int
@@ -2771,10 +2910,6 @@ options_dump(const or_options_t *options, int how_to_dump)
use_defaults = global_default_options;
minimal = 1;
break;
- case OPTIONS_DUMP_DEFAULTS:
- use_defaults = NULL;
- minimal = 1;
- break;
case OPTIONS_DUMP_ALL:
use_defaults = NULL;
minimal = 0;
@@ -3229,6 +3364,10 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
REJECT("TokenBucketRefillInterval must be between 1 and 1000 inclusive.");
}
+ if (options->AssumeReachable && options->AssumeReachableIPv6 == 0) {
+ REJECT("Cannot set AssumeReachable 1 and AssumeReachableIPv6 0.");
+ }
+
if (options->ExcludeExitNodes || options->ExcludeNodes) {
options->ExcludeExitNodesUnion_ = routerset_new();
routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeExitNodes);
@@ -3453,7 +3592,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
"configured. This is bad because it's very easy to locate your "
"entry guard which can then lead to the deanonymization of your "
"hidden service -- for more details, see "
- "https://trac.torproject.org/projects/tor/ticket/14917. "
+ "https://bugs.torproject.org/tpo/core/tor/14917. "
"For this reason, the use of one EntryNodes with an hidden "
"service is prohibited until a better solution is found.");
return -1;
@@ -3470,7 +3609,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
"be harmful to the service anonymity. Because of this, we "
"recommend you either don't do that or make sure you know what "
"you are doing. For more details, please look at "
- "https://trac.torproject.org/projects/tor/ticket/21155.");
+ "https://bugs.torproject.org/tpo/core/tor/21155.");
}
/* Single Onion Services: non-anonymous hidden services */
@@ -4045,7 +4184,7 @@ options_check_transition_cb(const void *old_,
if (! CFG_EQ_INT(old, new_val, opt)) \
BAD_CHANGE_TO(opt," with Sandbox active")
- SB_NOCHANGE_STR(Address);
+ SB_NOCHANGE_LINELIST(Address);
SB_NOCHANGE_STR(ServerDNSResolvConfFile);
SB_NOCHANGE_STR(DirPortFrontPage);
SB_NOCHANGE_STR(CookieAuthFile);
@@ -4351,37 +4490,7 @@ options_init_from_torrc(int argc, char **argv)
}
if (config_line_find(cmdline_only_options, "--library-versions")) {
- printf("Tor version %s. \n", get_version());
- printf("Library versions\tCompiled\t\tRuntime\n");
- printf("Libevent\t\t%-15s\t\t%s\n",
- tor_libevent_get_header_version_str(),
- tor_libevent_get_version_str());
-#ifdef ENABLE_OPENSSL
- printf("OpenSSL \t\t%-15s\t\t%s\n",
- crypto_openssl_get_header_version_str(),
- crypto_openssl_get_version_str());
-#endif
-#ifdef ENABLE_NSS
- printf("NSS \t\t%-15s\t\t%s\n",
- crypto_nss_get_header_version_str(),
- crypto_nss_get_version_str());
-#endif
- if (tor_compress_supports_method(ZLIB_METHOD)) {
- printf("Zlib \t\t%-15s\t\t%s\n",
- tor_compress_version_str(ZLIB_METHOD),
- tor_compress_header_version_str(ZLIB_METHOD));
- }
- if (tor_compress_supports_method(LZMA_METHOD)) {
- printf("Liblzma \t\t%-15s\t\t%s\n",
- tor_compress_version_str(LZMA_METHOD),
- tor_compress_header_version_str(LZMA_METHOD));
- }
- if (tor_compress_supports_method(ZSTD_METHOD)) {
- printf("Libzstd \t\t%-15s\t\t%s\n",
- tor_compress_version_str(ZSTD_METHOD),
- tor_compress_header_version_str(ZSTD_METHOD));
- }
- //TODO: Hex versions?
+ print_library_versions();
return 1;
}
@@ -4395,10 +4504,7 @@ options_init_from_torrc(int argc, char **argv)
cf = tor_strdup("");
} else {
cf_defaults = load_torrc_from_disk(cmdline_only_options, 1);
-
- const config_line_t *f_line = config_line_find(cmdline_only_options,
- "-f");
-
+ const config_line_t *f_line = config_line_find(cmdline_only_options, "-f");
const int read_torrc_from_stdin =
(f_line != NULL && strcmp(f_line->value, "-") == 0);
@@ -4419,74 +4525,54 @@ options_init_from_torrc(int argc, char **argv)
retval = options_init_from_string(cf_defaults, cf, command, command_arg,
&errmsg);
-
if (retval < 0)
goto err;
if (config_line_find(cmdline_only_options, "--no-passphrase")) {
- if (command == CMD_KEYGEN) {
- get_options_mutable()->keygen_force_passphrase = FORCE_PASSPHRASE_OFF;
- } else {
- log_err(LD_CONFIG, "--no-passphrase specified without --keygen!");
+ if (handle_cmdline_no_passphrase(command) < 0) {
retval = -1;
goto err;
}
}
+ const config_line_t *format_line = config_line_find(cmdline_only_options,
+ "--format");
+ if (format_line) {
+ if (handle_cmdline_format(command, format_line->value) < 0) {
+ retval = -1;
+ goto err;
+ }
+ } else {
+ get_options_mutable()->key_expiration_format =
+ KEY_EXPIRATION_FORMAT_ISO8601;
+ }
+
if (config_line_find(cmdline_only_options, "--newpass")) {
- if (command == CMD_KEYGEN) {
- get_options_mutable()->change_key_passphrase = 1;
- } else {
- log_err(LD_CONFIG, "--newpass specified without --keygen!");
+ if (handle_cmdline_newpass(command) < 0) {
retval = -1;
goto err;
}
}
- {
- const config_line_t *fd_line = config_line_find(cmdline_only_options,
- "--passphrase-fd");
- if (fd_line) {
- if (get_options()->keygen_force_passphrase == FORCE_PASSPHRASE_OFF) {
- log_err(LD_CONFIG, "--no-passphrase specified with --passphrase-fd!");
- retval = -1;
- goto err;
- } else if (command != CMD_KEYGEN) {
- log_err(LD_CONFIG, "--passphrase-fd specified without --keygen!");
- retval = -1;
- goto err;
- } else {
- const char *v = fd_line->value;
- int ok = 1;
- long fd = tor_parse_long(v, 10, 0, INT_MAX, &ok, NULL);
- if (fd < 0 || ok == 0) {
- log_err(LD_CONFIG, "Invalid --passphrase-fd value %s", escaped(v));
- retval = -1;
- goto err;
- }
- get_options_mutable()->keygen_passphrase_fd = (int)fd;
- get_options_mutable()->use_keygen_passphrase_fd = 1;
- get_options_mutable()->keygen_force_passphrase = FORCE_PASSPHRASE_ON;
- }
+ const config_line_t *fd_line = config_line_find(cmdline_only_options,
+ "--passphrase-fd");
+ if (fd_line) {
+ if (handle_cmdline_passphrase_fd(command, fd_line->value) < 0) {
+ retval = -1;
+ goto err;
}
}
- {
- const config_line_t *key_line = config_line_find(cmdline_only_options,
- "--master-key");
- if (key_line) {
- if (command != CMD_KEYGEN) {
- log_err(LD_CONFIG, "--master-key without --keygen!");
- retval = -1;
- goto err;
- } else {
- get_options_mutable()->master_key_fname = tor_strdup(key_line->value);
- }
+ const config_line_t *key_line = config_line_find(cmdline_only_options,
+ "--master-key");
+ if (key_line) {
+ if (handle_cmdline_master_key(command, key_line->value) < 0) {
+ retval = -1;
+ goto err;
}
}
err:
-
tor_free(cf);
tor_free(cf_defaults);
if (errmsg) {
@@ -5839,6 +5925,15 @@ port_parse_config(smartlist_t *out,
int got_zero_port=0, got_nonzero_port=0;
char *unix_socket_path = NULL;
port_cfg_t *cfg = NULL;
+ bool addr_is_explicit = false;
+ int family = -1;
+
+ /* Parse default address. This can fail for Unix socket for instance so
+ * family can be -1 and the default_addr will be made UNSPEC. */
+ tor_addr_t default_addr = TOR_ADDR_NULL;
+ if (defaultaddr) {
+ family = tor_addr_parse(&default_addr, defaultaddr);
+ }
/* If there's no FooPort, then maybe make a default one. */
if (! ports) {
@@ -5915,8 +6010,8 @@ port_parse_config(smartlist_t *out,
port = 1;
} else if (!strcasecmp(addrport, "auto")) {
port = CFG_AUTO_PORT;
- int af = tor_addr_parse(&addr, defaultaddr);
- tor_assert(af >= 0);
+ tor_assert(family >= 0);
+ tor_addr_copy(&addr, &default_addr);
} else if (!strcasecmpend(addrport, ":auto")) {
char *addrtmp = tor_strndup(addrport, strlen(addrport)-5);
port = CFG_AUTO_PORT;
@@ -5932,14 +6027,20 @@ port_parse_config(smartlist_t *out,
"9050" might be a valid address. */
port = (int) tor_parse_long(addrport, 10, 0, 65535, &ok, NULL);
if (ok) {
- int af = tor_addr_parse(&addr, defaultaddr);
- tor_assert(af >= 0);
+ tor_assert(family >= 0);
+ tor_addr_copy(&addr, &default_addr);
} else if (tor_addr_port_lookup(addrport, &addr, &ptmp) == 0) {
if (ptmp == 0) {
log_warn(LD_CONFIG, "%sPort line has address but no port", portname);
goto err;
}
+ if (family != -1 && tor_addr_family(&addr) != family) {
+ /* This means we are parsing another ORPort family but we are
+ * attempting to find the default address' family ORPort. */
+ goto ignore;
+ }
port = ptmp;
+ addr_is_explicit = true;
} else {
log_warn(LD_CONFIG, "Couldn't parse address %s for %sPort",
escaped(addrport), portname);
@@ -5950,6 +6051,7 @@ port_parse_config(smartlist_t *out,
/* Default port_cfg_t object initialization */
cfg = port_cfg_new(unix_socket_path ? strlen(unix_socket_path) : 0);
+ cfg->explicit_addr = addr_is_explicit;
if (unix_socket_path && default_to_group_writable)
cfg->is_group_writable = 1;
@@ -5992,15 +6094,25 @@ port_parse_config(smartlist_t *out,
}
if (cfg->server_cfg.bind_ipv4_only &&
tor_addr_family(&addr) != AF_INET) {
- log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4",
- portname);
- goto err;
+ if (cfg->explicit_addr) {
+ log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv4",
+ portname);
+ goto err;
+ }
+ /* This ORPort is IPv4Only but the default address is IPv6, ignore it
+ * since this will be configured with an IPv4 default address. */
+ goto ignore;
}
if (cfg->server_cfg.bind_ipv6_only &&
tor_addr_family(&addr) != AF_INET6) {
- log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6",
- portname);
- goto err;
+ if (cfg->explicit_addr) {
+ log_warn(LD_CONFIG, "Could not interpret %sPort address as IPv6",
+ portname);
+ goto err;
+ }
+ /* This ORPort is IPv6Only but the default address is IPv4, ignore it
+ * since this will be configured with an IPv6 default address. */
+ goto ignore;
}
} else {
/* This is a client port; parse isolation options */
@@ -6213,9 +6325,10 @@ port_parse_config(smartlist_t *out,
smartlist_add(out, cfg);
/* out owns cfg now, don't re-use or free it */
cfg = NULL;
- } else {
- tor_free(cfg);
}
+
+ ignore:
+ tor_free(cfg);
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_clear(elts);
tor_free(addrport);
@@ -6512,14 +6625,13 @@ get_first_listener_addrport_string(int listener_type)
return NULL;
}
-/** Return the first advertised port of type <b>listener_type</b> in
- * <b>address_family</b>. Returns 0 when no port is found, and when passed
- * AF_UNSPEC. */
-int
-get_first_advertised_port_by_type_af(int listener_type, int address_family)
+/** Find and return the first configured advertised `port_cfg_t` of type @a
+ * listener_type in @a address_family. */
+static const port_cfg_t *
+portconf_get_first_advertised(int listener_type, int address_family)
{
if (address_family == AF_UNSPEC)
- return 0;
+ return NULL;
const smartlist_t *conf_ports = get_configured_ports();
SMARTLIST_FOREACH_BEGIN(conf_ports, const port_cfg_t *, cfg) {
@@ -6527,33 +6639,35 @@ get_first_advertised_port_by_type_af(int listener_type, int address_family)
!cfg->server_cfg.no_advertise) {
if ((address_family == AF_INET && port_binds_ipv4(cfg)) ||
(address_family == AF_INET6 && port_binds_ipv6(cfg))) {
- return cfg->port;
+ return cfg;
}
}
} SMARTLIST_FOREACH_END(cfg);
- return 0;
+ return NULL;
+}
+
+/** Return the first advertised port of type <b>listener_type</b> in
+ * <b>address_family</b>. Returns 0 when no port is found, and when passed
+ * AF_UNSPEC. */
+int
+portconf_get_first_advertised_port(int listener_type, int address_family)
+{
+ const port_cfg_t *cfg;
+ cfg = portconf_get_first_advertised(listener_type, address_family);
+
+ return cfg ? cfg->port : 0;
}
/** Return the first advertised address of type <b>listener_type</b> in
* <b>address_family</b>. Returns NULL if there is no advertised address,
* and when passed AF_UNSPEC. */
const tor_addr_t *
-get_first_advertised_addr_by_type_af(int listener_type, int address_family)
+portconf_get_first_advertised_addr(int listener_type, int address_family)
{
- if (address_family == AF_UNSPEC)
- return NULL;
- if (!configured_ports)
- return NULL;
- SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) {
- if (cfg->type == listener_type &&
- !cfg->server_cfg.no_advertise) {
- if ((address_family == AF_INET && port_binds_ipv4(cfg)) ||
- (address_family == AF_INET6 && port_binds_ipv6(cfg))) {
- return &cfg->addr;
- }
- }
- } SMARTLIST_FOREACH_END(cfg);
- return NULL;
+ const port_cfg_t *cfg;
+ cfg = portconf_get_first_advertised(listener_type, address_family);
+
+ return cfg ? &cfg->addr : NULL;
}
/** Return 1 if a port exists of type <b>listener_type</b> on <b>addr</b> and
diff --git a/src/app/config/config.h b/src/app/config/config.h
index 1ba10d1d37..e95ef4a728 100644
--- a/src/app/config/config.h
+++ b/src/app/config/config.h
@@ -58,8 +58,7 @@ setopt_err_t options_trial_assign(struct config_line_t *list, unsigned flags,
void options_init(or_options_t *options);
#define OPTIONS_DUMP_MINIMAL 1
-#define OPTIONS_DUMP_DEFAULTS 2
-#define OPTIONS_DUMP_ALL 3
+#define OPTIONS_DUMP_ALL 2
char *options_dump(const or_options_t *options, int how_to_dump);
int options_init_from_torrc(int argc, char **argv);
setopt_err_t options_init_from_string(const char *cf_defaults, const char *cf,
@@ -160,13 +159,11 @@ int get_num_cpus(const or_options_t *options);
MOCK_DECL(const smartlist_t *,get_configured_ports,(void));
int port_binds_ipv4(const port_cfg_t *port);
int port_binds_ipv6(const port_cfg_t *port);
-int get_first_advertised_port_by_type_af(int listener_type,
- int address_family);
-#define get_primary_or_port() \
- (get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, AF_INET))
-#define get_primary_dir_port() \
- (get_first_advertised_port_by_type_af(CONN_TYPE_DIR_LISTENER, AF_INET))
-const tor_addr_t *get_first_advertised_addr_by_type_af(int listener_type,
+int portconf_get_first_advertised_port(int listener_type,
+ int address_family);
+#define portconf_get_primary_dir_port() \
+ (portconf_get_first_advertised_port(CONN_TYPE_DIR_LISTENER, AF_INET))
+const tor_addr_t *portconf_get_first_advertised_addr(int listener_type,
int address_family);
int port_exists_by_type_addr_port(int listener_type, const tor_addr_t *addr,
int port, int check_wildcard);
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
index bf58205f89..3b84e5e1f2 100644
--- a/src/app/config/or_options_st.h
+++ b/src/app/config/or_options_st.h
@@ -35,6 +35,12 @@ typedef enum {
TCP_PROXY_PROTOCOL_HAPROXY
} tcp_proxy_protocol_t;
+/** Enumeration of available time formats for output of --key-expiration */
+typedef enum {
+ KEY_EXPIRATION_FORMAT_ISO8601 = 0,
+ KEY_EXPIRATION_FORMAT_TIMESTAMP
+} key_expiration_format_t;
+
/** Configuration options for a Tor process. */
struct or_options_t {
uint32_t magic_;
@@ -71,7 +77,14 @@ struct or_options_t {
int CacheDirectoryGroupReadable; /**< Boolean: Is the CacheDirectory g+r? */
char *Nickname; /**< OR only: nickname of this onion router. */
- char *Address; /**< OR only: configured address for this onion router. */
+ /** OR only: configured address for this onion router. Up to two times this
+ * options is accepted as in IPv4 and IPv6. */
+ struct config_line_t *Address;
+
+ /** Boolean: If set, disable IPv6 address resolution, IPv6 ORPorts, IPv6
+ * reachability checks, and publishing an IPv6 ORPort in its descriptor. */
+ int AddressDisableIPv6;
+
char *PidFile; /**< Where to store PID of Tor process. */
struct routerset_t *ExitNodes; /**< Structure containing nicknames, digests,
@@ -192,7 +205,14 @@ struct or_options_t {
unsigned int HTTPTunnelPort_set : 1;
/**@}*/
- int AssumeReachable; /**< Whether to publish our descriptor regardless. */
+ /** Whether to publish our descriptor regardless of all our self-tests
+ */
+ int AssumeReachable;
+ /** Whether to publish our descriptor regardless of IPv6 self-tests.
+ *
+ * This is an autobool; when set to AUTO, it uses AssumeReachable.
+ **/
+ int AssumeReachableIPv6;
int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */
int V3AuthoritativeDir; /**< Boolean: is this an authoritative directory
* for version 3 directories? */
@@ -648,7 +668,7 @@ struct or_options_t {
int ClientUseIPv4;
/** If true, clients may connect over IPv6. If false, they will avoid
* connecting over IPv4. We enforce this for OR and Dir connections.
- * Use fascist_firewall_use_ipv6() instead of accessing this value
+ * Use reachable_addr_use_ipv6() instead of accessing this value
* directly. */
int ClientUseIPv6;
/** If true, prefer an IPv6 OR port over an IPv4 one for entry node
@@ -658,7 +678,7 @@ struct or_options_t {
int ClientPreferIPv6ORPort;
/** If true, prefer an IPv6 directory port over an IPv4 one for direct
* directory connections. If auto, bridge clients prefer IPv6, and other
- * clients prefer IPv4. Use fascist_firewall_prefer_ipv6_dirport() instead of
+ * clients prefer IPv4. Use reachable_addr_prefer_ipv6_dirport() instead of
* accessing this value directly. */
int ClientPreferIPv6DirPort;
@@ -930,6 +950,8 @@ struct or_options_t {
* ed25519 identity key except from tor --keygen */
int OfflineMasterKey;
+ key_expiration_format_t key_expiration_format;
+
enum {
FORCE_PASSPHRASE_AUTO=0,
FORCE_PASSPHRASE_ON,
diff --git a/src/app/config/or_state_st.h b/src/app/config/or_state_st.h
index 8c4e9d5e61..31b7f8a983 100644
--- a/src/app/config/or_state_st.h
+++ b/src/app/config/or_state_st.h
@@ -65,6 +65,14 @@ struct or_state_t {
int BWHistoryWriteInterval;
struct smartlist_t *BWHistoryWriteValues;
struct smartlist_t *BWHistoryWriteMaxima;
+ time_t BWHistoryIPv6ReadEnds;
+ int BWHistoryIPv6ReadInterval;
+ struct smartlist_t *BWHistoryIPv6ReadValues;
+ struct smartlist_t *BWHistoryIPv6ReadMaxima;
+ time_t BWHistoryIPv6WriteEnds;
+ int BWHistoryIPv6WriteInterval;
+ struct smartlist_t *BWHistoryIPv6WriteValues;
+ struct smartlist_t *BWHistoryIPv6WriteMaxima;
time_t BWHistoryDirReadEnds;
int BWHistoryDirReadInterval;
struct smartlist_t *BWHistoryDirReadValues;
diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c
index 9d1a8e0260..b37707d2da 100644
--- a/src/app/config/resolve_addr.c
+++ b/src/app/config/resolve_addr.c
@@ -14,301 +14,822 @@
#include "core/mainloop/mainloop.h"
#include "feature/control/control_events.h"
+#include "feature/dirauth/authmode.h"
+#include "lib/encoding/confline.h"
#include "lib/net/gethostname.h"
#include "lib/net/resolve.h"
-/** Last value actually set by resolve_my_address. */
-static uint32_t last_resolved_addr = 0;
+/** Maximum "Address" statement allowed in our configuration. */
+#define MAX_CONFIG_ADDRESS 2
+
+/** Ease our life. Arrays containing state per address family. These are to
+ * add semantic to the code so we know what is accessed. */
+#define IDX_NULL 0 /* Index to zeroed address object. */
+#define IDX_IPV4 1 /* Index to AF_INET. */
+#define IDX_IPV6 2 /* Index to AF_INET6. */
+#define IDX_SIZE 3 /* How many indexes do we have. */
+
+/** Function in our address function table return one of these code. */
+typedef enum {
+ /* The address has been found. */
+ FN_RET_OK = 0,
+ /* The failure requirements were not met and thus it is recommended that the
+ * caller stops the search. */
+ FN_RET_BAIL = 1,
+ /* The address was not found or failure is transient so the caller should go
+ * to the next method. */
+ FN_RET_NEXT = 2,
+} fn_address_ret_t;
+
+/** Last resolved addresses. */
+static tor_addr_t last_resolved_addrs[] =
+ { TOR_ADDR_NULL, TOR_ADDR_NULL, TOR_ADDR_NULL };
+CTASSERT(ARRAY_LENGTH(last_resolved_addrs) == IDX_SIZE);
+
+/** Last suggested addresses.
+ *
+ * These addresses come from a NETINFO cell from a trusted relay (currently
+ * only authorities). We only use those in last resort. */
+static tor_addr_t last_suggested_addrs[] =
+ { TOR_ADDR_NULL, TOR_ADDR_NULL, TOR_ADDR_NULL };
+CTASSERT(ARRAY_LENGTH(last_suggested_addrs) == IDX_SIZE);
+
+/** True iff the address was found to be configured that is from the
+ * configuration file either using Address or ORPort. */
+static bool last_addrs_configured[] = { false, false, false };
+CTASSERT(ARRAY_LENGTH(last_addrs_configured) == IDX_SIZE);
+
+static inline int
+af_to_idx(const int family)
+{
+ switch (family) {
+ case AF_INET:
+ return IDX_IPV4;
+ case AF_INET6:
+ return IDX_IPV6;
+ default:
+ /* It wouldn't be safe to just die here with an assert but we can heavily
+ * scream with a bug. Return the index of the NULL address. */
+ tor_assert_nonfatal_unreached();
+ return IDX_NULL;
+ }
+}
-/** Accessor for last_resolved_addr from outside this file. */
-uint32_t
-get_last_resolved_addr(void)
+/** Return string representation of the given method. */
+const char *
+resolved_addr_method_to_str(const resolved_addr_method_t method)
{
- return last_resolved_addr;
+ switch (method) {
+ case RESOLVED_ADDR_NONE:
+ return "NONE";
+ case RESOLVED_ADDR_CONFIGURED:
+ return "CONFIGURED";
+ case RESOLVED_ADDR_CONFIGURED_ORPORT:
+ return "CONFIGURED_ORPORT";
+ case RESOLVED_ADDR_GETHOSTNAME:
+ return "GETHOSTNAME";
+ case RESOLVED_ADDR_INTERFACE:
+ return "INTERFACE";
+ case RESOLVED_ADDR_RESOLVED:
+ return "RESOLVED";
+ default:
+ tor_assert_nonfatal_unreached();
+ return "???";
+ }
}
-/** Reset last_resolved_addr from outside this file. */
+/** Return true if the last address of family was configured or not. An
+ * address is considered configured if it was found in the Address or ORPort
+ * statement.
+ *
+ * This applies to the address returned by the function
+ * resolved_addr_get_last() which is the cache of discovered addresses. */
+bool
+resolved_addr_is_configured(int family)
+{
+ return last_addrs_configured[af_to_idx(family)];
+}
+
+/** Copy the last suggested address of family into addr_out.
+ *
+ * If no last suggested address exists, the addr_out is a null address (use
+ * tor_addr_is_null() to confirm). */
void
-reset_last_resolved_addr(void)
+resolved_addr_get_suggested(int family, tor_addr_t *addr_out)
{
- last_resolved_addr = 0;
+ tor_addr_copy(addr_out, &last_suggested_addrs[af_to_idx(family)]);
}
-/**
- * Attempt getting our non-local (as judged by tor_addr_is_internal()
- * function) IP address using following techniques, listed in
- * order from best (most desirable, try first) to worst (least
- * desirable, try if everything else fails).
- *
- * First, attempt using <b>options-\>Address</b> to get our
- * non-local IP address.
- *
- * If <b>options-\>Address</b> represents a non-local IP address,
- * consider it ours.
- *
- * If <b>options-\>Address</b> is a DNS name that resolves to
- * a non-local IP address, consider this IP address ours.
- *
- * If <b>options-\>Address</b> is NULL, fall back to getting local
- * hostname and using it in above-described ways to try and
- * get our IP address.
- *
- * In case local hostname cannot be resolved to a non-local IP
- * address, try getting an IP address of network interface
- * in hopes it will be non-local one.
- *
- * Fail if one or more of the following is true:
- * - DNS name in <b>options-\>Address</b> cannot be resolved.
- * - <b>options-\>Address</b> is a local host address.
- * - Attempt at getting local hostname fails.
- * - Attempt at getting network interface address fails.
- *
- * Return 0 if all is well, or -1 if we can't find a suitable
- * public IP address.
- *
- * If we are returning 0:
- * - Put our public IP address (in host order) into *<b>addr_out</b>.
- * - If <b>method_out</b> is non-NULL, set *<b>method_out</b> to a static
- * string describing how we arrived at our answer.
- * - "CONFIGURED" - parsed from IP address string in
- * <b>options-\>Address</b>
- * - "RESOLVED" - resolved from DNS name in <b>options-\>Address</b>
- * - "GETHOSTNAME" - resolved from a local hostname.
- * - "INTERFACE" - retrieved from a network interface.
- * - If <b>hostname_out</b> is non-NULL, and we resolved a hostname to
- * get our address, set *<b>hostname_out</b> to a newly allocated string
- * holding that hostname. (If we didn't get our address by resolving a
- * hostname, set *<b>hostname_out</b> to NULL.)
- *
- * XXXX ipv6
+/** Set the last suggested address into our cache. This is called when we get
+ * a new NETINFO cell from a trusted source. */
+void
+resolved_addr_set_suggested(const tor_addr_t *addr)
+{
+ if (BUG(tor_addr_family(addr) != AF_INET &&
+ tor_addr_family(addr) != AF_INET6)) {
+ return;
+ }
+ tor_addr_copy(&last_suggested_addrs[af_to_idx(tor_addr_family(addr))],
+ addr);
+}
+
+/** Copy the last resolved address of family into addr_out.
+ *
+ * If not last resolved address existed, the addr_out is a null address (use
+ * tor_addr_is_null()). */
+void
+resolved_addr_get_last(int family, tor_addr_t *addr_out)
+{
+ tor_addr_copy(addr_out, &last_resolved_addrs[af_to_idx(family)]);
+}
+
+/** Reset the last resolved address of family.
+ *
+ * This makes it null address. */
+void
+resolved_addr_reset_last(int family)
+{
+ tor_addr_make_null(&last_resolved_addrs[af_to_idx(family)], family);
+}
+
+/** Errors returned by address_can_be_used() in order for the caller to know
+ * why the address is denied or not. */
+#define ERR_DEFAULT_DIRAUTH -1 /* Using default authorities. */
+#define ERR_ADDRESS_IS_INTERNAL -2 /* IP is internal. */
+
+/** @brief Return true iff the given IP address can be used as a valid
+ * external resolved address.
+ *
+ * Two tests are done in this function:
+ * 1) If the address if NOT internal, it can be used.
+ * 2) If the address is internal and we have custom directory authorities
+ * configured then it can they be used. Important for testing networks.
+ *
+ * @param addr The IP address to validate.
+ * @param options Global configuration options.
+ * @param warn_severity Log level that should be used on error.
+ * @param explicit_ip Was the IP address explicitly given.
+ *
+ * @return Return 0 if it can be used. Return error code ERR_* found at the
+ * top of the file.
*/
-int
-resolve_my_address(int warn_severity, const or_options_t *options,
- uint32_t *addr_out,
- const char **method_out, char **hostname_out)
+static int
+address_can_be_used(const tor_addr_t *addr, const or_options_t *options,
+ int warn_severity, const bool explicit_ip)
{
- struct in_addr in;
- uint32_t addr; /* host order */
- char hostname[256];
- const char *method_used;
- const char *hostname_used;
- int explicit_ip=1;
- int explicit_hostname=1;
- int from_interface=0;
- char *addr_string = NULL;
- const char *address = options->Address;
- int notice_severity = warn_severity <= LOG_NOTICE ?
- LOG_NOTICE : warn_severity;
-
- tor_addr_t myaddr;
+ tor_assert(addr);
+
+ /* Public address, this is fine. */
+ if (!tor_addr_is_internal(addr, 0)) {
+ goto allow;
+ }
+
+ /* We have a private IP address. It is allowed only if we set custom
+ * directory authorities. */
+ if (using_default_dir_authorities(options)) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Address '%s' is a private IP address. Tor relays that use "
+ "the default DirAuthorities must have public IP addresses.",
+ fmt_addr(addr));
+ return ERR_DEFAULT_DIRAUTH;
+ }
+
+ if (!explicit_ip) {
+ /* Even with custom directory authorities, only an explicit internal
+ * address is accepted. */
+ log_fn(warn_severity, LD_CONFIG,
+ "Address %s was resolved and thus not explicitly "
+ "set. Even if DirAuthorities are custom, this is "
+ "not allowed.", fmt_addr(addr));
+ return ERR_ADDRESS_IS_INTERNAL;
+ }
+
+ allow:
+ return 0;
+}
+
+/** @brief Get IP address from the given config line and for a specific address
+ * family.
+ *
+ * This can fail is more than two Address statement are found for the same
+ * address family. It also fails if no statement is found.
+ *
+ * @param options Global configuration options.
+ * @param warn_severity Log level that should be used on error.
+ * @param family IP address family. Only AF_INET and AF_INET6 are supported.
+ * @param method_out OUT: Method denoting how the address was found.
+ * This is described in the control-spec.txt as
+ * actions for "STATUS_SERVER".
+ * @param hostname_out OUT: String containing the hostname gotten from the
+ * Address value if any.
+ * @param addr_out OUT: Tor address of the address found in the cline or
+ * resolved from the cline.
+ *
+ * @return Return 0 on success that is an address has been found or resolved
+ * successfully. Return error code ERR_* found at the top of the file.
+ */
+static fn_address_ret_t
+get_address_from_config(const or_options_t *options, int warn_severity,
+ int family, resolved_addr_method_t *method_out,
+ char **hostname_out, tor_addr_t *addr_out)
+{
+ int ret;
+ bool explicit_ip = false, resolve_failure = false;
+ int num_valid_addr = 0;
+
+ tor_assert(options);
tor_assert(addr_out);
+ tor_assert(method_out);
+ tor_assert(hostname_out);
- /*
- * Step one: Fill in 'hostname' to be our best guess.
- */
+ /* Set them to NULL for safety reasons. */
+ *hostname_out = NULL;
+ *method_out = RESOLVED_ADDR_NONE;
- if (address && *address) {
- strlcpy(hostname, address, sizeof(hostname));
- log_debug(LD_CONFIG, "Trying configured Address '%s' as local hostname",
- hostname);
- } else { /* then we need to guess our address */
- explicit_ip = 0; /* it's implicit */
- explicit_hostname = 0; /* it's implicit */
-
- if (tor_gethostname(hostname, sizeof(hostname)) < 0) {
- log_fn(warn_severity, LD_NET,"Error obtaining local hostname");
- return -1;
- }
- log_debug(LD_CONFIG, "Guessed local host name as '%s'", hostname);
+ log_debug(LD_CONFIG, "Attempting to get address from configuration");
+
+ if (!options->Address) {
+ log_info(LD_CONFIG, "No Address option found in configuration.");
+ /* No Address statement, inform caller to try next method. */
+ return FN_RET_NEXT;
}
- /*
- * Step two: Now that we know 'hostname', parse it or resolve it. If
- * it doesn't parse or resolve, look at the interface address. Set 'addr'
- * to be our (host-order) 32-bit answer.
- */
+ for (const config_line_t *cfg = options->Address; cfg != NULL;
+ cfg = cfg->next) {
+ int af;
+ tor_addr_t addr;
+
+ af = tor_addr_parse(&addr, cfg->value);
+ if (af == family) {
+ tor_addr_copy(addr_out, &addr);
+ *method_out = RESOLVED_ADDR_CONFIGURED;
+ explicit_ip = true;
+ num_valid_addr++;
+ continue;
+ } else if (af != -1) {
+ /* Parsable address but just not the one from the family we want. Skip
+ * it so we don't attempt a resolve. */
+ continue;
+ }
- if (tor_inet_aton(hostname, &in) == 0) {
- /* then we have to resolve it */
- log_debug(LD_CONFIG, "Local hostname '%s' is DNS address. "
- "Trying to resolve to IP address.", hostname);
- explicit_ip = 0;
- if (tor_lookup_hostname(hostname, &addr)) { /* failed to resolve */
- uint32_t interface_ip; /* host order */
-
- if (explicit_hostname) {
- log_fn(warn_severity, LD_CONFIG,
- "Could not resolve local Address '%s'. Failing.", hostname);
- return -1;
- }
- log_fn(notice_severity, LD_CONFIG,
- "Could not resolve guessed local hostname '%s'. "
- "Trying something else.", hostname);
- if (get_interface_address(warn_severity, &interface_ip)) {
- log_fn(warn_severity, LD_CONFIG,
- "Could not get local interface IP address. Failing.");
- return -1;
- }
- from_interface = 1;
- addr = interface_ip;
- log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for "
- "local interface. Using that.", fmt_addr32(addr));
- strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
- } else { /* resolved hostname into addr */
- tor_addr_from_ipv4h(&myaddr, addr);
-
- if (!explicit_hostname &&
- tor_addr_is_internal(&myaddr, 0)) {
- tor_addr_t interface_ip;
-
- log_fn(notice_severity, LD_CONFIG, "Guessed local hostname '%s' "
- "resolves to a private IP address (%s). Trying something "
- "else.", hostname, fmt_addr32(addr));
-
- if (get_interface_address6(warn_severity, AF_INET, &interface_ip)<0) {
- log_fn(warn_severity, LD_CONFIG,
- "Could not get local interface IP address. Too bad.");
- } else if (tor_addr_is_internal(&interface_ip, 0)) {
- log_fn(notice_severity, LD_CONFIG,
- "Interface IP address '%s' is a private address too. "
- "Ignoring.", fmt_addr(&interface_ip));
- } else {
- from_interface = 1;
- addr = tor_addr_to_ipv4h(&interface_ip);
- log_fn(notice_severity, LD_CONFIG,
- "Learned IP address '%s' for local interface."
- " Using that.", fmt_addr32(addr));
- strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
- }
+ /* Not an IP address. Considering this value a hostname and attempting to
+ * do a DNS lookup. */
+ if (!tor_addr_lookup(cfg->value, family, &addr)) {
+ tor_addr_copy(addr_out, &addr);
+ *method_out = RESOLVED_ADDR_RESOLVED;
+ if (*hostname_out) {
+ tor_free(*hostname_out);
}
+ *hostname_out = tor_strdup(cfg->value);
+ explicit_ip = false;
+ num_valid_addr++;
+ continue;
+ } else {
+ /* Hostname that can't be resolved, this is a fatal error. */
+ resolve_failure = true;
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not resolve local Address '%s'. Failing.", cfg->value);
+ continue;
}
- } else {
- log_debug(LD_CONFIG, "Local hostname '%s' is already IP address, "
- "skipping DNS resolution", hostname);
- addr = ntohl(in.s_addr); /* set addr so that addr_string is not
- * illformed */
}
- /*
- * Step three: Check whether 'addr' is an internal IP address, and error
- * out if it is and we don't want that.
- */
+ if (!num_valid_addr) {
+ if (resolve_failure) {
+ /* We found no address but we got a resolution failure. This means we
+ * can know if the hostname given was v4 or v6 so we can't continue. */
+ return FN_RET_BAIL;
+ }
+ log_info(LD_CONFIG,
+ "No Address option found for family %s in configuration.",
+ fmt_af_family(family));
+ /* No Address statement for family so move on to try next method. */
+ return FN_RET_NEXT;
+ }
- tor_addr_from_ipv4h(&myaddr,addr);
+ if (num_valid_addr >= MAX_CONFIG_ADDRESS) {
+ /* Too many Address for same family. This is a fatal error. */
+ log_fn(warn_severity, LD_CONFIG,
+ "Found %d Address statement of address family %s. "
+ "Only one is allowed.", num_valid_addr, fmt_af_family(family));
+ tor_free(*hostname_out);
+ return FN_RET_BAIL;
+ }
- addr_string = tor_dup_ip(addr);
- if (addr_string && tor_addr_is_internal(&myaddr, 0)) {
- /* make sure we're ok with publishing an internal IP */
- if (using_default_dir_authorities(options)) {
- /* if they are using the default authorities, disallow internal IPs
- * always. For IPv6 ORPorts, this check is done in
- * router_get_advertised_ipv6_or_ap(). See #33681. */
- log_fn(warn_severity, LD_CONFIG,
- "Address '%s' resolves to private IP address '%s'. "
- "Tor servers that use the default DirAuthorities must have "
- "public IP addresses.", hostname, addr_string);
- tor_free(addr_string);
- return -1;
- }
- if (!explicit_ip) {
- /* even if they've set their own authorities, require an explicit IP if
- * they're using an internal address. */
- log_fn(warn_severity, LD_CONFIG, "Address '%s' resolves to private "
- "IP address '%s'. Please set the Address config option to be "
- "the IP address you want to use.", hostname, addr_string);
- tor_free(addr_string);
- return -1;
- }
+ /* Great, we found an address. */
+ ret = address_can_be_used(addr_out, options, warn_severity, explicit_ip);
+ if (ret != 0) {
+ /* One of the requirement of this interface is if an internal Address is
+ * used, custom authorities must be defined else it is a fatal error.
+ * Furthermore, if the Address was resolved to an internal interface, we
+ * stop immediately. */
+ tor_free(*hostname_out);
+ return FN_RET_BAIL;
}
- /*
- * Step four: We have a winner! 'addr' is our answer for sure, and
- * 'addr_string' is its string form. Fill out the various fields to
- * say how we decided it.
- */
+ /* Address can be used. We are done. */
+ log_info(LD_CONFIG, "Address found in configuration: %s",
+ fmt_addr(addr_out));
+ return FN_RET_OK;
+}
- log_debug(LD_CONFIG, "Resolved Address to '%s'.", addr_string);
-
- if (explicit_ip) {
- method_used = "CONFIGURED";
- hostname_used = NULL;
- } else if (explicit_hostname) {
- method_used = "RESOLVED";
- hostname_used = hostname;
- } else if (from_interface) {
- method_used = "INTERFACE";
- hostname_used = NULL;
- } else {
- method_used = "GETHOSTNAME";
- hostname_used = hostname;
+/** @brief Get IP address from the local hostname by calling gethostbyname()
+ * and doing a DNS resolution on the hostname.
+ *
+ * @param options Global configuration options.
+ * @param warn_severity Log level that should be used on error.
+ * @param family IP address family. Only AF_INET and AF_INET6 are supported.
+ * @param method_out OUT: Method denoting how the address was found.
+ * This is described in the control-spec.txt as
+ * actions for "STATUS_SERVER".
+ * @param hostname_out OUT: String containing the local hostname.
+ * @param addr_out OUT: Tor address resolved from the local hostname.
+ *
+ * @return Return 0 on success that is an address has been found and resolved
+ * successfully. Return error code ERR_* found at the top of the file.
+ */
+static fn_address_ret_t
+get_address_from_hostname(const or_options_t *options, int warn_severity,
+ int family, resolved_addr_method_t *method_out,
+ char **hostname_out, tor_addr_t *addr_out)
+{
+ int ret;
+ char hostname[256];
+
+ tor_assert(addr_out);
+ tor_assert(method_out);
+
+ /* Set them to NULL for safety reasons. */
+ *hostname_out = NULL;
+ *method_out = RESOLVED_ADDR_NONE;
+
+ log_debug(LD_CONFIG, "Attempting to get address from local hostname");
+
+ if (tor_gethostname(hostname, sizeof(hostname)) < 0) {
+ log_fn(warn_severity, LD_NET, "Error obtaining local hostname");
+ /* Unable to obtain the local hostname is a fatal error. */
+ return FN_RET_BAIL;
+ }
+ if (tor_addr_lookup(hostname, family, addr_out)) {
+ log_fn(warn_severity, LD_NET,
+ "Could not resolve local hostname '%s'. Failing.", hostname);
+ /* Unable to resolve, inform caller to try next method. */
+ return FN_RET_NEXT;
}
- *addr_out = addr;
- if (method_out)
- *method_out = method_used;
- if (hostname_out)
- *hostname_out = hostname_used ? tor_strdup(hostname_used) : NULL;
+ ret = address_can_be_used(addr_out, options, warn_severity, false);
+ if (ret == ERR_DEFAULT_DIRAUTH) {
+ /* Non custom authorities, inform caller to try next method. */
+ return FN_RET_NEXT;
+ } else if (ret == ERR_ADDRESS_IS_INTERNAL) {
+ /* Internal address is a fatal error. */
+ return FN_RET_BAIL;
+ }
- /*
- * Step five: Check if the answer has changed since last time (or if
- * there was no last time), and if so call various functions to keep
- * us up-to-date.
- */
+ /* addr_out contains the address of the local hostname. */
+ *method_out = RESOLVED_ADDR_GETHOSTNAME;
+ *hostname_out = tor_strdup(hostname);
+
+ /* Found it! */
+ log_info(LD_CONFIG, "Address found from local hostname: %s",
+ fmt_addr(addr_out));
+ return FN_RET_OK;
+}
+
+/** @brief Get IP address from a network interface.
+ *
+ * @param options Global configuration options.
+ * @param warn_severity Log level that should be used on error.
+ * @param family IP address family. Only AF_INET and AF_INET6 are supported.
+ * @param method_out OUT: Always RESOLVED_ADDR_INTERFACE on success which
+ * is detailed in the control-spec.txt as actions
+ * for "STATUS_SERVER".
+ * @param hostname_out OUT: String containing the local hostname. For this
+ * function, it is always set to NULL.
+ * @param addr_out OUT: Tor address found attached to the interface.
+ *
+ * @return Return 0 on success that is an address has been found. Return
+ * error code ERR_* found at the top of the file.
+ */
+static fn_address_ret_t
+get_address_from_interface(const or_options_t *options, int warn_severity,
+ int family, resolved_addr_method_t *method_out,
+ char **hostname_out, tor_addr_t *addr_out)
+{
+ int ret;
+
+ tor_assert(method_out);
+ tor_assert(hostname_out);
+ tor_assert(addr_out);
+
+ /* Set them to NULL for safety reasons. */
+ *method_out = RESOLVED_ADDR_NONE;
+ *hostname_out = NULL;
+
+ log_debug(LD_CONFIG, "Attempting to get address from network interface");
+
+ if (get_interface_address6(warn_severity, family, addr_out) < 0) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not get local interface IP address.");
+ /* Unable to get IP from interface. Inform caller to try next method. */
+ return FN_RET_NEXT;
+ }
+
+ ret = address_can_be_used(addr_out, options, warn_severity, false);
+ if (ret < 0) {
+ /* Unable to use address. Inform caller to try next method. */
+ return FN_RET_NEXT;
+ }
- if (last_resolved_addr && last_resolved_addr != *addr_out) {
+ *method_out = RESOLVED_ADDR_INTERFACE;
+
+ /* Found it! */
+ log_info(LD_CONFIG, "Address found from interface: %s", fmt_addr(addr_out));
+ return FN_RET_OK;
+}
+
+/** @brief Get IP address from the ORPort (if any).
+ *
+ * @param options Global configuration options.
+ * @param warn_severity Log level that should be used on error.
+ * @param family IP address family. Only AF_INET and AF_INET6 are supported.
+ * @param method_out OUT: Always RESOLVED_ADDR_CONFIGURED_ORPORT on success
+ * which is detailed in the control-spec.txt as actions
+ * for "STATUS_SERVER".
+ * @param hostname_out OUT: String containing the ORPort hostname if any.
+ * @param addr_out OUT: Tor address found if any.
+ *
+ * @return Return 0 on success that is an address has been found. Return
+ * error code ERR_* found at the top of the file.
+ */
+static fn_address_ret_t
+get_address_from_orport(const or_options_t *options, int warn_severity,
+ int family, resolved_addr_method_t *method_out,
+ char **hostname_out, tor_addr_t *addr_out)
+{
+ int ret;
+ const tor_addr_t *addr;
+
+ tor_assert(method_out);
+ tor_assert(hostname_out);
+ tor_assert(addr_out);
+
+ /* Set them to NULL for safety reasons. */
+ *method_out = RESOLVED_ADDR_NONE;
+ *hostname_out = NULL;
+
+ log_debug(LD_CONFIG, "Attempting to get address from ORPort");
+
+ if (!options->ORPort_set) {
+ log_info(LD_CONFIG, "No ORPort found in configuration.");
+ /* No ORPort statement, inform caller to try next method. */
+ return FN_RET_NEXT;
+ }
+
+ /* Get ORPort for requested family. */
+ addr = get_orport_addr(family);
+ if (!addr) {
+ /* No address configured for the ORPort. Ignore. */
+ return FN_RET_NEXT;
+ }
+
+ /* We found the ORPort address. Just make sure it can be used. */
+ ret = address_can_be_used(addr, options, warn_severity, true);
+ if (ret < 0) {
+ /* Unable to use address. Inform caller to try next method. */
+ return FN_RET_NEXT;
+ }
+
+ /* Found it! */
+ *method_out = RESOLVED_ADDR_CONFIGURED_ORPORT;
+ tor_addr_copy(addr_out, addr);
+
+ log_fn(warn_severity, LD_CONFIG, "Address found from ORPort: %s",
+ fmt_addr(addr_out));
+ return FN_RET_OK;
+}
+
+/** @brief Set the last resolved address cache using the given address.
+ *
+ * A log notice is emitted if the given address has changed from before. Not
+ * emitted on first resolve.
+ *
+ * Control port event "STATUS_SERVER" is emitted with the new information if
+ * it has changed.
+ *
+ * Finally, tor is notified that the IP address has changed.
+ *
+ * @param addr IP address to update the cache with.
+ * @param method_used By which method did we resolved it (for logging and
+ * control port).
+ * @param hostname_used Which hostname was used. If none were used, it is
+ * NULL. (for logging and control port).
+ */
+void
+resolved_addr_set_last(const tor_addr_t *addr,
+ const resolved_addr_method_t method_used,
+ const char *hostname_used)
+{
+ /** Have we done a first resolve. This is used to control logging. */
+ static bool have_resolved_once[] = { false, false, false };
+ CTASSERT(ARRAY_LENGTH(have_resolved_once) == IDX_SIZE);
+
+ bool *done_one_resolve;
+ bool have_hostname = false;
+ tor_addr_t *last_resolved;
+
+ tor_assert(addr);
+
+ /* Do we have an hostname. */
+ have_hostname = (hostname_used != NULL);
+
+ int idx = af_to_idx(tor_addr_family(addr));
+ if (idx == IDX_NULL) {
+ /* Not suppose to happen and if it does, af_to_idx() screams loudly. */
+ return;
+ }
+
+ /* Get values from cache. */
+ done_one_resolve = &have_resolved_once[idx];
+ last_resolved = &last_resolved_addrs[idx];
+
+ /* Same address last resolved. Ignore. */
+ if (tor_addr_eq(last_resolved, addr)) {
+ return;
+ }
+
+ /* Don't log notice if this is the first resolve we do. */
+ if (*done_one_resolve) {
/* Leave this as a notice, regardless of the requested severity,
* at least until dynamic IP address support becomes bulletproof. */
log_notice(LD_NET,
"Your IP address seems to have changed to %s "
"(METHOD=%s%s%s). Updating.",
- addr_string, method_used,
- hostname_used ? " HOSTNAME=" : "",
- hostname_used ? hostname_used : "");
+ fmt_addr(addr),
+ resolved_addr_method_to_str(method_used),
+ have_hostname ? " HOSTNAME=" : "",
+ have_hostname ? hostname_used : "");
ip_address_changed(0);
}
- if (last_resolved_addr != *addr_out) {
- control_event_server_status(LOG_NOTICE,
- "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s%s%s",
- addr_string, method_used,
- hostname_used ? " HOSTNAME=" : "",
- hostname_used ? hostname_used : "");
+ /* Notify control port. */
+ control_event_server_status(LOG_NOTICE,
+ "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s%s%s",
+ fmt_addr(addr),
+ resolved_addr_method_to_str(method_used),
+ have_hostname ? " HOSTNAME=" : "",
+ have_hostname ? hostname_used : "");
+ /* Copy address to cache. */
+ tor_addr_copy(last_resolved, addr);
+ *done_one_resolve = true;
+
+ /* Flag true if the address was configured. Else, indicate it was not. */
+ last_addrs_configured[idx] = false;
+ if (method_used == RESOLVED_ADDR_CONFIGURED ||
+ method_used == RESOLVED_ADDR_CONFIGURED_ORPORT) {
+ last_addrs_configured[idx] = true;
+ }
+}
+
+/** Ease our lives. Typedef to the address discovery function signature. */
+typedef fn_address_ret_t
+ (*fn_address_t)(
+ const or_options_t *options, int warn_severity, int family,
+ resolved_addr_method_t *method_out, char **hostname_out,
+ tor_addr_t *addr_out);
+
+/** Address discovery function table. The order matters as in the first one is
+ * executed first and so on. */
+static const fn_address_t fn_address_table[] =
+{
+ /* These functions are in order for our find address algorithm. */
+ get_address_from_config,
+ get_address_from_orport,
+ get_address_from_interface,
+ get_address_from_hostname,
+};
+/** Length of address table as in how many functions. */
+static const size_t fn_address_table_len =
+ ARRAY_LENGTH(fn_address_table);
+
+/* Address discover function table for authorities (bridge or directory).
+ *
+ * They only discover their address from either the configuration file or the
+ * ORPort. They do not query the interface nor do any DNS resolution for
+ * security reasons. */
+static const fn_address_t fn_address_table_auth[] =
+{
+ /* These functions are in order for our find address algorithm. */
+ get_address_from_config,
+ get_address_from_orport,
+};
+/** Length of address table as in how many functions. */
+static const size_t fn_address_table_auth_len =
+ ARRAY_LENGTH(fn_address_table_auth);
+
+/** @brief Attempt to find our IP address that can be used as our external
+ * reachable address.
+ *
+ * The following describe the algorithm to find an address. Each have
+ * specific conditions so read carefully.
+ *
+ * On success, true is returned and depending on how the address was found,
+ * the out parameters can have different values.
+ *
+ * On error, false is returned and out parameters are set to NULL.
+ *
+ * 1. Look at the configuration Address option.
+
+ * If Address is a public address, True is returned and addr_out is set
+ * with it, the method_out is set to RESOLVED_ADDR_CONFIGURED and
+ * hostname_out is set to NULL.
+ *
+ * If Address is an internal address but NO custom authorities are used,
+ * an error is returned.
+ *
+ * If Address is a hostname, that is it can't be converted to an address,
+ * it is resolved. On success, addr_out is set with the address,
+ * method_out is set to RESOLVED_ADDR_RESOLVED and hostname_out is set
+ * to the resolved hostname. On failure to resolve, an error is returned.
+ *
+ * If no given Address, fallback to the local hostname (see section 2).
+ *
+ * 2. Look at the network interface.
+ *
+ * Attempt to find the first public usable address from the list of
+ * network interface returned by the OS.
+ *
+ * On failure, we attempt to look at the local hostname (3).
+ *
+ * On success, addr_out is set with it, method_out is set to
+ * RESOLVED_ADDR_INTERFACE and hostname_out is set to NULL.
+ *
+ * 3. Look at the local hostname.
+ *
+ * If the local hostname resolves to a non internal address, addr_out is
+ * set with it, method_out is set to RESOLVED_ADDR_GETHOSTNAME and
+ * hostname_out is set to the resolved hostname.
+ *
+ * If a local hostname can NOT be found, an error is returned.
+ *
+ * If the local hostname resolves to an internal address, an error is
+ * returned.
+ *
+ * If the local hostname can NOT be resolved, an error is returned.
+ *
+ * @param options Global configuration options.
+ * @param family IP address family. Only AF_INET and AF_INET6 are supported.
+ * @param warn_severity Logging level.
+ * @param addr_out OUT: Set with the IP address found if any.
+ * @param method_out OUT: (optional) Method denoting how the address wa
+ * found. This is described in the control-spec.txt as
+ * actions for "STATUS_SERVER".
+ * @param hostname_out OUT: String containing the hostname if any was used.
+ * Only be set for RESOLVED and GETHOSTNAME methods.
+ * Else it is set to NULL.
+ *
+ * @return True if the address was found for the given family. False if not or
+ * on errors.
+ */
+bool
+find_my_address(const or_options_t *options, int family, int warn_severity,
+ tor_addr_t *addr_out, resolved_addr_method_t *method_out,
+ char **hostname_out)
+{
+ resolved_addr_method_t method_used = RESOLVED_ADDR_NONE;
+ char *hostname_used = NULL;
+ tor_addr_t my_addr;
+ const fn_address_t *table = fn_address_table;
+ size_t table_len = fn_address_table_len;
+
+ tor_assert(options);
+ tor_assert(addr_out);
+
+ /* Set them to NULL for safety reasons. */
+ tor_addr_make_unspec(addr_out);
+ if (method_out) *method_out = RESOLVED_ADDR_NONE;
+ if (hostname_out) *hostname_out = NULL;
+
+ /* If an IPv6 is requested, check if IPv6 address discovery is disabled and
+ * if so we always return a failure. It is done here so we don't populate
+ * the resolve cache or do any DNS resolution. */
+ if (family == AF_INET6 && options->AddressDisableIPv6) {
+ return false;
+ }
+
+ /* For authorities (bridge and directory), we use a different table. */
+ if (authdir_mode(options)) {
+ table = fn_address_table_auth;
+ table_len = fn_address_table_auth_len;
}
- last_resolved_addr = *addr_out;
/*
- * And finally, clean up and return success.
+ * Step 1: Discover address by calling methods from the function table.
*/
- tor_free(addr_string);
- return 0;
+ /* Go over the function table. They are in order. */
+ for (size_t idx = 0; idx < table_len; idx++) {
+ fn_address_ret_t ret = table[idx](options, warn_severity, family,
+ &method_used, &hostname_used, &my_addr);
+ if (ret == FN_RET_BAIL) {
+ return false;
+ } else if (ret == FN_RET_OK) {
+ goto found;
+ }
+ tor_assert(ret == FN_RET_NEXT);
+ }
+
+ /* We've exhausted our attempts. Failure. */
+ log_fn(warn_severity, LD_CONFIG, "Unable to find our IP address.");
+ return false;
+
+ found:
+ /*
+ * Step 2: Update last resolved address cache and inform the control port.
+ */
+ resolved_addr_set_last(&my_addr, method_used, hostname_used);
+
+ if (method_out) {
+ *method_out = method_used;
+ }
+ if (hostname_out) {
+ *hostname_out = hostname_used;
+ } else {
+ tor_free(hostname_used);
+ }
+
+ tor_addr_copy(addr_out, &my_addr);
+ return true;
}
-/** Return true iff <b>addr</b> is judged to be on the same network as us, or
- * on a private network.
+/** @brief: Return true iff the given addr is judged to be local to our
+ * resolved address.
+ *
+ * This function is used to tell whether another address is 'remote' enough
+ * that we can trust it when it tells us that we are reachable, or that we
+ * have a certain address.
+ *
+ * The criterion to learn if the address is local are the following:
+ *
+ * 1. Internal address.
+ * 2. If EnforceDistinctSubnets is set then it is never local.
+ * 3. Network mask is compared. IPv4: /24 and IPv6 /48. This is different
+ * from the path selection that looks at /16 and /32 because we only
+ * want to learn here if the address is considered to come from the
+ * Internet basically.
+ *
+ * @param addr The address to test if local and also test against our resovled
+ * address.
+ *
+ * @return True iff address is considered local or else False.
*/
-MOCK_IMPL(int,
-is_local_addr, (const tor_addr_t *addr))
+MOCK_IMPL(bool,
+is_local_to_resolve_addr, (const tor_addr_t *addr))
{
- if (tor_addr_is_internal(addr, 0))
- return 1;
- /* Check whether ip is on the same /24 as we are. */
- if (get_options()->EnforceDistinctSubnets == 0)
- return 0;
- if (tor_addr_family(addr) == AF_INET) {
- uint32_t ip = tor_addr_to_ipv4h(addr);
+ const int family = tor_addr_family(addr);
+ const tor_addr_t *last_resolved_addr =
+ &last_resolved_addrs[af_to_idx(family)];
+
+ /* Internal address is always local. */
+ if (tor_addr_is_internal(addr, 0)) {
+ return true;
+ }
+ /* Address is not local if we don't enforce subnet distinction. */
+ if (get_options()->EnforceDistinctSubnets == 0) {
+ return false;
+ }
+
+ switch (family) {
+ case AF_INET:
/* It's possible that this next check will hit before the first time
- * resolve_my_address actually succeeds. (For clients, it is likely that
- * resolve_my_address will never be called at all). In those cases,
- * last_resolved_addr will be 0, and so checking to see whether ip is on
- * the same /24 as last_resolved_addr will be the same as checking whether
- * it was on net 0, which is already done by tor_addr_is_internal.
- */
- if ((last_resolved_addr & (uint32_t)0xffffff00ul)
- == (ip & (uint32_t)0xffffff00ul))
- return 1;
+ * find_my_address actually succeeds. For clients, it is likely that
+ * find_my_address will never be called at all. In those cases,
+ * last_resolved_addr_v4 will be 0, and so checking to see whether ip is
+ * on the same /24 as last_resolved_addrs[AF_INET] will be the same as
+ * checking whether it was on net 0, which is already done by
+ * tor_addr_is_internal. */
+ return tor_addr_compare_masked(addr, last_resolved_addr, 24,
+ CMP_SEMANTIC) == 0;
+ case AF_INET6:
+ /* Look at /48 because it is typically the smallest network in the global
+ * IPv6 routing tables, and it was previously the recommended per-customer
+ * network block. (See [RFC 6177: IPv6 End Site Address Assignment].) */
+ return tor_addr_compare_masked(addr, last_resolved_addr, 48,
+ CMP_SEMANTIC) == 0;
+ break;
+ default:
+ /* Unknown address type so not local. */
+ return false;
}
- return 0;
}
+
+#ifdef TOR_UNIT_TESTS
+
+void
+resolve_addr_reset_suggested(int family)
+{
+ tor_addr_make_unspec(&last_suggested_addrs[af_to_idx(family)]);
+}
+
+#endif /* TOR_UNIT_TESTS */
diff --git a/src/app/config/resolve_addr.h b/src/app/config/resolve_addr.h
index 3747546402..96c86eeeea 100644
--- a/src/app/config/resolve_addr.h
+++ b/src/app/config/resolve_addr.h
@@ -9,19 +9,58 @@
#ifndef TOR_CONFIG_RESOLVE_ADDR_H
#define TOR_CONFIG_RESOLVE_ADDR_H
+#include "app/config/config.h"
+#include "core/mainloop/connection.h"
+
#include "app/config/or_options_st.h"
-int resolve_my_address(int warn_severity, const or_options_t *options,
- uint32_t *addr_out,
- const char **method_out, char **hostname_out);
+/** Method used to resolved an address. In other words, how was the address
+ * discovered by tor. */
+typedef enum {
+ /* Default value. Indiate that no method found the address. */
+ RESOLVED_ADDR_NONE = 0,
+ /* Found from the "Address" configuration option. */
+ RESOLVED_ADDR_CONFIGURED = 1,
+ /* Found from the "ORPort" configuration option. */
+ RESOLVED_ADDR_CONFIGURED_ORPORT = 2,
+ /* Found by resolving the local hostname. */
+ RESOLVED_ADDR_GETHOSTNAME = 3,
+ /* Found by querying the local interface(s). */
+ RESOLVED_ADDR_INTERFACE = 4,
+ /* Found by resolving the hostname from the Address configuration option. */
+ RESOLVED_ADDR_RESOLVED = 5,
+} resolved_addr_method_t;
+
+const char *resolved_addr_method_to_str(const resolved_addr_method_t method);
+
+#define get_orport_addr(family) \
+ (portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER, family))
+
+bool find_my_address(const or_options_t *options, int family,
+ int warn_severity, tor_addr_t *addr_out,
+ resolved_addr_method_t *method_out, char **hostname_out);
+
+void resolved_addr_get_last(int family, tor_addr_t *addr_out);
+void resolved_addr_reset_last(int family);
+void resolved_addr_set_last(const tor_addr_t *addr,
+ const resolved_addr_method_t method_used,
+ const char *hostname_used);
-uint32_t get_last_resolved_addr(void);
-void reset_last_resolved_addr(void);
+void resolved_addr_get_suggested(int family, tor_addr_t *addr_out);
+void resolved_addr_set_suggested(const tor_addr_t *addr);
-MOCK_DECL(int, is_local_addr, (const tor_addr_t *addr));
+bool resolved_addr_is_configured(int family);
+
+MOCK_DECL(bool, is_local_to_resolve_addr, (const tor_addr_t *addr));
#ifdef RESOLVE_ADDR_PRIVATE
+#ifdef TOR_UNIT_TESTS
+
+void resolve_addr_reset_suggested(int family);
+
+#endif /* TOR_UNIT_TESTS */
+
#endif /* RESOLVE_ADDR_PRIVATE */
#endif /* TOR_CONFIG_RESOLVE_ADDR_H */
diff --git a/src/app/config/statefile.c b/src/app/config/statefile.c
index dcc55f1898..b25167d2ec 100644
--- a/src/app/config/statefile.c
+++ b/src/app/config/statefile.c
@@ -40,7 +40,7 @@
#include "feature/control/control_events.h"
#include "feature/client/entrynodes.h"
#include "feature/hibernate/hibernate.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/bwhist.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "lib/sandbox/sandbox.h"
@@ -112,6 +112,14 @@ static const config_var_t state_vars_[] = {
V(BWHistoryWriteInterval, POSINT, "900"),
V(BWHistoryWriteValues, CSV, ""),
V(BWHistoryWriteMaxima, CSV, ""),
+ V(BWHistoryIPv6ReadEnds, ISOTIME, NULL),
+ V(BWHistoryIPv6ReadInterval, POSINT, "900"),
+ V(BWHistoryIPv6ReadValues, CSV, ""),
+ V(BWHistoryIPv6ReadMaxima, CSV, ""),
+ V(BWHistoryIPv6WriteEnds, ISOTIME, NULL),
+ V(BWHistoryIPv6WriteInterval, POSINT, "900"),
+ V(BWHistoryIPv6WriteValues, CSV, ""),
+ V(BWHistoryIPv6WriteMaxima, CSV, ""),
V(BWHistoryDirReadEnds, ISOTIME, NULL),
V(BWHistoryDirReadInterval, POSINT, "900"),
V(BWHistoryDirReadValues, CSV, ""),
@@ -324,7 +332,7 @@ or_state_set(or_state_t *new_state)
tor_free(err);
ret = -1;
}
- if (rep_hist_load_state(global_state, &err)<0) {
+ if (bwhist_load_state(global_state, &err)<0) {
log_warn(LD_GENERAL,"Unparseable bandwidth history state: %s",err);
tor_free(err);
ret = -1;
@@ -523,7 +531,7 @@ or_state_save(time_t now)
* to avoid redundant writes. */
(void) subsystems_flush_state(get_state_mgr(), global_state);
entry_guards_update_state(global_state);
- rep_hist_update_state(global_state);
+ bwhist_update_state(global_state);
circuit_build_times_update_state(get_circuit_build_times(), global_state);
if (accounting_is_enabled(get_options()))
diff --git a/src/app/config/testnet.inc b/src/app/config/testnet.inc
index 907c35f97c..00b307782b 100644
--- a/src/app/config/testnet.inc
+++ b/src/app/config/testnet.inc
@@ -1,8 +1,7 @@
// When modifying, don't forget to update the defaults
-// for 'TestingTorNetwork' in 'doc/tor.1.txt'
+// for 'TestingTorNetwork' in 'doc/man/tor.1.txt'
{ "DirAllowPrivateAddresses", "1" },
{ "EnforceDistinctSubnets", "0" },
-{ "AssumeReachable", "1" },
{ "AuthDirMaxServersPerAddr", "0" },
{ "ClientBootstrapConsensusAuthorityDownloadInitialDelay", "0" },
{ "ClientBootstrapConsensusFallbackDownloadInitialDelay", "0" },
diff --git a/src/app/include.am b/src/app/include.am
index 97d53ec0fd..8488a1bf19 100644
--- a/src/app/include.am
+++ b/src/app/include.am
@@ -18,9 +18,9 @@ src_app_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) @TOR_LDFLAGS_li
src_app_tor_LDADD = $(TOR_INTERNAL_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
- @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
if COVERAGE_ENABLED
src_app_tor_cov_SOURCES = $(src_app_tor_SOURCES)
@@ -29,7 +29,7 @@ src_app_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_app_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) @TOR_LDFLAGS_libevent@
src_app_tor_cov_LDADD = $(TOR_INTERNAL_TESTING_LIBS) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
- @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ \
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ \
@CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
endif
diff --git a/src/app/main/main.c b/src/app/main/main.c
index d7d36bff4e..31a4f141ad 100644
--- a/src/app/main/main.c
+++ b/src/app/main/main.c
@@ -53,18 +53,21 @@
#include "feature/rend/rendcache.h"
#include "feature/rend/rendservice.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/bwhist.h"
#include "feature/stats/rephist.h"
#include "lib/compress/compress.h"
#include "lib/buf/buffers.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_s2k.h"
#include "lib/net/resolve.h"
+#include "lib/trace/trace.h"
#include "lib/process/waitpid.h"
#include "lib/pubsub/pubsub_build.h"
#include "lib/meminfo/meminfo.h"
#include "lib/osinfo/uname.h"
+#include "lib/osinfo/libc.h"
#include "lib/sandbox/sandbox.h"
#include "lib/fs/lockfile.h"
#include "lib/tls/tortls.h"
@@ -336,16 +339,12 @@ dumpstats(int severity)
SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
int i = conn_sl_idx;
tor_log(severity, LD_GENERAL,
- "Conn %d (socket %d) type %d (%s), state %d (%s), created %d secs ago",
- i, (int)conn->s, conn->type, conn_type_to_string(conn->type),
- conn->state, conn_state_to_string(conn->type, conn->state),
+ "Conn %d (socket %d) is a %s, created %d secs ago",
+ i, (int)conn->s,
+ connection_describe(conn),
(int)(now - conn->timestamp_created));
if (!connection_is_listener(conn)) {
tor_log(severity,LD_GENERAL,
- "Conn %d is to %s:%d.", i,
- safe_str_client(conn->address),
- conn->port);
- tor_log(severity,LD_GENERAL,
"Conn %d: %d bytes waiting on inbuf (len %d, last read %d secs ago)",
i,
(int)connection_get_inbuf_len(conn),
@@ -549,6 +548,7 @@ tor_init(int argc, char *argv[])
/* Initialize the history structures. */
rep_hist_init();
+ bwhist_init();
/* Initialize the service cache. */
rend_cache_init();
addressmap_init(); /* Init the client dns cache. Do it always, since it's
@@ -575,7 +575,8 @@ tor_init(int argc, char *argv[])
const char *version = get_version();
log_notice(LD_GENERAL, "Tor %s running on %s with Libevent %s, "
- "%s %s, Zlib %s, Liblzma %s, and Libzstd %s.", version,
+ "%s %s, Zlib %s, Liblzma %s, Libzstd %s and %s %s as libc.",
+ version,
get_uname(),
tor_libevent_get_version_str(),
crypto_get_library_name(),
@@ -585,7 +586,10 @@ tor_init(int argc, char *argv[])
tor_compress_supports_method(LZMA_METHOD) ?
tor_compress_version_str(LZMA_METHOD) : "N/A",
tor_compress_supports_method(ZSTD_METHOD) ?
- tor_compress_version_str(ZSTD_METHOD) : "N/A");
+ tor_compress_version_str(ZSTD_METHOD) : "N/A",
+ tor_libc_get_name() ?
+ tor_libc_get_name() : "Unknown",
+ tor_libc_get_version_str());
log_notice(LD_GENERAL, "Tor can't help you if you use it wrong! "
"Learn how to be safe at "
@@ -602,6 +606,9 @@ tor_init(int argc, char *argv[])
rust_log_welcome_string();
#endif /* defined(HAVE_RUST) */
+ /* Warn _if_ the tracing subsystem is built in. */
+ tracing_log_warning();
+
int init_rv = options_init_from_torrc(argc,argv);
if (init_rv < 0) {
log_err(LD_CONFIG,"Reading config failed--see warnings above.");
@@ -775,12 +782,14 @@ do_dump_config(void)
if (!strcmp(arg, "short")) {
how = OPTIONS_DUMP_MINIMAL;
} else if (!strcmp(arg, "non-builtin")) {
- how = OPTIONS_DUMP_DEFAULTS;
+ // Deprecated since 0.4.5.1-alpha.
+ fprintf(stderr, "'non-builtin' is deprecated; use 'short' instead.\n");
+ how = OPTIONS_DUMP_MINIMAL;
} else if (!strcmp(arg, "full")) {
how = OPTIONS_DUMP_ALL;
} else {
fprintf(stderr, "No valid argument to --dump-config found!\n");
- fprintf(stderr, "Please select 'short', 'non-builtin', or 'full'.\n");
+ fprintf(stderr, "Please select 'short' or 'full'.\n");
return -1;
}
@@ -795,8 +804,7 @@ do_dump_config(void)
static void
init_addrinfo(void)
{
- if (! server_mode(get_options()) ||
- (get_options()->Address && strlen(get_options()->Address) > 0)) {
+ if (! server_mode(get_options()) || get_options()->Address) {
/* We don't need to seed our own hostname, because we won't be calling
* resolve_my_address on it.
*/
@@ -1065,12 +1073,14 @@ sandbox_init_filter(void)
OPEN_DATADIR("approved-routers");
OPEN_DATADIR_SUFFIX("fingerprint", ".tmp");
+ OPEN_DATADIR_SUFFIX("fingerprint-ed25519", ".tmp");
OPEN_DATADIR_SUFFIX("hashed-fingerprint", ".tmp");
OPEN_DATADIR_SUFFIX("router-stability", ".tmp");
OPEN("/etc/resolv.conf");
RENAME_SUFFIX("fingerprint", ".tmp");
+ RENAME_SUFFIX("fingerprint-ed25519", ".tmp");
RENAME_KEYDIR_SUFFIX("secret_onion_key_ntor", ".tmp");
RENAME_KEYDIR_SUFFIX("secret_id_key", ".tmp");
diff --git a/src/app/main/shutdown.c b/src/app/main/shutdown.c
index aac15246b9..4a556333db 100644
--- a/src/app/main/shutdown.c
+++ b/src/app/main/shutdown.c
@@ -47,6 +47,7 @@
#include "feature/relay/relay_config.h"
#include "feature/rend/rendcache.h"
#include "feature/rend/rendclient.h"
+#include "feature/stats/bwhist.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/rephist.h"
#include "lib/evloop/compat_libevent.h"
@@ -121,6 +122,7 @@ tor_free_all(int postfork)
rend_cache_free_all();
rend_service_authorization_free_all();
rep_hist_free_all();
+ bwhist_free_all();
circuit_free_all();
circpad_machines_free();
entry_guards_free_all();
diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c
index e32083537f..c6da6f4893 100644
--- a/src/app/main/subsystem_list.c
+++ b/src/app/main/subsystem_list.c
@@ -26,6 +26,7 @@
#include "lib/thread/thread_sys.h"
#include "lib/time/time_sys.h"
#include "lib/tls/tortls_sys.h"
+#include "lib/trace/trace_sys.h"
#include "lib/wallclock/wallclock_sys.h"
#include "lib/evloop/evloop_sys.h"
@@ -47,6 +48,8 @@ const subsys_fns_t *tor_subsystems[] = {
&sys_logging,
&sys_threads,
+ &sys_tracing,
+
&sys_time,
&sys_crypto,
diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in
index 51e1c3af4b..0690cbb931 100644
--- a/src/config/torrc.sample.in
+++ b/src/config/torrc.sample.in
@@ -242,11 +242,12 @@
#PublishServerDescriptor 0
## Configuration options can be imported from files or folders using the %include
-## option with the value being a path. If the path is a file, the options from the
-## file will be parsed as if they were written where the %include option is. If
-## the path is a folder, all files on that folder will be parsed following lexical
-## order. Files starting with a dot are ignored. Files on subfolders are ignored.
+## option with the value being a path. This path can have wildcards. Wildcards are
+## expanded first, using lexical order. Then, for each matching file or folder, the following
+## rules are followed: if the path is a file, the options from the file will be parsed as if
+## they were written where the %include option is. If the path is a folder, all files on that
+## folder will be parsed following lexical order. Files starting with a dot are ignored. Files
+## on subfolders are ignored.
## The %include option can be used recursively.
-#%include /etc/torrc.d/
-#%include /etc/torrc.custom
+#%include /etc/torrc.d/*.conf
diff --git a/src/core/crypto/onion_crypto.c b/src/core/crypto/onion_crypto.c
index 69b4dc40aa..1f34be1cc1 100644
--- a/src/core/crypto/onion_crypto.c
+++ b/src/core/crypto/onion_crypto.c
@@ -31,7 +31,7 @@
**/
#include "core/or/or.h"
-#include "core/or/circuitbuild.h"
+#include "core/or/extendinfo.h"
#include "core/crypto/onion_crypto.h"
#include "core/crypto/onion_fast.h"
#include "core/crypto/onion_ntor.h"
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c
index fd5bf879c5..29ffdaaf4e 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -82,6 +82,7 @@
#include "core/or/policies.h"
#include "core/or/reasons.h"
#include "core/or/relay.h"
+#include "core/or/status.h"
#include "core/or/crypt_path.h"
#include "core/proto/proto_haproxy.h"
#include "core/proto/proto_http.h"
@@ -105,7 +106,9 @@
#include "feature/relay/routermode.h"
#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
+#include "feature/stats/connstats.h"
#include "feature/stats/rephist.h"
+#include "feature/stats/bwhist.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/geoip/geoip.h"
@@ -218,8 +221,12 @@ static smartlist_t *outgoing_addrs = NULL;
/**************************************************************/
-/** Convert a connection_t* to an listener_connection_t*; assert if the cast
- * is invalid. */
+/**
+ * Cast a `connection_t *` to a `listener_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not a
+ * `listener_connection_t`.
+ **/
listener_connection_t *
TO_LISTENER_CONN(connection_t *c)
{
@@ -227,6 +234,18 @@ TO_LISTENER_CONN(connection_t *c)
return DOWNCAST(listener_connection_t, c);
}
+/**
+ * Cast a `const connection_t *` to a `const listener_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not a
+ * `listener_connection_t`.
+ **/
+const listener_connection_t *
+CONST_TO_LISTENER_CONN(const connection_t *c)
+{
+ return TO_LISTENER_CONN((connection_t *)c);
+}
+
size_t
connection_get_inbuf_len(connection_t *conn)
{
@@ -350,13 +369,179 @@ conn_state_to_string(int type, int state)
break;
}
+ if (state == 0) {
+ return "uninitialized";
+ }
+
log_warn(LD_BUG, "unknown connection state %d (type %d)", state, type);
tor_snprintf(buf, sizeof(buf),
"unknown state [%d] on unknown [%s] connection",
state, conn_type_to_string(type));
+ tor_assert_nonfatal_unreached_once();
return buf;
}
+/**
+ * Helper: describe the peer or address of connection @a conn in a
+ * human-readable manner.
+ *
+ * Returns a pointer to a static buffer; future calls to
+ * connection_describe_peer_internal() will invalidate this buffer.
+ *
+ * If <b>include_preposition</b> is true, include a preposition before the
+ * peer address.
+ *
+ * Nobody should parse the output of this function; it can and will change in
+ * future versions of tor.
+ **/
+static const char *
+connection_describe_peer_internal(const connection_t *conn,
+ bool include_preposition)
+{
+ IF_BUG_ONCE(!conn) {
+ return "null peer";
+ }
+
+ static char peer_buf[256];
+ const tor_addr_t *addr = &conn->addr;
+ const char *address = NULL;
+ const char *prep;
+ bool scrub = false;
+ char extra_buf[128];
+ extra_buf[0] = 0;
+
+ /* First, figure out the preposition to use */
+ switch (conn->type) {
+ CASE_ANY_LISTENER_TYPE:
+ prep = "on";
+ break;
+ case CONN_TYPE_EXIT:
+ prep = "to";
+ break;
+ case CONN_TYPE_CONTROL:
+ case CONN_TYPE_AP:
+ case CONN_TYPE_EXT_OR:
+ prep = "from";
+ break;
+ default:
+ prep = "with";
+ break;
+ }
+
+ /* Now figure out the address. */
+ if (conn->socket_family == AF_UNIX) {
+ /* For unix sockets, we always use the `address` string. */
+ address = conn->address ? conn->address : "unix socket";
+ } else if (conn->type == CONN_TYPE_OR) {
+ /* For OR connections, we have a lot to do. */
+ const or_connection_t *or_conn = CONST_TO_OR_CONN(conn);
+ /* We report the IDs we're talking to... */
+ if (fast_digest_is_zero(or_conn->identity_digest)) {
+ // This could be a client, so scrub it. No identity to report.
+ scrub = true;
+ } else {
+ char id_buf[HEX_DIGEST_LEN+1];
+ base16_encode(id_buf, sizeof(id_buf),
+ or_conn->identity_digest, DIGEST_LEN);
+ tor_snprintf(extra_buf, sizeof(extra_buf),
+ " ID=%s", id_buf);
+ }
+ if (! scrub && (! tor_addr_eq(addr, &or_conn->canonical_orport.addr) ||
+ conn->port != or_conn->canonical_orport.port)) {
+ /* We report canonical address, if it's different */
+ char canonical_addr_buf[TOR_ADDR_BUF_LEN];
+ if (tor_addr_to_str(canonical_addr_buf, &or_conn->canonical_orport.addr,
+ sizeof(canonical_addr_buf), 1)) {
+ tor_snprintf(extra_buf+strlen(extra_buf),
+ sizeof(extra_buf)-strlen(extra_buf),
+ " canonical_addr=%s:%"PRIu16,
+ canonical_addr_buf,
+ or_conn->canonical_orport.port);
+ }
+ }
+ } else if (conn->type == CONN_TYPE_EXIT) {
+ scrub = true; /* This is a client's request; scrub it with SafeLogging. */
+ if (tor_addr_is_null(addr)) {
+ address = conn->address;
+ strlcpy(extra_buf, " (DNS lookup pending)", sizeof(extra_buf));
+ }
+ }
+
+ char addr_buf[TOR_ADDR_BUF_LEN];
+ if (address == NULL) {
+ if (tor_addr_family(addr) == 0) {
+ address = "<unset>";
+ } else {
+ address = tor_addr_to_str(addr_buf, addr, sizeof(addr_buf), 1);
+ if (!address) {
+ address = "<can't format!>";
+ tor_assert_nonfatal_unreached_once();
+ }
+ }
+ }
+
+ char portbuf[7];
+ portbuf[0]=0;
+ if (scrub && get_options()->SafeLogging_ != SAFELOG_SCRUB_NONE) {
+ address = "[scrubbed]";
+ } else {
+ /* Only set the port if we're not scrubbing the address. */
+ if (conn->port != 0) {
+ tor_snprintf(portbuf, sizeof(portbuf), ":%d", conn->port);
+ }
+ }
+
+ const char *sp = include_preposition ? " " : "";
+ if (! include_preposition)
+ prep = "";
+
+ tor_snprintf(peer_buf, sizeof(peer_buf),
+ "%s%s%s%s%s", prep, sp, address, portbuf, extra_buf);
+ return peer_buf;
+}
+
+/**
+ * Describe the peer or address of connection @a conn in a
+ * human-readable manner.
+ *
+ * Returns a pointer to a static buffer; future calls to
+ * connection_describe_peer() or connection_describe() will invalidate this
+ * buffer.
+ *
+ * Nobody should parse the output of this function; it can and will change in
+ * future versions of tor.
+ **/
+const char *
+connection_describe_peer(const connection_t *conn)
+{
+ return connection_describe_peer_internal(conn, false);
+}
+
+/**
+ * Describe a connection for logging purposes.
+ *
+ * Returns a pointer to a static buffer; future calls to connection_describe()
+ * will invalidate this buffer.
+ *
+ * Nobody should parse the output of this function; it can and will change in
+ * future versions of tor.
+ **/
+const char *
+connection_describe(const connection_t *conn)
+{
+ IF_BUG_ONCE(!conn) {
+ return "null connection";
+ }
+ static char desc_buf[256];
+ const char *peer = connection_describe_peer_internal(conn, true);
+ tor_snprintf(desc_buf, sizeof(desc_buf),
+ "%s connection (%s) %s",
+ conn_type_to_string(conn->type),
+ conn_state_to_string(conn->type, conn->state),
+ peer);
+ return desc_buf;
+}
+
/** Allocate and return a new dir_connection_t, initialized as by
* connection_init(). */
dir_connection_t *
@@ -382,6 +567,7 @@ or_connection_new(int type, int socket_family)
tor_assert(type == CONN_TYPE_OR || type == CONN_TYPE_EXT_OR);
connection_init(now, TO_CONN(or_conn), type, socket_family);
+ tor_addr_make_unspec(&or_conn->canonical_orport.addr);
connection_or_set_canonical(or_conn, 0);
if (type == CONN_TYPE_EXT_OR) {
@@ -852,11 +1038,11 @@ connection_close_immediate(connection_t *conn)
tor_fragile_assert();
return;
}
- if (conn->outbuf_flushlen) {
- log_info(LD_NET,"fd %d, type %s, state %s, %d bytes on outbuf.",
+ if (connection_get_outbuf_len(conn)) {
+ log_info(LD_NET,"fd %d, type %s, state %s, %"TOR_PRIuSZ" bytes on outbuf.",
(int)conn->s, conn_type_to_string(conn->type),
conn_state_to_string(conn->type, conn->state),
- (int)conn->outbuf_flushlen);
+ buf_datalen(conn->outbuf));
}
connection_unregister_events(conn);
@@ -872,7 +1058,6 @@ connection_close_immediate(connection_t *conn)
conn->linked_conn_is_closed = 1;
if (conn->outbuf)
buf_clear(conn->outbuf);
- conn->outbuf_flushlen = 0;
}
/** Mark <b>conn</b> to be closed next time we loop through
@@ -1549,13 +1734,8 @@ connection_listener_new(const struct sockaddr *listensockaddr,
*/
connection_check_oos(get_n_open_sockets(), 0);
- if (conn->socket_family == AF_UNIX) {
- log_notice(LD_NET, "Opened %s on %s",
- conn_type_to_string(type), conn->address);
- } else {
- log_notice(LD_NET, "Opened %s on %s",
- conn_type_to_string(type), fmt_addrport(&addr, gotPort));
- }
+ log_notice(LD_NET, "Opened %s", connection_describe(conn));
+
return conn;
err:
@@ -1863,6 +2043,9 @@ connection_handle_listener_read(connection_t *conn, int new_type)
connection_mark_for_close(newconn);
return 0;
}
+
+ note_connection(true /* inbound */, conn->socket_family);
+
return 0;
}
@@ -2034,6 +2217,8 @@ connection_connect_sockaddr,(connection_t *conn,
}
}
+ note_connection(false /* outbound */, conn->socket_family);
+
/* it succeeded. we're connected. */
log_fn(inprogress ? LOG_DEBUG : LOG_INFO, LD_NET,
"Connection to socket %s (sock "TOR_SOCKET_T_FORMAT").",
@@ -2067,22 +2252,13 @@ connection_connect_log_client_use_ip_version(const connection_t *conn)
return;
}
- const int must_ipv4 = !fascist_firewall_use_ipv6(options);
+ const int must_ipv4 = !reachable_addr_use_ipv6(options);
const int must_ipv6 = (options->ClientUseIPv4 == 0);
const int pref_ipv6 = (conn->type == CONN_TYPE_OR
- ? fascist_firewall_prefer_ipv6_orport(options)
- : fascist_firewall_prefer_ipv6_dirport(options));
+ ? reachable_addr_prefer_ipv6_orport(options)
+ : reachable_addr_prefer_ipv6_dirport(options));
tor_addr_t real_addr;
- tor_addr_make_null(&real_addr, AF_UNSPEC);
-
- /* OR conns keep the original address in real_addr, as addr gets overwritten
- * with the descriptor address */
- if (conn->type == CONN_TYPE_OR) {
- const or_connection_t *or_conn = TO_OR_CONN((connection_t *)conn);
- tor_addr_copy(&real_addr, &or_conn->real_addr);
- } else if (conn->type == CONN_TYPE_DIR) {
- tor_addr_copy(&real_addr, &conn->addr);
- }
+ tor_addr_copy(&real_addr, &conn->addr);
/* Check if we broke a mandatory address family restriction */
if ((must_ipv4 && tor_addr_family(&real_addr) == AF_INET6)
@@ -2105,7 +2281,7 @@ connection_connect_log_client_use_ip_version(const connection_t *conn)
return;
}
- if (fascist_firewall_use_ipv6(options)) {
+ if (reachable_addr_use_ipv6(options)) {
log_info(LD_NET, "Our outgoing connection is using IPv%d.",
tor_addr_family(&real_addr) == AF_INET6 ? 6 : 4);
}
@@ -2115,13 +2291,13 @@ connection_connect_log_client_use_ip_version(const connection_t *conn)
|| (pref_ipv6 && tor_addr_family(&real_addr) == AF_INET)) {
log_info(LD_NET, "Outgoing connection to %s doesn't satisfy "
"ClientPreferIPv6%sPort %d, with ClientUseIPv4 %d, and "
- "fascist_firewall_use_ipv6 %d (ClientUseIPv6 %d and UseBridges "
+ "reachable_addr_use_ipv6 %d (ClientUseIPv6 %d and UseBridges "
"%d).",
fmt_addr(&real_addr),
conn->type == CONN_TYPE_OR ? "OR" : "Dir",
conn->type == CONN_TYPE_OR ? options->ClientPreferIPv6ORPort
: options->ClientPreferIPv6DirPort,
- options->ClientUseIPv4, fascist_firewall_use_ipv6(options),
+ options->ClientUseIPv4, reachable_addr_use_ipv6(options),
options->ClientUseIPv6, options->UseBridges);
}
}
@@ -2608,8 +2784,8 @@ connection_read_https_proxy_response(connection_t *conn)
if (parse_http_response(headers, &status_code, &date_header,
NULL, &reason) < 0) {
log_warn(LD_NET,
- "Unparseable headers from proxy (connecting to '%s'). Closing.",
- conn->address);
+ "Unparseable headers from proxy (%s). Closing.",
+ connection_describe(conn));
tor_free(headers);
return -1;
}
@@ -2618,8 +2794,8 @@ connection_read_https_proxy_response(connection_t *conn)
if (status_code == 200) {
log_info(LD_NET,
- "HTTPS connect to '%s' successful! (200 %s) Starting TLS.",
- conn->address, escaped(reason));
+ "HTTPS connect for %s successful! (200 %s) Starting TLS.",
+ connection_describe(conn), escaped(reason));
tor_free(reason);
return 1;
}
@@ -2835,16 +3011,16 @@ connection_read_proxy_handshake(connection_t *conn)
if (ret < 0) {
if (reason) {
- log_warn(LD_NET, "Proxy Client: unable to connect to %s:%d (%s)",
- conn->address, conn->port, escaped(reason));
+ log_warn(LD_NET, "Proxy Client: unable to connect %s (%s)",
+ connection_describe(conn), escaped(reason));
tor_free(reason);
} else {
- log_warn(LD_NET, "Proxy Client: unable to connect to %s:%d",
- conn->address, conn->port);
+ log_warn(LD_NET, "Proxy Client: unable to connect %s",
+ connection_describe(conn));
}
} else if (ret == 1) {
- log_info(LD_NET, "Proxy Client: connection to %s:%d successful",
- conn->address, conn->port);
+ log_info(LD_NET, "Proxy Client: %s successful",
+ connection_describe(conn));
}
return ret;
@@ -3001,10 +3177,10 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol)
smartlist_t *replacements = smartlist_new();
const or_options_t *options = get_options();
int retval = 0;
- const uint16_t old_or_port = router_get_advertised_or_port(options);
+ const uint16_t old_or_port = routerconf_find_or_port(options, AF_INET);
const uint16_t old_or_port_ipv6 =
- router_get_advertised_or_port_by_af(options,AF_INET6);
- const uint16_t old_dir_port = router_get_advertised_dir_port(options, 0);
+ routerconf_find_or_port(options,AF_INET6);
+ const uint16_t old_dir_port = routerconf_find_dir_port(options, 0);
SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
if (connection_is_listener(conn) && !conn->marked_for_close)
@@ -3035,8 +3211,8 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol)
connection_t *old_conn = r->old_conn;
if (skip) {
- log_debug(LD_NET, "Skipping creating new listener for %s:%d",
- old_conn->address, old_conn->port);
+ log_debug(LD_NET, "Skipping creating new listener for %s",
+ connection_describe(old_conn));
continue;
}
@@ -3048,14 +3224,22 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol)
&skip, &addr_in_use);
}
- tor_assert(new_conn);
+ /* There are many reasons why we can't open a new listener port so in case
+ * we hit those, bail early so tor can stop. */
+ if (!new_conn) {
+ log_warn(LD_NET, "Unable to create listener port: %s:%d",
+ fmt_addr(&r->new_port->addr), r->new_port->port);
+ retval = -1;
+ break;
+ }
smartlist_add(new_conns, new_conn);
- log_notice(LD_NET, "Closed no-longer-configured %s on %s:%d "
- "(replaced by %s:%d)",
- conn_type_to_string(old_conn->type), old_conn->address,
- old_conn->port, new_conn->address, new_conn->port);
+ char *old_desc = tor_strdup(connection_describe(old_conn));
+ log_notice(LD_NET, "Closed no-longer-configured %s "
+ "(replaced by %s)",
+ old_desc, connection_describe(new_conn));
+ tor_free(old_desc);
} SMARTLIST_FOREACH_END(r);
#endif /* defined(ENABLE_LISTENER_REBIND) */
@@ -3073,10 +3257,9 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol)
SMARTLIST_FOREACH(replacements, listener_replacement_t *, r, tor_free(r));
smartlist_free(replacements);
- if (old_or_port != router_get_advertised_or_port(options) ||
- old_or_port_ipv6 != router_get_advertised_or_port_by_af(options,
- AF_INET6) ||
- old_dir_port != router_get_advertised_dir_port(options, 0)) {
+ if (old_or_port != routerconf_find_or_port(options, AF_INET) ||
+ old_or_port_ipv6 != routerconf_find_or_port(options, AF_INET6) ||
+ old_dir_port != routerconf_find_dir_port(options, 0)) {
/* Our chosen ORPort or DirPort is not what it used to be: the
* descriptor we had (if any) should be regenerated. (We won't
* automatically notice this because of changes in the option,
@@ -3254,12 +3437,12 @@ connection_bucket_write_limit(connection_t *conn, time_t now)
{
int base = RELAY_PAYLOAD_SIZE;
int priority = conn->type != CONN_TYPE_DIR;
- size_t conn_bucket = conn->outbuf_flushlen;
+ size_t conn_bucket = buf_datalen(conn->outbuf);
size_t global_bucket_val = token_bucket_rw_get_write(&global_bucket);
if (!connection_is_rate_limited(conn)) {
/* be willing to write to local conns even if our buckets are empty */
- return conn->outbuf_flushlen;
+ return conn_bucket;
}
if (connection_speaks_cells(conn)) {
@@ -3349,9 +3532,9 @@ record_num_bytes_transferred_impl(connection_t *conn,
/* Count bytes of answering direct and tunneled directory requests */
if (conn->type == CONN_TYPE_DIR && conn->purpose == DIR_PURPOSE_SERVER) {
if (num_read > 0)
- rep_hist_note_dir_bytes_read(num_read, now);
+ bwhist_note_dir_bytes_read(num_read, now);
if (num_written > 0)
- rep_hist_note_dir_bytes_written(num_written, now);
+ bwhist_note_dir_bytes_written(num_written, now);
}
/* Linked connections and internal IPs aren't counted for statistics or
@@ -3366,15 +3549,16 @@ record_num_bytes_transferred_impl(connection_t *conn,
if (!connection_is_rate_limited(conn))
return;
+ const bool is_ipv6 = (conn->socket_family == AF_INET6);
if (conn->type == CONN_TYPE_OR)
- rep_hist_note_or_conn_bytes(conn->global_identifier, num_read,
- num_written, now);
+ conn_stats_note_or_conn_bytes(conn->global_identifier, num_read,
+ num_written, now, is_ipv6);
if (num_read > 0) {
- rep_hist_note_bytes_read(num_read, now);
+ bwhist_note_bytes_read(num_read, now, is_ipv6);
}
if (num_written > 0) {
- rep_hist_note_bytes_written(num_written, now);
+ bwhist_note_bytes_written(num_written, now, is_ipv6);
}
if (conn->type == CONN_TYPE_EXIT)
rep_hist_note_exit_bytes(conn->port, num_written, num_read);
@@ -3863,17 +4047,14 @@ connection_buf_read_from_socket(connection_t *conn, ssize_t *max_to_read,
switch (result) {
case TOR_TLS_CLOSE:
case TOR_TLS_ERROR_IO:
- log_debug(LD_NET,"TLS connection closed %son read. Closing. "
- "(Nickname %s, address %s)",
- result == TOR_TLS_CLOSE ? "cleanly " : "",
- or_conn->nickname ? or_conn->nickname : "not set",
- conn->address);
+ log_debug(LD_NET,"TLS %s closed %son read. Closing.",
+ connection_describe(conn),
+ result == TOR_TLS_CLOSE ? "cleanly " : "");
return result;
CASE_TOR_TLS_ERROR_ANY_NONIO:
- log_debug(LD_NET,"tls error [%s]. breaking (nickname %s, address %s).",
+ log_debug(LD_NET,"tls error [%s] from %s. Breaking.",
tor_tls_err_to_string(result),
- or_conn->nickname ? or_conn->nickname : "not set",
- conn->address);
+ connection_describe(conn));
return result;
case TOR_TLS_WANTWRITE:
connection_start_writing(conn);
@@ -3914,12 +4095,7 @@ connection_buf_read_from_socket(connection_t *conn, ssize_t *max_to_read,
result, (long)n_read, (long)n_written);
} else if (conn->linked) {
if (conn->linked_conn) {
- result = buf_move_to_buf(conn->inbuf, conn->linked_conn->outbuf,
- &conn->linked_conn->outbuf_flushlen);
- if (BUG(result<0)) {
- log_warn(LD_BUG, "reading from linked connection buffer failed.");
- return -1;
- }
+ result = (int) buf_move_all(conn->inbuf, conn->linked_conn->outbuf);
} else {
result = 0;
}
@@ -4023,12 +4199,11 @@ connection_fetch_from_buf_http(connection_t *conn,
body_out, body_used, max_bodylen, force_complete);
}
-/** Return conn-\>outbuf_flushlen: how many bytes conn wants to flush
- * from its outbuf. */
+/** Return true if this connection has data to flush. */
int
connection_wants_to_flush(connection_t *conn)
{
- return conn->outbuf_flushlen > 0;
+ return connection_get_outbuf_len(conn) > 0;
}
/** Are there too many bytes on edge connection <b>conn</b>'s outbuf to
@@ -4038,7 +4213,7 @@ connection_wants_to_flush(connection_t *conn)
int
connection_outbuf_too_full(connection_t *conn)
{
- return (conn->outbuf_flushlen > 10*CELL_PAYLOAD_SIZE);
+ return connection_get_outbuf_len(conn) > 10*CELL_PAYLOAD_SIZE;
}
/**
@@ -4164,7 +4339,7 @@ connection_handle_write_impl(connection_t *conn, int force)
return -1;
}
- max_to_write = force ? (ssize_t)conn->outbuf_flushlen
+ max_to_write = force ? (ssize_t)buf_datalen(conn->outbuf)
: connection_bucket_write_limit(conn, now);
if (connection_speaks_cells(conn) &&
@@ -4196,7 +4371,7 @@ connection_handle_write_impl(connection_t *conn, int force)
/* else open, or closing */
initial_size = buf_datalen(conn->outbuf);
result = buf_flush_to_tls(conn->outbuf, or_conn->tls,
- max_to_write, &conn->outbuf_flushlen);
+ max_to_write);
if (result >= 0)
update_send_buffer_size(conn->s);
@@ -4262,7 +4437,7 @@ connection_handle_write_impl(connection_t *conn, int force)
} else {
CONN_LOG_PROTECT(conn,
result = buf_flush_to_socket(conn->outbuf, conn->s,
- max_to_write, &conn->outbuf_flushlen));
+ max_to_write));
if (result < 0) {
if (CONN_IS_EDGE(conn))
connection_edge_end_errno(TO_EDGE_CONN(conn));
@@ -4418,10 +4593,10 @@ connection_write_to_buf_failed(connection_t *conn)
/** Helper for connection_write_to_buf_impl and connection_write_buf_to_buf:
*
* Called when an attempt to add bytes on <b>conn</b>'s outbuf has succeeded:
- * record the number of bytes added.
+ * start writing if appropriate.
*/
static void
-connection_write_to_buf_commit(connection_t *conn, size_t len)
+connection_write_to_buf_commit(connection_t *conn)
{
/* If we receive optimistic data in the EXIT_CONN_STATE_RESOLVING
* state, we don't want to try to write it right away, since
@@ -4430,7 +4605,6 @@ connection_write_to_buf_commit(connection_t *conn, size_t len)
if (conn->write_event) {
connection_start_writing(conn);
}
- conn->outbuf_flushlen += len;
}
/** Append <b>len</b> bytes of <b>string</b> onto <b>conn</b>'s
@@ -4453,25 +4627,20 @@ connection_write_to_buf_impl_,(const char *string, size_t len,
if (!connection_may_write_to_buf(conn))
return;
- size_t written;
-
if (zlib) {
- size_t old_datalen = buf_datalen(conn->outbuf);
dir_connection_t *dir_conn = TO_DIR_CONN(conn);
int done = zlib < 0;
CONN_LOG_PROTECT(conn, r = buf_add_compress(conn->outbuf,
dir_conn->compress_state,
string, len, done));
- written = buf_datalen(conn->outbuf) - old_datalen;
} else {
CONN_LOG_PROTECT(conn, r = buf_add(conn->outbuf, string, len));
- written = len;
}
if (r < 0) {
connection_write_to_buf_failed(conn);
return;
}
- connection_write_to_buf_commit(conn, written);
+ connection_write_to_buf_commit(conn);
}
/**
@@ -4516,7 +4685,7 @@ connection_buf_add_buf(connection_t *conn, buf_t *buf)
return;
buf_move_all(conn->outbuf, buf);
- connection_write_to_buf_commit(conn, len);
+ connection_write_to_buf_commit(conn);
}
#define CONN_GET_ALL_TEMPLATE(var, test) \
@@ -4726,7 +4895,7 @@ any_other_active_or_conns(const or_connection_t *this_conn)
connection_t *conn = connection_get_another_active_or_conn(this_conn);
if (conn != NULL) {
log_debug(LD_DIR, "%s: Found an OR connection: %s",
- __func__, conn->address);
+ __func__, connection_describe(conn));
return 1;
}
@@ -4876,7 +5045,7 @@ client_check_address_changed(tor_socket_t sock)
smartlist_clear(outgoing_addrs);
smartlist_add(outgoing_addrs, tor_memdup(&out_addr, sizeof(tor_addr_t)));
/* We'll need to resolve ourselves again. */
- reset_last_resolved_addr();
+ resolved_addr_reset_last(AF_INET);
/* Okay, now change our keys. */
ip_address_changed(1);
}
@@ -5404,18 +5573,6 @@ assert_connection_ok(connection_t *conn, time_t now)
if (conn->linked)
tor_assert(!SOCKET_OK(conn->s));
- if (conn->outbuf_flushlen > 0) {
- /* With optimistic data, we may have queued data in
- * EXIT_CONN_STATE_RESOLVING while the conn is not yet marked to writing.
- * */
- tor_assert((conn->type == CONN_TYPE_EXIT &&
- conn->state == EXIT_CONN_STATE_RESOLVING) ||
- connection_is_writing(conn) ||
- conn->write_blocked_on_bw ||
- (CONN_IS_EDGE(conn) &&
- TO_EDGE_CONN(conn)->edge_blocked_on_circ));
- }
-
if (conn->hold_open_until_flushed)
tor_assert(conn->marked_for_close);
diff --git a/src/core/mainloop/connection.h b/src/core/mainloop/connection.h
index bcd3d590a5..ee3dce49f4 100644
--- a/src/core/mainloop/connection.h
+++ b/src/core/mainloop/connection.h
@@ -31,6 +31,8 @@ struct tor_addr_t;
struct or_options_t;
struct listener_connection_t *TO_LISTENER_CONN(struct connection_t *);
+const struct listener_connection_t *CONST_TO_LISTENER_CONN(
+ const struct connection_t *);
struct buf_t;
@@ -116,6 +118,9 @@ const char *conn_type_to_string(int type);
const char *conn_state_to_string(int type, int state);
int conn_listener_type_supports_af_unix(int type);
+const char *connection_describe(const connection_t *conn);
+const char *connection_describe_peer(const connection_t *conn);
+
struct dir_connection_t *dir_connection_new(int socket_family);
struct or_connection_t *or_connection_new(int type, int socket_family);
struct edge_connection_t *edge_connection_new(int type, int socket_family);
diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c
index e4e17f6b76..c75039b378 100644
--- a/src/core/mainloop/mainloop.c
+++ b/src/core/mainloop/mainloop.c
@@ -95,6 +95,7 @@
#include "feature/rend/rendservice.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/connstats.h"
#include "feature/stats/rephist.h"
#include "lib/buf/buffers.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -984,33 +985,29 @@ conn_close_if_marked(int i)
if (!conn->hold_open_until_flushed)
log_info(LD_NET,
"Conn (addr %s, fd %d, type %s, state %d) marked, but wants "
- "to flush %d bytes. (Marked at %s:%d)",
+ "to flush %"TOR_PRIuSZ" bytes. (Marked at %s:%d)",
escaped_safe_str_client(conn->address),
(int)conn->s, conn_type_to_string(conn->type), conn->state,
- (int)conn->outbuf_flushlen,
- conn->marked_for_close_file, conn->marked_for_close);
+ connection_get_outbuf_len(conn),
+ conn->marked_for_close_file, conn->marked_for_close);
if (conn->linked_conn) {
- retval = buf_move_to_buf(conn->linked_conn->inbuf, conn->outbuf,
- &conn->outbuf_flushlen);
+ retval = (int) buf_move_all(conn->linked_conn->inbuf, conn->outbuf);
if (retval >= 0) {
/* The linked conn will notice that it has data when it notices that
* we're gone. */
connection_start_reading_from_linked_conn(conn->linked_conn);
}
log_debug(LD_GENERAL, "Flushed last %d bytes from a linked conn; "
- "%d left; flushlen %d; wants-to-flush==%d", retval,
+ "%d left; wants-to-flush==%d", retval,
(int)connection_get_outbuf_len(conn),
- (int)conn->outbuf_flushlen,
connection_wants_to_flush(conn));
} else if (connection_speaks_cells(conn)) {
if (conn->state == OR_CONN_STATE_OPEN) {
- retval = buf_flush_to_tls(conn->outbuf, TO_OR_CONN(conn)->tls, sz,
- &conn->outbuf_flushlen);
+ retval = buf_flush_to_tls(conn->outbuf, TO_OR_CONN(conn)->tls, sz);
} else
retval = -1; /* never flush non-open broken tls connections */
} else {
- retval = buf_flush_to_socket(conn->outbuf, conn->s, sz,
- &conn->outbuf_flushlen);
+ retval = buf_flush_to_socket(conn->outbuf, conn->s, sz);
}
if (retval >= 0 && /* Technically, we could survive things like
TLS_WANT_WRITE here. But don't bother for now. */
@@ -1950,7 +1947,7 @@ write_stats_file_callback(time_t now, const or_options_t *options)
next_time_to_write_stats_files = next_write;
}
if (options->ConnDirectionStatistics) {
- time_t next_write = rep_hist_conn_stats_write(now);
+ time_t next_write = conn_stats_save(now);
if (next_write && next_write < next_time_to_write_stats_files)
next_time_to_write_stats_files = next_write;
}
diff --git a/src/core/or/channel.c b/src/core/or/channel.c
index 5ed6bb9272..d082174dc8 100644
--- a/src/core/or/channel.c
+++ b/src/core/or/channel.c
@@ -84,13 +84,6 @@
#include "core/or/cell_queue_st.h"
-/* Static function prototypes */
-
-static bool channel_matches_target_addr_for_extend(
- channel_t *chan,
- const tor_addr_t *target_ipv4_addr,
- const tor_addr_t *target_ipv6_addr);
-
/* Global lists of channels */
/* All channel_t instances */
@@ -878,6 +871,8 @@ channel_init(channel_t *chan)
/* Channel is not in the scheduler heap. */
chan->sched_heap_idx = -1;
+
+ tor_addr_make_unspec(&chan->addr_according_to_peer);
}
/**
@@ -2573,7 +2568,7 @@ channel_dump_statistics, (channel_t *chan, int severity))
/* Handle remote address and descriptions */
have_remote_addr = channel_get_addr_if_possible(chan, &remote_addr);
if (have_remote_addr) {
- char *actual = tor_strdup(channel_get_actual_remote_descr(chan));
+ char *actual = tor_strdup(channel_describe_peer(chan));
remote_addr_str = tor_addr_to_str_dup(&remote_addr);
tor_log(severity, LD_GENERAL,
" * Channel %"PRIu64 " says its remote address"
@@ -2581,18 +2576,18 @@ channel_dump_statistics, (channel_t *chan, int severity))
"actual description of \"%s\"",
(chan->global_identifier),
safe_str(remote_addr_str),
- safe_str(channel_get_canonical_remote_descr(chan)),
+ safe_str(channel_describe_peer(chan)),
safe_str(actual));
tor_free(remote_addr_str);
tor_free(actual);
} else {
- char *actual = tor_strdup(channel_get_actual_remote_descr(chan));
+ char *actual = tor_strdup(channel_describe_peer(chan));
tor_log(severity, LD_GENERAL,
" * Channel %"PRIu64 " does not know its remote "
"address, but gives a canonical description of \"%s\" and an "
"actual description of \"%s\"",
(chan->global_identifier),
- channel_get_canonical_remote_descr(chan),
+ channel_describe_peer(chan),
actual);
tor_free(actual);
}
@@ -2798,75 +2793,41 @@ channel_listener_dump_transport_statistics(channel_listener_t *chan_l,
}
/**
- * Return text description of the remote endpoint.
- *
- * This function return a test provided by the lower layer of the remote
- * endpoint for this channel; it should specify the actual address connected
- * to/from.
- *
- * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr}
- * may invalidate the return value from this function.
- */
-const char *
-channel_get_actual_remote_descr(channel_t *chan)
-{
- tor_assert(chan);
- tor_assert(chan->get_remote_descr);
-
- /* Param 1 indicates the actual description */
- return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL);
-}
-
-/**
- * Return the text address of the remote endpoint.
- *
- * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr}
- * may invalidate the return value from this function.
- */
-const char *
-channel_get_actual_remote_address(channel_t *chan)
-{
- /* Param 1 indicates the actual description */
- return chan->get_remote_descr(chan, GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY);
-}
-
-/**
* Return text description of the remote endpoint canonical address.
*
- * This function return a test provided by the lower layer of the remote
- * endpoint for this channel; it should use the known canonical address for
- * this OR's identity digest if possible.
+ * This function returns a human-readable string for logging; nothing
+ * should parse it or rely on a particular format.
*
- * Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr}
- * may invalidate the return value from this function.
+ * Subsequent calls to this function may invalidate its return value.
*/
MOCK_IMPL(const char *,
-channel_get_canonical_remote_descr,(channel_t *chan))
+channel_describe_peer,(channel_t *chan))
{
tor_assert(chan);
- tor_assert(chan->get_remote_descr);
+ tor_assert(chan->describe_peer);
- /* Param 0 indicates the canonicalized description */
- return chan->get_remote_descr(chan, 0);
+ return chan->describe_peer(chan);
}
/**
- * Get remote address if possible.
+ * Get the remote address for this channel, if possible.
*
* Write the remote address out to a tor_addr_t if the underlying transport
* supports this operation, and return 1. Return 0 if the underlying transport
* doesn't let us do this.
+ *
+ * Always returns the "real" address of the peer -- the one we're connected to
+ * on the internet.
*/
MOCK_IMPL(int,
-channel_get_addr_if_possible,(channel_t *chan, tor_addr_t *addr_out))
+channel_get_addr_if_possible,(const channel_t *chan,
+ tor_addr_t *addr_out))
{
tor_assert(chan);
tor_assert(addr_out);
+ tor_assert(chan->get_remote_addr);
- if (chan->get_remote_addr)
- return chan->get_remote_addr(chan, addr_out);
- /* Else no support, method not implemented */
- else return 0;
+ return chan->get_remote_addr(chan, addr_out);
}
/**
@@ -3290,6 +3251,9 @@ channel_when_last_xmit(channel_t *chan)
*
* This function calls the lower layer and asks if this channel matches a
* given extend_info_t.
+ *
+ * NOTE that this function only checks for an address/port match, and should
+ * be used only when no identity is available.
*/
int
channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info)
@@ -3311,7 +3275,7 @@ channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info)
* This function calls into the lower layer and asks if this channel thinks
* it matches the target addresses for circuit extension purposes.
*/
-static bool
+STATIC bool
channel_matches_target_addr_for_extend(channel_t *chan,
const tor_addr_t *target_ipv4_addr,
const tor_addr_t *target_ipv6_addr)
diff --git a/src/core/or/channel.h b/src/core/or/channel.h
index 82d89471b4..606b0730b8 100644
--- a/src/core/or/channel.h
+++ b/src/core/or/channel.h
@@ -236,6 +236,9 @@ struct channel_t {
/** The handle to this channel (to free on canceled timers) */
struct channel_handle_t *timer_handle;
+ /** If not UNSPEC, the address that the peer says we have. */
+ tor_addr_t addr_according_to_peer;
+
/**
* These two fields specify the minimum and maximum negotiated timeout
* values for inactivity (send or receive) before we decide to pad a
@@ -329,24 +332,18 @@ struct channel_t {
*/
double (*get_overhead_estimate)(channel_t *);
/*
- * Ask the underlying transport what the remote endpoint address is, in
- * a tor_addr_t. This is optional and subclasses may leave this NULL.
- * If they implement it, they should write the address out to the
- * provided tor_addr_t *, and return 1 if successful or 0 if no address
- * available.
+ * Ask the underlying transport what the remote endpoint address is, in a
+ * tor_addr_t. Write the address out to the provided tor_addr_t *, and
+ * return 1 if successful or 0 if no address available.
*/
- int (*get_remote_addr)(channel_t *, tor_addr_t *);
+ int (*get_remote_addr)(const channel_t *, tor_addr_t *);
int (*get_transport_name)(channel_t *chan, char **transport_out);
-#define GRD_FLAG_ORIGINAL 1
-#define GRD_FLAG_ADDR_ONLY 2
/**
- * Get a text description of the remote endpoint; canonicalized if the flag
- * GRD_FLAG_ORIGINAL is not set, or the one we originally connected
- * to/received from if it is. If GRD_FLAG_ADDR_ONLY is set, we return only
- * the original address.
+ * Get a human-readable text description of the remote endpoint, for
+ * logging.
*/
- const char * (*get_remote_descr)(channel_t *, int);
+ const char * (*describe_peer)(const channel_t *);
/** Check if the lower layer has queued writes */
int (*has_queued_writes)(channel_t *);
/**
@@ -560,7 +557,10 @@ void channel_listener_dumpstats(int severity);
#ifdef CHANNEL_FILE_PRIVATE
STATIC void channel_add_to_digest_map(channel_t *chan);
-
+STATIC bool channel_matches_target_addr_for_extend(
+ channel_t *chan,
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr);
#endif /* defined(CHANNEL_FILE_PRIVATE) */
/* Channel operations for subclasses and internal use only */
@@ -719,11 +719,9 @@ channel_is_in_state(channel_t *chan, channel_state_t state)
const char * channel_describe_transport(channel_t *chan);
MOCK_DECL(void, channel_dump_statistics, (channel_t *chan, int severity));
void channel_dump_transport_statistics(channel_t *chan, int severity);
-const char * channel_get_actual_remote_descr(channel_t *chan);
-const char * channel_get_actual_remote_address(channel_t *chan);
-MOCK_DECL(int, channel_get_addr_if_possible, (channel_t *chan,
+MOCK_DECL(int, channel_get_addr_if_possible, (const channel_t *chan,
tor_addr_t *addr_out));
-MOCK_DECL(const char *, channel_get_canonical_remote_descr,(channel_t *chan));
+MOCK_DECL(const char *, channel_describe_peer,(channel_t *chan));
int channel_has_queued_writes(channel_t *chan);
int channel_is_bad_for_new_circs(channel_t *chan);
void channel_mark_bad_for_new_circs(channel_t *chan);
diff --git a/src/core/or/channelpadding.c b/src/core/or/channelpadding.c
index be2ce78a17..d0c43e8bdc 100644
--- a/src/core/or/channelpadding.c
+++ b/src/core/or/channelpadding.c
@@ -90,7 +90,7 @@ static int consensus_nf_pad_single_onion;
* for every single connection, every second.
*/
void
-channelpadding_new_consensus_params(networkstatus_t *ns)
+channelpadding_new_consensus_params(const networkstatus_t *ns)
{
#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_LOW 1500
#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_HIGH 9500
@@ -265,7 +265,7 @@ channelpadding_update_padding_for_channel(channel_t *chan,
log_fn_ratelim(&relay_limit,LOG_PROTOCOL_WARN,LD_PROTOCOL,
"Got a PADDING_NEGOTIATE from relay at %s (%s). "
"This should not happen.",
- chan->get_remote_descr(chan, 0),
+ channel_describe_peer(chan),
hex_str(chan->identity_digest, DIGEST_LEN));
return -1;
}
@@ -399,7 +399,7 @@ channelpadding_send_padding_cell_for_callback(channel_t *chan)
"Sending netflow keepalive on %"PRIu64" to %s (%s) after "
"%"PRId64" ms. Delta %"PRId64"ms",
(chan->global_identifier),
- safe_str_client(chan->get_remote_descr(chan, 0)),
+ safe_str_client(channel_describe_peer(chan)),
safe_str_client(hex_str(chan->identity_digest, DIGEST_LEN)),
(monotime_coarse_diff_msec(&chan->timestamp_xfer,&now)),
(
diff --git a/src/core/or/channelpadding.h b/src/core/or/channelpadding.h
index d1c7192ffd..9246988cdc 100644
--- a/src/core/or/channelpadding.h
+++ b/src/core/or/channelpadding.h
@@ -37,7 +37,6 @@ int channelpadding_send_enable_command(channel_t *chan, uint16_t low_timeout,
int channelpadding_get_circuits_available_timeout(void);
unsigned int channelpadding_get_channel_idle_timeout(const channel_t *, int);
-void channelpadding_new_consensus_params(networkstatus_t *ns);
+void channelpadding_new_consensus_params(const networkstatus_t *ns);
#endif /* !defined(TOR_CHANNELPADDING_H) */
-
diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c
index 56552f0095..a0debf8d22 100644
--- a/src/core/or/channeltls.c
+++ b/src/core/or/channeltls.c
@@ -63,15 +63,16 @@
#include "trunnel/channelpadding_negotiation.h"
#include "trunnel/netinfo.h"
#include "core/or/channelpadding.h"
+#include "core/or/extendinfo.h"
#include "core/or/cell_st.h"
#include "core/or/cell_queue_st.h"
-#include "core/or/extend_info_st.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 "feature/nodelist/routerinfo_st.h"
#include "core/or/var_cell_st.h"
+#include "src/feature/relay/relay_find_addr.h"
#include "lib/tls/tortls.h"
#include "lib/tls/x509.h"
@@ -102,12 +103,11 @@ static void channel_tls_close_method(channel_t *chan);
static const char * channel_tls_describe_transport_method(channel_t *chan);
static void channel_tls_free_method(channel_t *chan);
static double channel_tls_get_overhead_estimate_method(channel_t *chan);
-static int
-channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out);
+static int channel_tls_get_remote_addr_method(const channel_t *chan,
+ tor_addr_t *addr_out);
static int
channel_tls_get_transport_name_method(channel_t *chan, char **transport_out);
-static const char *
-channel_tls_get_remote_descr_method(channel_t *chan, int flags);
+static const char *channel_tls_describe_peer_method(const channel_t *chan);
static int channel_tls_has_queued_writes_method(channel_t *chan);
static int channel_tls_is_canonical_method(channel_t *chan);
static int
@@ -163,7 +163,7 @@ channel_tls_common_init(channel_tls_t *tlschan)
chan->free_fn = channel_tls_free_method;
chan->get_overhead_estimate = channel_tls_get_overhead_estimate_method;
chan->get_remote_addr = channel_tls_get_remote_addr_method;
- chan->get_remote_descr = channel_tls_get_remote_descr_method;
+ chan->describe_peer = channel_tls_describe_peer_method;
chan->get_transport_name = channel_tls_get_transport_name_method;
chan->has_queued_writes = channel_tls_has_queued_writes_method;
chan->is_canonical = channel_tls_is_canonical_method;
@@ -203,7 +203,7 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port,
tlschan,
(chan->global_identifier));
- if (is_local_addr(addr)) {
+ if (is_local_to_resolve_addr(addr)) {
log_debug(LD_CHANNEL,
"Marking new outgoing channel %"PRIu64 " at %p as local",
(chan->global_identifier), chan);
@@ -340,7 +340,7 @@ channel_tls_handle_incoming(or_connection_t *orconn)
tlschan->conn = orconn;
orconn->chan = tlschan;
- if (is_local_addr(&(TO_CONN(orconn)->addr))) {
+ if (is_local_to_resolve_addr(&(TO_CONN(orconn)->addr))) {
log_debug(LD_CHANNEL,
"Marking new incoming channel %"PRIu64 " at %p as local",
(chan->global_identifier), chan);
@@ -389,6 +389,25 @@ channel_tls_from_base(channel_t *chan)
return (channel_tls_t *)(chan);
}
+/**
+ * Cast a const channel_tls_t to a const channel_t.
+ */
+const channel_t *
+channel_tls_to_base_const(const channel_tls_t *tlschan)
+{
+ return channel_tls_to_base((channel_tls_t*) tlschan);
+}
+
+/**
+ * Cast a const channel_t to a const channel_tls_t, with appropriate
+ * type-checking asserts.
+ */
+const channel_tls_t *
+channel_tls_from_base_const(const channel_t *chan)
+{
+ return channel_tls_from_base((channel_t *)chan);
+}
+
/********************************************
* Method implementations for channel_tls_t *
*******************************************/
@@ -510,24 +529,29 @@ channel_tls_get_overhead_estimate_method(channel_t *chan)
* Get the remote address of a channel_tls_t.
*
* This implements the get_remote_addr method for channel_tls_t; copy the
- * remote endpoint of the channel to addr_out and return 1 (always
- * succeeds for this transport).
+ * remote endpoint of the channel to addr_out and return 1. (Always
+ * succeeds if this channel is attached to an OR connection.)
+ *
+ * Always returns the real address of the peer, not the canonical address.
*/
static int
-channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out)
+channel_tls_get_remote_addr_method(const channel_t *chan,
+ tor_addr_t *addr_out)
{
- int rv = 0;
- channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+ const channel_tls_t *tlschan = CONST_BASE_CHAN_TO_TLS(chan);
tor_assert(tlschan);
tor_assert(addr_out);
- if (tlschan->conn) {
- tor_addr_copy(addr_out, &(tlschan->conn->real_addr));
- rv = 1;
- } else tor_addr_make_unspec(addr_out);
+ if (tlschan->conn == NULL) {
+ tor_addr_make_unspec(addr_out);
+ return 0;
+ }
- return rv;
+ /* They want the real address, so give it to them. */
+ tor_addr_copy(addr_out, &TO_CONN(tlschan->conn)->addr);
+
+ return 1;
}
/**
@@ -555,62 +579,22 @@ channel_tls_get_transport_name_method(channel_t *chan, char **transport_out)
}
/**
- * Get endpoint description of a channel_tls_t.
+ * Get a human-readable endpoint description of a channel_tls_t.
*
- * This implements the get_remote_descr method for channel_tls_t; it returns
- * a text description of the remote endpoint of the channel suitable for use
- * in log messages. The req parameter is 0 for the canonical address or 1 for
- * the actual address seen.
+ * This format is intended for logging, and may change in the future;
+ * nothing should parse or rely on its particular details.
*/
static const char *
-channel_tls_get_remote_descr_method(channel_t *chan, int flags)
+channel_tls_describe_peer_method(const channel_t *chan)
{
- static char buf[TOR_ADDRPORT_BUF_LEN];
- channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
- connection_t *conn;
- const char *answer = NULL;
- char *addr_str;
-
+ const channel_tls_t *tlschan = CONST_BASE_CHAN_TO_TLS(chan);
tor_assert(tlschan);
if (tlschan->conn) {
- conn = TO_CONN(tlschan->conn);
- switch (flags) {
- case 0:
- /* Canonical address with port*/
- tor_snprintf(buf, TOR_ADDRPORT_BUF_LEN,
- "%s:%u", conn->address, conn->port);
- answer = buf;
- break;
- case GRD_FLAG_ORIGINAL:
- /* Actual address with port */
- addr_str = tor_addr_to_str_dup(&(tlschan->conn->real_addr));
- tor_snprintf(buf, TOR_ADDRPORT_BUF_LEN, "%s:%u", addr_str, conn->port);
- tor_free(addr_str);
- answer = buf;
- break;
- case GRD_FLAG_ADDR_ONLY:
- /* Canonical address, no port */
- strlcpy(buf, conn->address, sizeof(buf));
- answer = buf;
- break;
- case GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY:
- /* Actual address, no port */
- addr_str = tor_addr_to_str_dup(&(tlschan->conn->real_addr));
- strlcpy(buf, addr_str, sizeof(buf));
- tor_free(addr_str);
- answer = buf;
- break;
- default:
- /* Something's broken in channel.c */
- tor_assert_nonfatal_unreached_once();
- }
+ return connection_describe_peer(TO_CONN(tlschan->conn));
} else {
- strlcpy(buf, "(No connection)", sizeof(buf));
- answer = buf;
+ return "(No connection)";
}
-
- return answer;
}
/**
@@ -671,6 +655,9 @@ channel_tls_is_canonical_method(channel_t *chan)
*
* This implements the matches_extend_info method for channel_tls_t; the upper
* layer wants to know if this channel matches an extend_info_t.
+ *
+ * NOTE that this function only checks for an address/port match, and should
+ * be used only when no identify is available.
*/
static int
channel_tls_matches_extend_info_method(channel_t *chan,
@@ -690,9 +677,19 @@ channel_tls_matches_extend_info_method(channel_t *chan,
return 0;
}
- return (tor_addr_eq(&(extend_info->addr),
- &(TO_CONN(tlschan->conn)->addr)) &&
- (extend_info->port == TO_CONN(tlschan->conn)->port));
+ const tor_addr_port_t *orport = &tlschan->conn->canonical_orport;
+ // If the canonical address is set, then we'll allow matches based on that.
+ if (! tor_addr_is_unspec(&orport->addr)) {
+ if (extend_info_has_orport(extend_info, &orport->addr, orport->port)) {
+ return 1;
+ }
+ }
+
+ // We also want to match if the true address and port are listed in the
+ // extend info.
+ return extend_info_has_orport(extend_info,
+ &TO_CONN(tlschan->conn)->addr,
+ TO_CONN(tlschan->conn)->port);
}
/**
@@ -720,8 +717,8 @@ channel_tls_matches_target_method(channel_t *chan,
return 0;
}
- /* real_addr is the address this connection came from.
- * base_.addr is updated by connection_or_init_conn_from_address()
+ /* addr is the address this connection came from.
+ * canonical_orport is updated by connection_or_init_conn_from_address()
* to be the address in the descriptor. It may be tempting to
* allow either address to be allowed, but if we did so, it would
* enable someone who steals a relay's keys to covertly impersonate/MITM it
@@ -732,7 +729,7 @@ channel_tls_matches_target_method(channel_t *chan,
* An adversary who has stolen a relay's keys could also post a fake relay
* descriptor, but that attack is easier to detect.
*/
- return tor_addr_eq(&(tlschan->conn->real_addr), target);
+ return tor_addr_eq(&TO_CONN(tlschan->conn)->addr, target);
}
/**
@@ -1341,7 +1338,7 @@ channel_tls_update_marks(or_connection_t *conn)
chan = TLS_CHAN_TO_BASE(conn->chan);
- if (is_local_addr(&(TO_CONN(conn)->addr))) {
+ if (is_local_to_resolve_addr(&(TO_CONN(conn)->addr))) {
if (!channel_is_local(chan)) {
log_debug(LD_CHANNEL,
"Marking channel %"PRIu64 " at %p as local",
@@ -1505,7 +1502,7 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan)
log_fn(LOG_WARN, LD_OR,
"Negotiated link with non-2 protocol after doing a v2 TLS "
"handshake with %s. Closing connection.",
- fmt_addr(&chan->conn->base_.addr));
+ connection_describe_peer(TO_CONN(chan->conn)));
connection_or_close_for_error(chan->conn, 0);
return;
}
@@ -1517,10 +1514,9 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan)
if (chan->conn->link_proto == 2) {
log_info(LD_OR,
- "Negotiated version %d with %s:%d; sending NETINFO.",
+ "Negotiated version %d on %s; sending NETINFO.",
highest_supported_version,
- safe_str_client(chan->conn->base_.address),
- chan->conn->base_.port);
+ connection_describe(TO_CONN(chan->conn)));
if (connection_or_send_netinfo(chan->conn) < 0) {
connection_or_close_for_error(chan->conn, 0);
@@ -1540,10 +1536,9 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan)
tor_assert(chan->conn->link_proto >= 3);
log_info(LD_OR,
- "Negotiated version %d with %s:%d; %s%s%s%s%s",
+ "Negotiated version %d with on %s; %s%s%s%s%s",
highest_supported_version,
- safe_str_client(chan->conn->base_.address),
- chan->conn->base_.port,
+ connection_describe(TO_CONN(chan->conn)),
send_any ? "Sending cells:" : "Waiting for CERTS cell",
send_versions ? " VERSIONS" : "",
send_certs ? " CERTS" : "",
@@ -1676,6 +1671,85 @@ time_abs(time_t val)
return (val < 0) ? -val : val;
}
+/** Return true iff the channel can process a NETINFO cell. For this to return
+ * true, these channel conditions apply:
+ *
+ * 1. Link protocol is version 2 or higher (tor-spec.txt, NETINFO cells
+ * section).
+ *
+ * 2. Underlying OR connection of the channel is either in v2 or v3
+ * handshaking state.
+ */
+static bool
+can_process_netinfo_cell(const channel_tls_t *chan)
+{
+ /* NETINFO cells can only be negotiated on link protocol 2 or higher. */
+ if (chan->conn->link_proto < 2) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Received a NETINFO cell on %s connection; dropping.",
+ chan->conn->link_proto == 0 ? "non-versioned" : "a v1");
+ return false;
+ }
+
+ /* Can't process a NETINFO cell if the connection is not handshaking. */
+ if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V2 &&
+ chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Received a NETINFO cell on non-handshaking connection; dropping.");
+ return false;
+ }
+
+ /* Make sure we do have handshake state. */
+ tor_assert(chan->conn->handshake_state);
+ tor_assert(chan->conn->handshake_state->received_versions);
+
+ return true;
+}
+
+/** Mark the given channel endpoint as a client (which means either a tor
+ * client or a tor bridge).
+ *
+ * This MUST be done on an _unauthenticated_ channel. It is a mistake to mark
+ * an authenticated channel as a client.
+ *
+ * The following is done on the channel:
+ *
+ * 1. Marked as a client.
+ * 2. Type of circuit ID type is set.
+ * 3. The underlying OR connection is initialized with the address of the
+ * endpoint.
+ */
+static void
+mark_channel_tls_endpoint_as_client(channel_tls_t *chan)
+{
+ /* Ending up here for an authenticated link is a mistake. */
+ if (BUG(chan->conn->handshake_state->authenticated)) {
+ return;
+ }
+
+ tor_assert(tor_digest_is_zero(
+ (const char*)(chan->conn->handshake_state->
+ authenticated_rsa_peer_id)));
+ tor_assert(fast_mem_is_zero(
+ (const char*)(chan->conn->handshake_state->
+ authenticated_ed25519_peer_id.pubkey), 32));
+ /* If the client never authenticated, it's a tor client or bridge
+ * relay, and we must not use it for EXTEND requests (nor could we, as
+ * there are no authenticated peer IDs) */
+ channel_mark_client(TLS_CHAN_TO_BASE(chan));
+ channel_set_circid_type(TLS_CHAN_TO_BASE(chan), NULL,
+ chan->conn->link_proto < MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS);
+
+ connection_or_init_conn_from_address(chan->conn,
+ &(chan->conn->base_.addr),
+ chan->conn->base_.port,
+ /* zero, checked above */
+ (const char*)(chan->conn->handshake_state->
+ authenticated_rsa_peer_id),
+ NULL, /* Ed25519 ID: Also checked as zero */
+ 0);
+}
+
/**
* Process a 'netinfo' cell
*
@@ -1701,20 +1775,12 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
tor_assert(chan);
tor_assert(chan->conn);
- if (chan->conn->link_proto < 2) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received a NETINFO cell on %s connection; dropping.",
- chan->conn->link_proto == 0 ? "non-versioned" : "a v1");
+ /* Make sure we can process a NETINFO cell. Link protocol and state
+ * validation is done to make sure of it. */
+ if (!can_process_netinfo_cell(chan)) {
return;
}
- if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V2 &&
- chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received a NETINFO cell on non-handshaking connection; dropping.");
- return;
- }
- tor_assert(chan->conn->handshake_state &&
- chan->conn->handshake_state->received_versions);
+
started_here = connection_or_nonopen_was_started_here(chan->conn);
identity_digest = chan->conn->identity_digest;
@@ -1729,30 +1795,13 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
return;
}
} else {
- /* we're the server. If the client never authenticated, we have
- some housekeeping to do.*/
+ /* We're the server. If the client never authenticated, we have some
+ * housekeeping to do.
+ *
+ * It's a tor client or bridge relay, and we must not use it for EXTEND
+ * requests (nor could we, as there are no authenticated peer IDs) */
if (!(chan->conn->handshake_state->authenticated)) {
- tor_assert(tor_digest_is_zero(
- (const char*)(chan->conn->handshake_state->
- authenticated_rsa_peer_id)));
- tor_assert(fast_mem_is_zero(
- (const char*)(chan->conn->handshake_state->
- authenticated_ed25519_peer_id.pubkey), 32));
- /* If the client never authenticated, it's a tor client or bridge
- * relay, and we must not use it for EXTEND requests (nor could we, as
- * there are no authenticated peer IDs) */
- channel_mark_client(TLS_CHAN_TO_BASE(chan));
- channel_set_circid_type(TLS_CHAN_TO_BASE(chan), NULL,
- chan->conn->link_proto < MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS);
-
- connection_or_init_conn_from_address(chan->conn,
- &(chan->conn->base_.addr),
- chan->conn->base_.port,
- /* zero, checked above */
- (const char*)(chan->conn->handshake_state->
- authenticated_rsa_peer_id),
- NULL, /* Ed25519 ID: Also checked as zero */
- 0);
+ mark_channel_tls_endpoint_as_client(chan);
}
}
}
@@ -1795,7 +1844,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
if (my_addr_type == NETINFO_ADDR_TYPE_IPV4 && my_addr_len == 4) {
if (!get_options()->BridgeRelay && me &&
- tor_addr_eq_ipv4h(&my_apparent_addr, me->addr)) {
+ tor_addr_eq(&my_apparent_addr, &me->ipv4_addr)) {
TLS_CHAN_TO_BASE(chan)->is_canonical_to_peer = 1;
}
} else if (my_addr_type == NETINFO_ADDR_TYPE_IPV6 &&
@@ -1807,6 +1856,13 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
}
}
+ if (me) {
+ /* We have a descriptor, so we are a relay: record the address that the
+ * other side said we had. */
+ tor_addr_copy(&TLS_CHAN_TO_BASE(chan)->addr_according_to_peer,
+ &my_apparent_addr);
+ }
+
n_other_addrs = netinfo_cell_get_n_my_addrs(netinfo_cell);
for (uint8_t i = 0; i < n_other_addrs; i++) {
/* Consider all the other addresses; if any matches, this connection is
@@ -1829,7 +1885,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
* might be doing something funny, but nobody else is doing a MITM
* on the relay's TCP.
*/
- if (tor_addr_eq(&addr, &(chan->conn->real_addr))) {
+ if (tor_addr_eq(&addr, &TO_CONN(chan->conn)->addr)) {
connection_or_set_canonical(chan->conn, 1);
break;
}
@@ -1839,8 +1895,8 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
if (me && !TLS_CHAN_TO_BASE(chan)->is_canonical_to_peer &&
channel_is_canonical(TLS_CHAN_TO_BASE(chan))) {
- const char *descr =
- TLS_CHAN_TO_BASE(chan)->get_remote_descr(TLS_CHAN_TO_BASE(chan), 0);
+ const char *descr = channel_describe_peer(
+ TLS_CHAN_TO_BASE(chan));
log_info(LD_OR,
"We made a connection to a relay at %s (fp=%s) but we think "
"they will not consider this connection canonical. They "
@@ -1849,7 +1905,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
safe_str(hex_str(identity_digest, DIGEST_LEN)),
safe_str(tor_addr_is_null(&my_apparent_addr) ?
"<none>" : fmt_and_decorate_addr(&my_apparent_addr)),
- safe_str(fmt_addr32(me->addr)));
+ safe_str(fmt_addr(&me->ipv4_addr)));
}
/* Act on apparent skew. */
@@ -1863,8 +1919,12 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
"NETINFO cell", "OR");
}
- /* XXX maybe act on my_apparent_addr, if the source is sufficiently
- * trustworthy. */
+ /* Consider our apparent address as a possible suggestion for our address if
+ * we were unable to resolve it previously. The endpoint address is passed
+ * in order to make sure to never consider an address that is the same as
+ * our endpoint. */
+ relay_address_new_suggestion(&my_apparent_addr, &TO_CONN(chan->conn)->addr,
+ identity_digest);
if (! chan->conn->handshake_state->sent_netinfo) {
/* If we were prepared to authenticate, but we never got an AUTH_CHALLENGE
@@ -1878,18 +1938,16 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
if (connection_or_set_state_open(chan->conn) < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Got good NETINFO cell from %s:%d; but "
+ "Got good NETINFO cell on %s; but "
"was unable to make the OR connection become open.",
- safe_str_client(chan->conn->base_.address),
- chan->conn->base_.port);
+ connection_describe(TO_CONN(chan->conn)));
connection_or_close_for_error(chan->conn, 0);
} else {
log_info(LD_OR,
- "Got good NETINFO cell from %s:%d; OR connection is now "
+ "Got good NETINFO cell on %s; OR connection is now "
"open, using protocol version %d. Its ID digest is %s. "
"Our address is apparently %s.",
- safe_str_client(chan->conn->base_.address),
- chan->conn->base_.port,
+ connection_describe(TO_CONN(chan->conn)),
(int)(chan->conn->link_proto),
hex_str(identity_digest, DIGEST_LEN),
tor_addr_is_null(&my_apparent_addr) ?
@@ -1974,9 +2032,9 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
#define ERR(s) \
do { \
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
- "Received a bad CERTS cell from %s:%d: %s", \
- safe_str(chan->conn->base_.address), \
- chan->conn->base_.port, (s)); \
+ "Received a bad CERTS cell on %s: %s", \
+ connection_describe(TO_CONN(chan->conn)), \
+ (s)); \
connection_or_close_for_error(chan->conn, 0); \
goto err; \
} while (0)
@@ -2024,9 +2082,8 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
tor_x509_cert_t *x509_cert = tor_x509_cert_decode(cert_body, cert_len);
if (!x509_cert) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received undecodable certificate in CERTS cell from %s:%d",
- safe_str(chan->conn->base_.address),
- chan->conn->base_.port);
+ "Received undecodable certificate in CERTS cell on %s",
+ connection_describe(TO_CONN(chan->conn)));
} else {
if (x509_certs[cert_type]) {
tor_x509_cert_free(x509_cert);
@@ -2042,9 +2099,8 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
if (!ed_cert) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Received undecodable Ed certificate "
- "in CERTS cell from %s:%d",
- safe_str(chan->conn->base_.address),
- chan->conn->base_.port);
+ "in CERTS cell on %s",
+ connection_describe(TO_CONN(chan->conn)));
} else {
if (ed_certs[cert_type]) {
tor_cert_free(ed_cert);
@@ -2154,9 +2210,9 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
ERR("Problem setting or checking peer id");
log_info(LD_HANDSHAKE,
- "Got some good certificates from %s:%d: Authenticated it with "
+ "Got some good certificates on %s: Authenticated it with "
"RSA%s",
- safe_str(chan->conn->base_.address), chan->conn->base_.port,
+ connection_describe(TO_CONN(chan->conn)),
checked_ed_id ? " and Ed25519" : "");
if (!public_server_mode(get_options())) {
@@ -2168,11 +2224,10 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
} else {
/* We can't call it authenticated till we see an AUTHENTICATE cell. */
log_info(LD_OR,
- "Got some good RSA%s certificates from %s:%d. "
+ "Got some good RSA%s certificates on %s. "
"Waiting for AUTHENTICATE.",
checked_ed_id ? " and Ed25519" : "",
- safe_str(chan->conn->base_.address),
- chan->conn->base_.port);
+ connection_describe(TO_CONN(chan->conn)));
/* XXXX check more stuff? */
}
@@ -2221,9 +2276,9 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
#define ERR(s) \
do { \
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
- "Received a bad AUTH_CHALLENGE cell from %s:%d: %s", \
- safe_str(chan->conn->base_.address), \
- chan->conn->base_.port, (s)); \
+ "Received a bad AUTH_CHALLENGE cell on %s: %s", \
+ connection_describe(TO_CONN(chan->conn)), \
+ (s)); \
connection_or_close_for_error(chan->conn, 0); \
goto done; \
} while (0)
@@ -2268,10 +2323,9 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
if (use_type >= 0) {
log_info(LD_OR,
- "Got an AUTH_CHALLENGE cell from %s:%d: Sending "
+ "Got an AUTH_CHALLENGE cell on %s: Sending "
"authentication type %d",
- safe_str(chan->conn->base_.address),
- chan->conn->base_.port,
+ connection_describe(TO_CONN(chan->conn)),
use_type);
if (connection_or_send_authenticate_cell(chan->conn, use_type) < 0) {
@@ -2282,10 +2336,9 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
}
} else {
log_info(LD_OR,
- "Got an AUTH_CHALLENGE cell from %s:%d, but we don't "
+ "Got an AUTH_CHALLENGE cell on %s, but we don't "
"know any of its authentication types. Not authenticating.",
- safe_str(chan->conn->base_.address),
- chan->conn->base_.port);
+ connection_describe(TO_CONN(chan->conn)));
}
if (connection_or_send_netinfo(chan->conn) < 0) {
@@ -2325,9 +2378,9 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
#define ERR(s) \
do { \
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
- "Received a bad AUTHENTICATE cell from %s:%d: %s", \
- safe_str(chan->conn->base_.address), \
- chan->conn->base_.port, (s)); \
+ "Received a bad AUTHENTICATE cell on %s: %s", \
+ connection_describe(TO_CONN(chan->conn)), \
+ (s)); \
connection_or_close_for_error(chan->conn, 0); \
var_cell_free(expected_cell); \
return; \
@@ -2488,9 +2541,9 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
crypto_pk_free(identity_rcvd);
log_debug(LD_HANDSHAKE,
- "Calling connection_or_init_conn_from_address for %s "
+ "Calling connection_or_init_conn_from_address on %s "
" from %s, with%s ed25519 id.",
- safe_str(chan->conn->base_.address),
+ connection_describe(TO_CONN(chan->conn)),
__func__,
ed_identity_received ? "" : "out");
@@ -2503,10 +2556,9 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
0);
log_debug(LD_HANDSHAKE,
- "Got an AUTHENTICATE cell from %s:%d, type %d: Looks good.",
- safe_str(chan->conn->base_.address),
- chan->conn->base_.port,
- authtype);
+ "Got an AUTHENTICATE cell on %s, type %d: Looks good.",
+ connection_describe(TO_CONN(chan->conn)),
+ authtype);
}
var_cell_free(expected_cell);
diff --git a/src/core/or/channeltls.h b/src/core/or/channeltls.h
index f04ce0fa9c..e7010a51fc 100644
--- a/src/core/or/channeltls.h
+++ b/src/core/or/channeltls.h
@@ -19,6 +19,8 @@ struct curve25519_public_key_t;
#define BASE_CHAN_TO_TLS(c) (channel_tls_from_base((c)))
#define TLS_CHAN_TO_BASE(c) (channel_tls_to_base((c)))
+#define CONST_BASE_CHAN_TO_TLS(c) (channel_tls_from_base_const((c)))
+#define CONST_TLS_CHAN_TO_BASE(c) (channel_tls_to_base_const((c)))
#define TLS_CHAN_MAGIC 0x8a192427U
@@ -44,6 +46,8 @@ channel_t * channel_tls_handle_incoming(or_connection_t *orconn);
channel_t * channel_tls_to_base(channel_tls_t *tlschan);
channel_tls_t * channel_tls_from_base(channel_t *chan);
+const channel_t * channel_tls_to_base_const(const channel_tls_t *tlschan);
+const channel_tls_t * channel_tls_from_base_const(const channel_t *chan);
/* Things for connection_or.c to call back into */
void channel_tls_handle_cell(cell_t *cell, or_connection_t *conn);
diff --git a/src/core/or/circuit_st.h b/src/core/or/circuit_st.h
index 4baafb1848..35d214ce08 100644
--- a/src/core/or/circuit_st.h
+++ b/src/core/or/circuit_st.h
@@ -238,6 +238,12 @@ struct circuit_t {
* Each element of this array corresponds to a different padding machine,
* and we can have up to CIRCPAD_MAX_MACHINES such machines. */
struct circpad_machine_runtime_t *padding_info[CIRCPAD_MAX_MACHINES];
+
+ /** padding_machine_ctr increments each time a new padding machine
+ * is negotiated. It is used for shutdown conditions, to ensure
+ * that STOP commands actually correspond to the current machine,
+ * and not a previous one. */
+ uint32_t padding_machine_ctr;
};
#endif /* !defined(CIRCUIT_ST_H) */
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index a1b8ba78ab..ab4ce9f784 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -45,10 +45,12 @@
#include "core/or/command.h"
#include "core/or/connection_edge.h"
#include "core/or/connection_or.h"
+#include "core/or/extendinfo.h"
#include "core/or/onion.h"
#include "core/or/ocirc_event.h"
#include "core/or/policies.h"
#include "core/or/relay.h"
+#include "core/or/trace_probes_circuit.h"
#include "core/or/crypt_path.h"
#include "feature/client/bridges.h"
#include "feature/client/circpathbias.h"
@@ -70,6 +72,7 @@
#include "feature/rend/rendcommon.h"
#include "feature/stats/predict_ports.h"
#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/trace/events.h"
#include "core/or/cell_st.h"
#include "core/or/cpath_build_state_st.h"
@@ -78,9 +81,6 @@
#include "feature/nodelist/node_st.h"
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
-#include "feature/nodelist/microdesc_st.h"
-#include "feature/nodelist/routerinfo_st.h"
-#include "feature/nodelist/routerstatus_st.h"
static int circuit_send_first_onion_skin(origin_circuit_t *circ);
static int circuit_build_no_more_hops(origin_circuit_t *circ);
@@ -96,13 +96,17 @@ static const node_t *choose_good_middle_server(uint8_t purpose,
* callbacks.
*/
MOCK_IMPL(channel_t *,
-channel_connect_for_circuit,(const tor_addr_t *addr, uint16_t port,
- const char *id_digest,
- const struct ed25519_public_key_t *ed_id))
+channel_connect_for_circuit,(const extend_info_t *ei))
{
channel_t *chan;
- chan = channel_connect(addr, port, id_digest, ed_id);
+ const tor_addr_port_t *orport = extend_info_pick_orport(ei);
+ if (!orport)
+ return NULL;
+ const char *id_digest = ei->identity_digest;
+ const ed25519_public_key_t *ed_id = &ei->ed_identity;
+
+ chan = channel_connect(&orport->addr, orport->port, id_digest, ed_id);
if (chan) command_setup_channel(chan);
return chan;
@@ -439,7 +443,8 @@ onion_populate_cpath(origin_circuit_t *circ)
/** Create and return a new origin circuit. Initialize its purpose and
* build-state based on our arguments. The <b>flags</b> argument is a
- * bitfield of CIRCLAUNCH_* flags. */
+ * bitfield of CIRCLAUNCH_* flags, see circuit_launch_by_extend_info() for
+ * more details. */
origin_circuit_t *
origin_circuit_init(uint8_t purpose, int flags)
{
@@ -455,13 +460,16 @@ origin_circuit_init(uint8_t purpose, int flags)
((flags & CIRCLAUNCH_NEED_CAPACITY) ? 1 : 0);
circ->build_state->is_internal =
((flags & CIRCLAUNCH_IS_INTERNAL) ? 1 : 0);
+ circ->build_state->is_ipv6_selftest =
+ ((flags & CIRCLAUNCH_IS_IPV6_SELFTEST) ? 1 : 0);
circ->base_.purpose = purpose;
return circ;
}
-/** Build a new circuit for <b>purpose</b>. If <b>exit</b>
- * is defined, then use that as your exit router, else choose a suitable
- * exit node.
+/** Build a new circuit for <b>purpose</b>. If <b>exit</b> is defined, then use
+ * that as your exit router, else choose a suitable exit node. The <b>flags</b>
+ * argument is a bitfield of CIRCLAUNCH_* flags, see
+ * circuit_launch_by_extend_info() for more details.
*
* Also launch a connection to the first OR in the chosen path, if
* it's not open already.
@@ -491,6 +499,8 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *exit_ei, int flags)
circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason);
return NULL;
}
+
+ tor_trace(TR_SUBSYS(circuit), TR_EV(establish), circ);
return circ;
}
@@ -546,7 +556,7 @@ circuit_handle_first_hop(origin_circuit_t *circ)
* - the address is internal, and
* - we're not connecting to a configured bridge, and
* - we're not configured to allow extends to private addresses. */
- if (tor_addr_is_internal(&firsthop->extend_info->addr, 0) &&
+ if (extend_info_any_orport_addr_is_internal(firsthop->extend_info) &&
!extend_info_is_a_configured_bridge(firsthop->extend_info) &&
!options->ExtendAllowPrivateAddresses) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
@@ -555,19 +565,15 @@ circuit_handle_first_hop(origin_circuit_t *circ)
}
/* now see if we're already connected to the first OR in 'route' */
- log_debug(LD_CIRC,"Looking for firsthop '%s'",
- fmt_addrport(&firsthop->extend_info->addr,
- firsthop->extend_info->port));
-
- /* We'll cleanup this code in #33220, when we add an IPv6 address to
- * extend_info_t. */
- const bool addr_is_ipv4 =
- (tor_addr_family(&firsthop->extend_info->addr) == AF_INET);
+ const tor_addr_port_t *orport4 =
+ extend_info_get_orport(firsthop->extend_info, AF_INET);
+ const tor_addr_port_t *orport6 =
+ extend_info_get_orport(firsthop->extend_info, AF_INET6);
n_chan = channel_get_for_extend(
firsthop->extend_info->identity_digest,
&firsthop->extend_info->ed_identity,
- addr_is_ipv4 ? &firsthop->extend_info->addr : NULL,
- addr_is_ipv4 ? NULL : &firsthop->extend_info->addr,
+ orport4 ? &orport4->addr : NULL,
+ orport6 ? &orport6->addr : NULL,
&msg,
&should_launch);
@@ -579,11 +585,7 @@ circuit_handle_first_hop(origin_circuit_t *circ)
circ->base_.n_hop = extend_info_dup(firsthop->extend_info);
if (should_launch) {
- n_chan = channel_connect_for_circuit(
- &firsthop->extend_info->addr,
- firsthop->extend_info->port,
- firsthop->extend_info->identity_digest,
- &firsthop->extend_info->ed_identity);
+ n_chan = channel_connect_for_circuit(firsthop->extend_info);
if (!n_chan) { /* connect failed, forget the whole thing */
log_info(LD_CIRC,"connect to firsthop failed. Closing.");
return -END_CIRC_REASON_CONNECTFAILED;
@@ -601,7 +603,8 @@ circuit_handle_first_hop(origin_circuit_t *circ)
tor_assert(!circ->base_.n_hop);
circ->base_.n_chan = n_chan;
circuit_chan_publish(circ, n_chan);
- log_debug(LD_CIRC,"Conn open. Delivering first onion skin.");
+ log_debug(LD_CIRC,"Conn open for %s. Delivering first onion skin.",
+ safe_str_client(extend_info_describe(firsthop->extend_info)));
if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) {
log_info(LD_CIRC,"circuit_send_next_onion_skin failed.");
circ->base_.n_chan = NULL;
@@ -629,7 +632,7 @@ circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits)
tor_assert(chan);
log_debug(LD_CIRC,"chan to %s, status=%d",
- channel_get_canonical_remote_descr(chan), status);
+ channel_describe_peer(chan), status);
pending_circs = smartlist_new();
circuit_get_all_pending_on_channel(pending_circs, chan);
@@ -982,6 +985,7 @@ circuit_send_first_onion_skin(origin_circuit_t *circ)
if (circuit_deliver_create_cell(TO_CIRCUIT(circ), &cc, 0) < 0)
return - END_CIRC_REASON_RESOURCELIMIT;
+ tor_trace(TR_SUBSYS(circuit), TR_EV(first_onion_skin), circ, circ->cpath);
circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
@@ -1052,8 +1056,8 @@ circuit_build_no_more_hops(origin_circuit_t *circ)
control_event_bootstrap(BOOTSTRAP_STATUS_DONE, 0);
control_event_client_status(LOG_NOTICE, "CIRCUIT_ESTABLISHED");
clear_broken_connection_map(1);
- if (server_mode(options) && !check_whether_orport_reachable(options)) {
- inform_testing_reachability();
+ if (server_mode(options) &&
+ !router_all_orports_seem_reachable(options)) {
router_do_reachability_checks(1, 1);
}
}
@@ -1077,23 +1081,40 @@ circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
{
int len;
extend_cell_t ec;
+ /* Relays and bridges can send IPv6 extends. But for clients, it's an
+ * obvious version distinguisher. */
+ const bool include_ipv6 = server_mode(get_options());
memset(&ec, 0, sizeof(ec));
+ tor_addr_make_unspec(&ec.orport_ipv4.addr);
+ tor_addr_make_unspec(&ec.orport_ipv6.addr);
log_debug(LD_CIRC,"starting to send subsequent skin.");
- if (tor_addr_family(&hop->extend_info->addr) != AF_INET) {
- log_warn(LD_BUG, "Trying to extend to a non-IPv4 address.");
- return - END_CIRC_REASON_INTERNAL;
- }
-
circuit_pick_extend_handshake(&ec.cell_type,
&ec.create_cell.cell_type,
&ec.create_cell.handshake_type,
hop->extend_info);
- tor_addr_copy(&ec.orport_ipv4.addr, &hop->extend_info->addr);
- ec.orport_ipv4.port = hop->extend_info->port;
- tor_addr_make_unspec(&ec.orport_ipv6.addr);
+ const tor_addr_port_t *orport4 =
+ extend_info_get_orport(hop->extend_info, AF_INET);
+ const tor_addr_port_t *orport6 =
+ extend_info_get_orport(hop->extend_info, AF_INET6);
+ int n_addrs_set = 0;
+ if (orport4) {
+ tor_addr_copy(&ec.orport_ipv4.addr, &orport4->addr);
+ ec.orport_ipv4.port = orport4->port;
+ ++n_addrs_set;
+ }
+ if (orport6 && include_ipv6) {
+ tor_addr_copy(&ec.orport_ipv6.addr, &orport6->addr);
+ ec.orport_ipv6.port = orport6->port;
+ ++n_addrs_set;
+ }
+
+ if (n_addrs_set == 0) {
+ log_warn(LD_BUG, "No supported address family found in extend_info.");
+ return - END_CIRC_REASON_INTERNAL;
+ }
memcpy(ec.node_id, hop->extend_info->identity_digest, DIGEST_LEN);
/* Set the ED25519 identity too -- it will only get included
* in the extend2 cell if we're configured to use it, though. */
@@ -1128,6 +1149,7 @@ circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
return 0; /* circuit is closed */
}
hop->state = CPATH_STATE_AWAITING_KEYS;
+ tor_trace(TR_SUBSYS(circuit), TR_EV(intermediate_onion_skin), circ, hop);
return 0;
}
@@ -1541,7 +1563,23 @@ choose_good_exit_server_general(router_crn_flags_t flags)
const node_t *selected_node=NULL;
const int need_uptime = (flags & CRN_NEED_UPTIME) != 0;
const int need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
- const int direct_conn = (flags & CRN_DIRECT_CONN) != 0;
+
+ /* We should not require guard flags on exits. */
+ IF_BUG_ONCE(flags & CRN_NEED_GUARD)
+ return NULL;
+
+ /* We reject single-hop exits for all node positions. */
+ IF_BUG_ONCE(flags & CRN_DIRECT_CONN)
+ return NULL;
+
+ /* This isn't the function for picking rendezvous nodes. */
+ IF_BUG_ONCE(flags & CRN_RENDEZVOUS_V3)
+ return NULL;
+
+ /* We only want exits to extend if we cannibalize the circuit.
+ * But we don't require IPv6 extends yet. */
+ IF_BUG_ONCE(flags & CRN_INITIATE_IPV6_EXTEND)
+ return NULL;
connections = get_connection_array();
@@ -1574,19 +1612,14 @@ choose_good_exit_server_general(router_crn_flags_t flags)
*/
continue;
}
- if (!node_has_preferred_descriptor(node, direct_conn)) {
+ if (!router_can_choose_node(node, flags)) {
n_supported[i] = -1;
continue;
}
- if (!node->is_running || node->is_bad_exit) {
+ if (node->is_bad_exit) {
n_supported[i] = -1;
continue; /* skip routers that are known to be down or bad exits */
}
- if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) {
- /* never pick a non-general node as a random exit. */
- n_supported[i] = -1;
- continue;
- }
if (routerset_contains_node(options->ExcludeExitNodesUnion_, node)) {
n_supported[i] = -1;
continue; /* user asked us not to use it, no matter what */
@@ -1596,27 +1629,6 @@ choose_good_exit_server_general(router_crn_flags_t flags)
n_supported[i] = -1;
continue; /* not one of our chosen exit nodes */
}
-
- if (node_is_unreliable(node, need_uptime, need_capacity, 0)) {
- n_supported[i] = -1;
- continue; /* skip routers that are not suitable. Don't worry if
- * this makes us reject all the possible routers: if so,
- * we'll retry later in this function with need_update and
- * need_capacity set to 0. */
- }
- if (!(node->is_valid)) {
- /* if it's invalid and we don't want it */
- n_supported[i] = -1;
-// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- invalid router.",
-// router->nickname, i);
- continue; /* skip invalid routers */
- }
- /* We do not allow relays that allow single hop exits by default. Option
- * was deprecated in 0.2.9.2-alpha and removed in 0.3.1.0-alpha. */
- if (node_allows_single_hop_exits(node)) {
- n_supported[i] = -1;
- continue;
- }
if (node_exit_policy_rejects_all(node)) {
n_supported[i] = -1;
// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- it rejects all.",
@@ -1767,35 +1779,29 @@ pick_restricted_middle_node(router_crn_flags_t flags,
{
const node_t *middle_node = NULL;
- smartlist_t *whitelisted_live_middles = smartlist_new();
+ smartlist_t *allowlisted_live_middles = smartlist_new();
smartlist_t *all_live_nodes = smartlist_new();
tor_assert(pick_from);
/* Add all running nodes to all_live_nodes */
- router_add_running_nodes_to_smartlist(all_live_nodes,
- (flags & CRN_NEED_UPTIME) != 0,
- (flags & CRN_NEED_CAPACITY) != 0,
- (flags & CRN_NEED_GUARD) != 0,
- (flags & CRN_NEED_DESC) != 0,
- (flags & CRN_PREF_ADDR) != 0,
- (flags & CRN_DIRECT_CONN) != 0);
-
- /* Filter all_live_nodes to only add live *and* whitelisted middles
- * to the list whitelisted_live_middles. */
+ router_add_running_nodes_to_smartlist(all_live_nodes, flags);
+
+ /* Filter all_live_nodes to only add live *and* allowlisted middles
+ * to the list allowlisted_live_middles. */
SMARTLIST_FOREACH_BEGIN(all_live_nodes, node_t *, live_node) {
if (routerset_contains_node(pick_from, live_node)) {
- smartlist_add(whitelisted_live_middles, live_node);
+ smartlist_add(allowlisted_live_middles, live_node);
}
} SMARTLIST_FOREACH_END(live_node);
/* Honor ExcludeNodes */
if (exclude_set) {
- routerset_subtract_nodes(whitelisted_live_middles, exclude_set);
+ routerset_subtract_nodes(allowlisted_live_middles, exclude_set);
}
if (exclude_list) {
- smartlist_subtract(whitelisted_live_middles, exclude_list);
+ smartlist_subtract(allowlisted_live_middles, exclude_list);
}
/**
@@ -1811,9 +1817,9 @@ pick_restricted_middle_node(router_crn_flags_t flags,
* If there are a lot of nodes in here, assume they did not load balance
* and do it for them, but also warn them that they may be Doing It Wrong.
*/
- if (smartlist_len(whitelisted_live_middles) <=
+ if (smartlist_len(allowlisted_live_middles) <=
MAX_SANE_RESTRICTED_NODES) {
- middle_node = smartlist_choose(whitelisted_live_middles);
+ middle_node = smartlist_choose(allowlisted_live_middles);
} else {
static ratelim_t pinned_notice_limit = RATELIM_INIT(24*3600);
log_fn_ratelim(&pinned_notice_limit, LOG_NOTICE, LD_CIRC,
@@ -1821,17 +1827,17 @@ pick_restricted_middle_node(router_crn_flags_t flags,
"in %d total nodes. This is a lot of nodes. "
"You may want to consider using a Tor controller "
"to select and update a smaller set of nodes instead.",
- position_hint, smartlist_len(whitelisted_live_middles));
+ position_hint, smartlist_len(allowlisted_live_middles));
/* NO_WEIGHTING here just means don't take node flags into account
* (ie: use consensus measurement only). This is done so that
* we don't further surprise the user by not using Exits that they
* specified at all */
- middle_node = node_sl_choose_by_bandwidth(whitelisted_live_middles,
+ middle_node = node_sl_choose_by_bandwidth(allowlisted_live_middles,
NO_WEIGHTING);
}
- smartlist_free(whitelisted_live_middles);
+ smartlist_free(allowlisted_live_middles);
smartlist_free(all_live_nodes);
return middle_node;
@@ -1959,6 +1965,43 @@ warn_if_last_router_excluded(origin_circuit_t *circ,
return;
}
+/* Return a set of generic CRN_* flags based on <b>state</b>.
+ *
+ * Called for every position in the circuit. */
+STATIC int
+cpath_build_state_to_crn_flags(const cpath_build_state_t *state)
+{
+ router_crn_flags_t flags = 0;
+ /* These flags apply to entry, middle, and exit nodes.
+ * If a flag only applies to a specific position, it should be checked in
+ * that function. */
+ if (state->need_uptime)
+ flags |= CRN_NEED_UPTIME;
+ if (state->need_capacity)
+ flags |= CRN_NEED_CAPACITY;
+ return flags;
+}
+
+/* Return the CRN_INITIATE_IPV6_EXTEND flag, based on <b>state</b> and
+ * <b>cur_len</b>.
+ *
+ * Only called for middle nodes (for now). Must not be called on single-hop
+ * circuits. */
+STATIC int
+cpath_build_state_to_crn_ipv6_extend_flag(const cpath_build_state_t *state,
+ int cur_len)
+{
+ IF_BUG_ONCE(state->desired_path_len < 2)
+ return 0;
+
+ /* The last node is the relay doing the self-test. So we want to extend over
+ * IPv6 from the second-last node. */
+ if (state->is_ipv6_selftest && cur_len == state->desired_path_len - 2)
+ return CRN_INITIATE_IPV6_EXTEND;
+ else
+ return 0;
+}
+
/** Decide a suitable length for circ's cpath, and pick an exit
* router (or use <b>exit</b> if provided). Store these in the
* cpath.
@@ -1992,14 +2035,13 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
exit_ei = extend_info_dup(exit_ei);
} else { /* we have to decide one */
router_crn_flags_t flags = CRN_NEED_DESC;
- if (state->need_uptime)
- flags |= CRN_NEED_UPTIME;
- if (state->need_capacity)
- flags |= CRN_NEED_CAPACITY;
- if (is_hs_v3_rp_circuit)
- flags |= CRN_RENDEZVOUS_V3;
+ flags |= cpath_build_state_to_crn_flags(state);
+ /* Some internal exits are one hop, for example directory connections.
+ * (Guards are always direct, middles are never direct.) */
if (state->onehop_tunnel)
flags |= CRN_DIRECT_CONN;
+ if (is_hs_v3_rp_circuit)
+ flags |= CRN_RENDEZVOUS_V3;
const node_t *node =
choose_good_exit_server(circ, flags, state->is_internal);
if (!node) {
@@ -2061,32 +2103,27 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit_ei)
return 0;
}
-/** Return the number of routers in <b>routers</b> that are currently up
- * and available for building circuits through.
+/** Return the number of routers in <b>nodes</b> that are currently up and
+ * available for building circuits through.
*
- * (Note that this function may overcount or undercount, if we have
- * descriptors that are not the type we would prefer to use for some
- * particular router. See bug #25885.)
+ * If <b>direct</b> is true, only count nodes that are suitable for direct
+ * connections. Counts nodes regardless of whether their addresses are
+ * preferred.
*/
MOCK_IMPL(STATIC int,
count_acceptable_nodes, (const smartlist_t *nodes, int direct))
{
int num=0;
+ int flags = CRN_NEED_DESC;
+
+ if (direct)
+ flags |= CRN_DIRECT_CONN;
SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) {
// log_debug(LD_CIRC,
-// "Contemplating whether router %d (%s) is a new option.",
-// i, r->nickname);
- if (! node->is_running)
-// log_debug(LD_CIRC,"Nope, the directory says %d is not running.",i);
- continue;
- if (! node->is_valid)
-// log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i);
- continue;
- if (! node_has_preferred_descriptor(node, direct))
- continue;
- /* The node has a descriptor, so we can just check the ntor key directly */
- if (!node_has_curve25519_onion_key(node))
+ // "Contemplating whether router %d (%s) is a new option.",
+ // i, r->nickname);
+ if (!router_can_choose_node(node, flags))
continue;
++num;
} SMARTLIST_FOREACH_END(node);
@@ -2111,7 +2148,7 @@ count_acceptable_nodes, (const smartlist_t *nodes, int direct))
* The alternative is building the circuit in reverse. Reverse calls to
* onion_extend_cpath() (ie: select outer hops first) would then have the
* property that you don't gain information about inner hops by observing
- * outer ones. See https://trac.torproject.org/projects/tor/ticket/24487
+ * outer ones. See https://bugs.torproject.org/tpo/core/tor/24487
* for this.
*
* (Note further that we still exclude the exit to prevent A - B - A
@@ -2280,10 +2317,8 @@ choose_good_middle_server(uint8_t purpose,
excluded = build_middle_exclude_list(purpose, state, head, cur_len);
- if (state->need_uptime)
- flags |= CRN_NEED_UPTIME;
- if (state->need_capacity)
- flags |= CRN_NEED_CAPACITY;
+ flags |= cpath_build_state_to_crn_flags(state);
+ flags |= cpath_build_state_to_crn_ipv6_extend_flag(state, cur_len);
/** If a hidden service circuit wants a specific middle node, pin it. */
if (middle_node_must_be_vanguard(options, purpose, cur_len)) {
@@ -2359,10 +2394,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state,
}
if (state) {
- if (state->need_uptime)
- flags |= CRN_NEED_UPTIME;
- if (state->need_capacity)
- flags |= CRN_NEED_CAPACITY;
+ flags |= cpath_build_state_to_crn_flags(state);
}
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
@@ -2431,143 +2463,6 @@ onion_extend_cpath(origin_circuit_t *circ)
return 0;
}
-/** Allocate a new extend_info object based on the various arguments. */
-extend_info_t *
-extend_info_new(const char *nickname,
- const char *rsa_id_digest,
- const ed25519_public_key_t *ed_id,
- crypto_pk_t *onion_key,
- const curve25519_public_key_t *ntor_key,
- const tor_addr_t *addr, uint16_t port)
-{
- extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t));
- memcpy(info->identity_digest, rsa_id_digest, DIGEST_LEN);
- if (ed_id && !ed25519_public_key_is_zero(ed_id))
- memcpy(&info->ed_identity, ed_id, sizeof(ed25519_public_key_t));
- if (nickname)
- strlcpy(info->nickname, nickname, sizeof(info->nickname));
- if (onion_key)
- info->onion_key = crypto_pk_dup_key(onion_key);
- if (ntor_key)
- memcpy(&info->curve25519_onion_key, ntor_key,
- sizeof(curve25519_public_key_t));
- tor_addr_copy(&info->addr, addr);
- info->port = port;
- return info;
-}
-
-/** Allocate and return a new extend_info that can be used to build a
- * circuit to or through the node <b>node</b>. Use the primary address
- * of the node (i.e. its IPv4 address) unless
- * <b>for_direct_connect</b> is true, in which case the preferred
- * address is used instead. May return NULL if there is not enough
- * info about <b>node</b> to extend to it--for example, if the preferred
- * routerinfo_t or microdesc_t is missing, or if for_direct_connect is
- * true and none of the node's addresses is allowed by tor's firewall
- * and IP version config.
- **/
-extend_info_t *
-extend_info_from_node(const node_t *node, int for_direct_connect)
-{
- crypto_pk_t *rsa_pubkey = NULL;
- extend_info_t *info = NULL;
- tor_addr_port_t ap;
- int valid_addr = 0;
-
- if (!node_has_preferred_descriptor(node, for_direct_connect)) {
- return NULL;
- }
-
- /* Choose a preferred address first, but fall back to an allowed address. */
- if (for_direct_connect)
- fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0, &ap);
- else {
- node_get_prim_orport(node, &ap);
- }
- valid_addr = tor_addr_port_is_valid_ap(&ap, 0);
-
- if (valid_addr)
- log_debug(LD_CIRC, "using %s for %s",
- fmt_addrport(&ap.addr, ap.port),
- node->ri ? node->ri->nickname : node->rs->nickname);
- else
- log_warn(LD_CIRC, "Could not choose valid address for %s",
- node->ri ? node->ri->nickname : node->rs->nickname);
-
- /* Every node we connect or extend to must support ntor */
- if (!node_has_curve25519_onion_key(node)) {
- log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
- "Attempted to create extend_info for a node that does not support "
- "ntor: %s", node_describe(node));
- return NULL;
- }
-
- const ed25519_public_key_t *ed_pubkey = NULL;
-
- /* Don't send the ed25519 pubkey unless the target node actually supports
- * authenticating with it. */
- if (node_supports_ed25519_link_authentication(node, 0)) {
- log_info(LD_CIRC, "Including Ed25519 ID for %s", node_describe(node));
- ed_pubkey = node_get_ed25519_id(node);
- } else if (node_get_ed25519_id(node)) {
- log_info(LD_CIRC, "Not including the ed25519 ID for %s, since it won't "
- "be able to authenticate it.",
- node_describe(node));
- }
-
- /* Retrieve the curve25519 pubkey. */
- const curve25519_public_key_t *curve_pubkey =
- node_get_curve25519_onion_key(node);
- rsa_pubkey = node_get_rsa_onion_key(node);
-
- if (valid_addr && node->ri) {
- info = extend_info_new(node->ri->nickname,
- node->identity,
- ed_pubkey,
- rsa_pubkey,
- curve_pubkey,
- &ap.addr,
- ap.port);
- } else if (valid_addr && node->rs && node->md) {
- info = extend_info_new(node->rs->nickname,
- node->identity,
- ed_pubkey,
- rsa_pubkey,
- curve_pubkey,
- &ap.addr,
- ap.port);
- }
-
- crypto_pk_free(rsa_pubkey);
- return info;
-}
-
-/** Release storage held by an extend_info_t struct. */
-void
-extend_info_free_(extend_info_t *info)
-{
- if (!info)
- return;
- crypto_pk_free(info->onion_key);
- tor_free(info);
-}
-
-/** Allocate and return a new extend_info_t with the same contents as
- * <b>info</b>. */
-extend_info_t *
-extend_info_dup(extend_info_t *info)
-{
- extend_info_t *newinfo;
- tor_assert(info);
- newinfo = tor_malloc(sizeof(extend_info_t));
- memcpy(newinfo, info, sizeof(extend_info_t));
- if (info->onion_key)
- newinfo->onion_key = crypto_pk_dup_key(info->onion_key);
- else
- newinfo->onion_key = NULL;
- return newinfo;
-}
-
/** Return the node_t for the chosen exit router in <b>state</b>.
* If there is no chosen exit, or if we don't know the node_t for
* the chosen exit, return NULL.
@@ -2603,43 +2498,6 @@ build_state_get_exit_nickname(cpath_build_state_t *state)
return state->chosen_exit->nickname;
}
-/** Return true iff the given address can be used to extend to. */
-int
-extend_info_addr_is_allowed(const tor_addr_t *addr)
-{
- tor_assert(addr);
-
- /* Check if we have a private address and if we can extend to it. */
- if ((tor_addr_is_internal(addr, 0) || tor_addr_is_multicast(addr)) &&
- !get_options()->ExtendAllowPrivateAddresses) {
- goto disallow;
- }
- /* Allowed! */
- return 1;
- disallow:
- return 0;
-}
-
-/* Does ei have a valid TAP key? */
-int
-extend_info_supports_tap(const extend_info_t* ei)
-{
- tor_assert(ei);
- /* Valid TAP keys are not NULL */
- return ei->onion_key != NULL;
-}
-
-/* Does ei have a valid ntor key? */
-int
-extend_info_supports_ntor(const extend_info_t* ei)
-{
- tor_assert(ei);
- /* Valid ntor keys have at least one non-zero byte */
- return !fast_mem_is_zero(
- (const char*)ei->curve25519_onion_key.public_key,
- CURVE25519_PUBKEY_LEN);
-}
-
/* Is circuit purpose allowed to use the deprecated TAP encryption protocol?
* The hidden service protocol still uses TAP for some connections, because
* ntor onion keys aren't included in HS descriptors or INTRODUCE cells. */
@@ -2674,15 +2532,6 @@ circuit_has_usable_onion_key(const origin_circuit_t *circ)
circuit_can_use_tap(circ));
}
-/* Does ei have an onion key which it would prefer to use?
- * Currently, we prefer ntor keys*/
-int
-extend_info_has_preferred_onion_key(const extend_info_t* ei)
-{
- tor_assert(ei);
- return extend_info_supports_ntor(ei);
-}
-
/** Find the circuits that are waiting to find out whether their guards are
* usable, and if any are ready to become usable, mark them open and try
* attaching streams as appropriate. */
diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h
index e62bb41de9..0cd1eb4f45 100644
--- a/src/core/or/circuitbuild.h
+++ b/src/core/or/circuitbuild.h
@@ -42,23 +42,8 @@ MOCK_DECL(int, circuit_all_predicted_ports_handled, (time_t now,
int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
-extend_info_t *extend_info_new(const char *nickname,
- const char *rsa_id_digest,
- const struct ed25519_public_key_t *ed_id,
- crypto_pk_t *onion_key,
- const struct curve25519_public_key_t *ntor_key,
- const tor_addr_t *addr, uint16_t port);
-extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect);
-extend_info_t *extend_info_dup(extend_info_t *info);
-void extend_info_free_(extend_info_t *info);
-#define extend_info_free(info) \
- FREE_AND_NULL(extend_info_t, extend_info_free_, (info))
-int extend_info_addr_is_allowed(const tor_addr_t *addr);
-int extend_info_supports_tap(const extend_info_t* ei);
-int extend_info_supports_ntor(const extend_info_t* ei);
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);
MOCK_DECL(const node_t *,
build_state_get_exit_node,(cpath_build_state_t *state));
@@ -71,13 +56,7 @@ const node_t *choose_good_entry_server(uint8_t purpose,
struct circuit_guard_state_t **guard_state_out);
void circuit_upgrade_circuits_from_guard_wait(void);
-struct ed25519_public_key_t;
-
-MOCK_DECL(channel_t *,
-channel_connect_for_circuit,(const tor_addr_t *addr,
- uint16_t port,
- const char *id_digest,
- const struct ed25519_public_key_t *ed_id));
+MOCK_DECL(channel_t *, channel_connect_for_circuit,(const extend_info_t *ei));
struct create_cell_t;
MOCK_DECL(int,
@@ -97,6 +76,10 @@ STATIC int onion_extend_cpath(origin_circuit_t *circ);
STATIC int
onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
int is_hs_v3_rp_circuit);
+STATIC int cpath_build_state_to_crn_flags(const cpath_build_state_t *state);
+STATIC int cpath_build_state_to_crn_ipv6_extend_flag(
+ const cpath_build_state_t *state,
+ int cur_len);
#endif /* defined(CIRCUITBUILD_PRIVATE) */
diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c
index 90cce47490..c31fe00dea 100644
--- a/src/core/or/circuitlist.c
+++ b/src/core/or/circuitlist.c
@@ -64,6 +64,8 @@
#include "core/or/circuitstats.h"
#include "core/or/circuitpadding.h"
#include "core/or/crypt_path.h"
+#include "core/or/extendinfo.h"
+#include "core/or/trace_probes_circuit.h"
#include "core/mainloop/connection.h"
#include "app/config/config.h"
#include "core/or/connection_edge.h"
@@ -89,6 +91,7 @@
#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/bwhist.h"
#include "feature/stats/rephist.h"
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/routerset.h"
@@ -564,6 +567,8 @@ circuit_set_state(circuit_t *circ, uint8_t state)
}
if (state == CIRCUIT_STATE_GUARD_WAIT || state == CIRCUIT_STATE_OPEN)
tor_assert(!circ->n_chan_create_cell);
+
+ tor_trace(TR_SUBSYS(circuit), TR_EV(change_state), circ, circ->state, state);
circ->state = state;
if (CIRCUIT_IS_ORIGIN(circ))
circuit_state_publish(circ);
@@ -614,7 +619,7 @@ circuit_count_pending_on_channel(channel_t *chan)
cnt = smartlist_len(sl);
smartlist_free(sl);
log_debug(LD_CIRC,"or_conn to %s, %d pending circs",
- channel_get_canonical_remote_descr(chan),
+ channel_describe_peer(chan),
cnt);
return cnt;
}
@@ -1078,6 +1083,7 @@ origin_circuit_new(void)
prediction_time_remaining);
}
+ tor_trace(TR_SUBSYS(circuit), TR_EV(new_origin), circ);
return circ;
}
@@ -1100,6 +1106,7 @@ or_circuit_new(circid_t p_circ_id, channel_t *p_chan)
init_circuit_base(TO_CIRCUIT(circ));
+ tor_trace(TR_SUBSYS(circuit), TR_EV(new_or), circ);
return circ;
}
@@ -1252,6 +1259,10 @@ circuit_free_(circuit_t *circ)
/* Clear all dangling handle references. */
circuit_handles_clear(circ);
+ /* Tracepoint. Data within the circuit object is recorded so do this before
+ * the actual memory free. */
+ tor_trace(TR_SUBSYS(circuit), TR_EV(free), circ);
+
if (should_free) {
memwipe(mem, 0xAA, memlen); /* poison memory */
tor_free(mem);
@@ -1944,7 +1955,7 @@ circuit_find_to_cannibalize(uint8_t purpose_to_produce, extend_info_t *info,
/* Ignore any circuits for which we can't use the Guard. It is possible
* that the Guard was removed from the sampled set after the circuit
- * was created so avoid using it. */
+ * was created, so avoid using it. */
if (!entry_guard_could_succeed(circ->guard_state)) {
goto next;
}
@@ -2133,7 +2144,7 @@ circuit_mark_all_dirty_circs_as_unusable(void)
* This function is in the critical path of circuit_mark_for_close().
* It must be (and is) O(1)!
*
- * See https://trac.torproject.org/projects/tor/ticket/23512.
+ * See https://bugs.torproject.org/tpo/core/tor/23512
*/
void
circuit_synchronize_written_or_bandwidth(const circuit_t *c,
@@ -2165,6 +2176,12 @@ circuit_synchronize_written_or_bandwidth(const circuit_t *c,
else
cell_size = CELL_MAX_NETWORK_SIZE;
+ /* If we know the channel, find out if it's IPv6. */
+ tor_addr_t remote_addr;
+ bool is_ipv6 = chan &&
+ channel_get_addr_if_possible(chan, &remote_addr) &&
+ tor_addr_family(&remote_addr) == AF_INET6;
+
/* The missing written bytes are the cell counts times their cell
* size plus TLS per cell overhead */
written_sync = cells*(cell_size+TLS_PER_CELL_OVERHEAD);
@@ -2172,7 +2189,7 @@ circuit_synchronize_written_or_bandwidth(const circuit_t *c,
/* Report the missing bytes as written, to avoid asymmetry.
* We must use time() for consistency with rephist, even though on
* some very old rare platforms, approx_time() may be faster. */
- rep_hist_note_bytes_written(written_sync, time(NULL));
+ bwhist_note_bytes_written(written_sync, time(NULL), is_ipv6);
}
/** Mark <b>circ</b> to be closed next time we call
@@ -2274,6 +2291,7 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
CIRCUIT_IS_ORIGIN(circ) ?
TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0,
file, line, orig_reason, reason);
+ tor_trace(TR_SUBSYS(circuit), TR_EV(mark_for_close), circ);
}
/** Called immediately before freeing a marked circuit <b>circ</b> from
@@ -2419,7 +2437,6 @@ single_conn_free_bytes(connection_t *conn)
if (conn->outbuf) {
result += buf_allocation(conn->outbuf);
buf_clear(conn->outbuf);
- conn->outbuf_flushlen = 0;
}
if (conn->type == CONN_TYPE_DIR) {
dir_connection_t *dir_conn = TO_DIR_CONN(conn);
diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c
index 43f4a31624..889ffb03f1 100644
--- a/src/core/or/circuitpadding.c
+++ b/src/core/or/circuitpadding.c
@@ -266,18 +266,31 @@ circpad_marked_circuit_for_padding(circuit_t *circ, int reason)
/**
* Free all the machineinfos in <b>circ</b> that match <b>machine_num</b>.
*
+ * If machine_ctr is non-zero, also make sure it matches the padding_info's
+ * machine counter before freeing.
+ *
* Returns true if any machineinfos with that number were freed.
* False otherwise. */
static int
-free_circ_machineinfos_with_machine_num(circuit_t *circ, int machine_num)
+free_circ_machineinfos_with_machine_num(circuit_t *circ, int machine_num,
+ uint32_t machine_ctr)
{
int found = 0;
FOR_EACH_CIRCUIT_MACHINE_BEGIN(i) {
if (circ->padding_machine[i] &&
circ->padding_machine[i]->machine_num == machine_num) {
- circpad_circuit_machineinfo_free_idx(circ, i);
- circ->padding_machine[i] = NULL;
- found = 1;
+ /* If machine_ctr is non-zero, make sure it matches too. This
+ * is to ensure that old STOP messages don't shutdown newer machines. */
+ if (machine_ctr && circ->padding_info[i] &&
+ circ->padding_info[i]->machine_ctr != machine_ctr) {
+ log_info(LD_CIRC,
+ "Padding shutdown for wrong (old?) machine ctr: %u vs %u",
+ machine_ctr, circ->padding_info[i]->machine_ctr);
+ } else {
+ circpad_circuit_machineinfo_free_idx(circ, i);
+ circ->padding_machine[i] = NULL;
+ found = 1;
+ }
}
} FOR_EACH_CIRCUIT_MACHINE_END;
@@ -306,6 +319,7 @@ circpad_circuit_machineinfo_new(circuit_t *on_circ, int machine_index)
mi->machine_index = machine_index;
mi->on_circ = on_circ;
mi->last_cell_time_sec = approx_time();
+ mi->machine_ctr = on_circ->padding_machine_ctr;
return mi;
}
@@ -1556,19 +1570,23 @@ circpad_machine_spec_transitioned_to_end(circpad_machine_runtime_t *mi)
/* We free the machine info here so that we can be replaced
* by a different machine. But we must leave the padding_machine
* in place to wait for the negotiated response */
+ uint32_t machine_ctr = mi->machine_ctr;
circpad_circuit_machineinfo_free_idx(on_circ,
machine->machine_index);
circpad_negotiate_padding(TO_ORIGIN_CIRCUIT(on_circ),
machine->machine_num,
machine->target_hopnum,
- CIRCPAD_COMMAND_STOP);
+ CIRCPAD_COMMAND_STOP,
+ machine_ctr);
} else {
+ uint32_t machine_ctr = mi->machine_ctr;
circpad_circuit_machineinfo_free_idx(on_circ,
machine->machine_index);
circpad_padding_negotiated(on_circ,
machine->machine_num,
CIRCPAD_COMMAND_STOP,
- CIRCPAD_RESPONSE_OK);
+ CIRCPAD_RESPONSE_OK,
+ machine_ctr);
on_circ->padding_machine[machine->machine_index] = NULL;
}
}
@@ -1990,7 +2008,7 @@ circpad_internal_event_state_length_up(circpad_machine_runtime_t *mi)
* Returns true if the circuit matches the conditions.
*/
static inline bool
-circpad_machine_conditions_met(origin_circuit_t *circ,
+circpad_machine_conditions_apply(origin_circuit_t *circ,
const circpad_machine_spec_t *machine)
{
/* If padding is disabled, no machines should match/apply. This has
@@ -2007,7 +2025,7 @@ circpad_machine_conditions_met(origin_circuit_t *circ,
}
if (!(circpad_circ_purpose_to_mask(TO_CIRCUIT(circ)->purpose)
- & machine->conditions.purpose_mask))
+ & machine->conditions.apply_purpose_mask))
return 0;
if (machine->conditions.requires_vanguards) {
@@ -2023,7 +2041,7 @@ circpad_machine_conditions_met(origin_circuit_t *circ,
* "I want to apply to circuits with either streams or no streams"; OR
* "I only want to apply to circuits with streams"; OR
* "I only want to apply to circuits without streams". */
- if (!(circpad_circuit_state(circ) & machine->conditions.state_mask))
+ if (!(circpad_circuit_state(circ) & machine->conditions.apply_state_mask))
return 0;
if (circuit_get_cpath_opened_len(circ) < machine->conditions.min_hops)
@@ -2033,6 +2051,26 @@ circpad_machine_conditions_met(origin_circuit_t *circ,
}
/**
+ * Check to see if any of the keep conditions still apply to this circuit.
+ *
+ * These conditions keep the machines active if they match, but do not
+ * cause new machines to start up.
+ */
+static inline bool
+circpad_machine_conditions_keep(origin_circuit_t *circ,
+ const circpad_machine_spec_t *machine)
+{
+ if ((circpad_circ_purpose_to_mask(TO_CIRCUIT(circ)->purpose)
+ & machine->conditions.keep_purpose_mask))
+ return 1;
+
+ if ((circpad_circuit_state(circ) & machine->conditions.keep_state_mask))
+ return 1;
+
+ return 0;
+}
+
+/**
* Returns a minimized representation of the circuit state.
*
* The padding code only cares if the circuit is building,
@@ -2097,15 +2135,22 @@ circpad_shutdown_old_machines(origin_circuit_t *on_circ)
circuit_t *circ = TO_CIRCUIT(on_circ);
FOR_EACH_ACTIVE_CIRCUIT_MACHINE_BEGIN(i, circ) {
- if (!circpad_machine_conditions_met(on_circ,
+ /* We shut down a machine if neither the apply conditions
+ * nor the keep conditions match. If either set of conditions match,
+ * keep it around. */
+ if (!circpad_machine_conditions_apply(on_circ,
+ circ->padding_machine[i]) &&
+ !circpad_machine_conditions_keep(on_circ,
circ->padding_machine[i])) {
+ uint32_t machine_ctr = circ->padding_info[i]->machine_ctr;
// Clear machineinfo (frees timers)
circpad_circuit_machineinfo_free_idx(circ, i);
// Send padding negotiate stop
circpad_negotiate_padding(on_circ,
circ->padding_machine[i]->machine_num,
circ->padding_machine[i]->target_hopnum,
- CIRCPAD_COMMAND_STOP);
+ CIRCPAD_COMMAND_STOP,
+ machine_ctr);
}
} FOR_EACH_ACTIVE_CIRCUIT_MACHINE_END;
}
@@ -2154,7 +2199,7 @@ circpad_add_matching_machines(origin_circuit_t *on_circ,
* machines installed on a circuit. Make sure we only
* add this machine if its target machine index is free. */
if (machine->machine_index == i &&
- circpad_machine_conditions_met(on_circ, machine)) {
+ circpad_machine_conditions_apply(on_circ, machine)) {
// We can only replace this machine if the target hopnum
// is the same, otherwise we'll get invalid data
@@ -2172,7 +2217,8 @@ circpad_add_matching_machines(origin_circuit_t *on_circ,
circpad_setup_machine_on_circ(circ, machine);
if (circpad_negotiate_padding(on_circ, machine->machine_num,
machine->target_hopnum,
- CIRCPAD_COMMAND_START) < 0) {
+ CIRCPAD_COMMAND_START,
+ circ->padding_machine_ctr) < 0) {
log_info(LD_CIRC,
"Padding not negotiated. Cleaning machine from circuit %u",
CIRCUIT_IS_ORIGIN(circ) ?
@@ -2463,6 +2509,17 @@ circpad_setup_machine_on_circ(circuit_t *on_circ,
machine->name, on_circ->purpose);
}
+ /* Padding machine ctr starts at 1, so we increment this ctr first.
+ * (machine ctr of 0 means "any machine").
+ *
+ * See https://bugs.tororject.org/30992. */
+ on_circ->padding_machine_ctr++;
+
+ /* uint32 wraparound check: 0 is special, just wrap to 1 */
+ if (on_circ->padding_machine_ctr == 0) {
+ on_circ->padding_machine_ctr = 1;
+ }
+
on_circ->padding_info[machine->machine_index] =
circpad_circuit_machineinfo_new(on_circ, machine->machine_index);
on_circ->padding_machine[machine->machine_index] = machine;
@@ -2555,9 +2612,9 @@ circpad_circ_client_machine_init(void)
= tor_malloc_zero(sizeof(circpad_machine_spec_t));
circ_client_machine->conditions.min_hops = 2;
- circ_client_machine->conditions.state_mask =
+ circ_client_machine->conditions.apply_state_mask =
CIRCPAD_CIRC_BUILDING|CIRCPAD_CIRC_OPENED|CIRCPAD_CIRC_HAS_RELAY_EARLY;
- circ_client_machine->conditions.purpose_mask = CIRCPAD_PURPOSE_ALL;
+ circ_client_machine->conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
circ_client_machine->conditions.reduced_padding_ok = 1;
circ_client_machine->target_hopnum = 2;
@@ -2816,7 +2873,8 @@ signed_error_t
circpad_negotiate_padding(origin_circuit_t *circ,
circpad_machine_num_t machine,
uint8_t target_hopnum,
- uint8_t command)
+ uint8_t command,
+ uint32_t machine_ctr)
{
circpad_negotiate_t type;
cell_t cell;
@@ -2838,14 +2896,16 @@ circpad_negotiate_padding(origin_circuit_t *circ,
circpad_negotiate_set_command(&type, command);
circpad_negotiate_set_version(&type, 0);
circpad_negotiate_set_machine_type(&type, machine);
+ circpad_negotiate_set_machine_ctr(&type, machine_ctr);
if ((len = circpad_negotiate_encode(cell.payload, CELL_PAYLOAD_SIZE,
&type)) < 0)
return -1;
log_fn(LOG_INFO,LD_CIRC,
- "Negotiating padding on circuit %u (%d), command %d",
- circ->global_identifier, TO_CIRCUIT(circ)->purpose, command);
+ "Negotiating padding on circuit %u (%d), command %d, for ctr %u",
+ circ->global_identifier, TO_CIRCUIT(circ)->purpose, command,
+ machine_ctr);
return circpad_send_command_to_hop(circ, target_hopnum,
RELAY_COMMAND_PADDING_NEGOTIATE,
@@ -2861,7 +2921,8 @@ bool
circpad_padding_negotiated(circuit_t *circ,
circpad_machine_num_t machine,
uint8_t command,
- uint8_t response)
+ uint8_t response,
+ uint32_t machine_ctr)
{
circpad_negotiated_t type;
cell_t cell;
@@ -2878,6 +2939,7 @@ circpad_padding_negotiated(circuit_t *circ,
circpad_negotiated_set_response(&type, response);
circpad_negotiated_set_version(&type, 0);
circpad_negotiated_set_machine_type(&type, machine);
+ circpad_negotiated_set_machine_ctr(&type, machine_ctr);
if ((len = circpad_negotiated_encode(cell.payload, CELL_PAYLOAD_SIZE,
&type)) < 0)
@@ -2923,19 +2985,33 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell)
if (negotiate->command == CIRCPAD_COMMAND_STOP) {
/* Free the machine corresponding to this machine type */
if (free_circ_machineinfos_with_machine_num(circ,
- negotiate->machine_type)) {
- log_info(LD_CIRC, "Received STOP command for machine %u",
- negotiate->machine_type);
+ negotiate->machine_type,
+ negotiate->machine_ctr)) {
+ log_info(LD_CIRC, "Received STOP command for machine %u, ctr %u",
+ negotiate->machine_type, negotiate->machine_ctr);
goto done;
}
- log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
- "Received circuit padding stop command for unknown machine.");
- goto err;
- } else if (negotiate->command == CIRCPAD_COMMAND_START) {
+ if (negotiate->machine_ctr <= circ->padding_machine_ctr) {
+ log_info(LD_CIRC, "Received STOP command for old machine %u, ctr %u",
+ negotiate->machine_type, negotiate->machine_ctr);
+ goto done;
+
+ } else {
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Received circuit padding stop command for unknown machine.");
+ goto err;
+ }
+ } else if (negotiate->command == CIRCPAD_COMMAND_START) {
SMARTLIST_FOREACH_BEGIN(relay_padding_machines,
const circpad_machine_spec_t *, m) {
if (m->machine_num == negotiate->machine_type) {
circpad_setup_machine_on_circ(circ, m);
+ if (negotiate->machine_ctr &&
+ circ->padding_machine_ctr != negotiate->machine_ctr) {
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Client and relay have different counts for padding machines: "
+ "%u vs %u", circ->padding_machine_ctr, negotiate->machine_ctr);
+ }
circpad_cell_event_nonpadding_received(circ);
goto done;
}
@@ -2948,7 +3024,8 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell)
done:
circpad_padding_negotiated(circ, negotiate->machine_type,
negotiate->command,
- (retval == 0) ? CIRCPAD_RESPONSE_OK : CIRCPAD_RESPONSE_ERR);
+ (retval == 0) ? CIRCPAD_RESPONSE_OK : CIRCPAD_RESPONSE_ERR,
+ negotiate->machine_ctr);
circpad_negotiate_free(negotiate);
return retval;
@@ -2999,17 +3076,22 @@ circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell,
* circpad_add_matching_matchines() added a new machine,
* there may be a padding_machine for a different machine num
* than this response. */
- free_circ_machineinfos_with_machine_num(circ, negotiated->machine_type);
+ free_circ_machineinfos_with_machine_num(circ, negotiated->machine_type,
+ negotiated->machine_ctr);
} else if (negotiated->command == CIRCPAD_COMMAND_START &&
negotiated->response == CIRCPAD_RESPONSE_ERR) {
- // This can happen due to consensus drift.. free the machines
+ // This can still happen due to consensus drift.. free the machines
// and be sad
- free_circ_machineinfos_with_machine_num(circ, negotiated->machine_type);
- TO_ORIGIN_CIRCUIT(circ)->padding_negotiation_failed = 1;
- log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
- "Middle node did not accept our padding request on circuit %u (%d)",
- TO_ORIGIN_CIRCUIT(circ)->global_identifier,
- circ->purpose);
+ if (free_circ_machineinfos_with_machine_num(circ, negotiated->machine_type,
+ negotiated->machine_ctr)) {
+ // Only fail if a machine was there and matched the error cell
+ TO_ORIGIN_CIRCUIT(circ)->padding_negotiation_failed = 1;
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Middle node did not accept our padding request on circuit "
+ "%u (%d)",
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier,
+ circ->purpose);
+ }
}
circpad_negotiated_free(negotiated);
diff --git a/src/core/or/circuitpadding.h b/src/core/or/circuitpadding.h
index 74b69a1c7a..3d2929cf74 100644
--- a/src/core/or/circuitpadding.h
+++ b/src/core/or/circuitpadding.h
@@ -173,11 +173,21 @@ typedef struct circpad_machine_conditions_t {
/** Only apply the machine *if* the circuit's state matches any of
* the bits set in this bitmask. */
- circpad_circuit_state_t state_mask;
+ circpad_circuit_state_t apply_state_mask;
/** Only apply a machine *if* the circuit's purpose matches one
* of the bits set in this bitmask */
- circpad_purpose_mask_t purpose_mask;
+ circpad_purpose_mask_t apply_purpose_mask;
+
+ /** Keep a machine if any of the circuits's state machine's match
+ * the bits set in this bitmask, but don't apply new machines if
+ * they match this mask. */
+ circpad_circuit_state_t keep_state_mask;
+
+ /** Keep a machine if any of the circuits's state machine's match
+ * the bits set in this bitmask, but don't apply new machines if
+ * they match this mask. */
+ circpad_purpose_mask_t keep_purpose_mask;
} circpad_machine_conditions_t;
@@ -565,6 +575,13 @@ typedef struct circpad_machine_runtime_t {
/** What state is this machine in? */
circpad_statenum_t current_state;
+ /** Machine counter, for shutdown sync.
+ *
+ * Set from circuit_t.padding_machine_ctr, which is incremented each
+ * padding machine instantiation.
+ */
+ uint32_t machine_ctr;
+
/**
* True if we have scheduled a timer for padding.
*
@@ -726,11 +743,13 @@ signed_error_t circpad_handle_padding_negotiated(struct circuit_t *circ,
signed_error_t circpad_negotiate_padding(struct origin_circuit_t *circ,
circpad_machine_num_t machine,
uint8_t target_hopnum,
- uint8_t command);
+ uint8_t command,
+ uint32_t machine_ctr);
bool circpad_padding_negotiated(struct circuit_t *circ,
circpad_machine_num_t machine,
uint8_t command,
- uint8_t response);
+ uint8_t response,
+ uint32_t machine_ctr);
circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose);
diff --git a/src/core/or/circuitpadding_machines.c b/src/core/or/circuitpadding_machines.c
index 98767f9e8f..1e6b580f5b 100644
--- a/src/core/or/circuitpadding_machines.c
+++ b/src/core/or/circuitpadding_machines.c
@@ -67,7 +67,7 @@ circpad_machine_client_hide_intro_circuits(smartlist_t *machines_sl)
client_machine->name = "client_ip_circ";
- client_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED;
+ client_machine->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED;
client_machine->target_hopnum = 2;
/* This is a client machine */
@@ -102,9 +102,18 @@ circpad_machine_client_hide_intro_circuits(smartlist_t *machines_sl)
* INTRO_MACHINE_MAXIMUM_PADDING cells, to match the "...(inbound data cells
* continue)" portion of the trace (aka the rest of an HTTPS response body).
*/
- client_machine->conditions.purpose_mask =
- circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)|
- circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_INTRODUCE_ACKED)|
+
+ /* Start the machine on fresh intro circs. */
+ client_machine->conditions.apply_purpose_mask =
+ circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT);
+
+ /* If the client purpose changes back to CIRCUIT_PURPOSE_C_INTRODUCING,
+ * or transitions to CIRCUIT_PURPOSE_C_INTRODUCE_ACKED, keep the machine
+ * alive, but do not launch new machines for these purposes. Also
+ * keep the machine around if it is in the CIRCUIT_PADDING purpose
+ * (but do not try to take over other machines in that purpose). */
+ client_machine->conditions.keep_purpose_mask =
+ circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_INTRODUCE_ACKED) |
circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_CIRCUIT_PADDING);
/* Keep the circuit alive even after the introduction has been finished,
@@ -152,7 +161,7 @@ circpad_machine_relay_hide_intro_circuits(smartlist_t *machines_sl)
relay_machine->name = "relay_ip_circ";
- relay_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED;
+ relay_machine->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED;
/* This is a relay-side machine */
relay_machine->is_origin_side = 0;
@@ -263,7 +272,7 @@ circpad_machine_client_hide_rend_circuits(smartlist_t *machines_sl)
client_machine->name = "client_rp_circ";
/* Only pad after the circuit has been built and pad to the middle */
- client_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED;
+ client_machine->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED;
client_machine->target_hopnum = 2;
/* This is a client machine */
@@ -299,7 +308,7 @@ circpad_machine_client_hide_rend_circuits(smartlist_t *machines_sl)
*
* Hence this way we make rendezvous circuits look like general circuits up
* till the end of the circuit setup. */
- client_machine->conditions.purpose_mask =
+ client_machine->conditions.apply_purpose_mask =
circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_REND_JOINED)|
circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_REND_READY)|
circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED);
@@ -383,7 +392,7 @@ circpad_machine_relay_hide_rend_circuits(smartlist_t *machines_sl)
/* Only pad after the circuit has been built and pad to the middle */
relay_machine->conditions.min_hops = 2;
- relay_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED;
+ relay_machine->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED;
/* This is a relay-side machine */
relay_machine->is_origin_side = 0;
diff --git a/src/core/or/circuitstats.c b/src/core/or/circuitstats.c
index 5875627b93..51bd9e1208 100644
--- a/src/core/or/circuitstats.c
+++ b/src/core/or/circuitstats.c
@@ -53,9 +53,6 @@
#undef log
#include <math.h>
-static void cbt_control_event_buildtimeout_set(
- const circuit_build_times_t *cbt,
- buildtimeout_set_event_t type);
static void circuit_build_times_scale_circ_counts(circuit_build_times_t *cbt);
#define CBT_BIN_TO_MS(bin) ((bin)*CBT_BIN_WIDTH + (CBT_BIN_WIDTH/2))
@@ -402,7 +399,7 @@ circuit_build_times_initial_timeout(void)
* and learn a new timeout.
*/
static int32_t
-circuit_build_times_recent_circuit_count(networkstatus_t *ns)
+circuit_build_times_recent_circuit_count(const networkstatus_t *ns)
{
int32_t num;
num = networkstatus_get_param(ns, "cbtrecentcount",
@@ -428,7 +425,7 @@ circuit_build_times_recent_circuit_count(networkstatus_t *ns)
*/
void
circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
- networkstatus_t *ns)
+ const networkstatus_t *ns)
{
int32_t num;
@@ -545,7 +542,7 @@ circuit_build_times_get_initial_timeout(void)
* Leave estimated parameters, timeout and network liveness intact
* for future use.
*/
-STATIC void
+void
circuit_build_times_reset(circuit_build_times_t *cbt)
{
memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times));
@@ -1893,61 +1890,3 @@ circuit_build_times_update_last_circ(circuit_build_times_t *cbt)
{
cbt->last_circ_at = approx_time();
}
-
-static void
-cbt_control_event_buildtimeout_set(const circuit_build_times_t *cbt,
- buildtimeout_set_event_t type)
-{
- char *args = NULL;
- double qnt;
- double timeout_rate = 0.0;
- double close_rate = 0.0;
-
- switch (type) {
- case BUILDTIMEOUT_SET_EVENT_RESET:
- case BUILDTIMEOUT_SET_EVENT_SUSPENDED:
- case BUILDTIMEOUT_SET_EVENT_DISCARD:
- qnt = 1.0;
- break;
- case BUILDTIMEOUT_SET_EVENT_COMPUTED:
- case BUILDTIMEOUT_SET_EVENT_RESUME:
- default:
- qnt = circuit_build_times_quantile_cutoff();
- break;
- }
-
- /* The timeout rate is the ratio of the timeout count over
- * the total number of circuits attempted. The total number of
- * circuits is (timeouts+succeeded), since every circuit
- * either succeeds, or times out. "Closed" circuits are
- * MEASURE_TIMEOUT circuits whose measurement period expired.
- * All MEASURE_TIMEOUT circuits are counted in the timeouts stat
- * before transitioning to MEASURE_TIMEOUT (in
- * circuit_build_times_mark_circ_as_measurement_only()).
- * MEASURE_TIMEOUT circuits that succeed are *not* counted as
- * "succeeded". See circuit_build_times_handle_completed_hop().
- *
- * We cast the denominator
- * to promote it to double before the addition, to avoid int32
- * overflow. */
- const double total_circuits =
- ((double)cbt->num_circ_timeouts) + cbt->num_circ_succeeded;
- if (total_circuits >= 1.0) {
- timeout_rate = cbt->num_circ_timeouts / total_circuits;
- close_rate = cbt->num_circ_closed / total_circuits;
- }
-
- tor_asprintf(&args, "TOTAL_TIMES=%lu "
- "TIMEOUT_MS=%lu XM=%lu ALPHA=%f CUTOFF_QUANTILE=%f "
- "TIMEOUT_RATE=%f CLOSE_MS=%lu CLOSE_RATE=%f",
- (unsigned long)cbt->total_build_times,
- (unsigned long)cbt->timeout_ms,
- (unsigned long)cbt->Xm, cbt->alpha, qnt,
- timeout_rate,
- (unsigned long)cbt->close_ms,
- close_rate);
-
- control_event_buildtimeout_set(type, args);
-
- tor_free(args);
-}
diff --git a/src/core/or/circuitstats.h b/src/core/or/circuitstats.h
index 52c9100f53..930e0a9ba3 100644
--- a/src/core/or/circuitstats.h
+++ b/src/core/or/circuitstats.h
@@ -43,12 +43,13 @@ int circuit_build_times_needs_circuits_now(const circuit_build_times_t *cbt);
void circuit_build_times_init(circuit_build_times_t *cbt);
void circuit_build_times_free_timeouts(circuit_build_times_t *cbt);
void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
- networkstatus_t *ns);
+ const networkstatus_t *ns);
double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt);
double circuit_build_times_close_rate(const circuit_build_times_t *cbt);
void circuit_build_times_update_last_circ(circuit_build_times_t *cbt);
void circuit_build_times_mark_circ_as_measurement_only(origin_circuit_t *circ);
+void circuit_build_times_reset(circuit_build_times_t *cbt);
/** Total size of the circuit timeout history to accumulate.
* 1000 is approx 2.5 days worth of continual-use circuits. */
@@ -137,7 +138,6 @@ int32_t circuit_build_times_initial_timeout(void);
STATIC double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
double quantile);
STATIC int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
-STATIC void circuit_build_times_reset(circuit_build_times_t *cbt);
/* Network liveness functions */
STATIC int circuit_build_times_network_check_changed(
@@ -158,7 +158,6 @@ void circuit_build_times_network_is_live(circuit_build_times_t *cbt);
int circuit_build_times_network_check_live(const circuit_build_times_t *cbt);
void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
-#ifdef CIRCUITSTATS_PRIVATE
/** Information about the state of our local network connection */
typedef struct {
/** The timestamp we last completed a TLS handshake or received a cell */
@@ -208,6 +207,5 @@ struct circuit_build_times_t {
uint32_t num_circ_closed;
};
-#endif /* defined(CIRCUITSTATS_PRIVATE) */
#endif /* !defined(TOR_CIRCUITSTATS_H) */
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
index e2c4df25d0..df23c63cff 100644
--- a/src/core/or/circuituse.c
+++ b/src/core/or/circuituse.c
@@ -37,7 +37,9 @@
#include "core/or/circuituse.h"
#include "core/or/circuitpadding.h"
#include "core/or/connection_edge.h"
+#include "core/or/extendinfo.h"
#include "core/or/policies.h"
+#include "core/or/trace_probes_circuit.h"
#include "feature/client/addressmap.h"
#include "feature/client/bridges.h"
#include "feature/client/circpathbias.h"
@@ -62,6 +64,7 @@
#include "feature/stats/predict_ports.h"
#include "lib/math/fp.h"
#include "lib/time/tvdiff.h"
+#include "lib/trace/events.h"
#include "core/or/cpath_build_state_st.h"
#include "feature/dircommon/dir_connection_st.h"
@@ -202,8 +205,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
const int family = tor_addr_parse(&addr,
conn->socks_request->address);
if (family < 0 ||
- !tor_addr_eq(&build_state->chosen_exit->addr, &addr) ||
- build_state->chosen_exit->port != conn->socks_request->port)
+ !extend_info_has_orport(build_state->chosen_exit, &addr,
+ conn->socks_request->port))
return 0;
}
}
@@ -816,7 +819,7 @@ circuit_expire_building(void)
log_info(LD_CIRC,
"Abandoning circ %u %s:%u (state %d,%d:%s, purpose %d, "
"len %d)", TO_ORIGIN_CIRCUIT(victim)->global_identifier,
- channel_get_canonical_remote_descr(victim->n_chan),
+ channel_describe_peer(victim->n_chan),
(unsigned)victim->n_circ_id,
TO_ORIGIN_CIRCUIT(victim)->has_opened,
victim->state, circuit_state_to_string(victim->state),
@@ -837,6 +840,7 @@ circuit_expire_building(void)
-1);
circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim));
+ tor_trace(TR_SUBSYS(circuit), TR_EV(timeout), TO_ORIGIN_CIRCUIT(victim));
if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
circuit_mark_for_close(victim, END_CIRC_REASON_MEASUREMENT_EXPIRED);
else
@@ -1500,8 +1504,11 @@ circuit_expire_old_circuits_clientside(void)
circ->purpose);
/* Don't do this magic for testing circuits. Their death is governed
* by circuit_expire_building */
- if (circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
+ if (circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) {
+ tor_trace(TR_SUBSYS(circuit), TR_EV(idle_timeout),
+ TO_ORIGIN_CIRCUIT(circ));
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
+ }
} else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN) {
if (timercmp(&circ->timestamp_began, &cutoff, OP_LT)) {
if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL ||
@@ -1520,6 +1527,8 @@ circuit_expire_old_circuits_clientside(void)
" that has been unused for %ld msec.",
TO_ORIGIN_CIRCUIT(circ)->global_identifier,
tv_mdiff(&circ->timestamp_began, &now));
+ tor_trace(TR_SUBSYS(circuit), TR_EV(idle_timeout),
+ TO_ORIGIN_CIRCUIT(circ));
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
} else if (!TO_ORIGIN_CIRCUIT(circ)->is_ancient) {
/* Server-side rend joined circuits can end up really old, because
@@ -1642,11 +1651,12 @@ static void
circuit_testing_opened(origin_circuit_t *circ)
{
if (have_performed_bandwidth_test ||
- !check_whether_orport_reachable(get_options())) {
+ !router_orport_seems_reachable(get_options(), AF_INET)) {
/* either we've already done everything we want with testing circuits,
- * or this testing circuit became open due to a fluke, e.g. we picked
- * a last hop where we already had the connection open due to an
- * outgoing local circuit. */
+ * OR this IPv4 testing circuit became open due to a fluke, e.g. we picked
+ * a last hop where we already had the connection open due to a
+ * outgoing local circuit, OR this is an IPv6 self-test circuit, not
+ * a bandwidth test circuit. */
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
} else if (circuit_enough_testing_circs()) {
router_perform_bandwidth_test(NUM_PARALLEL_TESTING_CIRCS, time(NULL));
@@ -1660,7 +1670,8 @@ static void
circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
{
const or_options_t *options = get_options();
- if (server_mode(options) && check_whether_orport_reachable(options))
+ if (server_mode(options) &&
+ router_all_orports_seem_reachable(options))
return;
log_info(LD_GENERAL,
@@ -1681,6 +1692,7 @@ circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
void
circuit_has_opened(origin_circuit_t *circ)
{
+ tor_trace(TR_SUBSYS(circuit), TR_EV(opened), circ);
circuit_event_status(circ, CIRC_EVENT_BUILT, 0);
/* Remember that this circuit has finished building. Now if we start
@@ -1846,7 +1858,7 @@ circuit_build_failed(origin_circuit_t *circ)
"from the first hop (%s). I'm going to try to rotate to a "
"better connection.",
TO_CIRCUIT(circ)->n_circ_id, circ->global_identifier,
- channel_get_canonical_remote_descr(n_chan));
+ channel_describe_peer(n_chan));
n_chan->is_bad_for_new_circs = 1;
} else {
log_info(LD_OR,
@@ -2092,11 +2104,18 @@ circuit_should_cannibalize_to_build(uint8_t purpose_to_build,
}
/** Launch a new circuit with purpose <b>purpose</b> and exit node
- * <b>extend_info</b> (or NULL to select a random exit node). If flags
- * contains CIRCLAUNCH_NEED_UPTIME, choose among routers with high uptime. If
- * CIRCLAUNCH_NEED_CAPACITY is set, choose among routers with high bandwidth.
- * If CIRCLAUNCH_IS_INTERNAL is true, the last hop need not be an exit node.
- * If CIRCLAUNCH_ONEHOP_TUNNEL is set, the circuit will have only one hop.
+ * <b>extend_info</b> (or NULL to select a random exit node).
+ *
+ * If flags contains:
+ * - CIRCLAUNCH_ONEHOP_TUNNEL: the circuit will have only one hop;
+ * - CIRCLAUNCH_NEED_UPTIME: choose routers with high uptime;
+ * - CIRCLAUNCH_NEED_CAPACITY: choose routers with high bandwidth;
+ * - CIRCLAUNCH_IS_IPV6_SELFTEST: the second-last hop must support IPv6
+ * extends;
+ * - CIRCLAUNCH_IS_INTERNAL: the last hop need not be an exit node;
+ * - CIRCLAUNCH_IS_V3_RP: the last hop must support v3 onion service
+ * rendezvous.
+ *
* Return the newly allocated circuit on success, or NULL on failure. */
origin_circuit_t *
circuit_launch_by_extend_info(uint8_t purpose,
@@ -2195,6 +2214,8 @@ circuit_launch_by_extend_info(uint8_t purpose,
tor_fragile_assert();
return NULL;
}
+
+ tor_trace(TR_SUBSYS(circuit), TR_EV(cannibalized), circ);
return circ;
}
}
@@ -3126,6 +3147,8 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
old_purpose = circ->purpose;
circ->purpose = new_purpose;
+ tor_trace(TR_SUBSYS(circuit), TR_EV(change_purpose), circ, old_purpose,
+ new_purpose);
if (CIRCUIT_IS_ORIGIN(circ)) {
control_event_circuit_purpose_changed(TO_ORIGIN_CIRCUIT(circ),
diff --git a/src/core/or/circuituse.h b/src/core/or/circuituse.h
index 95d36d6474..028fe4aa48 100644
--- a/src/core/or/circuituse.h
+++ b/src/core/or/circuituse.h
@@ -36,17 +36,23 @@ void circuit_try_attaching_streams(origin_circuit_t *circ);
void circuit_build_failed(origin_circuit_t *circ);
/** Flag to set when a circuit should have only a single hop. */
-#define CIRCLAUNCH_ONEHOP_TUNNEL (1<<0)
+#define CIRCLAUNCH_ONEHOP_TUNNEL (1<<0)
/** Flag to set when a circuit needs to be built of high-uptime nodes */
-#define CIRCLAUNCH_NEED_UPTIME (1<<1)
+#define CIRCLAUNCH_NEED_UPTIME (1<<1)
/** Flag to set when a circuit needs to be built of high-capacity nodes */
-#define CIRCLAUNCH_NEED_CAPACITY (1<<2)
+#define CIRCLAUNCH_NEED_CAPACITY (1<<2)
/** Flag to set when the last hop of a circuit doesn't need to be an
* exit node. */
-#define CIRCLAUNCH_IS_INTERNAL (1<<3)
+#define CIRCLAUNCH_IS_INTERNAL (1<<3)
/** Flag to set when we are trying to launch a v3 rendezvous circuit. We need
* to apply some additional filters on the node picked. */
-#define CIRCLAUNCH_IS_V3_RP (1<<4)
+#define CIRCLAUNCH_IS_V3_RP (1<<4)
+/** Flag to set when we are trying to launch a self-testing circuit to our
+ * IPv6 ORPort. We need to apply some additional filters on the second-last
+ * node in the circuit. (We are both the client and the last node in the
+ * circuit.) */
+#define CIRCLAUNCH_IS_IPV6_SELFTEST (1<<5)
+
origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
extend_info_t *info,
int flags);
diff --git a/src/core/or/command.c b/src/core/or/command.c
index 8a1d2066cc..9226309ff7 100644
--- a/src/core/or/command.c
+++ b/src/core/or/command.c
@@ -252,7 +252,7 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Received a create cell (type %d) from %s with zero circID; "
" ignoring.", (int)cell->command,
- channel_get_actual_remote_descr(chan));
+ channel_describe_peer(chan));
return;
}
@@ -295,7 +295,7 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
"Received create cell (type %d) from %s, but we're connected "
"to it as a client. "
"Sending back a destroy.",
- (int)cell->command, channel_get_canonical_remote_descr(chan));
+ (int)cell->command, channel_describe_peer(chan));
channel_send_destroy(cell->circ_id, chan,
END_CIRC_REASON_TORPROTOCOL);
return;
@@ -475,7 +475,7 @@ command_process_relay_cell(cell_t *cell, channel_t *chan)
log_debug(LD_OR,
"unknown circuit %u on connection from %s. Dropping.",
(unsigned)cell->circ_id,
- channel_get_canonical_remote_descr(chan));
+ channel_describe_peer(chan));
return;
}
@@ -536,7 +536,7 @@ command_process_relay_cell(cell_t *cell, channel_t *chan)
control_event_circ_bandwidth_used_for_circ(TO_ORIGIN_CIRCUIT(circ));
} else if (circ->n_chan) {
log_warn(LD_OR, " upstream=%s",
- channel_get_actual_remote_descr(circ->n_chan));
+ channel_describe_peer(circ->n_chan));
}
circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
return;
@@ -547,7 +547,7 @@ command_process_relay_cell(cell_t *cell, channel_t *chan)
"Received too many RELAY_EARLY cells on circ %u from %s."
" Closing circuit.",
(unsigned)cell->circ_id,
- safe_str(channel_get_canonical_remote_descr(chan)));
+ safe_str(channel_describe_peer(chan)));
circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
return;
}
@@ -618,7 +618,7 @@ command_process_destroy_cell(cell_t *cell, channel_t *chan)
if (!circ) {
log_info(LD_OR,"unknown circuit %u on connection from %s. Dropping.",
(unsigned)cell->circ_id,
- channel_get_canonical_remote_descr(chan));
+ channel_describe_peer(chan));
return;
}
log_debug(LD_OR,"Received for circID %u.",(unsigned)cell->circ_id);
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
index 26595003c1..25337f0720 100644
--- a/src/core/or/connection_edge.c
+++ b/src/core/or/connection_edge.c
@@ -70,6 +70,7 @@
#include "core/or/circuitpadding.h"
#include "core/or/connection_edge.h"
#include "core/or/connection_or.h"
+#include "core/or/extendinfo.h"
#include "core/or/policies.h"
#include "core/or/reasons.h"
#include "core/or/relay.h"
@@ -165,8 +166,12 @@ static int connection_exit_connect_dir(edge_connection_t *exitconn);
static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port);
static int connection_ap_supports_optimistic_data(const entry_connection_t *);
-/** Convert a connection_t* to an edge_connection_t*; assert if the cast is
- * invalid. */
+/**
+ * Cast a `connection_t *` to an `edge_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not an
+ * `edge_connection_t`.
+ **/
edge_connection_t *
TO_EDGE_CONN(connection_t *c)
{
@@ -175,6 +180,24 @@ TO_EDGE_CONN(connection_t *c)
return DOWNCAST(edge_connection_t, c);
}
+/**
+ * Cast a `const connection_t *` to a `const edge_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not an
+ * `edge_connection_t`.
+ **/
+const edge_connection_t *
+CONST_TO_EDGE_CONN(const connection_t *c)
+{
+ return TO_EDGE_CONN((connection_t *)c);
+}
+
+/**
+ * Cast a `connection_t *` to an `entry_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not an
+ * `entry_connection_t`.
+ **/
entry_connection_t *
TO_ENTRY_CONN(connection_t *c)
{
@@ -182,6 +205,24 @@ TO_ENTRY_CONN(connection_t *c)
return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_.base_);
}
+/**
+ * Cast a `const connection_t *` to a `const entry_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not an
+ * `entry_connection_t`.
+ **/
+const entry_connection_t *
+CONST_TO_ENTRY_CONN(const connection_t *c)
+{
+ return TO_ENTRY_CONN((connection_t*) c);
+}
+
+/**
+ * Cast an `edge_connection_t *` to an `entry_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not an
+ * `entry_connection_t`.
+ **/
entry_connection_t *
EDGE_TO_ENTRY_CONN(edge_connection_t *c)
{
@@ -189,6 +230,18 @@ EDGE_TO_ENTRY_CONN(edge_connection_t *c)
return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_);
}
+/**
+ * Cast a `const edge_connection_t *` to a `const entry_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not an
+ * `entry_connection_t`.
+ **/
+const entry_connection_t *
+CONST_EDGE_TO_ENTRY_CONN(const edge_connection_t *c)
+{
+ return EDGE_TO_ENTRY_CONN((edge_connection_t*)c);
+}
+
/** An AP stream has failed/finished. If it hasn't already sent back
* a socks reply, send one now (based on endreason). Also set
* has_sent_end to 1, and mark the conn.
@@ -423,9 +476,7 @@ warn_if_hs_unreachable(const edge_connection_t *conn, uint8_t reason)
char *m;
if ((m = rate_limit_log(&warn_limit, approx_time()))) {
log_warn(LD_EDGE, "Onion service connection to %s failed (%s)",
- (conn->base_.socket_family == AF_UNIX) ?
- safe_str(conn->base_.address) :
- safe_str(fmt_addrport(&conn->base_.addr, conn->base_.port)),
+ connection_describe_peer(TO_CONN(conn)),
stream_end_reason_to_string(reason));
tor_free(m);
}
@@ -921,9 +972,8 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn)
conn = TO_CONN(edge_conn);
tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING);
- log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.",
- escaped_safe_str(conn->address), conn->port,
- safe_str(fmt_and_decorate_addr(&conn->addr)));
+ log_info(LD_EXIT,"%s established.",
+ connection_describe(conn));
rep_hist_note_exit_stream_opened(conn->port);
@@ -1444,8 +1494,8 @@ connection_ap_fail_onehop(const char *failed_digest,
continue;
}
if (tor_addr_parse(&addr, entry_conn->socks_request->address)<0 ||
- !tor_addr_eq(&build_state->chosen_exit->addr, &addr) ||
- build_state->chosen_exit->port != entry_conn->socks_request->port)
+ !extend_info_has_orport(build_state->chosen_exit, &addr,
+ entry_conn->socks_request->port))
continue;
}
log_info(LD_APP, "Closing one-hop stream to '%s/%s' because the OR conn "
@@ -1503,6 +1553,16 @@ circuit_discard_optional_exit_enclaves(extend_info_t *info)
} SMARTLIST_FOREACH_END(conn);
}
+/** Set the connection state to CONTROLLER_WAIT and send an control port event.
+ */
+void
+connection_entry_set_controller_wait(entry_connection_t *conn)
+{
+ CONNECTION_AP_EXPECT_NONPENDING(conn);
+ ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT;
+ control_event_stream_status(conn, STREAM_EVENT_CONTROLLER_WAIT, 0);
+}
+
/** The AP connection <b>conn</b> has just failed while attaching or
* sending a BEGIN or resolving on <b>circ</b>, but another circuit
* might work. Detach the circuit, and either reattach it, launch a
@@ -1534,8 +1594,7 @@ connection_ap_detach_retriable(entry_connection_t *conn,
circuit_detach_stream(TO_CIRCUIT(circ),ENTRY_TO_EDGE_CONN(conn));
connection_ap_mark_as_pending_circuit(conn);
} else {
- CONNECTION_AP_EXPECT_NONPENDING(conn);
- ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT;
+ connection_entry_set_controller_wait(conn);
circuit_detach_stream(TO_CIRCUIT(circ),ENTRY_TO_EDGE_CONN(conn));
}
return 0;
@@ -1688,8 +1747,7 @@ connection_ap_rewrite_and_attach_if_allowed,(entry_connection_t *conn,
const or_options_t *options = get_options();
if (options->LeaveStreamsUnattached) {
- CONNECTION_AP_EXPECT_NONPENDING(conn);
- ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_CONTROLLER_WAIT;
+ connection_entry_set_controller_wait(conn);
return 0;
}
return connection_ap_handshake_rewrite_and_attach(conn, circ, cpath);
@@ -3839,8 +3897,8 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn)
return -1;
}
if (ret < 0) {
- log_info(LD_REND, "Didn't find rendezvous service (addr%s, port %d)",
- fmt_addr(&TO_CONN(conn)->addr), TO_CONN(conn)->port);
+ log_info(LD_REND, "Didn't find rendezvous service at %s",
+ connection_describe_peer(TO_CONN(conn)));
/* Send back reason DONE because we want to make hidden service port
* scanning harder thus instead of returning that the exit policy
* didn't match, which makes it obvious that the port is closed,
@@ -3975,7 +4033,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
* proxies. */
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Attempt by %s to open a stream %s. Closing.",
- safe_str(channel_get_canonical_remote_descr(or_circ->p_chan)),
+ safe_str(channel_describe_peer(or_circ->p_chan)),
client_chan ? "on first hop of circuit" :
"from unknown relay");
relay_send_end_cell_from_edge(rh.stream_id, circ,
@@ -3998,10 +4056,13 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
* caller might want to know whether the remote IP address has changed,
* and we might already have corrected base_.addr[ess] for the relay's
* canonical IP address. */
- if (or_circ && or_circ->p_chan)
- address = tor_strdup(channel_get_actual_remote_address(or_circ->p_chan));
- else
+ tor_addr_t chan_addr;
+ if (or_circ && or_circ->p_chan &&
+ channel_get_addr_if_possible(or_circ->p_chan, &chan_addr)) {
+ address = tor_addr_to_str_dup(&chan_addr);
+ } else {
address = tor_strdup("127.0.0.1");
+ }
port = 1; /* XXXX This value is never actually used anywhere, and there
* isn't "really" a connection here. But we
* need to set it to something nonzero. */
@@ -4191,8 +4252,8 @@ connection_exit_connect(edge_connection_t *edge_conn)
&why_failed_exit_policy)) {
if (BUG(!why_failed_exit_policy))
why_failed_exit_policy = "";
- log_info(LD_EXIT,"%s:%d failed exit policy%s. Closing.",
- escaped_safe_str_client(conn->address), conn->port,
+ log_info(LD_EXIT,"%s failed exit policy%s. Closing.",
+ connection_describe(conn),
why_failed_exit_policy);
connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY);
circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
diff --git a/src/core/or/connection_edge.h b/src/core/or/connection_edge.h
index 8c06af5664..c9433adade 100644
--- a/src/core/or/connection_edge.h
+++ b/src/core/or/connection_edge.h
@@ -20,6 +20,10 @@ edge_connection_t *TO_EDGE_CONN(connection_t *);
entry_connection_t *TO_ENTRY_CONN(connection_t *);
entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *);
+const edge_connection_t *CONST_TO_EDGE_CONN(const connection_t *);
+const entry_connection_t *CONST_TO_ENTRY_CONN(const connection_t *);
+const entry_connection_t *CONST_EDGE_TO_ENTRY_CONN(const edge_connection_t *);
+
#define EXIT_CONN_STATE_MIN_ 1
/** State for an exit connection: waiting for response from DNS farm. */
#define EXIT_CONN_STATE_RESOLVING 1
@@ -94,6 +98,8 @@ int connection_edge_flushed_some(edge_connection_t *conn);
int connection_edge_finished_flushing(edge_connection_t *conn);
int connection_edge_finished_connecting(edge_connection_t *conn);
+void connection_entry_set_controller_wait(entry_connection_t *conn);
+
void connection_ap_about_to_close(entry_connection_t *edge_conn);
void connection_exit_about_to_close(edge_connection_t *edge_conn);
diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c
index b88d1b6afb..0795521be0 100644
--- a/src/core/or/connection_or.c
+++ b/src/core/or/connection_or.c
@@ -99,8 +99,11 @@ static void connection_or_check_canonicity(or_connection_t *conn,
/**************************************************************/
-/** Convert a connection_t* to an or_connection_t*; assert if the cast is
- * invalid. */
+/**
+ * Cast a `connection_t *` to an `or_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not an `or_connnection_t`.
+ **/
or_connection_t *
TO_OR_CONN(connection_t *c)
{
@@ -108,6 +111,17 @@ TO_OR_CONN(connection_t *c)
return DOWNCAST(or_connection_t, c);
}
+/**
+ * Cast a `const connection_t *` to a `const or_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not an `or_connnection_t`.
+ **/
+const or_connection_t *
+CONST_TO_OR_CONN(const connection_t *c)
+{
+ return TO_OR_CONN((connection_t *)c);
+}
+
/** Clear clear conn->identity_digest and update other data
* structures as appropriate.*/
void
@@ -151,9 +165,9 @@ connection_or_set_identity_digest(or_connection_t *conn,
if (conn->chan)
chan = TLS_CHAN_TO_BASE(conn->chan);
- log_info(LD_HANDSHAKE, "Set identity digest for %p (%s): %s %s.",
+ log_info(LD_HANDSHAKE, "Set identity digest for %s at %p: %s %s.",
+ connection_describe(TO_CONN(conn)),
conn,
- escaped_safe_str(conn->base_.address),
hex_str(rsa_digest, DIGEST_LEN),
ed25519_fmt(ed_id));
log_info(LD_HANDSHAKE, " (Previously: %s %s)",
@@ -575,11 +589,9 @@ connection_or_process_inbuf(or_connection_t *conn)
* 100% true. */
if (buf_datalen(conn->base_.inbuf) > MAX_OR_INBUF_WHEN_NONOPEN) {
log_fn(LOG_PROTOCOL_WARN, LD_NET, "Accumulated too much data (%d bytes) "
- "on nonopen OR connection %s %s:%u in state %s; closing.",
+ "on non-open %s; closing.",
(int)buf_datalen(conn->base_.inbuf),
- connection_or_nonopen_was_started_here(conn) ? "to" : "from",
- conn->base_.address, conn->base_.port,
- conn_state_to_string(conn->base_.type, conn->base_.state));
+ connection_describe(TO_CONN(conn)));
connection_or_close_for_error(conn, 0);
ret = -1;
}
@@ -691,8 +703,8 @@ connection_or_finished_connecting(or_connection_t *or_conn)
conn = TO_CONN(or_conn);
tor_assert(conn->state == OR_CONN_STATE_CONNECTING);
- log_debug(LD_HANDSHAKE,"OR connect() to router at %s:%u finished.",
- conn->address,conn->port);
+ log_debug(LD_HANDSHAKE,"connect finished for %s",
+ connection_describe(conn));
if (proxy_type != PROXY_NONE) {
/* start proxy handshake */
@@ -881,7 +893,9 @@ connection_or_init_conn_from_address(or_connection_t *conn,
conn->base_.port = port;
tor_addr_copy(&conn->base_.addr, addr);
- tor_addr_copy(&conn->real_addr, addr);
+ if (! conn->base_.address) {
+ conn->base_.address = tor_strdup(fmt_addr(addr));
+ }
connection_or_check_canonicity(conn, started_here);
}
@@ -893,9 +907,10 @@ connection_or_init_conn_from_address(or_connection_t *conn,
static void
connection_or_check_canonicity(or_connection_t *conn, int started_here)
{
+ (void) started_here;
+
const char *id_digest = conn->identity_digest;
const ed25519_public_key_t *ed_id = NULL;
- const tor_addr_t *addr = &conn->real_addr;
if (conn->chan)
ed_id = & TLS_CHAN_TO_BASE(conn->chan)->ed25519_identity;
@@ -924,34 +939,17 @@ connection_or_check_canonicity(or_connection_t *conn, int started_here)
} else {
node_ap = &node_ipv6_ap;
}
- if (!started_here) {
- /* Override the addr/port, so our log messages will make sense.
- * This is dangerous, since if we ever try looking up a conn by
- * its actual addr/port, we won't remember. Careful! */
- /* XXXX arma: this is stupid, and it's the reason we need real_addr
- * to track is_canonical properly. What requires it? */
- /* XXXX <arma> i believe the reason we did this, originally, is because
- * we wanted to log what OR a connection was to, and if we logged the
- * right IP address and port 56244, that wouldn't be as helpful. now we
- * log the "right" port too, so we know if it's moria1 or moria2.
- */
- /* See #33898 for a ticket that resolves this technical debt. */
- tor_addr_copy(&conn->base_.addr, &node_ap->addr);
- conn->base_.port = node_ap->port;
- }
+ /* Remember the canonical addr/port so our log messages will make
+ sense. */
+ tor_addr_port_copy(&conn->canonical_orport, node_ap);
tor_free(conn->nickname);
conn->nickname = tor_strdup(node_get_nickname(r));
- tor_free(conn->base_.address);
- conn->base_.address = tor_addr_to_str_dup(&node_ap->addr);
} else {
tor_free(conn->nickname);
conn->nickname = tor_malloc(HEX_DIGEST_LEN+2);
conn->nickname[0] = '$';
base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
conn->identity_digest, DIGEST_LEN);
-
- tor_free(conn->base_.address);
- conn->base_.address = tor_addr_to_str_dup(addr);
}
/*
@@ -1010,9 +1008,10 @@ connection_or_single_set_badness_(time_t now,
or_conn->base_.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD
< now) {
log_info(LD_OR,
- "Marking OR conn to %s:%d as too old for new circuits "
+ "Marking %s as too old for new circuits "
"(fd "TOR_SOCKET_T_FORMAT", %d secs old).",
- or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ connection_describe(TO_CONN(or_conn)),
+ or_conn->base_.s,
(int)(now - or_conn->base_.timestamp_created));
connection_or_mark_bad_for_new_circs(or_conn);
}
@@ -1077,10 +1076,11 @@ connection_or_group_set_badness_(smartlist_t *group, int force)
/* We have at least one open canonical connection to this router,
* and this one is open but not canonical. Mark it bad. */
log_info(LD_OR,
- "Marking OR conn to %s:%d as unsuitable for new circuits: "
+ "Marking %s unsuitable for new circuits: "
"(fd "TOR_SOCKET_T_FORMAT", %d secs old). It is not "
"canonical, and we have another connection to that OR that is.",
- or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ connection_describe(TO_CONN(or_conn)),
+ or_conn->base_.s,
(int)(now - or_conn->base_.timestamp_created));
connection_or_mark_bad_for_new_circs(or_conn);
continue;
@@ -1121,22 +1121,24 @@ connection_or_group_set_badness_(smartlist_t *group, int force)
/* This isn't the best conn, _and_ the best conn is better than it */
if (best->is_canonical) {
log_info(LD_OR,
- "Marking OR conn to %s:%d as unsuitable for new circuits: "
+ "Marking %s as unsuitable for new circuits: "
"(fd "TOR_SOCKET_T_FORMAT", %d secs old). "
"We have a better canonical one "
"(fd "TOR_SOCKET_T_FORMAT"; %d secs old).",
- or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ connection_describe(TO_CONN(or_conn)),
+ or_conn->base_.s,
(int)(now - or_conn->base_.timestamp_created),
best->base_.s, (int)(now - best->base_.timestamp_created));
connection_or_mark_bad_for_new_circs(or_conn);
- } else if (!tor_addr_compare(&or_conn->real_addr,
- &best->real_addr, CMP_EXACT)) {
+ } else if (tor_addr_eq(&TO_CONN(or_conn)->addr,
+ &TO_CONN(best)->addr)) {
log_info(LD_OR,
- "Marking OR conn to %s:%d as unsuitable for new circuits: "
+ "Marking %s unsuitable for new circuits: "
"(fd "TOR_SOCKET_T_FORMAT", %d secs old). We have a better "
"one with the "
"same address (fd "TOR_SOCKET_T_FORMAT"; %d secs old).",
- or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ connection_describe(TO_CONN(or_conn)),
+ or_conn->base_.s,
(int)(now - or_conn->base_.timestamp_created),
best->base_.s, (int)(now - best->base_.timestamp_created));
connection_or_mark_bad_for_new_circs(or_conn);
@@ -1160,7 +1162,7 @@ static time_t or_connect_failure_map_next_cleanup_ts = 0;
* port.
*
* We need to identify a connection failure with these three values because we
- * want to avoid to wrongfully blacklist a relay if someone is trying to
+ * want to avoid to wrongfully block a relay if someone is trying to
* extend to a known identity digest but with the wrong IP/port. For instance,
* it can happen if a relay changed its port but the client still has an old
* descriptor with the old port. We want to stop connecting to that
@@ -1259,7 +1261,7 @@ static or_connect_failure_entry_t *
or_connect_failure_new(const or_connection_t *or_conn)
{
or_connect_failure_entry_t *ocf = tor_malloc_zero(sizeof(*ocf));
- or_connect_failure_init(or_conn->identity_digest, &or_conn->real_addr,
+ or_connect_failure_init(or_conn->identity_digest, &TO_CONN(or_conn)->addr,
TO_CONN(or_conn)->port, ocf);
return ocf;
}
@@ -1464,10 +1466,9 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
* that is we haven't had a failure earlier. This is to avoid to try to
* constantly connect to relays that we think are not reachable. */
if (!should_connect_to_relay(conn)) {
- log_info(LD_GENERAL, "Can't connect to identity %s at %s:%u because we "
+ log_info(LD_GENERAL, "Can't connect to %s because we "
"failed earlier. Refusing.",
- hex_str(id_digest, DIGEST_LEN), fmt_addr(&TO_CONN(conn)->addr),
- TO_CONN(conn)->port);
+ connection_describe_peer(TO_CONN(conn)));
connection_free_(TO_CONN(conn));
return NULL;
}
@@ -1507,7 +1508,7 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
"transport proxy supporting '%s'. This can happen if you "
"haven't provided a ClientTransportPlugin line, or if "
"your pluggable transport proxy stopped running.",
- fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port),
+ connection_describe_peer(TO_CONN(conn)),
transport_name, transport_name);
control_event_bootstrap_prob_or(
@@ -1516,9 +1517,9 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
conn);
} else {
- log_warn(LD_GENERAL, "Tried to connect to '%s' through a proxy, but "
+ log_warn(LD_GENERAL, "Tried to connect to %s through a proxy, but "
"the proxy address could not be found.",
- fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port));
+ connection_describe_peer(TO_CONN(conn)));
}
connection_free_(TO_CONN(conn));
@@ -1638,8 +1639,8 @@ connection_tls_start_handshake,(or_connection_t *conn, int receiving))
log_warn(LD_BUG,"tor_tls_new failed. Closing.");
return -1;
}
- tor_tls_set_logged_address(conn->tls, // XXX client and relay?
- escaped_safe_str(conn->base_.address));
+ tor_tls_set_logged_address(conn->tls,
+ connection_describe_peer(TO_CONN(conn)));
connection_start_reading(TO_CONN(conn));
log_debug(LD_HANDSHAKE,"starting TLS handshake on fd "TOR_SOCKET_T_FORMAT,
@@ -1786,18 +1787,15 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
crypto_pk_t *identity_rcvd=NULL;
const or_options_t *options = get_options();
int severity = server_mode(options) ? LOG_PROTOCOL_WARN : LOG_WARN;
- const char *safe_address =
- started_here ? conn->base_.address :
- safe_str_client(conn->base_.address);
const char *conn_type = started_here ? "outgoing" : "incoming";
int has_cert = 0;
check_no_tls_errors();
has_cert = tor_tls_peer_has_cert(conn->tls);
if (started_here && !has_cert) {
- log_info(LD_HANDSHAKE,"Tried connecting to router at %s:%d, but it didn't "
+ log_info(LD_HANDSHAKE,"Tried connecting to router at %s, but it didn't "
"send a cert! Closing.",
- safe_address, conn->base_.port);
+ connection_describe_peer(TO_CONN(conn)));
return -1;
} else if (!has_cert) {
log_debug(LD_HANDSHAKE,"Got incoming connection with no certificate. "
@@ -1809,9 +1807,9 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
int v = tor_tls_verify(started_here?severity:LOG_INFO,
conn->tls, &identity_rcvd);
if (started_here && v<0) {
- log_fn(severity,LD_HANDSHAKE,"Tried connecting to router at %s:%d: It"
+ log_fn(severity,LD_HANDSHAKE,"Tried connecting to router at %s: It"
" has a cert but it's invalid. Closing.",
- safe_address, conn->base_.port);
+ connection_describe_peer(TO_CONN(conn)));
return -1;
} else if (v<0) {
log_info(LD_HANDSHAKE,"Incoming connection gave us an invalid cert "
@@ -1819,7 +1817,8 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
} else {
log_debug(LD_HANDSHAKE,
"The certificate seems to be valid on %s connection "
- "with %s:%d", conn_type, safe_address, conn->base_.port);
+ "with %s", conn_type,
+ connection_describe_peer(TO_CONN(conn)));
}
check_no_tls_errors();
}
@@ -1891,9 +1890,9 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
const int expected_ed_key =
! ed25519_public_key_is_zero(&chan->ed25519_identity);
- log_info(LD_HANDSHAKE, "learned peer id for %p (%s): %s, %s",
+ log_info(LD_HANDSHAKE, "learned peer id for %s at %p: %s, %s",
+ connection_describe(TO_CONN(conn)),
conn,
- safe_str_client(conn->base_.address),
hex_str((const char*)rsa_peer_id, DIGEST_LEN),
ed25519_fmt(ed_peer_id));
@@ -1907,9 +1906,9 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
conn->nickname[0] = '$';
base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
conn->identity_digest, DIGEST_LEN);
- log_info(LD_HANDSHAKE, "Connected to router %s at %s:%d without knowing "
- "its key. Hoping for the best.",
- conn->nickname, conn->base_.address, conn->base_.port);
+ log_info(LD_HANDSHAKE, "Connected to router at %s without knowing "
+ "its key. Hoping for the best.",
+ connection_describe_peer(TO_CONN(conn)));
/* if it's a bridge and we didn't know its identity fingerprint, now
* we do -- remember it for future attempts. */
learned_router_identity(&conn->base_.addr, conn->base_.port,
@@ -1983,9 +1982,9 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
}
log_fn(severity, LD_HANDSHAKE,
- "Tried connecting to router at %s:%d, but RSA + ed25519 identity "
+ "Tried connecting to router at %s, but RSA + ed25519 identity "
"keys were not as expected: wanted %s + %s but got %s + %s.%s",
- conn->base_.address, conn->base_.port,
+ connection_describe_peer(TO_CONN(conn)),
expected_rsa, expected_ed, seen_rsa, seen_ed, extra_log);
/* Tell the new guard API about the channel failure */
@@ -2012,9 +2011,14 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
/* If we learned an identity for this connection, then we might have
* just discovered it to be canonical. */
connection_or_check_canonicity(conn, conn->handshake_state->started_here);
+ if (conn->tls)
+ tor_tls_set_logged_address(conn->tls,
+ connection_describe_peer(TO_CONN(conn)));
}
if (authdir_mode_tests_reachability(options)) {
+ // We don't want to use canonical_orport here -- we want the address
+ // that we really used.
dirserv_orconn_tls_done(&conn->base_.addr, conn->base_.port,
(const char*)rsa_peer_id, ed_peer_id);
}
@@ -2057,11 +2061,10 @@ connection_tls_finish_handshake(or_connection_t *conn)
tor_assert(!started_here);
- log_debug(LD_HANDSHAKE,"%s tls handshake on %p with %s done, using "
+ log_debug(LD_HANDSHAKE,"%s tls handshake on %s done, using "
"ciphersuite %s. verifying.",
started_here?"outgoing":"incoming",
- conn,
- safe_str_client(conn->base_.address),
+ connection_describe_peer(TO_CONN(conn)),
tor_tls_get_ciphersuite_name(conn->tls));
if (connection_or_check_valid_tls_handshake(conn, started_here,
@@ -2493,11 +2496,9 @@ connection_or_send_netinfo,(or_connection_t *conn))
netinfo_cell_set_timestamp(netinfo_cell, (uint32_t)now);
/* Their address. */
- const tor_addr_t *remote_tor_addr =
- !tor_addr_is_null(&conn->real_addr) ? &conn->real_addr : &conn->base_.addr;
- /* We use &conn->real_addr below, unless it hasn't yet been set. If it
- * hasn't yet been set, we know that base_.addr hasn't been tampered with
- * yet either. */
+ const tor_addr_t *remote_tor_addr = &TO_CONN(conn)->addr;
+ /* We can safely use TO_CONN(conn)->addr here, since we no longer replace
+ * it with a canonical address. */
netinfo_addr_t *their_addr = netinfo_addr_from_tor_addr(remote_tor_addr);
netinfo_cell_set_other_addr(netinfo_cell, their_addr);
@@ -2507,14 +2508,11 @@ connection_or_send_netinfo,(or_connection_t *conn))
* is an outgoing connection, act like a normal client and omit it. */
if ((public_server_mode(get_options()) || !conn->is_outgoing) &&
(me = router_get_my_routerinfo())) {
- tor_addr_t my_addr;
- tor_addr_from_ipv4h(&my_addr, me->addr);
-
uint8_t n_my_addrs = 1 + !tor_addr_is_null(&me->ipv6_addr);
netinfo_cell_set_n_my_addrs(netinfo_cell, n_my_addrs);
netinfo_cell_add_my_addrs(netinfo_cell,
- netinfo_addr_from_tor_addr(&my_addr));
+ netinfo_addr_from_tor_addr(&me->ipv4_addr));
if (!tor_addr_is_null(&me->ipv6_addr)) {
netinfo_cell_add_my_addrs(netinfo_cell,
diff --git a/src/core/or/connection_or.h b/src/core/or/connection_or.h
index e9ace56ab4..fe81b5c5e1 100644
--- a/src/core/or/connection_or.h
+++ b/src/core/or/connection_or.h
@@ -16,6 +16,7 @@ struct ed25519_public_key_t;
struct ed25519_keypair_t;
or_connection_t *TO_OR_CONN(connection_t *);
+const or_connection_t *CONST_TO_OR_CONN(const connection_t *);
#include "core/or/orconn_event.h"
diff --git a/src/core/or/connection_st.h b/src/core/or/connection_st.h
index 685c9f89f4..082420c4bc 100644
--- a/src/core/or/connection_st.h
+++ b/src/core/or/connection_st.h
@@ -101,8 +101,6 @@ struct connection_t {
struct buf_t *inbuf; /**< Buffer holding data read over this connection. */
struct buf_t *outbuf; /**< Buffer holding data to write over this
* connection. */
- size_t outbuf_flushlen; /**< How much data should we try to flush from the
- * outbuf? */
time_t timestamp_last_read_allowed; /**< When was the last time libevent said
* we could read? */
time_t timestamp_last_write_allowed; /**< When was the last time libevent
@@ -112,10 +110,39 @@ struct connection_t {
int socket_family; /**< Address family of this connection's socket. Usually
* AF_INET, but it can also be AF_UNIX, or AF_INET6 */
- tor_addr_t addr; /**< IP that socket "s" is directly connected to;
- * may be the IP address for a proxy or pluggable transport,
- * see "address" for the address of the final destination.
- */
+ /**
+ * IP address on the internet of this connection's peer, usually.
+ *
+ * This address may come from several sources. If this is an outbound
+ * connection, it is the address we are trying to connect to--either
+ * directly through `s`, or via a proxy. (If we used a proxy, then
+ * `getpeername(s)` will not give this address.)
+ *
+ * For incoming connections, this field is the address we got from
+ * getpeername() or accept(), as updated by any proxy that we
+ * are using (for example, an ExtORPort proxy).
+ *
+ * For listeners, this is the address we are trying to bind to.
+ *
+ * If this connection is using a unix socket, then this address is a null
+ * address, and the real address is in the `address` field.
+ *
+ * If this connection represents a request made somewhere other than via
+ * TCP (for example, a UDP dns request, or a controller resolve request),
+ * then this address is the address that originated the request.
+ *
+ * TECHNICAL DEBT:
+ *
+ * There are a few places in the code that modify this address,
+ * or use it in other ways that we don't currently like. Please don't add
+ * any more!
+ *
+ * The misuses of this field include:
+ * * Setting it on linked connections, possibly.
+ * * Updating it based on the Forwarded-For header-- Forwarded-For is
+ * set by a proxy, but not a local trusted proxy.
+ **/
+ tor_addr_t addr;
uint16_t port; /**< If non-zero, port that socket "s" is directly connected
* to; may be the port for a proxy or pluggable transport,
* see "address" for the port at the final destination. */
@@ -125,12 +152,18 @@ struct connection_t {
* marked.) */
const char *marked_for_close_file; /**< For debugging: in which file were
* we marked for close? */
- char *address; /**< FQDN (or IP) and port of the final destination for this
- * connection; this is always the remote address, it is
- * passed to a proxy or pluggable transport if one in use.
- * See "addr" and "port" for the address that socket "s" is
- * directly connected to.
- * strdup into this, because free_connection() frees it. */
+ /**
+ * String address of the peer of this connection.
+ *
+ * TECHNICAL DEBT:
+ *
+ * This field serves many purposes, and they're not all pretty. In addition
+ * to describing the peer we're connected to, it can also hold:
+ *
+ * * An address we're trying to resolve (as an exit).
+ * * A unix address we're trying to bind to (as a listener).
+ **/
+ char *address;
/** Another connection that's connected to this one in lieu of a socket. */
struct connection_t *linked_conn;
diff --git a/src/core/or/cpath_build_state_st.h b/src/core/or/cpath_build_state_st.h
index ee9a0d972c..eb8e97edc5 100644
--- a/src/core/or/cpath_build_state_st.h
+++ b/src/core/or/cpath_build_state_st.h
@@ -24,6 +24,8 @@ struct cpath_build_state_t {
unsigned int need_capacity : 1;
/** Whether the last hop was picked with exiting in mind. */
unsigned int is_internal : 1;
+ /** Is this an IPv6 ORPort self-testing circuit? */
+ unsigned int is_ipv6_selftest : 1;
/** Did we pick this as a one-hop tunnel (not safe for other streams)?
* These are for encrypted dir conns that exit to this router, not
* for arbitrary exits from the circuit. */
diff --git a/src/core/or/crypt_path.c b/src/core/or/crypt_path.c
index 8f41540848..e1bbd81251 100644
--- a/src/core/or/crypt_path.c
+++ b/src/core/or/crypt_path.c
@@ -30,6 +30,7 @@
#include "core/crypto/onion_crypto.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
+#include "core/or/extendinfo.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -259,4 +260,3 @@ cpath_get_n_hops(crypt_path_t **head_ptr)
}
#endif /* defined(TOR_UNIT_TESTS) */
-
diff --git a/src/core/or/dos.c b/src/core/or/dos.c
index 5f99280030..41bf303ffe 100644
--- a/src/core/or/dos.c
+++ b/src/core/or/dos.c
@@ -584,7 +584,7 @@ dos_geoip_entry_about_to_free(const clientmap_entry_t *geoip_ent)
SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
if (conn->type == CONN_TYPE_OR) {
or_connection_t *or_conn = TO_OR_CONN(conn);
- if (!tor_addr_compare(&geoip_ent->addr, &or_conn->real_addr,
+ if (!tor_addr_compare(&geoip_ent->addr, &TO_CONN(or_conn)->addr,
CMP_EXACT)) {
or_conn->tracked_for_dos_mitigation = 0;
}
@@ -696,12 +696,12 @@ dos_new_client_conn(or_connection_t *or_conn, const char *transport_name)
* reason to do so is because network reentry is possible where a client
* connection comes from an Exit node. Even when we'll fix reentry, this is
* a robust defense to keep in place. */
- if (nodelist_probably_contains_address(&or_conn->real_addr)) {
+ if (nodelist_probably_contains_address(&TO_CONN(or_conn)->addr)) {
goto end;
}
/* We are only interested in client connection from the geoip cache. */
- entry = geoip_lookup_client(&or_conn->real_addr, transport_name,
+ entry = geoip_lookup_client(&TO_CONN(or_conn)->addr, transport_name,
GEOIP_CLIENT_CONNECT);
if (BUG(entry == NULL)) {
/* Should never happen because we note down the address in the geoip
@@ -712,7 +712,7 @@ dos_new_client_conn(or_connection_t *or_conn, const char *transport_name)
entry->dos_stats.concurrent_count++;
or_conn->tracked_for_dos_mitigation = 1;
log_debug(LD_DOS, "Client address %s has now %u concurrent connections.",
- fmt_addr(&or_conn->real_addr),
+ fmt_addr(&TO_CONN(or_conn)->addr),
entry->dos_stats.concurrent_count);
end:
@@ -735,7 +735,7 @@ dos_close_client_conn(const 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(&TO_CONN(or_conn)->addr, NULL,
GEOIP_CLIENT_CONNECT);
if (entry == NULL) {
/* This can happen because we can close a connection before the channel
@@ -753,7 +753,7 @@ dos_close_client_conn(const or_connection_t *or_conn)
entry->dos_stats.concurrent_count--;
log_debug(LD_DOS, "Client address %s has lost a connection. Concurrent "
"connections are now at %u",
- fmt_addr(&or_conn->real_addr),
+ fmt_addr(&TO_CONN(or_conn)->addr),
entry->dos_stats.concurrent_count);
end:
diff --git a/src/core/or/extend_info_st.h b/src/core/or/extend_info_st.h
index a66ce24cfa..757c6a1771 100644
--- a/src/core/or/extend_info_st.h
+++ b/src/core/or/extend_info_st.h
@@ -15,9 +15,14 @@
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_ed25519.h"
+/** Largest number of addresses we handle in an extend_info.
+ *
+ * More are permitted in an EXTEND cell, but we won't handle them. */
+#define EXTEND_INFO_MAX_ADDRS 2
+
/** Information on router used when extending a circuit. We don't need a
* full routerinfo_t to extend: we only need addr:port:keyid to build an OR
- * connection, and onion_key to create the onionskin. Note that for onehop
+ * connection, and onion_key to create the onionskin. Note that for one-hop
* general-purpose tunnels, the onion_key is NULL. */
struct extend_info_t {
char nickname[MAX_HEX_NICKNAME_LEN+1]; /**< This router's nickname for
@@ -26,9 +31,12 @@ struct extend_info_t {
char identity_digest[DIGEST_LEN];
/** Ed25519 identity for this router, if any. */
ed25519_public_key_t ed_identity;
- uint16_t port; /**< OR port. */
- tor_addr_t addr; /**< IP address. */
- crypto_pk_t *onion_key; /**< Current onionskin key. */
+ /** IP/Port values for this hop's ORPort(s). Any unused values are set
+ * to a null address. */
+ tor_addr_port_t orports[EXTEND_INFO_MAX_ADDRS];
+ /** TAP onion key for this hop. */
+ crypto_pk_t *onion_key;
+ /** Ntor onion key for this hop. */
curve25519_public_key_t curve25519_onion_key;
};
diff --git a/src/core/or/extendinfo.c b/src/core/or/extendinfo.c
new file mode 100644
index 0000000000..22e5b664bb
--- /dev/null
+++ b/src/core/or/extendinfo.c
@@ -0,0 +1,330 @@
+/* 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 extendinfo.c
+ * @brief Functions for creating and using extend_info_t objects.
+ *
+ * An extend_info_t is the information we hold about a relay in order to
+ * extend a circuit to it.
+ **/
+
+#include "core/or/or.h"
+#include "core/or/extendinfo.h"
+
+#include "app/config/config.h"
+#include "core/or/policies.h"
+#include "feature/nodelist/describe.h"
+#include "feature/nodelist/nodelist.h"
+#include "feature/relay/router.h"
+#include "feature/relay/routermode.h"
+#include "lib/crypt_ops/crypto_rand.h"
+
+#include "core/or/extend_info_st.h"
+#include "feature/nodelist/node_st.h"
+#include "feature/nodelist/routerinfo_st.h"
+#include "feature/nodelist/routerstatus_st.h"
+
+/** Allocate a new extend_info object based on the various arguments. */
+extend_info_t *
+extend_info_new(const char *nickname,
+ const char *rsa_id_digest,
+ const ed25519_public_key_t *ed_id,
+ crypto_pk_t *onion_key,
+ const curve25519_public_key_t *ntor_key,
+ const tor_addr_t *addr, uint16_t port)
+{
+ extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t));
+ if (rsa_id_digest)
+ memcpy(info->identity_digest, rsa_id_digest, DIGEST_LEN);
+ if (ed_id && !ed25519_public_key_is_zero(ed_id))
+ memcpy(&info->ed_identity, ed_id, sizeof(ed25519_public_key_t));
+ if (nickname)
+ strlcpy(info->nickname, nickname, sizeof(info->nickname));
+ if (onion_key)
+ info->onion_key = crypto_pk_dup_key(onion_key);
+ if (ntor_key)
+ memcpy(&info->curve25519_onion_key, ntor_key,
+ sizeof(curve25519_public_key_t));
+ for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) {
+ tor_addr_make_unspec(&info->orports[i].addr);
+ }
+
+ if (addr) {
+ extend_info_add_orport(info, addr, port);
+ }
+ return info;
+}
+
+/**
+ * Add another address:port pair to a given extend_info_t, if there is
+ * room. Return 0 on success, -1 on failure.
+ **/
+int
+extend_info_add_orport(extend_info_t *ei,
+ const tor_addr_t *addr,
+ uint16_t port)
+{
+ for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) {
+ if (tor_addr_is_unspec(&ei->orports[i].addr)) {
+ tor_addr_copy(&ei->orports[i].addr, addr);
+ ei->orports[i].port = port;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/** Allocate and return a new extend_info that can be used to build a
+ * circuit to or through the node <b>node</b>. Use the primary address
+ * of the node (i.e. its IPv4 address) unless
+ * <b>for_direct_connect</b> is true, in which case the preferred
+ * address is used instead. May return NULL if there is not enough
+ * info about <b>node</b> to extend to it--for example, if the preferred
+ * routerinfo_t or microdesc_t is missing, or if for_direct_connect is
+ * true and none of the node's addresses is allowed by tor's firewall
+ * and IP version config.
+ **/
+extend_info_t *
+extend_info_from_node(const node_t *node, int for_direct_connect)
+{
+ crypto_pk_t *rsa_pubkey = NULL;
+ extend_info_t *info = NULL;
+ tor_addr_port_t ap;
+ int valid_addr = 0;
+
+ if (!node_has_preferred_descriptor(node, for_direct_connect)) {
+ return NULL;
+ }
+
+ /* Choose a preferred address first, but fall back to an allowed address. */
+ if (for_direct_connect)
+ reachable_addr_choose_from_node(node, FIREWALL_OR_CONNECTION, 0, &ap);
+ else {
+ node_get_prim_orport(node, &ap);
+ }
+ valid_addr = tor_addr_port_is_valid_ap(&ap, 0);
+
+ if (valid_addr)
+ log_debug(LD_CIRC, "using %s for %s",
+ fmt_addrport(&ap.addr, ap.port),
+ node->ri ? node->ri->nickname : node->rs->nickname);
+ else
+ log_warn(LD_CIRC, "Could not choose valid address for %s",
+ node->ri ? node->ri->nickname : node->rs->nickname);
+
+ /* Every node we connect or extend to must support ntor */
+ if (!node_has_curve25519_onion_key(node)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Attempted to create extend_info for a node that does not support "
+ "ntor: %s", node_describe(node));
+ return NULL;
+ }
+
+ const ed25519_public_key_t *ed_pubkey = NULL;
+
+ /* Don't send the ed25519 pubkey unless the target node actually supports
+ * authenticating with it. */
+ if (node_supports_ed25519_link_authentication(node, 0)) {
+ log_info(LD_CIRC, "Including Ed25519 ID for %s", node_describe(node));
+ ed_pubkey = node_get_ed25519_id(node);
+ } else if (node_get_ed25519_id(node)) {
+ log_info(LD_CIRC, "Not including the ed25519 ID for %s, since it won't "
+ "be able to authenticate it.",
+ node_describe(node));
+ }
+
+ /* Retrieve the curve25519 pubkey. */
+ const curve25519_public_key_t *curve_pubkey =
+ node_get_curve25519_onion_key(node);
+ rsa_pubkey = node_get_rsa_onion_key(node);
+
+ if (valid_addr && node->ri) {
+ info = extend_info_new(node->ri->nickname,
+ node->identity,
+ ed_pubkey,
+ rsa_pubkey,
+ curve_pubkey,
+ &ap.addr,
+ ap.port);
+ } else if (valid_addr && node->rs && node->md) {
+ info = extend_info_new(node->rs->nickname,
+ node->identity,
+ ed_pubkey,
+ rsa_pubkey,
+ curve_pubkey,
+ &ap.addr,
+ ap.port);
+ }
+
+ crypto_pk_free(rsa_pubkey);
+ return info;
+}
+
+/** Release storage held by an extend_info_t struct. */
+void
+extend_info_free_(extend_info_t *info)
+{
+ if (!info)
+ return;
+ crypto_pk_free(info->onion_key);
+ tor_free(info);
+}
+
+/** Allocate and return a new extend_info_t with the same contents as
+ * <b>info</b>. */
+extend_info_t *
+extend_info_dup(extend_info_t *info)
+{
+ extend_info_t *newinfo;
+ tor_assert(info);
+ newinfo = tor_malloc(sizeof(extend_info_t));
+ memcpy(newinfo, info, sizeof(extend_info_t));
+ if (info->onion_key)
+ newinfo->onion_key = crypto_pk_dup_key(info->onion_key);
+ else
+ newinfo->onion_key = NULL;
+ return newinfo;
+}
+
+/* Does ei have a valid TAP key? */
+int
+extend_info_supports_tap(const extend_info_t* ei)
+{
+ tor_assert(ei);
+ /* Valid TAP keys are not NULL */
+ return ei->onion_key != NULL;
+}
+
+/* Does ei have a valid ntor key? */
+int
+extend_info_supports_ntor(const extend_info_t* ei)
+{
+ tor_assert(ei);
+ /* Valid ntor keys have at least one non-zero byte */
+ return !fast_mem_is_zero(
+ (const char*)ei->curve25519_onion_key.public_key,
+ CURVE25519_PUBKEY_LEN);
+}
+
+/* Does ei have an onion key which it would prefer to use?
+ * Currently, we prefer ntor keys*/
+int
+extend_info_has_preferred_onion_key(const extend_info_t* ei)
+{
+ tor_assert(ei);
+ return extend_info_supports_ntor(ei);
+}
+
+/** Return true iff the given address can be used to extend to. */
+int
+extend_info_addr_is_allowed(const tor_addr_t *addr)
+{
+ tor_assert(addr);
+
+ /* Check if we have a private address and if we can extend to it. */
+ if ((tor_addr_is_internal(addr, 0) || tor_addr_is_multicast(addr)) &&
+ !get_options()->ExtendAllowPrivateAddresses) {
+ goto disallow;
+ }
+ /* Allowed! */
+ return 1;
+ disallow:
+ return 0;
+}
+
+/**
+ * Return true if @a addr : @a port is a listed ORPort in @a ei.
+ **/
+bool
+extend_info_has_orport(const extend_info_t *ei,
+ const tor_addr_t *addr, uint16_t port)
+{
+ IF_BUG_ONCE(ei == NULL) {
+ return false;
+ }
+
+ for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) {
+ const tor_addr_port_t *ei_ap = &ei->orports[i];
+ if (tor_addr_eq(&ei_ap->addr, addr) && ei_ap->port == port)
+ return true;
+ }
+ return false;
+}
+
+/**
+ * If the extend_info @a ei has an orport of the chosen family, then return
+ * that orport. Otherwise, return NULL.
+ **/
+const tor_addr_port_t *
+extend_info_get_orport(const extend_info_t *ei, int family)
+{
+ for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) {
+ if (tor_addr_is_unspec(&ei->orports[i].addr))
+ continue;
+ if (tor_addr_family(&ei->orports[i].addr) == family)
+ return &ei->orports[i];
+ }
+ return NULL;
+}
+
+/**
+ * Chose an addr_port_t within @a ei to connect to.
+ **/
+const tor_addr_port_t *
+extend_info_pick_orport(const extend_info_t *ei)
+{
+ IF_BUG_ONCE(!ei) {
+ return NULL;
+ }
+ const or_options_t *options = get_options();
+ if (!server_mode(options)) {
+ // If we aren't a server, just pick the first address we built into
+ // this extendinfo.
+ return &ei->orports[0];
+ }
+
+ const bool ipv6_ok = router_can_extend_over_ipv6(options);
+
+ // Use 'usable' to collect the usable orports, then pick one.
+ const tor_addr_port_t *usable[EXTEND_INFO_MAX_ADDRS];
+ int n_usable = 0;
+ for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) {
+ const tor_addr_port_t *a = &ei->orports[i];
+ const int family = tor_addr_family(&a->addr);
+ if (family == AF_INET || (ipv6_ok && family == AF_INET6)) {
+ usable[n_usable++] = a;
+ }
+ }
+
+ if (n_usable == 0) {
+ // Need to bail out early, since nothing will work.
+ return NULL;
+ }
+
+ crypto_fast_rng_t *rng = get_thread_fast_rng();
+ const int idx = crypto_fast_rng_get_uint(rng, n_usable);
+
+ return usable[idx];
+}
+
+/**
+ * Return true if any orport address in @a ei is an internal address.
+ **/
+bool
+extend_info_any_orport_addr_is_internal(const extend_info_t *ei)
+{
+ IF_BUG_ONCE(ei == NULL) {
+ return false;
+ }
+
+ for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) {
+ if (! tor_addr_is_unspec(&ei->orports[i].addr) &&
+ tor_addr_is_internal(&ei->orports[i].addr, 0))
+ return true;
+ }
+ return false;
+}
diff --git a/src/core/or/extendinfo.h b/src/core/or/extendinfo.h
new file mode 100644
index 0000000000..0049dd0189
--- /dev/null
+++ b/src/core/or/extendinfo.h
@@ -0,0 +1,40 @@
+/* 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 extendinfo.h
+ * @brief Header for core/or/extendinfo.c
+ **/
+
+#ifndef TOR_CORE_OR_EXTENDINFO_H
+#define TOR_CORE_OR_EXTENDINFO_H
+
+extend_info_t *extend_info_new(const char *nickname,
+ const char *rsa_id_digest,
+ const struct ed25519_public_key_t *ed_id,
+ crypto_pk_t *onion_key,
+ const struct curve25519_public_key_t *ntor_key,
+ const tor_addr_t *addr, uint16_t port);
+extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect);
+extend_info_t *extend_info_dup(extend_info_t *info);
+void extend_info_free_(extend_info_t *info);
+#define extend_info_free(info) \
+ FREE_AND_NULL(extend_info_t, extend_info_free_, (info))
+int extend_info_addr_is_allowed(const tor_addr_t *addr);
+int extend_info_supports_tap(const extend_info_t* ei);
+int extend_info_supports_ntor(const extend_info_t* ei);
+int extend_info_has_preferred_onion_key(const extend_info_t* ei);
+bool extend_info_has_orport(const extend_info_t *ei,
+ const tor_addr_t *addr, uint16_t port);
+int extend_info_add_orport(extend_info_t *ei,
+ const tor_addr_t *addr,
+ uint16_t port);
+const tor_addr_port_t *extend_info_get_orport(const extend_info_t *ei,
+ int family);
+const tor_addr_port_t *extend_info_pick_orport(const extend_info_t *ei);
+bool extend_info_any_orport_addr_is_internal(const extend_info_t *ei);
+
+#endif /* !defined(TOR_CORE_OR_EXTENDINFO_H) */
diff --git a/src/core/or/include.am b/src/core/or/include.am
index 3626e76bed..9ff92adbde 100644
--- a/src/core/or/include.am
+++ b/src/core/or/include.am
@@ -18,6 +18,7 @@ LIBTOR_APP_A_SOURCES += \
src/core/or/connection_edge.c \
src/core/or/connection_or.c \
src/core/or/dos.c \
+ src/core/or/extendinfo.c \
src/core/or/onion.c \
src/core/or/ocirc_event.c \
src/core/or/or_periodic.c \
@@ -64,6 +65,7 @@ noinst_HEADERS += \
src/core/or/destroy_cell_queue_st.h \
src/core/or/dos.h \
src/core/or/edge_connection_st.h \
+ src/core/or/extendinfo.h \
src/core/or/half_edge_st.h \
src/core/or/entry_connection_st.h \
src/core/or/entry_port_cfg_st.h \
@@ -94,3 +96,10 @@ noinst_HEADERS += \
src/core/or/tor_version_st.h \
src/core/or/var_cell_st.h \
src/core/or/versions.h
+
+if USE_TRACING_INSTRUMENTATION_LTTNG
+LIBTOR_APP_A_SOURCES += \
+ src/core/or/trace_probes_circuit.c
+noinst_HEADERS += \
+ src/core/or/trace_probes_circuit.h
+endif
diff --git a/src/core/or/lttng_circuit.inc b/src/core/or/lttng_circuit.inc
new file mode 100644
index 0000000000..fc3e175c8a
--- /dev/null
+++ b/src/core/or/lttng_circuit.inc
@@ -0,0 +1,322 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file lttng_circuit.inc
+ * \brief LTTng tracing probe declaration for the circuit subsystem. It is in
+* this .inc file due to the non C standard syntax and the way we guard
+* the header with the LTTng specific TRACEPOINT_HEADER_MULTI_READ.
+ **/
+
+#include "orconfig.h"
+
+/* We only build the following if LTTng instrumentation has been enabled. */
+#ifdef USE_TRACING_INSTRUMENTATION_LTTNG
+
+/* The following defines are LTTng-UST specific. */
+#undef TRACEPOINT_PROVIDER
+#define TRACEPOINT_PROVIDER tor_circuit
+
+#undef TRACEPOINT_INCLUDE
+#define TRACEPOINT_INCLUDE "./src/core/or/lttng_circuit.inc"
+
+#if !defined(LTTNG_CIRCUIT_INC) || defined(TRACEPOINT_HEADER_MULTI_READ)
+#define LTTNG_CIRCUIT_INC
+
+#include <lttng/tracepoint.h>
+
+/*
+ * Circuit Purposes
+ *
+ * The following defines an enumeration of all possible circuit purpose so
+ * they appear in the trace with the define name (first parameter of
+ * ctf_enum_value) instead of the numerical value.
+ */
+TRACEPOINT_ENUM(tor_circuit, purpose,
+ TP_ENUM_VALUES(
+ /* Initializing. */
+ ctf_enum_value("<UNSET>", 0)
+
+ /* OR Side. */
+ ctf_enum_value("OR", CIRCUIT_PURPOSE_OR)
+ ctf_enum_value("OR_INTRO_POINT", CIRCUIT_PURPOSE_INTRO_POINT)
+ ctf_enum_value("OR_REND_POINT_WAITING",
+ CIRCUIT_PURPOSE_REND_POINT_WAITING)
+ ctf_enum_value("OR_REND_ESTABLISHED", CIRCUIT_PURPOSE_REND_ESTABLISHED)
+
+ /* Client Side. */
+ ctf_enum_value("C_GENERAL", CIRCUIT_PURPOSE_C_GENERAL)
+ ctf_enum_value("C_INTRODUCING", CIRCUIT_PURPOSE_C_INTRODUCING)
+ ctf_enum_value("C_INTRODUCE_ACK_WAIT",
+ CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
+ ctf_enum_value("C_INTRODUCE_ACKED", CIRCUIT_PURPOSE_C_INTRODUCE_ACKED)
+ ctf_enum_value("C_ESTABLISH_REND", CIRCUIT_PURPOSE_C_ESTABLISH_REND)
+ ctf_enum_value("C_REND_READY", CIRCUIT_PURPOSE_C_REND_READY)
+ ctf_enum_value("C_REND_READY_INTRO_ACKED",
+ CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
+ ctf_enum_value("C_REND_JOINED", CIRCUIT_PURPOSE_C_REND_JOINED)
+ ctf_enum_value("C_HSDIR_GET", CIRCUIT_PURPOSE_C_HSDIR_GET)
+
+ /* CBT and Padding. */
+ ctf_enum_value("C_MEASURE_TIMEOUT", CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
+ ctf_enum_value("C_CIRCUIT_PADDING", CIRCUIT_PURPOSE_C_CIRCUIT_PADDING)
+
+ /* Service Side. */
+ ctf_enum_value("S_ESTABLISH_INTRO", CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)
+ ctf_enum_value("S_INTRO", CIRCUIT_PURPOSE_S_INTRO)
+ ctf_enum_value("S_CONNECT_REND", CIRCUIT_PURPOSE_S_CONNECT_REND)
+ ctf_enum_value("S_REND_JOINED", CIRCUIT_PURPOSE_S_REND_JOINED)
+ ctf_enum_value("S_HSDIR_POST", CIRCUIT_PURPOSE_S_HSDIR_POST)
+
+ /* Misc. */
+ ctf_enum_value("TESTING", CIRCUIT_PURPOSE_TESTING)
+ ctf_enum_value("CONTROLER", CIRCUIT_PURPOSE_CONTROLLER)
+ ctf_enum_value("PATH_BIAS_TESTING", CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
+
+ /* VanGuard */
+ ctf_enum_value("HS_VANGUARDS", CIRCUIT_PURPOSE_HS_VANGUARDS)
+ )
+)
+
+/*
+ * Circuit End Reasons
+ *
+ * The following defines an enumeration of all possible circuit end reasons so
+ * they appear in the trace with the define name (first parameter of
+ * ctf_enum_value) instead of the numerical value.
+ */
+TRACEPOINT_ENUM(tor_circuit, end_reason,
+ TP_ENUM_VALUES(
+ /* Local reasons. */
+ ctf_enum_value("IP_NOW_REDUNDANT", END_CIRC_REASON_IP_NOW_REDUNDANT)
+ ctf_enum_value("MEASUREMENT_EXPIRED", END_CIRC_REASON_MEASUREMENT_EXPIRED)
+ ctf_enum_value("REASON_NOPATH", END_CIRC_REASON_NOPATH)
+ ctf_enum_value("AT_ORIGIN", END_CIRC_AT_ORIGIN)
+ ctf_enum_value("NONE", END_CIRC_REASON_NONE)
+ ctf_enum_value("TORPROTOCOL", END_CIRC_REASON_TORPROTOCOL)
+ ctf_enum_value("INTERNAL", END_CIRC_REASON_INTERNAL)
+ ctf_enum_value("REQUESTED", END_CIRC_REASON_REQUESTED)
+ ctf_enum_value("HIBERNATING", END_CIRC_REASON_HIBERNATING)
+ ctf_enum_value("RESOURCELIMIT", END_CIRC_REASON_RESOURCELIMIT)
+ ctf_enum_value("CONNECTFAILED", END_CIRC_REASON_CONNECTFAILED)
+ ctf_enum_value("OR_IDENTITY", END_CIRC_REASON_OR_IDENTITY)
+ ctf_enum_value("CHANNEL_CLOSED", END_CIRC_REASON_CHANNEL_CLOSED)
+ ctf_enum_value("FINISHED", END_CIRC_REASON_FINISHED)
+ ctf_enum_value("TIMEOUT", END_CIRC_REASON_TIMEOUT)
+ ctf_enum_value("DESTROYED", END_CIRC_REASON_DESTROYED)
+ ctf_enum_value("NOSUCHSERVICE", END_CIRC_REASON_NOSUCHSERVICE)
+
+ /* Remote reasons. */
+ ctf_enum_value("FLAG_REMOTE", END_CIRC_REASON_FLAG_REMOTE)
+ ctf_enum_value("REMOTE_TORPROTOCOL",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_TORPROTOCOL)
+ ctf_enum_value("REMOTE_INTERNAL",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_INTERNAL)
+ ctf_enum_value("REMOTE_REQUESTED",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_REQUESTED)
+ ctf_enum_value("REMOTE_HIBERNATING",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_HIBERNATING)
+ ctf_enum_value("REMOTE_RESOURCELIMIT",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_RESOURCELIMIT)
+ ctf_enum_value("REMOTE_CONNECTFAILED",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_CONNECTFAILED)
+ ctf_enum_value("REMOTE_OR_IDENTITY",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_OR_IDENTITY)
+ ctf_enum_value("REMOTE_CHANNEL_CLOSED",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_CHANNEL_CLOSED)
+ ctf_enum_value("REMOTE_FINISHED",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_FINISHED)
+ ctf_enum_value("REMOTE_TIMEOUT",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_TIMEOUT)
+ ctf_enum_value("REMOTE_DESTROYED",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_DESTROYED)
+ ctf_enum_value("REMOTE_NOSUCHSERVICE",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_NOSUCHSERVICE)
+ )
+)
+
+/*
+ * Circuit State
+ *
+ * The following defines an enumeration of all possible circuit state so they
+ * appear in the trace with the define name (first parameter of
+ * ctf_enum_value) instead of the numerical value.
+ */
+TRACEPOINT_ENUM(tor_circuit, state,
+ TP_ENUM_VALUES(
+ ctf_enum_value("BUILDING", CIRCUIT_STATE_BUILDING)
+ ctf_enum_value("ONIONSKIN_PENDING", CIRCUIT_STATE_ONIONSKIN_PENDING)
+ ctf_enum_value("CHAN_WAIT", CIRCUIT_STATE_CHAN_WAIT)
+ ctf_enum_value("GUARD_WAIT", CIRCUIT_STATE_GUARD_WAIT)
+ ctf_enum_value("OPEN", CIRCUIT_STATE_OPEN)
+ )
+)
+
+/*
+ * Event Class
+ *
+ * A tracepoint class is a class of tracepoints which share the same output
+ * event field definitions. They are then used by the
+ * TRACEPOINT_EVENT_INSTANCE() macro as a base field definition.
+ */
+
+/* Class for origin circuit. */
+TRACEPOINT_EVENT_CLASS(tor_circuit, origin_circuit_t_class,
+ TP_ARGS(const origin_circuit_t *, circ),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id, circ->global_identifier)
+ ctf_enum(tor_circuit, purpose, int, purpose, TO_CIRCUIT(circ)->purpose)
+ ctf_enum(tor_circuit, state, int, state, TO_CIRCUIT(circ)->state)
+ )
+)
+
+/* Class for or circuit. */
+TRACEPOINT_EVENT_CLASS(tor_circuit, or_circuit_t_class,
+ TP_ARGS(const or_circuit_t *, circ),
+ TP_FIELDS(
+ ctf_enum(tor_circuit, purpose, int, purpose, TO_CIRCUIT(circ)->purpose)
+ ctf_enum(tor_circuit, state, int, state, TO_CIRCUIT(circ)->state)
+ )
+)
+
+/*
+ * Origin circuit events.
+ *
+ * Tracepoint use the origin_circuit_t object.
+ */
+
+/* Tracepoint emitted when a new origin circuit has been created. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, origin_circuit_t_class, new_origin,
+ TP_ARGS(const origin_circuit_t *, circ)
+)
+
+/* Tracepoint emitted when an origin circuit has opened. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, origin_circuit_t_class, opened,
+ TP_ARGS(const origin_circuit_t *, circ)
+)
+
+/* Tracepoint emitted when an origin circuit has established. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, origin_circuit_t_class, establish,
+ TP_ARGS(const origin_circuit_t *, circ)
+)
+
+/* Tracepoint emitted when an origin circuit has been cannibalized. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, origin_circuit_t_class, cannibalized,
+ TP_ARGS(const origin_circuit_t *, circ)
+)
+
+/* Tracepoint emitted when an origin circuit has timed out. This is called
+ * when circuit_expire_building() as selected the circuit and is about to
+ * close it for timeout. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, origin_circuit_t_class, timeout,
+ TP_ARGS(const origin_circuit_t *, circ)
+)
+
+/* Tracepoint emitted when an origin circuit has timed out due to idleness.
+ * This is when the circuit is closed after MaxCircuitDirtiness. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, origin_circuit_t_class, idle_timeout,
+ TP_ARGS(const origin_circuit_t *, circ)
+)
+
+/* Tracepoint emitted when an origin circuit sends out its first onion skin. */
+TRACEPOINT_EVENT(tor_circuit, first_onion_skin,
+ TP_ARGS(const origin_circuit_t *, circ, const crypt_path_t *, hop),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id, circ->global_identifier)
+ ctf_enum(tor_circuit, purpose, int, purpose, TO_CIRCUIT(circ)->purpose)
+ ctf_enum(tor_circuit, state, int, state, TO_CIRCUIT(circ)->state)
+ ctf_array_hex(char, fingerprint, hop->extend_info->identity_digest,
+ DIGEST_LEN)
+ )
+)
+
+/* Tracepoint emitted when an origin circuit sends out an intermediate onion
+ * skin. */
+TRACEPOINT_EVENT(tor_circuit, intermediate_onion_skin,
+ TP_ARGS(const origin_circuit_t *, circ, const crypt_path_t *, hop),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id, circ->global_identifier)
+ ctf_enum(tor_circuit, purpose, int, purpose, TO_CIRCUIT(circ)->purpose)
+ ctf_enum(tor_circuit, state, int, state, TO_CIRCUIT(circ)->state)
+ ctf_array_hex(char, fingerprint, hop->extend_info->identity_digest,
+ DIGEST_LEN)
+ )
+)
+
+/*
+ * OR circuit events.
+ *
+ * Tracepoint use the or_circuit_t object.
+ */
+
+/* Tracepoint emitted when a new or circuit has been created. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, or_circuit_t_class, new_or,
+ TP_ARGS(const or_circuit_t *, circ)
+)
+
+/*
+ * General circuit events.
+ *
+ * Tracepoint use the circuit_t object.
+ */
+
+/* Tracepoint emitted when a circuit is freed. */
+TRACEPOINT_EVENT(tor_circuit, free,
+ TP_ARGS(const circuit_t *, circ),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id,
+ (CIRCUIT_IS_ORIGIN(circ) ?
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0))
+ ctf_enum(tor_circuit, purpose, int, purpose, circ->purpose)
+ ctf_enum(tor_circuit, state, int, state, circ->state)
+ )
+)
+
+/* Tracepoint emitted when a circuit is marked for close. */
+TRACEPOINT_EVENT(tor_circuit, mark_for_close,
+ TP_ARGS(const circuit_t *, circ),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id,
+ (CIRCUIT_IS_ORIGIN(circ) ?
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0))
+ ctf_enum(tor_circuit, purpose, int, purpose, circ->purpose)
+ ctf_enum(tor_circuit, state, int, state, circ->state)
+ ctf_enum(tor_circuit, end_reason, int, close_reason,
+ circ->marked_for_close_reason)
+ ctf_enum(tor_circuit, end_reason, int, orig_close_reason,
+ circ->marked_for_close_orig_reason)
+ )
+)
+
+/* Tracepoint emitted when a circuit changes purpose. */
+TRACEPOINT_EVENT(tor_circuit, change_purpose,
+ TP_ARGS(const circuit_t *, circ, int, old_purpose, int, new_purpose),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id,
+ (CIRCUIT_IS_ORIGIN(circ) ?
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0))
+ ctf_enum(tor_circuit, state, int, state, circ->state)
+ ctf_enum(tor_circuit, purpose, int, purpose, old_purpose)
+ ctf_enum(tor_circuit, purpose, int, new, new_purpose)
+ )
+)
+
+/* Tracepoint emitted when a circuit changes state. */
+TRACEPOINT_EVENT(tor_circuit, change_state,
+ TP_ARGS(const circuit_t *, circ, int, old_state, int, new_state),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id,
+ (CIRCUIT_IS_ORIGIN(circ) ?
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0))
+ ctf_enum(tor_circuit, purpose, int, purpose, circ->purpose)
+ ctf_enum(tor_circuit, state, int, old, old_state)
+ ctf_enum(tor_circuit, state, int, new, new_state)
+ )
+)
+
+#endif /* LTTNG_CIRCUIT_INC || TRACEPOINT_HEADER_MULTI_READ */
+
+/* Must be included after the probes declaration. */
+#include <lttng/tracepoint-event.h>
+
+#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */
diff --git a/src/core/or/onion.h b/src/core/or/onion.h
index 256f0a3f31..600e67c3cd 100644
--- a/src/core/or/onion.h
+++ b/src/core/or/onion.h
@@ -48,8 +48,7 @@ typedef struct extend_cell_t {
uint8_t cell_type;
/** An IPv4 address and port for the node we're connecting to. */
tor_addr_port_t orport_ipv4;
- /** An IPv6 address and port for the node we're connecting to. Not currently
- * used. */
+ /** An IPv6 address and port for the node we're connecting to. */
tor_addr_port_t orport_ipv6;
/** Identity fingerprint of the node we're conecting to.*/
uint8_t node_id[DIGEST_LEN];
diff --git a/src/core/or/or.h b/src/core/or/or.h
index 8758a2ec6f..d80c41371e 100644
--- a/src/core/or/or.h
+++ b/src/core/or/or.h
@@ -816,6 +816,18 @@ typedef struct protover_summary_flags_t {
* accept EXTEND2 cells. This requires Relay=2. */
unsigned int supports_extend2_cells:1;
+ /** True iff this router has a version or protocol list that allows it to
+ * accept IPv6 connections. This requires Relay=2 or Relay=3. */
+ unsigned int supports_accepting_ipv6_extends:1;
+
+ /** True iff this router has a version or protocol list that allows it to
+ * initiate IPv6 connections. This requires Relay=3. */
+ unsigned int supports_initiating_ipv6_extends:1;
+
+ /** True iff this router has a version or protocol list that allows it to
+ * consider IPv6 connections canonical. This requires Relay=3. */
+ unsigned int supports_canonical_ipv6_conns:1;
+
/** True iff this router has a protocol list that allows it to negotiate
* ed25519 identity keys on a link handshake with us. This
* requires LinkAuth=3. */
@@ -831,6 +843,10 @@ typedef struct protover_summary_flags_t {
* the v3 protocol detailed in proposal 224. This requires HSIntro=4. */
unsigned int supports_ed25519_hs_intro : 1;
+ /** True iff this router has a protocol list that allows it to support the
+ * ESTABLISH_INTRO DoS cell extension. Requires HSIntro=5. */
+ unsigned int supports_establish_intro_dos_extension : 1;
+
/** True iff this router has a protocol list that allows it to be an hidden
* service directory supporting version 3 as seen in proposal 224. This
* requires HSDir=2. */
@@ -842,12 +858,9 @@ typedef struct protover_summary_flags_t {
unsigned int supports_v3_rendezvous_point: 1;
/** True iff this router has a protocol list that allows clients to
- * negotiate hs circuit setup padding. Requires Padding>=2. */
+ * negotiate hs circuit setup padding. Requires Padding=2. */
unsigned int supports_hs_setup_padding : 1;
- /** True iff this router has a protocol list that allows it to support the
- * ESTABLISH_INTRO DoS cell extension. Requires HSIntro>=5. */
- unsigned int supports_establish_intro_dos_extension : 1;
} protover_summary_flags_t;
typedef struct routerinfo_t routerinfo_t;
diff --git a/src/core/or/or_connection_st.h b/src/core/or/or_connection_st.h
index 92956c2847..8e012a6b85 100644
--- a/src/core/or/or_connection_st.h
+++ b/src/core/or/or_connection_st.h
@@ -49,10 +49,19 @@ struct or_connection_t {
/* Channel using this connection */
channel_tls_t *chan;
- tor_addr_t real_addr; /**< The actual address that this connection came from
- * or went to. The <b>addr</b> field is prone to
- * getting overridden by the address from the router
- * descriptor matching <b>identity_digest</b>. */
+ /**
+ * The "canonical" address and port for this relay's ORPort, if this is
+ * a known relay.
+ *
+ * An ORPort is "canonical" in this sense only if it is the same ORPort
+ * that is listed for this identity in the consensus we have.
+ *
+ * This field may be set on outbound connections for _any_ relay, and on
+ * inbound connections after authentication. If we don't know the relay's
+ * identity, or if we don't have the relay's identity in our consensus, we
+ * leave this address as UNSPEC.
+ **/
+ tor_addr_port_t canonical_orport;
/** Should this connection be used for extending circuits to the server
* matching the <b>identity_digest</b> field? Set to true if we're pretty
diff --git a/src/core/or/policies.c b/src/core/or/policies.c
index 2bf2dc7005..0dc440cc96 100644
--- a/src/core/or/policies.c
+++ b/src/core/or/policies.c
@@ -311,7 +311,7 @@ parse_reachable_addresses(void)
"ReachableAddresses, ReachableORAddresses, or "
"ReachableDirAddresses reject all IPv4 addresses. "
"Tor will not connect using IPv4.");
- } else if (fascist_firewall_use_ipv6(options)
+ } else if (reachable_addr_use_ipv6(options)
&& (policy_is_reject_star(reachable_or_addr_policy, AF_INET6, 0)
|| policy_is_reject_star(reachable_dir_addr_policy, AF_INET6, 0))) {
log_warn(LD_CONFIG, "You have configured tor to use or prefer IPv6 "
@@ -389,19 +389,6 @@ addr_policy_permits_tor_addr(const tor_addr_t *addr, uint16_t port,
}
}
-/** Return true iff <b> policy</b> (possibly NULL) will allow a connection to
- * <b>addr</b>:<b>port</b>. <b>addr</b> is an IPv4 address given in host
- * order. */
-/* XXXX deprecate when possible. */
-static int
-addr_policy_permits_address(uint32_t addr, uint16_t port,
- smartlist_t *policy)
-{
- tor_addr_t a;
- tor_addr_from_ipv4h(&a, addr);
- return addr_policy_permits_tor_addr(&a, port, policy);
-}
-
/** Return true iff we think our firewall will let us make a connection to
* addr:port.
*
@@ -412,12 +399,12 @@ addr_policy_permits_address(uint32_t addr, uint16_t port,
* - if ClientUseIPv4 is 0, or
* if pref_only and pref_ipv6 are both true;
* - return false for all IPv6 addresses:
- * - if fascist_firewall_use_ipv6() is 0, or
+ * - if reachable_addr_use_ipv6() is 0, or
* - if pref_only is true and pref_ipv6 is false.
*
* Return false if addr is NULL or tor_addr_is_null(), or if port is 0. */
STATIC int
-fascist_firewall_allows_address(const tor_addr_t *addr,
+reachable_addr_allows(const tor_addr_t *addr,
uint16_t port,
smartlist_t *firewall_policy,
int pref_only, int pref_ipv6)
@@ -440,7 +427,7 @@ fascist_firewall_allows_address(const tor_addr_t *addr,
/* Clients and Servers won't use IPv6 unless it's enabled (and in most
* cases, IPv6 must also be preferred before it will be used). */
if (tor_addr_family(addr) == AF_INET6 &&
- (!fascist_firewall_use_ipv6(options) || (pref_only && !pref_ipv6))) {
+ (!reachable_addr_use_ipv6(options) || (pref_only && !pref_ipv6))) {
return 0;
}
@@ -456,7 +443,7 @@ fascist_firewall_allows_address(const tor_addr_t *addr,
* port: it supports bridge client per-node IPv6 preferences.
*/
int
-fascist_firewall_use_ipv6(const or_options_t *options)
+reachable_addr_use_ipv6(const or_options_t *options)
{
/* Clients use IPv6 if it's set, or they use bridges, or they don't use
* IPv4, or they prefer it.
@@ -471,7 +458,7 @@ fascist_firewall_use_ipv6(const or_options_t *options)
* If we're unsure, return -1, otherwise, return 1 for IPv6 and 0 for IPv4.
*/
static int
-fascist_firewall_prefer_ipv6_impl(const or_options_t *options)
+reachable_addr_prefer_ipv6_impl(const or_options_t *options)
{
/*
Cheap implementation of config options ClientUseIPv4 & ClientUseIPv6 --
@@ -479,7 +466,7 @@ fascist_firewall_prefer_ipv6_impl(const or_options_t *options)
If IPv4 is disabled, use IPv6.
*/
- if (server_mode(options) || !fascist_firewall_use_ipv6(options)) {
+ if (server_mode(options) || !reachable_addr_use_ipv6(options)) {
return 0;
}
@@ -495,9 +482,9 @@ fascist_firewall_prefer_ipv6_impl(const or_options_t *options)
* per-node IPv6 preferences.
*/
int
-fascist_firewall_prefer_ipv6_orport(const or_options_t *options)
+reachable_addr_prefer_ipv6_orport(const or_options_t *options)
{
- int pref_ipv6 = fascist_firewall_prefer_ipv6_impl(options);
+ int pref_ipv6 = reachable_addr_prefer_ipv6_impl(options);
if (pref_ipv6 >= 0) {
return pref_ipv6;
@@ -517,9 +504,9 @@ fascist_firewall_prefer_ipv6_orport(const or_options_t *options)
* preferences. There's no reason to use it instead of this function.)
*/
int
-fascist_firewall_prefer_ipv6_dirport(const or_options_t *options)
+reachable_addr_prefer_ipv6_dirport(const or_options_t *options)
{
- int pref_ipv6 = fascist_firewall_prefer_ipv6_impl(options);
+ int pref_ipv6 = reachable_addr_prefer_ipv6_impl(options);
if (pref_ipv6 >= 0) {
return pref_ipv6;
@@ -541,16 +528,16 @@ fascist_firewall_prefer_ipv6_dirport(const or_options_t *options)
* If pref_only is false, ignore pref_ipv6, and return true if addr is allowed.
*/
int
-fascist_firewall_allows_address_addr(const tor_addr_t *addr, uint16_t port,
+reachable_addr_allows_addr(const tor_addr_t *addr, uint16_t port,
firewall_connection_t fw_connection,
int pref_only, int pref_ipv6)
{
if (fw_connection == FIREWALL_OR_CONNECTION) {
- return fascist_firewall_allows_address(addr, port,
+ return reachable_addr_allows(addr, port,
reachable_or_addr_policy,
pref_only, pref_ipv6);
} else if (fw_connection == FIREWALL_DIR_CONNECTION) {
- return fascist_firewall_allows_address(addr, port,
+ return reachable_addr_allows(addr, port,
reachable_dir_addr_policy,
pref_only, pref_ipv6);
} else {
@@ -563,34 +550,15 @@ fascist_firewall_allows_address_addr(const tor_addr_t *addr, uint16_t port,
/** Return true iff we think our firewall will let us make a connection to
* addr:port (ap). Uses ReachableORAddresses or ReachableDirAddresses based on
* fw_connection.
- * pref_only and pref_ipv6 work as in fascist_firewall_allows_address_addr().
+ * pref_only and pref_ipv6 work as in reachable_addr_allows_addr().
*/
static int
-fascist_firewall_allows_address_ap(const tor_addr_port_t *ap,
+reachable_addr_allows_ap(const tor_addr_port_t *ap,
firewall_connection_t fw_connection,
int pref_only, int pref_ipv6)
{
tor_assert(ap);
- return fascist_firewall_allows_address_addr(&ap->addr, ap->port,
- fw_connection, pref_only,
- pref_ipv6);
-}
-
-/* Return true iff we think our firewall will let us make a connection to
- * ipv4h_or_addr:ipv4_or_port. ipv4h_or_addr is interpreted in host order.
- * Uses ReachableORAddresses or ReachableDirAddresses based on
- * fw_connection.
- * pref_only and pref_ipv6 work as in fascist_firewall_allows_address_addr().
- */
-static int
-fascist_firewall_allows_address_ipv4h(uint32_t ipv4h_or_addr,
- uint16_t ipv4_or_port,
- firewall_connection_t fw_connection,
- int pref_only, int pref_ipv6)
-{
- tor_addr_t ipv4_or_addr;
- tor_addr_from_ipv4h(&ipv4_or_addr, ipv4h_or_addr);
- return fascist_firewall_allows_address_addr(&ipv4_or_addr, ipv4_or_port,
+ return reachable_addr_allows_addr(&ap->addr, ap->port,
fw_connection, pref_only,
pref_ipv6);
}
@@ -599,17 +567,17 @@ fascist_firewall_allows_address_ipv4h(uint32_t ipv4h_or_addr,
* ipv4h_addr/ipv6_addr. Uses ipv4_orport/ipv6_orport/ReachableORAddresses or
* ipv4_dirport/ipv6_dirport/ReachableDirAddresses based on IPv4/IPv6 and
* <b>fw_connection</b>.
- * pref_only and pref_ipv6 work as in fascist_firewall_allows_address_addr().
+ * pref_only and pref_ipv6 work as in reachable_addr_allows_addr().
*/
static int
-fascist_firewall_allows_base(uint32_t ipv4h_addr, uint16_t ipv4_orport,
+reachable_addr_allows_base(const tor_addr_t *ipv4_addr, uint16_t ipv4_orport,
uint16_t ipv4_dirport,
const tor_addr_t *ipv6_addr, uint16_t ipv6_orport,
uint16_t ipv6_dirport,
firewall_connection_t fw_connection,
int pref_only, int pref_ipv6)
{
- if (fascist_firewall_allows_address_ipv4h(ipv4h_addr,
+ if (reachable_addr_allows_addr(ipv4_addr,
(fw_connection == FIREWALL_OR_CONNECTION
? ipv4_orport
: ipv4_dirport),
@@ -618,7 +586,7 @@ fascist_firewall_allows_base(uint32_t ipv4h_addr, uint16_t ipv4_orport,
return 1;
}
- if (fascist_firewall_allows_address_addr(ipv6_addr,
+ if (reachable_addr_allows_addr(ipv6_addr,
(fw_connection == FIREWALL_OR_CONNECTION
? ipv6_orport
: ipv6_dirport),
@@ -630,9 +598,9 @@ fascist_firewall_allows_base(uint32_t ipv4h_addr, uint16_t ipv4_orport,
return 0;
}
-/** Like fascist_firewall_allows_base(), but takes ri. */
+/** Like reachable_addr_allows_base(), but takes ri. */
static int
-fascist_firewall_allows_ri_impl(const routerinfo_t *ri,
+reachable_addr_allows_ri_impl(const routerinfo_t *ri,
firewall_connection_t fw_connection,
int pref_only, int pref_ipv6)
{
@@ -641,15 +609,15 @@ fascist_firewall_allows_ri_impl(const routerinfo_t *ri,
}
/* Assume IPv4 and IPv6 DirPorts are the same */
- return fascist_firewall_allows_base(ri->addr, ri->or_port, ri->dir_port,
- &ri->ipv6_addr, ri->ipv6_orport,
- ri->dir_port, fw_connection, pref_only,
- pref_ipv6);
+ return reachable_addr_allows_base(&ri->ipv4_addr, ri->ipv4_orport,
+ ri->ipv4_dirport, &ri->ipv6_addr,
+ ri->ipv6_orport, ri->ipv4_dirport,
+ fw_connection, pref_only, pref_ipv6);
}
-/** Like fascist_firewall_allows_rs, but takes pref_ipv6. */
+/** Like reachable_addr_allows_rs, but takes pref_ipv6. */
static int
-fascist_firewall_allows_rs_impl(const routerstatus_t *rs,
+reachable_addr_allows_rs_impl(const routerstatus_t *rs,
firewall_connection_t fw_connection,
int pref_only, int pref_ipv6)
{
@@ -658,20 +626,20 @@ fascist_firewall_allows_rs_impl(const routerstatus_t *rs,
}
/* Assume IPv4 and IPv6 DirPorts are the same */
- return fascist_firewall_allows_base(rs->addr, rs->or_port, rs->dir_port,
- &rs->ipv6_addr, rs->ipv6_orport,
- rs->dir_port, fw_connection, pref_only,
- pref_ipv6);
+ return reachable_addr_allows_base(&rs->ipv4_addr, rs->ipv4_orport,
+ rs->ipv4_dirport, &rs->ipv6_addr,
+ rs->ipv6_orport, rs->ipv4_dirport,
+ fw_connection, pref_only, pref_ipv6);
}
-/** Like fascist_firewall_allows_base(), but takes rs.
+/** Like reachable_addr_allows_base(), but takes rs.
* When rs is a fake_status from a dir_server_t, it can have a reachable
* address, even when the corresponding node does not.
* nodes can be missing addresses when there's no consensus (IPv4 and IPv6),
* or when there is a microdescriptor consensus, but no microdescriptors
* (microdescriptors have IPv6, the microdesc consensus does not). */
int
-fascist_firewall_allows_rs(const routerstatus_t *rs,
+reachable_addr_allows_rs(const routerstatus_t *rs,
firewall_connection_t fw_connection, int pref_only)
{
if (!rs) {
@@ -682,20 +650,20 @@ fascist_firewall_allows_rs(const routerstatus_t *rs,
* generic IPv6 preference instead. */
const or_options_t *options = get_options();
int pref_ipv6 = (fw_connection == FIREWALL_OR_CONNECTION
- ? fascist_firewall_prefer_ipv6_orport(options)
- : fascist_firewall_prefer_ipv6_dirport(options));
+ ? reachable_addr_prefer_ipv6_orport(options)
+ : reachable_addr_prefer_ipv6_dirport(options));
- return fascist_firewall_allows_rs_impl(rs, fw_connection, pref_only,
+ return reachable_addr_allows_rs_impl(rs, fw_connection, pref_only,
pref_ipv6);
}
/** Return true iff we think our firewall will let us make a connection to
* ipv6_addr:ipv6_orport based on ReachableORAddresses.
* If <b>fw_connection</b> is FIREWALL_DIR_CONNECTION, returns 0.
- * pref_only and pref_ipv6 work as in fascist_firewall_allows_address_addr().
+ * pref_only and pref_ipv6 work as in reachable_addr_allows_addr().
*/
static int
-fascist_firewall_allows_md_impl(const microdesc_t *md,
+reachable_addr_allows_md_impl(const microdesc_t *md,
firewall_connection_t fw_connection,
int pref_only, int pref_ipv6)
{
@@ -709,15 +677,15 @@ fascist_firewall_allows_md_impl(const microdesc_t *md,
}
/* Also can't check IPv4, doesn't have that either */
- return fascist_firewall_allows_address_addr(&md->ipv6_addr, md->ipv6_orport,
+ return reachable_addr_allows_addr(&md->ipv6_addr, md->ipv6_orport,
fw_connection, pref_only,
pref_ipv6);
}
-/** Like fascist_firewall_allows_base(), but takes node, and looks up pref_ipv6
+/** Like reachable_addr_allows_base(), but takes node, and looks up pref_ipv6
* from node_ipv6_or/dir_preferred(). */
int
-fascist_firewall_allows_node(const node_t *node,
+reachable_addr_allows_node(const node_t *node,
firewall_connection_t fw_connection,
int pref_only)
{
@@ -733,15 +701,15 @@ fascist_firewall_allows_node(const node_t *node,
/* Sometimes, the rs is missing the IPv6 address info, and we need to go
* all the way to the md */
- if (node->ri && fascist_firewall_allows_ri_impl(node->ri, fw_connection,
+ if (node->ri && reachable_addr_allows_ri_impl(node->ri, fw_connection,
pref_only, pref_ipv6)) {
return 1;
- } else if (node->rs && fascist_firewall_allows_rs_impl(node->rs,
+ } else if (node->rs && reachable_addr_allows_rs_impl(node->rs,
fw_connection,
pref_only,
pref_ipv6)) {
return 1;
- } else if (node->md && fascist_firewall_allows_md_impl(node->md,
+ } else if (node->md && reachable_addr_allows_md_impl(node->md,
fw_connection,
pref_only,
pref_ipv6)) {
@@ -753,9 +721,9 @@ fascist_firewall_allows_node(const node_t *node,
}
}
-/** Like fascist_firewall_allows_rs(), but takes ds. */
+/** Like reachable_addr_allows_rs(), but takes ds. */
int
-fascist_firewall_allows_dir_server(const dir_server_t *ds,
+reachable_addr_allows_dir_server(const dir_server_t *ds,
firewall_connection_t fw_connection,
int pref_only)
{
@@ -766,8 +734,8 @@ fascist_firewall_allows_dir_server(const dir_server_t *ds,
/* A dir_server_t always has a fake_status. As long as it has the same
* addresses/ports in both fake_status and dir_server_t, this works fine.
* (See #17867.)
- * fascist_firewall_allows_rs only checks the addresses in fake_status. */
- return fascist_firewall_allows_rs(&ds->fake_status, fw_connection,
+ * reachable_addr_allows_rs only checks the addresses in fake_status. */
+ return reachable_addr_allows_rs(&ds->fake_status, fw_connection,
pref_only);
}
@@ -775,10 +743,10 @@ fascist_firewall_allows_dir_server(const dir_server_t *ds,
* choose one based on want_a and return it.
* Otherwise, return whichever is allowed.
* Otherwise, return NULL.
- * pref_only and pref_ipv6 work as in fascist_firewall_allows_address_addr().
+ * pref_only and pref_ipv6 work as in reachable_addr_allows_addr().
*/
static const tor_addr_port_t *
-fascist_firewall_choose_address_impl(const tor_addr_port_t *a,
+reachable_addr_choose_impl(const tor_addr_port_t *a,
const tor_addr_port_t *b,
int want_a,
firewall_connection_t fw_connection,
@@ -787,12 +755,12 @@ fascist_firewall_choose_address_impl(const tor_addr_port_t *a,
const tor_addr_port_t *use_a = NULL;
const tor_addr_port_t *use_b = NULL;
- if (fascist_firewall_allows_address_ap(a, fw_connection, pref_only,
+ if (reachable_addr_allows_ap(a, fw_connection, pref_only,
pref_ipv6)) {
use_a = a;
}
- if (fascist_firewall_allows_address_ap(b, fw_connection, pref_only,
+ if (reachable_addr_allows_ap(b, fw_connection, pref_only,
pref_ipv6)) {
use_b = b;
}
@@ -816,13 +784,13 @@ fascist_firewall_choose_address_impl(const tor_addr_port_t *a,
* - Otherwise, return whichever is preferred.
* Otherwise, return NULL. */
STATIC const tor_addr_port_t *
-fascist_firewall_choose_address(const tor_addr_port_t *a,
+reachable_addr_choose(const tor_addr_port_t *a,
const tor_addr_port_t *b,
int want_a,
firewall_connection_t fw_connection,
int pref_only, int pref_ipv6)
{
- const tor_addr_port_t *pref = fascist_firewall_choose_address_impl(
+ const tor_addr_port_t *pref = reachable_addr_choose_impl(
a, b, want_a,
fw_connection,
1, pref_ipv6);
@@ -834,7 +802,7 @@ fascist_firewall_choose_address(const tor_addr_port_t *a,
} else {
/* If there's no preferred address, and we can return addresses that are
* not preferred, use an address that's allowed */
- return fascist_firewall_choose_address_impl(a, b, want_a, fw_connection,
+ return reachable_addr_choose_impl(a, b, want_a, fw_connection,
0, pref_ipv6);
}
}
@@ -849,7 +817,7 @@ fascist_firewall_choose_address(const tor_addr_port_t *a,
* If both addresses could be chosen (they are both preferred or both allowed)
* choose IPv6 if pref_ipv6 is true, otherwise choose IPv4. */
static void
-fascist_firewall_choose_address_base(const tor_addr_t *ipv4_addr,
+reachable_addr_choose_base(const tor_addr_t *ipv4_addr,
uint16_t ipv4_orport,
uint16_t ipv4_dirport,
const tor_addr_t *ipv6_addr,
@@ -881,7 +849,7 @@ fascist_firewall_choose_address_base(const tor_addr_t *ipv4_addr,
? ipv6_orport
: ipv6_dirport);
- result = fascist_firewall_choose_address(&ipv4_ap, &ipv6_ap,
+ result = reachable_addr_choose(&ipv4_ap, &ipv6_ap,
want_ipv4,
fw_connection, pref_only,
pref_ipv6);
@@ -892,41 +860,13 @@ fascist_firewall_choose_address_base(const tor_addr_t *ipv4_addr,
}
}
-/** Like fascist_firewall_choose_address_base(), but takes a host-order IPv4
- * address as the first parameter. */
-static void
-fascist_firewall_choose_address_ipv4h(uint32_t ipv4h_addr,
- uint16_t ipv4_orport,
- uint16_t ipv4_dirport,
- const tor_addr_t *ipv6_addr,
- uint16_t ipv6_orport,
- uint16_t ipv6_dirport,
- firewall_connection_t fw_connection,
- int pref_only,
- int pref_ipv6,
- tor_addr_port_t* ap)
-{
- tor_addr_t ipv4_addr;
- tor_addr_from_ipv4h(&ipv4_addr, ipv4h_addr);
- tor_assert(ap);
-
- tor_addr_make_null(&ap->addr, AF_UNSPEC);
- ap->port = 0;
-
- fascist_firewall_choose_address_base(&ipv4_addr, ipv4_orport,
- ipv4_dirport, ipv6_addr,
- ipv6_orport, ipv6_dirport,
- fw_connection, pref_only,
- pref_ipv6, ap);
-}
-
-/** Like fascist_firewall_choose_address_base(), but takes <b>rs</b>.
+/** Like reachable_addr_choose_base(), but takes <b>rs</b>.
* Consults the corresponding node, then falls back to rs if node is NULL.
* This should only happen when there's no valid consensus, and rs doesn't
* correspond to a bridge client's bridge.
*/
void
-fascist_firewall_choose_address_rs(const routerstatus_t *rs,
+reachable_addr_choose_from_rs(const routerstatus_t *rs,
firewall_connection_t fw_connection,
int pref_only, tor_addr_port_t* ap)
{
@@ -943,30 +883,29 @@ fascist_firewall_choose_address_rs(const routerstatus_t *rs,
const node_t *node = node_get_by_id(rs->identity_digest);
if (node) {
- fascist_firewall_choose_address_node(node, fw_connection, pref_only, ap);
+ reachable_addr_choose_from_node(node, fw_connection, pref_only, ap);
} else {
/* There's no node-specific IPv6 preference, so use the generic IPv6
* preference instead. */
int pref_ipv6 = (fw_connection == FIREWALL_OR_CONNECTION
- ? fascist_firewall_prefer_ipv6_orport(options)
- : fascist_firewall_prefer_ipv6_dirport(options));
+ ? reachable_addr_prefer_ipv6_orport(options)
+ : reachable_addr_prefer_ipv6_dirport(options));
- /* Assume IPv4 and IPv6 DirPorts are the same.
- * Assume the IPv6 OR and Dir addresses are the same. */
- fascist_firewall_choose_address_ipv4h(rs->addr, rs->or_port, rs->dir_port,
- &rs->ipv6_addr, rs->ipv6_orport,
- rs->dir_port, fw_connection,
- pref_only, pref_ipv6, ap);
+ reachable_addr_choose_base(&rs->ipv4_addr, rs->ipv4_orport,
+ rs->ipv4_dirport, &rs->ipv6_addr,
+ rs->ipv6_orport, rs->ipv4_dirport,
+ fw_connection, pref_only, pref_ipv6,
+ ap);
}
}
-/** Like fascist_firewall_choose_address_base(), but takes in a smartlist
+/** Like reachable_addr_choose_base(), but takes in a smartlist
* <b>lspecs</b> consisting of one or more link specifiers. We assume
* fw_connection is FIREWALL_OR_CONNECTION as link specifiers cannot
* contain DirPorts.
*/
void
-fascist_firewall_choose_address_ls(const smartlist_t *lspecs,
+reachable_addr_choose_from_ls(const smartlist_t *lspecs,
int pref_only, tor_addr_port_t* ap)
{
int have_v4 = 0, have_v6 = 0;
@@ -1028,20 +967,20 @@ fascist_firewall_choose_address_ls(const smartlist_t *lspecs,
/* Here, don't check for DirPorts as link specifiers are only used for
* ORPorts. */
const or_options_t *options = get_options();
- int pref_ipv6 = fascist_firewall_prefer_ipv6_orport(options);
+ int pref_ipv6 = reachable_addr_prefer_ipv6_orport(options);
/* Assume that the DirPorts are zero as link specifiers only use ORPorts. */
- fascist_firewall_choose_address_base(&addr_v4, port_v4, 0,
+ reachable_addr_choose_base(&addr_v4, port_v4, 0,
&addr_v6, port_v6, 0,
FIREWALL_OR_CONNECTION,
pref_only, pref_ipv6,
ap);
}
-/** Like fascist_firewall_choose_address_base(), but takes <b>node</b>, and
+/** Like reachable_addr_choose_base(), but takes <b>node</b>, and
* looks up the node's IPv6 preference rather than taking an argument
* for pref_ipv6. */
void
-fascist_firewall_choose_address_node(const node_t *node,
+reachable_addr_choose_from_node(const node_t *node,
firewall_connection_t fw_connection,
int pref_only, tor_addr_port_t *ap)
{
@@ -1071,16 +1010,16 @@ fascist_firewall_choose_address_node(const node_t *node,
node_get_pref_ipv6_dirport(node, &ipv6_dir_ap);
/* Assume the IPv6 OR and Dir addresses are the same. */
- fascist_firewall_choose_address_base(&ipv4_or_ap.addr, ipv4_or_ap.port,
+ reachable_addr_choose_base(&ipv4_or_ap.addr, ipv4_or_ap.port,
ipv4_dir_ap.port, &ipv6_or_ap.addr,
ipv6_or_ap.port, ipv6_dir_ap.port,
fw_connection, pref_only,
pref_ipv6_node, ap);
}
-/** Like fascist_firewall_choose_address_rs(), but takes <b>ds</b>. */
+/** Like reachable_addr_choose_from_rs(), but takes <b>ds</b>. */
void
-fascist_firewall_choose_address_dir_server(const dir_server_t *ds,
+reachable_addr_choose_from_dir_server(const dir_server_t *ds,
firewall_connection_t fw_connection,
int pref_only,
tor_addr_port_t *ap)
@@ -1097,9 +1036,9 @@ fascist_firewall_choose_address_dir_server(const dir_server_t *ds,
/* A dir_server_t always has a fake_status. As long as it has the same
* addresses/ports in both fake_status and dir_server_t, this works fine.
* (See #17867.)
- * This function relies on fascist_firewall_choose_address_rs looking up the
+ * This function relies on reachable_addr_choose_from_rs looking up the
* node if it can, because that will get the latest info for the relay. */
- fascist_firewall_choose_address_rs(&ds->fake_status, fw_connection,
+ reachable_addr_choose_from_rs(&ds->fake_status, fw_connection,
pref_only, ap);
}
@@ -1124,17 +1063,14 @@ socks_policy_permits_address(const tor_addr_t *addr)
/** Return true iff the address <b>addr</b> is in a country listed in the
* case-insensitive list of country codes <b>cc_list</b>. */
static int
-addr_is_in_cc_list(uint32_t addr, const smartlist_t *cc_list)
+addr_is_in_cc_list(const tor_addr_t *addr, const smartlist_t *cc_list)
{
country_t country;
const char *name;
- tor_addr_t tar;
if (!cc_list)
return 0;
- /* XXXXipv6 */
- tor_addr_from_ipv4h(&tar, addr);
- country = geoip_get_country_by_addr(&tar);
+ country = geoip_get_country_by_addr(addr);
name = geoip_get_country_name(country);
return smartlist_contains_string_case(cc_list, name);
}
@@ -1143,9 +1079,9 @@ addr_is_in_cc_list(uint32_t addr, const smartlist_t *cc_list)
* directory, based on <b>authdir_reject_policy</b>. Else return 0.
*/
int
-authdir_policy_permits_address(uint32_t addr, uint16_t port)
+authdir_policy_permits_address(const tor_addr_t *addr, uint16_t port)
{
- if (! addr_policy_permits_address(addr, port, authdir_reject_policy))
+ if (!addr_policy_permits_tor_addr(addr, port, authdir_reject_policy))
return 0;
return !addr_is_in_cc_list(addr, get_options()->AuthDirRejectCCs);
}
@@ -1154,9 +1090,9 @@ authdir_policy_permits_address(uint32_t addr, uint16_t port)
* directory, based on <b>authdir_invalid_policy</b>. Else return 0.
*/
int
-authdir_policy_valid_address(uint32_t addr, uint16_t port)
+authdir_policy_valid_address(const tor_addr_t *addr, uint16_t port)
{
- if (! addr_policy_permits_address(addr, port, authdir_invalid_policy))
+ if (!addr_policy_permits_tor_addr(addr, port, authdir_invalid_policy))
return 0;
return !addr_is_in_cc_list(addr, get_options()->AuthDirInvalidCCs);
}
@@ -1165,9 +1101,9 @@ authdir_policy_valid_address(uint32_t addr, uint16_t port)
* based on <b>authdir_badexit_policy</b>. Else return 0.
*/
int
-authdir_policy_badexit_address(uint32_t addr, uint16_t port)
+authdir_policy_badexit_address(const tor_addr_t *addr, uint16_t port)
{
- if (! addr_policy_permits_address(addr, port, authdir_badexit_policy))
+ if (!addr_policy_permits_tor_addr(addr, port, authdir_badexit_policy))
return 1;
return addr_is_in_cc_list(addr, get_options()->AuthDirBadExitCCs);
}
@@ -2086,22 +2022,6 @@ policies_copy_addr_to_smartlist(smartlist_t *addr_list, const tor_addr_t *addr)
}
}
-/** Helper function that adds ipv4h_addr to a smartlist as a tor_addr_t *,
- * as long as it is not tor_addr_is_null(), by converting it to a tor_addr_t
- * and passing it to policies_add_addr_to_smartlist.
- *
- * The caller is responsible for freeing all the tor_addr_t* in the smartlist.
- */
-static void
-policies_copy_ipv4h_to_smartlist(smartlist_t *addr_list, uint32_t ipv4h_addr)
-{
- if (ipv4h_addr) {
- tor_addr_t ipv4_tor_addr;
- tor_addr_from_ipv4h(&ipv4_tor_addr, ipv4h_addr);
- policies_copy_addr_to_smartlist(addr_list, &ipv4_tor_addr);
- }
-}
-
/** Helper function that adds copies of or_options->OutboundBindAddresses
* to a smartlist as tor_addr_t *, as long as or_options is non-NULL, and
* the addresses are not tor_addr_is_null(), by passing them to
@@ -2133,8 +2053,8 @@ policies_copy_outbound_addresses_to_smartlist(smartlist_t *addr_list,
* If <b>or_options->ExitPolicyRejectPrivate</b> is true:
* - prepend an entry that rejects all destinations in all netblocks reserved
* for private use.
- * - if local_address is non-zero, treat it as a host-order IPv4 address, and
- * add it to the list of configured addresses.
+ * - if ipv4_local_address is non-zero, treat it as a host-order IPv4 address,
+ * and add it to the list of configured addresses.
* - if ipv6_local_address is non-NULL, and not the null tor_addr_t, add it
* to the list of configured addresses.
* If <b>or_options->ExitPolicyRejectLocalInterfaces</b> is true:
@@ -2151,7 +2071,7 @@ policies_copy_outbound_addresses_to_smartlist(smartlist_t *addr_list,
*/
int
policies_parse_exit_policy_from_options(const or_options_t *or_options,
- uint32_t local_address,
+ const tor_addr_t *ipv4_local_address,
const tor_addr_t *ipv6_local_address,
smartlist_t **result)
{
@@ -2192,7 +2112,7 @@ policies_parse_exit_policy_from_options(const or_options_t *or_options,
/* Copy the configured addresses into the tor_addr_t* list */
if (or_options->ExitPolicyRejectPrivate) {
- policies_copy_ipv4h_to_smartlist(configured_addresses, local_address);
+ policies_copy_addr_to_smartlist(configured_addresses, ipv4_local_address);
policies_copy_addr_to_smartlist(configured_addresses, ipv6_local_address);
}
@@ -3062,7 +2982,7 @@ getinfo_helper_policies(control_connection_t *conn,
/* Copy the configured addresses into the tor_addr_t* list */
if (options->ExitPolicyRejectPrivate) {
- policies_copy_ipv4h_to_smartlist(configured_addresses, me->addr);
+ policies_copy_addr_to_smartlist(configured_addresses, &me->ipv4_addr);
policies_copy_addr_to_smartlist(configured_addresses, &me->ipv6_addr);
}
diff --git a/src/core/or/policies.h b/src/core/or/policies.h
index 72a37d62b0..c8502a5516 100644
--- a/src/core/or/policies.h
+++ b/src/core/or/policies.h
@@ -69,42 +69,42 @@ 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);
-int fascist_firewall_prefer_ipv6_orport(const or_options_t *options);
-int fascist_firewall_prefer_ipv6_dirport(const or_options_t *options);
+int reachable_addr_use_ipv6(const or_options_t *options);
+int reachable_addr_prefer_ipv6_orport(const or_options_t *options);
+int reachable_addr_prefer_ipv6_dirport(const or_options_t *options);
-int fascist_firewall_allows_address_addr(const tor_addr_t *addr,
+int reachable_addr_allows_addr(const tor_addr_t *addr,
uint16_t port,
firewall_connection_t fw_connection,
int pref_only, int pref_ipv6);
-int fascist_firewall_allows_rs(const routerstatus_t *rs,
+int reachable_addr_allows_rs(const routerstatus_t *rs,
firewall_connection_t fw_connection,
int pref_only);
-int fascist_firewall_allows_node(const node_t *node,
+int reachable_addr_allows_node(const node_t *node,
firewall_connection_t fw_connection,
int pref_only);
-int fascist_firewall_allows_dir_server(const dir_server_t *ds,
+int reachable_addr_allows_dir_server(const dir_server_t *ds,
firewall_connection_t fw_connection,
int pref_only);
-void fascist_firewall_choose_address_rs(const routerstatus_t *rs,
+void reachable_addr_choose_from_rs(const routerstatus_t *rs,
firewall_connection_t fw_connection,
int pref_only, tor_addr_port_t* ap);
-void fascist_firewall_choose_address_ls(const smartlist_t *lspecs,
+void reachable_addr_choose_from_ls(const smartlist_t *lspecs,
int pref_only, tor_addr_port_t* ap);
-void fascist_firewall_choose_address_node(const node_t *node,
+void reachable_addr_choose_from_node(const node_t *node,
firewall_connection_t fw_connection,
int pref_only, tor_addr_port_t* ap);
-void fascist_firewall_choose_address_dir_server(const dir_server_t *ds,
+void reachable_addr_choose_from_dir_server(const dir_server_t *ds,
firewall_connection_t fw_connection,
int pref_only, tor_addr_port_t* ap);
int dir_policy_permits_address(const tor_addr_t *addr);
int socks_policy_permits_address(const tor_addr_t *addr);
-int authdir_policy_permits_address(uint32_t addr, uint16_t port);
-int authdir_policy_valid_address(uint32_t addr, uint16_t port);
-int authdir_policy_badexit_address(uint32_t addr, uint16_t port);
+int authdir_policy_permits_address(const tor_addr_t *addr, uint16_t port);
+int authdir_policy_valid_address(const tor_addr_t *addr, uint16_t port);
+int authdir_policy_badexit_address(const tor_addr_t *addr, uint16_t port);
int validate_addr_policies(const or_options_t *options, char **msg);
void policy_expand_private(smartlist_t **policy);
@@ -120,7 +120,7 @@ addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr,
int policies_parse_exit_policy_from_options(
const or_options_t *or_options,
- uint32_t local_address,
+ const tor_addr_t *ipv4_local_address,
const tor_addr_t *ipv6_local_address,
smartlist_t **result);
struct config_line_t;
@@ -173,11 +173,11 @@ addr_policy_result_t compare_tor_addr_to_short_policy(
#ifdef POLICIES_PRIVATE
STATIC void append_exit_policy_string(smartlist_t **policy, const char *more);
-STATIC int fascist_firewall_allows_address(const tor_addr_t *addr,
+STATIC int reachable_addr_allows(const tor_addr_t *addr,
uint16_t port,
smartlist_t *firewall_policy,
int pref_only, int pref_ipv6);
-STATIC const tor_addr_port_t * fascist_firewall_choose_address(
+STATIC const tor_addr_port_t * reachable_addr_choose(
const tor_addr_port_t *a,
const tor_addr_port_t *b,
int want_a,
diff --git a/src/core/or/port_cfg_st.h b/src/core/or/port_cfg_st.h
index 064e679d78..f8ff6f8cc8 100644
--- a/src/core/or/port_cfg_st.h
+++ b/src/core/or/port_cfg_st.h
@@ -26,6 +26,8 @@ struct port_cfg_t {
unsigned is_group_writable : 1;
unsigned is_world_writable : 1;
unsigned relax_dirmode_check : 1;
+ unsigned explicit_addr : 1; /** Indicate if address was explicitly set or
+ * we are using the default address. */
entry_port_cfg_t entry_cfg;
diff --git a/src/core/or/protover.c b/src/core/or/protover.c
index c3f443631b..26fcefe8ac 100644
--- a/src/core/or/protover.c
+++ b/src/core/or/protover.c
@@ -250,7 +250,8 @@ parse_single_entry(const char *s, const char *end_of_entry)
}
s = comma;
- while (*s == ',' && s < end_of_entry)
+ // Skip the comma separator between ranges. Don't ignore a trailing comma.
+ if (s < (end_of_entry - 1))
++s;
}
@@ -298,11 +299,12 @@ parse_protocol_list(const char *s)
}
/**
- * Return true if the unparsed protover in <b>s</b> would contain a protocol
- * name longer than MAX_PROTOCOL_NAME_LENGTH, and false otherwise.
+ * Return true if the unparsed protover list in <b>s</b> contains a
+ * parsing error, such as extra commas, a bad number, or an over-long
+ * name.
*/
bool
-protover_contains_long_protocol_names(const char *s)
+protover_list_is_invalid(const char *s)
{
smartlist_t *list = parse_protocol_list(s);
if (!list)
@@ -326,6 +328,9 @@ protover_is_supported_here(protocol_type_t pr, uint32_t ver)
/**
* Return true iff "list" encodes a protocol list that includes support for
* the indicated protocol and version.
+ *
+ * If the protocol list is unparseable, treat it as if it defines no
+ * protocols, and return 0.
*/
int
protocol_list_supports_protocol(const char *list, protocol_type_t tp,
@@ -348,6 +353,9 @@ protocol_list_supports_protocol(const char *list, protocol_type_t tp,
/**
* Return true iff "list" encodes a protocol list that includes support for
* the indicated protocol and version, or some later version.
+ *
+ * If the protocol list is unparseable, treat it as if it defines no
+ * protocols, and return 0.
*/
int
protocol_list_supports_protocol_or_later(const char *list,
@@ -387,6 +395,11 @@ protocol_list_supports_protocol_or_later(const char *list,
const char *
protover_get_supported_protocols(void)
{
+ /* WARNING!
+ *
+ * Remember to edit the SUPPORTED_PROTOCOLS list in protover.rs if you
+ * are editing this list.
+ */
return
"Cons=1-2 "
"Desc=1-2 "
@@ -403,7 +416,7 @@ protover_get_supported_protocols(void)
#endif
"Microdesc=1-2 "
"Padding=2 "
- "Relay=1-2";
+ "Relay=1-3";
}
/** The protocols from protover_get_supported_protocols(), as parsed into a
@@ -740,6 +753,9 @@ protover_compute_vote(const smartlist_t *list_of_proto_strings,
* one that we support, and false otherwise. If <b>missing_out</b> is
* provided, set it to the list of protocols we do not support.
*
+ * If the protocol version string is unparseable, treat it as if it defines no
+ * protocols, and return 1.
+ *
* NOTE: This is quadratic, but we don't do it much: only a few times per
* consensus. Checking signatures should be way more expensive than this
* ever would be.
diff --git a/src/core/or/protover.h b/src/core/or/protover.h
index 9509f3e8a3..24008f46b9 100644
--- a/src/core/or/protover.h
+++ b/src/core/or/protover.h
@@ -22,12 +22,32 @@ struct smartlist_t;
/// `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS`
#define FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS "0.2.9.3-alpha"
-/** The protover version number that signifies HSDir support for HSv3 */
-#define PROTOVER_HSDIR_V3 2
+/** The protover version number that signifies ed25519 link handshake support
+ */
+#define PROTOVER_LINKAUTH_ED25519_HANDSHAKE 3
+
+/** The protover version number that signifies extend2 cell support */
+#define PROTOVER_RELAY_EXTEND2 2
+/** The protover version number where relays can accept IPv6 connections */
+#define PROTOVER_RELAY_ACCEPT_IPV6 2
+/** The protover version number where relays can initiate IPv6 extends */
+#define PROTOVER_RELAY_EXTEND_IPV6 3
+/** The protover version number where relays can consider IPv6 connections
+ * canonical */
+#define PROTOVER_RELAY_CANONICAL_IPV6 3
+
/** The protover version number that signifies HSv3 intro point support */
#define PROTOVER_HS_INTRO_V3 4
+/** The protover version number where intro points support denial of service
+ * resistance */
+#define PROTOVER_HS_INTRO_DOS 5
+
/** The protover version number that signifies HSv3 rendezvous point support */
#define PROTOVER_HS_RENDEZVOUS_POINT_V3 2
+
+/** The protover version number that signifies HSDir support for HSv3 */
+#define PROTOVER_HSDIR_V3 2
+
/** The protover that signals support for HS circuit setup padding machines */
#define PROTOVER_HS_SETUP_PADDING 2
@@ -49,7 +69,7 @@ typedef enum protocol_type_t {
PRT_FLOWCTRL = 11,
} protocol_type_t;
-bool protover_contains_long_protocol_names(const char *s);
+bool protover_list_is_invalid(const char *s);
int protover_all_supported(const char *s, char **missing);
int protover_is_supported_here(protocol_type_t pr, uint32_t ver);
const char *protover_get_supported_protocols(void);
diff --git a/src/core/or/protover_rust.c b/src/core/or/protover_rust.c
index f44746b6da..99f3aa7f69 100644
--- a/src/core/or/protover_rust.c
+++ b/src/core/or/protover_rust.c
@@ -25,7 +25,7 @@ int protover_contains_long_protocol_names_(const char *s);
* name longer than MAX_PROTOCOL_NAME_LENGTH, and false otherwise.
*/
bool
-protover_contains_long_protocol_names(const char *s)
+protover_list_is_invalid(const char *s)
{
return protover_contains_long_protocol_names_(s) != 0;
}
diff --git a/src/core/or/relay.c b/src/core/or/relay.c
index 75d2d479e7..6895591064 100644
--- a/src/core/or/relay.c
+++ b/src/core/or/relay.c
@@ -56,6 +56,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/circuitpadding.h"
+#include "core/or/extendinfo.h"
#include "lib/compress/compress.h"
#include "app/config/config.h"
#include "core/mainloop/connection.h"
diff --git a/src/core/or/scheduler.c b/src/core/or/scheduler.c
index 072d78128b..18f11487d9 100644
--- a/src/core/or/scheduler.c
+++ b/src/core/or/scheduler.c
@@ -713,7 +713,7 @@ scheduler_bug_occurred(const channel_t *chan)
if (chan != NULL) {
const size_t outbuf_len =
- buf_datalen(TO_CONN(BASE_CHAN_TO_TLS((channel_t *) chan)->conn)->outbuf);
+ buf_datalen(TO_CONN(CONST_BASE_CHAN_TO_TLS(chan)->conn)->outbuf);
tor_snprintf(buf, sizeof(buf),
"Channel %" PRIu64 " in state %s and scheduler state %s."
" Num cells on cmux: %d. Connection outbuf len: %lu.",
diff --git a/src/core/or/scheduler_kist.c b/src/core/or/scheduler_kist.c
index c73d768f88..8c6a7bd1d1 100644
--- a/src/core/or/scheduler_kist.c
+++ b/src/core/or/scheduler_kist.c
@@ -203,7 +203,7 @@ update_socket_info_impl, (socket_table_ent_t *ent))
tor_assert(ent);
tor_assert(ent->chan);
const tor_socket_t sock =
- TO_CONN(BASE_CHAN_TO_TLS((channel_t *) ent->chan)->conn)->s;
+ TO_CONN(CONST_BASE_CHAN_TO_TLS(ent->chan)->conn)->s;
struct tcp_info tcp;
socklen_t tcp_info_len = sizeof(tcp);
@@ -445,6 +445,11 @@ update_socket_written(socket_table_t *table, channel_t *chan, size_t bytes)
* one cell for each and bouncing back and forth. This KIST impl avoids that
* by only writing a channel's outbuf to the kernel if it has 8 cells or more
* in it.
+ *
+ * Note: The number 8 has been picked for no particular reasons except that it
+ * is 4096 bytes which is a common number for buffering. A TLS record can hold
+ * up to 16KiB thus using 8 cells means that a relay will at most send a TLS
+ * record of 4KiB or 1/4 of the maximum capacity of a TLS record.
*/
MOCK_IMPL(int, channel_should_write_to_kernel,
(outbuf_table_t *table, channel_t *chan))
diff --git a/src/core/or/sendme.c b/src/core/or/sendme.c
index 788f56088c..8ea9ef15d2 100644
--- a/src/core/or/sendme.c
+++ b/src/core/or/sendme.c
@@ -394,7 +394,7 @@ sendme_connection_edge_consider_sending(edge_connection_t *conn)
while (conn->deliver_window <=
(STREAMWINDOW_START - STREAMWINDOW_INCREMENT)) {
log_debug(log_domain, "Outbuf %" TOR_PRIuSZ ", queuing stream SENDME.",
- TO_CONN(conn)->outbuf_flushlen);
+ buf_datalen(TO_CONN(conn)->outbuf));
conn->deliver_window += STREAMWINDOW_INCREMENT;
if (connection_edge_send_command(conn, RELAY_COMMAND_SENDME,
NULL, 0) < 0) {
diff --git a/src/core/or/status.c b/src/core/or/status.c
index ed8448883c..00a88a3178 100644
--- a/src/core/or/status.c
+++ b/src/core/or/status.c
@@ -113,6 +113,41 @@ log_onion_service_stats(void)
hs_stats_get_n_rendezvous_launches());
}
+/**
+ * @name connection counts for heartbeat
+ *
+ * Tracks incoming and outgoing connections on IPv4/IPv6, for heartbeat
+ * logs.
+ **/
+/**@{*/
+static unsigned n_incoming_ipv4;
+static unsigned n_incoming_ipv6;
+static unsigned n_outgoing_ipv4;
+static unsigned n_outgoing_ipv6;
+/**@}*/
+
+/**
+ * Note that a connection has arrived or has been made, for use in the
+ * heartbeat message.
+ **/
+void
+note_connection(bool inbound, int family)
+{
+ if (family == AF_INET) {
+ if (inbound) {
+ ++n_incoming_ipv4;
+ } else {
+ ++n_outgoing_ipv4;
+ }
+ } else if (family == AF_INET6) {
+ if (inbound) {
+ ++n_incoming_ipv6;
+ } else {
+ ++n_outgoing_ipv6;
+ }
+ }
+}
+
/** Log a "heartbeat" message describing Tor's status and history so that the
* user can know that there is indeed a running Tor. Return 0 on success and
* -1 on failure. */
@@ -143,8 +178,12 @@ log_heartbeat(time_t now)
bw_sent = bytes_to_usage(get_bytes_written());
log_fn(LOG_NOTICE, LD_HEARTBEAT, "Heartbeat: Tor's uptime is %s, with %d "
- "circuits open. I've sent %s and received %s.%s",
+ "circuits open. I've sent %s and received %s. I've received %u "
+ "connections on IPv4 and %u on IPv6. I've made %u connections "
+ "with IPv4 and %u with IPv6.%s",
uptime, count_circuits(), bw_sent, bw_rcvd,
+ n_incoming_ipv4, n_incoming_ipv6,
+ n_outgoing_ipv4, n_outgoing_ipv6,
hibernating?" We are currently hibernating.":"");
dirclient_dump_total_dls();
diff --git a/src/core/or/status.h b/src/core/or/status.h
index 639f8cdf51..271e0dbc9a 100644
--- a/src/core/or/status.h
+++ b/src/core/or/status.h
@@ -11,6 +11,7 @@
#include "lib/testsupport/testsupport.h"
+void note_connection(bool inbound, int family);
int log_heartbeat(time_t now);
#ifdef STATUS_PRIVATE
diff --git a/src/core/or/trace_probes_circuit.c b/src/core/or/trace_probes_circuit.c
new file mode 100644
index 0000000000..b186ffda7f
--- /dev/null
+++ b/src/core/or/trace_probes_circuit.c
@@ -0,0 +1,30 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file trace_probes_circuit.c
+ * \brief Tracepoint provider source file for the circuit subsystem. Probes
+ * are generated within this C file for LTTng-UST
+ **/
+
+#include "orconfig.h"
+
+/*
+ * Following section is specific to LTTng-UST.
+ */
+#ifdef USE_TRACING_INSTRUMENTATION_LTTNG
+
+/* Header files that the probes need. */
+#include "core/or/circuitlist.h"
+#include "core/or/crypt_path_st.h"
+#include "core/or/extend_info_st.h"
+#include "core/or/or.h"
+#include "core/or/or_circuit_st.h"
+#include "core/or/origin_circuit_st.h"
+
+#define TRACEPOINT_DEFINE
+#define TRACEPOINT_CREATE_PROBES
+
+#include "trace_probes_circuit.h"
+
+#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */
diff --git a/src/core/or/trace_probes_circuit.h b/src/core/or/trace_probes_circuit.h
new file mode 100644
index 0000000000..59f53c324a
--- /dev/null
+++ b/src/core/or/trace_probes_circuit.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file trace_probes_circuit.c
+ * \brief The tracing probes for the circuit subsystem. Currently, only
+ * LTTng-UST probes are available.
+ **/
+
+#ifndef TOR_TRACE_PROBES_CIRCUIT_H
+#define TOR_TRACE_PROBES_CIRCUIT_H
+
+#include "lib/trace/events.h"
+
+/* We only build the following if LTTng instrumentation has been enabled. */
+#ifdef USE_TRACING_INSTRUMENTATION_LTTNG
+
+#include "core/or/lttng_circuit.inc"
+
+#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */
+
+#endif /* TOR_TRACE_PROBES_CIRCUIT_H */
diff --git a/src/core/or/versions.c b/src/core/or/versions.c
index 31f1f5b997..5dfe0c2cc9 100644
--- a/src/core/or/versions.c
+++ b/src/core/or/versions.c
@@ -408,6 +408,10 @@ static strmap_t *protover_summary_map = NULL;
/**
* Helper. Given a non-NULL protover string <b>protocols</b>, set <b>out</b>
* to its summary, and memoize the result in <b>protover_summary_map</b>.
+ *
+ * If the protover string does not contain any recognised protocols, sets
+ * protocols_known, but does not set any other flags. (Empty strings are also
+ * treated this way.)
*/
static void
memoize_protover_summary(protover_summary_flags_t *out,
@@ -434,25 +438,49 @@ memoize_protover_summary(protover_summary_flags_t *out,
memset(out, 0, sizeof(*out));
out->protocols_known = 1;
- out->supports_extend2_cells =
- protocol_list_supports_protocol(protocols, PRT_RELAY, 2);
+
out->supports_ed25519_link_handshake_compat =
- protocol_list_supports_protocol(protocols, PRT_LINKAUTH, 3);
+ protocol_list_supports_protocol(protocols, PRT_LINKAUTH,
+ PROTOVER_LINKAUTH_ED25519_HANDSHAKE);
out->supports_ed25519_link_handshake_any =
- protocol_list_supports_protocol_or_later(protocols, PRT_LINKAUTH, 3);
+ protocol_list_supports_protocol_or_later(
+ protocols,
+ PRT_LINKAUTH,
+ PROTOVER_LINKAUTH_ED25519_HANDSHAKE);
+
+ out->supports_extend2_cells =
+ protocol_list_supports_protocol(protocols, PRT_RELAY,
+ PROTOVER_RELAY_EXTEND2);
+ out->supports_accepting_ipv6_extends = (
+ protocol_list_supports_protocol(protocols, PRT_RELAY,
+ PROTOVER_RELAY_ACCEPT_IPV6) ||
+ protocol_list_supports_protocol(protocols, PRT_RELAY,
+ PROTOVER_RELAY_EXTEND_IPV6));
+ out->supports_initiating_ipv6_extends =
+ protocol_list_supports_protocol(protocols, PRT_RELAY,
+ PROTOVER_RELAY_EXTEND_IPV6);
+ out->supports_canonical_ipv6_conns =
+ protocol_list_supports_protocol(protocols, PRT_RELAY,
+ PROTOVER_RELAY_CANONICAL_IPV6);
+
out->supports_ed25519_hs_intro =
- protocol_list_supports_protocol(protocols, PRT_HSINTRO, 4);
- out->supports_v3_hsdir =
- protocol_list_supports_protocol(protocols, PRT_HSDIR,
- PROTOVER_HSDIR_V3);
+ protocol_list_supports_protocol(protocols, PRT_HSINTRO,
+ PROTOVER_HS_INTRO_V3);
+ out->supports_establish_intro_dos_extension =
+ protocol_list_supports_protocol(protocols, PRT_HSINTRO,
+ PROTOVER_HS_INTRO_DOS);
+
out->supports_v3_rendezvous_point =
protocol_list_supports_protocol(protocols, PRT_HSREND,
PROTOVER_HS_RENDEZVOUS_POINT_V3);
+
+ out->supports_v3_hsdir =
+ protocol_list_supports_protocol(protocols, PRT_HSDIR,
+ PROTOVER_HSDIR_V3);
+
out->supports_hs_setup_padding =
protocol_list_supports_protocol(protocols, PRT_PADDING,
PROTOVER_HS_SETUP_PADDING);
- out->supports_establish_intro_dos_extension =
- protocol_list_supports_protocol(protocols, PRT_HSINTRO, 5);
protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out));
cached = strmap_set(protover_summary_map, protocols, new_cached);
@@ -461,6 +489,13 @@ memoize_protover_summary(protover_summary_flags_t *out,
/** Summarize the protocols listed in <b>protocols</b> into <b>out</b>,
* falling back or correcting them based on <b>version</b> as appropriate.
+ *
+ * If protocols and version are both NULL or "", returns a summary with no
+ * flags set.
+ *
+ * If the protover string does not contain any recognised protocols, and the
+ * version is not recognised, sets protocols_known, but does not set any other
+ * flags. (Empty strings are also treated this way.)
*/
void
summarize_protover_flags(protover_summary_flags_t *out,
@@ -469,10 +504,10 @@ summarize_protover_flags(protover_summary_flags_t *out,
{
tor_assert(out);
memset(out, 0, sizeof(*out));
- if (protocols) {
+ if (protocols && strcmp(protocols, "")) {
memoize_protover_summary(out, protocols);
}
- if (version && !strcmpstart(version, "Tor ")) {
+ if (version && strcmp(version, "") && !strcmpstart(version, "Tor ")) {
if (!out->protocols_known) {
/* The version is a "Tor" version, and where there is no
* list of protocol versions that we should be looking at instead. */
diff --git a/src/core/proto/proto_socks.c b/src/core/proto/proto_socks.c
index 198195c0ae..08febee5bb 100644
--- a/src/core/proto/proto_socks.c
+++ b/src/core/proto/proto_socks.c
@@ -67,8 +67,8 @@ log_unsafe_socks_warning(int socks_protocol, const char *address,
"Tor only an IP address. Applications that do DNS resolves "
"themselves may leak information. Consider using Socks4A "
"(e.g. via privoxy or socat) instead. For more information, "
- "please see https://wiki.torproject.org/TheOnionRouter/"
- "TorFAQ#SOCKSAndDNS.%s",
+ "please see https://2019.www.torproject.org/docs/faq.html.en"
+ "#WarningsAboutSOCKSandDNSInformationLeaks.%s",
socks_protocol,
(int)port,
safe_socks ? " Rejecting." : "");
diff --git a/src/core/stA1RajU b/src/core/stA1RajU
deleted file mode 100644
index e69de29bb2..0000000000
--- a/src/core/stA1RajU
+++ /dev/null
diff --git a/src/core/stiysZND b/src/core/stiysZND
deleted file mode 100644
index faa365b769..0000000000
--- a/src/core/stiysZND
+++ /dev/null
Binary files differ
diff --git a/src/ext/README b/src/ext/README
deleted file mode 100644
index d7e5439c71..0000000000
--- a/src/ext/README
+++ /dev/null
@@ -1,79 +0,0 @@
-
-OpenBSD_malloc_Linux.c:
-
- The OpenBSD malloc implementation, ported to Linux. Used only when
- --enable-openbsd-malloc is passed to the configure script.
-
-strlcat.c
-strlcpy.c
-
- Implementations of strlcat and strlcpy, the more sane replacements
- for strcat and strcpy. These are nonstandard, and some libc
- implementations refuse to add them for religious reasons.
-
-ht.h
-
- An implementation of a hash table in the style of Niels Provos's
- tree.h. Shared with Libevent.
-
-tinytest.[ch]
-tinytest_demos.c
-tinytest_macros.h
-
- A unit testing framework. https://github.com/nmathewson/tinytest
-
-tor_queue.h
-
- A copy of sys/queue.h from OpenBSD. We keep our own copy rather
- than using sys/queue.h, since some platforms don't have a
- sys/queue.h, and the ones that do have diverged in incompatible
- ways. (CIRCLEQ or no CIRCLEQ? SIMPLQ or STAILQ?) We also rename
- the identifiers with a TOR_ prefix to avoid conflicts with
- the system headers.
-
-curve25519_donna/*.c
-
- A copy of Adam Langley's curve25519-donna mostly-portable
- implementations of curve25519.
-
-csiphash.c
-siphash.h
-
- Marek Majkowski's implementation of siphash 2-4, a secure keyed
- hash algorithm to avoid collision-based DoS attacks against hash
- tables.
-
-trunnel/*.[ch]
-
- Headers and runtime code for Trunnel, a system for generating
- code to encode and decode binary formats.
-
-ed25519/ref10/*
-
- Daniel Bernsten's portable ref10 implementation of ed25519.
- Public domain.
-
-ed25519/donna/*
-
- Andrew Moon's semi-portable ed25519-donna implementation of
- ed25519. Public domain.
-
-keccak-tiny/
-
- David Leon Gil's portable Keccak implementation. CC0.
-
-readpassphrase.[ch]
-
- Portable readpassphrase implementation from OpenSSH portable, version
- 6.8p1.
-
-timeouts/
-
- William Ahern's hierarchical timer-wheel implementation. MIT license.
-
-mulodi/
-
- Contains an overflow-checking 64-bit signed integer multiply
- from LLVM's compiler_rt. For some reason, this is missing from
- 32-bit libclang in many places. Dual licensed MIT-license and
- BSD-like license; see mulodi/LICENSE.TXT.
diff --git a/src/ext/ed25519/donna/ed25519_tor.c b/src/ext/ed25519/donna/ed25519_tor.c
index a5bb6f4e21..4b35c9f634 100644
--- a/src/ext/ed25519/donna/ed25519_tor.c
+++ b/src/ext/ed25519/donna/ed25519_tor.c
@@ -43,6 +43,7 @@
#include "ed25519-randombytes.h"
#include "ed25519-hash.h"
+#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
typedef unsigned char ed25519_signature[64];
diff --git a/src/ext/ext.md b/src/ext/ext.md
new file mode 100644
index 0000000000..1eaaab605b
--- /dev/null
+++ b/src/ext/ext.md
@@ -0,0 +1,88 @@
+@dir /ext
+@brief Externally maintained code
+
+The "ext" directory holds code that was written elsewhere, and is not
+reliably packaged as a library where we want to build, so we ship
+it along with Tor.
+
+In general, you should not edit this code: we are not the maintainers.
+Instead, you should submit patches upstream.
+
+OpenBSD_malloc_Linux.c:
+
+> The OpenBSD malloc implementation, ported to Linux. Used only when
+> --enable-openbsd-malloc is passed to the configure script.
+
+strlcat.c
+strlcpy.c
+
+> Implementations of strlcat and strlcpy, the more sane replacements
+> for strcat and strcpy. These are nonstandard, and some libc
+> implementations refuse to add them for religious reasons.
+
+ht.h
+
+> An implementation of a hash table in the style of Niels Provos's
+> tree.h. Shared with Libevent.
+
+tinytest.c tinytest.h
+tinytest_demos.c
+tinytest_macros.h
+
+> A unit testing framework. https://github.com/nmathewson/tinytest
+
+tor_queue.h
+
+> A copy of sys/queue.h from OpenBSD. We keep our own copy rather
+> than using sys/queue.h, since some platforms don't have a
+> sys/queue.h, and the ones that do have diverged in incompatible
+> ways. (CIRCLEQ or no CIRCLEQ? SIMPLQ or STAILQ?) We also rename
+> the identifiers with a TOR_ prefix to avoid conflicts with
+> the system headers.
+
+curve25519_donna/*.c
+
+> A copy of Adam Langley's curve25519-donna mostly-portable
+> implementations of curve25519.
+
+csiphash.c
+siphash.h
+
+> Marek Majkowski's implementation of siphash 2-4, a secure keyed
+> hash algorithm to avoid collision-based DoS attacks against hash
+> tables.
+
+trunnel/*.[ch]
+
+> Headers and runtime code for Trunnel, a system for generating
+> code to encode and decode binary formats.
+
+ed25519/ref10/*
+
+> Daniel Bernsten's portable ref10 implementation of ed25519.
+> Public domain.
+
+ed25519/donna/*
+
+> Andrew Moon's semi-portable ed25519-donna implementation of
+> ed25519. Public domain.
+
+keccak-tiny/
+
+> David Leon Gil's portable Keccak implementation. CC0.
+
+readpassphrase.[ch]
+
+> Portable readpassphrase implementation from OpenSSH portable, version
+> 6.8p1.
+
+timeouts/
+
+> William Ahern's hierarchical timer-wheel implementation. MIT license.
+
+mulodi/
+
+> Contains an overflow-checking 64-bit signed integer multiply
+> from LLVM's compiler_rt. For some reason, this is missing from
+> 32-bit libclang in many places. Dual licensed MIT-license and
+> BSD-like license; see mulodi/LICENSE.TXT.
diff --git a/src/ext/include.am b/src/ext/include.am
index 317e25d78e..8b646b1b4e 100644
--- a/src/ext/include.am
+++ b/src/ext/include.am
@@ -1,7 +1,7 @@
AM_CPPFLAGS += -I$(srcdir)/src/ext -Isrc/ext
-EXTRA_DIST += src/ext/README
+EXTRA_DIST += src/ext/ext.md
EXTHEADERS = \
src/ext/ht.h \
diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c
index 66b04f3bc2..59f79219cf 100644
--- a/src/feature/client/bridges.c
+++ b/src/feature/client/bridges.c
@@ -249,8 +249,8 @@ get_configured_bridge_by_exact_addr_port_digest(const tor_addr_t *addr,
* address/port matches only. */
int
addr_is_a_configured_bridge(const tor_addr_t *addr,
- uint16_t port,
- const char *digest)
+ uint16_t port,
+ const char *digest)
{
tor_assert(addr);
return get_configured_bridge_by_addr_port_digest(addr, port, digest) ? 1 : 0;
@@ -259,12 +259,26 @@ addr_is_a_configured_bridge(const tor_addr_t *addr,
/** If we have a bridge configured whose digest matches
* <b>ei->identity_digest</b>, or a bridge with no known digest whose address
* matches <b>ei->addr</b>:<b>ei->port</b>, return 1. Else return 0.
- * If <b>ei->onion_key</b> is NULL, check for address/port matches only. */
+ * If <b>ei->onion_key</b> is NULL, check for address/port matches only.
+ *
+ * Note that if the extend_info_t contains multiple addresses, we return true
+ * only if _every_ address is a bridge.
+ */
int
extend_info_is_a_configured_bridge(const extend_info_t *ei)
{
const char *digest = ei->onion_key ? ei->identity_digest : NULL;
- return addr_is_a_configured_bridge(&ei->addr, ei->port, digest);
+ const tor_addr_port_t *ap1 = NULL, *ap2 = NULL;
+ if (! tor_addr_is_null(&ei->orports[0].addr))
+ ap1 = &ei->orports[0];
+ if (! tor_addr_is_null(&ei->orports[1].addr))
+ ap2 = &ei->orports[1];
+ IF_BUG_ONCE(ap1 == NULL) {
+ return 0;
+ }
+ return addr_is_a_configured_bridge(&ap1->addr, ap1->port, digest) &&
+ (ap2 == NULL ||
+ addr_is_a_configured_bridge(&ap2->addr, ap2->port, digest));
}
/** Wrapper around get_configured_bridge_by_addr_port_digest() to look
@@ -289,51 +303,21 @@ routerinfo_is_a_configured_bridge(const routerinfo_t *ri)
}
/**
- * Return 1 iff <b>bridge_list</b> contains entry matching
- * given; IPv4 address in host byte order (<b>ipv4_addr</b>
- * and <b>port</b> (and no identity digest) OR it contains an
- * entry whose identity matches <b>digest</b>. Otherwise,
- * return 0.
- */
-static int
-bridge_exists_with_ipv4h_addr_and_port(const uint32_t ipv4_addr,
- const uint16_t port,
- const char *digest)
-{
- tor_addr_t node_ipv4;
-
- if (tor_addr_port_is_valid_ipv4h(ipv4_addr, port, 0)) {
- tor_addr_from_ipv4h(&node_ipv4, ipv4_addr);
-
- bridge_info_t *bridge =
- get_configured_bridge_by_addr_port_digest(&node_ipv4,
- port,
- digest);
-
- return (bridge != NULL);
- }
-
- return 0;
-}
-
-/**
* Return 1 iff <b>bridge_list</b> contains entry matching given
- * <b>ipv6_addr</b> and <b>port</b> (and no identity digest) OR
+ * <b>addr</b> and <b>port</b> (and no identity digest) OR
* it contains an entry whose identity matches <b>digest</b>.
* Otherwise, return 0.
*/
static int
-bridge_exists_with_ipv6_addr_and_port(const tor_addr_t *ipv6_addr,
- const uint16_t port,
- const char *digest)
+bridge_exists_with_addr_and_port(const tor_addr_t *addr,
+ const uint16_t port,
+ const char *digest)
{
- if (!tor_addr_port_is_valid(ipv6_addr, port, 0))
+ if (!tor_addr_port_is_valid(addr, port, 0))
return 0;
bridge_info_t *bridge =
- get_configured_bridge_by_addr_port_digest(ipv6_addr,
- port,
- digest);
+ get_configured_bridge_by_addr_port_digest(addr, port, digest);
return (bridge != NULL);
}
@@ -360,29 +344,29 @@ node_is_a_configured_bridge(const node_t *node)
* check for absence of identity digest in a bridge.
*/
if (node->ri) {
- if (bridge_exists_with_ipv4h_addr_and_port(node->ri->addr,
- node->ri->or_port,
- node->identity))
+ if (bridge_exists_with_addr_and_port(&node->ri->ipv4_addr,
+ node->ri->ipv4_orport,
+ node->identity))
return 1;
- if (bridge_exists_with_ipv6_addr_and_port(&node->ri->ipv6_addr,
- node->ri->ipv6_orport,
- node->identity))
+ if (bridge_exists_with_addr_and_port(&node->ri->ipv6_addr,
+ node->ri->ipv6_orport,
+ node->identity))
return 1;
} else if (node->rs) {
- if (bridge_exists_with_ipv4h_addr_and_port(node->rs->addr,
- node->rs->or_port,
- node->identity))
+ if (bridge_exists_with_addr_and_port(&node->rs->ipv4_addr,
+ node->rs->ipv4_orport,
+ node->identity))
return 1;
- if (bridge_exists_with_ipv6_addr_and_port(&node->rs->ipv6_addr,
- node->rs->ipv6_orport,
- node->identity))
+ if (bridge_exists_with_addr_and_port(&node->rs->ipv6_addr,
+ node->rs->ipv6_orport,
+ node->identity))
return 1;
} else if (node->md) {
- if (bridge_exists_with_ipv6_addr_and_port(&node->md->ipv6_addr,
- node->md->ipv6_orport,
- node->identity))
+ if (bridge_exists_with_addr_and_port(&node->md->ipv6_addr,
+ node->md->ipv6_orport,
+ node->identity))
return 1;
}
@@ -612,7 +596,7 @@ find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port)
*/
int
get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
- const transport_t **transport)
+ const transport_t **transport)
{
*transport = NULL;
if (!bridge_list)
@@ -670,7 +654,7 @@ launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
/* Until we get a descriptor for the bridge, we only know one address for
* it. */
- if (!fascist_firewall_allows_address_addr(&bridge->addr, bridge->port,
+ if (!reachable_addr_allows_addr(&bridge->addr, bridge->port,
FIREWALL_OR_CONNECTION, 0, 0)) {
log_notice(LD_CONFIG, "Tried to fetch a descriptor directly from a "
"bridge, but that bridge is not reachable through our "
@@ -762,7 +746,7 @@ fetch_bridge_descriptors(const or_options_t *options, time_t now)
!options->UpdateBridgesFromAuthority, !num_bridge_auths);
if (ask_bridge_directly &&
- !fascist_firewall_allows_address_addr(&bridge->addr, bridge->port,
+ !reachable_addr_allows_addr(&bridge->addr, bridge->port,
FIREWALL_OR_CONNECTION, 0,
0)) {
log_notice(LD_DIR, "Bridge at '%s' isn't reachable by our "
@@ -811,25 +795,23 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
* do that safely if we know that no function that connects to an OR
* does so through an address from any source other than node_get_addr().
*/
- tor_addr_t addr;
const or_options_t *options = get_options();
if (node->ri) {
routerinfo_t *ri = node->ri;
- tor_addr_from_ipv4h(&addr, ri->addr);
- if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
- bridge->port == ri->or_port) ||
+ if ((!tor_addr_compare(&bridge->addr, &ri->ipv4_addr, CMP_EXACT) &&
+ bridge->port == ri->ipv4_orport) ||
(!tor_addr_compare(&bridge->addr, &ri->ipv6_addr, CMP_EXACT) &&
bridge->port == ri->ipv6_orport)) {
/* they match, so no need to do anything */
} else {
if (tor_addr_family(&bridge->addr) == AF_INET) {
- ri->addr = tor_addr_to_ipv4h(&bridge->addr);
- ri->or_port = bridge->port;
+ tor_addr_copy(&ri->ipv4_addr, &bridge->addr);
+ ri->ipv4_orport = bridge->port;
log_info(LD_DIR,
"Adjusted bridge routerinfo for '%s' to match configured "
"address %s:%d.",
- ri->nickname, fmt_addr32(ri->addr), ri->or_port);
+ ri->nickname, fmt_addr(&ri->ipv4_addr), ri->ipv4_orport);
} else if (tor_addr_family(&bridge->addr) == AF_INET6) {
tor_addr_copy(&ri->ipv6_addr, &bridge->addr);
ri->ipv6_orport = bridge->port;
@@ -850,7 +832,7 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
!tor_addr_is_null(&node->ri->ipv6_addr));
} else {
/* Mark which address to use based on user preference */
- node->ipv6_preferred = (fascist_firewall_prefer_ipv6_orport(options) &&
+ node->ipv6_preferred = (reachable_addr_prefer_ipv6_orport(options) &&
!tor_addr_is_null(&node->ri->ipv6_addr));
}
@@ -872,21 +854,20 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
}
if (node->rs) {
routerstatus_t *rs = node->rs;
- tor_addr_from_ipv4h(&addr, rs->addr);
- if ((!tor_addr_compare(&bridge->addr, &addr, CMP_EXACT) &&
- bridge->port == rs->or_port) ||
+ if ((!tor_addr_compare(&bridge->addr, &rs->ipv4_addr, CMP_EXACT) &&
+ bridge->port == rs->ipv4_orport) ||
(!tor_addr_compare(&bridge->addr, &rs->ipv6_addr, CMP_EXACT) &&
bridge->port == rs->ipv6_orport)) {
/* they match, so no need to do anything */
} else {
if (tor_addr_family(&bridge->addr) == AF_INET) {
- rs->addr = tor_addr_to_ipv4h(&bridge->addr);
- rs->or_port = bridge->port;
+ tor_addr_copy(&rs->ipv4_addr, &bridge->addr);
+ rs->ipv4_orport = bridge->port;
log_info(LD_DIR,
"Adjusted bridge routerstatus for '%s' to match "
"configured address %s.",
- rs->nickname, fmt_addrport(&bridge->addr, rs->or_port));
+ rs->nickname, fmt_addrport(&bridge->addr, rs->ipv4_orport));
/* set IPv6 preferences even if there is no ri */
} else if (tor_addr_family(&bridge->addr) == AF_INET6) {
tor_addr_copy(&rs->ipv6_addr, &bridge->addr);
@@ -908,7 +889,7 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node)
!tor_addr_is_null(&node->rs->ipv6_addr));
} else {
/* Mark which address to use based on user preference */
- node->ipv6_preferred = (fascist_firewall_prefer_ipv6_orport(options) &&
+ node->ipv6_preferred = (reachable_addr_prefer_ipv6_orport(options) &&
!tor_addr_is_null(&node->rs->ipv6_addr));
}
diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c
index 45e484540c..2104a622da 100644
--- a/src/feature/client/entrynodes.c
+++ b/src/feature/client/entrynodes.c
@@ -1466,7 +1466,7 @@ node_passes_guard_filter(const or_options_t *options,
!routerset_contains_node(options->EntryNodes, node))
return 0;
- if (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0))
+ if (!reachable_addr_allows_node(node, FIREWALL_OR_CONNECTION, 0))
return 0;
if (node_is_a_configured_bridge(node))
@@ -1492,7 +1492,7 @@ bridge_passes_guard_filter(const or_options_t *options,
/* Ignore entrynodes */
const tor_addr_port_t *addrport = bridge_get_addr_port(bridge);
- if (!fascist_firewall_allows_address_addr(&addrport->addr,
+ if (!reachable_addr_allows_addr(&addrport->addr,
addrport->port,
FIREWALL_OR_CONNECTION,
0, 0))
@@ -1554,7 +1554,7 @@ guard_in_node_family(const entry_guard_t *guard, const node_t *node)
if (get_options()->EnforceDistinctSubnets && guard->bridge_addr) {
tor_addr_t node_addr;
node_get_addr(node, &node_addr);
- if (addrs_in_same_network_family(&node_addr,
+ if (router_addrs_in_same_network(&node_addr,
&guard->bridge_addr->addr)) {
return 1;
}
@@ -1576,12 +1576,12 @@ guard_create_exit_restriction(const uint8_t *exit_id)
}
/** If we have fewer than this many possible usable guards, don't set
- * MD-availability-based restrictions: we might blacklist all of them. */
+ * MD-availability-based restrictions: we might denylist all of them. */
#define MIN_GUARDS_FOR_MD_RESTRICTION 10
/** Return true if we should set md dirserver restrictions. We might not want
* to set those if our guard options are too restricted, since we don't want
- * to blacklist all of them. */
+ * to denylist all of them. */
static int
should_set_md_dirserver_restriction(void)
{
diff --git a/src/feature/client/transports.c b/src/feature/client/transports.c
index 2bdc0ae151..2eb05d6a67 100644
--- a/src/feature/client/transports.c
+++ b/src/feature/client/transports.c
@@ -1643,17 +1643,26 @@ pt_get_extra_info_descriptor_string(void)
SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) {
char *transport_args = NULL;
+ const char *addrport = NULL;
/* If the transport proxy returned "0.0.0.0" as its address, and
* we know our external IP address, use it. Otherwise, use the
* returned address. */
- const char *addrport = NULL;
- uint32_t external_ip_address = 0;
- if (tor_addr_is_null(&t->addr) &&
- router_pick_published_address(get_options(),
- &external_ip_address, 0) >= 0) {
+ if (tor_addr_is_null(&t->addr)) {
tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, external_ip_address);
+ /* Attempt to find the IPv4 and then attempt to find the IPv6 if we
+ * can't find it. */
+ bool found = relay_find_addr_to_publish(get_options(), AF_INET,
+ RELAY_FIND_ADDR_NO_FLAG,
+ &addr);
+ if (!found) {
+ found = relay_find_addr_to_publish(get_options(), AF_INET6,
+ RELAY_FIND_ADDR_NO_FLAG, &addr);
+ }
+ if (!found) {
+ log_err(LD_PT, "Unable to find address for transport %s", t->name);
+ continue;
+ }
addrport = fmt_addrport(&addr, t->port);
} else {
addrport = fmt_addrport(&t->addr, t->port);
diff --git a/src/feature/control/control.c b/src/feature/control/control.c
index ee1026359d..ef707319a6 100644
--- a/src/feature/control/control.c
+++ b/src/feature/control/control.c
@@ -61,8 +61,12 @@
#include <sys/stat.h>
#endif
-/** Convert a connection_t* to an control_connection_t*; assert if the cast is
- * invalid. */
+/**
+ * Cast a `connection_t *` to a `control_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not a
+ * `control_connection_t`.
+ **/
control_connection_t *
TO_CONTROL_CONN(connection_t *c)
{
@@ -70,6 +74,18 @@ TO_CONTROL_CONN(connection_t *c)
return DOWNCAST(control_connection_t, c);
}
+/**
+ * Cast a `const connection_t *` to a `const control_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not a
+ * `control_connection_t`.
+ **/
+const control_connection_t *
+CONST_TO_CONTROL_CONN(const connection_t *c)
+{
+ return TO_CONTROL_CONN((connection_t*)c);
+}
+
/** Create and add a new controller connection on <b>sock</b>. If
* <b>CC_LOCAL_FD_IS_OWNER</b> is set in <b>flags</b>, this Tor process should
* exit when the connection closes. If <b>CC_LOCAL_FD_IS_AUTHENTICATED</b>
diff --git a/src/feature/control/control.h b/src/feature/control/control.h
index 7e72b2736b..f884286ec7 100644
--- a/src/feature/control/control.h
+++ b/src/feature/control/control.h
@@ -13,6 +13,7 @@
#define TOR_CONTROL_H
control_connection_t *TO_CONTROL_CONN(connection_t *);
+const control_connection_t *CONST_TO_CONTROL_CONN(const connection_t *);
#define CONTROL_CONN_STATE_MIN_ 1
/** State for a control connection: Authenticated and accepting v1 commands. */
diff --git a/src/feature/control/control_bootstrap.c b/src/feature/control/control_bootstrap.c
index fee7612ba2..d4f2adde81 100644
--- a/src/feature/control/control_bootstrap.c
+++ b/src/feature/control/control_bootstrap.c
@@ -274,7 +274,7 @@ control_event_bootstrap_problem(const char *warn, const char *reason,
const char *recommendation = "ignore";
int severity;
char *or_id = NULL, *hostaddr = NULL;
- or_connection_t *or_conn = NULL;
+ const or_connection_t *or_conn = NULL;
/* bootstrap_percent must not be in "undefined" state here. */
tor_assert(status >= 0);
@@ -301,7 +301,7 @@ control_event_bootstrap_problem(const char *warn, const char *reason,
if (conn && conn->type == CONN_TYPE_OR) {
/* XXX TO_OR_CONN can't deal with const */
- or_conn = TO_OR_CONN((connection_t *)conn);
+ or_conn = CONST_TO_OR_CONN(conn);
or_id = tor_strdup(hex_str(or_conn->identity_digest, DIGEST_LEN));
} else {
or_id = tor_strdup("?");
diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c
index d9a38011de..5b75c24692 100644
--- a/src/feature/control/control_cmd.c
+++ b/src/feature/control/control_cmd.c
@@ -20,6 +20,8 @@
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/connection_edge.h"
+#include "core/or/circuitstats.h"
+#include "core/or/extendinfo.h"
#include "feature/client/addressmap.h"
#include "feature/client/dnsserv.h"
#include "feature/client/entrynodes.h"
@@ -55,6 +57,8 @@
#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
#include "feature/rend/rend_service_descriptor_st.h"
+#include "src/app/config/statefile.h"
+
static int control_setconf_helper(control_connection_t *conn,
const control_cmd_args_t *args,
int use_defaults);
@@ -977,8 +981,7 @@ handle_control_attachstream(control_connection_t *conn,
edge_conn->end_reason = 0;
if (tmpcirc)
circuit_detach_stream(tmpcirc, edge_conn);
- CONNECTION_AP_EXPECT_NONPENDING(ap_conn);
- TO_CONN(edge_conn)->state = AP_CONN_STATE_CONTROLLER_WAIT;
+ connection_entry_set_controller_wait(ap_conn);
}
if (circ && (circ->base_.state != CIRCUIT_STATE_OPEN)) {
@@ -1396,6 +1399,34 @@ handle_control_dropguards(control_connection_t *conn,
return 0;
}
+static const control_cmd_syntax_t droptimeouts_syntax = {
+ .max_args = 0,
+};
+
+/** Implementation for the DROPTIMEOUTS command. */
+static int
+handle_control_droptimeouts(control_connection_t *conn,
+ const control_cmd_args_t *args)
+{
+ (void) args; /* We don't take arguments. */
+
+ static int have_warned = 0;
+ if (! have_warned) {
+ log_warn(LD_CONTROL, "DROPTIMEOUTS is dangerous; make sure you understand "
+ "the risks before using it. It may be removed in a future "
+ "version of Tor.");
+ have_warned = 1;
+ }
+
+ circuit_build_times_reset(get_circuit_build_times_mutable());
+ send_control_done(conn);
+ or_state_mark_dirty(get_or_state(), 0);
+ cbt_control_event_buildtimeout_set(get_circuit_build_times(),
+ BUILDTIMEOUT_SET_EVENT_RESET);
+
+ return 0;
+}
+
static const char *hsfetch_keywords[] = {
"SERVER", NULL,
};
@@ -1430,7 +1461,7 @@ handle_control_hsfetch(control_connection_t *conn,
rend_valid_descriptor_id(arg1 + v2_str_len) &&
base32_decode(digest, sizeof(digest), arg1 + v2_str_len,
REND_DESC_ID_V2_LEN_BASE32) ==
- REND_DESC_ID_V2_LEN_BASE32) {
+ sizeof(digest)) {
/* We have a well formed version 2 descriptor ID. Keep the decoded value
* of the id. */
desc_id = digest;
@@ -2331,6 +2362,7 @@ static const control_cmd_def_t CONTROL_COMMANDS[] =
ONE_LINE(protocolinfo, 0),
ONE_LINE(authchallenge, CMD_FL_WIPE),
ONE_LINE(dropguards, 0),
+ ONE_LINE(droptimeouts, 0),
ONE_LINE(hsfetch, 0),
MULTLINE(hspost, 0),
ONE_LINE(add_onion, CMD_FL_WIPE),
diff --git a/src/feature/control/control_events.c b/src/feature/control/control_events.c
index 916ccea875..2970745ca0 100644
--- a/src/feature/control/control_events.c
+++ b/src/feature/control/control_events.c
@@ -17,6 +17,7 @@
#include "core/mainloop/mainloop.h"
#include "core/or/channeltls.h"
#include "core/or/circuitlist.h"
+#include "core/or/circuitstats.h"
#include "core/or/command.h"
#include "core/or/connection_edge.h"
#include "core/or/connection_or.h"
@@ -141,6 +142,64 @@ clear_circ_bw_fields(void)
SMARTLIST_FOREACH_END(circ);
}
+/* Helper to emit the BUILDTIMEOUT_SET circuit build time event */
+void
+cbt_control_event_buildtimeout_set(const circuit_build_times_t *cbt,
+ buildtimeout_set_event_t type)
+{
+ char *args = NULL;
+ double qnt;
+ double timeout_rate = 0.0;
+ double close_rate = 0.0;
+
+ switch (type) {
+ case BUILDTIMEOUT_SET_EVENT_RESET:
+ case BUILDTIMEOUT_SET_EVENT_SUSPENDED:
+ case BUILDTIMEOUT_SET_EVENT_DISCARD:
+ qnt = 1.0;
+ break;
+ case BUILDTIMEOUT_SET_EVENT_COMPUTED:
+ case BUILDTIMEOUT_SET_EVENT_RESUME:
+ default:
+ qnt = circuit_build_times_quantile_cutoff();
+ break;
+ }
+
+ /* The timeout rate is the ratio of the timeout count over
+ * the total number of circuits attempted. The total number of
+ * circuits is (timeouts+succeeded), since every circuit
+ * either succeeds, or times out. "Closed" circuits are
+ * MEASURE_TIMEOUT circuits whose measurement period expired.
+ * All MEASURE_TIMEOUT circuits are counted in the timeouts stat
+ * before transitioning to MEASURE_TIMEOUT (in
+ * circuit_build_times_mark_circ_as_measurement_only()).
+ * MEASURE_TIMEOUT circuits that succeed are *not* counted as
+ * "succeeded". See circuit_build_times_handle_completed_hop().
+ *
+ * We cast the denominator
+ * to promote it to double before the addition, to avoid int32
+ * overflow. */
+ const double total_circuits =
+ ((double)cbt->num_circ_timeouts) + cbt->num_circ_succeeded;
+ if (total_circuits >= 1.0) {
+ timeout_rate = cbt->num_circ_timeouts / total_circuits;
+ close_rate = cbt->num_circ_closed / total_circuits;
+ }
+
+ tor_asprintf(&args, "TOTAL_TIMES=%lu "
+ "TIMEOUT_MS=%lu XM=%lu ALPHA=%f CUTOFF_QUANTILE=%f "
+ "TIMEOUT_RATE=%f CLOSE_MS=%lu CLOSE_RATE=%f",
+ (unsigned long)cbt->total_build_times,
+ (unsigned long)cbt->timeout_ms,
+ (unsigned long)cbt->Xm, cbt->alpha, qnt,
+ timeout_rate,
+ (unsigned long)cbt->close_ms,
+ close_rate);
+
+ control_event_buildtimeout_set(type, args);
+
+ tor_free(args);
+}
/** Set <b>global_event_mask*</b> to the bitwise OR of each live control
* connection's event_mask field. */
void
@@ -759,6 +818,7 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp,
case STREAM_EVENT_NEW_RESOLVE: status = "NEWRESOLVE"; break;
case STREAM_EVENT_FAILED_RETRIABLE: status = "DETACHED"; break;
case STREAM_EVENT_REMAP: status = "REMAP"; break;
+ case STREAM_EVENT_CONTROLLER_WAIT: status = "CONTROLLER_WAIT"; break;
default:
log_warn(LD_BUG, "Unrecognized status code %d", (int)tp);
return 0;
diff --git a/src/feature/control/control_events.h b/src/feature/control/control_events.h
index 4a5492b510..6e3cfef4e9 100644
--- a/src/feature/control/control_events.h
+++ b/src/feature/control/control_events.h
@@ -36,7 +36,8 @@ typedef enum stream_status_event_t {
STREAM_EVENT_NEW = 5,
STREAM_EVENT_NEW_RESOLVE = 6,
STREAM_EVENT_FAILED_RETRIABLE = 7,
- STREAM_EVENT_REMAP = 8
+ STREAM_EVENT_REMAP = 8,
+ STREAM_EVENT_CONTROLLER_WAIT = 9
} stream_status_event_t;
/** Used to indicate the type of a buildtime event */
@@ -223,6 +224,10 @@ void control_event_hs_descriptor_content(const char *onion_address,
const char *desc_id,
const char *hsdir_fp,
const char *content);
+void cbt_control_event_buildtimeout_set(const circuit_build_times_t *cbt,
+ buildtimeout_set_event_t type);
+
+int control_event_enter_controller_wait(void);
void control_events_free_all(void);
diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c
index 0823acbe07..461b8eeb94 100644
--- a/src/feature/control/control_getinfo.c
+++ b/src/feature/control/control_getinfo.c
@@ -51,6 +51,7 @@
#include "feature/rend/rendcache.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/rephist.h"
#include "lib/version/torversion.h"
#include "lib/encoding/kvline.h"
@@ -130,13 +131,23 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
smartlist_free(signal_names);
} else if (!strcmp(question, "features/names")) {
*answer = tor_strdup("VERBOSE_NAMES EXTENDED_EVENTS");
- } else if (!strcmp(question, "address")) {
- uint32_t addr;
- if (router_pick_published_address(get_options(), &addr, 0) < 0) {
+ } else if (!strcmp(question, "address") || !strcmp(question, "address/v4")) {
+ tor_addr_t addr;
+ if (!relay_find_addr_to_publish(get_options(), AF_INET,
+ RELAY_FIND_ADDR_CACHE_ONLY, &addr)) {
*errmsg = "Address unknown";
return -1;
}
- *answer = tor_dup_ip(addr);
+ *answer = tor_addr_to_str_dup(&addr);
+ tor_assert_nonfatal(*answer);
+ } else if (!strcmp(question, "address/v6")) {
+ tor_addr_t addr;
+ if (!relay_find_addr_to_publish(get_options(), AF_INET6,
+ RELAY_FIND_ADDR_CACHE_ONLY, &addr)) {
+ *errmsg = "Address unknown";
+ return -1;
+ }
+ *answer = tor_addr_to_str_dup(&addr);
tor_assert_nonfatal(*answer);
} else if (!strcmp(question, "traffic/read")) {
tor_asprintf(answer, "%"PRIu64, (get_bytes_read()));
@@ -1278,15 +1289,18 @@ getinfo_helper_events(control_connection_t *control_conn,
*answer = tor_strdup(directories_have_accepted_server_descriptor()
? "1" : "0");
} else if (!strcmp(question, "status/reachability-succeeded/or")) {
- *answer = tor_strdup(check_whether_orport_reachable(options) ?
- "1" : "0");
+ *answer = tor_strdup(
+ router_all_orports_seem_reachable(options) ?
+ "1" : "0");
} else if (!strcmp(question, "status/reachability-succeeded/dir")) {
- *answer = tor_strdup(check_whether_dirport_reachable(options) ?
- "1" : "0");
+ *answer = tor_strdup(
+ router_dirport_seems_reachable(options) ?
+ "1" : "0");
} else if (!strcmp(question, "status/reachability-succeeded")) {
- tor_asprintf(answer, "OR=%d DIR=%d",
- check_whether_orport_reachable(options) ? 1 : 0,
- check_whether_dirport_reachable(options) ? 1 : 0);
+ tor_asprintf(
+ answer, "OR=%d DIR=%d",
+ router_all_orports_seem_reachable(options) ? 1 : 0,
+ router_dirport_seems_reachable(options) ? 1 : 0);
} else if (!strcmp(question, "status/bootstrap-phase")) {
*answer = control_event_boot_last_msg();
} else if (!strcmpstart(question, "status/version/")) {
@@ -1437,6 +1451,39 @@ getinfo_helper_liveness(control_connection_t *control_conn,
return 0;
}
+/** Implementation helper for GETINFO: answers queries about circuit onion
+ * handshake rephist values */
+STATIC int
+getinfo_helper_rephist(control_connection_t *control_conn,
+ const char *question, char **answer,
+ const char **errmsg)
+{
+ (void) control_conn;
+ (void) errmsg;
+ int result;
+
+ if (!strcmp(question, "stats/ntor/assigned")) {
+ result =
+ rep_hist_get_circuit_handshake_assigned(ONION_HANDSHAKE_TYPE_NTOR);
+ } else if (!strcmp(question, "stats/ntor/requested")) {
+ result =
+ rep_hist_get_circuit_handshake_requested(ONION_HANDSHAKE_TYPE_NTOR);
+ } else if (!strcmp(question, "stats/tap/assigned")) {
+ result =
+ rep_hist_get_circuit_handshake_assigned(ONION_HANDSHAKE_TYPE_TAP);
+ } else if (!strcmp(question, "stats/tap/requested")) {
+ result =
+ rep_hist_get_circuit_handshake_requested(ONION_HANDSHAKE_TYPE_TAP);
+ } else {
+ *errmsg = "Unrecognized handshake type";
+ return -1;
+ }
+
+ tor_asprintf(answer, "%d", result);
+
+ return 0;
+}
+
/** Implementation helper for GETINFO: answers queries about shared random
* value. */
static int
@@ -1625,6 +1672,10 @@ static const getinfo_item_t getinfo_items[] = {
DOC("status/version/recommended", "List of currently recommended versions."),
DOC("status/version/current", "Status of the current version."),
ITEM("address", misc, "IP address of this Tor host, if we can guess it."),
+ ITEM("address/v4", misc,
+ "IPv4 address of this Tor host, if we can guess it."),
+ ITEM("address/v6", misc,
+ "IPv6 address of this Tor host, if we can guess it."),
ITEM("traffic/read", misc,"Bytes read since the process was started."),
ITEM("traffic/written", misc,
"Bytes written since the process was started."),
@@ -1661,6 +1712,16 @@ static const getinfo_item_t getinfo_items[] = {
"Onion services detached from the control connection."),
ITEM("sr/current", sr, "Get current shared random value."),
ITEM("sr/previous", sr, "Get previous shared random value."),
+ PREFIX("stats/ntor/", rephist, "NTor circuit handshake stats."),
+ ITEM("stats/ntor/assigned", rephist,
+ "Assigned NTor circuit handshake stats."),
+ ITEM("stats/ntor/requested", rephist,
+ "Requested NTor circuit handshake stats."),
+ PREFIX("stats/tap/", rephist, "TAP circuit handshake stats."),
+ ITEM("stats/tap/assigned", rephist,
+ "Assigned TAP circuit handshake stats."),
+ ITEM("stats/tap/requested", rephist,
+ "Requested TAP circuit handshake stats."),
{ NULL, NULL, NULL, 0 }
};
diff --git a/src/feature/control/control_getinfo.h b/src/feature/control/control_getinfo.h
index 0ada49258e..f61d632446 100644
--- a/src/feature/control/control_getinfo.h
+++ b/src/feature/control/control_getinfo.h
@@ -60,6 +60,10 @@ STATIC int getinfo_helper_current_time(
control_connection_t *control_conn,
const char *question, char **answer,
const char **errmsg);
+STATIC int getinfo_helper_rephist(
+ control_connection_t *control_conn,
+ const char *question, char **answer,
+ const char **errmsg);
#endif /* defined(CONTROL_GETINFO_PRIVATE) */
#endif /* !defined(TOR_CONTROL_GETINFO_H) */
diff --git a/src/feature/dirauth/dirauth_config.c b/src/feature/dirauth/dirauth_config.c
index a0b6de7eca..1ffd33e5f1 100644
--- a/src/feature/dirauth/dirauth_config.c
+++ b/src/feature/dirauth/dirauth_config.c
@@ -77,8 +77,8 @@ options_validate_dirauth_mode(const or_options_t *old_options,
return 0;
/* confirm that our address isn't broken, so we can complain now */
- uint32_t tmp;
- if (resolve_my_address(LOG_WARN, options, &tmp, NULL, NULL) < 0)
+ tor_addr_t tmp;
+ if (!find_my_address(options, AF_INET, LOG_WARN, &tmp, NULL, NULL))
REJECT("Failed to resolve/guess local address. See logs for details.");
if (!options->ContactInfo && !options->TestingTorNetwork)
diff --git a/src/feature/dirauth/dirauth_options.inc b/src/feature/dirauth/dirauth_options.inc
index 21f4996c39..40ef7c3bab 100644
--- a/src/feature/dirauth/dirauth_options.inc
+++ b/src/feature/dirauth/dirauth_options.inc
@@ -44,6 +44,13 @@ CONF_VAR(AuthDirSharedRandomness, BOOL, 0, "1")
/* NOTE: remove this option someday. */
CONF_VAR(AuthDirTestEd25519LinkKeys, BOOL, 0, "1")
+/**
+ * Bool (default 1): As an authority, should we launch tests for
+ * reachability, and use those results to vote on "Running"? If 0,
+ * we assume that every relay is Runnning.
+ **/
+CONF_VAR(AuthDirTestReachability, BOOL, 0, "1")
+
/** Authority only: key=value pairs that we add to our networkstatus
* consensus vote on the 'params' line. */
CONF_VAR(ConsensusParams, STRING, 0, NULL)
diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c
index 79651563b4..8676df76ab 100644
--- a/src/feature/dirauth/dirvote.c
+++ b/src/feature/dirauth/dirvote.c
@@ -225,7 +225,6 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
smartlist_t *chunks = smartlist_new();
char fingerprint[FINGERPRINT_LEN+1];
char digest[DIGEST_LEN];
- uint32_t addr;
char *protocols_lines = NULL;
char *client_versions_line = NULL, *server_versions_line = NULL;
char *shared_random_vote_str = NULL;
@@ -237,8 +236,6 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
voter = smartlist_get(v3_ns->voters, 0);
- addr = voter->addr;
-
base16_encode(fingerprint, sizeof(fingerprint),
v3_ns->cert->cache_info.identity_digest, DIGEST_LEN);
@@ -322,7 +319,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
tor_free(digest_algo_b64_digest_bw_file);
}
- const char *ip_str = fmt_addr32(addr);
+ const char *ip_str = fmt_addr(&voter->ipv4_addr);
if (ip_str[0]) {
smartlist_add_asprintf(chunks,
@@ -358,7 +355,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
bw_headers_line ? bw_headers_line : "",
bw_file_digest ? bw_file_digest: "",
voter->nickname, fingerprint, voter->address,
- ip_str, voter->dir_port, voter->or_port,
+ ip_str, voter->ipv4_dirport, voter->ipv4_orport,
voter->contact,
shared_random_vote_str ?
shared_random_vote_str : "");
@@ -636,9 +633,12 @@ compare_vote_rs(const vote_routerstatus_t *a, const vote_routerstatus_t *b)
if ((r = strcmp(b->status.nickname, a->status.nickname)))
return r;
- CMP_FIELD(unsigned, int, addr);
- CMP_FIELD(unsigned, int, or_port);
- CMP_FIELD(unsigned, int, dir_port);
+ if ((r = tor_addr_compare(&a->status.ipv4_addr, &b->status.ipv4_addr,
+ CMP_EXACT))) {
+ return r;
+ }
+ CMP_FIELD(unsigned, int, ipv4_orport);
+ CMP_FIELD(unsigned, int, ipv4_dirport);
return 0;
}
@@ -1740,9 +1740,9 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_add_asprintf(chunks,
"dir-source %s%s %s %s %s %d %d\n",
voter->nickname, e->is_legacy ? "-legacy" : "",
- fingerprint, voter->address, fmt_addr32(voter->addr),
- voter->dir_port,
- voter->or_port);
+ fingerprint, voter->address, fmt_addr(&voter->ipv4_addr),
+ voter->ipv4_dirport,
+ voter->ipv4_orport);
if (! e->is_legacy) {
smartlist_add_asprintf(chunks,
"contact %s\n"
@@ -2039,10 +2039,10 @@ networkstatus_compute_consensus(smartlist_t *votes,
memcpy(rs_out.identity_digest, current_rsa_id, DIGEST_LEN);
memcpy(rs_out.descriptor_digest, rs->status.descriptor_digest,
DIGEST_LEN);
- rs_out.addr = rs->status.addr;
+ tor_addr_copy(&rs_out.ipv4_addr, &rs->status.ipv4_addr);
rs_out.published_on = rs->status.published_on;
- rs_out.dir_port = rs->status.dir_port;
- rs_out.or_port = rs->status.or_port;
+ rs_out.ipv4_dirport = rs->status.ipv4_dirport;
+ rs_out.ipv4_orport = rs->status.ipv4_orport;
tor_addr_copy(&rs_out.ipv6_addr, &alt_orport.addr);
rs_out.ipv6_orport = alt_orport.port;
rs_out.has_bandwidth = 0;
@@ -3848,11 +3848,10 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
smartlist_add_asprintf(chunks, "onion-key\n%s", key);
if (ri->onion_curve25519_pkey) {
- char kbuf[128];
- base64_encode(kbuf, sizeof(kbuf),
- (const char*)ri->onion_curve25519_pkey->public_key,
- CURVE25519_PUBKEY_LEN, BASE64_ENCODE_MULTILINE);
- smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
+ char kbuf[CURVE25519_BASE64_PADDED_LEN + 1];
+ bool add_padding = (consensus_method < MIN_METHOD_FOR_UNPADDED_NTOR_KEY);
+ curve25519_public_to_base64(kbuf, ri->onion_curve25519_pkey, add_padding);
+ smartlist_add_asprintf(chunks, "ntor-onion-key %s\n", kbuf);
}
if (family) {
@@ -3963,6 +3962,8 @@ static const struct consensus_method_range_t {
{MIN_SUPPORTED_CONSENSUS_METHOD,
MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS - 1},
{MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS,
+ MIN_METHOD_FOR_UNPADDED_NTOR_KEY - 1},
+ {MIN_METHOD_FOR_UNPADDED_NTOR_KEY,
MAX_SUPPORTED_CONSENSUS_METHOD},
{-1, -1}
};
@@ -4219,12 +4220,14 @@ compare_routerinfo_by_ip_and_bw_(const void **a, const void **b)
uint32_t bw_kb_first, bw_kb_second;
const node_t *node_first, *node_second;
int first_is_running, second_is_running;
+ uint32_t first_ipv4h = tor_addr_to_ipv4h(&first->ipv4_addr);
+ uint32_t second_ipv4h = tor_addr_to_ipv4h(&second->ipv4_addr);
/* we return -1 if first should appear before second... that is,
* if first is a better router. */
- if (first->addr < second->addr)
+ if (first_ipv4h < second_ipv4h)
return -1;
- else if (first->addr > second->addr)
+ else if (first_ipv4h > second_ipv4h)
return 1;
/* Potentially, this next bit could cause k n lg n memeq calls. But in
@@ -4275,7 +4278,7 @@ get_possible_sybil_list(const smartlist_t *routers)
const dirauth_options_t *options = dirauth_get_options();
digestmap_t *omit_as_sybil;
smartlist_t *routers_by_ip = smartlist_new();
- uint32_t last_addr;
+ tor_addr_t last_addr = TOR_ADDR_NULL;
int addr_count;
/* Allow at most this number of Tor servers on a single IP address, ... */
int max_with_same_addr = options->AuthDirMaxServersPerAddr;
@@ -4286,11 +4289,10 @@ get_possible_sybil_list(const smartlist_t *routers)
smartlist_sort(routers_by_ip, compare_routerinfo_by_ip_and_bw_);
omit_as_sybil = digestmap_new();
- last_addr = 0;
addr_count = 0;
SMARTLIST_FOREACH_BEGIN(routers_by_ip, routerinfo_t *, ri) {
- if (last_addr != ri->addr) {
- last_addr = ri->addr;
+ if (!tor_addr_eq(&last_addr, &ri->ipv4_addr)) {
+ tor_addr_copy(&last_addr, &ri->ipv4_addr);
addr_count = 1;
} else if (++addr_count > max_with_same_addr) {
digestmap_set(omit_as_sybil, ri->cache_info.identity_digest, ri);
@@ -4463,7 +4465,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
const or_options_t *options = get_options();
const dirauth_options_t *d_options = dirauth_get_options();
networkstatus_t *v3_out = NULL;
- uint32_t addr;
+ tor_addr_t addr;
char *hostname = NULL, *client_versions = NULL, *server_versions = NULL;
const char *contact;
smartlist_t *routers, *routerstatuses;
@@ -4492,13 +4494,13 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
log_err(LD_BUG, "Error computing identity key digest");
return NULL;
}
- if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) {
+ if (!find_my_address(options, AF_INET, LOG_WARN, &addr, NULL, &hostname)) {
log_warn(LD_NET, "Couldn't resolve my hostname");
return NULL;
}
if (!hostname || !strchr(hostname, '.')) {
tor_free(hostname);
- hostname = tor_dup_ip(addr);
+ hostname = tor_addr_to_str_dup(&addr);
}
if (!hostname) {
@@ -4565,7 +4567,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
/* If it has a protover list and contains a protocol name greater than
* MAX_PROTOCOL_NAME_LENGTH, skip it. */
if (ri->protocol_list &&
- protover_contains_long_protocol_names(ri->protocol_list)) {
+ protover_list_is_invalid(ri->protocol_list)) {
continue;
}
if (ri->cache_info.published_on >= cutoff) {
@@ -4722,9 +4724,9 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
memcpy(voter->identity_digest, identity_digest, DIGEST_LEN);
voter->sigs = smartlist_new();
voter->address = hostname;
- voter->addr = addr;
- voter->dir_port = router_get_advertised_dir_port(options, 0);
- voter->or_port = router_get_advertised_or_port(options);
+ tor_addr_copy(&voter->ipv4_addr, &addr);
+ voter->ipv4_dirport = routerconf_find_dir_port(options, 0);
+ voter->ipv4_orport = routerconf_find_or_port(options, AF_INET);
voter->contact = tor_strdup(contact);
if (options->V3AuthUseLegacyKey) {
authority_cert_t *c = get_my_v3_legacy_cert();
diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h
index 1b1c9f2cc7..9cc87489b4 100644
--- a/src/feature/dirauth/dirvote.h
+++ b/src/feature/dirauth/dirvote.h
@@ -53,7 +53,7 @@
#define MIN_SUPPORTED_CONSENSUS_METHOD 28
/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 29
+#define MAX_SUPPORTED_CONSENSUS_METHOD 30
/**
* Lowest consensus method where microdescriptor lines are put in canonical
@@ -61,6 +61,10 @@
**/
#define MIN_METHOD_FOR_CANONICAL_FAMILIES_IN_MICRODESCS 29
+/** Lowest consensus method where an unpadded base64 onion-key-ntor is allowed
+ * See #7869 */
+#define MIN_METHOD_FOR_UNPADDED_NTOR_KEY 30
+
/** Default bandwidth to clip unmeasured bandwidths to using method >=
* MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not
* get confused with the above macros.) */
diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c
index 5025d0ae39..b08ffeba07 100644
--- a/src/feature/dirauth/process_descs.c
+++ b/src/feature/dirauth/process_descs.c
@@ -56,8 +56,9 @@ static was_router_added_t dirserv_add_extrainfo(extrainfo_t *ei,
static uint32_t
dirserv_get_status_impl(const char *id_digest,
const ed25519_public_key_t *ed25519_public_key,
- const char *nickname, uint32_t addr, uint16_t or_port,
- const char *platform, const char **msg, int severity);
+ const char *nickname, const tor_addr_t *ipv4_addr,
+ uint16_t ipv4_orport, const char *platform,
+ const char **msg, int severity);
/** Should be static; exposed for testing. */
static authdir_config_t *fingerprint_list = NULL;
@@ -307,9 +308,9 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg,
/* This has an ed25519 identity key. */
signing_key = &router->cache_info.signing_key_cert->signing_key;
}
- r = dirserv_get_status_impl(d, signing_key, router->nickname, router->addr,
- router->or_port, router->platform, msg,
- severity);
+ r = dirserv_get_status_impl(d, signing_key, router->nickname,
+ &router->ipv4_addr, router->ipv4_orport,
+ router->platform, msg, severity);
if (r)
return r;
@@ -378,7 +379,8 @@ dirserv_would_reject_router(const routerstatus_t *rs,
memcpy(&pk.pubkey, vrs->ed25519_id, ED25519_PUBKEY_LEN);
res = dirserv_get_status_impl(rs->identity_digest, &pk, rs->nickname,
- rs->addr, rs->or_port, NULL, NULL, LOG_DEBUG);
+ &rs->ipv4_addr, rs->ipv4_orport, NULL, NULL,
+ LOG_DEBUG);
return (res & RTR_REJECT) != 0;
}
@@ -409,11 +411,11 @@ dirserv_rejects_tor_version(const char *platform,
return true;
}
- /* Series between Tor 0.3.6 and 0.4.1.4-rc inclusive are unsupported.
- * Reject them. 0.3.6.0-alpha-dev only existed for a short time, before
- * it was renamed to 0.4.0.0-alpha-dev. */
+ /* Series between Tor 0.3.6 and 0.4.1 inclusive are unsupported. Reject
+ * them. 0.3.6.0-alpha-dev only existed for a short time, before it was
+ * renamed to 0.4.0.0-alpha-dev. */
if (tor_version_as_new_as(platform,"0.3.6.0-alpha-dev") &&
- !tor_version_as_new_as(platform,"0.4.1.5")) {
+ !tor_version_as_new_as(platform,"0.4.2.1-alpha")) {
if (msg) {
*msg = please_upgrade_string;
}
@@ -433,8 +435,9 @@ dirserv_rejects_tor_version(const char *platform,
static uint32_t
dirserv_get_status_impl(const char *id_digest,
const ed25519_public_key_t *ed25519_public_key,
- const char *nickname, uint32_t addr, uint16_t or_port,
- const char *platform, const char **msg, int severity)
+ const char *nickname, const tor_addr_t *ipv4_addr,
+ uint16_t ipv4_orport, const char *platform,
+ const char **msg, int severity)
{
uint32_t result = 0;
rtr_flags_t *status_by_digest;
@@ -485,16 +488,16 @@ dirserv_get_status_impl(const char *id_digest,
*msg = "Fingerprint and/or ed25519 identity is marked invalid";
}
- if (authdir_policy_badexit_address(addr, or_port)) {
+ if (authdir_policy_badexit_address(ipv4_addr, ipv4_orport)) {
log_fn(severity, LD_DIRSERV,
"Marking '%s' as bad exit because of address '%s'",
- nickname, fmt_addr32(addr));
+ nickname, fmt_addr(ipv4_addr));
result |= RTR_BADEXIT;
}
- if (!authdir_policy_permits_address(addr, or_port)) {
+ if (!authdir_policy_permits_address(ipv4_addr, ipv4_orport)) {
log_fn(severity, LD_DIRSERV, "Rejecting '%s' because of address '%s'",
- nickname, fmt_addr32(addr));
+ nickname, fmt_addr(ipv4_addr));
if (msg)
*msg = "Suspicious relay address range -- if you think this is a "
"mistake please set a valid email address in ContactInfo and "
@@ -502,10 +505,10 @@ dirserv_get_status_impl(const char *id_digest,
"your address(es) and fingerprint(s)?";
return RTR_REJECT;
}
- if (!authdir_policy_valid_address(addr, or_port)) {
+ if (!authdir_policy_valid_address(ipv4_addr, ipv4_orport)) {
log_fn(severity, LD_DIRSERV,
"Not marking '%s' valid because of address '%s'",
- nickname, fmt_addr32(addr));
+ nickname, fmt_addr(ipv4_addr));
result |= RTR_INVALID;
}
@@ -534,13 +537,11 @@ dirserv_free_fingerprint_list(void)
STATIC int
dirserv_router_has_valid_address(routerinfo_t *ri)
{
- tor_addr_t addr;
-
if (get_options()->DirAllowPrivateAddresses)
return 0; /* whatever it is, we're fine with it */
- tor_addr_from_ipv4h(&addr, ri->addr);
- if (tor_addr_is_null(&addr) || tor_addr_is_internal(&addr, 0)) {
+ if (tor_addr_is_null(&ri->ipv4_addr) ||
+ tor_addr_is_internal(&ri->ipv4_addr, 0)) {
log_info(LD_DIRSERV,
"Router %s published internal IPv4 address. Refusing.",
router_describe(ri));
diff --git a/src/feature/dirauth/reachability.c b/src/feature/dirauth/reachability.c
index 65fa27ed80..eb88b4aa07 100644
--- a/src/feature/dirauth/reachability.c
+++ b/src/feature/dirauth/reachability.c
@@ -84,7 +84,7 @@ dirserv_orconn_tls_done(const tor_addr_t *addr,
log_info(LD_DIRSERV, "Found router %s to be reachable at %s:%d. Yay.",
router_describe(ri),
tor_addr_to_str(addrstr, addr, sizeof(addrstr), 1),
- ri->or_port);
+ ri->ipv4_orport);
if (tor_addr_family(addr) == AF_INET) {
rep_hist_note_router_reachable(digest_rcvd, addr, or_port, now);
node->last_reachable = now;
@@ -105,6 +105,8 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri,
{
if (!authdir_mode_handles_descs(get_options(), ri->purpose))
return 0;
+ if (! dirauth_get_options()->AuthDirTestReachability)
+ return 0;
if (!ri_old) {
/* New router: Launch an immediate reachability test, so we will have an
* opinion soon in case we're generating a consensus soon */
@@ -130,7 +132,6 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router)
const dirauth_options_t *dirauth_options = dirauth_get_options();
channel_t *chan = NULL;
const node_t *node = NULL;
- tor_addr_t router_addr;
const ed25519_public_key_t *ed_id_key;
(void) now;
@@ -148,9 +149,9 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router)
/* IPv4. */
log_debug(LD_OR,"Testing reachability of %s at %s:%u.",
- router->nickname, fmt_addr32(router->addr), router->or_port);
- tor_addr_from_ipv4h(&router_addr, router->addr);
- chan = channel_tls_connect(&router_addr, router->or_port,
+ router->nickname, fmt_addr(&router->ipv4_addr),
+ router->ipv4_orport);
+ chan = channel_tls_connect(&router->ipv4_addr, router->ipv4_orport,
router->cache_info.identity_digest,
ed_id_key);
if (chan) command_setup_channel(chan);
@@ -189,6 +190,9 @@ dirserv_test_reachability(time_t now)
* the testing, and directory authorities are easy to upgrade. Let's
* wait til 0.2.0. -RD */
// time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
+ if (! dirauth_get_options()->AuthDirTestReachability)
+ return;
+
routerlist_t *rl = router_get_routerlist();
static char ctr = 0;
int bridge_auth = authdir_mode_bridge(get_options());
diff --git a/src/feature/dirauth/voteflags.c b/src/feature/dirauth/voteflags.c
index 477eb6f0b7..3938b61adb 100644
--- a/src/feature/dirauth/voteflags.c
+++ b/src/feature/dirauth/voteflags.c
@@ -487,7 +487,6 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
unreachable.
*/
int answer;
- const or_options_t *options = get_options();
const dirauth_options_t *dirauth_options = dirauth_get_options();
node_t *node = node_get_mutable_by_id(router->cache_info.identity_digest);
tor_assert(node);
@@ -501,8 +500,9 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
/* A hibernating router is down unless we (somehow) had contact with it
* since it declared itself to be hibernating. */
answer = 0;
- } else if (options->AssumeReachable) {
- /* If AssumeReachable, everybody is up unless they say they are down! */
+ } else if (! dirauth_options->AuthDirTestReachability) {
+ /* If we aren't testing reachability, then everybody is up unless they say
+ * they are down. */
answer = 1;
} else {
/* Otherwise, a router counts as up if we found all announced OR
diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c
index ca127720f2..efcae41084 100644
--- a/src/feature/dircache/dircache.c
+++ b/src/feature/dircache/dircache.c
@@ -142,7 +142,7 @@ write_http_response_header_impl(dir_connection_t *conn, ssize_t length,
if (type) {
buf_add_printf(buf, "Content-Type: %s\r\n", type);
}
- if (!is_local_addr(&conn->base_.addr)) {
+ if (!is_local_to_resolve_addr(&conn->base_.addr)) {
/* Don't report the source address for a nearby/private connection.
* Otherwise we tend to mis-report in cases where incoming ports are
* being forwarded to a Tor server running behind the firewall. */
@@ -1614,7 +1614,8 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers,
if (!public_server_mode(options)) {
log_info(LD_DIR, "Rejected dir post request from %s "
- "since we're not a public relay.", conn->base_.address);
+ "since we're not a public relay.",
+ connection_describe_peer(TO_CONN(conn)));
write_short_http_response(conn, 503, "Not acting as a public relay");
goto done;
}
@@ -1630,7 +1631,8 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers,
!strcmpstart(url,"/tor/rendezvous2/publish")) {
if (rend_cache_store_v2_desc_as_dir(body) < 0) {
log_warn(LD_REND, "Rejected v2 rend descriptor (body size %d) from %s.",
- (int)body_len, conn->base_.address);
+ (int)body_len,
+ connection_describe_peer(TO_CONN(conn)));
write_short_http_response(conn, 400,
"Invalid v2 service descriptor rejected");
} else {
@@ -1686,7 +1688,8 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers,
log_info(LD_DIRSERV,
"Rejected router descriptor or extra-info from %s "
"(\"%s\").",
- conn->base_.address, msg);
+ connection_describe_peer(TO_CONN(conn)),
+ msg);
write_short_http_response(conn, 400, msg);
}
goto done;
@@ -1701,7 +1704,8 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers,
} else {
tor_assert(msg);
log_warn(LD_DIRSERV, "Rejected vote from %s (\"%s\").",
- conn->base_.address, msg);
+ connection_describe_peer(TO_CONN(conn)),
+ msg);
write_short_http_response(conn, status, msg);
}
goto done;
@@ -1714,7 +1718,8 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers,
write_short_http_response(conn, 200, msg?msg:"Signatures stored");
} else {
log_warn(LD_DIR, "Unable to store signatures posted by %s: %s",
- conn->base_.address, msg?msg:"???");
+ connection_describe_peer(TO_CONN(conn)),
+ msg?msg:"???");
write_short_http_response(conn, 400,
msg?msg:"Unable to store signatures");
}
@@ -1775,8 +1780,8 @@ directory_handle_command(dir_connection_t *conn)
&body, &body_len, MAX_DIR_UL_SIZE, 0)) {
case -1: /* overflow */
log_warn(LD_DIRSERV,
- "Request too large from address '%s' to DirPort. Closing.",
- safe_str(conn->base_.address));
+ "Request too large from %s to DirPort. Closing.",
+ connection_describe_peer(TO_CONN(conn)));
return -1;
case 0:
log_debug(LD_DIRSERV,"command not all here yet.");
diff --git a/src/feature/dirclient/dir_server_st.h b/src/feature/dirclient/dir_server_st.h
index 37fa3148a7..57530a571b 100644
--- a/src/feature/dirclient/dir_server_st.h
+++ b/src/feature/dirclient/dir_server_st.h
@@ -24,10 +24,10 @@ struct dir_server_t {
char *address; /**< Hostname. */
/* XX/teor - why do we duplicate the address and port fields here and in
* fake_status? Surely we could just use fake_status (#17867). */
+ tor_addr_t ipv4_addr;
+ uint16_t ipv4_dirport; /**< Directory port. */
+ uint16_t ipv4_orport; /**< OR port: Used for tunneling connections. */
tor_addr_t ipv6_addr; /**< IPv6 address if present; AF_UNSPEC if not */
- uint32_t addr; /**< IPv4 address. */
- uint16_t dir_port; /**< Directory port. */
- uint16_t or_port; /**< OR port: Used for tunneling connections. */
uint16_t ipv6_orport; /**< OR port corresponding to ipv6_addr. */
double weight; /** Weight used when selecting this node at random */
char digest[DIGEST_LEN]; /**< Digest of identity key. */
diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c
index ae1e018df2..f088ef8283 100644
--- a/src/feature/dirclient/dirclient.c
+++ b/src/feature/dirclient/dirclient.c
@@ -284,10 +284,10 @@ directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
}
if (purpose_needs_anonymity(dir_purpose, router_purpose, NULL)) {
indirection = DIRIND_ANONYMOUS;
- } else if (!fascist_firewall_allows_dir_server(ds,
+ } else if (!reachable_addr_allows_dir_server(ds,
FIREWALL_DIR_CONNECTION,
0)) {
- if (fascist_firewall_allows_dir_server(ds, FIREWALL_OR_CONNECTION, 0))
+ if (reachable_addr_allows_dir_server(ds, FIREWALL_OR_CONNECTION, 0))
indirection = DIRIND_ONEHOP;
else
indirection = DIRIND_ANONYMOUS;
@@ -487,7 +487,7 @@ directory_get_from_dirserver,(
tor_addr_port_t or_ap;
directory_request_t *req = directory_request_new(dir_purpose);
/* we are willing to use a non-preferred address if we need to */
- fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0,
+ reachable_addr_choose_from_node(node, FIREWALL_OR_CONNECTION, 0,
&or_ap);
directory_request_set_or_addr_port(req, &or_ap);
directory_request_set_directory_id_digest(req,
@@ -654,11 +654,11 @@ directory_choose_address_routerstatus(const routerstatus_t *status,
/* ORPort connections */
if (indirection == DIRIND_ANONYMOUS) {
- if (status->addr) {
+ if (!tor_addr_is_null(&status->ipv4_addr)) {
/* Since we're going to build a 3-hop circuit and ask the 2nd relay
* to extend to this address, always use the primary (IPv4) OR address */
- tor_addr_from_ipv4h(&use_or_ap->addr, status->addr);
- use_or_ap->port = status->or_port;
+ tor_addr_copy(&use_or_ap->addr, &status->ipv4_addr);
+ use_or_ap->port = status->ipv4_orport;
have_or = 1;
}
} else if (indirection == DIRIND_ONEHOP) {
@@ -666,7 +666,7 @@ directory_choose_address_routerstatus(const routerstatus_t *status,
* Use the preferred address and port if they are reachable, otherwise,
* use the alternate address and port (if any).
*/
- fascist_firewall_choose_address_rs(status, FIREWALL_OR_CONNECTION, 0,
+ reachable_addr_choose_from_rs(status, FIREWALL_OR_CONNECTION, 0,
use_or_ap);
have_or = tor_addr_port_is_valid_ap(use_or_ap, 0);
}
@@ -677,7 +677,7 @@ directory_choose_address_routerstatus(const routerstatus_t *status,
indirection == DIRIND_ANON_DIRPORT ||
(indirection == DIRIND_ONEHOP
&& !dirclient_must_use_begindir(options))) {
- fascist_firewall_choose_address_rs(status, FIREWALL_DIR_CONNECTION, 0,
+ reachable_addr_choose_from_rs(status, FIREWALL_DIR_CONNECTION, 0,
use_dir_ap);
have_dir = tor_addr_port_is_valid_ap(use_dir_ap, 0);
}
@@ -686,12 +686,14 @@ directory_choose_address_routerstatus(const routerstatus_t *status,
* connect to it. */
if (!have_or && !have_dir) {
static int logged_backtrace = 0;
+ char *ipv6_str = tor_addr_to_str_dup(&status->ipv6_addr);
log_info(LD_BUG, "Rejected all OR and Dir addresses from %s when "
"launching an outgoing directory connection to: IPv4 %s OR %d "
"Dir %d IPv6 %s OR %d Dir %d", routerstatus_describe(status),
- fmt_addr32(status->addr), status->or_port,
- status->dir_port, fmt_addr(&status->ipv6_addr),
- status->ipv6_orport, status->dir_port);
+ fmt_addr(&status->ipv4_addr), status->ipv4_orport,
+ status->ipv4_dirport, ipv6_str, status->ipv6_orport,
+ status->ipv4_dirport);
+ tor_free(ipv6_str);
if (!logged_backtrace) {
log_backtrace(LOG_INFO, LD_BUG, "Addresses came from");
logged_backtrace = 1;
@@ -713,8 +715,8 @@ directory_conn_is_self_reachability_test(dir_connection_t *conn)
const routerinfo_t *me = router_get_my_routerinfo();
if (me &&
router_digest_is_me(conn->identity_digest) &&
- tor_addr_eq_ipv4h(&conn->base_.addr, me->addr) && /*XXXX prop 118*/
- me->dir_port == conn->base_.port)
+ tor_addr_eq(&TO_CONN(conn)->addr, &me->ipv4_addr) &&
+ me->ipv4_dirport == conn->base_.port)
return 1;
}
return 0;
@@ -740,8 +742,8 @@ connection_dir_client_request_failed(dir_connection_t *conn)
if (conn->base_.purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
conn->base_.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) {
log_info(LD_DIR, "Giving up on serverdesc/extrainfo fetch from "
- "directory server at '%s'; retrying",
- conn->base_.address);
+ "directory server at %s; retrying",
+ connection_describe_peer(TO_CONN(conn)));
if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE)
connection_dir_bridge_routerdesc_failed(conn);
connection_dir_download_routerdesc_failed(conn);
@@ -750,18 +752,19 @@ connection_dir_client_request_failed(dir_connection_t *conn)
networkstatus_consensus_download_failed(0, conn->requested_resource);
} else if (conn->base_.purpose == DIR_PURPOSE_FETCH_CERTIFICATE) {
log_info(LD_DIR, "Giving up on certificate fetch from directory server "
- "at '%s'; retrying",
- conn->base_.address);
+ "at %s; retrying",
+ connection_describe_peer(TO_CONN(conn)));
connection_dir_download_cert_failed(conn, 0);
} else if (conn->base_.purpose == DIR_PURPOSE_FETCH_DETACHED_SIGNATURES) {
- log_info(LD_DIR, "Giving up downloading detached signatures from '%s'",
- conn->base_.address);
+ log_info(LD_DIR, "Giving up downloading detached signatures from %s",
+ connection_describe_peer(TO_CONN(conn)));
} else if (conn->base_.purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) {
- log_info(LD_DIR, "Giving up downloading votes from '%s'",
- conn->base_.address);
+ log_info(LD_DIR, "Giving up downloading votes from %s",
+ connection_describe_peer(TO_CONN(conn)));
} else if (conn->base_.purpose == DIR_PURPOSE_FETCH_MICRODESC) {
log_info(LD_DIR, "Giving up on downloading microdescriptors from "
- "directory server at '%s'; will retry", conn->base_.address);
+ "directory server at %s; will retry",
+ connection_describe_peer(TO_CONN(conn)));
connection_dir_download_routerdesc_failed(conn);
}
}
@@ -918,7 +921,7 @@ directory_command_should_use_begindir(const or_options_t *options,
}
if (indirection == DIRIND_ONEHOP) {
/* We're firewalled and want a direct OR connection */
- if (!fascist_firewall_allows_address_addr(or_addr, or_port,
+ if (!reachable_addr_allows_addr(or_addr, or_port,
FIREWALL_OR_CONNECTION, 0, 0)) {
*reason = "ORPort not reachable";
return 0;
@@ -1754,10 +1757,10 @@ directory_send_command(dir_connection_t *conn,
smartlist_free(headers);
log_debug(LD_DIR,
- "Sent request to directory server '%s:%d': "
+ "Sent request to directory server %s "
"(purpose: %d, request size: %"TOR_PRIuSZ", "
"payload size: %"TOR_PRIuSZ")",
- conn->base_.address, conn->base_.port,
+ connection_describe_peer(TO_CONN(conn)),
conn->base_.purpose,
(total_request_len),
(payload ? payload_len : 0));
@@ -1893,9 +1896,10 @@ dir_client_decompress_response_body(char **bodyp, size_t *bodylenp,
}
tor_log(severity, LD_HTTP,
- "HTTP body from server '%s:%d' was labeled as %s, "
+ "HTTP body from %s was labeled as %s, "
"%s it seems to be %s.%s",
- conn->base_.address, conn->base_.port, description1,
+ connection_describe(TO_CONN(conn)),
+ description1,
guessed != compression?"but":"and",
description2,
(compression>0 && guessed>0 && want_to_try_both)?
@@ -1941,11 +1945,11 @@ dir_client_decompress_response_body(char **bodyp, size_t *bodylenp,
* we didn't manage to uncompress it, then warn and bail. */
if (!plausible && !new_body) {
log_fn(LOG_PROTOCOL_WARN, LD_HTTP,
- "Unable to decompress HTTP body (tried %s%s%s, server '%s:%d').",
+ "Unable to decompress HTTP body (tried %s%s%s, on %s).",
description1,
tried_both?" and ":"",
tried_both?description2:"",
- conn->base_.address, conn->base_.port);
+ connection_describe(TO_CONN(conn)));
rv = -1;
goto done;
}
@@ -2052,8 +2056,8 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
allow_partial)) {
case -1: /* overflow */
log_warn(LD_PROTOCOL,
- "'fetch' response too large (server '%s:%d'). Closing.",
- conn->base_.address, conn->base_.port);
+ "'fetch' response too large (%s). Closing.",
+ connection_describe(TO_CONN(conn)));
return -1;
case 0:
log_info(LD_HTTP,
@@ -2064,22 +2068,22 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
if (parse_http_response(headers, &status_code, &date_header,
&compression, &reason) < 0) {
- log_warn(LD_HTTP,"Unparseable headers (server '%s:%d'). Closing.",
- conn->base_.address, conn->base_.port);
-
+ log_warn(LD_HTTP,"Unparseable headers (%s). Closing.",
+ connection_describe(TO_CONN(conn)));
rv = -1;
goto done;
}
if (!reason) reason = tor_strdup("[no reason given]");
tor_log(LOG_DEBUG, LD_DIR,
- "Received response from directory server '%s:%d': %d %s "
+ "Received response on %s: %d %s "
"(purpose: %d, response size: %"TOR_PRIuSZ
#ifdef MEASUREMENTS_21206
", data cells received: %d, data cells sent: %d"
#endif
", compression: %d)",
- conn->base_.address, conn->base_.port, status_code,
+ connection_describe(TO_CONN(conn)),
+ status_code,
escaped(reason), conn->base_.purpose,
(received_bytes),
#ifdef MEASUREMENTS_21206
@@ -2104,7 +2108,13 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
if (conn->dirconn_direct) {
char *guess = http_get_header(headers, X_ADDRESS_HEADER);
if (guess) {
- router_new_address_suggestion(guess, conn);
+ tor_addr_t addr;
+ if (tor_addr_parse(&addr, guess) < 0) {
+ log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.",
+ escaped(guess));
+ } else {
+ relay_address_new_suggestion(&addr, &TO_CONN(conn)->addr, NULL);
+ }
tor_free(guess);
}
}
@@ -2133,9 +2143,9 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
dir_server_t *ds;
const char *id_digest = conn->identity_digest;
log_info(LD_DIR,"Received http status code %d (%s) from server "
- "'%s:%d'. I'll try again soon.",
- status_code, escaped(reason), conn->base_.address,
- conn->base_.port);
+ "%s. I'll try again soon.",
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)));
time_t now = approx_time();
if ((rs = router_get_mutable_consensus_status_by_id(id_digest)))
rs->last_dir_503_at = now;
@@ -2240,9 +2250,9 @@ handle_response_fetch_consensus(dir_connection_t *conn,
int severity = (status_code == 304) ? LOG_INFO : LOG_WARN;
tor_log(severity, LD_DIR,
"Received http status code %d (%s) from server "
- "'%s:%d' while fetching consensus directory.",
- status_code, escaped(reason), conn->base_.address,
- conn->base_.port);
+ "%s while fetching consensus directory.",
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)));
networkstatus_consensus_download_failed(status_code, flavname);
return -1;
}
@@ -2277,21 +2287,21 @@ handle_response_fetch_consensus(dir_connection_t *conn,
tor_munmap_file(mapped_consensus);
if (new_consensus == NULL) {
log_warn(LD_DIR, "Could not apply consensus diff received from server "
- "'%s:%d'", conn->base_.address, conn->base_.port);
+ "%s", connection_describe_peer(TO_CONN(conn)));
// XXXX If this happens too many times, we should maybe not use
// XXXX this directory for diffs any more?
networkstatus_consensus_download_failed(0, flavname);
return -1;
}
log_info(LD_DIR, "Applied consensus diff (size %d) from server "
- "'%s:%d', resulting in a new consensus document (size %d).",
- (int)body_len, conn->base_.address, conn->base_.port,
+ "%s, resulting in a new consensus document (size %d).",
+ (int)body_len, connection_describe_peer(TO_CONN(conn)),
(int)strlen(new_consensus));
consensus = new_consensus;
sourcename = "generated based on a diff";
} else {
log_info(LD_DIR,"Received consensus directory (body size %d) from server "
- "'%s:%d'", (int)body_len, conn->base_.address, conn->base_.port);
+ "%s", (int)body_len, connection_describe_peer(TO_CONN(conn)));
consensus = body;
sourcename = "downloaded";
}
@@ -2302,8 +2312,9 @@ handle_response_fetch_consensus(dir_connection_t *conn,
conn->identity_digest))<0) {
log_fn(r<-1?LOG_WARN:LOG_INFO, LD_DIR,
"Unable to load %s consensus directory %s from "
- "server '%s:%d'. I'll try again soon.",
- flavname, sourcename, conn->base_.address, conn->base_.port);
+ "server %s. I'll try again soon.",
+ flavname, sourcename,
+ connection_describe_peer(TO_CONN(conn)));
networkstatus_consensus_download_failed(0, flavname);
tor_free(new_consensus);
return -1;
@@ -2344,15 +2355,16 @@ handle_response_fetch_certificate(dir_connection_t *conn,
if (status_code != 200) {
log_warn(LD_DIR,
"Received http status code %d (%s) from server "
- "'%s:%d' while fetching \"/tor/keys/%s\".",
- status_code, escaped(reason), conn->base_.address,
- conn->base_.port, conn->requested_resource);
+ "%s while fetching \"/tor/keys/%s\".",
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)),
+ conn->requested_resource);
connection_dir_download_cert_failed(conn, status_code);
return -1;
}
log_info(LD_DIR,"Received authority certificates (body size %d) from "
- "server '%s:%d'",
- (int)body_len, conn->base_.address, conn->base_.port);
+ "server %s",
+ (int)body_len, connection_describe_peer(TO_CONN(conn)));
/*
* Tell trusted_dirs_load_certs_from_string() whether it was by fp
@@ -2403,14 +2415,15 @@ handle_response_fetch_status_vote(dir_connection_t *conn,
const char *msg;
int st;
- log_info(LD_DIR,"Got votes (body size %d) from server %s:%d",
- (int)body_len, conn->base_.address, conn->base_.port);
+ log_info(LD_DIR,"Got votes (body size %d) from server %s",
+ (int)body_len, connection_describe_peer(TO_CONN(conn)));
if (status_code != 200) {
log_warn(LD_DIR,
"Received http status code %d (%s) from server "
- "'%s:%d' while fetching \"/tor/status-vote/next/%s.z\".",
- status_code, escaped(reason), conn->base_.address,
- conn->base_.port, conn->requested_resource);
+ "%s while fetching \"/tor/status-vote/next/%s.z\".",
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)),
+ conn->requested_resource);
return -1;
}
dirvote_add_vote(body, 0, &msg, &st);
@@ -2438,19 +2451,21 @@ handle_response_fetch_detached_signatures(dir_connection_t *conn,
const size_t body_len = args->body_len;
const char *msg = NULL;
- log_info(LD_DIR,"Got detached signatures (body size %d) from server %s:%d",
- (int)body_len, conn->base_.address, conn->base_.port);
+ log_info(LD_DIR,"Got detached signatures (body size %d) from server %s",
+ (int)body_len,
+ connection_describe_peer(TO_CONN(conn)));
if (status_code != 200) {
log_warn(LD_DIR,
- "Received http status code %d (%s) from server '%s:%d' while fetching "
+ "Received http status code %d (%s) from server %s while fetching "
"\"/tor/status-vote/next/consensus-signatures.z\".",
- status_code, escaped(reason), conn->base_.address,
- conn->base_.port);
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)));
return -1;
}
if (dirvote_add_signatures(body, conn->base_.address, &msg)<0) {
- log_warn(LD_DIR, "Problem adding detached signatures from %s:%d: %s",
- conn->base_.address, conn->base_.port, msg?msg:"???");
+ log_warn(LD_DIR, "Problem adding detached signatures from %s: %s",
+ connection_describe_peer(TO_CONN(conn)),
+ msg?msg:"???");
}
return 0;
@@ -2476,9 +2491,9 @@ handle_response_fetch_desc(dir_connection_t *conn,
int n_asked_for = 0;
int descriptor_digests = conn->requested_resource &&
!strcmpstart(conn->requested_resource,"d/");
- log_info(LD_DIR,"Received %s (body size %d) from server '%s:%d'",
+ log_info(LD_DIR,"Received %s (body size %d) from server %s",
was_ei ? "extra server info" : "server info",
- (int)body_len, conn->base_.address, conn->base_.port);
+ (int)body_len, connection_describe_peer(TO_CONN(conn)));
if (conn->requested_resource &&
(!strcmpstart(conn->requested_resource,"d/") ||
!strcmpstart(conn->requested_resource,"fp/"))) {
@@ -2494,10 +2509,11 @@ handle_response_fetch_desc(dir_connection_t *conn,
/* 404 means that it didn't have them; no big deal.
* Older (pre-0.1.1.8) servers said 400 Servers unavailable instead. */
log_fn(dir_okay ? LOG_INFO : LOG_WARN, LD_DIR,
- "Received http status code %d (%s) from server '%s:%d' "
+ "Received http status code %d (%s) from server %s "
"while fetching \"/tor/server/%s\". I'll try again soon.",
- status_code, escaped(reason), conn->base_.address,
- conn->base_.port, conn->requested_resource);
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)),
+ conn->requested_resource);
if (!which) {
connection_dir_download_routerdesc_failed(conn);
} else {
@@ -2537,10 +2553,10 @@ handle_response_fetch_desc(dir_connection_t *conn,
}
}
if (which) { /* mark remaining ones as failed */
- log_info(LD_DIR, "Received %d/%d %s requested from %s:%d",
+ log_info(LD_DIR, "Received %d/%d %s requested from %s",
n_asked_for-smartlist_len(which), n_asked_for,
was_ei ? "extra-info documents" : "router descriptors",
- conn->base_.address, (int)conn->base_.port);
+ connection_describe_peer(TO_CONN(conn)));
if (smartlist_len(which)) {
dir_routerdesc_download_failed(which, status_code,
conn->router_purpose,
@@ -2571,9 +2587,9 @@ handle_response_fetch_microdesc(dir_connection_t *conn,
smartlist_t *which = NULL;
log_info(LD_DIR,"Received answer to microdescriptor request (status %d, "
- "body size %d) from server '%s:%d'",
- status_code, (int)body_len, conn->base_.address,
- conn->base_.port);
+ "body size %d) from server %s",
+ status_code, (int)body_len,
+ connection_describe_peer(TO_CONN(conn)));
tor_assert(conn->requested_resource &&
!strcmpstart(conn->requested_resource, "d/"));
tor_assert_nonfatal(!fast_mem_is_zero(conn->identity_digest, DIGEST_LEN));
@@ -2583,10 +2599,11 @@ handle_response_fetch_microdesc(dir_connection_t *conn,
DSR_DIGEST256|DSR_BASE64);
if (status_code != 200) {
log_info(LD_DIR, "Received status code %d (%s) from server "
- "'%s:%d' while fetching \"/tor/micro/%s\". I'll try again "
+ "%s while fetching \"/tor/micro/%s\". I'll try again "
"soon.",
- status_code, escaped(reason), conn->base_.address,
- (int)conn->base_.port, conn->requested_resource);
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)),
+ conn->requested_resource);
dir_microdesc_download_failed(which, status_code, conn->identity_digest);
SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
smartlist_free(which);
@@ -2661,8 +2678,8 @@ handle_response_upload_dir(dir_connection_t *conn,
break;
case 400:
log_warn(LD_GENERAL,"http status 400 (%s) response from "
- "dirserver '%s:%d'. Please correct.",
- escaped(reason), conn->base_.address, conn->base_.port);
+ "dirserver %s. Please correct.",
+ escaped(reason), connection_describe_peer(TO_CONN(conn)));
control_event_server_status(LOG_WARN,
"BAD_SERVER_DESCRIPTOR DIRAUTH=%s:%d REASON=\"%s\"",
conn->base_.address, conn->base_.port, escaped(reason));
@@ -2670,10 +2687,10 @@ handle_response_upload_dir(dir_connection_t *conn,
default:
log_warn(LD_GENERAL,
"HTTP status %d (%s) was unexpected while uploading "
- "descriptor to server '%s:%d'. Possibly the server is "
+ "descriptor to server %s'. Possibly the server is "
"misconfigured?",
- status_code, escaped(reason), conn->base_.address,
- conn->base_.port);
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)));
break;
}
/* return 0 in all cases, since we don't want to mark any
@@ -2696,21 +2713,21 @@ handle_response_upload_vote(dir_connection_t *conn,
switch (status_code) {
case 200: {
- log_notice(LD_DIR,"Uploaded a vote to dirserver %s:%d",
- conn->base_.address, conn->base_.port);
+ log_notice(LD_DIR,"Uploaded a vote to dirserver %s",
+ connection_describe_peer(TO_CONN(conn)));
}
break;
case 400:
log_warn(LD_DIR,"http status 400 (%s) response after uploading "
- "vote to dirserver '%s:%d'. Please correct.",
- escaped(reason), conn->base_.address, conn->base_.port);
+ "vote to dirserver %s. Please correct.",
+ escaped(reason), connection_describe_peer(TO_CONN(conn)));
break;
default:
log_warn(LD_GENERAL,
"HTTP status %d (%s) was unexpected while uploading "
- "vote to server '%s:%d'.",
- status_code, escaped(reason), conn->base_.address,
- conn->base_.port);
+ "vote to server %s.",
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)));
break;
}
/* return 0 in all cases, since we don't want to mark any
@@ -2732,21 +2749,21 @@ handle_response_upload_signatures(dir_connection_t *conn,
switch (status_code) {
case 200: {
- log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s:%d",
- conn->base_.address, conn->base_.port);
+ log_notice(LD_DIR,"Uploaded signature(s) to dirserver %s",
+ connection_describe_peer(TO_CONN(conn)));
}
break;
case 400:
log_warn(LD_DIR,"http status 400 (%s) response after uploading "
- "signatures to dirserver '%s:%d'. Please correct.",
- escaped(reason), conn->base_.address, conn->base_.port);
+ "signatures to dirserver %s. Please correct.",
+ escaped(reason), connection_describe_peer(TO_CONN(conn)));
break;
default:
log_warn(LD_GENERAL,
"HTTP status %d (%s) was unexpected while uploading "
- "signatures to server '%s:%d'.",
- status_code, escaped(reason), conn->base_.address,
- conn->base_.port);
+ "signatures to server %s.",
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)));
break;
}
/* return 0 in all cases, since we don't want to mark any
@@ -2861,10 +2878,10 @@ handle_response_fetch_renddesc_v2(dir_connection_t *conn,
default:
log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
"http status %d (%s) response unexpected while "
- "fetching v2 hidden service descriptor (server '%s:%d'). "
+ "fetching v2 hidden service descriptor (server %s). "
"Retrying at another directory.",
- status_code, escaped(reason), conn->base_.address,
- conn->base_.port);
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)));
SEND_HS_DESC_FAILED_EVENT("UNEXPECTED");
SEND_HS_DESC_FAILED_CONTENT();
break;
@@ -2908,15 +2925,15 @@ handle_response_upload_renddesc_v2(dir_connection_t *conn,
break;
case 400:
log_warn(LD_REND,"http status 400 (%s) response from dirserver "
- "'%s:%d'. Malformed rendezvous descriptor?",
- escaped(reason), conn->base_.address, conn->base_.port);
+ "%s. Malformed rendezvous descriptor?",
+ escaped(reason), connection_describe_peer(TO_CONN(conn)));
SEND_HS_DESC_UPLOAD_FAILED_EVENT("UPLOAD_REJECTED");
break;
default:
log_warn(LD_REND,"http status %d (%s) response unexpected (server "
- "'%s:%d').",
- status_code, escaped(reason), conn->base_.address,
- conn->base_.port);
+ "%s).",
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)));
SEND_HS_DESC_UPLOAD_FAILED_EVENT("UNEXPECTED");
break;
}
@@ -2954,17 +2971,17 @@ handle_response_upload_hsdesc(dir_connection_t *conn,
log_fn(LOG_PROTOCOL_WARN, LD_REND,
"Uploading hidden service descriptor: http "
"status 400 (%s) response from dirserver "
- "'%s:%d'. Malformed hidden service descriptor?",
- escaped(reason), conn->base_.address, conn->base_.port);
+ "%s. Malformed hidden service descriptor?",
+ escaped(reason), connection_describe_peer(TO_CONN(conn)));
hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
"UPLOAD_REJECTED");
break;
default:
log_warn(LD_REND, "Uploading hidden service descriptor: http "
"status %d (%s) response unexpected (server "
- "'%s:%d').",
- status_code, escaped(reason), conn->base_.address,
- conn->base_.port);
+ "%s').",
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(conn)));
hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
"UNEXPECTED");
break;
@@ -3116,7 +3133,7 @@ connection_dir_close_consensus_fetches(dir_connection_t *except_this_one,
if (d == except_this_one)
continue;
log_info(LD_DIR, "Closing consensus fetch (to %s) since one "
- "has just arrived.", TO_CONN(d)->address);
+ "has just arrived.", connection_describe_peer(TO_CONN(d)));
connection_mark_for_close(TO_CONN(d));
} SMARTLIST_FOREACH_END(d);
smartlist_free(conns_to_close);
diff --git a/src/feature/dirclient/dirclient_modes.c b/src/feature/dirclient/dirclient_modes.c
index 31a3f8af58..62cdad6c36 100644
--- a/src/feature/dirclient/dirclient_modes.c
+++ b/src/feature/dirclient/dirclient_modes.c
@@ -40,15 +40,19 @@ int
dirclient_fetches_from_authorities(const or_options_t *options)
{
const routerinfo_t *me;
- uint32_t addr;
int refuseunknown;
if (options->FetchDirInfoEarly)
return 1;
if (options->BridgeRelay == 1)
return 0;
- if (server_mode(options) &&
- router_pick_published_address(options, &addr, 1) < 0)
- return 1; /* we don't know our IP address; ask an authority. */
+ /* We don't know our IP address; ask an authority. IPv4 is still mandatory
+ * to have thus if we don't have it, we ought to learn it from an authority
+ * through the NETINFO cell or the HTTP header it sends us back.
+ *
+ * Note that at the moment, relay do a direct connection so no NETINFO cell
+ * for now. */
+ if (server_mode(options) && !relay_has_address_set(AF_INET))
+ return 1;
refuseunknown = ! router_my_exit_policy_is_reject_star() &&
should_refuse_unknown_exits(options);
if (!dir_server_mode(options) && !refuseunknown)
diff --git a/src/feature/dircommon/directory.c b/src/feature/dircommon/directory.c
index b177fe5201..b276ac3441 100644
--- a/src/feature/dircommon/directory.c
+++ b/src/feature/dircommon/directory.c
@@ -79,8 +79,12 @@
* connection_finished_connecting() in connection.c
*/
-/** Convert a connection_t* to a dir_connection_t*; assert if the cast is
- * invalid. */
+/**
+ * Cast a `connection_t *` to a `dir_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not a
+ * `dir_connection_t`.
+ **/
dir_connection_t *
TO_DIR_CONN(connection_t *c)
{
@@ -88,6 +92,18 @@ TO_DIR_CONN(connection_t *c)
return DOWNCAST(dir_connection_t, c);
}
+/**
+ * Cast a `const connection_t *` to a `const dir_connection_t *`.
+ *
+ * Exit with an assertion failure if the input is not a
+ * `dir_connection_t`.
+ **/
+const dir_connection_t *
+CONST_TO_DIR_CONN(const connection_t *c)
+{
+ return TO_DIR_CONN((connection_t *)c);
+}
+
/** Return false if the directory purpose <b>dir_purpose</b>
* does not require an anonymous (three-hop) connection.
*
@@ -217,7 +233,7 @@ connection_dir_is_anonymous(const dir_connection_t *dir_conn)
return false;
}
- edge_conn = TO_EDGE_CONN((connection_t *) linked_conn);
+ edge_conn = CONST_TO_EDGE_CONN(linked_conn);
circ = edge_conn->on_circuit;
/* Can't be a circuit we initiated and without a circuit, no channel. */
@@ -455,9 +471,9 @@ connection_dir_process_inbuf(dir_connection_t *conn)
if (connection_get_inbuf_len(TO_CONN(conn)) > max_size) {
log_warn(LD_HTTP,
- "Too much data received from directory connection (%s): "
+ "Too much data received from %s: "
"denial of service attempt, or you need to upgrade?",
- conn->base_.address);
+ connection_describe(TO_CONN(conn)));
connection_mark_for_close(TO_CONN(conn));
return -1;
}
@@ -540,8 +556,8 @@ connection_dir_finished_connecting(dir_connection_t *conn)
tor_assert(conn->base_.type == CONN_TYPE_DIR);
tor_assert(conn->base_.state == DIR_CONN_STATE_CONNECTING);
- log_debug(LD_HTTP,"Dir connection to router %s:%u established.",
- conn->base_.address,conn->base_.port);
+ log_debug(LD_HTTP,"Dir connection to %s established.",
+ connection_describe_peer(TO_CONN(conn)));
/* start flushing conn */
conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING;
diff --git a/src/feature/dircommon/directory.h b/src/feature/dircommon/directory.h
index 0f26cdeff9..0aa2ff53ef 100644
--- a/src/feature/dircommon/directory.h
+++ b/src/feature/dircommon/directory.h
@@ -13,6 +13,7 @@
#define TOR_DIRECTORY_H
dir_connection_t *TO_DIR_CONN(connection_t *c);
+const dir_connection_t *CONST_TO_DIR_CONN(const connection_t *c);
#define DIR_CONN_STATE_MIN_ 1
/** State for connection to directory server: waiting for connect(). */
diff --git a/src/feature/dirparse/authcert_parse.c b/src/feature/dirparse/authcert_parse.c
index deb45c12de..b2460f6ace 100644
--- a/src/feature/dirparse/authcert_parse.c
+++ b/src/feature/dirparse/authcert_parse.c
@@ -130,13 +130,13 @@ authority_cert_parse_from_string(const char *s, size_t maxlen,
tor_assert(tok->n_args);
/* XXX++ use some tor_addr parse function below instead. -RD */
if (tor_addr_port_split(LOG_WARN, tok->args[0], &address,
- &cert->dir_port) < 0 ||
+ &cert->ipv4_dirport) < 0 ||
tor_inet_aton(address, &in) == 0) {
log_warn(LD_DIR, "Couldn't parse dir-address in certificate");
tor_free(address);
goto err;
}
- cert->addr = ntohl(in.s_addr);
+ tor_addr_from_in(&cert->ipv4_addr, &in);
tor_free(address);
}
diff --git a/src/feature/dirparse/ns_parse.c b/src/feature/dirparse/ns_parse.c
index ac9325a608..927870c4aa 100644
--- a/src/feature/dirparse/ns_parse.c
+++ b/src/feature/dirparse/ns_parse.c
@@ -13,6 +13,7 @@
#include "core/or/or.h"
#include "app/config/config.h"
+#include "core/or/protover.h"
#include "core/or/versions.h"
#include "feature/client/entrynodes.h"
#include "feature/dirauth/dirvote.h"
@@ -384,12 +385,12 @@ routerstatus_parse_entry_from_string(memarea_t *area,
escaped(tok->args[5+offset]));
goto err;
}
- rs->addr = ntohl(in.s_addr);
+ tor_addr_from_in(&rs->ipv4_addr, &in);
- rs->or_port = (uint16_t) tor_parse_long(tok->args[6+offset],
- 10,0,65535,NULL,NULL);
- rs->dir_port = (uint16_t) tor_parse_long(tok->args[7+offset],
- 10,0,65535,NULL,NULL);
+ rs->ipv4_orport = (uint16_t) tor_parse_long(tok->args[6+offset],
+ 10,0,65535,NULL,NULL);
+ rs->ipv4_dirport = (uint16_t) tor_parse_long(tok->args[7+offset],
+ 10,0,65535,NULL,NULL);
{
smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
@@ -466,6 +467,10 @@ routerstatus_parse_entry_from_string(memarea_t *area,
}
}
+ // If the protover line is malformed, reject this routerstatus.
+ if (protocols && protover_list_is_invalid(protocols)) {
+ goto err;
+ }
summarize_protover_flags(&rs->pv, protocols, version);
}
@@ -563,7 +568,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
log_info(LD_BUG, "Found an entry in networkstatus with no "
"microdescriptor digest. (Router %s ($%s) at %s:%d.)",
rs->nickname, hex_str(rs->identity_digest, DIGEST_LEN),
- fmt_addr32(rs->addr), rs->or_port);
+ fmt_addr(&rs->ipv4_addr), rs->ipv4_orport);
}
}
@@ -1063,6 +1068,19 @@ extract_shared_random_srvs(networkstatus_t *ns, smartlist_t *tokens)
}
}
+/** Allocate a copy of a protover line, if present. If present but malformed,
+ * set *error to true. */
+static char *
+dup_protocols_string(smartlist_t *tokens, bool *error, directory_keyword kw)
+{
+ directory_token_t *tok = find_opt_by_keyword(tokens, kw);
+ if (!tok)
+ return NULL;
+ if (protover_list_is_invalid(tok->args[0]))
+ *error = true;
+ return tor_strdup(tok->args[0]);
+}
+
/** Parse a v3 networkstatus vote, opinion, or consensus (depending on
* ns_type), from <b>s</b>, and return the result. Return NULL on failure. */
networkstatus_t *
@@ -1184,14 +1202,18 @@ networkstatus_parse_vote_from_string(const char *s,
}
}
- if ((tok = find_opt_by_keyword(tokens, K_RECOMMENDED_CLIENT_PROTOCOLS)))
- ns->recommended_client_protocols = tor_strdup(tok->args[0]);
- if ((tok = find_opt_by_keyword(tokens, K_RECOMMENDED_RELAY_PROTOCOLS)))
- ns->recommended_relay_protocols = tor_strdup(tok->args[0]);
- if ((tok = find_opt_by_keyword(tokens, K_REQUIRED_CLIENT_PROTOCOLS)))
- ns->required_client_protocols = tor_strdup(tok->args[0]);
- if ((tok = find_opt_by_keyword(tokens, K_REQUIRED_RELAY_PROTOCOLS)))
- ns->required_relay_protocols = tor_strdup(tok->args[0]);
+ // Reject the vote if any of the protocols lines are malformed.
+ bool unparseable = false;
+ ns->recommended_client_protocols = dup_protocols_string(tokens, &unparseable,
+ K_RECOMMENDED_CLIENT_PROTOCOLS);
+ ns->recommended_relay_protocols = dup_protocols_string(tokens, &unparseable,
+ K_RECOMMENDED_RELAY_PROTOCOLS);
+ ns->required_client_protocols = dup_protocols_string(tokens, &unparseable,
+ K_REQUIRED_CLIENT_PROTOCOLS);
+ ns->required_relay_protocols = dup_protocols_string(tokens, &unparseable,
+ K_REQUIRED_RELAY_PROTOCOLS);
+ if (unparseable)
+ goto err;
tok = find_by_keyword(tokens, K_VALID_AFTER);
if (parse_iso_time(tok->args[0], &ns->valid_after))
@@ -1354,8 +1376,8 @@ networkstatus_parse_vote_from_string(const char *s,
goto err;
}
if (ns->type != NS_TYPE_CONSENSUS) {
- if (authority_cert_is_blacklisted(ns->cert)) {
- log_warn(LD_DIR, "Rejecting vote signature made with blacklisted "
+ if (authority_cert_is_denylisted(ns->cert)) {
+ log_warn(LD_DIR, "Rejecting vote signature made with denylisted "
"signing key %s",
hex_str(ns->cert->signing_key_digest, DIGEST_LEN));
goto err;
@@ -1367,13 +1389,13 @@ networkstatus_parse_vote_from_string(const char *s,
escaped(tok->args[3]));
goto err;
}
- voter->addr = ntohl(in.s_addr);
+ tor_addr_from_in(&voter->ipv4_addr, &in);
int ok;
- voter->dir_port = (uint16_t)
+ voter->ipv4_dirport = (uint16_t)
tor_parse_long(tok->args[4], 10, 0, 65535, &ok, NULL);
if (!ok)
goto err;
- voter->or_port = (uint16_t)
+ voter->ipv4_orport = (uint16_t)
tor_parse_long(tok->args[5], 10, 0, 65535, &ok, NULL);
if (!ok)
goto err;
@@ -1453,6 +1475,7 @@ networkstatus_parse_vote_from_string(const char *s,
smartlist_add(ns->routerstatus_list, rs);
} else {
vote_routerstatus_free(rs);
+ goto err; // Malformed routerstatus, reject this vote.
}
} else {
routerstatus_t *rs;
@@ -1463,6 +1486,8 @@ networkstatus_parse_vote_from_string(const char *s,
flav))) {
/* Use exponential-backoff scheduling when downloading microdescs */
smartlist_add(ns->routerstatus_list, rs);
+ } else {
+ goto err; // Malformed routerstatus, reject this vote.
}
}
}
diff --git a/src/feature/dirparse/routerparse.c b/src/feature/dirparse/routerparse.c
index 8828a0f97a..42a53101b0 100644
--- a/src/feature/dirparse/routerparse.c
+++ b/src/feature/dirparse/routerparse.c
@@ -519,15 +519,15 @@ router_parse_entry_from_string(const char *s, const char *end,
log_warn(LD_DIR,"Router address is not an IP address.");
goto err;
}
- router->addr = ntohl(in.s_addr);
+ tor_addr_from_in(&router->ipv4_addr, &in);
- router->or_port =
+ router->ipv4_orport =
(uint16_t) tor_parse_long(tok->args[2],10,0,65535,&ok,NULL);
if (!ok) {
log_warn(LD_DIR,"Invalid OR port %s", escaped(tok->args[2]));
goto err;
}
- router->dir_port =
+ router->ipv4_dirport =
(uint16_t) tor_parse_long(tok->args[4],10,0,65535,&ok,NULL);
if (!ok) {
log_warn(LD_DIR,"Invalid dir port %s", escaped(tok->args[4]));
@@ -907,13 +907,14 @@ router_parse_entry_from_string(const char *s, const char *end,
/* This router accepts tunnelled directory requests via begindir if it has
* an open dirport or it included "tunnelled-dir-server". */
- if (find_opt_by_keyword(tokens, K_DIR_TUNNELLED) || router->dir_port > 0) {
+ if (find_opt_by_keyword(tokens, K_DIR_TUNNELLED) ||
+ router->ipv4_dirport > 0) {
router->supports_tunnelled_dir_requests = 1;
}
tok = find_by_keyword(tokens, K_ROUTER_SIGNATURE);
- if (!router->or_port) {
+ if (!router->ipv4_orport) {
log_warn(LD_DIR,"or_port unreadable or 0. Failing.");
goto err;
}
diff --git a/src/feature/feature.md b/src/feature/feature.md
index acc3487e55..d9f7bd5c0e 100644
--- a/src/feature/feature.md
+++ b/src/feature/feature.md
@@ -5,3 +5,26 @@ The "feature" directory has modules that Tor uses only for a particular
role or service, such as maintaining/using an onion service, operating as a
relay or a client, or being a directory authority.
+Current subdirectories are:
+
+ - \refdir{feature/api} -- Support for making Tor embeddable
+ - \refdir{feature/client} -- Functionality which only Tor clients need
+ - \refdir{feature/control} -- Controller implementation
+ - \refdir{feature/dirauth} -- Directory authority
+ - \refdir{feature/dircache} -- Directory cache
+ - \refdir{feature/dirclient} -- Directory client
+ - \refdir{feature/dircommon} -- Shared code between the other directory modules
+ - \refdir{feature/dirparse} -- Directory parsing code.
+ - \refdir{feature/hibernate} -- Hibernating when Tor is out of bandwidth
+ or shutting down
+ - \refdir{feature/hs} -- v3 onion service implementation
+ - \refdir{feature/hs_common} -- shared code between both onion service
+ implementations
+ - \refdir{feature/keymgt} -- shared code for key management between
+ relays and onion services.
+ - \refdir{feature/nodelist} -- storing and accessing the list of relays on
+ the network.
+ - \refdir{feature/relay} -- code that only relay servers and exit servers
+ need.
+ - \refdir{feature/rend} -- v2 onion service implementation
+ - \refdir{feature/stats} -- statistics and history
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
index 447f664f81..5e7a3ac9c8 100644
--- a/src/feature/hs/hs_circuit.c
+++ b/src/feature/hs/hs_circuit.c
@@ -16,6 +16,7 @@
#include "core/or/policies.h"
#include "core/or/relay.h"
#include "core/or/crypt_path.h"
+#include "core/or/extendinfo.h"
#include "feature/client/circpathbias.h"
#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_circuit.h"
diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c
index fc1fd76efc..b67ff237b5 100644
--- a/src/feature/hs/hs_client.c
+++ b/src/feature/hs/hs_client.c
@@ -16,6 +16,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/connection_edge.h"
+#include "core/or/extendinfo.h"
#include "core/or/reasons.h"
#include "feature/client/circpathbias.h"
#include "feature/dirclient/dirclient.h"
@@ -1559,9 +1560,9 @@ client_dir_fetch_unexpected(dir_connection_t *dir_conn, const char *reason,
log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: "
"http status %d (%s) response unexpected from HSDir "
- "server '%s:%d'. Retrying at another directory.",
- status_code, escaped(reason), TO_CONN(dir_conn)->address,
- TO_CONN(dir_conn)->port);
+ "server %s'. Retrying at another directory.",
+ status_code, escaped(reason),
+ connection_describe_peer(TO_CONN(dir_conn)));
/* Fire control port FAILED event. */
hs_control_desc_event_failed(dir_conn->hs_ident, dir_conn->identity_digest,
"UNEXPECTED");
diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c
index 4639cdb68a..cbcb672140 100644
--- a/src/feature/hs/hs_common.c
+++ b/src/feature/hs/hs_common.c
@@ -16,6 +16,7 @@
#include "app/config/config.h"
#include "core/or/circuitbuild.h"
#include "core/or/policies.h"
+#include "core/or/extendinfo.h"
#include "feature/dirauth/shared_random_state.h"
#include "feature/hs/hs_cache.h"
#include "feature/hs/hs_circuitmap.h"
@@ -1743,7 +1744,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs,
switch (link_specifier_get_ls_type(ls)) {
case LS_IPV4:
/* Skip if we already seen a v4. If direct_conn is true, we skip this
- * block because fascist_firewall_choose_address_ls() will set ap. If
+ * block because reachable_addr_choose_from_ls() will set ap. If
* direct_conn is false, set ap to the first IPv4 address and port in
* the link specifiers.*/
if (have_v4 || direct_conn) continue;
@@ -1775,7 +1776,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs,
/* Choose a preferred address first, but fall back to an allowed address. */
if (direct_conn)
- fascist_firewall_choose_address_ls(lspecs, 0, &ap);
+ reachable_addr_choose_from_ls(lspecs, 0, &ap);
/* Legacy ID is mandatory, and we require an IP address. */
if (!tor_addr_port_is_valid_ap(&ap, 0)) {
diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c
index 50a46fb40f..30a36030d1 100644
--- a/src/feature/hs/hs_descriptor.c
+++ b/src/feature/hs/hs_descriptor.c
@@ -55,6 +55,7 @@
/* For unit tests.*/
#define HS_DESCRIPTOR_PRIVATE
+#include <stdbool.h>
#include "core/or/or.h"
#include "app/config/config.h"
#include "trunnel/ed25519_cert.h" /* Trunnel interface. */
@@ -404,7 +405,7 @@ encode_enc_key(const hs_desc_intro_point_t *ip)
tor_assert(ip);
/* Base64 encode the encryption key for the "enc-key" field. */
- curve25519_public_to_base64(key_b64, &ip->enc_key);
+ curve25519_public_to_base64(key_b64, &ip->enc_key, true);
if (tor_cert_encode_ed22519(ip->enc_key_cert, &encoded_cert) < 0) {
goto done;
}
@@ -430,7 +431,7 @@ encode_onion_key(const hs_desc_intro_point_t *ip)
tor_assert(ip);
/* Base64 encode the encryption key for the "onion-key" field. */
- curve25519_public_to_base64(key_b64, &ip->onion_key);
+ curve25519_public_to_base64(key_b64, &ip->onion_key, true);
tor_asprintf(&encoded, "%s ntor %s", str_ip_onion_key, key_b64);
return encoded;
@@ -813,7 +814,7 @@ get_outer_encrypted_layer_plaintext(const hs_descriptor_t *desc,
tor_assert(!fast_mem_is_zero((char *) ephemeral_pubkey->public_key,
CURVE25519_PUBKEY_LEN));
- curve25519_public_to_base64(ephemeral_key_base64, ephemeral_pubkey);
+ curve25519_public_to_base64(ephemeral_key_base64, ephemeral_pubkey, true);
smartlist_add_asprintf(lines, "%s %s\n",
str_desc_auth_key, ephemeral_key_base64);
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index a42879a48f..f2a8898b2c 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -16,6 +16,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
+#include "core/or/extendinfo.h"
#include "core/or/relay.h"
#include "feature/client/circpathbias.h"
#include "feature/dirclient/dirclient.h"
@@ -989,7 +990,7 @@ write_address_to_file(const hs_service_t *service, const char *fname_)
tor_asprintf(&addr_buf, "%s.%s\n", service->onion_address, address_tld);
/* Notice here that we use the given "fname_". */
fname = hs_path_from_filename(service->config.directory_path, fname_);
- if (write_str_to_file(fname, addr_buf, 0) < 0) {
+ if (write_str_to_file_if_not_equal(fname, addr_buf)) {
log_warn(LD_REND, "Could not write onion address to hostname file %s",
escaped(fname));
goto end;
@@ -1586,7 +1587,7 @@ setup_desc_intro_point(const ed25519_keypair_t *signing_kp,
memcpy(&desc_ip->onion_key, &ip->onion_key, sizeof(desc_ip->onion_key));
/* Key and certificate material. */
- desc_ip->auth_key_cert = tor_cert_create(signing_kp,
+ desc_ip->auth_key_cert = tor_cert_create_ed25519(signing_kp,
CERT_TYPE_AUTH_HS_IP_KEY,
&ip->auth_key_kp.pubkey,
nearest_hour,
@@ -1637,7 +1638,7 @@ setup_desc_intro_point(const ed25519_keypair_t *signing_kp,
ed25519_public_key_from_curve25519_public_key(&ed25519_pubkey,
&ip->enc_key_kp.pubkey,
0);
- desc_ip->enc_key_cert = tor_cert_create(signing_kp,
+ desc_ip->enc_key_cert = tor_cert_create_ed25519(signing_kp,
CERT_TYPE_CROSS_HS_IP_KEYS,
&ed25519_pubkey, nearest_hour,
HS_DESC_CERT_LIFETIME,
@@ -1711,12 +1712,13 @@ build_desc_signing_key_cert(hs_service_descriptor_t *desc, time_t now)
/* Fresh certificate for the signing key. */
plaintext->signing_key_cert =
- tor_cert_create(&desc->blinded_kp, CERT_TYPE_SIGNING_HS_DESC,
+ tor_cert_create_ed25519(&desc->blinded_kp, CERT_TYPE_SIGNING_HS_DESC,
&desc->signing_kp.pubkey, now, HS_DESC_CERT_LIFETIME,
CERT_FLAG_INCLUDE_SIGNING_KEY);
/* If the cert creation fails, the descriptor encoding will fail and thus
* ultimately won't be uploaded. We'll get a stack trace to help us learn
- * where the call came from and the tor_cert_create() will log the error. */
+ * where the call came from and the tor_cert_create_ed25519() will log the
+ * error. */
tor_assert_nonfatal(plaintext->signing_key_cert);
}
@@ -2873,6 +2875,9 @@ upload_descriptor_to_hsdir(const hs_service_t *service,
hsdir->hsdir_index.store_first;
char *blinded_pubkey_log_str =
tor_strdup(hex_str((char*)&desc->blinded_kp.pubkey.pubkey, 32));
+ /* This log message is used by Chutney as part of its bootstrap
+ * detection mechanism. Please don't change without first checking
+ * Chutney. */
log_info(LD_REND, "Service %s %s descriptor of revision %" PRIu64
" initiated upload request to %s with index %s (%s)",
safe_str_client(service->onion_address),
@@ -3900,7 +3905,7 @@ hs_service_exports_circuit_id(const ed25519_public_key_t *pk)
/** Add to file_list every filename used by a configured hidden service, and to
* dir_list every directory path used by a configured hidden service. This is
- * used by the sandbox subsystem to whitelist those. */
+ * used by the sandbox subsystem to allowlist those. */
void
hs_service_lists_fnames_for_sandbox(smartlist_t *file_list,
smartlist_t *dir_list)
diff --git a/src/feature/keymgt/loadkey.c b/src/feature/keymgt/loadkey.c
index 7958bd964f..9b8f2f018a 100644
--- a/src/feature/keymgt/loadkey.c
+++ b/src/feature/keymgt/loadkey.c
@@ -661,7 +661,7 @@ ed_key_init_from_file(const char *fname, uint32_t flags,
uint32_t cert_flags = 0;
if (flags & INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT)
cert_flags |= CERT_FLAG_INCLUDE_SIGNING_KEY;
- cert = tor_cert_create(signing_key, cert_type,
+ cert = tor_cert_create_ed25519(signing_key, cert_type,
&keypair->pubkey,
now, lifetime,
cert_flags);
@@ -739,7 +739,7 @@ ed_key_new(const ed25519_keypair_t *signing_key,
uint32_t cert_flags = 0;
if (flags & INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT)
cert_flags |= CERT_FLAG_INCLUDE_SIGNING_KEY;
- tor_cert_t *cert = tor_cert_create(signing_key, cert_type,
+ tor_cert_t *cert = tor_cert_create_ed25519(signing_key, cert_type,
&keypair->pubkey,
now, lifetime,
cert_flags);
diff --git a/src/feature/nodelist/authcert.c b/src/feature/nodelist/authcert.c
index 97e44d53e3..c5b31be9e3 100644
--- a/src/feature/nodelist/authcert.c
+++ b/src/feature/nodelist/authcert.c
@@ -460,19 +460,15 @@ trusted_dirs_load_certs_from_string(const char *contents, int source,
if (ds && cert->cache_info.published_on > ds->addr_current_at) {
/* Check to see whether we should update our view of the authority's
* address. */
- if (cert->addr && cert->dir_port &&
- (ds->addr != cert->addr ||
- ds->dir_port != cert->dir_port)) {
- char *a = tor_dup_ip(cert->addr);
- if (a) {
- log_notice(LD_DIR, "Updating address for directory authority %s "
- "from %s:%d to %s:%d based on certificate.",
- ds->nickname, ds->address, (int)ds->dir_port,
- a, cert->dir_port);
- tor_free(a);
- }
- ds->addr = cert->addr;
- ds->dir_port = cert->dir_port;
+ if (!tor_addr_is_null(&cert->ipv4_addr) && cert->ipv4_dirport &&
+ (!tor_addr_eq(&ds->ipv4_addr, &cert->ipv4_addr) ||
+ ds->ipv4_dirport != cert->ipv4_dirport)) {
+ log_notice(LD_DIR, "Updating address for directory authority %s "
+ "from %s:%"PRIu16" to %s:%"PRIu16" based on certificate.",
+ ds->nickname, ds->address, ds->ipv4_dirport,
+ fmt_addr(&cert->ipv4_addr), cert->ipv4_dirport);
+ tor_addr_copy(&ds->ipv4_addr, &cert->ipv4_addr);
+ ds->ipv4_dirport = cert->ipv4_dirport;
}
ds->addr_current_at = cert->cache_info.published_on;
}
@@ -745,7 +741,7 @@ static const char *BAD_SIGNING_KEYS[] = {
* which, because of the old openssl heartbleed vulnerability, should
* never be trusted. */
int
-authority_cert_is_blacklisted(const authority_cert_t *cert)
+authority_cert_is_denylisted(const authority_cert_t *cert)
{
char hex_digest[HEX_DIGEST_LEN+1];
int i;
@@ -812,7 +808,7 @@ authority_certs_fetch_resource_impl(const char *resource,
/* clients always make OR connections to bridges */
tor_addr_port_t or_ap;
/* we are willing to use a non-preferred address if we need to */
- fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0,
+ reachable_addr_choose_from_node(node, FIREWALL_OR_CONNECTION, 0,
&or_ap);
req = directory_request_new(DIR_PURPOSE_FETCH_CERTIFICATE);
diff --git a/src/feature/nodelist/authcert.h b/src/feature/nodelist/authcert.h
index 33065589ba..4c3d79ceed 100644
--- a/src/feature/nodelist/authcert.h
+++ b/src/feature/nodelist/authcert.h
@@ -41,7 +41,7 @@ void authority_cert_dl_failed(const char *id_digest,
void authority_certs_fetch_missing(networkstatus_t *status, time_t now,
const char *dir_hint);
int authority_cert_dl_looks_uncertain(const char *id_digest);
-int authority_cert_is_blacklisted(const authority_cert_t *cert);
+int authority_cert_is_denylisted(const authority_cert_t *cert);
void authority_cert_free_(authority_cert_t *cert);
#define authority_cert_free(cert) \
diff --git a/src/feature/nodelist/authority_cert_st.h b/src/feature/nodelist/authority_cert_st.h
index 9145b12bbf..aa9831d12e 100644
--- a/src/feature/nodelist/authority_cert_st.h
+++ b/src/feature/nodelist/authority_cert_st.h
@@ -27,10 +27,10 @@ struct authority_cert_t {
char signing_key_digest[DIGEST_LEN];
/** The listed expiration time of this certificate. */
time_t expires;
- /** This authority's IPv4 address, in host order. */
- uint32_t addr;
+ /** This authority's IPv4 address. */
+ tor_addr_t ipv4_addr;
/** This authority's directory port. */
- uint16_t dir_port;
+ uint16_t ipv4_dirport;
};
#endif /* !defined(AUTHORITY_CERT_ST_H) */
diff --git a/src/feature/nodelist/describe.c b/src/feature/nodelist/describe.c
index 00896d5a44..96604800e9 100644
--- a/src/feature/nodelist/describe.c
+++ b/src/feature/nodelist/describe.c
@@ -12,6 +12,7 @@
#define DESCRIBE_PRIVATE
#include "core/or/or.h"
+#include "core/or/extendinfo.h"
#include "feature/nodelist/describe.h"
#include "core/or/extend_info_st.h"
@@ -25,9 +26,8 @@
* <b>id_digest</b>, nickname <b>nickname</b>, and addresses <b>addr32h</b> and
* <b>addr</b>.
*
- * The <b>nickname</b> and <b>addr</b> fields are optional and may be set to
- * NULL or the null address. The <b>addr32h</b> field is optional and may be
- * set to 0.
+ * The <b>nickname</b>, <b>ipv6_addr</b> and <b>ipv4_addr</b> fields are
+ * optional and may be set to NULL or the null address.
*
* Return a pointer to the front of <b>buf</b>.
* If buf is NULL, return a string constant describing the error.
@@ -36,11 +36,12 @@ STATIC const char *
format_node_description(char *buf,
const char *id_digest,
const char *nickname,
- const tor_addr_t *addr,
- uint32_t addr32h)
+ const tor_addr_t *ipv4_addr,
+ const tor_addr_t *ipv6_addr)
{
size_t rv = 0;
- bool has_addr = addr && !tor_addr_is_null(addr);
+ bool has_ipv6 = ipv6_addr && !tor_addr_is_null(ipv6_addr);
+ bool valid_ipv4 = false;
if (!buf)
return "<NULL BUFFER>";
@@ -76,39 +77,37 @@ format_node_description(char *buf,
rv = strlcat(buf, nickname, NODE_DESC_BUF_LEN);
tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
}
- if (addr32h || has_addr) {
+ if (ipv4_addr || has_ipv6) {
rv = strlcat(buf, " at ", NODE_DESC_BUF_LEN);
tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
}
- if (addr32h) {
- int ntoa_rv = 0;
- char ipv4_addr_str[INET_NTOA_BUF_LEN];
- memset(ipv4_addr_str, 0, sizeof(ipv4_addr_str));
- struct in_addr in;
- memset(&in, 0, sizeof(in));
-
- in.s_addr = htonl(addr32h);
- ntoa_rv = tor_inet_ntoa(&in, ipv4_addr_str, sizeof(ipv4_addr_str));
- tor_assert_nonfatal(ntoa_rv >= 0);
-
- rv = strlcat(buf, ipv4_addr_str, NODE_DESC_BUF_LEN);
- tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ if (ipv4_addr) {
+ const char *str_rv = NULL;
+ char addr_str[TOR_ADDR_BUF_LEN];
+ memset(addr_str, 0, sizeof(addr_str));
+
+ str_rv = tor_addr_to_str(addr_str, ipv4_addr, sizeof(addr_str), 0);
+ if (str_rv) {
+ rv = strlcat(buf, addr_str, NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ valid_ipv4 = true;
+ }
}
/* Both addresses are valid */
- if (addr32h && has_addr) {
+ if (valid_ipv4 && has_ipv6) {
rv = strlcat(buf, " and ", NODE_DESC_BUF_LEN);
tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
}
- if (has_addr) {
+ if (has_ipv6) {
const char *str_rv = NULL;
char addr_str[TOR_ADDR_BUF_LEN];
memset(addr_str, 0, sizeof(addr_str));
- str_rv = tor_addr_to_str(addr_str, addr, sizeof(addr_str), 1);
- tor_assert_nonfatal(str_rv == addr_str);
-
- rv = strlcat(buf, addr_str, NODE_DESC_BUF_LEN);
- tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ str_rv = tor_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str), 1);
+ if (str_rv) {
+ rv = strlcat(buf, addr_str, NODE_DESC_BUF_LEN);
+ tor_assert_nonfatal(rv < NODE_DESC_BUF_LEN);
+ }
}
return buf;
@@ -130,8 +129,8 @@ router_describe(const routerinfo_t *ri)
return format_node_description(buf,
ri->cache_info.identity_digest,
ri->nickname,
- &ri->ipv6_addr,
- ri->addr);
+ &ri->ipv4_addr,
+ &ri->ipv6_addr);
}
/** Return a human-readable description of the node_t <b>node</b>.
@@ -144,15 +143,14 @@ node_describe(const node_t *node)
{
static char buf[NODE_DESC_BUF_LEN];
const char *nickname = NULL;
- uint32_t addr32h = 0;
- const tor_addr_t *ipv6_addr = NULL;
+ const tor_addr_t *ipv6_addr = NULL, *ipv4_addr = NULL;
if (!node)
return "<null>";
if (node->rs) {
nickname = node->rs->nickname;
- addr32h = node->rs->addr;
+ ipv4_addr = &node->rs->ipv4_addr;
ipv6_addr = &node->rs->ipv6_addr;
/* Support consensus versions less than 28, when IPv6 addresses were in
* microdescs. This code can be removed when 0.2.9 is no longer supported,
@@ -162,7 +160,7 @@ node_describe(const node_t *node)
}
} else if (node->ri) {
nickname = node->ri->nickname;
- addr32h = node->ri->addr;
+ ipv4_addr = &node->ri->ipv4_addr;
ipv6_addr = &node->ri->ipv6_addr;
} else {
return "<null rs and ri>";
@@ -171,8 +169,8 @@ node_describe(const node_t *node)
return format_node_description(buf,
node->identity,
nickname,
- ipv6_addr,
- addr32h);
+ ipv4_addr,
+ ipv6_addr);
}
/** Return a human-readable description of the routerstatus_t <b>rs</b>.
@@ -191,8 +189,8 @@ routerstatus_describe(const routerstatus_t *rs)
return format_node_description(buf,
rs->identity_digest,
rs->nickname,
- &rs->ipv6_addr,
- rs->addr);
+ &rs->ipv4_addr,
+ &rs->ipv6_addr);
}
/** Return a human-readable description of the extend_info_t <b>ei</b>.
@@ -208,11 +206,16 @@ extend_info_describe(const extend_info_t *ei)
if (!ei)
return "<null>";
+ const tor_addr_port_t *ap4 = extend_info_get_orport(ei, AF_INET);
+ const tor_addr_port_t *ap6 = extend_info_get_orport(ei, AF_INET6);
+ const tor_addr_t *addr4 = ap4 ? &ap4->addr : NULL;
+ const tor_addr_t *addr6 = ap6 ? &ap6->addr : NULL;
+
return format_node_description(buf,
ei->identity_digest,
ei->nickname,
- &ei->addr,
- 0);
+ addr4,
+ addr6);
}
/** Set <b>buf</b> (which must have MAX_VERBOSE_NICKNAME_LEN+1 bytes) to the
diff --git a/src/feature/nodelist/describe.h b/src/feature/nodelist/describe.h
index d0fa1af263..62f6c693e2 100644
--- a/src/feature/nodelist/describe.h
+++ b/src/feature/nodelist/describe.h
@@ -49,8 +49,8 @@ void router_get_verbose_nickname(char *buf, const routerinfo_t *router);
STATIC const char *format_node_description(char *buf,
const char *id_digest,
const char *nickname,
- const tor_addr_t *addr,
- uint32_t addr32h);
+ const tor_addr_t *ipv4_addr,
+ const tor_addr_t *ipv6_addr);
#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/feature/nodelist/dirlist.c b/src/feature/nodelist/dirlist.c
index 33d1bfc4d0..cd2921e653 100644
--- a/src/feature/nodelist/dirlist.c
+++ b/src/feature/nodelist/dirlist.c
@@ -59,9 +59,9 @@ add_trusted_dir_to_nodelist_addr_set(const dir_server_t *dir)
tor_assert(dir->is_authority);
/* Add IPv4 and then IPv6 if applicable. */
- nodelist_add_addr4_to_address_set(dir->addr);
+ nodelist_add_addr_to_address_set(&dir->ipv4_addr);
if (!tor_addr_is_null(&dir->ipv6_addr)) {
- nodelist_add_addr6_to_address_set(&dir->ipv6_addr);
+ nodelist_add_addr_to_address_set(&dir->ipv6_addr);
}
}
@@ -250,6 +250,34 @@ router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type)
return 0;
}
+/** Return true iff the given address matches a trusted directory that matches
+ * at least one bit of type.
+ *
+ * If type is NO_DIRINFO or ALL_DIRINFO, any authority is matched. */
+bool
+router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type)
+{
+ int family = tor_addr_family(addr);
+
+ if (!trusted_dir_servers) {
+ return false;
+ }
+
+ SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, dir_server_t *, ent) {
+ /* Ignore entries that don't match the given type. */
+ if (type != NO_DIRINFO && (type & ent->type) == 0) {
+ continue;
+ }
+ /* Match IPv4 or IPv6 address. */
+ if ((family == AF_INET && tor_addr_eq(addr, &ent->ipv4_addr)) ||
+ (family == AF_INET6 && tor_addr_eq(addr, &ent->ipv6_addr))) {
+ return true;
+ }
+ } SMARTLIST_FOREACH_END(ent);
+
+ return false;
+}
+
/** Create a directory server at <b>address</b>:<b>port</b>, with OR identity
* key <b>digest</b> which has DIGEST_LEN bytes. If <b>address</b> is NULL,
* add ourself. If <b>is_authority</b>, this is a directory authority. Return
@@ -257,16 +285,15 @@ router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type)
static dir_server_t *
dir_server_new(int is_authority,
const char *nickname,
- const tor_addr_t *addr,
+ const tor_addr_t *ipv4_addr,
const char *hostname,
- uint16_t dir_port, uint16_t or_port,
+ uint16_t ipv4_dirport, uint16_t ipv4_orport,
const tor_addr_port_t *addrport_ipv6,
const char *digest, const char *v3_auth_digest,
dirinfo_type_t type,
double weight)
{
dir_server_t *ent;
- uint32_t a;
char *hostname_ = NULL;
tor_assert(digest);
@@ -274,27 +301,26 @@ dir_server_new(int is_authority,
if (weight < 0)
return NULL;
- if (tor_addr_family(addr) == AF_INET)
- a = tor_addr_to_ipv4h(addr);
- else
+ if (!ipv4_addr) {
return NULL;
+ }
if (!hostname)
- hostname_ = tor_addr_to_str_dup(addr);
+ hostname_ = tor_addr_to_str_dup(ipv4_addr);
else
hostname_ = tor_strdup(hostname);
ent = tor_malloc_zero(sizeof(dir_server_t));
ent->nickname = nickname ? tor_strdup(nickname) : NULL;
ent->address = hostname_;
- ent->addr = a;
- ent->dir_port = dir_port;
- ent->or_port = or_port;
+ tor_addr_copy(&ent->ipv4_addr, ipv4_addr);
+ ent->ipv4_dirport = ipv4_dirport;
+ ent->ipv4_orport = ipv4_orport;
ent->is_running = 1;
ent->is_authority = is_authority;
ent->type = type;
ent->weight = weight;
- if (addrport_ipv6) {
+ if (addrport_ipv6 && tor_addr_port_is_valid_ap(addrport_ipv6, 0)) {
if (tor_addr_family(&addrport_ipv6->addr) != AF_INET6) {
log_warn(LD_BUG, "Hey, I got a non-ipv6 addr as addrport_ipv6.");
tor_addr_make_unspec(&ent->ipv6_addr);
@@ -311,13 +337,13 @@ dir_server_new(int is_authority,
memcpy(ent->v3_identity_digest, v3_auth_digest, DIGEST_LEN);
if (nickname)
- tor_asprintf(&ent->description, "directory server \"%s\" at %s:%d",
- nickname, hostname_, (int)dir_port);
+ tor_asprintf(&ent->description, "directory server \"%s\" at %s:%" PRIu16,
+ nickname, hostname_, ipv4_dirport);
else
- tor_asprintf(&ent->description, "directory server at %s:%d",
- hostname_, (int)dir_port);
+ tor_asprintf(&ent->description, "directory server at %s:%" PRIu16,
+ hostname_, ipv4_dirport);
- ent->fake_status.addr = ent->addr;
+ tor_addr_copy(&ent->fake_status.ipv4_addr, &ent->ipv4_addr);
tor_addr_copy(&ent->fake_status.ipv6_addr, &ent->ipv6_addr);
memcpy(ent->fake_status.identity_digest, digest, DIGEST_LEN);
if (nickname)
@@ -325,44 +351,43 @@ dir_server_new(int is_authority,
sizeof(ent->fake_status.nickname));
else
ent->fake_status.nickname[0] = '\0';
- ent->fake_status.dir_port = ent->dir_port;
- ent->fake_status.or_port = ent->or_port;
+ ent->fake_status.ipv4_dirport = ent->ipv4_dirport;
+ ent->fake_status.ipv4_orport = ent->ipv4_orport;
ent->fake_status.ipv6_orport = ent->ipv6_orport;
return ent;
}
-/** Create an authoritative directory server at
- * <b>address</b>:<b>port</b>, with identity key <b>digest</b>. If
- * <b>address</b> is NULL, add ourself. Return the new trusted directory
- * server entry on success or NULL if we couldn't add it. */
+/** Create an authoritative directory server at <b>address</b>:<b>port</b>,
+ * with identity key <b>digest</b>. If <b>ipv4_addr_str</b> is NULL, add
+ * ourself. Return the new trusted directory server entry on success or NULL
+ * if we couldn't add it. */
dir_server_t *
trusted_dir_server_new(const char *nickname, const char *address,
- uint16_t dir_port, uint16_t or_port,
+ uint16_t ipv4_dirport, uint16_t ipv4_orport,
const tor_addr_port_t *ipv6_addrport,
const char *digest, const char *v3_auth_digest,
dirinfo_type_t type, double weight)
{
- uint32_t a;
- tor_addr_t addr;
+ tor_addr_t ipv4_addr;
char *hostname=NULL;
dir_server_t *result;
if (!address) { /* The address is us; we should guess. */
- if (resolve_my_address(LOG_WARN, get_options(),
- &a, NULL, &hostname) < 0) {
+ if (!find_my_address(get_options(), AF_INET, LOG_WARN, &ipv4_addr,
+ NULL, &hostname)) {
log_warn(LD_CONFIG,
"Couldn't find a suitable address when adding ourself as a "
"trusted directory server.");
return NULL;
}
if (!hostname)
- hostname = tor_dup_ip(a);
+ hostname = tor_addr_to_str_dup(&ipv4_addr);
if (!hostname)
return NULL;
} else {
- if (tor_lookup_hostname(address, &a)) {
+ if (tor_addr_lookup(address, AF_INET, &ipv4_addr)) {
log_warn(LD_CONFIG,
"Unable to lookup address for directory server at '%s'",
address);
@@ -370,10 +395,9 @@ trusted_dir_server_new(const char *nickname, const char *address,
}
hostname = tor_strdup(address);
}
- tor_addr_from_ipv4h(&addr, a);
- result = dir_server_new(1, nickname, &addr, hostname,
- dir_port, or_port,
+ result = dir_server_new(1, nickname, &ipv4_addr, hostname,
+ ipv4_dirport, ipv4_orport,
ipv6_addrport,
digest,
v3_auth_digest, type, weight);
@@ -385,15 +409,13 @@ trusted_dir_server_new(const char *nickname, const char *address,
* <b>addr</b>:<b>or_port</b>/<b>dir_port</b>, with identity key digest
* <b>id_digest</b> */
dir_server_t *
-fallback_dir_server_new(const tor_addr_t *addr,
- uint16_t dir_port, uint16_t or_port,
+fallback_dir_server_new(const tor_addr_t *ipv4_addr,
+ uint16_t ipv4_dirport, uint16_t ipv4_orport,
const tor_addr_port_t *addrport_ipv6,
const char *id_digest, double weight)
{
- return dir_server_new(0, NULL, addr, NULL, dir_port, or_port,
- addrport_ipv6,
- id_digest,
- NULL, ALL_DIRINFO, weight);
+ return dir_server_new(0, NULL, ipv4_addr, NULL, ipv4_dirport, ipv4_orport,
+ addrport_ipv6, id_digest, NULL, ALL_DIRINFO, weight);
}
/** Add a directory server to the global list(s). */
diff --git a/src/feature/nodelist/dirlist.h b/src/feature/nodelist/dirlist.h
index 9201e76a9c..c9310ff357 100644
--- a/src/feature/nodelist/dirlist.h
+++ b/src/feature/nodelist/dirlist.h
@@ -25,6 +25,11 @@ int router_digest_is_fallback_dir(const char *digest);
MOCK_DECL(dir_server_t *, trusteddirserver_get_by_v3_auth_digest,
(const char *d));
+bool router_addr_is_trusted_dir_type(const tor_addr_t *addr,
+ dirinfo_type_t type);
+#define router_addr_is_trusted_dir(d) \
+ router_addr_is_trusted_dir_type((d), NO_DIRINFO)
+
int router_digest_is_trusted_dir_type(const char *digest,
dirinfo_type_t type);
#define router_digest_is_trusted_dir(d) \
diff --git a/src/feature/nodelist/fmt_routerstatus.c b/src/feature/nodelist/fmt_routerstatus.c
index ca4a312639..252b2e61fe 100644
--- a/src/feature/nodelist/fmt_routerstatus.c
+++ b/src/feature/nodelist/fmt_routerstatus.c
@@ -53,7 +53,7 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
char digest64[BASE64_DIGEST_LEN+1];
smartlist_t *chunks = smartlist_new();
- const char *ip_str = fmt_addr32(rs->addr);
+ const char *ip_str = fmt_addr(&rs->ipv4_addr);
if (ip_str[0] == '\0')
goto err;
@@ -62,15 +62,15 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
digest_to_base64(digest64, rs->descriptor_digest);
smartlist_add_asprintf(chunks,
- "r %s %s %s%s%s %s %d %d\n",
+ "r %s %s %s%s%s %s %" PRIu16 " %" PRIu16 "\n",
rs->nickname,
identity64,
(format==NS_V3_CONSENSUS_MICRODESC)?"":digest64,
(format==NS_V3_CONSENSUS_MICRODESC)?"":" ",
published,
ip_str,
- (int)rs->or_port,
- (int)rs->dir_port);
+ rs->ipv4_orport,
+ rs->ipv4_dirport);
/* TODO: Maybe we want to pass in what we need to build the rest of
* this here, instead of in the caller. Then we could use the
diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c
index e07d58c91c..9210518de0 100644
--- a/src/feature/nodelist/networkstatus.c
+++ b/src/feature/nodelist/networkstatus.c
@@ -471,8 +471,8 @@ networkstatus_check_document_signature(const networkstatus_t *consensus,
DIGEST_LEN))
return -1;
- if (authority_cert_is_blacklisted(cert)) {
- /* We implement blacklisting for authority signing keys by treating
+ if (authority_cert_is_denylisted(cert)) {
+ /* We implement denylisting for authority signing keys by treating
* all their signatures as always bad. That way we don't get into
* crazy loops of dropping and re-fetching signatures. */
log_warn(LD_DIR, "Ignoring a consensus signature made with deprecated"
@@ -608,25 +608,25 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus,
SMARTLIST_FOREACH(unrecognized, networkstatus_voter_info_t *, voter,
{
tor_log(severity, LD_DIR, "Consensus includes unrecognized authority "
- "'%s' at %s:%d (contact %s; identity %s)",
- voter->nickname, voter->address, (int)voter->dir_port,
+ "'%s' at %s:%" PRIu16 " (contact %s; identity %s)",
+ voter->nickname, voter->address, voter->ipv4_dirport,
voter->contact?voter->contact:"n/a",
hex_str(voter->identity_digest, DIGEST_LEN));
});
SMARTLIST_FOREACH(need_certs_from, networkstatus_voter_info_t *, voter,
{
tor_log(severity, LD_DIR, "Looks like we need to download a new "
- "certificate from authority '%s' at %s:%d (contact %s; "
- "identity %s)",
- voter->nickname, voter->address, (int)voter->dir_port,
+ "certificate from authority '%s' at %s:%" PRIu16
+ " (contact %s; identity %s)",
+ voter->nickname, voter->address, voter->ipv4_dirport,
voter->contact?voter->contact:"n/a",
hex_str(voter->identity_digest, DIGEST_LEN));
});
SMARTLIST_FOREACH(missing_authorities, dir_server_t *, ds,
{
tor_log(severity, LD_DIR, "Consensus does not include configured "
- "authority '%s' at %s:%d (identity %s)",
- ds->nickname, ds->address, (int)ds->dir_port,
+ "authority '%s' at %s:%" PRIu16 " (identity %s)",
+ ds->nickname, ds->address, ds->ipv4_dirport,
hex_str(ds->v3_identity_digest, DIGEST_LEN));
});
{
@@ -1594,9 +1594,9 @@ routerstatus_has_visibly_changed(const routerstatus_t *a,
return strcmp(a->nickname, b->nickname) ||
fast_memneq(a->descriptor_digest, b->descriptor_digest, DIGEST_LEN) ||
- a->addr != b->addr ||
- a->or_port != b->or_port ||
- a->dir_port != b->dir_port ||
+ !tor_addr_eq(&a->ipv4_addr, &b->ipv4_addr) ||
+ a->ipv4_orport != b->ipv4_orport ||
+ a->ipv4_dirport != b->ipv4_dirport ||
a->is_authority != b->is_authority ||
a->is_exit != b->is_exit ||
a->is_stable != b->is_stable ||
@@ -1670,7 +1670,35 @@ notify_before_networkstatus_changes(const networkstatus_t *old_c,
static void
notify_after_networkstatus_changes(void)
{
+ const networkstatus_t *c = networkstatus_get_latest_consensus();
+ const or_options_t *options = get_options();
+ const time_t now = approx_time();
+
scheduler_notify_networkstatus_changed();
+
+ /* The "current" consensus has just been set and it is a usable flavor so
+ * the first thing we need to do is recalculate the voting schedule static
+ * object so we can use the timings in there needed by some subsystems
+ * such as hidden service and shared random. */
+ dirauth_sched_recalculate_timing(options, now);
+ reschedule_dirvote(options);
+
+ nodelist_set_consensus(c);
+
+ update_consensus_networkstatus_fetch_time(now);
+
+ /* Change the cell EWMA settings */
+ cmux_ewma_set_options(options, c);
+
+ /* XXXX this call might be unnecessary here: can changing the
+ * current consensus really alter our view of any OR's rate limits? */
+ connection_or_update_token_buckets(get_connection_array(), options);
+
+ circuit_build_times_new_consensus_params(
+ get_circuit_build_times_mutable(), c);
+ channelpadding_new_consensus_params(c);
+ circpad_new_consensus_params(c);
+ router_new_consensus_params(c);
}
/** Copy all the ancillary information (like router download status and so on)
@@ -2115,29 +2143,6 @@ networkstatus_set_current_consensus(const char *consensus,
/* Notify that we just changed the consensus so the current global value
* can be looked at. */
notify_after_networkstatus_changes();
-
- /* The "current" consensus has just been set and it is a usable flavor so
- * the first thing we need to do is recalculate the voting schedule static
- * object so we can use the timings in there needed by some subsystems
- * such as hidden service and shared random. */
- dirauth_sched_recalculate_timing(options, now);
- reschedule_dirvote(options);
-
- nodelist_set_consensus(c);
-
- update_consensus_networkstatus_fetch_time(now);
-
- /* Change the cell EWMA settings */
- cmux_ewma_set_options(options, c);
-
- /* XXXX this call might be unnecessary here: can changing the
- * current consensus really alter our view of any OR's rate limits? */
- connection_or_update_token_buckets(get_connection_array(), options);
-
- circuit_build_times_new_consensus_params(
- get_circuit_build_times_mutable(), c);
- channelpadding_new_consensus_params(c);
- circpad_new_consensus_params(c);
}
/* Reset the failure count only if this consensus is actually valid. */
@@ -2387,10 +2392,10 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
memcpy(rs->identity_digest, node->identity, DIGEST_LEN);
memcpy(rs->descriptor_digest, ri->cache_info.signed_descriptor_digest,
DIGEST_LEN);
- rs->addr = ri->addr;
+ tor_addr_copy(&rs->ipv4_addr, &ri->ipv4_addr);
strlcpy(rs->nickname, ri->nickname, sizeof(rs->nickname));
- rs->or_port = ri->or_port;
- rs->dir_port = ri->dir_port;
+ rs->ipv4_orport = ri->ipv4_orport;
+ rs->ipv4_dirport = ri->ipv4_dirport;
rs->is_v2_dir = ri->supports_tunnelled_dir_requests;
tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr);
diff --git a/src/feature/nodelist/networkstatus_voter_info_st.h b/src/feature/nodelist/networkstatus_voter_info_st.h
index b4d0b1dd17..a0fba2e1b5 100644
--- a/src/feature/nodelist/networkstatus_voter_info_st.h
+++ b/src/feature/nodelist/networkstatus_voter_info_st.h
@@ -21,9 +21,9 @@ struct networkstatus_voter_info_t {
* consensuses, we treat legacy keys as additional signers. */
char legacy_id_digest[DIGEST_LEN];
char *address; /**< Address of this voter, in string format. */
- uint32_t addr; /**< Address of this voter, in IPv4, in host order. */
- uint16_t dir_port; /**< Directory port of this voter */
- uint16_t or_port; /**< OR port of this voter */
+ tor_addr_t ipv4_addr;
+ uint16_t ipv4_dirport; /**< Directory port of this voter */
+ uint16_t ipv4_orport; /**< OR port of this voter */
char *contact; /**< Contact information for this voter. */
char vote_digest[DIGEST_LEN]; /**< Digest of this voter's vote, as signed. */
diff --git a/src/feature/nodelist/node_select.c b/src/feature/nodelist/node_select.c
index e831248413..ecb70aef14 100644
--- a/src/feature/nodelist/node_select.c
+++ b/src/feature/nodelist/node_select.c
@@ -141,7 +141,7 @@ router_pick_dirserver_generic(smartlist_t *sourcelist,
#define RETRY_ALTERNATE_IP_VERSION(retry_label) \
STMT_BEGIN \
if (result == NULL && try_ip_pref && options->ClientUseIPv4 \
- && fascist_firewall_use_ipv6(options) && !server_mode(options) \
+ && reachable_addr_use_ipv6(options) && !server_mode(options) \
&& !n_busy) { \
n_excluded = 0; \
n_busy = 0; \
@@ -212,18 +212,20 @@ router_picked_poor_directory_log(const routerstatus_t *rs)
log_debug(LD_DIR, "Wanted to make an outgoing directory connection, but "
"we couldn't find a directory that fit our criteria. "
"Perhaps we will succeed next time with less strict criteria.");
- } else if (!fascist_firewall_allows_rs(rs, FIREWALL_OR_CONNECTION, 1)
- && !fascist_firewall_allows_rs(rs, FIREWALL_DIR_CONNECTION, 1)
+ } else if (!reachable_addr_allows_rs(rs, FIREWALL_OR_CONNECTION, 1)
+ && !reachable_addr_allows_rs(rs, FIREWALL_DIR_CONNECTION, 1)
) {
/* This is rare, and might be interesting to users trying to diagnose
* connection issues on dual-stack machines. */
+ char *ipv4_str = tor_addr_to_str_dup(&rs->ipv4_addr);
log_info(LD_DIR, "Selected a directory %s with non-preferred OR and Dir "
"addresses for launching an outgoing connection: "
"IPv4 %s OR %d Dir %d IPv6 %s OR %d Dir %d",
routerstatus_describe(rs),
- fmt_addr32(rs->addr), rs->or_port,
- rs->dir_port, fmt_addr(&rs->ipv6_addr),
- rs->ipv6_orport, rs->dir_port);
+ ipv4_str, rs->ipv4_orport,
+ rs->ipv4_dirport, fmt_addr(&rs->ipv6_addr),
+ rs->ipv6_orport, rs->ipv4_dirport);
+ tor_free(ipv4_str);
}
}
@@ -266,7 +268,7 @@ router_is_already_dir_fetching(const tor_addr_port_t *ap, int serverdesc,
* If so, return 1, if not, return 0.
*/
static int
-router_is_already_dir_fetching_(uint32_t ipv4_addr,
+router_is_already_dir_fetching_(const tor_addr_t *ipv4_addr,
const tor_addr_t *ipv6_addr,
uint16_t dir_port,
int serverdesc,
@@ -275,7 +277,7 @@ router_is_already_dir_fetching_(uint32_t ipv4_addr,
tor_addr_port_t ipv4_dir_ap, ipv6_dir_ap;
/* Assume IPv6 DirPort is the same as IPv4 DirPort */
- tor_addr_from_ipv4h(&ipv4_dir_ap.addr, ipv4_addr);
+ tor_addr_copy(&ipv4_dir_ap.addr, ipv4_addr);
ipv4_dir_ap.port = dir_port;
tor_addr_copy(&ipv6_dir_ap.addr, ipv6_addr);
ipv6_dir_ap.port = dir_port;
@@ -321,8 +323,12 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
overloaded_direct = smartlist_new();
overloaded_tunnel = smartlist_new();
- const int skip_or_fw = router_skip_or_reachability(options, try_ip_pref);
- const int skip_dir_fw = router_skip_dir_reachability(options, try_ip_pref);
+ const int skip_or_fw = router_or_conn_should_skip_reachable_address_check(
+ options,
+ try_ip_pref);
+ const int skip_dir_fw = router_dir_conn_should_skip_reachable_address_check(
+ options,
+ try_ip_pref);
const int must_have_or = dirclient_must_use_begindir(options);
/* Find all the running dirservers we know about. */
@@ -348,9 +354,9 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
continue;
}
- if (router_is_already_dir_fetching_(status->addr,
+ if (router_is_already_dir_fetching_(&status->ipv4_addr,
&status->ipv6_addr,
- status->dir_port,
+ status->ipv4_dirport,
no_serverdesc_fetching,
no_microdesc_fetching)) {
++n_busy;
@@ -368,12 +374,12 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
* we try routers that only have one address both times.)
*/
if (!fascistfirewall || skip_or_fw ||
- fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION,
+ reachable_addr_allows_node(node, FIREWALL_OR_CONNECTION,
try_ip_pref))
smartlist_add(is_trusted ? trusted_tunnel :
is_overloaded ? overloaded_tunnel : tunnel, (void*)node);
else if (!must_have_or && (skip_dir_fw ||
- fascist_firewall_allows_node(node, FIREWALL_DIR_CONNECTION,
+ reachable_addr_allows_node(node, FIREWALL_DIR_CONNECTION,
try_ip_pref)))
smartlist_add(is_trusted ? trusted_direct :
is_overloaded ? overloaded_direct : direct, (void*)node);
@@ -926,64 +932,67 @@ nodelist_subtract(smartlist_t *sl, const smartlist_t *excluded)
bitarray_free(excluded_idx);
}
-/** Return a random running node from the nodelist. Never
- * pick a node that is in
- * <b>excludedsmartlist</b>, or which matches <b>excludedset</b>,
- * even if they are the only nodes available.
- * If <b>CRN_NEED_UPTIME</b> is set in flags and any router has more than
- * a minimum uptime, return one of those.
- * If <b>CRN_NEED_CAPACITY</b> is set in flags, weight your choice by the
- * advertised capacity of each router.
- * If <b>CRN_NEED_GUARD</b> is set in flags, consider only Guard routers.
- * If <b>CRN_WEIGHT_AS_EXIT</b> is set in flags, we weight bandwidths as if
- * picking an exit node, otherwise we weight bandwidths for picking a relay
- * node (that is, possibly discounting exit nodes).
- * If <b>CRN_NEED_DESC</b> is set in flags, we only consider nodes that
- * have a routerinfo or microdescriptor -- that is, enough info to be
- * used to build a circuit.
- * If <b>CRN_PREF_ADDR</b> is set in flags, we only consider nodes that
- * have an address that is preferred by the ClientPreferIPv6ORPort setting
- * (regardless of this flag, we exclude nodes that aren't allowed by the
- * firewall, including ClientUseIPv4 0 and fascist_firewall_use_ipv6() == 0).
+/* Node selection helper for router_choose_random_node().
+ *
+ * Populates a node list based on <b>flags</b>, ignoring nodes in
+ * <b>excludednodes</b> and <b>excludedset</b>. Chooses the node based on
+ * <b>rule</b>. */
+static const node_t *
+router_choose_random_node_helper(smartlist_t *excludednodes,
+ routerset_t *excludedset,
+ router_crn_flags_t flags,
+ bandwidth_weight_rule_t rule)
+{
+ smartlist_t *sl=smartlist_new();
+ const node_t *choice = NULL;
+
+ router_add_running_nodes_to_smartlist(sl, flags);
+ log_debug(LD_CIRC,
+ "We found %d running nodes.",
+ smartlist_len(sl));
+
+ nodelist_subtract(sl, excludednodes);
+
+ if (excludedset) {
+ routerset_subtract_nodes(sl,excludedset);
+ log_debug(LD_CIRC,
+ "We removed excludedset, leaving %d nodes.",
+ smartlist_len(sl));
+ }
+
+ // Always weight by bandwidth
+ choice = node_sl_choose_by_bandwidth(sl, rule);
+
+ smartlist_free(sl);
+
+ return choice;
+}
+
+/** Return a random running node from the nodelist. Never pick a node that is
+ * in <b>excludedsmartlist</b>, or which matches <b>excludedset</b>, even if
+ * they are the only nodes available.
+ *
+ * <b>flags</b> is a set of CRN_* flags, see
+ * router_add_running_nodes_to_smartlist() for details.
*/
const node_t *
router_choose_random_node(smartlist_t *excludedsmartlist,
routerset_t *excludedset,
router_crn_flags_t flags)
-{ /* XXXX MOVE */
- const int need_uptime = (flags & CRN_NEED_UPTIME) != 0;
- const int need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
- const int need_guard = (flags & CRN_NEED_GUARD) != 0;
- const int weight_for_exit = (flags & CRN_WEIGHT_AS_EXIT) != 0;
- const int need_desc = (flags & CRN_NEED_DESC) != 0;
- const int pref_addr = (flags & CRN_PREF_ADDR) != 0;
- const int direct_conn = (flags & CRN_DIRECT_CONN) != 0;
- const int rendezvous_v3 = (flags & CRN_RENDEZVOUS_V3) != 0;
-
- const smartlist_t *node_list = nodelist_get_list();
- smartlist_t *sl=smartlist_new(),
- *excludednodes=smartlist_new();
+{
+ /* A limited set of flags, used for fallback node selection.
+ */
+ const bool need_uptime = (flags & CRN_NEED_UPTIME) != 0;
+ const bool need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
+ const bool need_guard = (flags & CRN_NEED_GUARD) != 0;
+ const bool pref_addr = (flags & CRN_PREF_ADDR) != 0;
+
+ smartlist_t *excludednodes=smartlist_new();
const node_t *choice = NULL;
const routerinfo_t *r;
bandwidth_weight_rule_t rule;
- tor_assert(!(weight_for_exit && need_guard));
- rule = weight_for_exit ? WEIGHT_FOR_EXIT :
- (need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID);
-
- SMARTLIST_FOREACH_BEGIN(node_list, const node_t *, node) {
- if (node_allows_single_hop_exits(node)) {
- /* Exclude relays that allow single hop exit circuits. This is an
- * obsolete option since 0.2.9.2-alpha and done by default in
- * 0.3.1.0-alpha. */
- smartlist_add(excludednodes, (node_t*)node);
- } else if (rendezvous_v3 &&
- !node_supports_v3_rendezvous_point(node)) {
- /* Exclude relays that do not support to rendezvous for a hidden service
- * version 3. */
- smartlist_add(excludednodes, (node_t*)node);
- }
- } SMARTLIST_FOREACH_END(node);
+ rule = (need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID);
/* If the node_t is not found we won't be to exclude ourself but we
* won't be able to pick ourself in router_choose_random_node() so
@@ -991,41 +1000,30 @@ router_choose_random_node(smartlist_t *excludedsmartlist,
if ((r = router_get_my_routerinfo()))
routerlist_add_node_and_family(excludednodes, r);
- router_add_running_nodes_to_smartlist(sl, need_uptime, need_capacity,
- need_guard, need_desc, pref_addr,
- direct_conn);
- log_debug(LD_CIRC,
- "We found %d running nodes.",
- smartlist_len(sl));
-
if (excludedsmartlist) {
smartlist_add_all(excludednodes, excludedsmartlist);
}
- nodelist_subtract(sl, excludednodes);
- if (excludedset) {
- routerset_subtract_nodes(sl,excludedset);
- log_debug(LD_CIRC,
- "We removed excludedset, leaving %d nodes.",
- smartlist_len(sl));
- }
+ choice = router_choose_random_node_helper(excludednodes,
+ excludedset,
+ flags,
+ rule);
- // Always weight by bandwidth
- choice = node_sl_choose_by_bandwidth(sl, rule);
-
- smartlist_free(sl);
if (!choice && (need_uptime || need_capacity || need_guard || pref_addr)) {
- /* try once more -- recurse but with fewer restrictions. */
+ /* try once more, with fewer restrictions. */
log_info(LD_CIRC,
- "We couldn't find any live%s%s%s routers; falling back "
+ "We couldn't find any live%s%s%s%s routers; falling back "
"to list of all routers.",
need_capacity?", fast":"",
need_uptime?", stable":"",
- need_guard?", guard":"");
+ need_guard?", guard":"",
+ pref_addr?", preferred address":"");
flags &= ~ (CRN_NEED_UPTIME|CRN_NEED_CAPACITY|CRN_NEED_GUARD|
CRN_PREF_ADDR);
- choice = router_choose_random_node(
- excludedsmartlist, excludedset, flags);
+ choice = router_choose_random_node_helper(excludednodes,
+ excludedset,
+ flags,
+ rule);
}
smartlist_free(excludednodes);
if (!choice) {
@@ -1120,8 +1118,12 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
overloaded_direct = smartlist_new();
overloaded_tunnel = smartlist_new();
- const int skip_or_fw = router_skip_or_reachability(options, try_ip_pref);
- const int skip_dir_fw = router_skip_dir_reachability(options, try_ip_pref);
+ const int skip_or_fw = router_or_conn_should_skip_reachable_address_check(
+ options,
+ try_ip_pref);
+ const int skip_dir_fw = router_dir_conn_should_skip_reachable_address_check(
+ options,
+ try_ip_pref);
const int must_have_or = dirclient_must_use_begindir(options);
SMARTLIST_FOREACH_BEGIN(sourcelist, const dir_server_t *, d)
@@ -1143,9 +1145,9 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
continue;
}
- if (router_is_already_dir_fetching_(d->addr,
+ if (router_is_already_dir_fetching_(&d->ipv4_addr,
&d->ipv6_addr,
- d->dir_port,
+ d->ipv4_dirport,
no_serverdesc_fetching,
no_microdesc_fetching)) {
++n_busy;
@@ -1160,11 +1162,11 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
* we try routers that only have one address both times.)
*/
if (!fascistfirewall || skip_or_fw ||
- fascist_firewall_allows_dir_server(d, FIREWALL_OR_CONNECTION,
+ reachable_addr_allows_dir_server(d, FIREWALL_OR_CONNECTION,
try_ip_pref))
smartlist_add(is_overloaded ? overloaded_tunnel : tunnel, (void*)d);
else if (!must_have_or && (skip_dir_fw ||
- fascist_firewall_allows_dir_server(d, FIREWALL_DIR_CONNECTION,
+ reachable_addr_allows_dir_server(d, FIREWALL_DIR_CONNECTION,
try_ip_pref)))
smartlist_add(is_overloaded ? overloaded_direct : direct, (void*)d);
}
diff --git a/src/feature/nodelist/node_select.h b/src/feature/nodelist/node_select.h
index 2e67f990f6..1776d8ea1a 100644
--- a/src/feature/nodelist/node_select.h
+++ b/src/feature/nodelist/node_select.h
@@ -14,20 +14,26 @@
/** Flags to be passed to control router_choose_random_node() to indicate what
* kind of nodes to pick according to what algorithm. */
typedef enum router_crn_flags_t {
+ /* Try to choose stable nodes. */
CRN_NEED_UPTIME = 1<<0,
+ /* Try to choose nodes with a reasonable amount of bandwidth. */
CRN_NEED_CAPACITY = 1<<1,
- CRN_NEED_GUARD = 1<<2,
- /* XXXX not used, apparently. */
- CRN_WEIGHT_AS_EXIT = 1<<5,
- CRN_NEED_DESC = 1<<6,
- /* On clients, only provide nodes that satisfy ClientPreferIPv6OR */
- CRN_PREF_ADDR = 1<<7,
+ /* Only choose nodes if we have downloaded their descriptor or
+ * microdescriptor. */
+ CRN_NEED_DESC = 1<<2,
+ /* Choose nodes that can be used as Guard relays. */
+ CRN_NEED_GUARD = 1<<3,
/* On clients, only provide nodes that we can connect to directly, based on
- * our firewall rules */
- CRN_DIRECT_CONN = 1<<8,
- /* On clients, only provide nodes with HSRend >= 2 protocol version which
- * is required for hidden service version >= 3. */
- CRN_RENDEZVOUS_V3 = 1<<9,
+ * our firewall rules. */
+ CRN_DIRECT_CONN = 1<<4,
+ /* On clients, if choosing a node for a direct connection, only provide
+ * nodes that satisfy ClientPreferIPv6OR. */
+ CRN_PREF_ADDR = 1<<5,
+ /* On clients, only provide nodes with HSRend=2 protocol version which
+ * is required for hidden service version 3. */
+ CRN_RENDEZVOUS_V3 = 1<<6,
+ /* On clients, only provide nodes that can initiate IPv6 extends. */
+ CRN_INITIATE_IPV6_EXTEND = 1<<7,
} router_crn_flags_t;
/** Possible ways to weight routers when choosing one randomly. See
diff --git a/src/feature/nodelist/node_st.h b/src/feature/nodelist/node_st.h
index b1ec4db202..3769f9dc84 100644
--- a/src/feature/nodelist/node_st.h
+++ b/src/feature/nodelist/node_st.h
@@ -84,12 +84,11 @@ struct node_t {
/* Local info: derived. */
- /** True if the IPv6 OR port is preferred over the IPv4 OR port.
- * XX/teor - can this become out of date if the torrc changes? */
+ /** True if the IPv6 OR port is preferred over the IPv4 OR port. */
unsigned int ipv6_preferred:1;
/** According to the geoip db what country is this router in? */
- /* XXXprop186 what is this suppose to mean with multiple OR ports? */
+ /* IPv6: what is this supposed to mean with multiple OR ports? */
country_t country;
/* The below items are used only by authdirservers for
diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c
index 7454f342f9..7edc1fc51c 100644
--- a/src/feature/nodelist/nodelist.c
+++ b/src/feature/nodelist/nodelist.c
@@ -454,38 +454,29 @@ node_add_to_address_set(const node_t *node)
* to add them all than to compare them all for equality. */
if (node->rs) {
- if (node->rs->addr)
- nodelist_add_addr4_to_address_set(node->rs->addr);
+ if (!tor_addr_is_null(&node->rs->ipv4_addr))
+ nodelist_add_addr_to_address_set(&node->rs->ipv4_addr);
if (!tor_addr_is_null(&node->rs->ipv6_addr))
- nodelist_add_addr6_to_address_set(&node->rs->ipv6_addr);
+ nodelist_add_addr_to_address_set(&node->rs->ipv6_addr);
}
if (node->ri) {
- if (node->ri->addr)
- nodelist_add_addr4_to_address_set(node->ri->addr);
+ if (!tor_addr_is_null(&node->ri->ipv4_addr))
+ nodelist_add_addr_to_address_set(&node->ri->ipv4_addr);
if (!tor_addr_is_null(&node->ri->ipv6_addr))
- nodelist_add_addr6_to_address_set(&node->ri->ipv6_addr);
+ nodelist_add_addr_to_address_set(&node->ri->ipv6_addr);
}
if (node->md) {
if (!tor_addr_is_null(&node->md->ipv6_addr))
- nodelist_add_addr6_to_address_set(&node->md->ipv6_addr);
+ nodelist_add_addr_to_address_set(&node->md->ipv6_addr);
}
}
-/** Add the given v4 address into the nodelist address set. */
+/** Add the given address into the nodelist address set. */
void
-nodelist_add_addr4_to_address_set(const uint32_t addr)
+nodelist_add_addr_to_address_set(const tor_addr_t *addr)
{
- if (!the_nodelist || !the_nodelist->node_addrs || addr == 0) {
- return;
- }
- address_set_add_ipv4h(the_nodelist->node_addrs, addr);
-}
-
-/** Add the given v6 address into the nodelist address set. */
-void
-nodelist_add_addr6_to_address_set(const tor_addr_t *addr)
-{
- if (BUG(!addr) || tor_addr_is_null(addr) || tor_addr_is_v4(addr) ||
+ if (BUG(!addr) || tor_addr_is_null(addr) ||
+ (!tor_addr_is_v4(addr) && !tor_addr_is_v6(addr)) ||
!the_nodelist || !the_nodelist->node_addrs) {
return;
}
@@ -621,7 +612,7 @@ get_estimated_address_per_node, (void))
* and grab microdescriptors into nodes as appropriate.
*/
void
-nodelist_set_consensus(networkstatus_t *ns)
+nodelist_set_consensus(const networkstatus_t *ns)
{
const or_options_t *options = get_options();
int authdir = authdir_mode_v3(options);
@@ -675,7 +666,7 @@ nodelist_set_consensus(networkstatus_t *ns)
node->is_bad_exit = rs->is_bad_exit;
node->is_hs_dir = rs->is_hs_dir;
node->ipv6_preferred = 0;
- if (fascist_firewall_prefer_ipv6_orport(options) &&
+ if (reachable_addr_prefer_ipv6_orport(options) &&
(tor_addr_is_null(&rs->ipv6_addr) == 0 ||
(node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0)))
node->ipv6_preferred = 1;
@@ -952,7 +943,7 @@ nodelist_assert_ok(void)
/** Ensure that the nodelist has been created with the most recent consensus.
* If that's not the case, make it so. */
void
-nodelist_ensure_freshness(networkstatus_t *ns)
+nodelist_ensure_freshness(const networkstatus_t *ns)
{
tor_assert(ns);
@@ -1133,7 +1124,7 @@ node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id)
/** Dummy object that should be unreturnable. Used to ensure that
* node_get_protover_summary_flags() always returns non-NULL. */
static const protover_summary_flags_t zero_protover_flags = {
- 0,0,0,0,0,0,0,0,0
+ 0,0,0,0,0,0,0,0,0,0,0,0
};
/** Return the protover_summary_flags for a given node. */
@@ -1158,9 +1149,9 @@ node_get_protover_summary_flags(const node_t *node)
* by ed25519 ID during the link handshake. If <b>compatible_with_us</b>,
* it needs to be using a link authentication method that we understand.
* If not, any plausible link authentication method will do. */
-MOCK_IMPL(int,
+MOCK_IMPL(bool,
node_supports_ed25519_link_authentication,(const node_t *node,
- int compatible_with_us))
+ bool compatible_with_us))
{
if (! node_get_ed25519_id(node))
return 0;
@@ -1175,7 +1166,7 @@ node_supports_ed25519_link_authentication,(const node_t *node,
/** Return true iff <b>node</b> supports the hidden service directory version
* 3 protocol (proposal 224). */
-int
+bool
node_supports_v3_hsdir(const node_t *node)
{
tor_assert(node);
@@ -1185,7 +1176,7 @@ node_supports_v3_hsdir(const node_t *node)
/** Return true iff <b>node</b> supports ed25519 authentication as an hidden
* service introduction point.*/
-int
+bool
node_supports_ed25519_hs_intro(const node_t *node)
{
tor_assert(node);
@@ -1193,9 +1184,24 @@ node_supports_ed25519_hs_intro(const node_t *node)
return node_get_protover_summary_flags(node)->supports_ed25519_hs_intro;
}
+/** Return true iff <b>node</b> can be a rendezvous point for hidden
+ * service version 3 (HSRend=2). */
+bool
+node_supports_v3_rendezvous_point(const node_t *node)
+{
+ tor_assert(node);
+
+ /* We can't use a v3 rendezvous point without the curve25519 onion pk. */
+ if (!node_get_curve25519_onion_key(node)) {
+ return 0;
+ }
+
+ return node_get_protover_summary_flags(node)->supports_v3_rendezvous_point;
+}
+
/** Return true iff <b>node</b> supports the DoS ESTABLISH_INTRO cell
* extenstion. */
-int
+bool
node_supports_establish_intro_dos_extension(const node_t *node)
{
tor_assert(node);
@@ -1204,19 +1210,54 @@ node_supports_establish_intro_dos_extension(const node_t *node)
supports_establish_intro_dos_extension;
}
-/** Return true iff <b>node</b> supports to be a rendezvous point for hidden
- * service version 3 (HSRend=2). */
-int
-node_supports_v3_rendezvous_point(const node_t *node)
+/** Return true iff <b>node</b> can initiate IPv6 extends (Relay=3).
+ *
+ * This check should only be performed by client path selection code.
+ *
+ * Extending relays should check their own IPv6 support using
+ * router_can_extend_over_ipv6(). Like other extends, they should not verify
+ * the link specifiers in the extend cell against the consensus, because it
+ * may be out of date. */
+bool
+node_supports_initiating_ipv6_extends(const node_t *node)
{
tor_assert(node);
- /* We can't use a v3 rendezvous point without the curve25519 onion pk. */
- if (!node_get_curve25519_onion_key(node)) {
+ /* Relays can't initiate an IPv6 extend, unless they have an IPv6 ORPort. */
+ if (!node_has_ipv6_orport(node)) {
return 0;
}
- return node_get_protover_summary_flags(node)->supports_v3_rendezvous_point;
+ /* Initiating relays also need to support the relevant protocol version. */
+ return
+ node_get_protover_summary_flags(node)->supports_initiating_ipv6_extends;
+}
+
+/** Return true iff <b>node</b> can accept IPv6 extends (Relay=2 or Relay=3)
+ * from other relays. If <b>need_canonical_ipv6_conn</b> is true, also check
+ * if the relay supports canonical IPv6 connections (Relay=3 only).
+ *
+ * This check should only be performed by client path selection code.
+ */
+bool
+node_supports_accepting_ipv6_extends(const node_t *node,
+ bool need_canonical_ipv6_conn)
+{
+ tor_assert(node);
+
+ /* Relays can't accept an IPv6 extend, unless they have an IPv6 ORPort. */
+ if (!node_has_ipv6_orport(node)) {
+ return 0;
+ }
+
+ /* Accepting relays also need to support the relevant protocol version. */
+ if (need_canonical_ipv6_conn) {
+ return
+ node_get_protover_summary_flags(node)->supports_canonical_ipv6_conns;
+ } else {
+ return
+ node_get_protover_summary_flags(node)->supports_accepting_ipv6_extends;
+ }
}
/** Return the RSA ID key's SHA1 digest for the provided node. */
@@ -1491,32 +1532,14 @@ node_exit_policy_is_exact(const node_t *node, sa_family_t family)
* "addr" is an IPv4 host-order address and port_field is a uint16_t.
* r is typically a routerinfo_t or routerstatus_t.
*/
-#define SL_ADD_NEW_IPV4_AP(r, port_field, sl, valid) \
- STMT_BEGIN \
- if (tor_addr_port_is_valid_ipv4h((r)->addr, (r)->port_field, 0)) { \
- valid = 1; \
- tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); \
- tor_addr_from_ipv4h(&ap->addr, (r)->addr); \
- ap->port = (r)->port_field; \
- smartlist_add((sl), ap); \
- } \
- STMT_END
-
-/* Check if the "addr" and port_field fields from r are a valid non-listening
- * address/port. If so, set valid to true and add a newly allocated
- * tor_addr_port_t containing "addr" and port_field to sl.
- * "addr" is a tor_addr_t and port_field is a uint16_t.
- * r is typically a routerinfo_t or routerstatus_t.
- */
-#define SL_ADD_NEW_IPV6_AP(r, port_field, sl, valid) \
- STMT_BEGIN \
- if (tor_addr_port_is_valid(&(r)->ipv6_addr, (r)->port_field, 0)) { \
- valid = 1; \
- tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t)); \
- tor_addr_copy(&ap->addr, &(r)->ipv6_addr); \
- ap->port = (r)->port_field; \
- smartlist_add((sl), ap); \
- } \
+#define SL_ADD_NEW_AP(r, addr_field, port_field, sl, valid) \
+ STMT_BEGIN \
+ if (tor_addr_port_is_valid(&(r)->addr_field, (r)->port_field, 0)) { \
+ valid = 1; \
+ tor_addr_port_t *ap = tor_addr_port_new(&(r)->addr_field, \
+ (r)->port_field); \
+ smartlist_add((sl), ap); \
+ } \
STMT_END
/** Return list of tor_addr_port_t with all OR ports (in the sense IP
@@ -1535,33 +1558,32 @@ node_get_all_orports(const node_t *node)
/* Find a valid IPv4 address and port */
if (node->ri != NULL) {
- SL_ADD_NEW_IPV4_AP(node->ri, or_port, sl, valid);
+ SL_ADD_NEW_AP(node->ri, ipv4_addr, ipv4_orport, sl, valid);
}
/* If we didn't find a valid address/port in the ri, try the rs */
if (!valid && node->rs != NULL) {
- SL_ADD_NEW_IPV4_AP(node->rs, or_port, sl, valid);
+ SL_ADD_NEW_AP(node->rs, ipv4_addr, ipv4_orport, sl, valid);
}
/* Find a valid IPv6 address and port */
valid = 0;
if (node->ri != NULL) {
- SL_ADD_NEW_IPV6_AP(node->ri, ipv6_orport, sl, valid);
+ SL_ADD_NEW_AP(node->ri, ipv6_addr, ipv6_orport, sl, valid);
}
if (!valid && node->rs != NULL) {
- SL_ADD_NEW_IPV6_AP(node->rs, ipv6_orport, sl, valid);
+ SL_ADD_NEW_AP(node->rs, ipv6_addr, ipv6_orport, sl, valid);
}
if (!valid && node->md != NULL) {
- SL_ADD_NEW_IPV6_AP(node->md, ipv6_orport, sl, valid);
+ SL_ADD_NEW_AP(node->md, ipv6_addr, ipv6_orport, sl, valid);
}
return sl;
}
-#undef SL_ADD_NEW_IPV4_AP
-#undef SL_ADD_NEW_IPV6_AP
+#undef SL_ADD_NEW_AP
/** Wrapper around node_get_prim_orport for backward
compatibility. */
@@ -1573,21 +1595,20 @@ node_get_addr(const node_t *node, tor_addr_t *addr_out)
tor_addr_copy(addr_out, &ap.addr);
}
-/** Return the host-order IPv4 address for <b>node</b>, or 0 if it doesn't
- * seem to have one. */
-uint32_t
-node_get_prim_addr_ipv4h(const node_t *node)
+/** Return the IPv4 address for <b>node</b>, or NULL if none found. */
+static const tor_addr_t *
+node_get_prim_addr_ipv4(const node_t *node)
{
/* Don't check the ORPort or DirPort, as this function isn't port-specific,
* and the node might have a valid IPv4 address, yet have a zero
* ORPort or DirPort.
*/
- if (node->ri && tor_addr_is_valid_ipv4h(node->ri->addr, 0)) {
- return node->ri->addr;
- } else if (node->rs && tor_addr_is_valid_ipv4h(node->rs->addr, 0)) {
- return node->rs->addr;
+ if (node->ri && tor_addr_is_valid(&node->ri->ipv4_addr, 0)) {
+ return &node->ri->ipv4_addr;
+ } else if (node->rs && tor_addr_is_valid(&node->rs->ipv4_addr, 0)) {
+ return &node->rs->ipv4_addr;
}
- return 0;
+ return NULL;
}
/** Copy a string representation of an IP address for <b>node</b> into
@@ -1595,12 +1616,10 @@ node_get_prim_addr_ipv4h(const node_t *node)
void
node_get_address_string(const node_t *node, char *buf, size_t len)
{
- uint32_t ipv4_addr = node_get_prim_addr_ipv4h(node);
+ const tor_addr_t *ipv4_addr = node_get_prim_addr_ipv4(node);
- if (tor_addr_is_valid_ipv4h(ipv4_addr, 0)) {
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, ipv4_addr);
- tor_addr_to_str(buf, &addr, len, 0);
+ if (ipv4_addr) {
+ tor_addr_to_str(buf, ipv4_addr, len, 0);
} else if (len > 0) {
buf[0] = '\0';
}
@@ -1685,7 +1704,7 @@ node_has_ipv6_dirport(const node_t *node)
* ii) the router has no IPv4 OR address.
*
* If you don't have a node, consider looking it up.
- * If there is no node, use fascist_firewall_prefer_ipv6_orport().
+ * If there is no node, use reachable_addr_prefer_ipv6_orport().
*/
int
node_ipv6_or_preferred(const node_t *node)
@@ -1695,10 +1714,10 @@ node_ipv6_or_preferred(const node_t *node)
node_assert_ok(node);
/* XX/teor - node->ipv6_preferred is set from
- * fascist_firewall_prefer_ipv6_orport() each time the consensus is loaded.
+ * reachable_addr_prefer_ipv6_orport() each time the consensus is loaded.
*/
node_get_prim_orport(node, &ipv4_addr);
- if (!fascist_firewall_use_ipv6(options)) {
+ if (!reachable_addr_use_ipv6(options)) {
return 0;
} else if (node->ipv6_preferred ||
!tor_addr_port_is_valid_ap(&ipv4_addr, 0)) {
@@ -1707,12 +1726,12 @@ node_ipv6_or_preferred(const node_t *node)
return 0;
}
-#define RETURN_IPV4_AP(r, port_field, ap_out) \
- STMT_BEGIN \
- if (r && tor_addr_port_is_valid_ipv4h((r)->addr, (r)->port_field, 0)) { \
- tor_addr_from_ipv4h(&(ap_out)->addr, (r)->addr); \
- (ap_out)->port = (r)->port_field; \
- } \
+#define RETURN_IPV4_AP(r, port_field, ap_out) \
+ STMT_BEGIN \
+ if (r && tor_addr_port_is_valid(&(r)->ipv4_addr, (r)->port_field, 0)) { \
+ tor_addr_copy(&(ap_out)->addr, &(r)->ipv4_addr); \
+ (ap_out)->port = (r)->port_field; \
+ } \
STMT_END
/** Copy the primary (IPv4) OR port (IP address and TCP port) for <b>node</b>
@@ -1731,8 +1750,8 @@ node_get_prim_orport(const node_t *node, tor_addr_port_t *ap_out)
/* Check ri first, because rewrite_node_address_for_bridge() updates
* node->ri with the configured bridge address. */
- RETURN_IPV4_AP(node->ri, or_port, ap_out);
- RETURN_IPV4_AP(node->rs, or_port, ap_out);
+ RETURN_IPV4_AP(node->ri, ipv4_orport, ap_out);
+ RETURN_IPV4_AP(node->rs, ipv4_orport, ap_out);
/* Microdescriptors only have an IPv6 address */
}
@@ -1793,7 +1812,7 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out)
* or
* ii) our preference is for IPv6 Dir addresses.
*
- * If there is no node, use fascist_firewall_prefer_ipv6_dirport().
+ * If there is no node, use reachable_addr_prefer_ipv6_dirport().
*/
int
node_ipv6_dir_preferred(const node_t *node)
@@ -1802,15 +1821,15 @@ node_ipv6_dir_preferred(const node_t *node)
tor_addr_port_t ipv4_addr;
node_assert_ok(node);
- /* node->ipv6_preferred is set from fascist_firewall_prefer_ipv6_orport(),
+ /* node->ipv6_preferred is set from reachable_addr_prefer_ipv6_orport(),
* so we can't use it to determine DirPort IPv6 preference.
* This means that bridge clients will use IPv4 DirPorts by default.
*/
node_get_prim_dirport(node, &ipv4_addr);
- if (!fascist_firewall_use_ipv6(options)) {
+ if (!reachable_addr_use_ipv6(options)) {
return 0;
} else if (!tor_addr_port_is_valid_ap(&ipv4_addr, 0)
- || fascist_firewall_prefer_ipv6_dirport(get_options())) {
+ || reachable_addr_prefer_ipv6_dirport(get_options())) {
return node_has_ipv6_dirport(node);
}
return 0;
@@ -1832,8 +1851,8 @@ node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out)
/* Check ri first, because rewrite_node_address_for_bridge() updates
* node->ri with the configured bridge address. */
- RETURN_IPV4_AP(node->ri, dir_port, ap_out);
- RETURN_IPV4_AP(node->rs, dir_port, ap_out);
+ RETURN_IPV4_AP(node->ri, ipv4_dirport, ap_out);
+ RETURN_IPV4_AP(node->rs, ipv4_dirport, ap_out);
/* Microdescriptors only have an IPv6 address */
}
@@ -1870,13 +1889,13 @@ node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out)
/* Assume IPv4 and IPv6 dirports are the same */
if (node->ri && tor_addr_port_is_valid(&node->ri->ipv6_addr,
- node->ri->dir_port, 0)) {
+ node->ri->ipv4_dirport, 0)) {
tor_addr_copy(&ap_out->addr, &node->ri->ipv6_addr);
- ap_out->port = node->ri->dir_port;
+ ap_out->port = node->ri->ipv4_dirport;
} else if (node->rs && tor_addr_port_is_valid(&node->rs->ipv6_addr,
- node->rs->dir_port, 0)) {
+ node->rs->ipv4_dirport, 0)) {
tor_addr_copy(&ap_out->addr, &node->rs->ipv6_addr);
- ap_out->port = node->rs->dir_port;
+ ap_out->port = node->rs->ipv4_dirport;
} else {
tor_addr_make_null(&ap_out->addr, AF_INET6);
ap_out->port = 0;
@@ -1961,15 +1980,21 @@ node_get_rsa_onion_key(const node_t *node)
void
node_set_country(node_t *node)
{
- tor_addr_t addr = TOR_ADDR_NULL;
+ const tor_addr_t *ipv4_addr = NULL;
/* XXXXipv6 */
if (node->rs)
- tor_addr_from_ipv4h(&addr, node->rs->addr);
+ ipv4_addr = &node->rs->ipv4_addr;
else if (node->ri)
- tor_addr_from_ipv4h(&addr, node->ri->addr);
+ ipv4_addr = &node->ri->ipv4_addr;
- node->country = geoip_get_country_by_addr(&addr);
+ /* IPv4 is mandatory for a relay so this should not happen unless we are
+ * attempting to set the country code on a node without a descriptor. */
+ if (BUG(!ipv4_addr)) {
+ node->country = -1;
+ return;
+ }
+ node->country = geoip_get_country_by_addr(ipv4_addr);
}
/** Set the country code of all routers in the routerlist. */
@@ -1984,7 +2009,7 @@ nodelist_refresh_countries(void)
/** Return true iff router1 and router2 have similar enough network addresses
* that we should treat them as being in the same family */
int
-addrs_in_same_network_family(const tor_addr_t *a1,
+router_addrs_in_same_network(const tor_addr_t *a1,
const tor_addr_t *a2)
{
if (tor_addr_is_null(a1) || tor_addr_is_null(a2))
@@ -2100,8 +2125,8 @@ nodes_in_same_family(const node_t *node1, const node_t *node2)
node_get_pref_ipv6_orport(node1, &ap6_1);
node_get_pref_ipv6_orport(node2, &ap6_2);
- if (addrs_in_same_network_family(&a1, &a2) ||
- addrs_in_same_network_family(&ap6_1.addr, &ap6_2.addr))
+ if (router_addrs_in_same_network(&a1, &a2) ||
+ router_addrs_in_same_network(&ap6_1.addr, &ap6_2.addr))
return 1;
}
@@ -2159,8 +2184,8 @@ nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
tor_addr_port_t ap6;
node_get_addr(node2, &a);
node_get_pref_ipv6_orport(node2, &ap6);
- if (addrs_in_same_network_family(&a, &node_addr) ||
- addrs_in_same_network_family(&ap6.addr, &node_ap6.addr))
+ if (router_addrs_in_same_network(&a, &node_addr) ||
+ router_addrs_in_same_network(&ap6.addr, &node_ap6.addr))
smartlist_add(sl, (void*)node2);
} SMARTLIST_FOREACH_END(node2);
}
@@ -2200,21 +2225,18 @@ nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
const node_t *
router_find_exact_exit_enclave(const char *address, uint16_t port)
{/*XXXX MOVE*/
- uint32_t addr;
struct in_addr in;
- tor_addr_t a;
+ tor_addr_t ipv4_addr;
const or_options_t *options = get_options();
if (!tor_inet_aton(address, &in))
return NULL; /* it's not an IP already */
- addr = ntohl(in.s_addr);
-
- tor_addr_from_ipv4h(&a, addr);
+ tor_addr_from_in(&ipv4_addr, &in);
SMARTLIST_FOREACH(nodelist_get_list(), const node_t *, node, {
- if (node_get_addr_ipv4h(node) == addr &&
+ if (tor_addr_eq(node_get_prim_addr_ipv4(node), &ipv4_addr) &&
node->is_running &&
- compare_tor_addr_to_node_policy(&a, port, node) ==
+ compare_tor_addr_to_node_policy(&ipv4_addr, port, node) ==
ADDR_POLICY_ACCEPTED &&
!routerset_contains_node(options->ExcludeExitNodesUnion_, node))
return node;
diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h
index 57ab2d5913..b762fb339c 100644
--- a/src/feature/nodelist/nodelist.h
+++ b/src/feature/nodelist/nodelist.h
@@ -32,11 +32,10 @@ const node_t *node_get_by_hex_id(const char *identity_digest,
unsigned flags);
node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out);
node_t *nodelist_add_microdesc(microdesc_t *md);
-void nodelist_set_consensus(networkstatus_t *ns);
-void nodelist_ensure_freshness(networkstatus_t *ns);
+void nodelist_set_consensus(const networkstatus_t *ns);
+void nodelist_ensure_freshness(const networkstatus_t *ns);
int nodelist_probably_contains_address(const tor_addr_t *addr);
-void nodelist_add_addr4_to_address_set(const uint32_t addr);
-void nodelist_add_addr6_to_address_set(const tor_addr_t *addr);
+void nodelist_add_addr_to_address_set(const tor_addr_t *addr);
void nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md);
void nodelist_remove_routerinfo(routerinfo_t *ri);
@@ -67,20 +66,23 @@ smartlist_t *node_get_all_orports(const node_t *node);
int node_allows_single_hop_exits(const node_t *node);
const char *node_get_nickname(const node_t *node);
const char *node_get_platform(const node_t *node);
-uint32_t node_get_prim_addr_ipv4h(const node_t *node);
void node_get_address_string(const node_t *node, char *cp, size_t len);
long node_get_declared_uptime(const node_t *node);
MOCK_DECL(const struct ed25519_public_key_t *,node_get_ed25519_id,
(const node_t *node));
int node_ed25519_id_matches(const node_t *node,
const struct ed25519_public_key_t *id);
-MOCK_DECL(int,node_supports_ed25519_link_authentication,
+MOCK_DECL(bool,node_supports_ed25519_link_authentication,
(const node_t *node,
- int compatible_with_us));
-int node_supports_v3_hsdir(const node_t *node);
-int node_supports_ed25519_hs_intro(const node_t *node);
-int node_supports_v3_rendezvous_point(const node_t *node);
-int node_supports_establish_intro_dos_extension(const node_t *node);
+ bool compatible_with_us));
+bool node_supports_v3_hsdir(const node_t *node);
+bool node_supports_ed25519_hs_intro(const node_t *node);
+bool node_supports_v3_rendezvous_point(const node_t *node);
+bool node_supports_establish_intro_dos_extension(const node_t *node);
+bool node_supports_initiating_ipv6_extends(const node_t *node);
+bool node_supports_accepting_ipv6_extends(const node_t *node,
+ bool need_canonical_ipv6_conn);
+
const uint8_t *node_get_rsa_id_digest(const node_t *node);
MOCK_DECL(smartlist_t *,node_get_link_specifier_smartlist,(const node_t *node,
bool direct_conn));
@@ -110,7 +112,6 @@ MOCK_DECL(const smartlist_t *, nodelist_get_list, (void));
/* Temporary during transition to multiple addresses. */
void node_get_addr(const node_t *node, tor_addr_t *addr_out);
-#define node_get_addr_ipv4h(n) node_get_prim_addr_ipv4h((n))
void nodelist_refresh_countries(void);
void node_set_country(node_t *node);
@@ -124,7 +125,7 @@ int node_is_unreliable(const node_t *router, int need_uptime,
int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
int need_uptime);
void router_set_status(const char *digest, int up);
-int addrs_in_same_network_family(const tor_addr_t *a1,
+int router_addrs_in_same_network(const tor_addr_t *a1,
const tor_addr_t *a2);
/** router_have_minimum_dir_info tests to see if we have enough
diff --git a/src/feature/nodelist/routerinfo.c b/src/feature/nodelist/routerinfo.c
index 0bf2a977f5..2a094d7fae 100644
--- a/src/feature/nodelist/routerinfo.c
+++ b/src/feature/nodelist/routerinfo.c
@@ -17,22 +17,45 @@
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerinfo_st.h"
-/** Copy the primary (IPv4) OR port (IP address and TCP port) for
- * <b>router</b> into *<b>ap_out</b>. */
-void
-router_get_prim_orport(const routerinfo_t *router, tor_addr_port_t *ap_out)
+/** Copy the OR port (IP address and TCP port) for <b>router</b> and
+ * <b>family</b> into *<b>ap_out</b>.
+ *
+ * If the requested ORPort does not exist, sets *<b>ap_out</b> to the null
+ * address and port, and returns -1. Otherwise, returns 0. */
+int
+router_get_orport(const routerinfo_t *router,
+ tor_addr_port_t *ap_out,
+ int family)
{
tor_assert(ap_out != NULL);
- tor_addr_from_ipv4h(&ap_out->addr, router->addr);
- ap_out->port = router->or_port;
+ if (family == AF_INET) {
+ tor_addr_copy(&ap_out->addr, &router->ipv4_addr);
+ ap_out->port = router->ipv4_orport;
+ return 0;
+ } else if (family == AF_INET6) {
+ /* IPv6 addresses are optional, so check if it is valid. */
+ if (tor_addr_port_is_valid(&router->ipv6_addr, router->ipv6_orport, 0)) {
+ tor_addr_copy(&ap_out->addr, &router->ipv6_addr);
+ ap_out->port = router->ipv6_orport;
+ return 0;
+ } else {
+ tor_addr_port_make_null_ap(ap_out, AF_INET6);
+ return -1;
+ }
+ } else {
+ /* Unsupported address family */
+ tor_assert_nonfatal_unreached();
+ tor_addr_port_make_null_ap(ap_out, AF_UNSPEC);
+ return -1;
+ }
}
int
router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport)
{
return
- (tor_addr_eq_ipv4h(&orport->addr, router->addr) &&
- orport->port == router->or_port) ||
+ (tor_addr_eq(&orport->addr, &router->ipv4_addr) &&
+ orport->port == router->ipv4_orport) ||
(tor_addr_eq(&orport->addr, &router->ipv6_addr) &&
orport->port == router->ipv6_orport);
}
diff --git a/src/feature/nodelist/routerinfo.h b/src/feature/nodelist/routerinfo.h
index 604e478999..2e12cbeba3 100644
--- a/src/feature/nodelist/routerinfo.h
+++ b/src/feature/nodelist/routerinfo.h
@@ -12,8 +12,9 @@
#ifndef TOR_ROUTERINFO_H
#define TOR_ROUTERINFO_H
-void router_get_prim_orport(const routerinfo_t *router,
- tor_addr_port_t *addr_port_out);
+int router_get_orport(const routerinfo_t *router,
+ tor_addr_port_t *addr_port_out,
+ int family);
int router_has_orport(const routerinfo_t *router,
const tor_addr_port_t *orport);
diff --git a/src/feature/nodelist/routerinfo_st.h b/src/feature/nodelist/routerinfo_st.h
index 36ead50e33..7197c88c18 100644
--- a/src/feature/nodelist/routerinfo_st.h
+++ b/src/feature/nodelist/routerinfo_st.h
@@ -21,9 +21,10 @@ struct routerinfo_t {
signed_descriptor_t cache_info;
char *nickname; /**< Human-readable OR name. */
- uint32_t addr; /**< IPv4 address of OR, in host order. */
- uint16_t or_port; /**< Port for TLS connections. */
- uint16_t dir_port; /**< Port for HTTP directory connections. */
+ /** A router's IPv4 address. */
+ tor_addr_t ipv4_addr;
+ uint16_t ipv4_orport;
+ uint16_t ipv4_dirport;
/** A router's IPv6 address, if it has one. */
tor_addr_t ipv6_addr;
diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c
index 96bea5a670..fcaf507efc 100644
--- a/src/feature/nodelist/routerlist.c
+++ b/src/feature/nodelist/routerlist.c
@@ -89,6 +89,7 @@
#include "feature/nodelist/routerset.h"
#include "feature/nodelist/torcert.h"
#include "feature/relay/routermode.h"
+#include "feature/relay/relay_find_addr.h"
#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -465,11 +466,20 @@ router_reload_router_list(void)
return 0;
}
-/* When iterating through the routerlist, can OR address/port preference
- * and reachability checks be skipped?
+/* When selecting a router for a direct connection, can OR address/port
+ * preference and reachability checks be skipped?
+ *
+ * Servers never check ReachableAddresses or ClientPreferIPv6. Returns
+ * true for servers.
+ *
+ * Otherwise, if <b>try_ip_pref</b> is true, returns false. Used to make
+ * clients check ClientPreferIPv6, even if ReachableAddresses is not set.
+ * Finally, return true if ReachableAddresses is set.
*/
int
-router_skip_or_reachability(const or_options_t *options, int try_ip_pref)
+router_or_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref)
{
/* Servers always have and prefer IPv4.
* And if clients are checking against the firewall for reachability only,
@@ -477,11 +487,15 @@ router_skip_or_reachability(const or_options_t *options, int try_ip_pref)
return server_mode(options) || (!try_ip_pref && !firewall_is_fascist_or());
}
-/* When iterating through the routerlist, can Dir address/port preference
+/* When selecting a router for a direct connection, can Dir address/port
* and reachability checks be skipped?
+ *
+ * This function is obsolete, because clients only use ORPorts.
*/
int
-router_skip_dir_reachability(const or_options_t *options, int try_ip_pref)
+router_dir_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref)
{
/* Servers always have and prefer IPv4.
* And if clients are checking against the firewall for reachability only,
@@ -493,45 +507,115 @@ router_skip_dir_reachability(const or_options_t *options, int try_ip_pref)
int
routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2)
{
- return r1->addr == r2->addr && r1->or_port == r2->or_port &&
+ return tor_addr_eq(&r1->ipv4_addr, &r2->ipv4_addr) &&
+ r1->ipv4_orport == r2->ipv4_orport &&
tor_addr_eq(&r1->ipv6_addr, &r2->ipv6_addr) &&
r1->ipv6_orport == r2->ipv6_orport;
}
+/* Returns true if <b>node</b> can be chosen based on <b>flags</b>.
+ *
+ * The following conditions are applied to all nodes:
+ * - is running;
+ * - is valid;
+ * - supports EXTEND2 cells;
+ * - has an ntor circuit crypto key; and
+ * - does not allow single-hop exits.
+ *
+ * If the node has a routerinfo, we're checking for a direct connection, and
+ * we're using bridges, the following condition is applied:
+ * - has a bridge-purpose routerinfo;
+ * and for all other nodes:
+ * - has a general-purpose routerinfo (or no routerinfo).
+ *
+ * Nodes that don't have a routerinfo must be general-purpose nodes, because
+ * routerstatuses and microdescriptors only come via consensuses.
+ *
+ * The <b>flags</b> chech that <b>node</b>:
+ * - <b>CRN_NEED_UPTIME</b>: has more than a minimum uptime;
+ * - <b>CRN_NEED_CAPACITY</b>: has more than a minimum capacity;
+ * - <b>CRN_NEED_GUARD</b>: is a Guard;
+ * - <b>CRN_NEED_DESC</b>: has a routerinfo or microdescriptor -- that is,
+ * enough info to be used to build a circuit;
+ * - <b>CRN_DIRECT_CONN</b>: is suitable for direct connections. Checks
+ * for the relevant descriptors. Checks the address
+ * against ReachableAddresses, ClientUseIPv4 0, and
+ * reachable_addr_use_ipv6() == 0);
+ * - <b>CRN_PREF_ADDR</b>: if we are connecting directly to the node, it has
+ * an address that is preferred by the
+ * ClientPreferIPv6ORPort setting;
+ * - <b>CRN_RENDEZVOUS_V3</b>: can become a v3 onion service rendezvous point;
+ * - <b>CRN_INITIATE_IPV6_EXTEND</b>: can initiate IPv6 extends.
+ */
+bool
+router_can_choose_node(const node_t *node, int flags)
+{
+ /* The full set of flags used for node selection. */
+ const bool need_uptime = (flags & CRN_NEED_UPTIME) != 0;
+ const bool need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
+ const bool need_guard = (flags & CRN_NEED_GUARD) != 0;
+ const bool need_desc = (flags & CRN_NEED_DESC) != 0;
+ const bool pref_addr = (flags & CRN_PREF_ADDR) != 0;
+ const bool direct_conn = (flags & CRN_DIRECT_CONN) != 0;
+ const bool rendezvous_v3 = (flags & CRN_RENDEZVOUS_V3) != 0;
+ const bool initiate_ipv6_extend = (flags & CRN_INITIATE_IPV6_EXTEND) != 0;
+
+ const or_options_t *options = get_options();
+ const bool check_reach =
+ !router_or_conn_should_skip_reachable_address_check(options, pref_addr);
+ const bool direct_bridge = direct_conn && options->UseBridges;
+
+ if (!node->is_running || !node->is_valid)
+ return false;
+ if (need_desc && !node_has_preferred_descriptor(node, direct_conn))
+ return false;
+ if (node->ri) {
+ if (direct_bridge && node->ri->purpose != ROUTER_PURPOSE_BRIDGE)
+ return false;
+ else if (node->ri->purpose != ROUTER_PURPOSE_GENERAL)
+ return false;
+ }
+ if (node_is_unreliable(node, need_uptime, need_capacity, need_guard))
+ return false;
+ /* Don't choose nodes if we are certain they can't do EXTEND2 cells */
+ if (node->rs && !routerstatus_version_supports_extend2_cells(node->rs, 1))
+ return false;
+ /* Don't choose nodes if we are certain they can't do ntor. */
+ if ((node->ri || node->md) && !node_has_curve25519_onion_key(node))
+ return false;
+ /* Exclude relays that allow single hop exit circuits. This is an
+ * obsolete option since 0.2.9.2-alpha and done by default in
+ * 0.3.1.0-alpha. */
+ if (node_allows_single_hop_exits(node))
+ return false;
+ /* Exclude relays that can not become a rendezvous for a hidden service
+ * version 3. */
+ if (rendezvous_v3 &&
+ !node_supports_v3_rendezvous_point(node))
+ return false;
+ /* Choose a node with an OR address that matches the firewall rules */
+ if (direct_conn && check_reach &&
+ !reachable_addr_allows_node(node,
+ FIREWALL_OR_CONNECTION,
+ pref_addr))
+ return false;
+ if (initiate_ipv6_extend && !node_supports_initiating_ipv6_extends(node))
+ return false;
+
+ return true;
+}
+
/** Add every suitable node from our nodelist to <b>sl</b>, so that
- * we can pick a node for a circuit.
+ * we can pick a node for a circuit based on <b>flags</b>.
+ *
+ * See router_can_choose_node() for details of <b>flags</b>.
*/
void
-router_add_running_nodes_to_smartlist(smartlist_t *sl, int need_uptime,
- int need_capacity, int need_guard,
- int need_desc, int pref_addr,
- int direct_conn)
-{
- const int check_reach = !router_skip_or_reachability(get_options(),
- pref_addr);
- /* XXXX MOVE */
+router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags)
+{
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
- if (!node->is_running || !node->is_valid)
- continue;
- if (need_desc && !node_has_preferred_descriptor(node, direct_conn))
- continue;
- if (node->ri && node->ri->purpose != ROUTER_PURPOSE_GENERAL)
- continue;
- if (node_is_unreliable(node, need_uptime, need_capacity, need_guard))
- continue;
- /* Don't choose nodes if we are certain they can't do EXTEND2 cells */
- if (node->rs && !routerstatus_version_supports_extend2_cells(node->rs, 1))
- continue;
- /* Don't choose nodes if we are certain they can't do ntor. */
- if ((node->ri || node->md) && !node_has_curve25519_onion_key(node))
- continue;
- /* Choose a node with an OR address that matches the firewall rules */
- if (direct_conn && check_reach &&
- !fascist_firewall_allows_node(node,
- FIREWALL_OR_CONNECTION,
- pref_addr))
+ if (!router_can_choose_node(node, flags))
continue;
-
smartlist_add(sl, (void *)node);
} SMARTLIST_FOREACH_END(node);
}
@@ -2689,12 +2773,27 @@ launch_dummy_descriptor_download_as_needed(time_t now,
const or_options_t *options)
{
static time_t last_dummy_download = 0;
+ bool have_addr;
+ tor_addr_t addr_out;
+
+ /* This dummy fetch only matter for relays. */
+ if (!server_mode(options)) {
+ return;
+ }
+
+ /* Lookup the address cache to learn if we have a good usable address. We
+ * still force relays to have an IPv4 so that alone is enough to learn if we
+ * need a lookup. In case we don't have one, we might want to attempt a
+ * dummy fetch to learn our address as a suggestion from an authority. */
+ have_addr = relay_find_addr_to_publish(options, AF_INET,
+ RELAY_FIND_ADDR_CACHE_ONLY,
+ &addr_out);
+
/* XXXX+ we could be smarter here; see notes on bug 652. */
- /* If we're a server that doesn't have a configured address, we rely on
- * directory fetches to learn when our address changes. So if we haven't
- * tried to get any routerdescs in a long time, try a dummy fetch now. */
- if (!options->Address &&
- server_mode(options) &&
+ /* If we're a server that doesn't have an address, we rely on directory
+ * fetches to learn when our address changes. So if we haven't tried to get
+ * any routerdescs in a long time, try a dummy fetch now. */
+ if (!have_addr &&
last_descriptor_download_attempted + DUMMY_DOWNLOAD_INTERVAL < now &&
last_dummy_download + DUMMY_DOWNLOAD_INTERVAL < now) {
last_dummy_download = now;
@@ -2882,12 +2981,12 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2)
}
/* If any key fields differ, they're different. */
- if (r1->addr != r2->addr ||
+ if (!tor_addr_eq(&r1->ipv4_addr, &r2->ipv4_addr) ||
strcasecmp(r1->nickname, r2->nickname) ||
- r1->or_port != r2->or_port ||
+ r1->ipv4_orport != r2->ipv4_orport ||
!tor_addr_eq(&r1->ipv6_addr, &r2->ipv6_addr) ||
r1->ipv6_orport != r2->ipv6_orport ||
- r1->dir_port != r2->dir_port ||
+ r1->ipv4_dirport != r2->ipv4_dirport ||
r1->purpose != r2->purpose ||
r1->onion_pkey_len != r2->onion_pkey_len ||
!tor_memeq(r1->onion_pkey, r2->onion_pkey, r1->onion_pkey_len) ||
diff --git a/src/feature/nodelist/routerlist.h b/src/feature/nodelist/routerlist.h
index 81a2343540..98472b2771 100644
--- a/src/feature/nodelist/routerlist.h
+++ b/src/feature/nodelist/routerlist.h
@@ -50,14 +50,16 @@ typedef enum was_router_added_t {
int router_reload_router_list(void);
-int router_skip_or_reachability(const or_options_t *options, int try_ip_pref);
-int router_skip_dir_reachability(const or_options_t *options, int try_ip_pref);
+int router_or_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref);
+int router_dir_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref);
void router_reset_status_download_failures(void);
int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2);
-void router_add_running_nodes_to_smartlist(smartlist_t *sl, int need_uptime,
- int need_capacity, int need_guard,
- int need_desc, int pref_addr,
- int direct_conn);
+bool router_can_choose_node(const node_t *node, int flags);
+void router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags);
const routerinfo_t *routerlist_find_my_routerinfo(void);
uint32_t router_get_advertised_bandwidth(const routerinfo_t *router);
diff --git a/src/feature/nodelist/routerset.c b/src/feature/nodelist/routerset.c
index 2e06ecbf04..7234dc5441 100644
--- a/src/feature/nodelist/routerset.c
+++ b/src/feature/nodelist/routerset.c
@@ -223,11 +223,11 @@ routerset_len(const routerset_t *set)
*
* (If country is -1, then we take the country
* from addr.) */
-STATIC int
-routerset_contains(const routerset_t *set, const tor_addr_t *addr,
- uint16_t orport,
- const char *nickname, const char *id_digest,
- country_t country)
+static int
+routerset_contains2(const routerset_t *set, const tor_addr_t *addr,
+ uint16_t orport, const tor_addr_t *addr2,
+ uint16_t orport2, const char *nickname,
+ const char *id_digest, country_t country)
{
if (!set || !set->list)
return 0;
@@ -238,6 +238,9 @@ routerset_contains(const routerset_t *set, const tor_addr_t *addr,
if (addr && compare_tor_addr_to_addr_policy(addr, orport, set->policies)
== ADDR_POLICY_REJECTED)
return 3;
+ if (addr2 && compare_tor_addr_to_addr_policy(addr2, orport2, set->policies)
+ == ADDR_POLICY_REJECTED)
+ return 3;
if (set->countries) {
if (country < 0 && addr)
country = geoip_get_country_by_addr(addr);
@@ -249,6 +252,17 @@ routerset_contains(const routerset_t *set, const tor_addr_t *addr,
return 0;
}
+/** Helper. Like routerset_contains2() but for a single IP/port combo.
+ */
+STATIC int
+routerset_contains(const routerset_t *set, const tor_addr_t *addr,
+ uint16_t orport, const char *nickname,
+ const char *id_digest, country_t country)
+{
+ return routerset_contains2(set, addr, orport, NULL, 0,
+ nickname, id_digest, country);
+}
+
/** If *<b>setp</b> includes at least one country code, or if
* <b>only_some_cc_set</b> is 0, add the ?? and A1 country codes to
* *<b>setp</b>, creating it as needed. Return true iff *<b>setp</b> changed.
@@ -292,12 +306,19 @@ routerset_add_unknown_ccs(routerset_t **setp, int only_if_some_cc_set)
int
routerset_contains_extendinfo(const routerset_t *set, const extend_info_t *ei)
{
- return routerset_contains(set,
- &ei->addr,
- ei->port,
- ei->nickname,
- ei->identity_digest,
- -1 /*country*/);
+ const tor_addr_port_t *ap1 = NULL, *ap2 = NULL;
+ if (! tor_addr_is_null(&ei->orports[0].addr))
+ ap1 = &ei->orports[0];
+ if (! tor_addr_is_null(&ei->orports[1].addr))
+ ap2 = &ei->orports[1];
+ return routerset_contains2(set,
+ ap1 ? &ap1->addr : NULL,
+ ap1 ? ap1->port : 0,
+ ap2 ? &ap2->addr : NULL,
+ ap2 ? ap2->port : 0,
+ ei->nickname,
+ ei->identity_digest,
+ -1 /*country*/);
}
/** Return true iff <b>ri</b> is in <b>set</b>. If country is <b>-1</b>, we
@@ -306,14 +327,9 @@ int
routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
country_t country)
{
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, ri->addr);
- return routerset_contains(set,
- &addr,
- ri->or_port,
- ri->nickname,
- ri->cache_info.identity_digest,
- country);
+ return routerset_contains2(set, &ri->ipv4_addr, ri->ipv4_orport,
+ &ri->ipv6_addr, ri->ipv6_orport, ri->nickname,
+ ri->cache_info.identity_digest, country);
}
/** Return true iff <b>rs</b> is in <b>set</b>. If country is <b>-1</b>, we
@@ -323,11 +339,9 @@ routerset_contains_routerstatus(const routerset_t *set,
const routerstatus_t *rs,
country_t country)
{
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, rs->addr);
return routerset_contains(set,
- &addr,
- rs->or_port,
+ &rs->ipv4_addr,
+ rs->ipv4_orport,
rs->nickname,
rs->identity_digest,
country);
diff --git a/src/feature/nodelist/routerstatus_st.h b/src/feature/nodelist/routerstatus_st.h
index 735c754b31..254ba73f7f 100644
--- a/src/feature/nodelist/routerstatus_st.h
+++ b/src/feature/nodelist/routerstatus_st.h
@@ -29,9 +29,9 @@ struct routerstatus_t {
/** Digest of the router's most recent descriptor or microdescriptor.
* If it's a descriptor, we only use the first DIGEST_LEN bytes. */
char descriptor_digest[DIGEST256_LEN];
- uint32_t addr; /**< IPv4 address for this router, in host order. */
- uint16_t or_port; /**< IPv4 OR port for this router. */
- uint16_t dir_port; /**< Directory port for this router. */
+ tor_addr_t ipv4_addr;
+ uint16_t ipv4_orport; /**< IPv4 OR port for this router. */
+ uint16_t ipv4_dirport; /**< Directory port for this router. */
tor_addr_t ipv6_addr; /**< IPv6 address for this router. */
uint16_t ipv6_orport; /**< IPv6 OR port for this router. */
unsigned int is_authority:1; /**< True iff this router is an authority. */
diff --git a/src/feature/nodelist/torcert.c b/src/feature/nodelist/torcert.c
index 89cc9c88fb..dc36626122 100644
--- a/src/feature/nodelist/torcert.c
+++ b/src/feature/nodelist/torcert.c
@@ -37,11 +37,11 @@
#include "core/or/or_handshake_certs_st.h"
-/** Helper for tor_cert_create(): signs any 32 bytes, not just an ed25519
- * key.
+/** As tor_cert_create(), but accept an arbitrary signed_key_type as the
+ * subject key -- not just an ed25519 key.
*/
-static tor_cert_t *
-tor_cert_sign_impl(const ed25519_keypair_t *signing_key,
+tor_cert_t *
+tor_cert_create_raw(const ed25519_keypair_t *signing_key,
uint8_t cert_type,
uint8_t signed_key_type,
const uint8_t signed_key_info[32],
@@ -128,13 +128,13 @@ tor_cert_sign_impl(const ed25519_keypair_t *signing_key,
* the public part of <b>signing_key</b> in the certificate.
*/
tor_cert_t *
-tor_cert_create(const ed25519_keypair_t *signing_key,
+tor_cert_create_ed25519(const ed25519_keypair_t *signing_key,
uint8_t cert_type,
const ed25519_public_key_t *signed_key,
time_t now, time_t lifetime,
uint32_t flags)
{
- return tor_cert_sign_impl(signing_key, cert_type,
+ return tor_cert_create_raw(signing_key, cert_type,
SIGNED_KEY_TYPE_ED25519, signed_key->pubkey,
now, lifetime, flags);
}
diff --git a/src/feature/nodelist/torcert.h b/src/feature/nodelist/torcert.h
index f8fba2b794..3314ee2550 100644
--- a/src/feature/nodelist/torcert.h
+++ b/src/feature/nodelist/torcert.h
@@ -11,7 +11,9 @@
#include "lib/crypt_ops/crypto_ed25519.h"
-#define SIGNED_KEY_TYPE_ED25519 0x01
+#define SIGNED_KEY_TYPE_ED25519 0x01
+#define SIGNED_KEY_TYPE_SHA256_OF_RSA 0x02
+#define SIGNED_KEY_TYPE_SHA256_OF_X509 0x03
#define CERT_TYPE_ID_SIGNING 0x04
#define CERT_TYPE_SIGNING_LINK 0x05
@@ -56,11 +58,17 @@ typedef struct tor_cert_st {
struct tor_tls_t;
-tor_cert_t *tor_cert_create(const ed25519_keypair_t *signing_key,
+tor_cert_t *tor_cert_create_ed25519(const ed25519_keypair_t *signing_key,
uint8_t cert_type,
const ed25519_public_key_t *signed_key,
time_t now, time_t lifetime,
uint32_t flags);
+tor_cert_t * tor_cert_create_raw(const ed25519_keypair_t *signing_key,
+ uint8_t cert_type,
+ uint8_t signed_key_type,
+ const uint8_t signed_key_info[32],
+ time_t now, time_t lifetime,
+ uint32_t flags);
tor_cert_t *tor_cert_parse(const uint8_t *cert, size_t certlen);
diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c
index b89866b477..64f3c341ae 100644
--- a/src/feature/relay/circuitbuild_relay.c
+++ b/src/feature/relay/circuitbuild_relay.c
@@ -33,6 +33,7 @@
#include "core/or/channel.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
+#include "core/or/extendinfo.h"
#include "core/or/onion.h"
#include "core/or/relay.h"
@@ -122,6 +123,52 @@ circuit_extend_add_ed25519_helper(struct extend_cell_t *ec)
return 0;
}
+/* Make sure the extend cell <b>ec</b> has an IPv4 address if the relay
+ * supports in, and if not, fill it in. */
+STATIC int
+circuit_extend_add_ipv4_helper(struct extend_cell_t *ec)
+{
+ IF_BUG_ONCE(!ec) {
+ return -1;
+ }
+
+ const node_t *node = node_get_by_id((const char *) ec->node_id);
+ if (node) {
+ tor_addr_port_t node_ipv4;
+ node_get_prim_orport(node, &node_ipv4);
+ if (tor_addr_is_null(&ec->orport_ipv4.addr) &&
+ !tor_addr_is_null(&node_ipv4.addr)) {
+ tor_addr_copy(&ec->orport_ipv4.addr, &node_ipv4.addr);
+ ec->orport_ipv4.port = node_ipv4.port;
+ }
+ }
+
+ return 0;
+}
+
+/* Make sure the extend cell <b>ec</b> has an IPv6 address if the relay
+ * supports in, and if not, fill it in. */
+STATIC int
+circuit_extend_add_ipv6_helper(struct extend_cell_t *ec)
+{
+ IF_BUG_ONCE(!ec) {
+ return -1;
+ }
+
+ const node_t *node = node_get_by_id((const char *) ec->node_id);
+ if (node) {
+ tor_addr_port_t node_ipv6;
+ node_get_pref_ipv6_orport(node, &node_ipv6);
+ if (tor_addr_is_null(&ec->orport_ipv6.addr) &&
+ !tor_addr_is_null(&node_ipv6.addr)) {
+ tor_addr_copy(&ec->orport_ipv6.addr, &node_ipv6.addr);
+ ec->orport_ipv6.port = node_ipv6.port;
+ }
+ }
+
+ return 0;
+}
+
/* Check if the address and port in the tor_addr_port_t <b>ap</b> are valid,
* and are allowed by the current ExtendAllowPrivateAddresses config.
*
@@ -354,11 +401,7 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec,
if (should_launch) {
/* we should try to open a connection */
- channel_t *n_chan = channel_connect_for_circuit(
- &circ->n_hop->addr,
- circ->n_hop->port,
- circ->n_hop->identity_digest,
- &circ->n_hop->ed_identity);
+ channel_t *n_chan = channel_connect_for_circuit(circ->n_hop);
if (!n_chan) {
log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
@@ -412,6 +455,12 @@ circuit_extend(struct cell_t *cell, struct circuit_t *circ)
if (circuit_extend_lspec_valid_helper(&ec, circ) < 0)
return -1;
+ if (circuit_extend_add_ipv4_helper(&ec) < 0)
+ return -1;
+
+ if (circuit_extend_add_ipv6_helper(&ec) < 0)
+ return -1;
+
/* Check the addresses, without logging */
const int ipv4_valid = circuit_extend_addr_port_is_valid(&ec.orport_ipv4,
false, false, 0);
@@ -452,7 +501,7 @@ circuit_extend(struct cell_t *cell, struct circuit_t *circ)
circ->n_chan = n_chan;
log_debug(LD_CIRC,
"n_chan is %s.",
- channel_get_canonical_remote_descr(n_chan));
+ channel_describe_peer(n_chan));
if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0)
return -1;
@@ -539,10 +588,24 @@ onionskin_answer(struct or_circuit_t *circ,
if ((!channel_is_local(circ->p_chan)
|| get_options()->ExtendAllowPrivateAddresses)
&& !channel_is_outgoing(circ->p_chan)) {
- /* record that we could process create cells from a non-local conn
- * that we didn't initiate; presumably this means that create cells
- * can reach us too. */
- router_orport_found_reachable();
+ /* Okay, it's a create cell from a non-local connection
+ * that we didn't initiate. Presumably this means that create cells
+ * can reach us too. But what address can they reach us on? */
+ const tor_addr_t *my_supposed_addr = &circ->p_chan->addr_according_to_peer;
+ if (router_addr_is_my_published_addr(my_supposed_addr)) {
+ /* Great, this create cell came on connection where the peer says
+ * that the our address is an address we're actually advertising!
+ * That should mean that we're reachable. But before we finally
+ * declare ourselves reachable, make sure that the address listed
+ * by the peer is the same family as the peer is actually using.
+ */
+ tor_addr_t remote_addr;
+ int family = tor_addr_family(my_supposed_addr);
+ if (channel_get_addr_if_possible(circ->p_chan, &remote_addr) &&
+ tor_addr_family(&remote_addr) == family) {
+ router_orport_found_reachable(family);
+ }
+ }
}
return 0;
diff --git a/src/feature/relay/circuitbuild_relay.h b/src/feature/relay/circuitbuild_relay.h
index 0783161538..dc0b886a34 100644
--- a/src/feature/relay/circuitbuild_relay.h
+++ b/src/feature/relay/circuitbuild_relay.h
@@ -73,6 +73,8 @@ onionskin_answer(struct or_circuit_t *circ,
STATIC int circuit_extend_state_valid_helper(const struct circuit_t *circ);
STATIC int circuit_extend_add_ed25519_helper(struct extend_cell_t *ec);
+STATIC int circuit_extend_add_ipv4_helper(struct extend_cell_t *ec);
+STATIC int circuit_extend_add_ipv6_helper(struct extend_cell_t *ec);
STATIC int circuit_extend_lspec_valid_helper(const struct extend_cell_t *ec,
const struct circuit_t *circ);
STATIC const tor_addr_port_t * circuit_choose_ip_ap_for_extend(
diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c
index fac6a2f577..6504c680eb 100644
--- a/src/feature/relay/relay_config.c
+++ b/src/feature/relay/relay_config.c
@@ -36,6 +36,7 @@
#include "feature/nodelist/nickname.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/connstats.h"
#include "feature/stats/rephist.h"
#include "feature/dirauth/authmode.h"
@@ -132,12 +133,133 @@ port_warn_nonlocal_ext_orports(const smartlist_t *ports, const char *portname)
} SMARTLIST_FOREACH_END(port);
}
+/**
+ * Return a static buffer describing the port number in @a port, which may
+ * CFG_AUTO_PORT.
+ **/
+static const char *
+describe_portnum(int port)
+{
+ static char buf[16];
+ if (port == CFG_AUTO_PORT) {
+ return "auto";
+ } else {
+ tor_snprintf(buf, sizeof(buf), "%d", port);
+ return buf;
+ }
+}
+
+/** Return a static buffer containing the human readable logging string that
+ * describes the given port object. */
+static const char *
+describe_relay_port(const port_cfg_t *port)
+{
+ IF_BUG_ONCE(!port) {
+ return "<null port>";
+ }
+
+ static char buf[256];
+ const char *type, *addr;
+
+ switch (port->type) {
+ case CONN_TYPE_OR_LISTENER:
+ type = "OR";
+ break;
+ case CONN_TYPE_DIR_LISTENER:
+ type = "Dir";
+ break;
+ case CONN_TYPE_EXT_OR_LISTENER:
+ type = "ExtOR";
+ break;
+ default:
+ type = "";
+ break;
+ }
+
+ if (port->explicit_addr) {
+ addr = fmt_and_decorate_addr(&port->addr);
+ } else {
+ addr = "";
+ }
+
+ tor_snprintf(buf, sizeof(buf), "%sPort %s%s%s",
+ type, addr, (strlen(addr) > 0) ? ":" : "",
+ describe_portnum(port->port));
+ return buf;
+}
+
+/** Attempt to find duplicate ORPort that would be superseded by another and
+ * remove them from the given ports list. This is possible if we have for
+ * instance:
+ *
+ * ORPort 9050
+ * ORPort [4242::1]:9050
+ *
+ * First one binds to both v4 and v6 address but second one is specific to an
+ * address superseding the global bind one.
+ *
+ * The following is O(n^2) but it is done at bootstrap or config reload and
+ * the list is not very long usually. */
+STATIC void
+remove_duplicate_orports(smartlist_t *ports)
+{
+ /* First we'll decide what to remove, then we'll remove it. */
+ bool *removing = tor_calloc(smartlist_len(ports), sizeof(bool));
+
+ for (int i = 0; i < smartlist_len(ports); ++i) {
+ const port_cfg_t *current = smartlist_get(ports, i);
+ if (removing[i]) {
+ continue;
+ }
+
+ /* Skip non ORPorts. */
+ if (current->type != CONN_TYPE_OR_LISTENER) {
+ continue;
+ }
+
+ for (int j = 0; j < smartlist_len(ports); ++j) {
+ const port_cfg_t *next = smartlist_get(ports, j);
+
+ /* Avoid comparing the same object. */
+ if (current == next) {
+ continue;
+ }
+ if (removing[j]) {
+ continue;
+ }
+ /* Same address family and same port number, we have a match. */
+ if (!current->explicit_addr && next->explicit_addr &&
+ tor_addr_family(&current->addr) == tor_addr_family(&next->addr) &&
+ current->port == next->port) {
+ /* Remove current because next is explicitly set. */
+ removing[i] = true;
+ char *next_str = tor_strdup(describe_relay_port(next));
+ log_warn(LD_CONFIG, "Configuration port %s superseded by %s",
+ describe_relay_port(current), next_str);
+ tor_free(next_str);
+ }
+ }
+ }
+
+ /* Iterate over array in reverse order to keep indices valid. */
+ for (int i = smartlist_len(ports)-1; i >= 0; --i) {
+ tor_assert(i < smartlist_len(ports));
+ if (removing[i]) {
+ port_cfg_t *current = smartlist_get(ports, i);
+ smartlist_del_keeporder(ports, i);
+ port_cfg_free(current);
+ }
+ }
+
+ tor_free(removing);
+}
+
/** Given a list of <b>port_cfg_t</b> in <b>ports</b>, check them for internal
* consistency and warn as appropriate. On Unix-based OSes, set
* *<b>n_low_ports_out</b> to the number of sub-1024 ports we will be
* binding, and warn if we may be unable to re-bind after hibernation. */
static int
-check_server_ports(const smartlist_t *ports,
+check_and_prune_server_ports(smartlist_t *ports,
const or_options_t *options,
int *n_low_ports_out)
{
@@ -158,6 +280,9 @@ check_server_ports(const smartlist_t *ports,
int n_low_port = 0;
int r = 0;
+ /* Remove possible duplicate ORPorts before inspecting the list. */
+ remove_duplicate_orports(ports);
+
SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
if (port->type == CONN_TYPE_DIR_LISTENER) {
if (! port->server_cfg.no_advertise)
@@ -270,6 +395,14 @@ port_parse_ports_relay(or_options_t *options,
goto err;
}
if (port_parse_config(ports,
+ options->ORPort_lines,
+ "OR", CONN_TYPE_OR_LISTENER,
+ "[::]", 0,
+ CL_PORT_SERVER_OPTIONS) < 0) {
+ *msg = tor_strdup("Invalid ORPort configuration");
+ goto err;
+ }
+ if (port_parse_config(ports,
options->ExtORPort_lines,
"ExtOR", CONN_TYPE_EXT_OR_LISTENER,
"127.0.0.1", 0,
@@ -286,7 +419,7 @@ port_parse_ports_relay(or_options_t *options,
goto err;
}
- if (check_server_ports(ports, options, &n_low_ports) < 0) {
+ if (check_and_prune_server_ports(ports, options, &n_low_ports) < 0) {
*msg = tor_strdup("Misconfigured server ports");
goto err;
}
@@ -904,7 +1037,7 @@ options_validate_relay_mode(const or_options_t *old_options,
"Tor is currently configured as a relay and a hidden service. "
"That's not very secure: you should probably run your hidden service "
"in a separate Tor process, at least -- see "
- "https://trac.torproject.org/8742");
+ "https://bugs.torproject.org/tpo/core/tor/8742.");
if (options->BridgeRelay && options->DirPort_set) {
log_warn(LD_CONFIG, "Can't set a DirPort on a bridge relay; disabling "
@@ -1029,7 +1162,7 @@ options_transition_affects_descriptor(const or_options_t *old_options,
YES_IF_CHANGED_STRING(DataDirectory);
YES_IF_CHANGED_STRING(Nickname);
- YES_IF_CHANGED_STRING(Address);
+ YES_IF_CHANGED_LINELIST(Address);
YES_IF_CHANGED_LINELIST(ExitPolicy);
YES_IF_CHANGED_BOOL(ExitRelay);
YES_IF_CHANGED_BOOL(ExitPolicyRejectPrivate);
@@ -1114,8 +1247,6 @@ options_act_relay(const or_options_t *old_options)
if (server_mode_turned_on) {
ip_address_changed(0);
- if (have_completed_a_circuit() || !any_predicted_circuits(time(NULL)))
- inform_testing_reachability();
}
cpuworkers_rotate_keyinfo();
}
@@ -1309,7 +1440,7 @@ options_act_relay_stats(const or_options_t *old_options,
}
if ((!old_options || !old_options->ConnDirectionStatistics) &&
options->ConnDirectionStatistics) {
- rep_hist_conn_stats_init(now);
+ conn_stats_init(now);
}
if ((!old_options || !old_options->HiddenServiceStatistics) &&
options->HiddenServiceStatistics) {
@@ -1339,7 +1470,7 @@ options_act_relay_stats(const or_options_t *old_options,
rep_hist_exit_stats_term();
if (old_options && old_options->ConnDirectionStatistics &&
!options->ConnDirectionStatistics)
- rep_hist_conn_stats_term();
+ conn_stats_terminate();
return 0;
}
diff --git a/src/feature/relay/relay_config.h b/src/feature/relay/relay_config.h
index c70c322d88..671399ac0a 100644
--- a/src/feature/relay/relay_config.h
+++ b/src/feature/relay/relay_config.h
@@ -84,6 +84,7 @@ int options_act_relay_dir(const struct or_options_t *old_options);
#ifdef RELAY_CONFIG_PRIVATE
+STATIC void remove_duplicate_orports(struct smartlist_t *ports);
STATIC int check_bridge_distribution_setting(const char *bd);
STATIC int have_enough_mem_for_dircache(const struct or_options_t *options,
size_t total_mem, char **msg);
diff --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c
index 86cd799d42..43b958d563 100644
--- a/src/feature/relay/relay_find_addr.c
+++ b/src/feature/relay/relay_find_addr.c
@@ -15,119 +15,139 @@
#include "feature/control/control_events.h"
#include "feature/dircommon/dir_connection_st.h"
+#include "feature/nodelist/dirlist.h"
#include "feature/relay/relay_find_addr.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
-/** The most recently guessed value of our IP address, based on directory
- * headers. */
-static tor_addr_t last_guessed_ip = TOR_ADDR_NULL;
-
-/** We failed to resolve our address locally, but we'd like to build
- * a descriptor and publish / test reachability. If we have a guess
- * about our address based on directory headers, answer it and return
- * 0; else return -1. */
-static int
-router_guess_address_from_dir_headers(uint32_t *guess)
-{
- if (!tor_addr_is_null(&last_guessed_ip)) {
- *guess = tor_addr_to_ipv4h(&last_guessed_ip);
- return 0;
- }
- return -1;
-}
-
-/** A directory server <b>d_conn</b> told us our IP address is
- * <b>suggestion</b>.
- * If this address is different from the one we think we are now, and
- * if our computer doesn't actually know its IP address, then switch. */
+/** Consider the address suggestion suggested_addr as a possible one to use as
+ * our address.
+ *
+ * This is called when a valid NETINFO cell is received containing a candidate
+ * for our address or when a directory sends us back the X-Your-Address-Is
+ * header.
+ *
+ * The suggested address is ignored if it does NOT come from a trusted source.
+ * At the moment, we only look a trusted directory authorities.
+ *
+ * The suggested address is ignored if it is internal or it is the same as the
+ * given peer_addr which is the address from the endpoint that sent the
+ * NETINFO cell.
+ *
+ * The identity_digest is NULL if this is an address suggested by a directory
+ * since this is a plaintext connection.
+ *
+ * The suggested address is set in our suggested address cache if everything
+ * passes. */
void
-router_new_address_suggestion(const char *suggestion,
- const dir_connection_t *d_conn)
+relay_address_new_suggestion(const tor_addr_t *suggested_addr,
+ const tor_addr_t *peer_addr,
+ const char *identity_digest)
{
- tor_addr_t addr;
- uint32_t cur = 0; /* Current IPv4 address. */
const or_options_t *options = get_options();
- /* first, learn what the IP address actually is */
- if (tor_addr_parse(&addr, suggestion) == -1) {
- log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.",
- escaped(suggestion));
- return;
- }
-
- log_debug(LD_DIR, "Got X-Your-Address-Is: %s.", suggestion);
+ tor_assert(suggested_addr);
+ tor_assert(peer_addr);
+ /* Non server should just ignore this suggestion. Clients don't need to
+ * learn their address let alone cache it. */
if (!server_mode(options)) {
- tor_addr_copy(&last_guessed_ip, &addr);
return;
}
- /* XXXX ipv6 */
- cur = get_last_resolved_addr();
- if (cur ||
- resolve_my_address(LOG_INFO, options, &cur, NULL, NULL) >= 0) {
- /* We're all set -- we already know our address. Great. */
- tor_addr_from_ipv4h(&last_guessed_ip, cur); /* store it in case we
- need it later */
+ /* Is the peer a trusted source? Ignore anything coming from non trusted
+ * source. In this case, we only look at trusted directory authorities. */
+ if (!router_addr_is_trusted_dir(peer_addr) ||
+ (identity_digest && !router_digest_is_trusted_dir(identity_digest))) {
return;
}
- if (tor_addr_is_internal(&addr, 0)) {
- /* Don't believe anybody who says our IP is, say, 127.0.0.1. */
+
+ /* Ignore a suggestion that is an internal address or the same as the one
+ * the peer address. */
+ if (tor_addr_is_internal(suggested_addr, 0)) {
+ /* Do not believe anyone who says our address is internal. */
return;
}
- if (tor_addr_eq(&d_conn->base_.addr, &addr)) {
- /* Don't believe anybody who says our IP is their IP. */
- log_debug(LD_DIR, "A directory server told us our IP address is %s, "
- "but they are just reporting their own IP address. Ignoring.",
- suggestion);
+ if (tor_addr_eq(suggested_addr, peer_addr)) {
+ /* Do not believe anyone who says our address is their address. */
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "A relay endpoint %s is telling us that their address is ours.",
+ fmt_addr(peer_addr));
return;
}
- /* Okay. We can't resolve our own address, and X-Your-Address-Is is giving
- * us an answer different from what we had the last time we managed to
- * resolve it. */
- if (!tor_addr_eq(&last_guessed_ip, &addr)) {
- control_event_server_status(LOG_NOTICE,
- "EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV",
- suggestion);
- log_addr_has_changed(LOG_NOTICE, &last_guessed_ip, &addr,
- d_conn->base_.address);
- ip_address_changed(0);
- tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor()
- will fetch it */
- }
+ /* Save the suggestion in our cache. */
+ resolved_addr_set_suggested(suggested_addr);
}
-/** Make a current best guess at our address, either because
- * it's configured in torrc, or because we've learned it from
- * dirserver headers. Place the answer in *<b>addr</b> and return
- * 0 on success, else return -1 if we have no guess.
+/** Find our address to be published in our descriptor. Three places are
+ * looked at:
*
- * If <b>cache_only</b> is true, just return any cached answers, and
- * don't try to get any new answers.
- */
-MOCK_IMPL(int,
-router_pick_published_address, (const or_options_t *options, uint32_t *addr,
- int cache_only))
+ * 1. Resolved cache. Populated by find_my_address() during the relay
+ * periodic event that attempts to learn if our address has changed.
+ *
+ * 2. If flags is set with RELAY_FIND_ADDR_CACHE_ONLY, only the resolved
+ * and suggested cache are looked at. No address discovery will be done.
+ *
+ * 3. Finally, if all fails, use the suggested address cache which is
+ * populated by the NETINFO cell content or HTTP header from a
+ * directory.
+ *
+ * Return true on success and addr_out contains the address to use for the
+ * given family. On failure to find the address, false is returned and
+ * addr_out is set to an AF_UNSPEC address. */
+MOCK_IMPL(bool,
+relay_find_addr_to_publish, (const or_options_t *options, int family,
+ int flags, tor_addr_t *addr_out))
{
- /* First, check the cached output from resolve_my_address(). */
- *addr = get_last_resolved_addr();
- if (*addr)
- return 0;
-
- /* Second, consider doing a resolve attempt right here. */
- if (!cache_only) {
- if (resolve_my_address(LOG_INFO, options, addr, NULL, NULL) >= 0) {
- log_info(LD_CONFIG,"Success: chose address '%s'.", fmt_addr32(*addr));
- return 0;
+ tor_assert(options);
+ tor_assert(addr_out);
+
+ tor_addr_make_unspec(addr_out);
+
+ /* If an IPv6 is requested, check if IPv6 address discovery is disabled on
+ * this instance. If so, we return a failure. It is done here so we don't
+ * query the suggested cache that might be populated with an IPv6. */
+ if (family == AF_INET6 && options->AddressDisableIPv6) {
+ return false;
+ }
+
+ /* First, check our resolved address cache. It should contain the address
+ * we've discovered from the periodic relay event. */
+ resolved_addr_get_last(family, addr_out);
+ if (!tor_addr_is_null(addr_out)) {
+ goto found;
+ }
+
+ /* Second, attempt to find our address. The following can do a DNS resolve
+ * thus only do it when the no cache only flag is flipped. */
+ if (!(flags & RELAY_FIND_ADDR_CACHE_ONLY)) {
+ if (find_my_address(options, family, LOG_INFO, addr_out, NULL, NULL)) {
+ goto found;
}
}
- /* Third, check the cached output from router_new_address_suggestion(). */
- if (router_guess_address_from_dir_headers(addr) >= 0)
- return 0;
+ /* Third, consider address from our suggestion cache. */
+ resolved_addr_get_suggested(family, addr_out);
+ if (!tor_addr_is_null(addr_out)) {
+ goto found;
+ }
+
+ /* No publishable address was found. */
+ return false;
+
+ found:
+ return true;
+}
- /* We have no useful cached answers. Return failure. */
- return -1;
+/** Return true iff this relay has an address set for the given family.
+ *
+ * This only checks the caches so it will not trigger a full discovery of the
+ * address. */
+bool
+relay_has_address_set(int family)
+{
+ tor_addr_t addr;
+ return relay_find_addr_to_publish(get_options(), family,
+ RELAY_FIND_ADDR_CACHE_ONLY, &addr);
}
diff --git a/src/feature/relay/relay_find_addr.h b/src/feature/relay/relay_find_addr.h
index ac51a977e6..3d30946b05 100644
--- a/src/feature/relay/relay_find_addr.h
+++ b/src/feature/relay/relay_find_addr.h
@@ -9,11 +9,20 @@
#ifndef TOR_RELAY_FIND_ADDR_H
#define TOR_RELAY_FIND_ADDR_H
-MOCK_DECL(int, router_pick_published_address,
- (const or_options_t *options, uint32_t *addr, int cache_only));
+typedef enum {
+ RELAY_FIND_ADDR_NO_FLAG = (1U << 0),
+ RELAY_FIND_ADDR_CACHE_ONLY = (1U << 1),
+} relay_find_addr_flags_t;
-void router_new_address_suggestion(const char *suggestion,
- const dir_connection_t *d_conn);
+void relay_address_new_suggestion(const tor_addr_t *suggested_addr,
+ const tor_addr_t *peer_addr,
+ const char *identity_digest);
+
+MOCK_DECL(bool, relay_find_addr_to_publish,
+ (const or_options_t *options, int family, int flags,
+ tor_addr_t *addr_out));
+
+bool relay_has_address_set(int family);
#ifdef RELAY_FIND_ADDR_PRIVATE
diff --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c
index bfe12cd0b0..ac54064901 100644
--- a/src/feature/relay/relay_periodic.c
+++ b/src/feature/relay/relay_periodic.c
@@ -12,6 +12,8 @@
#include "orconfig.h"
#include "core/or/or.h"
+#include "app/config/resolve_addr.h"
+
#include "core/mainloop/periodic.h"
#include "core/mainloop/cpuworker.h" // XXXX use a pubsub event.
#include "core/mainloop/mainloop.h"
@@ -204,36 +206,77 @@ reachability_warnings_callback(time_t now, const or_options_t *options)
have_completed_a_circuit()) {
/* every 20 minutes, check and complain if necessary */
const routerinfo_t *me = router_get_my_routerinfo();
- if (me && !check_whether_orport_reachable(options)) {
- char *address = tor_dup_ip(me->addr);
- if (address) {
- log_warn(LD_CONFIG,
- "Your server (%s:%d) has not managed to confirm that "
- "its ORPort is reachable. Relays do not publish descriptors "
- "until their ORPort and DirPort are reachable. Please check "
- "your firewalls, ports, address, /etc/hosts file, etc.",
- address, me->or_port);
- control_event_server_status(LOG_WARN,
- "REACHABILITY_FAILED ORADDRESS=%s:%d",
- address, me->or_port);
- tor_free(address);
+ bool v4_ok =
+ router_orport_seems_reachable(options,AF_INET);
+ bool v6_ok =
+ router_orport_seems_reachable(options,AF_INET6);
+ if (me && !(v4_ok && v6_ok)) {
+ /* We need to warn that one or more of our ORPorts isn't reachable.
+ * Determine which, and give a reasonable warning. */
+ char *address4 = tor_addr_to_str_dup(&me->ipv4_addr);
+ char *address6 = tor_addr_to_str_dup(&me->ipv6_addr);
+ if (address4 || address6) {
+ char *where4=NULL, *where6=NULL;
+ if (!v4_ok)
+ tor_asprintf(&where4, "%s:%d", address4, me->ipv4_orport);
+ if (!v6_ok)
+ tor_asprintf(&where6, "[%s]:%d", address6, me->ipv6_orport);
+ const char *opt_and = (!v4_ok && !v6_ok) ? "and" : "";
+
+ /* IPv4 reachability test worked but not the IPv6. We will _not_
+ * publish the descriptor if our IPv6 was configured. We will if it
+ * was auto discovered. */
+ if (v4_ok && !v6_ok && !resolved_addr_is_configured(AF_INET6)) {
+ static ratelim_t rlim = RATELIM_INIT(3600);
+ log_fn_ratelim(&rlim, LOG_NOTICE, LD_CONFIG,
+ "Auto-discovered IPv6 address %s has not been found "
+ "reachable. However, IPv4 address is reachable. "
+ "Publishing server descriptor without IPv6 address.",
+ where6 ? where6 : "");
+ /* Indicate we want to publish even if reachability test failed. */
+ mark_my_descriptor_if_omit_ipv6_changes("IPv4 is reachable. "
+ "IPv6 is not but was "
+ "auto-discovered", true);
+ } else {
+ log_warn(LD_CONFIG,
+ "Your server has not managed to confirm reachability for "
+ "its ORPort(s) at %s%s%s. Relays do not publish "
+ "descriptors until their ORPort and DirPort are "
+ "reachable. Please check your firewalls, ports, address, "
+ "/etc/hosts file, etc.",
+ where4?where4:"",
+ opt_and,
+ where6?where6:"");
+ }
+ tor_free(where4);
+ tor_free(where6);
+ if (!v4_ok) {
+ control_event_server_status(LOG_WARN,
+ "REACHABILITY_FAILED ORADDRESS=%s:%d",
+ address4, me->ipv4_orport);
+ }
+ if (!v6_ok) {
+ control_event_server_status(LOG_WARN,
+ "REACHABILITY_FAILED ORADDRESS=[%s]:%d",
+ address6, me->ipv6_orport);
+ }
}
+ tor_free(address4);
+ tor_free(address6);
}
- if (me && !check_whether_dirport_reachable(options)) {
- char *address = tor_dup_ip(me->addr);
- if (address) {
- log_warn(LD_CONFIG,
- "Your server (%s:%d) has not managed to confirm that its "
- "DirPort is reachable. Relays do not publish descriptors "
- "until their ORPort and DirPort are reachable. Please check "
- "your firewalls, ports, address, /etc/hosts file, etc.",
- address, me->dir_port);
- control_event_server_status(LOG_WARN,
- "REACHABILITY_FAILED DIRADDRESS=%s:%d",
- address, me->dir_port);
- tor_free(address);
- }
+ if (me && !router_dirport_seems_reachable(options)) {
+ char *address4 = tor_addr_to_str_dup(&me->ipv4_addr);
+ log_warn(LD_CONFIG,
+ "Your server (%s:%d) has not managed to confirm that its "
+ "DirPort is reachable. Relays do not publish descriptors "
+ "until their ORPort and DirPort are reachable. Please check "
+ "your firewalls, ports, address, /etc/hosts file, etc.",
+ address4, me->ipv4_dirport);
+ control_event_server_status(LOG_WARN,
+ "REACHABILITY_FAILED DIRADDRESS=%s:%d",
+ address4, me->ipv4_dirport);
+ tor_free(address4);
}
}
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index 34d8163c36..11847a2616 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -38,12 +38,14 @@
#include "feature/relay/dns.h"
#include "feature/relay/relay_config.h"
#include "feature/relay/relay_find_addr.h"
+#include "feature/relay/relay_periodic.h"
#include "feature/relay/router.h"
#include "feature/relay/routerkeys.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
#include "lib/geoip/geoip.h"
#include "feature/stats/geoip_stats.h"
+#include "feature/stats/bwhist.h"
#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_format.h"
@@ -174,7 +176,7 @@ routerinfo_err_is_transient(int err)
/**
* For simplicity, we consider all errors other than
* "not a server" transient - see discussion on
- * https://trac.torproject.org/projects/tor/ticket/27034
+ * https://bugs.torproject.org/tpo/core/tor/27034.
*/
return err != TOR_ROUTERINFO_ERROR_NOT_A_SERVER;
}
@@ -831,53 +833,57 @@ router_initialize_tls_context(void)
* -1 if Tor should die,
*/
STATIC int
-router_write_fingerprint(int hashed)
+router_write_fingerprint(int hashed, int ed25519_identity)
{
- char *keydir = NULL, *cp = NULL;
+ char *keydir = NULL;
const char *fname = hashed ? "hashed-fingerprint" :
- "fingerprint";
+ (ed25519_identity ? "fingerprint-ed25519" :
+ "fingerprint");
char fingerprint[FINGERPRINT_LEN+1];
const or_options_t *options = get_options();
char *fingerprint_line = NULL;
int result = -1;
keydir = get_datadir_fname(fname);
- log_info(LD_GENERAL,"Dumping %sfingerprint to \"%s\"...",
- hashed ? "hashed " : "", keydir);
- if (!hashed) {
- if (crypto_pk_get_fingerprint(get_server_identity_key(),
- fingerprint, 0) < 0) {
- log_err(LD_GENERAL,"Error computing fingerprint");
- goto done;
- }
- } else {
- if (crypto_pk_get_hashed_fingerprint(get_server_identity_key(),
- fingerprint) < 0) {
- log_err(LD_GENERAL,"Error computing hashed fingerprint");
- goto done;
+ log_info(LD_GENERAL,"Dumping %s%s to \"%s\"...", hashed ? "hashed " : "",
+ ed25519_identity ? "ed25519 identity" : "fingerprint", keydir);
+
+ if (ed25519_identity) { /* ed25519 identity */
+ digest256_to_base64(fingerprint, (const char *)
+ get_master_identity_key()->pubkey);
+ } else { /* RSA identity */
+ if (!hashed) {
+ if (crypto_pk_get_fingerprint(get_server_identity_key(),
+ fingerprint, 0) < 0) {
+ log_err(LD_GENERAL,"Error computing fingerprint");
+ goto done;
+ }
+ } else {
+ if (crypto_pk_get_hashed_fingerprint(get_server_identity_key(),
+ fingerprint) < 0) {
+ log_err(LD_GENERAL,"Error computing hashed fingerprint");
+ goto done;
+ }
}
}
tor_asprintf(&fingerprint_line, "%s %s\n", options->Nickname, fingerprint);
/* Check whether we need to write the (hashed-)fingerprint file. */
-
- cp = read_file_to_str(keydir, RFTS_IGNORE_MISSING, NULL);
- if (!cp || strcmp(cp, fingerprint_line)) {
- if (write_str_to_file(keydir, fingerprint_line, 0)) {
- log_err(LD_FS, "Error writing %sfingerprint line to file",
- hashed ? "hashed " : "");
- goto done;
- }
+ if (write_str_to_file_if_not_equal(keydir, fingerprint_line)) {
+ log_err(LD_FS, "Error writing %s%s line to file",
+ hashed ? "hashed " : "",
+ ed25519_identity ? "ed25519 identity" : "fingerprint");
+ goto done;
}
- log_notice(LD_GENERAL, "Your Tor %s identity key fingerprint is '%s %s'",
- hashed ? "bridge's hashed" : "server's", options->Nickname,
- fingerprint);
+ log_notice(LD_GENERAL, "Your Tor %s identity key %s fingerprint is '%s %s'",
+ hashed ? "bridge's hashed" : "server's",
+ ed25519_identity ? "ed25519" : "",
+ options->Nickname, fingerprint);
result = 0;
done:
- tor_free(cp);
tor_free(keydir);
tor_free(fingerprint_line);
return result;
@@ -1109,15 +1115,20 @@ init_keys(void)
}
}
- /* 5. Dump fingerprint and possibly hashed fingerprint to files. */
- if (router_write_fingerprint(0)) {
+ /* 5. Dump fingerprint, ed25519 identity and possibly hashed fingerprint
+ * to files. */
+ if (router_write_fingerprint(0, 0)) {
log_err(LD_FS, "Error writing fingerprint to file");
return -1;
}
- if (!public_server_mode(options) && router_write_fingerprint(1)) {
+ if (!public_server_mode(options) && router_write_fingerprint(1, 0)) {
log_err(LD_FS, "Error writing hashed fingerprint to file");
return -1;
}
+ if (router_write_fingerprint(0, 1)) {
+ log_err(LD_FS, "Error writing ed25519 identity to file");
+ return -1;
+ }
if (!authdir_mode(options))
return 0;
@@ -1134,10 +1145,12 @@ init_keys(void)
ds = router_get_trusteddirserver_by_digest(digest);
if (!ds) {
+ tor_addr_port_t ipv6_orport;
+ routerconf_find_ipv6_or_ap(options, &ipv6_orport);
ds = trusted_dir_server_new(options->Nickname, NULL,
- router_get_advertised_dir_port(options, 0),
- router_get_advertised_or_port(options),
- NULL,
+ routerconf_find_dir_port(options, 0),
+ routerconf_find_or_port(options,AF_INET),
+ &ipv6_orport,
digest,
v3_digest,
type, 0.0);
@@ -1288,10 +1301,10 @@ decide_to_advertise_dir_impl(const or_options_t *options,
return 1;
if (net_is_disabled())
return 0;
- if (dir_port && !router_get_advertised_dir_port(options, dir_port))
+ if (dir_port && !routerconf_find_dir_port(options, dir_port))
return 0;
if (supports_tunnelled_dir_requests &&
- !router_get_advertised_or_port(options))
+ !routerconf_find_or_port(options, AF_INET))
return 0;
/* Part two: consider config options that could make us choose to
@@ -1335,6 +1348,17 @@ should_refuse_unknown_exits(const or_options_t *options)
}
}
+/**
+ * If true, then we will publish our descriptor even if our own IPv4 ORPort
+ * seems to be unreachable.
+ **/
+static bool publish_even_when_ipv4_orport_unreachable = false;
+/**
+ * If true, then we will publish our descriptor even if our own IPv6 ORPort
+ * seems to be unreachable.
+ **/
+static bool publish_even_when_ipv6_orport_unreachable = false;
+
/** Decide if we're a publishable server. We are a publishable server if:
* - We don't have the ClientOnly option set
* and
@@ -1361,16 +1385,26 @@ decide_if_publishable_server(void)
return 0;
if (authdir_mode(options))
return 1;
- if (!router_get_advertised_or_port(options))
- return 0;
- if (!check_whether_orport_reachable(options))
+ if (!routerconf_find_or_port(options, AF_INET))
return 0;
+ if (!router_orport_seems_reachable(options, AF_INET)) {
+ // We have an ipv4 orport, and it doesn't seem reachable.
+ if (!publish_even_when_ipv4_orport_unreachable) {
+ return 0;
+ }
+ }
+ if (!router_orport_seems_reachable(options, AF_INET6)) {
+ // We have an ipv6 orport, and it doesn't seem reachable.
+ if (!publish_even_when_ipv6_orport_unreachable) {
+ return 0;
+ }
+ }
if (router_have_consensus_path() == CONSENSUS_PATH_INTERNAL) {
/* All set: there are no exits in the consensus (maybe this is a tiny
* test network), so we can't check our DirPort reachability. */
return 1;
} else {
- return check_whether_dirport_reachable(options);
+ return router_dirport_seems_reachable(options);
}
}
@@ -1420,22 +1454,14 @@ router_get_active_listener_port_by_type_af(int listener_type,
return 0;
}
-/** Return the port that we should advertise as our ORPort; this is either
- * the one configured in the ORPort option, or the one we actually bound to
- * if ORPort is "auto". Returns 0 if no port is found. */
+/** Return the port that we should advertise as our ORPort in a given address
+ * family; this is either the one configured in the ORPort option, or the one
+ * we actually bound to if ORPort is "auto". Returns 0 if no port is found. */
uint16_t
-router_get_advertised_or_port(const or_options_t *options)
+routerconf_find_or_port(const or_options_t *options,
+ sa_family_t family)
{
- return router_get_advertised_or_port_by_af(options, AF_INET);
-}
-
-/** As router_get_advertised_or_port(), but allows an address family argument.
- */
-uint16_t
-router_get_advertised_or_port_by_af(const or_options_t *options,
- sa_family_t family)
-{
- int port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ int port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER,
family);
(void)options;
@@ -1448,11 +1474,11 @@ router_get_advertised_or_port_by_af(const or_options_t *options,
return port;
}
-/** As router_get_advertised_or_port(), but returns the IPv6 address and
+/** As routerconf_find_or_port(), but returns the IPv6 address and
* port in ipv6_ap_out, which must not be NULL. Returns a null address and
* zero port, if no ORPort is found. */
void
-router_get_advertised_ipv6_or_ap(const or_options_t *options,
+routerconf_find_ipv6_or_ap(const or_options_t *options,
tor_addr_port_t *ipv6_ap_out)
{
/* Bug in calling function, we can't return a sensible result, and it
@@ -1463,11 +1489,10 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options,
tor_addr_make_null(&ipv6_ap_out->addr, AF_INET6);
ipv6_ap_out->port = 0;
- const tor_addr_t *addr = get_first_advertised_addr_by_type_af(
+ const tor_addr_t *addr = portconf_get_first_advertised_addr(
CONN_TYPE_OR_LISTENER,
AF_INET6);
- const uint16_t port = router_get_advertised_or_port_by_af(
- options,
+ const uint16_t port = routerconf_find_or_port(options,
AF_INET6);
if (!addr || port == 0) {
@@ -1494,20 +1519,42 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options,
/** Returns true if this router has an advertised IPv6 ORPort. */
bool
-router_has_advertised_ipv6_orport(const or_options_t *options)
+routerconf_has_ipv6_orport(const or_options_t *options)
{
- tor_addr_port_t ipv6_ap;
- router_get_advertised_ipv6_or_ap(options, &ipv6_ap);
- return tor_addr_port_is_valid_ap(&ipv6_ap, 0);
+ /* What we want here is to learn if we have configured an IPv6 ORPort.
+ * Remember, ORPort can listen on [::] and thus consider internal by
+ * router_get_advertised_ipv6_or_ap() since we do _not_ want to advertise
+ * such address. */
+ const tor_addr_t *addr =
+ portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER, AF_INET6);
+ const uint16_t port =
+ routerconf_find_or_port(options, AF_INET6);
+
+ return tor_addr_port_is_valid(addr, port, 1);
}
-/** Returns true if this router has an advertised IPv6 ORPort. */
+/** Returns true if this router can extend over IPv6.
+ *
+ * This check should only be performed by relay extend code.
+ *
+ * Clients should check if relays can initiate and accept IPv6 extends using
+ * node_supports_initiating_ipv6_extends() and
+ * node_supports_accepting_ipv6_extends().
+ *
+ * As with other extends, relays should assume the client has already
+ * performed the relevant checks for the next hop. (Otherwise, relays that
+ * have just added IPv6 ORPorts won't be able to self-test those ORPorts.)
+ *
+ * Accepting relays don't need to perform any IPv6-specific checks before
+ * accepting a connection, because having an IPv6 ORPort implies support for
+ * the relevant protocol version.
+ */
MOCK_IMPL(bool,
router_can_extend_over_ipv6,(const or_options_t *options))
{
/* We might add some extra checks here, such as ExtendAllowIPv6Addresses
* from ticket 33818. */
- return router_has_advertised_ipv6_orport(options);
+ return routerconf_has_ipv6_orport(options);
}
/** Return the port that we should advertise as our DirPort;
@@ -1516,9 +1563,9 @@ router_can_extend_over_ipv6,(const or_options_t *options))
* the one configured in the DirPort option,
* or the one we actually bound to if DirPort is "auto". */
uint16_t
-router_get_advertised_dir_port(const or_options_t *options, uint16_t dirport)
+routerconf_find_dir_port(const or_options_t *options, uint16_t dirport)
{
- int dirport_configured = get_primary_dir_port();
+ int dirport_configured = portconf_get_primary_dir_port();
(void)options;
if (!dirport_configured)
@@ -1682,6 +1729,31 @@ router_is_me(const routerinfo_t *router)
return router_digest_is_me(router->cache_info.identity_digest);
}
+/**
+ * Return true if we are a server, and if @a addr is an address we are
+ * currently publishing (or trying to publish) in our descriptor.
+ * Return false otherwise.
+ **/
+bool
+router_addr_is_my_published_addr(const tor_addr_t *addr)
+{
+ IF_BUG_ONCE(!addr)
+ return false;
+
+ const routerinfo_t *me = router_get_my_routerinfo();
+ if (!me)
+ return false;
+
+ switch (tor_addr_family(addr)) {
+ case AF_INET:
+ return tor_addr_eq(addr, &me->ipv4_addr);
+ case AF_INET6:
+ return tor_addr_eq(addr, &me->ipv6_addr);
+ default:
+ return false;
+ }
+}
+
/** Return a routerinfo for this OR, rebuilding a fresh one if
* necessary. Return NULL on error, or if called on an OP. */
MOCK_IMPL(const routerinfo_t *,
@@ -1704,16 +1776,6 @@ router_get_my_routerinfo_with_err,(int *err))
return NULL;
}
- if (!desc_clean_since) {
- int rebuild_err = router_rebuild_descriptor(0);
- if (rebuild_err < 0) {
- if (err)
- *err = rebuild_err;
-
- return NULL;
- }
- }
-
if (!desc_routerinfo) {
if (err)
*err = TOR_ROUTERINFO_ERROR_DESC_REBUILDING;
@@ -1769,54 +1831,55 @@ router_get_descriptor_gen_reason(void)
* ORPort or DirPort.
* listener_type is either CONN_TYPE_OR_LISTENER or CONN_TYPE_DIR_LISTENER. */
static void
-router_check_descriptor_address_port_consistency(uint32_t ipv4h_desc_addr,
+router_check_descriptor_address_port_consistency(const tor_addr_t *addr,
int listener_type)
{
+ int family, port_cfg;
+
+ tor_assert(addr);
tor_assert(listener_type == CONN_TYPE_OR_LISTENER ||
listener_type == CONN_TYPE_DIR_LISTENER);
- /* The first advertised Port may be the magic constant CFG_AUTO_PORT.
- */
- int port_v4_cfg = get_first_advertised_port_by_type_af(listener_type,
- AF_INET);
- if (port_v4_cfg != 0 &&
- !port_exists_by_type_addr32h_port(listener_type,
- ipv4h_desc_addr, port_v4_cfg, 1)) {
- const tor_addr_t *port_addr = get_first_advertised_addr_by_type_af(
- listener_type,
- AF_INET);
- /* If we're building a descriptor with no advertised address,
- * something is terribly wrong. */
- tor_assert(port_addr);
-
- tor_addr_t desc_addr;
- char port_addr_str[TOR_ADDR_BUF_LEN];
- char desc_addr_str[TOR_ADDR_BUF_LEN];
-
- tor_addr_to_str(port_addr_str, port_addr, TOR_ADDR_BUF_LEN, 0);
-
- tor_addr_from_ipv4h(&desc_addr, ipv4h_desc_addr);
- tor_addr_to_str(desc_addr_str, &desc_addr, TOR_ADDR_BUF_LEN, 0);
-
- const char *listener_str = (listener_type == CONN_TYPE_OR_LISTENER ?
- "OR" : "Dir");
- log_warn(LD_CONFIG, "The IPv4 %sPort address %s does not match the "
- "descriptor address %s. If you have a static public IPv4 "
- "address, use 'Address <IPv4>' and 'OutboundBindAddress "
- "<IPv4>'. If you are behind a NAT, use two %sPort lines: "
- "'%sPort <PublicPort> NoListen' and '%sPort <InternalPort> "
- "NoAdvertise'.",
- listener_str, port_addr_str, desc_addr_str, listener_str,
- listener_str, listener_str);
- }
-}
-
-/* Tor relays only have one IPv4 address in the descriptor, which is derived
- * from the Address torrc option, or guessed using various methods in
- * router_pick_published_address().
- * Warn the operator if there is no ORPort on the descriptor address
- * ipv4h_desc_addr.
+ family = tor_addr_family(addr);
+ /* The first advertised Port may be the magic constant CFG_AUTO_PORT. */
+ port_cfg = portconf_get_first_advertised_port(listener_type, family);
+ if (port_cfg != 0 &&
+ !port_exists_by_type_addr_port(listener_type, addr, port_cfg, 1)) {
+ const tor_addr_t *port_addr =
+ portconf_get_first_advertised_addr(listener_type, family);
+ /* If we're building a descriptor with no advertised address,
+ * something is terribly wrong. */
+ tor_assert(port_addr);
+
+ char port_addr_str[TOR_ADDR_BUF_LEN];
+ char desc_addr_str[TOR_ADDR_BUF_LEN];
+
+ tor_addr_to_str(port_addr_str, port_addr, TOR_ADDR_BUF_LEN, 0);
+ tor_addr_to_str(desc_addr_str, addr, TOR_ADDR_BUF_LEN, 0);
+
+ const char *listener_str = (listener_type == CONN_TYPE_OR_LISTENER ?
+ "OR" : "Dir");
+ const char *af_str = fmt_af_family(family);
+ log_warn(LD_CONFIG, "The %s %sPort address %s does not match the "
+ "descriptor address %s. If you have a static public IPv4 "
+ "address, use 'Address <%s>' and 'OutboundBindAddress "
+ "<%s>'. If you are behind a NAT, use two %sPort lines: "
+ "'%sPort <PublicPort> NoListen' and '%sPort <InternalPort> "
+ "NoAdvertise'.",
+ af_str, listener_str, port_addr_str, desc_addr_str, af_str,
+ af_str, listener_str, listener_str, listener_str);
+ }
+}
+
+/** Tor relays only have one IPv4 or/and one IPv6 address in the descriptor,
+ * which is derived from the Address torrc option, or guessed using various
+ * methods in relay_find_addr_to_publish().
+ *
+ * Warn the operator if there is no ORPort associated with the given address
+ * in addr.
+ *
* Warn the operator if there is no DirPort on the descriptor address.
+ *
* This catches a few common config errors:
* - operators who expect ORPorts and DirPorts to be advertised on the
* ports' listen addresses, rather than the torrc Address (or guessed
@@ -1825,20 +1888,22 @@ router_check_descriptor_address_port_consistency(uint32_t ipv4h_desc_addr,
* addresses;
* - discrepancies between guessed addresses and configured listen
* addresses (when the Address option isn't set).
+ *
* If a listener is listening on all IPv4 addresses, it is assumed that it
* is listening on the configured Address, and no messages are logged.
+ *
* If an operators has specified NoAdvertise ORPorts in a NAT setting,
* no messages are logged, unless they have specified other advertised
* addresses.
+ *
* The message tells operators to configure an ORPort and DirPort that match
- * the Address (using NoListen if needed).
- */
+ * the Address (using NoListen if needed). */
static void
-router_check_descriptor_address_consistency(uint32_t ipv4h_desc_addr)
+router_check_descriptor_address_consistency(const tor_addr_t *addr)
{
- router_check_descriptor_address_port_consistency(ipv4h_desc_addr,
+ router_check_descriptor_address_port_consistency(addr,
CONN_TYPE_OR_LISTENER);
- router_check_descriptor_address_port_consistency(ipv4h_desc_addr,
+ router_check_descriptor_address_port_consistency(addr,
CONN_TYPE_DIR_LISTENER);
}
@@ -1980,33 +2045,56 @@ MOCK_IMPL(STATIC int,
router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
{
routerinfo_t *ri = NULL;
- uint32_t addr;
+ tor_addr_t ipv4_addr, ipv6_addr;
char platform[256];
int hibernating = we_are_hibernating();
const or_options_t *options = get_options();
int result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+ uint16_t ipv6_orport = 0;
if (BUG(!ri_out)) {
result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
goto err;
}
- if (router_pick_published_address(options, &addr, 0) < 0) {
+ /* Find our resolved address both IPv4 and IPv6. In case the address is not
+ * found, the object is set to an UNSPEC address. */
+ bool have_v4 = relay_find_addr_to_publish(options, AF_INET,
+ RELAY_FIND_ADDR_NO_FLAG,
+ &ipv4_addr);
+ bool have_v6 = relay_find_addr_to_publish(options, AF_INET6,
+ RELAY_FIND_ADDR_NO_FLAG,
+ &ipv6_addr);
+
+ /* Tor requires a relay to have an IPv4 so bail if we can't find it. */
+ if (!have_v4) {
log_warn(LD_CONFIG, "Don't know my address while generating descriptor");
result = TOR_ROUTERINFO_ERROR_NO_EXT_ADDR;
goto err;
}
-
/* Log a message if the address in the descriptor doesn't match the ORPort
* and DirPort addresses configured by the operator. */
- router_check_descriptor_address_consistency(addr);
+ router_check_descriptor_address_consistency(&ipv4_addr);
+ router_check_descriptor_address_consistency(&ipv6_addr);
ri = tor_malloc_zero(sizeof(routerinfo_t));
ri->cache_info.routerlist_index = -1;
ri->nickname = tor_strdup(options->Nickname);
- ri->addr = addr;
- ri->or_port = router_get_advertised_or_port(options);
- ri->dir_port = router_get_advertised_dir_port(options, 0);
+
+ /* IPv4. */
+ tor_addr_copy(&ri->ipv4_addr, &ipv4_addr);
+ ri->ipv4_orport = routerconf_find_or_port(options, AF_INET);
+ ri->ipv4_dirport = routerconf_find_dir_port(options, 0);
+
+ /* IPv6. Do not publish an IPv6 if we don't have an ORPort that can be used
+ * with the address. This is possible for instance if the ORPort is
+ * IPv4Only. */
+ ipv6_orport = routerconf_find_or_port(options, AF_INET6);
+ if (have_v6 && ipv6_orport != 0) {
+ tor_addr_copy(&ri->ipv6_addr, &ipv6_addr);
+ ri->ipv6_orport = ipv6_orport;
+ }
+
ri->supports_tunnelled_dir_requests =
directory_permits_begindir_requests(options);
ri->cache_info.published_on = time(NULL);
@@ -2018,13 +2106,6 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
tor_memdup(&get_current_curve25519_keypair()->pubkey,
sizeof(curve25519_public_key_t));
- /* For now, at most one IPv6 or-address is being advertised. */
- tor_addr_port_t ipv6_orport;
- router_get_advertised_ipv6_or_ap(options, &ipv6_orport);
- /* If there is no valid IPv6 ORPort, the address and port are null. */
- tor_addr_copy(&ri->ipv6_addr, &ipv6_orport.addr);
- ri->ipv6_orport = ipv6_orport.port;
-
ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key());
if (BUG(crypto_pk_get_digest(ri->identity_pkey,
ri->cache_info.identity_digest) < 0)) {
@@ -2046,13 +2127,14 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
ri->bandwidthburst = relay_get_effective_bwburst(options);
/* Report bandwidth, unless we're hibernating or shutting down */
- ri->bandwidthcapacity = hibernating ? 0 : rep_hist_bandwidth_assess();
+ ri->bandwidthcapacity = hibernating ? 0 : bwhist_bandwidth_assess();
if (dns_seems_to_be_broken() || has_dns_init_failed()) {
/* DNS is screwed up; don't claim to be an exit. */
policies_exit_policy_append_reject_star(&ri->exit_policy);
} else {
- policies_parse_exit_policy_from_options(options,ri->addr,&ri->ipv6_addr,
+ policies_parse_exit_policy_from_options(options, &ri->ipv4_addr,
+ &ri->ipv6_addr,
&ri->exit_policy);
}
ri->policy_is_reject_star =
@@ -2335,21 +2417,10 @@ router_rebuild_descriptor(int force)
int err = 0;
routerinfo_t *ri;
extrainfo_t *ei;
- uint32_t addr;
- const or_options_t *options = get_options();
if (desc_clean_since && !force)
return 0;
- if (router_pick_published_address(options, &addr, 0) < 0 ||
- router_get_advertised_or_port(options) == 0) {
- /* Stop trying to rebuild our descriptor every second. We'll
- * learn that it's time to try again when ip_address_changed()
- * marks it dirty. */
- desc_clean_since = time(NULL);
- return TOR_ROUTERINFO_ERROR_DESC_REBUILDING;
- }
-
log_info(LD_OR, "Rebuilding relay descriptor%s", force ? " (forced)" : "");
err = router_build_fresh_descriptor(&ri, &ei);
@@ -2373,6 +2444,52 @@ router_rebuild_descriptor(int force)
return 0;
}
+/** Called when we have a new set of consensus parameters. */
+void
+router_new_consensus_params(const networkstatus_t *ns)
+{
+ const int32_t DEFAULT_ASSUME_REACHABLE = 0;
+ const int32_t DEFAULT_ASSUME_REACHABLE_IPV6 = 0;
+ int ar, ar6;
+ ar = networkstatus_get_param(ns,
+ "assume-reachable",
+ DEFAULT_ASSUME_REACHABLE, 0, 1);
+ ar6 = networkstatus_get_param(ns,
+ "assume-reachable-ipv6",
+ DEFAULT_ASSUME_REACHABLE_IPV6, 0, 1);
+
+ publish_even_when_ipv4_orport_unreachable = ar;
+ publish_even_when_ipv6_orport_unreachable = ar || ar6;
+}
+
+/** Indicate if the IPv6 address should be omitted from the descriptor when
+ * publishing it. This can happen if the IPv4 is reachable but the
+ * auto-discovered IPv6 is not. We still publish the descriptor.
+ *
+ * Only relays should look at this and only for their descriptor.
+ *
+ * XXX: The real harder fix is to never put in the routerinfo_t a non
+ * reachable address and instead use the last resolved address cache to do
+ * reachability test or anything that has to do with what address tor thinks
+ * it has. */
+static bool omit_ipv6_on_publish = false;
+
+/** Mark our descriptor out of data iff the IPv6 omit status flag is flipped
+ * it changes from its previous value.
+ *
+ * This is used when our IPv6 port is found reachable or not. */
+void
+mark_my_descriptor_if_omit_ipv6_changes(const char *reason, bool omit_ipv6)
+{
+ bool previous = omit_ipv6_on_publish;
+ omit_ipv6_on_publish = omit_ipv6;
+
+ /* Only mark it dirty if the IPv6 omit flag was flipped. */
+ if (previous != omit_ipv6) {
+ mark_my_descriptor_dirty(reason);
+ }
+}
+
/** If our router descriptor ever goes this long without being regenerated
* because something changed, we force an immediate regenerate-and-upload. */
#define FORCE_REGENERATE_DESCRIPTOR_INTERVAL (18*60*60)
@@ -2431,11 +2548,13 @@ mark_my_descriptor_dirty(const char *reason)
if (BUG(reason == NULL)) {
reason = "marked descriptor dirty for unspecified reason";
}
- if (server_mode(options) && options->PublishServerDescriptor_)
+ if (server_mode(options) && options->PublishServerDescriptor_) {
log_info(LD_OR, "Decided to publish new relay descriptor: %s", reason);
+ }
desc_clean_since = 0;
if (!desc_dirty_reason)
desc_dirty_reason = reason;
+ reschedule_descriptor_update_check();
}
/** How frequently will we republish our descriptor because of large (factor
@@ -2474,7 +2593,7 @@ check_descriptor_bandwidth_changed(time_t now)
/* Consider ourselves to have zero bandwidth if we're hibernating or
* shutting down. */
- cur = hibernating ? 0 : rep_hist_bandwidth_assess();
+ cur = hibernating ? 0 : bwhist_bandwidth_assess();
if ((prev != cur && (!prev || !cur)) ||
cur > (prev * BANDWIDTH_CHANGE_FACTOR) ||
@@ -2518,48 +2637,59 @@ log_addr_has_changed(int severity,
addrbuf_cur, source);
}
-/** Check whether our own address as defined by the Address configuration
- * has changed. This is for routers that get their address from a service
- * like dyndns. If our address has changed, mark our descriptor dirty. */
+/** Check whether our own address has changed versus the one we have in our
+ * current descriptor.
+ *
+ * If our address has changed, call ip_address_changed() which takes
+ * appropriate actions. */
void
check_descriptor_ipaddress_changed(time_t now)
{
- uint32_t prev, cur;
- const or_options_t *options = get_options();
- const char *method = NULL;
- char *hostname = NULL;
const routerinfo_t *my_ri = router_get_my_routerinfo();
+ resolved_addr_method_t method = RESOLVED_ADDR_NONE;
+ char *hostname = NULL;
+ int families[2] = { AF_INET, AF_INET6 };
+ bool has_changed = false;
(void) now;
- if (my_ri == NULL) /* make sure routerinfo exists */
- return;
-
- /* XXXX ipv6 */
- prev = my_ri->addr;
- if (resolve_my_address(LOG_INFO, options, &cur, &method, &hostname) < 0) {
- log_info(LD_CONFIG,"options->Address didn't resolve into an IP.");
+ /* We can't learn our descriptor address without one. */
+ if (my_ri == NULL) {
return;
}
- if (prev != cur) {
- char *source;
- tor_addr_t tmp_prev, tmp_cur;
-
- tor_addr_from_ipv4h(&tmp_prev, prev);
- tor_addr_from_ipv4h(&tmp_cur, cur);
+ for (size_t i = 0; i < ARRAY_LENGTH(families); i++) {
+ tor_addr_t current;
+ const tor_addr_t *previous;
+ int family = families[i];
- tor_asprintf(&source, "METHOD=%s%s%s", method,
- hostname ? " HOSTNAME=" : "",
- hostname ? hostname : "");
+ /* Get the descriptor address from the family we are looking up. */
+ previous = &my_ri->ipv4_addr;
+ if (family == AF_INET6) {
+ previous = &my_ri->ipv6_addr;
+ }
- log_addr_has_changed(LOG_NOTICE, &tmp_prev, &tmp_cur, source);
- tor_free(source);
+ /* Ignore returned value because we want to notice not only an address
+ * change but also if an address is lost (current == UNSPEC). */
+ find_my_address(get_options(), family, LOG_INFO, &current, &method,
+ &hostname);
+
+ if (!tor_addr_eq(previous, &current)) {
+ char *source;
+ tor_asprintf(&source, "METHOD=%s%s%s",
+ resolved_addr_method_to_str(method),
+ hostname ? " HOSTNAME=" : "",
+ hostname ? hostname : "");
+ log_addr_has_changed(LOG_NOTICE, previous, &current, source);
+ tor_free(source);
+ has_changed = true;
+ }
+ tor_free(hostname);
+ }
+ if (has_changed) {
ip_address_changed(0);
}
-
- tor_free(hostname);
}
/** Set <b>platform</b> (max length <b>len</b>) to a NUL-terminated short
@@ -2765,7 +2895,7 @@ router_dump_router_to_string(routerinfo_t *router,
}
}
- if (router->ipv6_orport &&
+ if (!omit_ipv6_on_publish && router->ipv6_orport &&
tor_addr_family(&router->ipv6_addr) == AF_INET6) {
char addr[TOR_ADDR_BUF_LEN];
const char *a;
@@ -2783,7 +2913,7 @@ router_dump_router_to_string(routerinfo_t *router,
proto_line = tor_strdup("");
}
- address = tor_dup_ip(router->addr);
+ address = tor_addr_to_str_dup(&router->ipv4_addr);
if (!address)
goto err;
@@ -2807,8 +2937,8 @@ router_dump_router_to_string(routerinfo_t *router,
"%s%s%s",
router->nickname,
address,
- router->or_port,
- router_should_advertise_dirport(options, router->dir_port),
+ router->ipv4_orport,
+ router_should_advertise_dirport(options, router->ipv4_dirport),
ed_cert_line ? ed_cert_line : "",
extra_or_address ? extra_or_address : "",
router->platform,
@@ -2854,11 +2984,9 @@ router_dump_router_to_string(routerinfo_t *router,
}
if (router->onion_curve25519_pkey) {
- char kbuf[128];
- base64_encode(kbuf, sizeof(kbuf),
- (const char *)router->onion_curve25519_pkey->public_key,
- CURVE25519_PUBKEY_LEN, BASE64_ENCODE_MULTILINE);
- smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
+ char kbuf[CURVE25519_BASE64_PADDED_LEN + 1];
+ curve25519_public_to_base64(kbuf, router->onion_curve25519_pkey, false);
+ smartlist_add_asprintf(chunks, "ntor-onion-key %s\n", kbuf);
} else {
/* Authorities will start rejecting relays without ntor keys in 0.2.9 */
log_err(LD_BUG, "A relay must have an ntor onion key");
@@ -3135,7 +3263,7 @@ extrainfo_dump_to_string_stats_helper(smartlist_t *chunks,
log_info(LD_GENERAL, "Adding stats to extra-info descriptor.");
/* Bandwidth usage stats don't have their own option */
{
- contents = rep_hist_get_bandwidth_lines();
+ contents = bwhist_get_bandwidth_lines();
smartlist_add(chunks, contents);
}
/* geoip hashes aren't useful unless we are publishing other stats */
diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h
index 50790a73dd..f71ada8eb7 100644
--- a/src/feature/relay/router.h
+++ b/src/feature/relay/router.h
@@ -65,14 +65,13 @@ int init_keys_client(void);
uint16_t router_get_active_listener_port_by_type_af(int listener_type,
sa_family_t family);
-uint16_t router_get_advertised_or_port(const or_options_t *options);
-void router_get_advertised_ipv6_or_ap(const or_options_t *options,
+void routerconf_find_ipv6_or_ap(const or_options_t *options,
tor_addr_port_t *ipv6_ap_out);
-bool router_has_advertised_ipv6_orport(const or_options_t *options);
+bool routerconf_has_ipv6_orport(const or_options_t *options);
MOCK_DECL(bool, router_can_extend_over_ipv6,(const or_options_t *options));
-uint16_t router_get_advertised_or_port_by_af(const or_options_t *options,
- sa_family_t family);
-uint16_t router_get_advertised_dir_port(const or_options_t *options,
+uint16_t routerconf_find_or_port(const or_options_t *options,
+ sa_family_t family);
+uint16_t routerconf_find_dir_port(const or_options_t *options,
uint16_t dirport);
int router_should_advertise_dirport(const or_options_t *options,
@@ -81,9 +80,12 @@ int router_should_advertise_dirport(const or_options_t *options,
void consider_publishable_server(int force);
int should_refuse_unknown_exits(const or_options_t *options);
+void router_new_consensus_params(const networkstatus_t *);
void router_upload_dir_desc_to_dirservers(int force);
void mark_my_descriptor_dirty_if_too_old(time_t now);
void mark_my_descriptor_dirty(const char *reason);
+void mark_my_descriptor_if_omit_ipv6_changes(const char *reason,
+ bool omit_ipv6);
void check_descriptor_bandwidth_changed(time_t now);
void check_descriptor_ipaddress_changed(time_t now);
int router_has_bandwidth_to_be_dirserver(const or_options_t *options);
@@ -98,6 +100,7 @@ int router_digest_is_me(const char *digest);
const uint8_t *router_get_my_id_digest(void);
int router_extrainfo_digest_is_me(const char *digest);
int router_is_me(const routerinfo_t *router);
+bool router_addr_is_my_published_addr(const tor_addr_t *addr);
int router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e);
int router_rebuild_descriptor(int force);
char *router_dump_router_to_string(routerinfo_t *router,
@@ -124,7 +127,7 @@ void router_free_all(void);
#ifdef ROUTER_PRIVATE
/* Used only by router.c and the unit tests */
STATIC void get_platform_str(char *platform, size_t len);
-STATIC int router_write_fingerprint(int hashed);
+STATIC int router_write_fingerprint(int hashed, int ed25519_identity);
STATIC smartlist_t *get_my_declared_family(const or_options_t *options);
#ifdef TOR_UNIT_TESTS
diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c
index d3de83cb86..116f0b4e3d 100644
--- a/src/feature/relay/routerkeys.c
+++ b/src/feature/relay/routerkeys.c
@@ -387,12 +387,10 @@ generate_ed_link_cert(const or_options_t *options, time_t now,
return 0;
}
- ed25519_public_key_t dummy_key;
- memcpy(dummy_key.pubkey, digests->d[DIGEST_SHA256], DIGEST256_LEN);
-
- link_cert = tor_cert_create(get_master_signing_keypair(),
+ link_cert = tor_cert_create_raw(get_master_signing_keypair(),
CERT_TYPE_SIGNING_LINK,
- &dummy_key,
+ SIGNED_KEY_TYPE_SHA256_OF_X509,
+ (const uint8_t*)digests->d[DIGEST_SHA256],
now,
options->TestingLinkCertLifetime, 0);
@@ -466,7 +464,7 @@ init_mock_ed_keys(const crypto_pk_t *rsa_identity_key)
MAKEKEY(master_signing_key);
MAKEKEY(current_auth_key);
#define MAKECERT(cert, signing, signed_, type, flags) \
- cert = tor_cert_create(signing, \
+ cert = tor_cert_create_ed25519(signing, \
type, \
&signed_->pubkey, \
time(NULL), 86400, \
@@ -519,19 +517,33 @@ print_cert_expiration(const char *expiration,
/**
* Log when a certificate, <b>cert</b>, with some <b>description</b> and
- * stored in a file named <b>fname</b>, is going to expire.
+ * stored in a file named <b>fname</b>, is going to expire. Formats the expire
+ * time according to <b>time_format</b>.
*/
static void
log_ed_cert_expiration(const tor_cert_t *cert,
const char *description,
- const char *fname) {
- char expiration[ISO_TIME_LEN+1];
-
+ const char *fname,
+ key_expiration_format_t time_format) {
if (BUG(!cert)) { /* If the specified key hasn't been loaded */
log_warn(LD_OR, "No %s key loaded; can't get certificate expiration.",
description);
} else {
- format_local_iso_time(expiration, cert->valid_until);
+ char expiration[ISO_TIME_LEN+1];
+ switch (time_format) {
+ case KEY_EXPIRATION_FORMAT_ISO8601:
+ format_local_iso_time(expiration, cert->valid_until);
+ break;
+
+ case KEY_EXPIRATION_FORMAT_TIMESTAMP:
+ tor_snprintf(expiration, sizeof(expiration), "%"PRId64,
+ (int64_t) cert->valid_until);
+ break;
+
+ default:
+ log_err(LD_BUG, "Unknown time format value: %d.", time_format);
+ return;
+ }
log_notice(LD_OR, "The %s certificate stored in %s is valid until %s.",
description, fname, expiration);
print_cert_expiration(expiration, description);
@@ -567,7 +579,8 @@ log_master_signing_key_cert_expiration(const or_options_t *options)
/* If we do have a signing key, log the expiration time. */
if (signing_key) {
- log_ed_cert_expiration(signing_key, "signing", fn);
+ key_expiration_format_t time_format = options->key_expiration_format;
+ log_ed_cert_expiration(signing_key, "signing", fn, time_format);
} else {
log_warn(LD_OR, "Could not load signing key certificate from %s, so " \
"we couldn't learn anything about certificate expiration.", fn);
@@ -684,8 +697,8 @@ make_ntor_onion_key_crosscert(const curve25519_keypair_t *onion_key,
onion_key) < 0)
goto end;
- cert = tor_cert_create(&ed_onion_key, CERT_TYPE_ONION_ID, master_id_key,
- now, lifetime, 0);
+ cert = tor_cert_create_ed25519(&ed_onion_key, CERT_TYPE_ONION_ID,
+ master_id_key, now, lifetime, 0);
end:
memwipe(&ed_onion_key, 0, sizeof(ed_onion_key));
diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c
index 18fe25b989..87ba29c130 100644
--- a/src/feature/relay/selftest.c
+++ b/src/feature/relay/selftest.c
@@ -15,38 +15,66 @@
#include "core/or/or.h"
#include "app/config/config.h"
+
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
#include "core/mainloop/netstatus.h"
+
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/crypt_path_st.h"
+#include "core/or/extendinfo.h"
+#include "core/or/extend_info_st.h"
#include "core/or/origin_circuit_st.h"
#include "core/or/relay.h"
+
#include "feature/control/control_events.h"
+
#include "feature/dirclient/dirclient.h"
#include "feature/dircommon/directory.h"
+
#include "feature/nodelist/authority_cert_st.h"
#include "feature/nodelist/routerinfo.h"
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerlist.h" // but...
#include "feature/nodelist/routerset.h"
#include "feature/nodelist/torcert.h"
+
#include "feature/relay/relay_periodic.h"
#include "feature/relay/router.h"
#include "feature/relay/selftest.h"
-/** Whether we can reach our ORPort from the outside. */
-static int can_reach_or_port = 0;
+static bool have_orport_for_family(int family);
+static void inform_testing_reachability(const tor_addr_t *addr,
+ uint16_t port,
+ bool is_dirport);
+
+/** Whether we can reach our IPv4 ORPort from the outside. */
+static bool can_reach_or_port_ipv4 = false;
+/** Whether we can reach our IPv6 ORPort from the outside. */
+static bool can_reach_or_port_ipv6 = false;
/** Whether we can reach our DirPort from the outside. */
-static int can_reach_dir_port = 0;
+static bool can_reach_dir_port = false;
+
+/** Has informed_testing_reachable logged a message about testing our IPv4
+ * ORPort? */
+static bool have_informed_testing_or_port_ipv4 = false;
+/** Has informed_testing_reachable logged a message about testing our IPv6
+ * ORPort? */
+static bool have_informed_testing_or_port_ipv6 = false;
+/** Has informed_testing_reachable logged a message about testing our
+ * DirPort? */
+static bool have_informed_testing_dir_port = false;
/** Forget what we have learned about our reachability status. */
void
router_reset_reachability(void)
{
- can_reach_or_port = can_reach_dir_port = 0;
+ can_reach_or_port_ipv4 = can_reach_or_port_ipv6 = can_reach_dir_port = false;
+ have_informed_testing_or_port_ipv4 =
+ have_informed_testing_or_port_ipv6 =
+ have_informed_testing_dir_port = false;
}
/** Return 1 if we won't do reachability checks, because:
@@ -68,13 +96,43 @@ router_reachability_checks_disabled(const or_options_t *options)
* - we've seen a successful reachability check, or
* - AssumeReachable is set, or
* - the network is disabled.
+
+ * If `family'`is AF_INET or AF_INET6, return true only when we should skip
+ * the given family's orport check (Because it's been checked, or because we
+ * aren't checking it.) If `family` is 0, return true if we can skip _all_
+ * orport checks.
*/
int
-check_whether_orport_reachable(const or_options_t *options)
+router_orport_seems_reachable(const or_options_t *options,
+ int family)
{
+ tor_assert_nonfatal(family == AF_INET || family == AF_INET6 || family == 0);
int reach_checks_disabled = router_reachability_checks_disabled(options);
- return reach_checks_disabled ||
- can_reach_or_port;
+ if (reach_checks_disabled) {
+ return true;
+ }
+
+ // Note that we do a == 1 here, not just a boolean check. This value
+ // is also an autobool, so CFG_AUTO does not mean that we should
+ // assume IPv6 ports are reachable.
+ const bool ipv6_assume_reachable = (options->AssumeReachableIPv6 == 1);
+
+ // Which reachability flags should we look at?
+ const bool checking_ipv4 = (family == AF_INET || family == 0);
+ const bool checking_ipv6 = (family == AF_INET6 || family == 0);
+
+ if (checking_ipv4) {
+ if (have_orport_for_family(AF_INET) && !can_reach_or_port_ipv4) {
+ return false;
+ }
+ }
+ if (checking_ipv6 && !ipv6_assume_reachable) {
+ if (have_orport_for_family(AF_INET6) && !can_reach_or_port_ipv6) {
+ return false;
+ }
+ }
+
+ return true;
}
/** Return 0 if we need to do a DirPort reachability check, because:
@@ -87,7 +145,7 @@ check_whether_orport_reachable(const or_options_t *options)
* - the network is disabled.
*/
int
-check_whether_dirport_reachable(const or_options_t *options)
+router_dirport_seems_reachable(const or_options_t *options)
{
int reach_checks_disabled = router_reachability_checks_disabled(options) ||
!options->DirPort_set;
@@ -107,6 +165,7 @@ router_should_check_reachability(int test_or, int test_dir)
if (!me)
return 0;
+ /* Doesn't check our IPv6 address, see #34065. */
if (routerset_contains_router(options->ExcludeNodes, me, -1) &&
options->StrictNodes) {
/* If we've excluded ourself, and StrictNodes is set, we can't test
@@ -125,19 +184,51 @@ router_should_check_reachability(int test_or, int test_dir)
return 1;
}
+/**
+ * Return true if we have configured an ORPort for the given family that
+ * we would like to advertise.
+ *
+ * Like other self-testing functions, this function looks at our most
+ * recently built descriptor.
+ **/
+static bool
+have_orport_for_family(int family)
+{
+ const routerinfo_t *me = router_get_my_routerinfo();
+
+ if (!me)
+ return false;
+
+ tor_addr_port_t ap;
+ if (router_get_orport(me, &ap, family) < 0) {
+ return false;
+ }
+ return true;
+}
+
/** Allocate and return a new extend_info_t that can be used to build
- * a circuit to or through the router <b>r</b>. Uses the primary
- * address of the router, so should only be called on a server. */
+ * a circuit to or through the router <b>r</b>, using an address from
+ * <b>family</b> (if available).
+ *
+ * Clients don't have routerinfos, so this function should only be called on a
+ * server.
+ *
+ * If the requested address is not available, returns NULL. */
static extend_info_t *
-extend_info_from_router(const routerinfo_t *r)
+extend_info_from_router(const routerinfo_t *r, int family)
{
crypto_pk_t *rsa_pubkey;
extend_info_t *info;
tor_addr_port_t ap;
- tor_assert(r);
- /* Make sure we don't need to check address reachability */
- tor_assert_nonfatal(router_skip_or_reachability(get_options(), 0));
+ if (BUG(!r)) {
+ return NULL;
+ }
+
+ /* Relays always assume that the first hop is reachable. They ignore
+ * ReachableAddresses. */
+ tor_assert_nonfatal(router_or_conn_should_skip_reachable_address_check(
+ get_options(), 0));
const ed25519_public_key_t *ed_id_key;
if (r->cache_info.signing_key_cert)
@@ -145,7 +236,10 @@ extend_info_from_router(const routerinfo_t *r)
else
ed_id_key = NULL;
- router_get_prim_orport(r, &ap);
+ if (router_get_orport(r, &ap, family) < 0) {
+ /* We don't have an ORPort for the requested family. */
+ return NULL;
+ }
rsa_pubkey = router_get_rsa_onion_pkey(r->onion_pkey, r->onion_pkey_len);
info = extend_info_new(r->nickname, r->cache_info.identity_digest,
ed_id_key,
@@ -155,6 +249,75 @@ extend_info_from_router(const routerinfo_t *r)
return info;
}
+/** Launch a self-testing circuit to one of our ORPorts, using an address from
+ * <b>family</b> (if available). The circuit can be used to test reachability
+ * or bandwidth. <b>me</b> is our own routerinfo.
+ *
+ * Logs an info-level status message. If <b>orport_reachable</b> is false,
+ * call it a reachability circuit. Otherwise, call it a bandwidth circuit.
+ *
+ * See router_do_reachability_checks() for details. */
+static void
+router_do_orport_reachability_checks(const routerinfo_t *me,
+ int family,
+ int orport_reachable)
+{
+ extend_info_t *ei = extend_info_from_router(me, family);
+ int ipv6_flags = (family == AF_INET6 ? CIRCLAUNCH_IS_IPV6_SELFTEST : 0);
+
+ /* If we're trying to test IPv6, but we don't have an IPv6 ORPort, ei will
+ * be NULL. */
+ if (ei) {
+ const char *family_name = fmt_af_family(family);
+ const tor_addr_port_t *ap = extend_info_get_orport(ei, family);
+ log_info(LD_CIRC, "Testing %s of my %s ORPort: %s.",
+ !orport_reachable ? "reachability" : "bandwidth",
+ family_name, fmt_addrport_ap(ap));
+
+ inform_testing_reachability(&ap->addr, ap->port, false);
+
+ circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
+ CIRCLAUNCH_NEED_CAPACITY|
+ CIRCLAUNCH_IS_INTERNAL|
+ ipv6_flags);
+ extend_info_free(ei);
+ }
+}
+
+/** Launch a self-testing circuit, and ask an exit to connect to our DirPort.
+ * <b>me</b> is our own routerinfo.
+ *
+ * Relays don't advertise IPv6 DirPorts, so this function only supports IPv4.
+ *
+ * See router_do_reachability_checks() for details. */
+static void
+router_do_dirport_reachability_checks(const routerinfo_t *me)
+{
+ tor_addr_port_t my_dirport;
+ tor_addr_copy(&my_dirport.addr, &me->ipv4_addr);
+ my_dirport.port = me->ipv4_dirport;
+
+ /* If there is already a pending connection, don't open another one. */
+ if (!connection_get_by_type_addr_port_purpose(
+ CONN_TYPE_DIR,
+ &my_dirport.addr, my_dirport.port,
+ DIR_PURPOSE_FETCH_SERVERDESC)) {
+ /* ask myself, via tor, for my server descriptor. */
+ directory_request_t *req =
+ directory_request_new(DIR_PURPOSE_FETCH_SERVERDESC);
+ directory_request_set_dir_addr_port(req, &my_dirport);
+ directory_request_set_directory_id_digest(req,
+ me->cache_info.identity_digest);
+ /* ask via an anon circuit, connecting to our dirport. */
+ directory_request_set_indirection(req, DIRIND_ANON_DIRPORT);
+ directory_request_set_resource(req, "authority.z");
+ directory_initiate_request(req);
+ directory_request_free(req);
+
+ inform_testing_reachability(&my_dirport.addr, my_dirport.port, true);
+ }
+}
+
/** Some time has passed, or we just got new directory information.
* See if we currently believe our ORPort or DirPort to be
* unreachable. If so, launch a new test for it.
@@ -171,113 +334,140 @@ router_do_reachability_checks(int test_or, int test_dir)
{
const routerinfo_t *me = router_get_my_routerinfo();
const or_options_t *options = get_options();
- int orport_reachable = check_whether_orport_reachable(options);
- tor_addr_t addr;
+ int orport_reachable_v4 =
+ router_orport_seems_reachable(options, AF_INET);
+ int orport_reachable_v6 =
+ router_orport_seems_reachable(options, AF_INET6);
if (router_should_check_reachability(test_or, test_dir)) {
- if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) {
- extend_info_t *ei = extend_info_from_router(me);
- /* XXX IPv6 self testing */
- log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.",
- !orport_reachable ? "reachability" : "bandwidth",
- fmt_addr32(me->addr), me->or_port);
- circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
- CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL);
- extend_info_free(ei);
+ bool need_testing = !circuit_enough_testing_circs();
+ /* At the moment, tor relays believe that they are reachable when they
+ * receive any create cell on an inbound connection, if the address
+ * family is correct.
+ */
+ if (test_or && (!orport_reachable_v4 || need_testing)) {
+ router_do_orport_reachability_checks(me, AF_INET, orport_reachable_v4);
+ }
+ if (test_or && (!orport_reachable_v6 || need_testing)) {
+ router_do_orport_reachability_checks(me, AF_INET6, orport_reachable_v6);
}
- /* XXX IPv6 self testing */
- tor_addr_from_ipv4h(&addr, me->addr);
- if (test_dir && !check_whether_dirport_reachable(options) &&
- !connection_get_by_type_addr_port_purpose(
- CONN_TYPE_DIR, &addr, me->dir_port,
- DIR_PURPOSE_FETCH_SERVERDESC)) {
- tor_addr_port_t my_orport, my_dirport;
- memcpy(&my_orport.addr, &addr, sizeof(addr));
- memcpy(&my_dirport.addr, &addr, sizeof(addr));
- my_orport.port = me->or_port;
- my_dirport.port = me->dir_port;
- /* ask myself, via tor, for my server descriptor. */
- directory_request_t *req =
- directory_request_new(DIR_PURPOSE_FETCH_SERVERDESC);
- directory_request_set_or_addr_port(req, &my_orport);
- directory_request_set_dir_addr_port(req, &my_dirport);
- directory_request_set_directory_id_digest(req,
- me->cache_info.identity_digest);
- // ask via an anon circuit, connecting to our dirport.
- directory_request_set_indirection(req, DIRIND_ANON_DIRPORT);
- directory_request_set_resource(req, "authority.z");
- directory_initiate_request(req);
- directory_request_free(req);
+ if (test_dir && !router_dirport_seems_reachable(options)) {
+ router_do_dirport_reachability_checks(me);
}
}
}
-/** We've decided to start our reachability testing. If all
- * is set, log this to the user. Return 1 if we did, or 0 if
- * we chose not to log anything. */
-int
-inform_testing_reachability(void)
+/** Log a message informing the user that we are testing a port for
+ * reachability, if we have not already logged such a message.
+ *
+ * If @a is_dirport is true, then the port is a DirPort; otherwise it is an
+ * ORPort.
+ *
+ * Calls to router_reset_reachability() will reset our view of whether we have
+ * logged this message for a given port. */
+static void
+inform_testing_reachability(const tor_addr_t *addr,
+ uint16_t port,
+ bool is_dirport)
{
- char dirbuf[128];
- char *address;
- const routerinfo_t *me = router_get_my_routerinfo();
- if (!me)
- return 0;
+ if (!router_get_my_routerinfo())
+ return;
- address = tor_dup_ip(me->addr);
- if (!address)
- return 0;
+ bool *have_informed_ptr;
+ if (is_dirport) {
+ have_informed_ptr = &have_informed_testing_dir_port;
+ } else if (tor_addr_family(addr) == AF_INET) {
+ have_informed_ptr = &have_informed_testing_or_port_ipv4;
+ } else {
+ have_informed_ptr = &have_informed_testing_or_port_ipv6;
+ }
- control_event_server_status(LOG_NOTICE,
- "CHECKING_REACHABILITY ORADDRESS=%s:%d",
- address, me->or_port);
- if (me->dir_port) {
- tor_snprintf(dirbuf, sizeof(dirbuf), " and DirPort %s:%d",
- address, me->dir_port);
- control_event_server_status(LOG_NOTICE,
- "CHECKING_REACHABILITY DIRADDRESS=%s:%d",
- address, me->dir_port);
+ if (*have_informed_ptr) {
+ /* We already told the user that we're testing this port; no need to
+ * do it again. */
+ return;
}
- log_notice(LD_OR, "Now checking whether ORPort %s:%d%s %s reachable... "
- "(this may take up to %d minutes -- look for log "
- "messages indicating success)",
- address, me->or_port,
- me->dir_port ? dirbuf : "",
- me->dir_port ? "are" : "is",
- TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
-
- tor_free(address);
- return 1;
+
+ char addr_buf[TOR_ADDRPORT_BUF_LEN];
+ strlcpy(addr_buf, fmt_addrport(addr, port), sizeof(addr_buf));
+
+ const char *control_addr_type = is_dirport ? "DIRADDRESS" : "ORADDRESS";
+ const char *port_type = is_dirport ? "DirPort" : "ORPort";
+ const char *afname = fmt_af_family(tor_addr_family(addr));
+
+ control_event_server_status(LOG_NOTICE,
+ "CHECKING_REACHABILITY %s=%s",
+ control_addr_type, addr_buf);
+
+ log_notice(LD_OR, "Now checking whether %s %s %s is reachable... "
+ "(this may take up to %d minutes -- look for log "
+ "messages indicating success)",
+ afname, port_type, addr_buf,
+ TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
+
+ *have_informed_ptr = true;
+}
+
+/**
+ * Return true if this module knows of no reason why we shouldn't publish
+ * a server descriptor.
+ **/
+static bool
+ready_to_publish(const or_options_t *options)
+{
+ return options->PublishServerDescriptor_ != NO_DIRINFO &&
+ router_dirport_seems_reachable(options) &&
+ router_all_orports_seem_reachable(options);
}
-/** Annotate that we found our ORPort reachable. */
+/** Annotate that we found our ORPort reachable with a given address
+ * family. */
void
-router_orport_found_reachable(void)
+router_orport_found_reachable(int family)
{
const routerinfo_t *me = router_get_my_routerinfo();
const or_options_t *options = get_options();
- if (!can_reach_or_port && me) {
- char *address = tor_dup_ip(me->addr);
-
- if (!address)
+ const char *reachable_reason = "ORPort found reachable";
+ bool *can_reach_ptr;
+ if (family == AF_INET) {
+ can_reach_ptr = &can_reach_or_port_ipv4;
+ } else if (family == AF_INET6) {
+ can_reach_ptr = &can_reach_or_port_ipv6;
+ } else {
+ tor_assert_nonfatal_unreached();
+ return;
+ }
+ if (!*can_reach_ptr && me) {
+ tor_addr_port_t ap;
+ if (router_get_orport(me, &ap, family) < 0) {
return;
+ }
+ char *address = tor_strdup(fmt_addrport_ap(&ap));
+
+ *can_reach_ptr = true;
- log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
+ log_notice(LD_OR,"Self-testing indicates your ORPort %s is reachable from "
"the outside. Excellent.%s",
- options->PublishServerDescriptor_ != NO_DIRINFO
- && check_whether_dirport_reachable(options) ?
- " Publishing server descriptor." : "");
- can_reach_or_port = 1;
- mark_my_descriptor_dirty("ORPort found reachable");
+ address,
+ ready_to_publish(options) ?
+ " Publishing server descriptor." : "");
+
+ /* Make sure our descriptor is marked to publish the IPv6 if it is now
+ * reachable. This can change at runtime. */
+ if (family == AF_INET6) {
+ mark_my_descriptor_if_omit_ipv6_changes(reachable_reason, false);
+ } else {
+ mark_my_descriptor_dirty(reachable_reason);
+ }
/* This is a significant enough change to upload immediately,
* at least in a test network */
if (options->TestingTorNetwork == 1) {
reschedule_descriptor_update_check();
}
control_event_server_status(LOG_NOTICE,
- "REACHABILITY_SUCCEEDED ORADDRESS=%s:%d",
- address, me->or_port);
+ "REACHABILITY_SUCCEEDED ORADDRESS=%s",
+ address);
tor_free(address);
}
}
@@ -288,19 +478,20 @@ router_dirport_found_reachable(void)
{
const routerinfo_t *me = router_get_my_routerinfo();
const or_options_t *options = get_options();
+
if (!can_reach_dir_port && me) {
- char *address = tor_dup_ip(me->addr);
+ char *address = tor_addr_to_str_dup(&me->ipv4_addr);
if (!address)
return;
+ can_reach_dir_port = true;
log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
"from the outside. Excellent.%s",
- options->PublishServerDescriptor_ != NO_DIRINFO
- && check_whether_orport_reachable(options) ?
+ ready_to_publish(options) ?
" Publishing server descriptor." : "");
- can_reach_dir_port = 1;
- if (router_should_advertise_dirport(options, me->dir_port)) {
+
+ if (router_should_advertise_dirport(options, me->ipv4_dirport)) {
mark_my_descriptor_dirty("DirPort found reachable");
/* This is a significant enough change to upload immediately,
* at least in a test network */
@@ -310,13 +501,15 @@ router_dirport_found_reachable(void)
}
control_event_server_status(LOG_NOTICE,
"REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d",
- address, me->dir_port);
+ address, me->ipv4_dirport);
tor_free(address);
}
}
/** We have enough testing circuits open. Send a bunch of "drop"
- * cells down each of them, to exercise our bandwidth. */
+ * cells down each of them, to exercise our bandwidth.
+ *
+ * May use IPv4 and IPv6 testing circuits (if available). */
void
router_perform_bandwidth_test(int num_circs, time_t now)
{
diff --git a/src/feature/relay/selftest.h b/src/feature/relay/selftest.h
index f5babc95da..e09c0e7898 100644
--- a/src/feature/relay/selftest.h
+++ b/src/feature/relay/selftest.h
@@ -15,23 +15,29 @@
#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);
+#define router_all_orports_seem_reachable(opts) \
+ router_orport_seems_reachable((opts),0)
+int router_orport_seems_reachable(
+ const struct or_options_t *options,
+ int family);
+int router_dirport_seems_reachable(
+ const struct or_options_t *options);
void router_do_reachability_checks(int test_or, int test_dir);
void router_perform_bandwidth_test(int num_circs, time_t now);
-int inform_testing_reachability(void);
-void router_orport_found_reachable(void);
+void router_orport_found_reachable(int family);
void router_dirport_found_reachable(void);
void router_reset_reachability(void);
#else /* !defined(HAVE_MODULE_RELAY) */
-#define check_whether_orport_reachable(opts) \
+#define router_all_orports_seem_reachable(opts) \
((void)(opts), 0)
-#define check_whether_dirport_reachable(opts) \
+#define router_orport_seems_reachable(opts, fam) \
+ ((void)(opts), (void)(fam), 0)
+#define router_dirport_seems_reachable(opts) \
((void)(opts), 0)
static inline void
diff --git a/src/feature/rend/rendcache.c b/src/feature/rend/rendcache.c
index 0890a81d8f..53fec7532f 100644
--- a/src/feature/rend/rendcache.c
+++ b/src/feature/rend/rendcache.c
@@ -340,8 +340,9 @@ rend_cache_failure_purge(void)
/** Lookup the rend failure cache using a relay identity digest in
* <b>identity</b> which has DIGEST_LEN bytes and service ID <b>service_id</b>
- * which is a null-terminated string. If found, the intro failure is set in
- * <b>intro_entry</b> else it stays untouched. Return 1 iff found else 0. */
+ * which is a null-terminated string. If @a intro_entry is provided, then it
+ * is set to the entry on success, and to NULL on failure.
+ * Return 1 iff found else 0. */
STATIC int
cache_failure_intro_lookup(const uint8_t *identity, const char *service_id,
rend_cache_failure_intro_t **intro_entry)
diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c
index d33b61851f..8d3ed1ad03 100644
--- a/src/feature/rend/rendclient.c
+++ b/src/feature/rend/rendclient.c
@@ -15,6 +15,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/connection_edge.h"
+#include "core/or/extendinfo.h"
#include "core/or/relay.h"
#include "feature/client/circpathbias.h"
#include "feature/control/control_events.h"
@@ -234,9 +235,15 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
/* version 2 format */
extend_info_t *extend_info = rendcirc->build_state->chosen_exit;
int klen;
+ const tor_addr_port_t *orport =
+ extend_info_get_orport(extend_info, AF_INET);
+ IF_BUG_ONCE(! orport) {
+ /* we should never put an IPv6 address here. */
+ goto perm_err;
+ }
/* nul pads */
- set_uint32(tmp+v3_shift+1, tor_addr_to_ipv4n(&extend_info->addr));
- set_uint16(tmp+v3_shift+5, htons(extend_info->port));
+ set_uint32(tmp+v3_shift+1, tor_addr_to_ipv4n(&orport->addr));
+ set_uint16(tmp+v3_shift+5, htons(orport->port));
memcpy(tmp+v3_shift+7, extend_info->identity_digest, DIGEST_LEN);
klen = crypto_pk_asn1_encode(extend_info->onion_key,
tmp+v3_shift+7+DIGEST_LEN+2,
diff --git a/src/feature/rend/rendcommon.c b/src/feature/rend/rendcommon.c
index 5d04755819..775d487805 100644
--- a/src/feature/rend/rendcommon.c
+++ b/src/feature/rend/rendcommon.c
@@ -14,6 +14,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
+#include "core/or/extendinfo.h"
#include "app/config/config.h"
#include "feature/control/control_events.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -233,7 +234,12 @@ rend_encode_v2_intro_points(char **encoded, rend_service_descriptor_t *desc)
goto done;
}
/* Assemble everything for this introduction point. */
- address = tor_addr_to_str_dup(&info->addr);
+ const tor_addr_port_t *orport = extend_info_get_orport(info, AF_INET);
+ IF_BUG_ONCE(!orport) {
+ /* There must be an IPv4 address for v2 hs. */
+ goto done;
+ }
+ address = tor_addr_to_str_dup(&orport->addr);
res = tor_snprintf(unenc + unenc_written, unenc_len - unenc_written,
"introduction-point %s\n"
"ip-address %s\n"
@@ -242,7 +248,7 @@ rend_encode_v2_intro_points(char **encoded, rend_service_descriptor_t *desc)
"service-key\n%s",
id_base32,
address,
- info->port,
+ orport->port,
onion_key,
service_key);
tor_free(address);
diff --git a/src/feature/rend/rendparse.c b/src/feature/rend/rendparse.c
index 0979d767a7..c28add5ca9 100644
--- a/src/feature/rend/rendparse.c
+++ b/src/feature/rend/rendparse.c
@@ -10,6 +10,7 @@
**/
#include "core/or/or.h"
+#include "core/or/extendinfo.h"
#include "feature/dirparse/parsecommon.h"
#include "feature/dirparse/sigcommon.h"
#include "feature/rend/rendcommon.h"
@@ -428,7 +429,8 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed,
}
/* Allocate new intro point and extend info. */
intro = tor_malloc_zero(sizeof(rend_intro_point_t));
- info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
+ info = intro->extend_info =
+ extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
/* Parse identifier. */
tok = find_by_keyword(tokens, R_IPO_IDENTIFIER);
if (base32_decode(info->identity_digest, DIGEST_LEN,
@@ -446,12 +448,13 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed,
info->identity_digest, DIGEST_LEN);
/* Parse IP address. */
tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS);
- if (tor_addr_parse(&info->addr, tok->args[0])<0) {
+ tor_addr_t addr;
+ if (tor_addr_parse(&addr, tok->args[0])<0) {
log_warn(LD_REND, "Could not parse introduction point address.");
rend_intro_point_free(intro);
goto err;
}
- if (tor_addr_family(&info->addr) != AF_INET) {
+ if (tor_addr_family(&addr) != AF_INET) {
log_warn(LD_REND, "Introduction point address was not ipv4.");
rend_intro_point_free(intro);
goto err;
@@ -459,14 +462,18 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed,
/* Parse onion port. */
tok = find_by_keyword(tokens, R_IPO_ONION_PORT);
- info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
+ uint16_t port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
&num_ok,NULL);
- if (!info->port || !num_ok) {
+ if (!port || !num_ok) {
log_warn(LD_REND, "Introduction point onion port %s is invalid",
escaped(tok->args[0]));
rend_intro_point_free(intro);
goto err;
}
+
+ /* Add the address and port. */
+ extend_info_add_orport(info, &addr, port);
+
/* Parse onion key. */
tok = find_by_keyword(tokens, R_IPO_ONION_KEY);
if (!crypto_pk_public_exponent_ok(tok->key)) {
diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c
index 83388a72eb..68dd8f4f4a 100644
--- a/src/feature/rend/rendservice.c
+++ b/src/feature/rend/rendservice.c
@@ -16,6 +16,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
+#include "core/or/extendinfo.h"
#include "core/or/policies.h"
#include "core/or/relay.h"
#include "core/or/crypt_path.h"
@@ -1553,7 +1554,7 @@ rend_service_load_keys(rend_service_t *s)
fname = rend_service_path(s, hostname_fname);
tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id);
- if (write_str_to_file(fname,buf,0)<0) {
+ if (write_str_to_file_if_not_equal(fname, buf)) {
log_warn(LD_CONFIG, "Could not write onion address to hostname file.");
goto err;
}
@@ -1848,10 +1849,13 @@ rend_service_use_direct_connection(const or_options_t* options,
const extend_info_t* ei)
{
/* We'll connect directly all reachable addresses, whether preferred or not.
- * The prefer_ipv6 argument to fascist_firewall_allows_address_addr is
+ * The prefer_ipv6 argument to reachable_addr_allows_addr is
* ignored, because pref_only is 0. */
+ const tor_addr_port_t *ap = extend_info_get_orport(ei, AF_INET);
+ if (!ap)
+ return 0;
return (rend_service_allow_non_anonymous_connection(options) &&
- fascist_firewall_allows_address_addr(&ei->addr, ei->port,
+ reachable_addr_allows_addr(&ap->addr, ap->port,
FIREWALL_OR_CONNECTION, 0, 0));
}
@@ -1863,7 +1867,7 @@ rend_service_use_direct_connection_node(const or_options_t* options,
/* We'll connect directly all reachable addresses, whether preferred or not.
*/
return (rend_service_allow_non_anonymous_connection(options) &&
- fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0));
+ reachable_addr_allows_node(node, FIREWALL_OR_CONNECTION, 0));
}
/******
@@ -2280,7 +2284,8 @@ find_rp_for_intro(const rend_intro_cell_t *intro,
/* Make sure the RP we are being asked to connect to is _not_ a private
* address unless it's allowed. Let's avoid to build a circuit to our
* second middle node and fail right after when extending to the RP. */
- if (!extend_info_addr_is_allowed(&rp->addr)) {
+ const tor_addr_port_t *orport = extend_info_get_orport(rp, AF_INET);
+ if (! orport || !extend_info_addr_is_allowed(&orport->addr)) {
if (err_msg_out) {
tor_asprintf(&err_msg,
"Relay IP in INTRODUCE2 cell is private address.");
@@ -2549,9 +2554,11 @@ rend_service_parse_intro_for_v2(
goto err;
}
- extend_info = tor_malloc_zero(sizeof(extend_info_t));
- tor_addr_from_ipv4n(&extend_info->addr, get_uint32(buf + 1));
- extend_info->port = ntohs(get_uint16(buf + 5));
+ extend_info = extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
+ tor_addr_t addr;
+ tor_addr_from_ipv4n(&addr, get_uint32(buf + 1));
+ uint16_t port = ntohs(get_uint16(buf + 5));
+ extend_info_add_orport(extend_info, &addr, port);
memcpy(extend_info->identity_digest, buf + 7, DIGEST_LEN);
extend_info->nickname[0] = '$';
base16_encode(extend_info->nickname + 1, sizeof(extend_info->nickname) - 1,
@@ -3733,7 +3740,7 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
rend_data_free(rend_data);
base32_encode(desc_id_base32, sizeof(desc_id_base32),
desc->desc_id, DIGEST_LEN);
- hs_dir_ip = tor_dup_ip(hs_dir->addr);
+ hs_dir_ip = tor_addr_to_str_dup(&hs_dir->ipv4_addr);
if (hs_dir_ip) {
log_info(LD_REND, "Launching upload for v2 descriptor for "
"service '%s' with descriptor ID '%s' with validity "
@@ -3744,7 +3751,7 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
seconds_valid,
hs_dir->nickname,
hs_dir_ip,
- hs_dir->or_port);
+ hs_dir->ipv4_orport);
tor_free(hs_dir_ip);
}
@@ -3839,6 +3846,9 @@ upload_service_descriptor(rend_service_t *service)
rend_get_service_id(service->desc->pk, serviceid);
if (get_options()->PublishHidServDescriptors) {
/* Post the current descriptors to the hidden service directories. */
+ /* This log message is used by Chutney as part of its bootstrap
+ * detection mechanism. Please don't change without first checking
+ * Chutney. */
log_info(LD_REND, "Launching upload for hidden service %s",
serviceid);
directory_post_to_hs_dir(service->desc, descs, NULL, serviceid,
diff --git a/src/feature/stats/bw_array_st.h b/src/feature/stats/bw_array_st.h
new file mode 100644
index 0000000000..2d05ff0f77
--- /dev/null
+++ b/src/feature/stats/bw_array_st.h
@@ -0,0 +1,57 @@
+/* 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 bw_array_st.h
+ * @brief Declaration for bw_array_t structure and related constants
+ **/
+
+#ifndef TOR_FEATURE_STATS_BW_ARRAY_ST_H
+#define TOR_FEATURE_STATS_BW_ARRAY_ST_H
+
+/** For how many seconds do we keep track of individual per-second bandwidth
+ * totals? */
+#define NUM_SECS_ROLLING_MEASURE 10
+/** How large are the intervals for which we track and report bandwidth use? */
+#define NUM_SECS_BW_SUM_INTERVAL (24*60*60)
+/** How far in the past do we remember and publish bandwidth use? */
+#define NUM_SECS_BW_SUM_IS_VALID (5*24*60*60)
+/** How many bandwidth usage intervals do we remember? (derived) */
+#define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL)
+
+/** Structure to track bandwidth use, and remember the maxima for a given
+ * time period.
+ */
+struct bw_array_t {
+ /** Observation array: Total number of bytes transferred in each of the last
+ * NUM_SECS_ROLLING_MEASURE seconds. This is used as a circular array. */
+ uint64_t obs[NUM_SECS_ROLLING_MEASURE];
+ int cur_obs_idx; /**< Current position in obs. */
+ time_t cur_obs_time; /**< Time represented in obs[cur_obs_idx] */
+ uint64_t total_obs; /**< Total for all members of obs except
+ * obs[cur_obs_idx] */
+ uint64_t max_total; /**< Largest value that total_obs has taken on in the
+ * current period. */
+ uint64_t total_in_period; /**< Total bytes transferred in the current
+ * period. */
+
+ /** When does the next period begin? */
+ time_t next_period;
+ /** Where in 'maxima' should the maximum bandwidth usage for the current
+ * period be stored? */
+ int next_max_idx;
+ /** How many values in maxima/totals have been set ever? */
+ int num_maxes_set;
+ /** Circular array of the maximum
+ * bandwidth-per-NUM_SECS_ROLLING_MEASURE usage for the last
+ * NUM_TOTALS periods */
+ uint64_t maxima[NUM_TOTALS];
+ /** Circular array of the total bandwidth usage for the last NUM_TOTALS
+ * periods */
+ uint64_t totals[NUM_TOTALS];
+};
+
+#endif /* !defined(TOR_FEATURE_STATS_BW_ARRAY_ST_H) */
diff --git a/src/feature/stats/bwhist.c b/src/feature/stats/bwhist.c
new file mode 100644
index 0000000000..7cbc5f60a6
--- /dev/null
+++ b/src/feature/stats/bwhist.c
@@ -0,0 +1,548 @@
+/* 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 bwhist.c
+ * @brief Tracking for relay bandwidth history
+ *
+ * This module handles bandwidth usage history, used by relays to
+ * self-report how much bandwidth they've used for different
+ * purposes over last day or so, in order to generate the
+ * {dirreq-,}{read,write}-history lines in that they publish.
+ **/
+
+#define BWHIST_PRIVATE
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "feature/stats/bwhist.h"
+
+#include "app/config/config.h"
+#include "app/config/statefile.h"
+#include "feature/relay/routermode.h"
+
+#include "feature/stats/bw_array_st.h"
+#include "app/config/or_state_st.h"
+#include "app/config/or_options_st.h"
+
+/** Shift the current period of b forward by one. */
+STATIC void
+commit_max(bw_array_t *b)
+{
+ /* Store total from current period. */
+ b->totals[b->next_max_idx] = b->total_in_period;
+ /* Store maximum from current period. */
+ b->maxima[b->next_max_idx++] = b->max_total;
+ /* Advance next_period and next_max_idx */
+ b->next_period += NUM_SECS_BW_SUM_INTERVAL;
+ if (b->next_max_idx == NUM_TOTALS)
+ b->next_max_idx = 0;
+ if (b->num_maxes_set < NUM_TOTALS)
+ ++b->num_maxes_set;
+ /* Reset max_total. */
+ b->max_total = 0;
+ /* Reset total_in_period. */
+ b->total_in_period = 0;
+}
+
+/** Shift the current observation time of <b>b</b> forward by one second. */
+STATIC void
+advance_obs(bw_array_t *b)
+{
+ int nextidx;
+ uint64_t total;
+
+ /* Calculate the total bandwidth for the last NUM_SECS_ROLLING_MEASURE
+ * seconds; adjust max_total as needed.*/
+ total = b->total_obs + b->obs[b->cur_obs_idx];
+ if (total > b->max_total)
+ b->max_total = total;
+
+ nextidx = b->cur_obs_idx+1;
+ if (nextidx == NUM_SECS_ROLLING_MEASURE)
+ nextidx = 0;
+
+ b->total_obs = total - b->obs[nextidx];
+ b->obs[nextidx]=0;
+ b->cur_obs_idx = nextidx;
+
+ if (++b->cur_obs_time >= b->next_period)
+ commit_max(b);
+}
+
+/** Add <b>n</b> bytes to the number of bytes in <b>b</b> for second
+ * <b>when</b>. */
+STATIC void
+add_obs(bw_array_t *b, time_t when, uint64_t n)
+{
+ if (when < b->cur_obs_time)
+ return; /* Don't record data in the past. */
+
+ /* If we're currently adding observations for an earlier second than
+ * 'when', advance b->cur_obs_time and b->cur_obs_idx by an
+ * appropriate number of seconds, and do all the other housekeeping. */
+ while (when > b->cur_obs_time) {
+ /* Doing this one second at a time is potentially inefficient, if we start
+ with a state file that is very old. Fortunately, it doesn't seem to
+ show up in profiles, so we can just ignore it for now. */
+ advance_obs(b);
+ }
+
+ b->obs[b->cur_obs_idx] += n;
+ b->total_in_period += n;
+}
+
+/** Allocate, initialize, and return a new bw_array. */
+STATIC bw_array_t *
+bw_array_new(void)
+{
+ bw_array_t *b;
+ time_t start;
+ b = tor_malloc_zero(sizeof(bw_array_t));
+ start = time(NULL);
+ b->cur_obs_time = start;
+ b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
+ return b;
+}
+
+/** Free storage held by bandwidth array <b>b</b>. */
+STATIC void
+bw_array_free_(bw_array_t *b)
+{
+ if (!b) {
+ return;
+ }
+
+ tor_free(b);
+}
+
+/** Recent history of bandwidth observations for (all) read operations. */
+static bw_array_t *read_array = NULL;
+/** Recent history of bandwidth observations for IPv6 read operations. */
+static bw_array_t *read_array_ipv6 = NULL;
+/** Recent history of bandwidth observations for (all) write operations. */
+STATIC bw_array_t *write_array = NULL;
+/** Recent history of bandwidth observations for IPv6 write operations. */
+static bw_array_t *write_array_ipv6 = NULL;
+/** Recent history of bandwidth observations for read operations for the
+ directory protocol. */
+static bw_array_t *dir_read_array = NULL;
+/** Recent history of bandwidth observations for write operations for the
+ directory protocol. */
+static bw_array_t *dir_write_array = NULL;
+
+/** Set up structures for bandwidth history, clearing them if they already
+ * exist. */
+void
+bwhist_init(void)
+{
+ bw_array_free(read_array);
+ bw_array_free(read_array_ipv6);
+ bw_array_free(write_array);
+ bw_array_free(write_array_ipv6);
+ bw_array_free(dir_read_array);
+ bw_array_free(dir_write_array);
+
+ read_array = bw_array_new();
+ read_array_ipv6 = bw_array_new();
+ write_array = bw_array_new();
+ write_array_ipv6 = bw_array_new();
+ dir_read_array = bw_array_new();
+ dir_write_array = bw_array_new();
+}
+
+/** Remember that we read <b>num_bytes</b> bytes in second <b>when</b>.
+ *
+ * Add num_bytes to the current running total for <b>when</b>.
+ *
+ * <b>when</b> can go back to time, but it's safe to ignore calls
+ * earlier than the latest <b>when</b> you've heard of.
+ */
+void
+bwhist_note_bytes_written(uint64_t num_bytes, time_t when, bool ipv6)
+{
+/* Maybe a circular array for recent seconds, and step to a new point
+ * every time a new second shows up. Or simpler is to just to have
+ * a normal array and push down each item every second; it's short.
+ */
+/* When a new second has rolled over, compute the sum of the bytes we've
+ * seen over when-1 to when-1-NUM_SECS_ROLLING_MEASURE, and stick it
+ * somewhere. See bwhist_bandwidth_assess() below.
+ */
+ add_obs(write_array, when, num_bytes);
+ if (ipv6)
+ add_obs(write_array_ipv6, when, num_bytes);
+}
+
+/** Remember that we wrote <b>num_bytes</b> bytes in second <b>when</b>.
+ * (like bwhist_note_bytes_written() above)
+ */
+void
+bwhist_note_bytes_read(uint64_t num_bytes, time_t when, bool ipv6)
+{
+/* if we're smart, we can make this func and the one above share code */
+ add_obs(read_array, when, num_bytes);
+ if (ipv6)
+ add_obs(read_array_ipv6, when, num_bytes);
+}
+
+/** Remember that we wrote <b>num_bytes</b> directory bytes in second
+ * <b>when</b>. (like bwhist_note_bytes_written() above)
+ */
+void
+bwhist_note_dir_bytes_written(uint64_t num_bytes, time_t when)
+{
+ add_obs(dir_write_array, when, num_bytes);
+}
+
+/** Remember that we read <b>num_bytes</b> directory bytes in second
+ * <b>when</b>. (like bwhist_note_bytes_written() above)
+ */
+void
+bwhist_note_dir_bytes_read(uint64_t num_bytes, time_t when)
+{
+ add_obs(dir_read_array, when, num_bytes);
+}
+
+/** Helper: Return the largest value in b->maxima. (This is equal to the
+ * most bandwidth used in any NUM_SECS_ROLLING_MEASURE period for the last
+ * NUM_SECS_BW_SUM_IS_VALID seconds.)
+ */
+STATIC uint64_t
+find_largest_max(bw_array_t *b)
+{
+ int i;
+ uint64_t max;
+ max=0;
+ for (i=0; i<NUM_TOTALS; ++i) {
+ if (b->maxima[i]>max)
+ max = b->maxima[i];
+ }
+ return max;
+}
+
+/** Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly)
+ * seconds. Find one sum for reading and one for writing. They don't have
+ * to be at the same time.
+ *
+ * Return the smaller of these sums, divided by NUM_SECS_ROLLING_MEASURE.
+ */
+MOCK_IMPL(int,
+bwhist_bandwidth_assess,(void))
+{
+ uint64_t w,r;
+ r = find_largest_max(read_array);
+ w = find_largest_max(write_array);
+ if (r>w)
+ return (int)(((double)w)/NUM_SECS_ROLLING_MEASURE);
+ else
+ return (int)(((double)r)/NUM_SECS_ROLLING_MEASURE);
+}
+
+/** Print the bandwidth history of b (either [dir-]read_array or
+ * [dir-]write_array) into the buffer pointed to by buf. The format is
+ * simply comma separated numbers, from oldest to newest.
+ *
+ * It returns the number of bytes written.
+ */
+STATIC size_t
+bwhist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b)
+{
+ char *cp = buf;
+ int i, n;
+ const or_options_t *options = get_options();
+ uint64_t cutoff;
+
+ if (b->num_maxes_set <= b->next_max_idx) {
+ /* We haven't been through the circular array yet; time starts at i=0.*/
+ i = 0;
+ } else {
+ /* We've been around the array at least once. The next i to be
+ overwritten is the oldest. */
+ i = b->next_max_idx;
+ }
+
+ if (options->RelayBandwidthRate) {
+ /* We don't want to report that we used more bandwidth than the max we're
+ * willing to relay; otherwise everybody will know how much traffic
+ * we used ourself. */
+ cutoff = options->RelayBandwidthRate * NUM_SECS_BW_SUM_INTERVAL;
+ } else {
+ cutoff = UINT64_MAX;
+ }
+
+ for (n=0; n<b->num_maxes_set; ++n,++i) {
+ uint64_t total;
+ if (i >= NUM_TOTALS)
+ i -= NUM_TOTALS;
+ tor_assert(i < NUM_TOTALS);
+ /* Round the bandwidth used down to the nearest 1k. */
+ total = b->totals[i] & ~0x3ff;
+ if (total > cutoff)
+ total = cutoff;
+
+ if (n==(b->num_maxes_set-1))
+ tor_snprintf(cp, len-(cp-buf), "%"PRIu64, (total));
+ else
+ tor_snprintf(cp, len-(cp-buf), "%"PRIu64",", (total));
+ cp += strlen(cp);
+ }
+ return cp-buf;
+}
+
+/** Encode a single bandwidth history line into <b>buf</b>. */
+static void
+bwhist_get_one_bandwidth_line(buf_t *buf, const char *desc,
+ const bw_array_t *b)
+{
+ /* [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
+ /* The n,n,n part above. Largest representation of a uint64_t is 20 chars
+ * long, plus the comma. */
+#define MAX_HIST_VALUE_LEN (21*NUM_TOTALS)
+
+ char tmp[MAX_HIST_VALUE_LEN];
+ char end[ISO_TIME_LEN+1];
+
+ size_t slen = bwhist_fill_bandwidth_history(tmp, MAX_HIST_VALUE_LEN, b);
+ /* If we don't have anything to write, skip to the next entry. */
+ if (slen == 0)
+ return;
+
+ format_iso_time(end, b->next_period-NUM_SECS_BW_SUM_INTERVAL);
+ buf_add_printf(buf, "%s %s (%d s) %s\n",
+ desc, end, NUM_SECS_BW_SUM_INTERVAL, tmp);
+}
+
+/** Allocate and return lines for representing this server's bandwidth
+ * history in its descriptor. We publish these lines in our extra-info
+ * descriptor.
+ */
+char *
+bwhist_get_bandwidth_lines(void)
+{
+ buf_t *buf = buf_new();
+
+ bwhist_get_one_bandwidth_line(buf, "write-history", write_array);
+ bwhist_get_one_bandwidth_line(buf, "read-history", read_array);
+ bwhist_get_one_bandwidth_line(buf, "ipv6-write-history", write_array_ipv6);
+ bwhist_get_one_bandwidth_line(buf, "ipv6-read-history", read_array_ipv6);
+ bwhist_get_one_bandwidth_line(buf, "dirreq-write-history", dir_write_array);
+ bwhist_get_one_bandwidth_line(buf, "dirreq-read-history", dir_read_array);
+
+ char *result = buf_extract(buf, NULL);
+ buf_free(buf);
+ return result;
+}
+
+/** Write a single bw_array_t into the Values, Ends, Interval, and Maximum
+ * entries of an or_state_t. Done before writing out a new state file. */
+static void
+bwhist_update_bwhist_state_section(or_state_t *state,
+ const bw_array_t *b,
+ smartlist_t **s_values,
+ smartlist_t **s_maxima,
+ time_t *s_begins,
+ int *s_interval)
+{
+ int i,j;
+ uint64_t maxval;
+
+ if (*s_values) {
+ SMARTLIST_FOREACH(*s_values, char *, val, tor_free(val));
+ smartlist_free(*s_values);
+ }
+ if (*s_maxima) {
+ SMARTLIST_FOREACH(*s_maxima, char *, val, tor_free(val));
+ smartlist_free(*s_maxima);
+ }
+ if (! server_mode(get_options())) {
+ /* Clients don't need to store bandwidth history persistently;
+ * force these values to the defaults. */
+ /* FFFF we should pull the default out of config.c's state table,
+ * so we don't have two defaults. */
+ if (*s_begins != 0 || *s_interval != 900) {
+ time_t now = time(NULL);
+ time_t save_at = get_options()->AvoidDiskWrites ? now+3600 : now+600;
+ or_state_mark_dirty(state, save_at);
+ }
+ *s_begins = 0;
+ *s_interval = 900;
+ *s_values = smartlist_new();
+ *s_maxima = smartlist_new();
+ return;
+ }
+ *s_begins = b->next_period;
+ *s_interval = NUM_SECS_BW_SUM_INTERVAL;
+
+ *s_values = smartlist_new();
+ *s_maxima = smartlist_new();
+ /* Set i to first position in circular array */
+ i = (b->num_maxes_set <= b->next_max_idx) ? 0 : b->next_max_idx;
+ for (j=0; j < b->num_maxes_set; ++j,++i) {
+ if (i >= NUM_TOTALS)
+ i = 0;
+ smartlist_add_asprintf(*s_values, "%"PRIu64,
+ (b->totals[i] & ~0x3ff));
+ maxval = b->maxima[i] / NUM_SECS_ROLLING_MEASURE;
+ smartlist_add_asprintf(*s_maxima, "%"PRIu64,
+ (maxval & ~0x3ff));
+ }
+ smartlist_add_asprintf(*s_values, "%"PRIu64,
+ (b->total_in_period & ~0x3ff));
+ maxval = b->max_total / NUM_SECS_ROLLING_MEASURE;
+ smartlist_add_asprintf(*s_maxima, "%"PRIu64,
+ (maxval & ~0x3ff));
+}
+
+/** Update <b>state</b> with the newest bandwidth history. Done before
+ * writing out a new state file. */
+void
+bwhist_update_state(or_state_t *state)
+{
+#define UPDATE(arrname,st) \
+ bwhist_update_bwhist_state_section(state,\
+ (arrname),\
+ &state->BWHistory ## st ## Values, \
+ &state->BWHistory ## st ## Maxima, \
+ &state->BWHistory ## st ## Ends, \
+ &state->BWHistory ## st ## Interval)
+
+ UPDATE(write_array, Write);
+ UPDATE(read_array, Read);
+ UPDATE(write_array_ipv6, IPv6Write);
+ UPDATE(read_array_ipv6, IPv6Read);
+ UPDATE(dir_write_array, DirWrite);
+ UPDATE(dir_read_array, DirRead);
+
+ if (server_mode(get_options())) {
+ or_state_mark_dirty(state, time(NULL)+(2*3600));
+ }
+#undef UPDATE
+}
+
+/** Load a single bw_array_t from its Values, Ends, Maxima, and Interval
+ * entries in an or_state_t. Done while reading the state file. */
+static int
+bwhist_load_bwhist_state_section(bw_array_t *b,
+ const smartlist_t *s_values,
+ const smartlist_t *s_maxima,
+ const time_t s_begins,
+ const int s_interval)
+{
+ time_t now = time(NULL);
+ int retval = 0;
+ time_t start;
+
+ uint64_t v, mv;
+ int i,ok,ok_m = 0;
+ int have_maxima = s_maxima && s_values &&
+ (smartlist_len(s_values) == smartlist_len(s_maxima));
+
+ if (s_values && s_begins >= now - NUM_SECS_BW_SUM_INTERVAL*NUM_TOTALS) {
+ start = s_begins - s_interval*(smartlist_len(s_values));
+ if (start > now)
+ return 0;
+ b->cur_obs_time = start;
+ b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
+ SMARTLIST_FOREACH_BEGIN(s_values, const char *, cp) {
+ const char *maxstr = NULL;
+ v = tor_parse_uint64(cp, 10, 0, UINT64_MAX, &ok, NULL);
+ if (have_maxima) {
+ maxstr = smartlist_get(s_maxima, cp_sl_idx);
+ mv = tor_parse_uint64(maxstr, 10, 0, UINT64_MAX, &ok_m, NULL);
+ mv *= NUM_SECS_ROLLING_MEASURE;
+ } else {
+ /* No maxima known; guess average rate to be conservative. */
+ mv = (v / s_interval) * NUM_SECS_ROLLING_MEASURE;
+ }
+ if (!ok) {
+ retval = -1;
+ log_notice(LD_HIST, "Could not parse value '%s' into a number.'",cp);
+ }
+ if (maxstr && !ok_m) {
+ retval = -1;
+ log_notice(LD_HIST, "Could not parse maximum '%s' into a number.'",
+ maxstr);
+ }
+
+ if (start < now) {
+ time_t cur_start = start;
+ time_t actual_interval_len = s_interval;
+ uint64_t cur_val = 0;
+ /* Calculate the average per second. This is the best we can do
+ * because our state file doesn't have per-second resolution. */
+ if (start + s_interval > now)
+ actual_interval_len = now - start;
+ cur_val = v / actual_interval_len;
+ /* This is potentially inefficient, but since we don't do it very
+ * often it should be ok. */
+ while (cur_start < start + actual_interval_len) {
+ add_obs(b, cur_start, cur_val);
+ ++cur_start;
+ }
+ b->max_total = mv;
+ /* This will result in some fairly choppy history if s_interval
+ * is not the same as NUM_SECS_BW_SUM_INTERVAL. XXXX */
+ start += actual_interval_len;
+ }
+ } SMARTLIST_FOREACH_END(cp);
+ }
+
+ /* Clean up maxima and observed */
+ for (i=0; i<NUM_SECS_ROLLING_MEASURE; ++i) {
+ b->obs[i] = 0;
+ }
+ b->total_obs = 0;
+
+ return retval;
+}
+
+/** Set bandwidth history from the state file we just loaded. */
+int
+bwhist_load_state(or_state_t *state, char **err)
+{
+ int all_ok = 1;
+
+ /* Assert they already have been malloced */
+ tor_assert(read_array && write_array);
+ tor_assert(read_array_ipv6 && write_array_ipv6);
+ tor_assert(dir_read_array && dir_write_array);
+
+#define LOAD(arrname,st) \
+ if (bwhist_load_bwhist_state_section( \
+ (arrname), \
+ state->BWHistory ## st ## Values, \
+ state->BWHistory ## st ## Maxima, \
+ state->BWHistory ## st ## Ends, \
+ state->BWHistory ## st ## Interval)<0) \
+ all_ok = 0
+
+ LOAD(write_array, Write);
+ LOAD(read_array, Read);
+ LOAD(write_array_ipv6, IPv6Write);
+ LOAD(read_array_ipv6, IPv6Read);
+ LOAD(dir_write_array, DirWrite);
+ LOAD(dir_read_array, DirRead);
+
+#undef LOAD
+ if (!all_ok) {
+ *err = tor_strdup("Parsing of bandwidth history values failed");
+ /* and create fresh arrays */
+ bwhist_init();
+ return -1;
+ }
+ return 0;
+}
+
+void
+bwhist_free_all(void)
+{
+ bw_array_free(read_array);
+ bw_array_free(read_array_ipv6);
+ bw_array_free(write_array);
+ bw_array_free(write_array_ipv6);
+ bw_array_free(dir_read_array);
+ bw_array_free(dir_write_array);
+}
diff --git a/src/feature/stats/bwhist.h b/src/feature/stats/bwhist.h
new file mode 100644
index 0000000000..f88b951447
--- /dev/null
+++ b/src/feature/stats/bwhist.h
@@ -0,0 +1,47 @@
+/* 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 bwhist.h
+ * @brief Header for feature/stats/bwhist.c
+ **/
+
+#ifndef TOR_FEATURE_STATS_BWHIST_H
+#define TOR_FEATURE_STATS_BWHIST_H
+
+void bwhist_init(void);
+void bwhist_free_all(void);
+
+void bwhist_note_bytes_read(uint64_t num_bytes, time_t when, bool ipv6);
+void bwhist_note_bytes_written(uint64_t num_bytes, time_t when, bool ipv6);
+void bwhist_note_dir_bytes_read(uint64_t num_bytes, time_t when);
+void bwhist_note_dir_bytes_written(uint64_t num_bytes, time_t when);
+
+MOCK_DECL(int, bwhist_bandwidth_assess, (void));
+char *bwhist_get_bandwidth_lines(void);
+struct or_state_t;
+void bwhist_update_state(struct or_state_t *state);
+int bwhist_load_state(struct or_state_t *state, char **err);
+
+#ifdef BWHIST_PRIVATE
+typedef struct bw_array_t bw_array_t;
+STATIC uint64_t find_largest_max(bw_array_t *b);
+STATIC void commit_max(bw_array_t *b);
+STATIC void advance_obs(bw_array_t *b);
+STATIC bw_array_t *bw_array_new(void);
+STATIC void add_obs(bw_array_t *b, time_t when, uint64_t n);
+#define bw_array_free(val) \
+ FREE_AND_NULL(bw_array_t, bw_array_free_, (val))
+STATIC void bw_array_free_(bw_array_t *b);
+STATIC size_t bwhist_fill_bandwidth_history(char *buf, size_t len,
+ const bw_array_t *b);
+#endif /* defined(REPHIST_PRIVATE) */
+
+#ifdef TOR_UNIT_TESTS
+extern struct bw_array_t *write_array;
+#endif
+
+#endif /* !defined(TOR_FEATURE_STATS_BWHIST_H) */
diff --git a/src/feature/stats/connstats.c b/src/feature/stats/connstats.c
new file mode 100644
index 0000000000..827a332be1
--- /dev/null
+++ b/src/feature/stats/connstats.c
@@ -0,0 +1,283 @@
+/* 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 connstats.c
+ * @brief Count bidirectional vs one-way connections.
+ *
+ * Connection statistics, use to track one-way and bidirectional connections.
+ *
+ * Note that this code counts concurrent connections in each
+ * BIDI_INTERVAL-second interval, not total connections. It can tell you what
+ * fraction of connections are bidirectional at each time, not necessarily
+ * what number are bidirectional.
+ **/
+
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "feature/stats/connstats.h"
+#include "app/config/config.h"
+
+/** Start of the current connection stats interval or 0 if we're not
+ * collecting connection statistics. */
+static time_t start_of_conn_stats_interval;
+
+/** Initialize connection stats. */
+void
+conn_stats_init(time_t now)
+{
+ start_of_conn_stats_interval = now;
+}
+
+/** Count connections on which we read and wrote less than this many bytes
+ * as "below threshold." */
+#define BIDI_THRESHOLD 20480
+
+/** Count connections that we read or wrote at least this factor as many
+ * bytes from/to than we wrote or read to/from as mostly reading or
+ * writing. */
+#define BIDI_FACTOR 10
+
+/** Interval length in seconds for considering read and written bytes for
+ * connection stats. */
+#define BIDI_INTERVAL 10
+
+/** Start of next BIDI_INTERVAL second interval. */
+static time_t bidi_next_interval = 0;
+
+/** A single grouped set of connection type counts. */
+typedef struct conn_counts_t {
+ /** Number of connections that we read and wrote less than BIDI_THRESHOLD
+ * bytes from/to in BIDI_INTERVAL seconds. */
+ uint32_t below_threshold;
+
+ /** Number of connections that we read at least BIDI_FACTOR times more
+ * bytes from than we wrote to in BIDI_INTERVAL seconds. */
+ uint32_t mostly_read;
+
+ /** Number of connections that we wrote at least BIDI_FACTOR times more
+ * bytes to than we read from in BIDI_INTERVAL seconds. */
+ uint32_t mostly_written;
+
+ /** Number of connections that we read and wrote at least BIDI_THRESHOLD
+ * bytes from/to, but not BIDI_FACTOR times more in either direction in
+ * BIDI_INTERVAL seconds. */
+ uint32_t both_read_and_written;
+} conn_counts_t ;
+
+/** A collection of connection counts, over all OR connections. */
+static conn_counts_t counts;
+/** A collection of connection counts, over IPv6 OR connections only. */
+static conn_counts_t counts_ipv6;
+
+/** Entry in a map from connection ID to the number of read and written
+ * bytes on this connection in a BIDI_INTERVAL second interval. */
+typedef struct bidi_map_entry_t {
+ HT_ENTRY(bidi_map_entry_t) node;
+ uint64_t conn_id; /**< Connection ID */
+ size_t read; /**< Number of read bytes */
+ size_t written; /**< Number of written bytes */
+ bool is_ipv6; /**< True if this is an IPv6 connection */
+} bidi_map_entry_t;
+
+/** Map of OR connections together with the number of read and written
+ * bytes in the current BIDI_INTERVAL second interval. */
+static HT_HEAD(bidimap, bidi_map_entry_t) bidi_map =
+ HT_INITIALIZER();
+
+/** Hashtable helper: return true if @a a and @a b have the same key. */
+static int
+bidi_map_ent_eq(const bidi_map_entry_t *a, const bidi_map_entry_t *b)
+{
+ return a->conn_id == b->conn_id;
+}
+
+/** Hashtable helper: compute a digest for the key of @a entry. */
+static unsigned
+bidi_map_ent_hash(const bidi_map_entry_t *entry)
+{
+ return (unsigned) entry->conn_id;
+}
+
+HT_PROTOTYPE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
+ 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_);
+
+/** Release all storage held in connstats.c */
+void
+conn_stats_free_all(void)
+{
+ bidi_map_entry_t **ptr, **next, *ent;
+ for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
+ ent = *ptr;
+ next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
+ tor_free(ent);
+ }
+ HT_CLEAR(bidimap, &bidi_map);
+}
+
+/** Reset counters for conn statistics. */
+void
+conn_stats_reset(time_t now)
+{
+ start_of_conn_stats_interval = now;
+ memset(&counts, 0, sizeof(counts));
+ memset(&counts_ipv6, 0, sizeof(counts_ipv6));
+ conn_stats_free_all();
+}
+
+/** Stop collecting connection stats in a way that we can re-start doing
+ * so in conn_stats_init(). */
+void
+conn_stats_terminate(void)
+{
+ conn_stats_reset(0);
+}
+
+/**
+ * Record a single entry @a ent in the counts structure @a cnt.
+ */
+static void
+add_entry_to_count(conn_counts_t *cnt, const bidi_map_entry_t *ent)
+{
+ if (ent->read + ent->written < BIDI_THRESHOLD)
+ cnt->below_threshold++;
+ else if (ent->read >= ent->written * BIDI_FACTOR)
+ cnt->mostly_read++;
+ else if (ent->written >= ent->read * BIDI_FACTOR)
+ cnt->mostly_written++;
+ else
+ cnt->both_read_and_written++;
+}
+
+/**
+ * Count all the connection information we've received during the current
+ * period in 'bidimap', and store that information in the appropriate count
+ * structures.
+ **/
+static void
+collect_period_statistics(void)
+{
+ bidi_map_entry_t **ptr, **next, *ent;
+ for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
+ ent = *ptr;
+ add_entry_to_count(&counts, ent);
+ if (ent->is_ipv6)
+ add_entry_to_count(&counts_ipv6, ent);
+ next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
+ tor_free(ent);
+ }
+ log_info(LD_GENERAL, "%d below threshold, %d mostly read, "
+ "%d mostly written, %d both read and written.",
+ counts.below_threshold, counts.mostly_read, counts.mostly_written,
+ counts.both_read_and_written);
+}
+
+/** We read <b>num_read</b> bytes and wrote <b>num_written</b> from/to OR
+ * connection <b>conn_id</b> in second <b>when</b>. If this is the first
+ * observation in a new interval, sum up the last observations. Add bytes
+ * for this connection. */
+void
+conn_stats_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
+ size_t num_written, time_t when,
+ bool is_ipv6)
+{
+ if (!start_of_conn_stats_interval)
+ return;
+ /* Initialize */
+ if (bidi_next_interval == 0)
+ bidi_next_interval = when + BIDI_INTERVAL;
+ /* Sum up last period's statistics */
+ if (when >= bidi_next_interval) {
+ collect_period_statistics();
+ while (when >= bidi_next_interval)
+ bidi_next_interval += BIDI_INTERVAL;
+ }
+ /* Add this connection's bytes. */
+ if (num_read > 0 || num_written > 0) {
+ bidi_map_entry_t *entry, lookup;
+ lookup.conn_id = conn_id;
+ entry = HT_FIND(bidimap, &bidi_map, &lookup);
+ if (entry) {
+ entry->written += num_written;
+ entry->read += num_read;
+ entry->is_ipv6 |= is_ipv6;
+ } else {
+ entry = tor_malloc_zero(sizeof(bidi_map_entry_t));
+ entry->conn_id = conn_id;
+ entry->written = num_written;
+ entry->read = num_read;
+ entry->is_ipv6 = is_ipv6;
+ HT_INSERT(bidimap, &bidi_map, entry);
+ }
+ }
+}
+
+/** Return a newly allocated string containing the connection statistics
+ * until <b>now</b>, or NULL if we're not collecting conn stats. Caller must
+ * ensure start_of_conn_stats_interval is in the past. */
+char *
+conn_stats_format(time_t now)
+{
+ char *result, written_at[ISO_TIME_LEN+1];
+
+ if (!start_of_conn_stats_interval)
+ return NULL; /* Not initialized. */
+
+ tor_assert(now >= start_of_conn_stats_interval);
+
+ format_iso_time(written_at, now);
+ tor_asprintf(&result,
+ "conn-bi-direct %s (%d s) "
+ "%"PRIu32",%"PRIu32",%"PRIu32",%"PRIu32"\n"
+ "ipv6-conn-bi-direct %s (%d s) "
+ "%"PRIu32",%"PRIu32",%"PRIu32",%"PRIu32"\n",
+ written_at,
+ (unsigned) (now - start_of_conn_stats_interval),
+ counts.below_threshold,
+ counts.mostly_read,
+ counts.mostly_written,
+ counts.both_read_and_written,
+ written_at,
+ (unsigned) (now - start_of_conn_stats_interval),
+ counts_ipv6.below_threshold,
+ counts_ipv6.mostly_read,
+ counts_ipv6.mostly_written,
+ counts_ipv6.both_read_and_written);
+
+ return result;
+}
+
+/** If 24 hours have passed since the beginning of the current conn stats
+ * period, write conn stats to $DATADIR/stats/conn-stats (possibly
+ * overwriting an existing file) and reset counters. Return when we would
+ * next want to write conn stats or 0 if we never want to write. */
+time_t
+conn_stats_save(time_t now)
+{
+ char *str = NULL;
+
+ if (!start_of_conn_stats_interval)
+ return 0; /* Not initialized. */
+ if (start_of_conn_stats_interval + WRITE_STATS_INTERVAL > now)
+ goto done; /* Not ready to write */
+
+ /* Generate history string. */
+ str = conn_stats_format(now);
+
+ /* Reset counters. */
+ conn_stats_reset(now);
+
+ /* Try to write to disk. */
+ if (!check_or_create_data_subdir("stats")) {
+ write_to_data_subdir("stats", "conn-stats", str, "connection statistics");
+ }
+
+ done:
+ tor_free(str);
+ return start_of_conn_stats_interval + WRITE_STATS_INTERVAL;
+}
diff --git a/src/feature/stats/connstats.h b/src/feature/stats/connstats.h
new file mode 100644
index 0000000000..1a03d0748b
--- /dev/null
+++ b/src/feature/stats/connstats.h
@@ -0,0 +1,25 @@
+/* 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 connstats.h
+ * @brief Header for feature/stats/connstats.c
+ **/
+
+#ifndef TOR_FEATURE_STATS_CONNSTATS_H
+#define TOR_FEATURE_STATS_CONNSTATS_H
+
+void conn_stats_init(time_t now);
+void conn_stats_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
+ size_t num_written, time_t when,
+ bool is_ipv6);
+void conn_stats_reset(time_t now);
+char *conn_stats_format(time_t now);
+time_t conn_stats_save(time_t now);
+void conn_stats_terminate(void);
+void conn_stats_free_all(void);
+
+#endif /* !defined(TOR_FEATURE_STATS_CONNSTATS_H) */
diff --git a/src/feature/stats/include.am b/src/feature/stats/include.am
index 8789bc3d96..5be519936f 100644
--- a/src/feature/stats/include.am
+++ b/src/feature/stats/include.am
@@ -1,12 +1,17 @@
# ADD_C_FILE: INSERT SOURCES HERE.
LIBTOR_APP_A_SOURCES += \
+ src/feature/stats/bwhist.c \
+ src/feature/stats/connstats.c \
src/feature/stats/geoip_stats.c \
src/feature/stats/rephist.c \
src/feature/stats/predict_ports.c
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
+ src/feature/stats/bw_array_st.h \
+ src/feature/stats/bwhist.h \
+ src/feature/stats/connstats.h \
src/feature/stats/geoip_stats.h \
src/feature/stats/rephist.h \
src/feature/stats/predict_ports.h
diff --git a/src/feature/stats/predict_ports.c b/src/feature/stats/predict_ports.c
index d728f106a2..57463952e7 100644
--- a/src/feature/stats/predict_ports.c
+++ b/src/feature/stats/predict_ports.c
@@ -270,10 +270,10 @@ rep_hist_circbuilding_dormant(time_t now)
/* see if we'll still need to build testing circuits */
if (server_mode(options) &&
- (!check_whether_orport_reachable(options) ||
+ (!router_all_orports_seem_reachable(options) ||
!circuit_enough_testing_circs()))
return 0;
- if (!check_whether_dirport_reachable(options))
+ if (!router_dirport_seems_reachable(options))
return 0;
return 1;
diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c
index 71e2e00086..b6730e1226 100644
--- a/src/feature/stats/rephist.c
+++ b/src/feature/stats/rephist.c
@@ -18,11 +18,6 @@
* stability information about various relays, including "uptime",
* "weighted fractional uptime" and "mean time between failures".
*
- * <li>Bandwidth usage history, used by relays to self-report how much
- * bandwidth they've used for different purposes over last day or so,
- * in order to generate the {dirreq-,}{read,write}-history lines in
- * that they publish.
- *
* <li>Predicted ports, used by clients to remember how long it's been
* since they opened an exit connection to each given target
* port. Clients use this information in order to try to keep circuits
@@ -48,9 +43,6 @@
* <li>Descriptor serving statistics, used by directory caches to track
* how many descriptors they've served.
*
- * <li>Connection statistics, used by relays to track one-way and
- * bidirectional connections.
- *
* <li>Onion handshake statistics, used by relays to count how many
* TAP and ntor handshakes they've handled.
*
@@ -77,14 +69,13 @@
#define REPHIST_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
-#include "app/config/statefile.h"
#include "core/or/circuitlist.h"
#include "core/or/connection_or.h"
#include "feature/dirauth/authmode.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
-#include "feature/relay/routermode.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/connstats.h"
#include "feature/stats/rephist.h"
#include "lib/container/order.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -92,14 +83,11 @@
#include "feature/nodelist/networkstatus_st.h"
#include "core/or/or_circuit_st.h"
-#include "app/config/or_state_st.h"
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
-static void bw_arrays_init(void);
-
/** Total number of bytes currently allocated in fields used by rephist.c. */
uint64_t rephist_total_alloc=0;
/** Number of or_history_t objects currently allocated. */
@@ -232,7 +220,6 @@ void
rep_hist_init(void)
{
history_map = digestmap_new();
- bw_arrays_init();
}
/** We have just decided that this router with identity digest <b>id</b> is
@@ -973,560 +960,6 @@ rep_hist_load_mtbf_data(time_t now)
return r;
}
-/** For how many seconds do we keep track of individual per-second bandwidth
- * totals? */
-#define NUM_SECS_ROLLING_MEASURE 10
-/** How large are the intervals for which we track and report bandwidth use? */
-#define NUM_SECS_BW_SUM_INTERVAL (24*60*60)
-/** How far in the past do we remember and publish bandwidth use? */
-#define NUM_SECS_BW_SUM_IS_VALID (5*24*60*60)
-/** How many bandwidth usage intervals do we remember? (derived) */
-#define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL)
-
-/** Structure to track bandwidth use, and remember the maxima for a given
- * time period.
- */
-struct bw_array_t {
- /** Observation array: Total number of bytes transferred in each of the last
- * NUM_SECS_ROLLING_MEASURE seconds. This is used as a circular array. */
- uint64_t obs[NUM_SECS_ROLLING_MEASURE];
- int cur_obs_idx; /**< Current position in obs. */
- time_t cur_obs_time; /**< Time represented in obs[cur_obs_idx] */
- uint64_t total_obs; /**< Total for all members of obs except
- * obs[cur_obs_idx] */
- uint64_t max_total; /**< Largest value that total_obs has taken on in the
- * current period. */
- uint64_t total_in_period; /**< Total bytes transferred in the current
- * period. */
-
- /** When does the next period begin? */
- time_t next_period;
- /** Where in 'maxima' should the maximum bandwidth usage for the current
- * period be stored? */
- int next_max_idx;
- /** How many values in maxima/totals have been set ever? */
- int num_maxes_set;
- /** Circular array of the maximum
- * bandwidth-per-NUM_SECS_ROLLING_MEASURE usage for the last
- * NUM_TOTALS periods */
- uint64_t maxima[NUM_TOTALS];
- /** Circular array of the total bandwidth usage for the last NUM_TOTALS
- * periods */
- uint64_t totals[NUM_TOTALS];
-};
-
-/** Shift the current period of b forward by one. */
-STATIC void
-commit_max(bw_array_t *b)
-{
- /* Store total from current period. */
- b->totals[b->next_max_idx] = b->total_in_period;
- /* Store maximum from current period. */
- b->maxima[b->next_max_idx++] = b->max_total;
- /* Advance next_period and next_max_idx */
- b->next_period += NUM_SECS_BW_SUM_INTERVAL;
- if (b->next_max_idx == NUM_TOTALS)
- b->next_max_idx = 0;
- if (b->num_maxes_set < NUM_TOTALS)
- ++b->num_maxes_set;
- /* Reset max_total. */
- b->max_total = 0;
- /* Reset total_in_period. */
- b->total_in_period = 0;
-}
-
-/** Shift the current observation time of <b>b</b> forward by one second. */
-STATIC void
-advance_obs(bw_array_t *b)
-{
- int nextidx;
- uint64_t total;
-
- /* Calculate the total bandwidth for the last NUM_SECS_ROLLING_MEASURE
- * seconds; adjust max_total as needed.*/
- total = b->total_obs + b->obs[b->cur_obs_idx];
- if (total > b->max_total)
- b->max_total = total;
-
- nextidx = b->cur_obs_idx+1;
- if (nextidx == NUM_SECS_ROLLING_MEASURE)
- nextidx = 0;
-
- b->total_obs = total - b->obs[nextidx];
- b->obs[nextidx]=0;
- b->cur_obs_idx = nextidx;
-
- if (++b->cur_obs_time >= b->next_period)
- commit_max(b);
-}
-
-/** Add <b>n</b> bytes to the number of bytes in <b>b</b> for second
- * <b>when</b>. */
-static inline void
-add_obs(bw_array_t *b, time_t when, uint64_t n)
-{
- if (when < b->cur_obs_time)
- return; /* Don't record data in the past. */
-
- /* If we're currently adding observations for an earlier second than
- * 'when', advance b->cur_obs_time and b->cur_obs_idx by an
- * appropriate number of seconds, and do all the other housekeeping. */
- while (when > b->cur_obs_time) {
- /* Doing this one second at a time is potentially inefficient, if we start
- with a state file that is very old. Fortunately, it doesn't seem to
- show up in profiles, so we can just ignore it for now. */
- advance_obs(b);
- }
-
- b->obs[b->cur_obs_idx] += n;
- b->total_in_period += n;
-}
-
-/** Allocate, initialize, and return a new bw_array. */
-static bw_array_t *
-bw_array_new(void)
-{
- bw_array_t *b;
- time_t start;
- b = tor_malloc_zero(sizeof(bw_array_t));
- rephist_total_alloc += sizeof(bw_array_t);
- start = time(NULL);
- b->cur_obs_time = start;
- b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
- return b;
-}
-
-#define bw_array_free(val) \
- FREE_AND_NULL(bw_array_t, bw_array_free_, (val))
-
-/** Free storage held by bandwidth array <b>b</b>. */
-static void
-bw_array_free_(bw_array_t *b)
-{
- if (!b) {
- return;
- }
-
- rephist_total_alloc -= sizeof(bw_array_t);
- tor_free(b);
-}
-
-/** Recent history of bandwidth observations for read operations. */
-static bw_array_t *read_array = NULL;
-/** Recent history of bandwidth observations for write operations. */
-STATIC bw_array_t *write_array = NULL;
-/** Recent history of bandwidth observations for read operations for the
- directory protocol. */
-static bw_array_t *dir_read_array = NULL;
-/** Recent history of bandwidth observations for write operations for the
- directory protocol. */
-static bw_array_t *dir_write_array = NULL;
-
-/** Set up [dir_]read_array and [dir_]write_array, freeing them if they
- * already exist. */
-static void
-bw_arrays_init(void)
-{
- bw_array_free(read_array);
- bw_array_free(write_array);
- bw_array_free(dir_read_array);
- bw_array_free(dir_write_array);
-
- read_array = bw_array_new();
- write_array = bw_array_new();
- dir_read_array = bw_array_new();
- dir_write_array = bw_array_new();
-}
-
-/** Remember that we read <b>num_bytes</b> bytes in second <b>when</b>.
- *
- * Add num_bytes to the current running total for <b>when</b>.
- *
- * <b>when</b> can go back to time, but it's safe to ignore calls
- * earlier than the latest <b>when</b> you've heard of.
- */
-void
-rep_hist_note_bytes_written(uint64_t num_bytes, time_t when)
-{
-/* Maybe a circular array for recent seconds, and step to a new point
- * every time a new second shows up. Or simpler is to just to have
- * a normal array and push down each item every second; it's short.
- */
-/* When a new second has rolled over, compute the sum of the bytes we've
- * seen over when-1 to when-1-NUM_SECS_ROLLING_MEASURE, and stick it
- * somewhere. See rep_hist_bandwidth_assess() below.
- */
- add_obs(write_array, when, num_bytes);
-}
-
-/** Remember that we wrote <b>num_bytes</b> bytes in second <b>when</b>.
- * (like rep_hist_note_bytes_written() above)
- */
-void
-rep_hist_note_bytes_read(uint64_t num_bytes, time_t when)
-{
-/* if we're smart, we can make this func and the one above share code */
- add_obs(read_array, when, num_bytes);
-}
-
-/** Remember that we wrote <b>num_bytes</b> directory bytes in second
- * <b>when</b>. (like rep_hist_note_bytes_written() above)
- */
-void
-rep_hist_note_dir_bytes_written(uint64_t num_bytes, time_t when)
-{
- add_obs(dir_write_array, when, num_bytes);
-}
-
-/** Remember that we read <b>num_bytes</b> directory bytes in second
- * <b>when</b>. (like rep_hist_note_bytes_written() above)
- */
-void
-rep_hist_note_dir_bytes_read(uint64_t num_bytes, time_t when)
-{
- add_obs(dir_read_array, when, num_bytes);
-}
-
-/** Helper: Return the largest value in b->maxima. (This is equal to the
- * most bandwidth used in any NUM_SECS_ROLLING_MEASURE period for the last
- * NUM_SECS_BW_SUM_IS_VALID seconds.)
- */
-STATIC uint64_t
-find_largest_max(bw_array_t *b)
-{
- int i;
- uint64_t max;
- max=0;
- for (i=0; i<NUM_TOTALS; ++i) {
- if (b->maxima[i]>max)
- max = b->maxima[i];
- }
- return max;
-}
-
-/** Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly)
- * seconds. Find one sum for reading and one for writing. They don't have
- * to be at the same time.
- *
- * Return the smaller of these sums, divided by NUM_SECS_ROLLING_MEASURE.
- */
-MOCK_IMPL(int,
-rep_hist_bandwidth_assess,(void))
-{
- uint64_t w,r;
- r = find_largest_max(read_array);
- w = find_largest_max(write_array);
- if (r>w)
- return (int)(((double)w)/NUM_SECS_ROLLING_MEASURE);
- else
- return (int)(((double)r)/NUM_SECS_ROLLING_MEASURE);
-}
-
-/** Print the bandwidth history of b (either [dir-]read_array or
- * [dir-]write_array) into the buffer pointed to by buf. The format is
- * simply comma separated numbers, from oldest to newest.
- *
- * It returns the number of bytes written.
- */
-static size_t
-rep_hist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b)
-{
- char *cp = buf;
- int i, n;
- const or_options_t *options = get_options();
- uint64_t cutoff;
-
- if (b->num_maxes_set <= b->next_max_idx) {
- /* We haven't been through the circular array yet; time starts at i=0.*/
- i = 0;
- } else {
- /* We've been around the array at least once. The next i to be
- overwritten is the oldest. */
- i = b->next_max_idx;
- }
-
- if (options->RelayBandwidthRate) {
- /* We don't want to report that we used more bandwidth than the max we're
- * willing to relay; otherwise everybody will know how much traffic
- * we used ourself. */
- cutoff = options->RelayBandwidthRate * NUM_SECS_BW_SUM_INTERVAL;
- } else {
- cutoff = UINT64_MAX;
- }
-
- for (n=0; n<b->num_maxes_set; ++n,++i) {
- uint64_t total;
- if (i >= NUM_TOTALS)
- i -= NUM_TOTALS;
- tor_assert(i < NUM_TOTALS);
- /* Round the bandwidth used down to the nearest 1k. */
- total = b->totals[i] & ~0x3ff;
- if (total > cutoff)
- total = cutoff;
-
- if (n==(b->num_maxes_set-1))
- tor_snprintf(cp, len-(cp-buf), "%"PRIu64, (total));
- else
- tor_snprintf(cp, len-(cp-buf), "%"PRIu64",", (total));
- cp += strlen(cp);
- }
- return cp-buf;
-}
-
-/** Allocate and return lines for representing this server's bandwidth
- * history in its descriptor. We publish these lines in our extra-info
- * descriptor.
- */
-char *
-rep_hist_get_bandwidth_lines(void)
-{
- char *buf, *cp;
- char t[ISO_TIME_LEN+1];
- int r;
- bw_array_t *b = NULL;
- const char *desc = NULL;
- size_t len;
-
- /* [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
-/* The n,n,n part above. Largest representation of a uint64_t is 20 chars
- * long, plus the comma. */
-#define MAX_HIST_VALUE_LEN (21*NUM_TOTALS)
- len = (67+MAX_HIST_VALUE_LEN)*4;
- buf = tor_malloc_zero(len);
- cp = buf;
- for (r=0;r<4;++r) {
- char tmp[MAX_HIST_VALUE_LEN];
- size_t slen;
- switch (r) {
- case 0:
- b = write_array;
- desc = "write-history";
- break;
- case 1:
- b = read_array;
- desc = "read-history";
- break;
- case 2:
- b = dir_write_array;
- desc = "dirreq-write-history";
- break;
- case 3:
- b = dir_read_array;
- desc = "dirreq-read-history";
- break;
- }
- tor_assert(b);
- slen = rep_hist_fill_bandwidth_history(tmp, MAX_HIST_VALUE_LEN, b);
- /* If we don't have anything to write, skip to the next entry. */
- if (slen == 0)
- continue;
- format_iso_time(t, b->next_period-NUM_SECS_BW_SUM_INTERVAL);
- tor_snprintf(cp, len-(cp-buf), "%s %s (%d s) ",
- desc, t, NUM_SECS_BW_SUM_INTERVAL);
- cp += strlen(cp);
- strlcat(cp, tmp, len-(cp-buf));
- cp += slen;
- strlcat(cp, "\n", len-(cp-buf));
- ++cp;
- }
- return buf;
-}
-
-/** Write a single bw_array_t into the Values, Ends, Interval, and Maximum
- * entries of an or_state_t. Done before writing out a new state file. */
-static void
-rep_hist_update_bwhist_state_section(or_state_t *state,
- const bw_array_t *b,
- smartlist_t **s_values,
- smartlist_t **s_maxima,
- time_t *s_begins,
- int *s_interval)
-{
- int i,j;
- uint64_t maxval;
-
- if (*s_values) {
- SMARTLIST_FOREACH(*s_values, char *, val, tor_free(val));
- smartlist_free(*s_values);
- }
- if (*s_maxima) {
- SMARTLIST_FOREACH(*s_maxima, char *, val, tor_free(val));
- smartlist_free(*s_maxima);
- }
- if (! server_mode(get_options())) {
- /* Clients don't need to store bandwidth history persistently;
- * force these values to the defaults. */
- /* FFFF we should pull the default out of config.c's state table,
- * so we don't have two defaults. */
- if (*s_begins != 0 || *s_interval != 900) {
- time_t now = time(NULL);
- time_t save_at = get_options()->AvoidDiskWrites ? now+3600 : now+600;
- or_state_mark_dirty(state, save_at);
- }
- *s_begins = 0;
- *s_interval = 900;
- *s_values = smartlist_new();
- *s_maxima = smartlist_new();
- return;
- }
- *s_begins = b->next_period;
- *s_interval = NUM_SECS_BW_SUM_INTERVAL;
-
- *s_values = smartlist_new();
- *s_maxima = smartlist_new();
- /* Set i to first position in circular array */
- i = (b->num_maxes_set <= b->next_max_idx) ? 0 : b->next_max_idx;
- for (j=0; j < b->num_maxes_set; ++j,++i) {
- if (i >= NUM_TOTALS)
- i = 0;
- smartlist_add_asprintf(*s_values, "%"PRIu64,
- (b->totals[i] & ~0x3ff));
- maxval = b->maxima[i] / NUM_SECS_ROLLING_MEASURE;
- smartlist_add_asprintf(*s_maxima, "%"PRIu64,
- (maxval & ~0x3ff));
- }
- smartlist_add_asprintf(*s_values, "%"PRIu64,
- (b->total_in_period & ~0x3ff));
- maxval = b->max_total / NUM_SECS_ROLLING_MEASURE;
- smartlist_add_asprintf(*s_maxima, "%"PRIu64,
- (maxval & ~0x3ff));
-}
-
-/** Update <b>state</b> with the newest bandwidth history. Done before
- * writing out a new state file. */
-void
-rep_hist_update_state(or_state_t *state)
-{
-#define UPDATE(arrname,st) \
- rep_hist_update_bwhist_state_section(state,\
- (arrname),\
- &state->BWHistory ## st ## Values, \
- &state->BWHistory ## st ## Maxima, \
- &state->BWHistory ## st ## Ends, \
- &state->BWHistory ## st ## Interval)
-
- UPDATE(write_array, Write);
- UPDATE(read_array, Read);
- UPDATE(dir_write_array, DirWrite);
- UPDATE(dir_read_array, DirRead);
-
- if (server_mode(get_options())) {
- or_state_mark_dirty(state, time(NULL)+(2*3600));
- }
-#undef UPDATE
-}
-
-/** Load a single bw_array_t from its Values, Ends, Maxima, and Interval
- * entries in an or_state_t. Done while reading the state file. */
-static int
-rep_hist_load_bwhist_state_section(bw_array_t *b,
- const smartlist_t *s_values,
- const smartlist_t *s_maxima,
- const time_t s_begins,
- const int s_interval)
-{
- time_t now = time(NULL);
- int retval = 0;
- time_t start;
-
- uint64_t v, mv;
- int i,ok,ok_m = 0;
- int have_maxima = s_maxima && s_values &&
- (smartlist_len(s_values) == smartlist_len(s_maxima));
-
- if (s_values && s_begins >= now - NUM_SECS_BW_SUM_INTERVAL*NUM_TOTALS) {
- start = s_begins - s_interval*(smartlist_len(s_values));
- if (start > now)
- return 0;
- b->cur_obs_time = start;
- b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
- SMARTLIST_FOREACH_BEGIN(s_values, const char *, cp) {
- const char *maxstr = NULL;
- v = tor_parse_uint64(cp, 10, 0, UINT64_MAX, &ok, NULL);
- if (have_maxima) {
- maxstr = smartlist_get(s_maxima, cp_sl_idx);
- mv = tor_parse_uint64(maxstr, 10, 0, UINT64_MAX, &ok_m, NULL);
- mv *= NUM_SECS_ROLLING_MEASURE;
- } else {
- /* No maxima known; guess average rate to be conservative. */
- mv = (v / s_interval) * NUM_SECS_ROLLING_MEASURE;
- }
- if (!ok) {
- retval = -1;
- log_notice(LD_HIST, "Could not parse value '%s' into a number.'",cp);
- }
- if (maxstr && !ok_m) {
- retval = -1;
- log_notice(LD_HIST, "Could not parse maximum '%s' into a number.'",
- maxstr);
- }
-
- if (start < now) {
- time_t cur_start = start;
- time_t actual_interval_len = s_interval;
- uint64_t cur_val = 0;
- /* Calculate the average per second. This is the best we can do
- * because our state file doesn't have per-second resolution. */
- if (start + s_interval > now)
- actual_interval_len = now - start;
- cur_val = v / actual_interval_len;
- /* This is potentially inefficient, but since we don't do it very
- * often it should be ok. */
- while (cur_start < start + actual_interval_len) {
- add_obs(b, cur_start, cur_val);
- ++cur_start;
- }
- b->max_total = mv;
- /* This will result in some fairly choppy history if s_interval
- * is not the same as NUM_SECS_BW_SUM_INTERVAL. XXXX */
- start += actual_interval_len;
- }
- } SMARTLIST_FOREACH_END(cp);
- }
-
- /* Clean up maxima and observed */
- for (i=0; i<NUM_SECS_ROLLING_MEASURE; ++i) {
- b->obs[i] = 0;
- }
- b->total_obs = 0;
-
- return retval;
-}
-
-/** Set bandwidth history from the state file we just loaded. */
-int
-rep_hist_load_state(or_state_t *state, char **err)
-{
- int all_ok = 1;
-
- /* Assert they already have been malloced */
- tor_assert(read_array && write_array);
- tor_assert(dir_read_array && dir_write_array);
-
-#define LOAD(arrname,st) \
- if (rep_hist_load_bwhist_state_section( \
- (arrname), \
- state->BWHistory ## st ## Values, \
- state->BWHistory ## st ## Maxima, \
- state->BWHistory ## st ## Ends, \
- state->BWHistory ## st ## Interval)<0) \
- all_ok = 0
-
- LOAD(write_array, Write);
- LOAD(read_array, Read);
- LOAD(dir_write_array, DirWrite);
- LOAD(dir_read_array, DirRead);
-
-#undef LOAD
- if (!all_ok) {
- *err = tor_strdup("Parsing of bandwidth history values failed");
- /* and create fresh arrays */
- bw_arrays_init();
- return -1;
- }
- return 0;
-}
-
/*** Exit port statistics ***/
/* Some constants */
@@ -2213,223 +1646,6 @@ rep_hist_note_desc_served(const char * desc)
/*** Connection statistics ***/
-/** Start of the current connection stats interval or 0 if we're not
- * collecting connection statistics. */
-static time_t start_of_conn_stats_interval;
-
-/** Initialize connection stats. */
-void
-rep_hist_conn_stats_init(time_t now)
-{
- start_of_conn_stats_interval = now;
-}
-
-/* Count connections that we read and wrote less than these many bytes
- * from/to as below threshold. */
-#define BIDI_THRESHOLD 20480
-
-/* Count connections that we read or wrote at least this factor as many
- * bytes from/to than we wrote or read to/from as mostly reading or
- * writing. */
-#define BIDI_FACTOR 10
-
-/* Interval length in seconds for considering read and written bytes for
- * connection stats. */
-#define BIDI_INTERVAL 10
-
-/** Start of next BIDI_INTERVAL second interval. */
-static time_t bidi_next_interval = 0;
-
-/** Number of connections that we read and wrote less than BIDI_THRESHOLD
- * bytes from/to in BIDI_INTERVAL seconds. */
-static uint32_t below_threshold = 0;
-
-/** Number of connections that we read at least BIDI_FACTOR times more
- * bytes from than we wrote to in BIDI_INTERVAL seconds. */
-static uint32_t mostly_read = 0;
-
-/** Number of connections that we wrote at least BIDI_FACTOR times more
- * bytes to than we read from in BIDI_INTERVAL seconds. */
-static uint32_t mostly_written = 0;
-
-/** Number of connections that we read and wrote at least BIDI_THRESHOLD
- * bytes from/to, but not BIDI_FACTOR times more in either direction in
- * BIDI_INTERVAL seconds. */
-static uint32_t both_read_and_written = 0;
-
-/** Entry in a map from connection ID to the number of read and written
- * bytes on this connection in a BIDI_INTERVAL second interval. */
-typedef struct bidi_map_entry_t {
- HT_ENTRY(bidi_map_entry_t) node;
- uint64_t conn_id; /**< Connection ID */
- size_t read; /**< Number of read bytes */
- size_t written; /**< Number of written bytes */
-} bidi_map_entry_t;
-
-/** Map of OR connections together with the number of read and written
- * bytes in the current BIDI_INTERVAL second interval. */
-static HT_HEAD(bidimap, bidi_map_entry_t) bidi_map =
- HT_INITIALIZER();
-
-static int
-bidi_map_ent_eq(const bidi_map_entry_t *a, const bidi_map_entry_t *b)
-{
- return a->conn_id == b->conn_id;
-}
-
-/* DOCDOC bidi_map_ent_hash */
-static unsigned
-bidi_map_ent_hash(const bidi_map_entry_t *entry)
-{
- return (unsigned) entry->conn_id;
-}
-
-HT_PROTOTYPE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
- 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_);
-
-/* DOCDOC bidi_map_free */
-static void
-bidi_map_free_all(void)
-{
- bidi_map_entry_t **ptr, **next, *ent;
- for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
- ent = *ptr;
- next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
- tor_free(ent);
- }
- HT_CLEAR(bidimap, &bidi_map);
-}
-
-/** Reset counters for conn statistics. */
-void
-rep_hist_reset_conn_stats(time_t now)
-{
- start_of_conn_stats_interval = now;
- below_threshold = 0;
- mostly_read = 0;
- mostly_written = 0;
- both_read_and_written = 0;
- bidi_map_free_all();
-}
-
-/** Stop collecting connection stats in a way that we can re-start doing
- * so in rep_hist_conn_stats_init(). */
-void
-rep_hist_conn_stats_term(void)
-{
- rep_hist_reset_conn_stats(0);
-}
-
-/** We read <b>num_read</b> bytes and wrote <b>num_written</b> from/to OR
- * connection <b>conn_id</b> in second <b>when</b>. If this is the first
- * observation in a new interval, sum up the last observations. Add bytes
- * for this connection. */
-void
-rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
- size_t num_written, time_t when)
-{
- if (!start_of_conn_stats_interval)
- return;
- /* Initialize */
- if (bidi_next_interval == 0)
- bidi_next_interval = when + BIDI_INTERVAL;
- /* Sum up last period's statistics */
- if (when >= bidi_next_interval) {
- bidi_map_entry_t **ptr, **next, *ent;
- for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
- ent = *ptr;
- if (ent->read + ent->written < BIDI_THRESHOLD)
- below_threshold++;
- else if (ent->read >= ent->written * BIDI_FACTOR)
- mostly_read++;
- else if (ent->written >= ent->read * BIDI_FACTOR)
- mostly_written++;
- else
- both_read_and_written++;
- next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
- tor_free(ent);
- }
- while (when >= bidi_next_interval)
- bidi_next_interval += BIDI_INTERVAL;
- log_info(LD_GENERAL, "%d below threshold, %d mostly read, "
- "%d mostly written, %d both read and written.",
- below_threshold, mostly_read, mostly_written,
- both_read_and_written);
- }
- /* Add this connection's bytes. */
- if (num_read > 0 || num_written > 0) {
- bidi_map_entry_t *entry, lookup;
- lookup.conn_id = conn_id;
- entry = HT_FIND(bidimap, &bidi_map, &lookup);
- if (entry) {
- entry->written += num_written;
- entry->read += num_read;
- } else {
- entry = tor_malloc_zero(sizeof(bidi_map_entry_t));
- entry->conn_id = conn_id;
- entry->written = num_written;
- entry->read = num_read;
- HT_INSERT(bidimap, &bidi_map, entry);
- }
- }
-}
-
-/** Return a newly allocated string containing the connection statistics
- * until <b>now</b>, or NULL if we're not collecting conn stats. Caller must
- * ensure start_of_conn_stats_interval is in the past. */
-char *
-rep_hist_format_conn_stats(time_t now)
-{
- char *result, written[ISO_TIME_LEN+1];
-
- if (!start_of_conn_stats_interval)
- return NULL; /* Not initialized. */
-
- tor_assert(now >= start_of_conn_stats_interval);
-
- format_iso_time(written, now);
- tor_asprintf(&result, "conn-bi-direct %s (%d s) %d,%d,%d,%d\n",
- written,
- (unsigned) (now - start_of_conn_stats_interval),
- below_threshold,
- mostly_read,
- mostly_written,
- both_read_and_written);
- return result;
-}
-
-/** If 24 hours have passed since the beginning of the current conn stats
- * period, write conn stats to $DATADIR/stats/conn-stats (possibly
- * overwriting an existing file) and reset counters. Return when we would
- * next want to write conn stats or 0 if we never want to write. */
-time_t
-rep_hist_conn_stats_write(time_t now)
-{
- char *str = NULL;
-
- if (!start_of_conn_stats_interval)
- return 0; /* Not initialized. */
- if (start_of_conn_stats_interval + WRITE_STATS_INTERVAL > now)
- goto done; /* Not ready to write */
-
- /* Generate history string. */
- str = rep_hist_format_conn_stats(now);
-
- /* Reset counters. */
- rep_hist_reset_conn_stats(now);
-
- /* Try to write to disk. */
- if (!check_or_create_data_subdir("stats")) {
- write_to_data_subdir("stats", "conn-stats", str, "connection statistics");
- }
-
- done:
- tor_free(str);
- return start_of_conn_stats_interval + WRITE_STATS_INTERVAL;
-}
-
/** Internal statistics to track how many requests of each type of
* handshake we've received, and how many we've assigned to cpuworkers.
* Useful for seeing trends in cpu load.
@@ -2455,6 +1671,26 @@ rep_hist_note_circuit_handshake_assigned(uint16_t type)
onion_handshakes_assigned[type]++;
}
+/** Get the circuit handshake value that is requested. */
+MOCK_IMPL(int,
+rep_hist_get_circuit_handshake_requested, (uint16_t type))
+{
+ if (BUG(type > MAX_ONION_HANDSHAKE_TYPE)) {
+ return 0;
+ }
+ return onion_handshakes_requested[type];
+}
+
+/** Get the circuit handshake value that is assigned. */
+MOCK_IMPL(int,
+rep_hist_get_circuit_handshake_assigned, (uint16_t type))
+{
+ if (BUG(type > MAX_ONION_HANDSHAKE_TYPE)) {
+ return 0;
+ }
+ return onion_handshakes_assigned[type];
+}
+
/** Log our onionskin statistics since the last time we were called. */
void
rep_hist_log_circuit_handshake_stats(time_t now)
@@ -2901,23 +2137,11 @@ rep_hist_free_all(void)
hs_stats_free(hs_stats);
digestmap_free(history_map, free_or_history);
- bw_array_free(read_array);
- read_array = NULL;
-
- bw_array_free(write_array);
- write_array = NULL;
-
- bw_array_free(dir_read_array);
- dir_read_array = NULL;
-
- bw_array_free(dir_write_array);
- dir_write_array = NULL;
-
tor_free(exit_bytes_read);
tor_free(exit_bytes_written);
tor_free(exit_streams);
predicted_ports_free_all();
- bidi_map_free_all();
+ conn_stats_free_all();
if (circuits_for_buffer_stats) {
SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *, s,
diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h
index 92c3d2a5a5..c9ebc5c328 100644
--- a/src/feature/stats/rephist.h
+++ b/src/feature/stats/rephist.h
@@ -14,18 +14,9 @@
void rep_hist_init(void);
void rep_hist_dump_stats(time_t now, int severity);
-void rep_hist_note_bytes_read(uint64_t num_bytes, time_t when);
-void rep_hist_note_bytes_written(uint64_t num_bytes, time_t when);
void rep_hist_make_router_pessimal(const char *id, time_t when);
-void rep_hist_note_dir_bytes_read(uint64_t num_bytes, time_t when);
-void rep_hist_note_dir_bytes_written(uint64_t num_bytes, time_t when);
-
-MOCK_DECL(int, rep_hist_bandwidth_assess, (void));
-char *rep_hist_get_bandwidth_lines(void);
-void rep_hist_update_state(or_state_t *state);
-int rep_hist_load_state(or_state_t *state, char **err);
void rep_history_clean(time_t before);
void rep_hist_note_router_reachable(const char *id, const tor_addr_t *at_addr,
@@ -65,18 +56,13 @@ void rep_hist_note_desc_served(const char * desc);
void rep_hist_desc_stats_term(void);
time_t rep_hist_desc_stats_write(time_t now);
-void rep_hist_conn_stats_init(time_t now);
-void rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
- size_t num_written, time_t when);
-void rep_hist_reset_conn_stats(time_t now);
-char *rep_hist_format_conn_stats(time_t now);
-time_t rep_hist_conn_stats_write(time_t now);
-void rep_hist_conn_stats_term(void);
-
void rep_hist_note_circuit_handshake_requested(uint16_t type);
void rep_hist_note_circuit_handshake_assigned(uint16_t type);
void rep_hist_log_circuit_handshake_stats(time_t now);
+MOCK_DECL(int, rep_hist_get_circuit_handshake_requested, (uint16_t type));
+MOCK_DECL(int, rep_hist_get_circuit_handshake_assigned, (uint16_t type));
+
void rep_hist_hs_stats_init(time_t now);
void rep_hist_hs_stats_term(void);
time_t rep_hist_hs_stats_write(time_t now);
@@ -95,16 +81,8 @@ extern uint32_t rephist_total_num;
#ifdef TOR_UNIT_TESTS
extern int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1];
extern int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1];
-extern struct bw_array_t *write_array;
#endif
-#ifdef REPHIST_PRIVATE
-typedef struct bw_array_t bw_array_t;
-STATIC uint64_t find_largest_max(bw_array_t *b);
-STATIC void commit_max(bw_array_t *b);
-STATIC void advance_obs(bw_array_t *b);
-#endif /* defined(REPHIST_PRIVATE) */
-
/**
* Represents the type of a cell for padding accounting
*/
diff --git a/src/lib/buf/buffers.c b/src/lib/buf/buffers.c
index a5031a47a6..23fc1e23a6 100644
--- a/src/lib/buf/buffers.c
+++ b/src/lib/buf/buffers.c
@@ -685,19 +685,22 @@ buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen)
}
/** Moves all data from <b>buf_in</b> to <b>buf_out</b>, without copying.
+ * Return the number of bytes that were moved.
*/
-void
+size_t
buf_move_all(buf_t *buf_out, buf_t *buf_in)
{
tor_assert(buf_out);
if (!buf_in)
- return;
+ return 0;
if (buf_datalen(buf_in) == 0)
- return;
+ return 0;
if (BUG(buf_out->datalen > BUF_MAX_LEN || buf_in->datalen > BUF_MAX_LEN))
- return;
+ return 0;
if (BUG(buf_out->datalen > BUF_MAX_LEN - buf_in->datalen))
- return;
+ return 0;
+
+ size_t n_bytes_moved = buf_in->datalen;
if (buf_out->head == NULL) {
buf_out->head = buf_in->head;
@@ -710,6 +713,8 @@ buf_move_all(buf_t *buf_out, buf_t *buf_in)
buf_out->datalen += buf_in->datalen;
buf_in->head = buf_in->tail = NULL;
buf_in->datalen = 0;
+
+ return n_bytes_moved;
}
/** Internal structure: represents a position in a buffer. */
diff --git a/src/lib/buf/buffers.h b/src/lib/buf/buffers.h
index d8a77feb72..1361a02eba 100644
--- a/src/lib/buf/buffers.h
+++ b/src/lib/buf/buffers.h
@@ -46,7 +46,7 @@ void buf_add_printf(buf_t *buf, const char *format, ...)
void buf_add_vprintf(buf_t *buf, const char *format, va_list args)
CHECK_PRINTF(2, 0);
int buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen);
-void buf_move_all(buf_t *buf_out, buf_t *buf_in);
+size_t buf_move_all(buf_t *buf_out, buf_t *buf_in);
void buf_peek(const buf_t *buf, char *string, size_t string_len);
void buf_drain(buf_t *buf, size_t n);
int buf_get_bytes(buf_t *buf, char *string, size_t string_len);
diff --git a/src/lib/crypt_ops/crypto_curve25519.h b/src/lib/crypt_ops/crypto_curve25519.h
index 154a0b94bc..f1e5d1265d 100644
--- a/src/lib/crypt_ops/crypto_curve25519.h
+++ b/src/lib/crypt_ops/crypto_curve25519.h
@@ -9,6 +9,7 @@
#ifndef TOR_CRYPTO_CURVE25519_H
#define TOR_CRYPTO_CURVE25519_H
+#include <stdbool.h>
#include "lib/testsupport/testsupport.h"
#include "lib/cc/torint.h"
#include "lib/crypt_ops/crypto_digest.h"
@@ -77,7 +78,8 @@ STATIC int curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret);
int curve25519_public_from_base64(curve25519_public_key_t *pkey,
const char *input);
void curve25519_public_to_base64(char *output,
- const curve25519_public_key_t *pkey);
+ const curve25519_public_key_t *pkey,
+ bool pad);
void curve25519_set_impl_params(int use_ed);
void curve25519_init(void);
diff --git a/src/lib/crypt_ops/crypto_format.c b/src/lib/crypt_ops/crypto_format.c
index 92b8b9372e..4483b7d2f5 100644
--- a/src/lib/crypt_ops/crypto_format.c
+++ b/src/lib/crypt_ops/crypto_format.c
@@ -131,9 +131,10 @@ crypto_read_tagged_contents_from_file(const char *fname,
return r;
}
-/** Encode <b>pkey</b> as a base64-encoded string, including trailing "="
- * characters, in the buffer <b>output</b>, which must have at least
- * CURVE25519_BASE64_PADDED_LEN+1 bytes available.
+/** Encode <b>pkey</b> as a base64-encoded string in the buffer <b>output</b>.
+ * If <b>pad</b> is false do not include trailing "=" characters, otherwise
+ * include them. <b>output</b> must have at least
+ * CURVE25519_BASE64_PADDED_LEN+1 bytes available, even if <b>pad</b> is false.
* Can not fail.
*
* Careful! CURVE25519_BASE64_PADDED_LEN is one byte longer than
@@ -141,17 +142,25 @@ crypto_read_tagged_contents_from_file(const char *fname,
*/
void
curve25519_public_to_base64(char *output,
- const curve25519_public_key_t *pkey)
+ const curve25519_public_key_t *pkey, bool pad)
{
- char buf[128];
- int n = base64_encode(buf, sizeof(buf),
- (const char*)pkey->public_key,
- CURVE25519_PUBKEY_LEN, 0);
+ int n, expected_len;
+ if (pad) {
+ n = base64_encode(output, CURVE25519_BASE64_PADDED_LEN+1,
+ (const char*)pkey->public_key,
+ CURVE25519_PUBKEY_LEN, 0);
+ expected_len = CURVE25519_BASE64_PADDED_LEN;
+ } else {
+ n = base64_encode_nopad(output, CURVE25519_BASE64_PADDED_LEN+1,
+ (const uint8_t*)pkey->public_key,
+ CURVE25519_PUBKEY_LEN);
+ expected_len = CURVE25519_BASE64_LEN;
+ }
+
/* These asserts should always succeed, unless there is a bug in
* base64_encode(). */
- tor_assert(n == CURVE25519_BASE64_PADDED_LEN);
- tor_assert(buf[CURVE25519_BASE64_PADDED_LEN] == '\0');
- memcpy(output, buf, CURVE25519_BASE64_PADDED_LEN+1);
+ tor_assert(n == expected_len);
+ tor_assert(output[expected_len] == '\0');
}
/** Try to decode a base64-encoded curve25519 public key from <b>input</b>
@@ -162,11 +171,11 @@ curve25519_public_from_base64(curve25519_public_key_t *pkey,
const char *input)
{
size_t len = strlen(input);
- if (len == CURVE25519_BASE64_PADDED_LEN - 1) {
+ if (len == CURVE25519_BASE64_LEN) {
/* not padded */
return digest256_from_base64((char*)pkey->public_key, input);
} else if (len == CURVE25519_BASE64_PADDED_LEN) {
- char buf[128];
+ char buf[CURVE25519_BASE64_PADDED_LEN+1];
if (base64_decode(buf, sizeof(buf), input, len) != CURVE25519_PUBKEY_LEN)
return -1;
memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN);
diff --git a/src/lib/defs/x25519_sizes.h b/src/lib/defs/x25519_sizes.h
index acb08c5e6a..e650f5a350 100644
--- a/src/lib/defs/x25519_sizes.h
+++ b/src/lib/defs/x25519_sizes.h
@@ -36,6 +36,9 @@
/** Length of a Curve25519 key when encoded in base 64, with padding. */
#define CURVE25519_BASE64_PADDED_LEN 44
+/** Length of a Curve25519 key when encoded in base 64, without padding. */
+#define CURVE25519_BASE64_LEN 43
+
/** Length of a Ed25519 key when encoded in base 64, without padding. */
#define ED25519_BASE64_LEN 43
/** Length of a Ed25519 signature when encoded in base 64, without padding. */
diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c
index 9583093c12..f1f6d8ae5f 100644
--- a/src/lib/fs/conffile.c
+++ b/src/lib/fs/conffile.c
@@ -21,6 +21,8 @@
#include "lib/malloc/malloc.h"
#include "lib/string/printf.h"
+#include <stdbool.h>
+
static smartlist_t *config_get_file_list(const char *path,
smartlist_t *opened_files);
static int config_get_included_config(const char *path, int recursion_level,
@@ -50,62 +52,109 @@ config_get_lines_include(const char *string, config_line_t **result,
opened_lst, 1, NULL, config_process_include);
}
-/** Adds a list of configuration files present on <b>path</b> to
- * <b>file_list</b>. <b>path</b> can be a file or a directory. If it is a file,
- * only that file will be added to <b>file_list</b>. If it is a directory,
- * all paths for files on that directory root (no recursion) except for files
- * whose name starts with a dot will be added to <b>file_list</b>.
- * <b>opened_files</b> will have a list of files opened by this function
- * if provided. Return 0 on success, -1 on failure. Ignores empty files.
- */
+/** Returns a list of paths obtained when expading globs in <b>pattern</b>. If
+ * <b>pattern</b> has no globs, returns a list with <b>pattern</b> if it is an
+ * existing path or NULL otherwise. If <b>opened_files</b> is provided, adds
+ * paths opened by glob to it. Returns NULL on failure. */
static smartlist_t *
-config_get_file_list(const char *path, smartlist_t *opened_files)
+expand_glob(const char *pattern, smartlist_t *opened_files)
{
- smartlist_t *file_list = smartlist_new();
+ smartlist_t *matches = tor_glob(pattern);
+ if (!matches) {
+ return NULL;
+ }
- if (opened_files) {
- smartlist_add_strdup(opened_files, path);
+ // if it is not a glob, return error when the path is missing
+ if (!has_glob(pattern) && smartlist_len(matches) == 0) {
+ smartlist_free(matches);
+ return NULL;
}
- file_status_t file_type = file_status(path);
- if (file_type == FN_FILE) {
- smartlist_add_strdup(file_list, path);
- return file_list;
- } else if (file_type == FN_DIR) {
- smartlist_t *all_files = tor_listdir(path);
- if (!all_files) {
- smartlist_free(file_list);
+ if (opened_files) {
+ smartlist_t *glob_opened = get_glob_opened_files(pattern);
+ if (!glob_opened) {
+ SMARTLIST_FOREACH(matches, char *, f, tor_free(f));
+ smartlist_free(matches);
return NULL;
}
- smartlist_sort_strings(all_files);
- SMARTLIST_FOREACH_BEGIN(all_files, char *, f) {
- if (f[0] == '.') {
- tor_free(f);
- continue;
- }
+ smartlist_add_all(opened_files, glob_opened);
+ smartlist_free(glob_opened);
+ }
+ smartlist_sort_strings(matches);
+ return matches;
+}
+
+/** Returns a list of configuration files present on paths that match
+ * <b>pattern</b>. The pattern is expanded and then all the paths are
+ * processed. A path can be a file or a directory. If it is a file, that file
+ * will be added to the list to be returned. If it is a directory,
+ * all paths for files on that directory root (no recursion) except for files
+ * whose name starts with a dot will be added to the list to be returned.
+ * <b>opened_files</b> will have a list of files opened by this function
+ * if provided. Return NULL on failure. Ignores empty files.
+ */
+static smartlist_t *
+config_get_file_list(const char *pattern, smartlist_t *opened_files)
+{
+ smartlist_t *glob_matches = expand_glob(pattern, opened_files);
+ if (!glob_matches) {
+ return NULL;
+ }
- char *fullname;
- tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f);
- tor_free(f);
+ bool error_found = false;
+ smartlist_t *file_list = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(glob_matches, char *, path) {
+ if (opened_files) {
+ smartlist_add_strdup(opened_files, path);
+ }
- if (opened_files) {
- smartlist_add_strdup(opened_files, fullname);
+ file_status_t file_type = file_status(path);
+ if (file_type == FN_FILE) {
+ smartlist_add_strdup(file_list, path);
+ } else if (file_type == FN_DIR) {
+ smartlist_t *all_files = tor_listdir(path);
+ if (!all_files) {
+ error_found = true;
+ break;
}
-
- if (file_status(fullname) != FN_FILE) {
- tor_free(fullname);
+ smartlist_sort_strings(all_files);
+ SMARTLIST_FOREACH_BEGIN(all_files, char *, f) {
+ if (f[0] == '.') {
+ continue;
+ }
+
+ char *fullname;
+ tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f);
+
+ if (opened_files) {
+ smartlist_add_strdup(opened_files, fullname);
+ }
+
+ if (file_status(fullname) != FN_FILE) {
+ tor_free(fullname);
+ continue;
+ }
+ smartlist_add(file_list, fullname);
+ } SMARTLIST_FOREACH_END(f);
+ SMARTLIST_FOREACH(all_files, char *, f, tor_free(f));
+ smartlist_free(all_files);
+ } else if (file_type == FN_EMPTY) {
continue;
- }
- smartlist_add(file_list, fullname);
- } SMARTLIST_FOREACH_END(f);
- smartlist_free(all_files);
- return file_list;
- } else if (file_type == FN_EMPTY) {
- return file_list;
- } else {
+ } else {
+ error_found = true;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(path);
+ SMARTLIST_FOREACH(glob_matches, char *, f, tor_free(f));
+ smartlist_free(glob_matches);
+
+ if (error_found) {
+ SMARTLIST_FOREACH(file_list, char *, f, tor_free(f));
smartlist_free(file_list);
- return NULL;
+ file_list = NULL;
}
+
+ return file_list;
}
/** Creates a list of config lines present on included <b>path</b>.
@@ -133,19 +182,19 @@ config_get_included_config(const char *path, int recursion_level, int extended,
return 0;
}
-/** Process an %include <b>path</b> in a config file. Set <b>list</b> to the
+/** Process an %include <b>pattern</b> in a config file. Set <b>list</b> to the
* list of configuration settings obtained and <b>list_last</b> to the last
* element of the same list. <b>opened_lst</b> will have a list of opened
* files if provided. Return 0 on success, -1 on failure. */
static int
-config_process_include(const char *path, int recursion_level, int extended,
+config_process_include(const char *pattern, int recursion_level, int extended,
config_line_t **list, config_line_t **list_last,
smartlist_t *opened_lst)
{
config_line_t *ret_list = NULL;
config_line_t **next = &ret_list;
- smartlist_t *config_files = config_get_file_list(path, opened_lst);
+ smartlist_t *config_files = config_get_file_list(pattern, opened_lst);
if (!config_files) {
return -1;
}
diff --git a/src/lib/fs/files.c b/src/lib/fs/files.c
index aeaeb5daea..aff78db718 100644
--- a/src/lib/fs/files.c
+++ b/src/lib/fs/files.c
@@ -247,6 +247,22 @@ file_status(const char *fname)
}
}
+/** Returns true if <b>file_type</b> represents an existing file (even if
+ * empty). Returns false otherwise. */
+bool
+is_file(file_status_t file_type)
+{
+ return file_type != FN_ERROR && file_type != FN_NOENT && file_type != FN_DIR;
+}
+
+/** Returns true if <b>file_type</b> represents an existing directory. Returns
+ * false otherwise. */
+bool
+is_dir(file_status_t file_type)
+{
+ return file_type == FN_DIR;
+}
+
/** Create a file named <b>fname</b> with the contents <b>str</b>. Overwrite
* the previous <b>fname</b> if possible. Return 0 on success, -1 on failure.
*
@@ -607,6 +623,9 @@ read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out)
* If <b>flags</b> &amp; RFTS_BIN, open the file in binary mode.
* If <b>flags</b> &amp; RFTS_IGNORE_MISSING, don't warn if the file
* doesn't exist.
+ *
+ * Unless the RFTS_BIN flag is set in <b>flags</b>, this function will strip
+ * any CR characters in the return value on all platforms.
*/
/*
* This function <em>may</em> return an erroneous result if the file
@@ -685,7 +704,6 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out))
}
string[r] = '\0'; /* NUL-terminate the result. */
-#if defined(_WIN32) || defined(__CYGWIN__)
if (!bin && strchr(string, '\r')) {
log_debug(LD_FS, "We didn't convert CRLF to LF as well as we hoped "
"when reading %s. Coping.",
@@ -695,8 +713,7 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out))
}
if (!bin) {
statbuf.st_size = (size_t) r;
- } else
-#endif /* defined(_WIN32) || defined(__CYGWIN__) */
+ } else {
if (r != statbuf.st_size) {
/* Unless we're using text mode on win32, we'd better have an exact
* match for size. */
@@ -708,6 +725,7 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out))
errno = save_errno;
return NULL;
}
+ }
close(fd);
if (stat_out) {
memcpy(stat_out, &statbuf, sizeof(struct stat));
@@ -716,6 +734,26 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out))
return string;
}
+/** Attempt to read a file <b>fname</b>. If the file's contents is
+ * equal to the string <b>str</b>, return 0. Otherwise, attempt to
+ * overwrite the file with the contents of <b>str</b> and return
+ * the value of write_str_to_file().
+ */
+int
+write_str_to_file_if_not_equal(const char *fname, const char *str)
+{
+ char *fstr = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
+ int rv;
+
+ if (!fstr || strcmp(str, fstr)) {
+ rv = write_str_to_file(fname, str, 0);
+ } else {
+ rv = 0;
+ }
+ tor_free(fstr);
+ return rv;
+}
+
#if !defined(HAVE_GETDELIM) || defined(TOR_UNIT_TESTS)
#include "ext/getdelim.c"
#endif
diff --git a/src/lib/fs/files.h b/src/lib/fs/files.h
index a109cd6248..f0178e2b5b 100644
--- a/src/lib/fs/files.h
+++ b/src/lib/fs/files.h
@@ -55,6 +55,8 @@ MOCK_DECL(int,tor_unlink,(const char *pathname));
typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR, FN_EMPTY } file_status_t;
file_status_t file_status(const char *filename);
+bool is_file(file_status_t file_type);
+bool is_dir(file_status_t file_type);
int64_t tor_get_avail_disk_space(const char *path);
@@ -91,6 +93,8 @@ int append_bytes_to_file(const char *fname, const char *str, size_t len,
int write_bytes_to_new_file(const char *fname, const char *str, size_t len,
int bin);
+int write_str_to_file_if_not_equal(const char *fname, const char *str);
+
/** Flag for read_file_to_str: open the file in binary mode. */
#define RFTS_BIN 1
/** Flag for read_file_to_str: it's okay if the file doesn't exist. */
diff --git a/src/lib/fs/path.c b/src/lib/fs/path.c
index 0d57be4b06..1a15969419 100644
--- a/src/lib/fs/path.c
+++ b/src/lib/fs/path.c
@@ -13,15 +13,34 @@
#include "lib/malloc/malloc.h"
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
+#include "lib/container/smartlist.h"
+#include "lib/sandbox/sandbox.h"
#include "lib/string/printf.h"
#include "lib/string/util_string.h"
#include "lib/string/compat_ctype.h"
+#include "lib/string/compat_string.h"
+#include "lib/fs/files.h"
+#include "lib/fs/dir.h"
#include "lib/fs/userdb.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+#ifdef _WIN32
+#include <windows.h>
+#include <shlwapi.h>
+#else /* !(defined(_WIN32)) */
+#include <dirent.h>
+#include <glob.h>
+#endif /* defined(_WIN32) */
+
#include <errno.h>
#include <string.h>
@@ -294,3 +313,357 @@ make_path_absolute(const char *fname)
return absfname;
#endif /* defined(_WIN32) */
}
+
+/* The code below implements tor_glob and get_glob_opened_files. Because it is
+ * not easy to understand it by looking at individual functions, the big
+ * picture explanation here should be read first.
+ *
+ * Purpose of the functions:
+ * - tor_glob - recevies a pattern and returns all the paths that result from
+ * its glob expansion, globs can be present on all path components.
+ * - get_glob_opened_files - receives a pattern and returns all the paths that
+ * are opened during its expansion (the paths before any path fragment that
+ * contains a glob as they have to be opened to check for glob matches). This
+ * is used to get the paths that have to be added to the seccomp sandbox
+ * allowed list.
+ *
+ * Due to OS API differences explained below, the implementation of tor_glob is
+ * completly different for Windows and POSIX systems, so we ended up with three
+ * different implementations:
+ * - tor_glob for POSIX - as POSIX glob does everything we need, we simply call
+ * it and process the results. This is completly implemented in tor_glob.
+ * - tor_glob for WIN32 - because the WIN32 API only supports expanding globs
+ * in the last path fragment, we need to expand the globs in each path
+ * fragment manually and call recursively to get the same behaviour as POSIX
+ * glob. When there are no globs in pattern, we know we are on the last path
+ * fragment and collect the full path.
+ * - get_glob_opened_files - because the paths before any path fragment with a
+ * glob will be opened to check for matches, we need to collect them and we
+ * need to expand the globs in each path fragments and call recursively until
+ * we find no more globs.
+ *
+ * As seen from the description above, both tor_glob for WIN32 and
+ * get_glob_opened_files receive a pattern and return a list of paths and have
+ * to expand all path fragments that contain globs and call themselves
+ * recursively. The differences are:
+ * - get_glob_opened_files collects paths before path fragments with globs
+ * while tor_glob for WIN32 collects full paths resulting from the expansion
+ * of all globs.
+ * - get_glob_opened_files can call tor_glob to expand path fragments with
+ * globs while tor_glob for WIN32 cannot because it IS tor_glob. For tor_glob
+ * for WIN32, an auxiliary function has to be used for this purpose.
+ *
+ * To avoid code duplication, the logic of tor_glob for WIN32 and
+ * get_glob_opened_files is implemented in get_glob_paths. The differences are
+ * configured by the extra function parameters:
+ * - final - if true, returns a list of paths obtained from expanding pattern
+ * (implements tor_glob). Otherwise, returns the paths before path fragments
+ * with globs (implements get_glob_opened_files).
+ * - unglob - function used to expand a path fragment. The function signature
+ * is defined by the unglob_fn typedef. Two implementations are available:
+ * - unglob_win32 - uses tor_listdir and PathMatchSpec (for tor_glob WIN32)
+ * - unglob_opened_files - uses tor_glob (for get_glob_opened_files)
+ */
+
+/** Returns true if the character at position <b>pos</b> in <b>pattern</b> is
+ * considered a glob. Returns false otherwise. Takes escaping into account on
+ * systems where escaping globs is supported. */
+static inline bool
+is_glob_char(const char *pattern, int pos)
+{
+ bool is_glob = pattern[pos] == '*' || pattern[pos] == '?';
+#ifdef _WIN32
+ return is_glob;
+#else /* !defined(_WIN32) */
+ bool is_escaped = pos > 0 && pattern[pos-1] == '\\';
+ return is_glob && !is_escaped;
+#endif /* defined(_WIN32) */
+}
+
+/** Expands the first path fragment of <b>pattern</b> that contains globs. The
+ * path fragment is between <b>prev_sep</b> and <b>next_sep</b>. If the path
+ * fragment is the last fragment of <b>pattern</b>, <b>next_sep</b> will be the
+ * index of the last char. Returns a list of paths resulting from the glob
+ * expansion of the path fragment. Anything after <b>next_sep</b> is not
+ * included in the returned list. Returns NULL on failure. */
+typedef struct smartlist_t * unglob_fn(const char *pattern, int prev_sep,
+ int next_sep);
+
+/** Adds <b>path</b> to <b>result</b> if it exists and is a file type we can
+ * handle. Returns false if <b>path</b> is a file type we cannot handle,
+ * returns true otherwise. Used on tor_glob for WIN32. */
+static bool
+add_non_glob_path(const char *path, struct smartlist_t *result)
+{
+ file_status_t file_type = file_status(path);
+ if (file_type == FN_ERROR) {
+ return false;
+ } else if (file_type != FN_NOENT) {
+ char *to_add = tor_strdup(path);
+ clean_fname_for_stat(to_add);
+ smartlist_add(result, to_add);
+ }
+ /* If WIN32 tor_glob is called with a non-existing path, we want it to
+ * return an empty list instead of error to match the regular version */
+ return true;
+}
+
+/** Auxiliary function used by get_glob_opened_files and WIN32 tor_glob.
+ * Returns a list of paths obtained from <b>pattern</b> using <b>unglob</b> to
+ * expand each path fragment. If <b>final</b> is true, the paths are the result
+ * of the glob expansion of <b>pattern</b> (implements tor_glob). Otherwise,
+ * the paths are the paths opened by glob while expanding <b>pattern</b>
+ * (implements get_glob_opened_files). Returns NULL on failure. */
+static struct smartlist_t *
+get_glob_paths(const char *pattern, unglob_fn unglob, bool final)
+{
+ smartlist_t *result = smartlist_new();
+ int i, prev_sep = -1, next_sep = -1;
+ bool is_glob = false, error_found = false, is_sep = false, is_last = false;
+
+ // find first path fragment with globs
+ for (i = 0; pattern[i]; i++) {
+ is_glob = is_glob || is_glob_char(pattern, i);
+ is_last = !pattern[i+1];
+ is_sep = pattern[i] == *PATH_SEPARATOR || pattern[i] == '/';
+ if (is_sep || is_last) {
+ prev_sep = next_sep;
+ next_sep = i; // next_sep+1 is start of next fragment or end of string
+ if (is_glob) {
+ break;
+ }
+ }
+ }
+
+ if (!is_glob) { // pattern fully expanded or no glob in pattern
+ if (final && !add_non_glob_path(pattern, result)) {
+ error_found = true;
+ goto end;
+ }
+ return result;
+ }
+
+ if (!final) {
+ // add path before the glob to result
+ int len = prev_sep < 1 ? prev_sep + 1 : prev_sep; // handle /*
+ char *path_until_glob = tor_strndup(pattern, len);
+ smartlist_add(result, path_until_glob);
+ }
+
+ smartlist_t *unglobbed_paths = unglob(pattern, prev_sep, next_sep);
+ if (!unglobbed_paths) {
+ error_found = true;
+ } else {
+ // for each path for current fragment, add the rest of the pattern
+ // and call recursively to get all expanded paths
+ SMARTLIST_FOREACH_BEGIN(unglobbed_paths, char *, current_path) {
+ char *next_path;
+ tor_asprintf(&next_path, "%s"PATH_SEPARATOR"%s", current_path,
+ &pattern[next_sep+1]);
+ smartlist_t *opened_next = get_glob_paths(next_path, unglob, final);
+ tor_free(next_path);
+ if (!opened_next) {
+ error_found = true;
+ break;
+ }
+ smartlist_add_all(result, opened_next);
+ smartlist_free(opened_next);
+ } SMARTLIST_FOREACH_END(current_path);
+ SMARTLIST_FOREACH(unglobbed_paths, char *, p, tor_free(p));
+ smartlist_free(unglobbed_paths);
+ }
+
+end:
+ if (error_found) {
+ SMARTLIST_FOREACH(result, char *, p, tor_free(p));
+ smartlist_free(result);
+ result = NULL;
+ }
+ return result;
+}
+
+#ifdef _WIN32
+/** Expands globs in <b>pattern</b> for the path fragment between
+ * <b>prev_sep</b> and <b>next_sep</b> using the WIN32 API. Returns NULL on
+ * failure. Used by the WIN32 implementation of tor_glob. Implements unglob_fn,
+ * see its description for more details. */
+static struct smartlist_t *
+unglob_win32(const char *pattern, int prev_sep, int next_sep)
+{
+ smartlist_t *result = smartlist_new();
+ int len = prev_sep < 1 ? prev_sep + 1 : prev_sep; // handle /*
+ char *path_until_glob = tor_strndup(pattern, len);
+
+ if (!is_file(file_status(path_until_glob))) {
+ smartlist_t *filenames = tor_listdir(path_until_glob);
+ if (!filenames) {
+ smartlist_free(result);
+ result = NULL;
+ } else {
+ SMARTLIST_FOREACH_BEGIN(filenames, char *, filename) {
+ TCHAR tpattern[MAX_PATH] = {0};
+ TCHAR tfile[MAX_PATH] = {0};
+ char *full_path;
+ tor_asprintf(&full_path, "%s"PATH_SEPARATOR"%s",
+ path_until_glob, filename);
+ char *path_curr_glob = tor_strndup(pattern, next_sep + 1);
+ // *\ must return only dirs, remove \ from the pattern so it matches
+ if (is_dir(file_status(full_path))) {
+ clean_fname_for_stat(path_curr_glob);
+ }
+#ifdef UNICODE
+ mbstowcs(tpattern, path_curr_glob, MAX_PATH);
+ mbstowcs(tfile, full_path, MAX_PATH);
+#else /* !defined(UNICODE) */
+ strlcpy(tpattern, path_curr_glob, MAX_PATH);
+ strlcpy(tfile, full_path, MAX_PATH);
+#endif /* defined(UNICODE) */
+ if (PathMatchSpec(tfile, tpattern)) {
+ smartlist_add(result, full_path);
+ } else {
+ tor_free(full_path);
+ }
+ tor_free(path_curr_glob);
+ } SMARTLIST_FOREACH_END(filename);
+ SMARTLIST_FOREACH(filenames, char *, p, tor_free(p));
+ smartlist_free(filenames);
+ }
+ }
+ tor_free(path_until_glob);
+ return result;
+}
+#elif HAVE_GLOB
+/** Same as opendir but calls sandbox_intern_string before */
+static DIR *
+prot_opendir(const char *name)
+{
+ return opendir(sandbox_intern_string(name));
+}
+
+/** Same as stat but calls sandbox_intern_string before */
+static int
+prot_stat(const char *pathname, struct stat *buf)
+{
+ return stat(sandbox_intern_string(pathname), buf);
+}
+
+/** Same as lstat but calls sandbox_intern_string before */
+static int
+prot_lstat(const char *pathname, struct stat *buf)
+{
+ return lstat(sandbox_intern_string(pathname), buf);
+}
+/** As closedir, but has the right type for gl_closedir */
+static void
+wrap_closedir(void *arg)
+{
+ closedir(arg);
+}
+#endif /* defined(HAVE_GLOB) */
+
+/** Return a new list containing the paths that match the pattern
+ * <b>pattern</b>. Return NULL on error. On POSIX systems, errno is set by the
+ * glob function.
+ */
+struct smartlist_t *
+tor_glob(const char *pattern)
+{
+ smartlist_t *result = NULL;
+
+#ifdef _WIN32
+ // PathMatchSpec does not support forward slashes, change them to backslashes
+ char *pattern_normalized = tor_strdup(pattern);
+ tor_strreplacechar(pattern_normalized, '/', *PATH_SEPARATOR);
+ result = get_glob_paths(pattern_normalized, unglob_win32, true);
+ tor_free(pattern_normalized);
+#elif HAVE_GLOB /* !(defined(_WIN32)) */
+ glob_t matches;
+ int flags = GLOB_ERR | GLOB_NOSORT;
+#ifdef GLOB_ALTDIRFUNC
+ /* use functions that call sandbox_intern_string */
+ flags |= GLOB_ALTDIRFUNC;
+ typedef void *(*gl_opendir)(const char * name);
+ typedef struct dirent *(*gl_readdir)(void *);
+ typedef void (*gl_closedir)(void *);
+ matches.gl_opendir = (gl_opendir) &prot_opendir;
+ matches.gl_readdir = (gl_readdir) &readdir;
+ matches.gl_closedir = (gl_closedir) &wrap_closedir;
+ matches.gl_stat = &prot_stat;
+ matches.gl_lstat = &prot_lstat;
+#endif /* defined(GLOB_ALTDIRFUNC) */
+ int ret = glob(pattern, flags, NULL, &matches);
+ if (ret == GLOB_NOMATCH) {
+ return smartlist_new();
+ } else if (ret != 0) {
+ return NULL;
+ }
+
+ result = smartlist_new();
+ size_t i;
+ for (i = 0; i < matches.gl_pathc; i++) {
+ char *match = tor_strdup(matches.gl_pathv[i]);
+ size_t len = strlen(match);
+ if (len > 0 && match[len-1] == *PATH_SEPARATOR) {
+ match[len-1] = '\0';
+ }
+ smartlist_add(result, match);
+ }
+ globfree(&matches);
+#else
+ (void)pattern;
+ return result;
+#endif /* !defined(HAVE_GLOB) */
+
+ return result;
+}
+
+/** Returns true if <b>s</b> contains characters that can be globbed.
+ * Returns false otherwise. */
+bool
+has_glob(const char *s)
+{
+ int i;
+ for (i = 0; s[i]; i++) {
+ if (is_glob_char(s, i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/** Expands globs in <b>pattern</b> for the path fragment between
+ * <b>prev_sep</b> and <b>next_sep</b> using tor_glob. Returns NULL on
+ * failure. Used by get_glob_opened_files. Implements unglob_fn, see its
+ * description for more details. */
+static struct smartlist_t *
+unglob_opened_files(const char *pattern, int prev_sep, int next_sep)
+{
+ (void)prev_sep;
+ smartlist_t *result = smartlist_new();
+ // if the following fragments have no globs, we're done
+ if (has_glob(&pattern[next_sep+1])) {
+ // if there is a glob after next_sep, we know next_sep is a separator and
+ // not the last char and glob_path will have the path without the separator
+ char *glob_path = tor_strndup(pattern, next_sep);
+ smartlist_t *child_paths = tor_glob(glob_path);
+ tor_free(glob_path);
+ if (!child_paths) {
+ smartlist_free(result);
+ result = NULL;
+ } else {
+ smartlist_add_all(result, child_paths);
+ smartlist_free(child_paths);
+ }
+ }
+ return result;
+}
+
+/** Returns a list of files that are opened by the tor_glob function when
+ * called with <b>pattern</b>. Returns NULL on error. The purpose of this
+ * function is to create a list of files to be added to the sandbox white list
+ * before the sandbox is enabled. */
+struct smartlist_t *
+get_glob_opened_files(const char *pattern)
+{
+ return get_glob_paths(pattern, unglob_opened_files, false);
+}
diff --git a/src/lib/fs/path.h b/src/lib/fs/path.h
index f0e253c556..425bd12516 100644
--- a/src/lib/fs/path.h
+++ b/src/lib/fs/path.h
@@ -12,6 +12,10 @@
#ifndef TOR_PATH_H
#define TOR_PATH_H
+#include <stdbool.h>
+#ifdef _WIN32
+#include <windows.h>
+#endif
#include "lib/cc/compat_compiler.h"
#ifdef _WIN32
@@ -26,5 +30,8 @@ int path_is_relative(const char *filename);
void clean_fname_for_stat(char *name);
int get_parent_directory(char *fname);
char *make_path_absolute(const char *fname);
+struct smartlist_t *tor_glob(const char *pattern);
+bool has_glob(const char *s);
+struct smartlist_t *get_glob_opened_files(const char *pattern);
#endif /* !defined(TOR_PATH_H) */
diff --git a/src/lib/log/log.c b/src/lib/log/log.c
index 9ee87c0668..cd848fdd73 100644
--- a/src/lib/log/log.c
+++ b/src/lib/log/log.c
@@ -1308,7 +1308,7 @@ log_level_to_string(int level)
/** NULL-terminated array of names for log domains such that domain_list[dom]
* is a description of <b>dom</b>.
*
- * Remember to update doc/tor.1.txt if you modify this list.
+ * Remember to update doc/man/tor.1.txt if you modify this list.
* */
static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
diff --git a/src/lib/log/ratelim.c b/src/lib/log/ratelim.c
index ac401fb398..8dfaee3384 100644
--- a/src/lib/log/ratelim.c
+++ b/src/lib/log/ratelim.c
@@ -11,6 +11,7 @@
#include "lib/log/ratelim.h"
#include "lib/malloc/malloc.h"
#include "lib/string/printf.h"
+#include "lib/intmath/muldiv.h"
/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number
* of calls to rate_limit_is_ready (including this one!) since the last time
@@ -42,19 +43,24 @@ rate_limit_log(ratelim_t *lim, time_t now)
{
int n;
if ((n = rate_limit_is_ready(lim, now))) {
+ time_t started_limiting = lim->started_limiting;
+ lim->started_limiting = 0;
if (n == 1) {
return tor_strdup("");
} else {
char *cp=NULL;
const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : "";
- /* XXXX this is not exactly correct: the messages could have occurred
- * any time between the old value of lim->allowed and now. */
+ unsigned difference = (unsigned)(now - started_limiting);
+ difference = round_to_next_multiple_of(difference, 60);
tor_asprintf(&cp,
" [%s%d similar message(s) suppressed in last %d seconds]",
- opt_over, n-1, lim->rate);
+ opt_over, n-1, (int)difference);
return cp;
}
} else {
+ if (lim->started_limiting == 0) {
+ lim->started_limiting = now;
+ }
return NULL;
}
}
diff --git a/src/lib/log/ratelim.h b/src/lib/log/ratelim.h
index e9b55d40dc..9e202028cf 100644
--- a/src/lib/log/ratelim.h
+++ b/src/lib/log/ratelim.h
@@ -40,13 +40,19 @@
</pre>
*/
typedef struct ratelim_t {
+ /** How many seconds must elapse between log messages? */
int rate;
+ /** When did this limiter last allow a message to appear? */
time_t last_allowed;
+ /** When did this limiter start suppressing messages? */
+ time_t started_limiting;
+ /** How many messages has this limiter suppressed since it last allowed
+ * one to appear? */
int n_calls_since_last_time;
} ratelim_t;
#ifndef COCCI
-#define RATELIM_INIT(r) { (r), 0, 0 }
+#define RATELIM_INIT(r) { (r), 0, 0, 0 }
#endif
#define RATELIM_TOOMANY (16*1000*1000)
diff --git a/src/lib/net/address.c b/src/lib/net/address.c
index 6d46f9b955..5a32533610 100644
--- a/src/lib/net/address.c
+++ b/src/lib/net/address.c
@@ -764,6 +764,15 @@ tor_addr_is_v4(const tor_addr_t *addr)
return 0; /* Not IPv4 - unknown family or a full-blood IPv6 address */
}
+/** Determine whether an address <b>addr</b> is an IPv6 (AF_INET6). Return
+ * true if so else false. */
+int
+tor_addr_is_v6(const tor_addr_t *addr)
+{
+ tor_assert(addr);
+ return (tor_addr_family(addr) == AF_INET6);
+}
+
/** Determine whether an address <b>addr</b> is null, either all zeroes or
* belonging to family AF_UNSPEC.
*/
@@ -1217,20 +1226,28 @@ fmt_addr32(uint32_t addr)
return buf;
}
-/** Return a string representing the family of <b>addr</b>.
+/** Like fmt_addrport(), but takes <b>addr</b> as a host-order IPv4
+ * addresses. Also not thread-safe, also clobbers its return buffer on
+ * repeated calls. */
+const char *
+fmt_addr32_port(uint32_t addr, uint16_t port)
+{
+ static char buf[INET_NTOA_BUF_LEN + 6];
+ snprintf(buf, sizeof(buf), "%s:%u", fmt_addr32(addr), port);
+ return buf;
+}
+
+/** Return a string representing <b>family</b>.
*
* This string is a string constant, and must not be freed.
* This function is thread-safe.
*/
const char *
-fmt_addr_family(const tor_addr_t *addr)
+fmt_af_family(sa_family_t family)
{
static int default_bug_once = 0;
- IF_BUG_ONCE(!addr)
- return "NULL pointer";
-
- switch (tor_addr_family(addr)) {
+ switch (family) {
case AF_INET6:
return "IPv6";
case AF_INET:
@@ -1242,7 +1259,7 @@ fmt_addr_family(const tor_addr_t *addr)
default:
if (!default_bug_once) {
log_warn(LD_BUG, "Called with unknown address family %d",
- (int)tor_addr_family(addr));
+ (int)family);
default_bug_once = 1;
}
return "unknown";
@@ -1250,6 +1267,20 @@ fmt_addr_family(const tor_addr_t *addr)
//return "(unreachable code)";
}
+/** Return a string representing the family of <b>addr</b>.
+ *
+ * This string is a string constant, and must not be freed.
+ * This function is thread-safe.
+ */
+const char *
+fmt_addr_family(const tor_addr_t *addr)
+{
+ IF_BUG_ONCE(!addr)
+ return "NULL pointer";
+
+ return fmt_af_family(tor_addr_family(addr));
+}
+
/** Convert the string in <b>src</b> to a tor_addr_t <b>addr</b>. The string
* may be an IPv4 address, or an IPv6 address surrounded by square brackets.
*
@@ -2083,6 +2114,18 @@ tor_addr_port_eq(const tor_addr_port_t *a,
return tor_addr_eq(&a->addr, &b->addr) && a->port == b->port;
}
+/**
+ * Copy a tor_addr_port_t from @a source to @a dest.
+ **/
+void
+tor_addr_port_copy(tor_addr_port_t *dest,
+ const tor_addr_port_t *source)
+{
+ tor_assert(dest);
+ tor_assert(source);
+ memcpy(dest, source, sizeof(tor_addr_port_t));
+}
+
/** Return true if <b>string</b> represents a valid IPv4 adddress in
* 'a.b.c.d' form.
*/
diff --git a/src/lib/net/address.h b/src/lib/net/address.h
index e5016ee4fe..bc8ec7744f 100644
--- a/src/lib/net/address.h
+++ b/src/lib/net/address.h
@@ -95,6 +95,7 @@ static inline uint32_t tor_addr_to_ipv4n(const tor_addr_t *a);
static inline uint32_t tor_addr_to_ipv4h(const tor_addr_t *a);
static inline uint32_t tor_addr_to_mapped_ipv4h(const tor_addr_t *a);
static inline sa_family_t tor_addr_family(const tor_addr_t *a);
+static inline bool tor_addr_is_unspec(const tor_addr_t *a);
static inline const struct in_addr *tor_addr_to_in(const tor_addr_t *a);
static inline int tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u);
@@ -188,6 +189,15 @@ tor_addr_family(const tor_addr_t *a)
return a->family;
}
+/**
+ * Return true if the address @a is in the UNSPEC family.
+ **/
+static inline bool
+tor_addr_is_unspec(const tor_addr_t *a)
+{
+ return a->family == AF_UNSPEC;
+}
+
/** Return an in_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
* an IPv4 address. */
static inline const struct in_addr *
@@ -236,6 +246,8 @@ const char *fmt_addr_impl(const tor_addr_t *addr, int decorate);
const char *fmt_addrport(const tor_addr_t *addr, uint16_t port);
#define fmt_addrport_ap(ap) fmt_addrport(&(ap)->addr, (ap)->port)
const char *fmt_addr32(uint32_t addr);
+const char *fmt_addr32_port(uint32_t addr, uint16_t port);
+const char *fmt_af_family(sa_family_t family);
const char *fmt_addr_family(const tor_addr_t *addr);
MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family,
@@ -272,6 +284,7 @@ struct sipkey;
uint64_t tor_addr_keyed_hash(const struct sipkey *key, const tor_addr_t *addr);
int tor_addr_is_v4(const tor_addr_t *addr);
+int tor_addr_is_v6(const tor_addr_t *addr);
int tor_addr_is_internal_(const tor_addr_t *ip, int for_listening,
const char *filename, int lineno);
#define tor_addr_is_internal(addr, for_listening) \
@@ -381,6 +394,7 @@ get_interface_address_list(int severity, int include_internal)
tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port);
int tor_addr_port_eq(const tor_addr_port_t *a,
const tor_addr_port_t *b);
+void tor_addr_port_copy(tor_addr_port_t *dest, const tor_addr_port_t *source);
int string_is_valid_dest(const char *string);
int string_is_valid_nonrfc_hostname(const char *string);
diff --git a/src/lib/net/buffers_net.c b/src/lib/net/buffers_net.c
index 4dbf491e1a..4a0eb3bf16 100644
--- a/src/lib/net/buffers_net.c
+++ b/src/lib/net/buffers_net.c
@@ -137,13 +137,12 @@ buf_read_from_fd(buf_t *buf, int fd, size_t at_most,
}
/** Helper for buf_flush_to_socket(): try to write <b>sz</b> bytes from chunk
- * <b>chunk</b> of buffer <b>buf</b> onto file descriptor <b>fd</b>. On
- * success, deduct the bytes written from *<b>buf_flushlen</b>. Return the
- * number of bytes written on success, 0 on blocking, -1 on failure.
+ * <b>chunk</b> of buffer <b>buf</b> onto file descriptor <b>fd</b>. Return
+ * the number of bytes written on success, 0 on blocking, -1 on failure.
*/
static inline int
flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz,
- size_t *buf_flushlen, bool is_socket)
+ bool is_socket)
{
ssize_t write_result;
@@ -168,7 +167,6 @@ flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz,
log_debug(LD_NET,"write() would block, returning.");
return 0;
} else {
- *buf_flushlen -= write_result;
buf_drain(buf, write_result);
tor_assert(write_result <= BUF_MAX_LEN);
return (int)write_result;
@@ -176,27 +174,22 @@ flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz,
}
/** Write data from <b>buf</b> to the file descriptor <b>fd</b>. Write at most
- * <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by
- * the number of bytes actually written, and remove the written bytes
+ * <b>sz</b> bytes, and remove the written bytes
* from the buffer. Return the number of bytes written on success,
* -1 on failure. Return 0 if write() would block.
*/
static int
buf_flush_to_fd(buf_t *buf, int fd, size_t sz,
- size_t *buf_flushlen, bool is_socket)
+ bool is_socket)
{
/* XXXX It's stupid to overload the return values for these functions:
* "error status" and "number of bytes flushed" are not mutually exclusive.
*/
int r;
size_t flushed = 0;
- tor_assert(buf_flushlen);
tor_assert(SOCKET_OK(fd));
- if (BUG(*buf_flushlen > buf->datalen)) {
- *buf_flushlen = buf->datalen;
- }
- if (BUG(sz > *buf_flushlen)) {
- sz = *buf_flushlen;
+ if (BUG(sz > buf->datalen)) {
+ sz = buf->datalen;
}
check();
@@ -208,7 +201,7 @@ buf_flush_to_fd(buf_t *buf, int fd, size_t sz,
else
flushlen0 = buf->head->datalen;
- r = flush_chunk(fd, buf, buf->head, flushlen0, buf_flushlen, is_socket);
+ r = flush_chunk(fd, buf, buf->head, flushlen0, is_socket);
check();
if (r < 0)
return r;
@@ -228,10 +221,9 @@ buf_flush_to_fd(buf_t *buf, int fd, size_t sz,
* -1 on failure. Return 0 if write() would block.
*/
int
-buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz,
- size_t *buf_flushlen)
+buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz)
{
- return buf_flush_to_fd(buf, s, sz, buf_flushlen, true);
+ return buf_flush_to_fd(buf, s, sz, true);
}
/** Read from socket <b>s</b>, writing onto end of <b>buf</b>. Read at most
@@ -254,10 +246,9 @@ buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most,
* -1 on failure. Return 0 if write() would block.
*/
int
-buf_flush_to_pipe(buf_t *buf, int fd, size_t sz,
- size_t *buf_flushlen)
+buf_flush_to_pipe(buf_t *buf, int fd, size_t sz)
{
- return buf_flush_to_fd(buf, fd, sz, buf_flushlen, false);
+ return buf_flush_to_fd(buf, fd, sz, false);
}
/** Read from pipe <b>fd</b>, writing onto end of <b>buf</b>. Read at most
diff --git a/src/lib/net/buffers_net.h b/src/lib/net/buffers_net.h
index a45c23a273..556575c3dc 100644
--- a/src/lib/net/buffers_net.h
+++ b/src/lib/net/buffers_net.h
@@ -21,14 +21,12 @@ int buf_read_from_socket(struct buf_t *buf, tor_socket_t s, size_t at_most,
int *reached_eof,
int *socket_error);
-int buf_flush_to_socket(struct buf_t *buf, tor_socket_t s, size_t sz,
- size_t *buf_flushlen);
+int buf_flush_to_socket(struct buf_t *buf, tor_socket_t s, size_t sz);
int buf_read_from_pipe(struct buf_t *buf, int fd, size_t at_most,
int *reached_eof,
int *socket_error);
-int buf_flush_to_pipe(struct buf_t *buf, int fd, size_t sz,
- size_t *buf_flushlen);
+int buf_flush_to_pipe(struct buf_t *buf, int fd, size_t sz);
#endif /* !defined(TOR_BUFFERS_NET_H) */
diff --git a/src/lib/osinfo/include.am b/src/lib/osinfo/include.am
index 84bd7feb00..df8c98500c 100644
--- a/src/lib/osinfo/include.am
+++ b/src/lib/osinfo/include.am
@@ -7,7 +7,8 @@ endif
# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_osinfo_a_SOURCES = \
- src/lib/osinfo/uname.c
+ src/lib/osinfo/uname.c \
+ src/lib/osinfo/libc.c
src_lib_libtor_osinfo_testing_a_SOURCES = \
$(src_lib_libtor_osinfo_a_SOURCES)
@@ -16,4 +17,5 @@ src_lib_libtor_osinfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
- src/lib/osinfo/uname.h
+ src/lib/osinfo/uname.h \
+ src/lib/osinfo/libc.h
diff --git a/src/lib/osinfo/libc.c b/src/lib/osinfo/libc.c
new file mode 100644
index 0000000000..32cbad0fa2
--- /dev/null
+++ b/src/lib/osinfo/libc.c
@@ -0,0 +1,66 @@
+/* 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 libc.c
+ * @brief Functions to get the name and version of the system libc.
+ **/
+
+#include "orconfig.h"
+#include "lib/osinfo/libc.h"
+#include <stdlib.h>
+
+#ifdef HAVE_GNU_LIBC_VERSION_H
+#include <gnu/libc-version.h>
+#endif
+
+#ifdef HAVE_GNU_LIBC_VERSION_H
+#ifdef HAVE_GNU_GET_LIBC_VERSION
+#define CHECK_LIBC_VERSION
+#endif
+#endif
+
+#define STR_IMPL(x) #x
+#define STR(x) STR_IMPL(x)
+
+/** Return the name of the compile time libc. Returns NULL if we
+ * cannot identify the libc. */
+const char *
+tor_libc_get_name(void)
+{
+#ifdef __GLIBC__
+ return "Glibc";
+#else /* !defined(__GLIBC__) */
+ return NULL;
+#endif /* defined(__GLIBC__) */
+}
+
+/** Return a string representation of the version of the currently running
+ * version of Glibc. */
+const char *
+tor_libc_get_version_str(void)
+{
+#ifdef CHECK_LIBC_VERSION
+ const char *version = gnu_get_libc_version();
+ if (version == NULL)
+ return "N/A";
+ return version;
+#else /* !defined(CHECK_LIBC_VERSION) */
+ return "N/A";
+#endif /* defined(CHECK_LIBC_VERSION) */
+}
+
+/** Return a string representation of the version of Glibc that was used at
+ * compilation time. */
+const char *
+tor_libc_get_header_version_str(void)
+{
+#ifdef __GLIBC__
+ return STR(__GLIBC__) "." STR(__GLIBC_MINOR__);
+#else
+ return "N/A";
+#endif /* defined(__GLIBC__) */
+}
diff --git a/src/lib/osinfo/libc.h b/src/lib/osinfo/libc.h
new file mode 100644
index 0000000000..f4303f8c9c
--- /dev/null
+++ b/src/lib/osinfo/libc.h
@@ -0,0 +1,19 @@
+/* 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 libc.h
+ * @brief Header for lib/osinfo/libc.c
+ **/
+
+#ifndef TOR_LIB_OSINFO_LIBC_H
+#define TOR_LIB_OSINFO_LIBC_H
+
+const char *tor_libc_get_name(void);
+const char *tor_libc_get_version_str(void);
+const char *tor_libc_get_header_version_str(void);
+
+#endif /* !defined(TOR_LIB_OSINFO_LIBC_H) */
diff --git a/src/lib/process/process_unix.c b/src/lib/process/process_unix.c
index 2b47e1874d..82b2630a5d 100644
--- a/src/lib/process/process_unix.c
+++ b/src/lib/process/process_unix.c
@@ -418,7 +418,7 @@ process_unix_write(process_t *process, buf_t *buffer)
/* We have data to write and the kernel have told us to write it. */
return buf_flush_to_pipe(buffer,
process_get_unix_process(process)->stdin_handle.fd,
- max_to_write, &buffer_flush_len);
+ max_to_write);
}
/** Read data from the given process's standard output and put it into
diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c
index d4f0da8397..8d467c516e 100644
--- a/src/lib/sandbox/sandbox.c
+++ b/src/lib/sandbox/sandbox.c
@@ -204,6 +204,8 @@ static int filter_nopar_gen[] = {
#ifdef __NR__llseek
SCMP_SYS(_llseek),
#endif
+ // glob uses this..
+ SCMP_SYS(lstat),
SCMP_SYS(mkdir),
SCMP_SYS(mlockall),
#ifdef __NR_mmap
@@ -997,7 +999,7 @@ sb_epoll_ctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
* the seccomp filter sandbox.
*
* NOTE: if multiple filters need to be added, the PR_SECCOMP parameter needs
- * to be whitelisted in this function.
+ * to be allowlisted in this function.
*/
static int
sb_prctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
diff --git a/src/lib/string/compat_string.h b/src/lib/string/compat_string.h
index f05265bdcc..5c9bf05ebd 100644
--- a/src/lib/string/compat_string.h
+++ b/src/lib/string/compat_string.h
@@ -42,7 +42,7 @@ static inline int strcasecmp(const char *a, const char *b) {
* (If --enable-fragile-hardening is passed to configure, we use the hardened
* variants, which do not suffer from this issue.)
*
- * See https://trac.torproject.org/projects/tor/ticket/15205
+ * See https://bugs.torproject.org/tpo/core/tor/15205.
*/
#undef strlcat
#undef strlcpy
diff --git a/src/lib/string/util_string.c b/src/lib/string/util_string.c
index c8f12d780e..ba5f9f2203 100644
--- a/src/lib/string/util_string.c
+++ b/src/lib/string/util_string.c
@@ -143,6 +143,15 @@ tor_strupper(char *s)
}
}
+/** Replaces <b>old</b> with <b>replacement</b> in <b>s</b> */
+void
+tor_strreplacechar(char *s, char find, char replacement)
+{
+ for (s = strchr(s, find); s; s = strchr(s + 1, find)) {
+ *s = replacement;
+ }
+}
+
/** Return 1 if every character in <b>s</b> is printable, else return 0.
*/
int
diff --git a/src/lib/string/util_string.h b/src/lib/string/util_string.h
index e89233df88..15d35415fe 100644
--- a/src/lib/string/util_string.h
+++ b/src/lib/string/util_string.h
@@ -31,6 +31,7 @@ int tor_digest256_is_zero(const char *digest);
#define HEX_CHARACTERS "0123456789ABCDEFabcdef"
void tor_strlower(char *s);
void tor_strupper(char *s);
+void tor_strreplacechar(char *s, char find, char replacement);
int tor_strisprint(const char *s);
int tor_strisnonupper(const char *s);
int tor_strisspace(const char *s);
diff --git a/src/lib/tls/buffers_tls.c b/src/lib/tls/buffers_tls.c
index b92a14d6a1..de0e9cb4ef 100644
--- a/src/lib/tls/buffers_tls.c
+++ b/src/lib/tls/buffers_tls.c
@@ -59,6 +59,9 @@ read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls,
* Second, the TLS stream's events do not correspond directly to network
* events: sometimes, before a TLS stream can read, the network must be
* ready to write -- or vice versa.
+ *
+ * On success, return the number of bytes read. On error, a TOR_TLS_* negative
+ * code is returned (expect any of them except TOR_TLS_DONE).
*/
int
buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most)
@@ -92,8 +95,6 @@ buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most)
return r; /* Error */
tor_assert(total_read+r <= BUF_MAX_LEN);
total_read += r;
- if ((size_t)r < readlen) /* eof, block, or no more to read. */
- break;
}
return (int)total_read;
}
@@ -105,8 +106,7 @@ buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most)
* written on success, and a TOR_TLS error code on failure or blocking.
*/
static inline int
-flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk,
- size_t sz, size_t *buf_flushlen)
+flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, size_t sz)
{
int r;
size_t forced;
@@ -125,13 +125,9 @@ flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk,
r = tor_tls_write(tls, data, sz);
if (r < 0)
return r;
- if (*buf_flushlen > (size_t)r)
- *buf_flushlen -= r;
- else
- *buf_flushlen = 0;
buf_drain(buf, r);
- log_debug(LD_NET,"flushed %d bytes, %d ready to flush, %d remain.",
- r,(int)*buf_flushlen,(int)buf->datalen);
+ log_debug(LD_NET,"flushed %d bytes, %d remain.",
+ r,(int)buf->datalen);
return r;
}
@@ -139,18 +135,13 @@ flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk,
* more than <b>flushlen</b> bytes.
*/
int
-buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen,
- size_t *buf_flushlen)
+buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen)
{
int r;
size_t flushed = 0;
ssize_t sz;
- tor_assert(buf_flushlen);
- IF_BUG_ONCE(*buf_flushlen > buf->datalen) {
- *buf_flushlen = buf->datalen;
- }
- IF_BUG_ONCE(flushlen > *buf_flushlen) {
- flushlen = *buf_flushlen;
+ IF_BUG_ONCE(flushlen > buf->datalen) {
+ flushlen = buf->datalen;
}
sz = (ssize_t) flushlen;
@@ -169,7 +160,7 @@ buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen,
flushlen0 = 0;
}
- r = flush_chunk_tls(tls, buf, buf->head, flushlen0, buf_flushlen);
+ r = flush_chunk_tls(tls, buf, buf->head, flushlen0);
if (r < 0)
return r;
flushed += r;
diff --git a/src/lib/tls/buffers_tls.h b/src/lib/tls/buffers_tls.h
index 587426801d..ed391cefbd 100644
--- a/src/lib/tls/buffers_tls.h
+++ b/src/lib/tls/buffers_tls.h
@@ -18,6 +18,6 @@ struct tor_tls_t;
int buf_read_from_tls(struct buf_t *buf,
struct tor_tls_t *tls, size_t at_most);
int buf_flush_to_tls(struct buf_t *buf, struct tor_tls_t *tls,
- size_t sz, size_t *buf_flushlen);
+ size_t sz);
#endif /* !defined(TOR_BUFFERS_TLS_H) */
diff --git a/src/lib/trace/.may_include b/src/lib/trace/.may_include
index 45cd13676b..1ed533cc7a 100644
--- a/src/lib/trace/.may_include
+++ b/src/lib/trace/.may_include
@@ -1,3 +1,4 @@
orconfig.h
lib/log/*.h
lib/trace/*.h
+lib/subsys/*.h
diff --git a/src/lib/trace/debug.h b/src/lib/trace/debug.h
index 87b3074e0b..84a2867a6d 100644
--- a/src/lib/trace/debug.h
+++ b/src/lib/trace/debug.h
@@ -6,8 +6,10 @@
* \brief Macros for debugging our event-trace support.
**/
-#ifndef TOR_TRACE_LOG_DEBUG_H
-#define TOR_TRACE_LOG_DEBUG_H
+#ifndef TOR_TRACE_DEBUG_H
+#define TOR_TRACE_DEBUG_H
+
+#ifdef USE_TRACING_INSTRUMENTATION_LOG_DEBUG
#include "lib/log/log.h"
@@ -17,14 +19,20 @@
/* Send every event to a debug log level. This is useful to debug new trace
* events without implementing them for a specific event tracing framework.
- * Note that the arguments are ignored since at this step we do not know the
- * types and amount there is. */
+ *
+ * NOTE: arguments can't be used becaue there is no easy generic ways to learn
+ * their type and amount. It is probably doable with massive C pre-processor
+ * trickery but this is meant to be simple. */
+
+#define TOR_TRACE_LOG_DEBUG(subsystem, event_name, ...) \
+ log_debug(LD_GENERAL, "Tracepoint \"" XSTR(event_name) "\" from " \
+ "subsystem \"" XSTR(subsystem) "\" hit.")
+
+#else /* defined(USE_TRACING_INSTRUMENTATION_LOG_DEBUG) */
+
+/* NOP the debug event. */
+#define TOR_TRACE_LOG_DEBUG(subsystem, name, ...)
-/* Example on how to map a tracepoint to log_debug(). */
-#undef tor_trace
-#define tor_trace(subsystem, name, args...) \
- log_debug(LD_GENERAL, "Trace event \"" XSTR(name) "\" from " \
- "\"" XSTR(subsystem) "\" hit. " \
- "(line "XSTR(__LINE__) ")")
+#endif /* defined(USE_TRACING_INSTRUMENTATION_LOG_DEBUG) */
-#endif /* !defined(TOR_TRACE_LOG_DEBUG_H) */
+#endif /* !defined(TOR_TRACE_DEBUG_H) */
diff --git a/src/lib/trace/events.h b/src/lib/trace/events.h
index 368f85dd02..ce1604de22 100644
--- a/src/lib/trace/events.h
+++ b/src/lib/trace/events.h
@@ -3,43 +3,75 @@
/**
* \file events.h
- * \brief Header file for Tor event tracing.
+ * \brief Header file for Tor tracing instrumentation definition.
**/
-#ifndef TOR_TRACE_EVENTS_H
-#define TOR_TRACE_EVENTS_H
+#ifndef TOR_LIB_TRACE_EVENTS_H
+#define TOR_LIB_TRACE_EVENTS_H
+
+#include "orconfig.h"
/*
- * The following defines a generic event tracing function name that has to be
- * used to trace events in the code base.
+ * A tracepoint signature is defined as follow:
+ *
+ * tor_trace(<subsystem>, <event_name>, <args>...)
+ *
+ * If tracing is enabled, the tor_trace() macro is mapped to all possible
+ * instrumentations (defined below). Each instrumentation type MUST define a
+ * top level macro (TOR_TRACE_<type>) so it can be inserted into each
+ * tracepoint.
+ *
+ * In case no tracing is enabled (HAVE_TRACING), tracepoints are NOP and thus
+ * have no execution cost.
*
- * That generic function is then defined by a event tracing framework. For
- * instance, the "log debug" framework sends all trace events to log_debug()
- * which is defined in src/trace/debug.h which can only be enabled at compile
- * time (--enable-event-tracing-debug).
+ * Currently, three types of instrumentation are supported:
*
- * By default, every trace events in the code base are replaced by a NOP. See
- * doc/HACKING/Tracing.md for more information on how to use event tracing or
- * add events.
+ * log-debug: Every tracepoints is mapped to a log_debug() statement.
+ *
+ * User Statically-Defined Tracing (USDT): Probes that can be used with perf,
+ * dtrace, SystemTap, DTrace and BPF Compiler Collection (BCC).
+ *
+ * LTTng-UST: Probes for the LTTng Userspace Tracer. If USDT interface
+ * (sdt.h) is available, the USDT probes are also generated by LTTng thus
+ * enabling this instrumentation provides both probes.
*/
-#ifdef TOR_EVENT_TRACING_ENABLED
-/* Map every trace event to a per subsystem macro. */
-#define tor_trace(subsystem, name, ...) \
- tor_trace_##subsystem(name, __VA_ARGS__)
+/** Helper to disambiguate these identifiers in the code base. They should
+ * only be used with tor_trace() like so:
+ *
+ * tor_trace(TR_SUBSYS(circuit), TR_EV(opened), ...);
+ */
+
+#define TR_SUBSYS(name) tor_ ## name
+#define TR_EV(name) name
+
+#ifdef HAVE_TRACING
-/* Enable event tracing for the debug framework where all trace events are
- * mapped to a log_debug(). */
-#ifdef USE_EVENT_TRACING_DEBUG
+#define tor_trace(subsystem, event_name, ...) \
+ do { \
+ TOR_TRACE_LOG_DEBUG(subsystem, event_name); \
+ TOR_TRACE_USDT(subsystem, event_name, ## __VA_ARGS__); \
+ TOR_TRACE_LTTNG(subsystem, event_name, ## __VA_ARGS__); \
+ } while (0)
+
+/* This corresponds to the --enable-tracing-instrumentation-log-debug
+ * configure option which maps all tracepoints to a log_debug() statement. */
#include "lib/trace/debug.h"
-#endif
-#else /* !defined(TOR_EVENT_TRACING_ENABLED) */
+/* This corresponds to the --enable-tracing-instrumentation-usdt configure
+ * option which will generate USDT probes for each tracepoints. */
+#include "lib/trace/usdt/usdt.h"
+
+/* This corresponds to the --enable-tracing-instrumentation-lttng configure
+ * option which will generate LTTng probes for each tracepoints. */
+#include "lib/trace/lttng/lttng.h"
+
+#else /* !defined(HAVE_TRACING) */
-/* Reaching this point, we NOP every event declaration because event tracing
- * is not been enabled at compile time. */
-#define tor_trace(subsystem, name, args...)
+/* Reaching this point, tracing is disabled thus we NOP every tracepoints
+ * declaration so we have no execution cost at runtime. */
+#define tor_trace(subsystem, name, ...)
-#endif /* defined(TOR_EVENT_TRACING_ENABLED) */
+#endif /* defined(HAVE_TRACING) */
-#endif /* !defined(TOR_TRACE_EVENTS_H) */
+#endif /* !defined(TOR_LIB_TRACE_EVENTS_H) */
diff --git a/src/lib/trace/include.am b/src/lib/trace/include.am
index 98098c87f4..6fe1365652 100644
--- a/src/lib/trace/include.am
+++ b/src/lib/trace/include.am
@@ -2,18 +2,34 @@
noinst_LIBRARIES += \
src/lib/libtor-trace.a
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_TRACE_A_SOURCES = \
+ src/lib/trace/trace.c \
+ src/lib/trace/trace_sys.c
+
# ADD_C_FILE: INSERT HEADERS HERE.
TRACEHEADERS = \
- src/lib/trace/trace.h \
+ src/lib/trace/trace.h \
+ src/lib/trace/trace_sys.h \
src/lib/trace/events.h
-if USE_EVENT_TRACING_DEBUG
+if USE_TRACING_INSTRUMENTATION_LOG_DEBUG
TRACEHEADERS += \
src/lib/trace/debug.h
endif
-# ADD_C_FILE: INSERT SOURCES HERE.
-src_lib_libtor_trace_a_SOURCES = \
- src/lib/trace/trace.c
+if USE_TRACING_INSTRUMENTATION_USDT
+include src/lib/trace/usdt/include.am
+endif
+
+if USE_TRACING_INSTRUMENTATION_LTTNG
+include src/lib/trace/lttng/include.am
+endif
+
+if USE_TRACING
+src_lib_libtor_trace_a_SOURCES = $(LIBTOR_TRACE_A_SOURCES)
+else
+src_lib_libtor_trace_a_SOURCES = src/lib/trace/trace_stub.c
+endif
noinst_HEADERS+= $(TRACEHEADERS)
diff --git a/src/lib/trace/lttng/include.am b/src/lib/trace/lttng/include.am
new file mode 100644
index 0000000000..4495ce0900
--- /dev/null
+++ b/src/lib/trace/lttng/include.am
@@ -0,0 +1,3 @@
+# ADD_C_FILE: INSERT HEADERS HERE.
+TRACEHEADERS += \
+ src/lib/trace/lttng/lttng.h
diff --git a/src/lib/trace/lttng/lttng.h b/src/lib/trace/lttng/lttng.h
new file mode 100644
index 0000000000..8ede98bb02
--- /dev/null
+++ b/src/lib/trace/lttng/lttng.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file lttng.h
+ * \brief Header file for lttng.c.
+ **/
+
+#ifndef TOR_TRACE_LTTNG_LTTNG_H
+#define TOR_TRACE_LTTNG_LTTNG_H
+
+#ifdef USE_TRACING_INSTRUMENTATION_LTTNG
+
+#include <lttng/tracepoint.h>
+
+/* Map event to an LTTng tracepoint. */
+#define TOR_TRACE_LTTNG(subsystem, event_name, ...) \
+ tracepoint(subsystem, event_name, ## __VA_ARGS__)
+
+#else /* !defined(USE_TRACING_INSTRUMENTATION_LTTNG) */
+
+/* NOP event. */
+#define TOR_TRACE_LTTNG(subsystem, event_name, ...)
+
+#endif /* !defined(USE_TRACING_INSTRUMENTATION_LTTNG) */
+
+#endif /* TOR_TRACE_LTTNG_LTTNG_H */
+
diff --git a/src/lib/trace/trace.c b/src/lib/trace/trace.c
index 4e5c66b4c6..10d11c17c5 100644
--- a/src/lib/trace/trace.c
+++ b/src/lib/trace/trace.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,3 +15,9 @@ void
tor_trace_init(void)
{
}
+
+/** Free all the tracing library. */
+void
+tor_trace_free_all(void)
+{
+}
diff --git a/src/lib/trace/trace.h b/src/lib/trace/trace.h
index 5e24678c3c..22589dbe94 100644
--- a/src/lib/trace/trace.h
+++ b/src/lib/trace/trace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,9 +6,31 @@
* \brief Header for trace.c
**/
-#ifndef TOR_TRACE_TRACE_H
-#define TOR_TRACE_TRACE_H
+#ifndef TOR_LIB_TRACE_TRACE_H
+#define TOR_LIB_TRACE_TRACE_H
+
+#include "orconfig.h"
void tor_trace_init(void);
+void tor_trace_free_all(void);
+
+#ifdef HAVE_TRACING
+
+#include "lib/log/log.h"
+
+static inline void
+tracing_log_warning(void)
+{
+ log_warn(LD_GENERAL,
+ "Tracing capabilities have been built in. If this is NOT on "
+ "purpose, your tor is NOT safe to run.");
+}
+
+#else
+
+/* NOP it. */
+#define tracing_log_warning()
+
+#endif /* defined(HAVE_TRACING) */
-#endif /* !defined(TOR_TRACE_TRACE_H) */
+#endif /* !defined(TOR_LIB_TRACE_TRACE_H) */
diff --git a/src/lib/trace/trace_stub.c b/src/lib/trace/trace_stub.c
new file mode 100644
index 0000000000..9043efe360
--- /dev/null
+++ b/src/lib/trace/trace_stub.c
@@ -0,0 +1,19 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file trace_stub.c
+ * \brief Stub declaratinos for use when trace library is disabled.
+ **/
+
+#include "lib/subsys/subsys.h"
+
+#include "lib/trace/trace_sys.h"
+
+const subsys_fns_t sys_tracing = {
+ SUBSYS_DECLARE_LOCATION(),
+
+ .name = "tracing",
+ .supported = false,
+ .level = TRACE_SUBSYS_LEVEL,
+};
diff --git a/src/lib/trace/trace_sys.c b/src/lib/trace/trace_sys.c
new file mode 100644
index 0000000000..2ba0258407
--- /dev/null
+++ b/src/lib/trace/trace_sys.c
@@ -0,0 +1,36 @@
+/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file log_sys.c
+ * \brief Setup and tear down the tracing module.
+ **/
+
+#include "lib/subsys/subsys.h"
+
+#include "lib/trace/trace.h"
+#include "lib/trace/trace_sys.h"
+
+static int
+subsys_tracing_initialize(void)
+{
+ tor_trace_init();
+ return 0;
+}
+
+static void
+subsys_tracing_shutdown(void)
+{
+ tor_trace_free_all();
+}
+
+const subsys_fns_t sys_tracing = {
+ SUBSYS_DECLARE_LOCATION(),
+
+ .name = "tracing",
+ .supported = true,
+ .level = TRACE_SUBSYS_LEVEL,
+
+ .initialize = subsys_tracing_initialize,
+ .shutdown = subsys_tracing_shutdown,
+};
diff --git a/src/lib/trace/trace_sys.h b/src/lib/trace/trace_sys.h
new file mode 100644
index 0000000000..d4da5a9701
--- /dev/null
+++ b/src/lib/trace/trace_sys.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file log_sys.h
+ * \brief Declare subsystem object for the logging module.
+ **/
+
+#ifndef TOR_TRACE_SYS_H
+#define TOR_TRACE_SYS_H
+
+extern const struct subsys_fns_t sys_tracing;
+
+/**
+ * Subsystem level for the tracing system.
+ *
+ * Defined here so that it can be shared between the real and stub
+ * definitions.
+ **/
+#define TRACE_SUBSYS_LEVEL (-85)
+
+#endif /* !defined(TOR_TRACE_SYS_H) */
diff --git a/src/lib/trace/usdt/include.am b/src/lib/trace/usdt/include.am
new file mode 100644
index 0000000000..4e7e04c326
--- /dev/null
+++ b/src/lib/trace/usdt/include.am
@@ -0,0 +1,3 @@
+# ADD_C_FILE: INSERT HEADERS HERE.
+TRACEHEADERS += \
+ src/lib/trace/usdt/usdt.h
diff --git a/src/lib/trace/usdt/usdt.h b/src/lib/trace/usdt/usdt.h
new file mode 100644
index 0000000000..0b5fd6c444
--- /dev/null
+++ b/src/lib/trace/usdt/usdt.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file trace.h
+ * \brief Header for usdt.h
+ **/
+
+#ifndef TOR_TRACE_USDT_USDT_H
+#define TOR_TRACE_USDT_USDT_H
+
+#ifdef USE_TRACING_INSTRUMENTATION_USDT
+
+#ifdef HAVE_SYS_SDT_H
+#define SDT_USE_VARIADIC
+#include <sys/sdt.h>
+#define TOR_STAP_PROBEV STAP_PROBEV
+#else /* defined(HAVE_SYS_SDT_H) */
+#define TOR_STAP_PROBEV(...)
+#endif
+
+/* Map events to an USDT probe. */
+#define TOR_TRACE_USDT(subsystem, event_name, ...) \
+ TOR_STAP_PROBEV(subsystem, event_name, ## __VA_ARGS__);
+
+#else /* !defined(USE_TRACING_INSTRUMENTATION_USDT) */
+
+/* NOP event. */
+#define TOR_TRACE_USDT(subsystem, event_name, ...)
+
+#endif /* !defined(USE_TRACING_INSTRUMENTATION_USDT) */
+
+#endif /* !defined(TOR_TRACE_USDT_USDT_H) */
diff --git a/src/mainpage.md b/src/mainpage.md
index 2c4c494354..91ceb7dbf7 100644
--- a/src/mainpage.md
+++ b/src/mainpage.md
@@ -83,8 +83,9 @@ will be scheduled.
The codebase is divided into a few top-level subdirectories, each of
which contains several sub-modules.
- - `ext` -- Code maintained elsewhere that we include in the Tor
- source distribution.
+ - \refdir{ext} -- Code maintained elsewhere that we include in the Tor
+ source distribution. You should not edit this code if you can
+ avoid it: we try to keep it identical to the upstream versions.
- \refdir{lib} -- Lower-level utility code, not necessarily
tor-specific.
diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs
index 14170d0353..2bf8d3a987 100644
--- a/src/rust/protover/ffi.rs
+++ b/src/rust/protover/ffi.rs
@@ -84,7 +84,7 @@ pub extern "C" fn protocol_list_supports_protocol(
version: uint32_t,
) -> c_int {
if c_protocol_list.is_null() {
- return 1;
+ return 0;
}
// Require an unsafe block to read the version from a C string. The pointer
@@ -93,7 +93,7 @@ pub extern "C" fn protocol_list_supports_protocol(
let protocol_list = match c_str.to_str() {
Ok(n) => n,
- Err(_) => return 1,
+ Err(_) => return 0,
};
let proto_entry: UnvalidatedProtoEntry = match protocol_list.parse() {
Ok(n) => n,
@@ -140,7 +140,7 @@ pub extern "C" fn protocol_list_supports_protocol_or_later(
version: uint32_t,
) -> c_int {
if c_protocol_list.is_null() {
- return 1;
+ return 0;
}
// Require an unsafe block to read the version from a C string. The pointer
@@ -149,7 +149,7 @@ pub extern "C" fn protocol_list_supports_protocol_or_later(
let protocol_list = match c_str.to_str() {
Ok(n) => n,
- Err(_) => return 1,
+ Err(_) => return 0,
};
let protocol = match translate_to_rust(c_protocol) {
@@ -159,7 +159,7 @@ pub extern "C" fn protocol_list_supports_protocol_or_later(
let proto_entry: UnvalidatedProtoEntry = match protocol_list.parse() {
Ok(n) => n,
- Err(_) => return 1,
+ Err(_) => return 0,
};
if proto_entry.supports_protocol_or_later(&protocol.into(), &version) {
diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs
index 6d2ef33eec..550732734c 100644
--- a/src/rust/protover/protover.rs
+++ b/src/rust/protover/protover.rs
@@ -163,13 +163,13 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
DirCache=1-2 \
FlowCtrl=1 \
HSDir=1-2 \
- HSIntro=3-4 \
+ HSIntro=3-5 \
HSRend=1-2 \
Link=1-5 \
LinkAuth=3 \
Microdesc=1-2 \
Padding=2 \
- Relay=1-2"
+ Relay=1-3"
)
} else {
cstr!(
@@ -178,13 +178,13 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
DirCache=1-2 \
FlowCtrl=1 \
HSDir=1-2 \
- HSIntro=3-4 \
+ HSIntro=3-5 \
HSRend=1-2 \
Link=1-5 \
LinkAuth=1,3 \
Microdesc=1-2 \
Padding=2 \
- Relay=1-2"
+ Relay=1-3"
)
}
}
@@ -253,6 +253,11 @@ impl FromStr for ProtoEntry {
/// Otherwise, the `Err` value of this `Result` is a `ProtoverError`.
fn from_str(protocol_entry: &str) -> Result<ProtoEntry, ProtoverError> {
let mut proto_entry: ProtoEntry = ProtoEntry::default();
+
+ if protocol_entry.is_empty() {
+ return Ok(proto_entry);
+ }
+
let entries = protocol_entry.split(' ');
for entry in entries {
@@ -501,6 +506,10 @@ impl UnvalidatedProtoEntry {
) -> Result<Vec<(&'a str, &'a str)>, ProtoverError> {
let mut protovers: Vec<(&str, &str)> = Vec::new();
+ if protocol_string.is_empty() {
+ return Ok(protovers);
+ }
+
for subproto in protocol_string.split(' ') {
let mut parts = subproto.splitn(2, '=');
@@ -859,7 +868,8 @@ mod test {
#[test]
fn test_protoentry_from_str_empty() {
- assert_protoentry_is_unparseable!("");
+ assert_protoentry_is_parseable!("");
+ assert!(UnvalidatedProtoEntry::from_str("").is_ok());
}
#[test]
@@ -883,11 +893,6 @@ mod test {
}
#[test]
- fn test_protoentry_from_str_() {
- assert_protoentry_is_unparseable!("");
- }
-
- #[test]
fn test_protoentry_all_supported_single_protocol_single_version() {
let protocol: UnvalidatedProtoEntry = "Cons=1".parse().unwrap();
let unsupported: Option<UnvalidatedProtoEntry> = protocol.all_supported();
diff --git a/src/rust/protover/tests/protover.rs b/src/rust/protover/tests/protover.rs
index 942fe3c6ab..c97810a6f2 100644
--- a/src/rust/protover/tests/protover.rs
+++ b/src/rust/protover/tests/protover.rs
@@ -70,18 +70,6 @@ fn protocol_all_supported_with_one_value() {
}
#[test]
-#[should_panic]
-fn parse_protocol_unvalidated_with_empty() {
- let _: UnvalidatedProtoEntry = "".parse().unwrap();
-}
-
-#[test]
-#[should_panic]
-fn parse_protocol_validated_with_empty() {
- let _: UnvalidatedProtoEntry = "".parse().unwrap();
-}
-
-#[test]
fn protocol_all_supported_with_three_values() {
let protocols: UnvalidatedProtoEntry = "LinkAuth=1 Microdesc=1-2 Relay=2".parse().unwrap();
let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported();
@@ -156,7 +144,6 @@ fn parse_protocol_with_unexpected_characters() {
}
#[test]
-#[should_panic]
fn protover_compute_vote_returns_empty_for_empty_string() {
let protocols: &[UnvalidatedProtoEntry] = &["".parse().unwrap()];
let listed = ProtoverVote::compute(protocols, &1);
diff --git a/src/test/conf_examples/crypto_accel/expected_log_nss b/src/test/conf_examples/crypto_accel/expected_log_nss
index c0fe7b003c..bcbfa2cf6b 100644
--- a/src/test/conf_examples/crypto_accel/expected_log_nss
+++ b/src/test/conf_examples/crypto_accel/expected_log_nss
@@ -1 +1 @@
-Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, and Libzstd .*
+Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc
diff --git a/src/test/conf_examples/crypto_accel_req/expected_log_nss b/src/test/conf_examples/crypto_accel_req/expected_log_nss
index c0fe7b003c..bcbfa2cf6b 100644
--- a/src/test/conf_examples/crypto_accel_req/expected_log_nss
+++ b/src/test/conf_examples/crypto_accel_req/expected_log_nss
@@ -1 +1 @@
-Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, and Libzstd .*
+Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc
diff --git a/src/test/conf_examples/dirauth_3/error_no_dirauth b/src/test/conf_examples/dirauth_3/error_no_dirauth
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/error_no_dirauth
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/dirauth_3/error_no_dirauth_relay b/src/test/conf_examples/dirauth_3/error_no_dirauth_relay
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/dirauth_3/expected b/src/test/conf_examples/dirauth_3/expected
new file mode 100644
index 0000000000..23eac3a5f8
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/expected
@@ -0,0 +1,9 @@
+Address 192.0.2.1
+AuthoritativeDirectory 1
+ContactInfo tor_parse_test@example.net
+DirPort 192.0.2.1:2
+DownloadExtraInfo 1
+Nickname Unnamed
+ORPort 192.0.2.1:1
+ORPort [2001:DB8::1]:3
+V3AuthoritativeDirectory 1
diff --git a/src/test/conf_examples/dirauth_3/expected_log b/src/test/conf_examples/dirauth_3/expected_log
new file mode 100644
index 0000000000..3127c9b125
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/expected_log
@@ -0,0 +1 @@
+Read configuration file .*dirauth_3[./]*torrc
diff --git a/src/test/conf_examples/dirauth_3/torrc b/src/test/conf_examples/dirauth_3/torrc
new file mode 100644
index 0000000000..9663a9bc0c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/torrc
@@ -0,0 +1,13 @@
+# Authority with IPv6 address
+
+AuthoritativeDirectory 1
+V3AuthoritativeDirectory 1
+
+ContactInfo tor_parse_test@example.net
+
+Address 192.0.2.1
+
+ORPort 192.0.2.1:1
+DirPort 192.0.2.1:2
+
+ORPort [2001:DB8::1]:3
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log b/src/test/conf_examples/lzma_zstd_1/expected_log
index a5531ca21e..f143b23102 100644
--- a/src/test/conf_examples/lzma_zstd_1/expected_log
+++ b/src/test/conf_examples/lzma_zstd_1/expected_log
@@ -1 +1 @@
-Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma N/A, and Libzstd N/A
+Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma N/A, Libzstd N/A and .* .* as libc
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log_lzma b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma
index 2947e5991b..abb4731abc 100644
--- a/src/test/conf_examples/lzma_zstd_1/expected_log_lzma
+++ b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma
@@ -1 +1 @@
-Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma .*, and Libzstd N/A
+Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma .*, Libzstd N/A and .* .* as libc
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd
index e76e4357f8..b4e45772dd 100644
--- a/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd
+++ b/src/test/conf_examples/lzma_zstd_1/expected_log_lzma_zstd
@@ -1 +1 @@
-Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma .*, and Libzstd .* \ No newline at end of file
+Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc \ No newline at end of file
diff --git a/src/test/conf_examples/lzma_zstd_1/expected_log_zstd b/src/test/conf_examples/lzma_zstd_1/expected_log_zstd
index c8b174423b..994b46974b 100644
--- a/src/test/conf_examples/lzma_zstd_1/expected_log_zstd
+++ b/src/test/conf_examples/lzma_zstd_1/expected_log_zstd
@@ -1 +1 @@
-Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma N/A, and Libzstd .* \ No newline at end of file
+Tor 0.* running on .* with Libevent .*, .*, Zlib .*, Liblzma N/A, Libzstd .* and .* .* as libc \ No newline at end of file
diff --git a/src/test/conf_examples/nss_1/expected_log b/src/test/conf_examples/nss_1/expected_log
index 32e8cfc2f8..38f1febda5 100644
--- a/src/test/conf_examples/nss_1/expected_log
+++ b/src/test/conf_examples/nss_1/expected_log
@@ -1 +1 @@
-Tor 0.* running on .* with Libevent .*, OpenSSL .*, Zlib .*, Liblzma .*, and Libzstd .*
+Tor 0.* running on .* with Libevent .*, OpenSSL .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc
diff --git a/src/test/conf_examples/nss_1/expected_log_nss b/src/test/conf_examples/nss_1/expected_log_nss
index c0fe7b003c..bcbfa2cf6b 100644
--- a/src/test/conf_examples/nss_1/expected_log_nss
+++ b/src/test/conf_examples/nss_1/expected_log_nss
@@ -1 +1 @@
-Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, and Libzstd .*
+Tor 0.* running on .* with Libevent .*, NSS .*, Zlib .*, Liblzma .*, Libzstd .* and .* .* as libc
diff --git a/src/test/fuzz/include.am b/src/test/fuzz/include.am
index d0711f05d6..510ff35a3c 100644
--- a/src/test/fuzz/include.am
+++ b/src/test/fuzz/include.am
@@ -11,10 +11,10 @@ FUZZING_LIBS = \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
- @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@ \
@TOR_LZMA_LIBS@ \
- @TOR_ZSTD_LIBS@
+ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
oss-fuzz-prereqs: \
$(TOR_INTERNAL_TESTING_LIBS)
diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c
index 5116fc7169..e9aafa4760 100644
--- a/src/test/hs_test_helpers.c
+++ b/src/test/hs_test_helpers.c
@@ -75,7 +75,8 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
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,
+ ip->auth_key_cert = tor_cert_create_ed25519(signing_kp,
+ CERT_TYPE_AUTH_HS_IP_KEY,
&auth_kp.pubkey, now,
HS_DESC_CERT_LIFETIME,
CERT_FLAG_INCLUDE_SIGNING_KEY);
@@ -110,7 +111,8 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
}
ed25519_keypair_from_curve25519_keypair(&ed25519_kp, &signbit,
&curve25519_kp);
- cross_cert = tor_cert_create(signing_kp, CERT_TYPE_CROSS_HS_IP_KEYS,
+ cross_cert = tor_cert_create_ed25519(signing_kp,
+ CERT_TYPE_CROSS_HS_IP_KEYS,
&ed25519_kp.pubkey, time(NULL),
HS_DESC_CERT_LIFETIME,
CERT_FLAG_INCLUDE_SIGNING_KEY);
@@ -155,7 +157,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
sizeof(ed25519_public_key_t));
desc->plaintext_data.signing_key_cert =
- tor_cert_create(&blinded_kp, CERT_TYPE_SIGNING_HS_DESC,
+ tor_cert_create_ed25519(&blinded_kp, CERT_TYPE_SIGNING_HS_DESC,
&signing_kp->pubkey, now, 3600,
CERT_FLAG_INCLUDE_SIGNING_KEY);
tt_assert(desc->plaintext_data.signing_key_cert);
diff --git a/src/test/include.am b/src/test/include.am
index 7814dbca89..816eba894e 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -54,6 +54,7 @@ else
# Only do this when coverage is not on, since it invokes lots of code
# in a kind of unpredictable way.
TESTSCRIPTS += src/test/test_rebind.sh
+TESTSCRIPTS += src/test/test_include.sh
endif
endif
@@ -304,18 +305,17 @@ src_test_test_switch_id_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
-
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_USERENV@ \
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
src_test_test_LDADD = \
$(TOR_INTERNAL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_slow_CPPFLAGS = $(src_test_test_CPPFLAGS)
src_test_test_slow_CFLAGS = $(src_test_test_CFLAGS)
@@ -342,9 +342,9 @@ src_test_bench_LDADD = \
$(TOR_INTERNAL_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
@@ -352,9 +352,9 @@ src_test_test_workqueue_LDADD = \
$(TOR_INTERNAL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_timers_CPPFLAGS = $(src_test_test_CPPFLAGS)
src_test_test_timers_CFLAGS = $(src_test_test_CFLAGS)
@@ -364,9 +364,9 @@ src_test_test_timers_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
- @TOR_LZMA_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_TRACE_LIBS@
src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS)
# ADD_C_FILE: INSERT HEADERS HERE.
@@ -401,8 +401,8 @@ src_test_test_ntor_cl_LDADD = \
$(TOR_INTERNAL_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
- @CURVE25519_LIBS@ @TOR_LZMA_LIBS@
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @CURVE25519_LIBS@ @TOR_LZMA_LIBS@ @TOR_TRACE_LIBS@
src_test_test_ntor_cl_AM_CPPFLAGS = \
$(AM_CPPFLAGS)
@@ -411,7 +411,8 @@ src_test_test_hs_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB)
src_test_test_hs_ntor_cl_LDADD = \
$(TOR_INTERNAL_LIBS) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ \
+ @CURVE25519_LIBS@ @TOR_TRACE_LIBS@
src_test_test_hs_ntor_cl_AM_CPPFLAGS = \
$(AM_CPPFLAGS)
@@ -423,7 +424,8 @@ src_test_test_bt_cl_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_LIB_MATH@ \
- @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @TOR_TRACE_LIBS@
src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS)
endif
@@ -438,6 +440,8 @@ EXTRA_DIST += \
src/test/slownacl_curve25519.py \
src/test/test_rebind.sh \
src/test/test_rebind.py \
+ src/test/test_include.sh \
+ src/test/test_include.py \
src/test/zero_length_keys.sh \
scripts/maint/run_check_subsystem_order.sh \
src/test/rust_supp.txt \
diff --git a/src/test/rend_test_helpers.c b/src/test/rend_test_helpers.c
index 61bacb4d2e..8e40167aeb 100644
--- a/src/test/rend_test_helpers.c
+++ b/src/test/rend_test_helpers.c
@@ -2,6 +2,7 @@
/* See LICENSE for licensing information */
#include "core/or/or.h"
+#include "core/or/extendinfo.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "test/test.h"
#include "feature/rend/rendcommon.h"
@@ -58,7 +59,8 @@ create_descriptor(rend_service_descriptor_t **generated, char **service_id,
for (i = 0; i < intro_points; i++) {
rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t));
crypto_pk_t *okey = pk_generate(2 + i);
- intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
+ intro->extend_info =
+ extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
intro->extend_info->onion_key = okey;
crypto_pk_get_digest(intro->extend_info->onion_key,
intro->extend_info->identity_digest);
@@ -66,8 +68,12 @@ create_descriptor(rend_service_descriptor_t **generated, char **service_id,
base16_encode(intro->extend_info->nickname + 1,
sizeof(intro->extend_info->nickname) - 1,
intro->extend_info->identity_digest, DIGEST_LEN);
- tor_addr_from_ipv4h(&intro->extend_info->addr, crypto_rand_int(65536));
- intro->extend_info->port = 1 + crypto_rand_int(65535);
+ tor_addr_t addr;
+ uint16_t port;
+ /* Does not cover all IP addresses. */
+ tor_addr_from_ipv4h(&addr, crypto_rand_int(65536) + 1);
+ port = 1 + crypto_rand_int(65535);
+ extend_info_add_orport(intro->extend_info, &addr, port);
intro->intro_key = crypto_pk_dup_key(pk2);
smartlist_add((*generated)->intro_nodes, intro);
}
@@ -91,4 +97,3 @@ mock_rend_data(const char *onion_address)
DIGEST_LEN));
return rend_query;
}
-
diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c
index 4faf7bc5a1..5e4cc7678e 100644
--- a/src/test/test-memwipe.c
+++ b/src/test/test-memwipe.c
@@ -30,8 +30,8 @@ const char *s = NULL;
#define BUF_LEN 2048
#define FILL_BUFFER_IMPL() \
+ do { \
unsigned int i; \
- unsigned sum = 0; \
\
/* Fill up a 1k buffer with a recognizable pattern. */ \
for (i = 0; i < BUF_LEN; i += strlen(s)) { \
@@ -42,7 +42,8 @@ const char *s = NULL;
/* optimized away. */ \
for (i = 0; i < BUF_LEN; ++i) { \
sum += (unsigned char)buf[i]; \
- }
+ } \
+ } while (0)
#ifdef OpenBSD
/* Disable some of OpenBSD's malloc protections for this test. This helps
@@ -55,7 +56,8 @@ static unsigned
fill_a_buffer_memset(void)
{
char buf[BUF_LEN];
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
memset(buf, 0, sizeof(buf));
return sum;
}
@@ -64,7 +66,8 @@ static unsigned
fill_a_buffer_memwipe(void)
{
char buf[BUF_LEN];
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
memwipe(buf, 0, sizeof(buf));
return sum;
}
@@ -73,7 +76,8 @@ static unsigned
fill_a_buffer_nothing(void)
{
char buf[BUF_LEN];
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
return sum;
}
@@ -116,7 +120,8 @@ static unsigned
fill_heap_buffer_memset(void)
{
char *buf = heap_buf = raw_malloc(BUF_LEN);
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
memset(buf, 0, BUF_LEN);
raw_free(buf);
return sum;
@@ -126,7 +131,8 @@ static unsigned
fill_heap_buffer_memwipe(void)
{
char *buf = heap_buf = raw_malloc(BUF_LEN);
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
memwipe(buf, 0, BUF_LEN);
raw_free(buf);
return sum;
@@ -136,7 +142,8 @@ static unsigned
fill_heap_buffer_nothing(void)
{
char *buf = heap_buf = raw_malloc(BUF_LEN);
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
raw_free(buf);
return sum;
}
diff --git a/src/test/test.c b/src/test/test.c
index 4b6082ce4f..2961669c46 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+->a * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
@@ -44,6 +44,7 @@
#include "lib/compress/compress.h"
#include "app/config/config.h"
#include "core/or/connection_edge.h"
+#include "core/or/extendinfo.h"
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendcache.h"
#include "feature/rend/rendparse.h"
@@ -564,7 +565,8 @@ test_rend_fns(void *arg)
for (i = 0; i < 3; i++) {
rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t));
crypto_pk_t *okey = pk_generate(2 + i);
- intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
+ intro->extend_info =
+ extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
intro->extend_info->onion_key = okey;
crypto_pk_get_digest(intro->extend_info->onion_key,
intro->extend_info->identity_digest);
@@ -573,9 +575,12 @@ test_rend_fns(void *arg)
base16_encode(intro->extend_info->nickname + 1,
sizeof(intro->extend_info->nickname) - 1,
intro->extend_info->identity_digest, DIGEST_LEN);
+ tor_addr_t addr;
+ uint16_t port;
/* Does not cover all IP addresses. */
- tor_addr_from_ipv4h(&intro->extend_info->addr, crypto_rand_int(65536));
- intro->extend_info->port = 1 + crypto_rand_int(65535);
+ tor_addr_from_ipv4h(&addr, crypto_rand_int(65536) + 1);
+ port = 1 + crypto_rand_int(65535);
+ extend_info_add_orport(intro->extend_info, &addr, port);
intro->intro_key = crypto_pk_dup_key(pk2);
smartlist_add(generated->intro_nodes, intro);
}
@@ -613,8 +618,12 @@ test_rend_fns(void *arg)
tt_mem_op(gen_info->identity_digest,OP_EQ, par_info->identity_digest,
DIGEST_LEN);
tt_str_op(gen_info->nickname,OP_EQ, par_info->nickname);
- tt_assert(tor_addr_eq(&gen_info->addr, &par_info->addr));
- tt_int_op(gen_info->port,OP_EQ, par_info->port);
+ const tor_addr_port_t *a1, *a2;
+ a1 = extend_info_get_orport(gen_info, AF_INET);
+ a2 = extend_info_get_orport(par_info, AF_INET);
+ tt_assert(a1 && a2);
+ tt_assert(tor_addr_eq(&a1->addr, &a2->addr));
+ tt_int_op(a2->port,OP_EQ, a2->port);
}
rend_service_descriptor_free(parsed);
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index cf5aad7e71..dbc581288d 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -341,6 +341,7 @@ test_addr_ip6_helpers(void *arg)
test_pton6_bad("0XYXXY");
test_pton6_bad("0x");
test_pton6_bad("0X");
+ test_pton6_bad("2000::1a00::1000:fc098");
/* test internal checking */
test_external_ip("fbff:ffff::2:7", 0);
diff --git a/src/test/test_address.c b/src/test/test_address.c
index 4cedbda347..17479d69c2 100644
--- a/src/test/test_address.c
+++ b/src/test/test_address.c
@@ -1152,23 +1152,23 @@ test_address_tor_addr_in_same_network_family(void *ignored)
tor_addr_parse(&a, "8.8.8.8");
tor_addr_parse(&b, "8.8.4.4");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 1);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 1);
tor_addr_parse(&a, "8.8.8.8");
tor_addr_parse(&b, "1.1.1.1");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 0);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 0);
tor_addr_parse(&a, "8.8.8.8");
tor_addr_parse(&b, "2001:4860:4860::8844");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 0);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 0);
tor_addr_parse(&a, "2001:4860:4860::8888");
tor_addr_parse(&b, "2001:4860:4860::8844");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 1);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 1);
tor_addr_parse(&a, "2001:4860:4860::8888");
tor_addr_parse(&b, "2001:470:20::2");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 0);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 0);
done:
return;
@@ -1194,16 +1194,14 @@ helper_free_mock_node(node_t *node)
tor_free(node);
}
-#define NODE_SET_IPV4(node, ipv4_addr, ipv4_port) { \
- tor_addr_t addr; \
- tor_addr_parse(&addr, ipv4_addr); \
- node->ri->addr = tor_addr_to_ipv4h(&addr); \
- node->ri->or_port = ipv4_port; \
+#define NODE_SET_IPV4(node, ipv4_addr_str, ipv4_port) { \
+ tor_addr_parse(&(node)->ri->ipv4_addr, ipv4_addr_str); \
+ node->ri->ipv4_orport = ipv4_port; \
}
#define NODE_CLEAR_IPV4(node) { \
- node->ri->addr = 0; \
- node->ri->or_port = 0; \
+ tor_addr_make_unspec(&node->ri->ipv4_addr); \
+ node->ri->ipv4_orport = 0; \
}
#define NODE_SET_IPV6(node, ipv6_addr_str, ipv6_port) { \
@@ -1260,9 +1258,7 @@ mock_get_options(void)
#define TEST_ROUTER_VALID_ADDRESS_HELPER(ipv4_addr_str, ipv6_addr_str, rv) \
STMT_BEGIN \
ri = tor_malloc_zero(sizeof(routerinfo_t)); \
- tor_addr_t addr; \
- tor_addr_parse(&addr, (ipv4_addr_str)); \
- ri->addr = tor_addr_to_ipv4h(&addr); \
+ tor_addr_parse(&ri->ipv4_addr, (ipv4_addr_str)); \
tor_addr_parse(&ri->ipv6_addr, (ipv6_addr_str)); \
tt_int_op(dirserv_router_has_valid_address(ri), OP_EQ, (rv)); \
tor_free(ri); \
@@ -1320,7 +1316,7 @@ test_address_dirserv_router_addr_private(void *opt_dir_allow_private)
/* IPv6 null succeeds, because IPv4 is not internal */
{
ri = tor_malloc_zero(sizeof(routerinfo_t));
- ri->addr = 16777217; /* 1.0.0.1 */
+ tor_addr_parse(&ri->ipv4_addr, "1.0.0.1");
tt_int_op(dirserv_router_has_valid_address(ri), OP_EQ, 0);
tor_free(ri);
}
diff --git a/src/test/test_address_set.c b/src/test/test_address_set.c
index 829ecd79e8..3fee322c47 100644
--- a/src/test/test_address_set.c
+++ b/src/test/test_address_set.c
@@ -114,7 +114,6 @@ test_nodelist(void *arg)
tor_addr_t addr_v4, addr_v6, dummy_addr;
tor_addr_parse(&addr_v4, "42.42.42.42");
- uint32_t ipv4h = tor_addr_to_ipv4h(&addr_v4);
tor_addr_parse(&addr_v6, "1:2:3:4::");
memset(&dummy_addr, 'A', sizeof(dummy_addr));
@@ -148,9 +147,9 @@ test_nodelist(void *arg)
memcpy(rs->descriptor_digest, md->digest, DIGEST256_LEN);
/* Setup the rs, ri and md addresses. */
- rs->addr = ipv4h;
+ tor_addr_copy(&rs->ipv4_addr, &addr_v4);
tor_addr_parse(&rs->ipv6_addr, "1:2:3:4::");
- ri->addr = ipv4h;
+ tor_addr_copy(&ri->ipv4_addr, &addr_v4);
tor_addr_parse(&ri->ipv6_addr, "1:2:3:4::");
tor_addr_parse(&md->ipv6_addr, "1:2:3:4::");
diff --git a/src/test/test_bridges.c b/src/test/test_bridges.c
index f1624a529d..1942a8cb89 100644
--- a/src/test/test_bridges.c
+++ b/src/test/test_bridges.c
@@ -592,8 +592,12 @@ test_bridges_get_transport_by_bridge_addrport(void *arg)
static void
test_bridges_node_is_a_configured_bridge(void *arg)
{
- routerinfo_t ri_ipv4 = { .addr = 0x06060606, .or_port = 6666 };
- routerstatus_t rs_ipv4 = { .addr = 0x06060606, .or_port = 6666 };
+
+ routerinfo_t ri_ipv4 = { .ipv4_orport = 6666 };
+ tor_addr_parse(&ri_ipv4.ipv4_addr, "6.6.6.6");
+
+ routerstatus_t rs_ipv4 = { .ipv4_orport = 6666 };
+ tor_addr_parse(&rs_ipv4.ipv4_addr, "6.6.6.6");
routerinfo_t ri_ipv6 = { .ipv6_orport = 6666 };
tor_addr_parse(&(ri_ipv6.ipv6_addr),
@@ -632,8 +636,8 @@ test_bridges_node_is_a_configured_bridge(void *arg)
/* It won't match bridge1, though, since bridge1 has a digest, and this
isn't it! */
- node_ri_ipv4.ri->addr = 0x06060607;
- node_ri_ipv4.ri->or_port = 6667;
+ tor_addr_parse(&node_ri_ipv4.ri->ipv4_addr, "6.6.6.7");
+ node_ri_ipv4.ri->ipv4_orport = 6667;
tt_assert(! node_is_a_configured_bridge(&node_ri_ipv4));
/* If we set the fingerprint right, though, it will match. */
base16_decode(node_ri_ipv4.identity, DIGEST_LEN,
diff --git a/src/test/test_bwmgt.c b/src/test/test_bwmgt.c
index 117783cafc..4cf83e45d0 100644
--- a/src/test/test_bwmgt.c
+++ b/src/test/test_bwmgt.c
@@ -317,8 +317,8 @@ test_bwmgt_dir_conn_global_write_low(void *arg)
memcpy(rs->descriptor_digest, md->digest, DIGEST256_LEN);
/* Set IP address. */
- rs->addr = tor_addr_to_ipv4h(&relay_addr);
- ri->addr = rs->addr;
+ tor_addr_copy(&rs->ipv4_addr, &relay_addr);
+ tor_addr_copy(&ri->ipv4_addr, &rs->ipv4_addr);
/* Add the rs to the consensus becoming a node_t. */
smartlist_add(dummy_ns->routerstatus_list, rs);
diff --git a/src/test/test_channel.c b/src/test/test_channel.c
index 83b69cc80b..042eb27d9d 100644
--- a/src/test/test_channel.c
+++ b/src/test/test_channel.c
@@ -16,6 +16,10 @@
/* For packed_cell stuff */
#define RELAY_PRIVATE
#include "core/or/relay.h"
+/* For channel_tls_t object and private functions. */
+#define CHANNEL_OBJECT_PRIVATE
+#define CHANNELTLS_PRIVATE
+#include "core/or/channeltls.h"
/* For init/free stuff */
#include "core/or/scheduler.h"
#include "feature/nodelist/networkstatus.h"
@@ -25,6 +29,8 @@
#include "core/or/origin_circuit_st.h"
#include "feature/nodelist/routerstatus_st.h"
#include "core/or/var_cell_st.h"
+#include "core/or/or_connection_st.h"
+#include "lib/net/inaddr.h"
/* Test suite stuff */
#include "test/log_test_helpers.h"
@@ -156,16 +162,23 @@ chan_test_finish_close(channel_t *ch)
}
static const char *
-chan_test_get_remote_descr(channel_t *ch, int flags)
+chan_test_describe_peer(const channel_t *ch)
{
tt_assert(ch);
- tt_int_op(flags & ~(GRD_FLAG_ORIGINAL | GRD_FLAG_ADDR_ONLY), OP_EQ, 0);
done:
return "Fake channel for unit tests; no real endpoint";
}
static int
+chan_test_get_remote_addr(const channel_t *ch, tor_addr_t *out)
+{
+ (void)ch;
+ tor_addr_from_ipv4h(out, 0x7f000001);
+ return 1;
+}
+
+static int
chan_test_num_cells_writeable(channel_t *ch)
{
tt_assert(ch);
@@ -261,7 +274,8 @@ new_fake_channel(void)
chan->close = chan_test_close;
chan->num_cells_writeable = chan_test_num_cells_writeable;
- chan->get_remote_descr = chan_test_get_remote_descr;
+ chan->describe_peer = chan_test_describe_peer;
+ chan->get_remote_addr = chan_test_get_remote_addr;
chan->write_packed_cell = chan_test_write_packed_cell;
chan->write_var_cell = chan_test_write_var_cell;
chan->state = CHANNEL_STATE_OPEN;
@@ -1535,6 +1549,54 @@ test_channel_listener(void *arg)
channel_free_all();
}
+#define TEST_SETUP_MATCHES_ADDR(orcon, addr, src, rv) STMT_BEGIN \
+ rv = tor_inet_pton(addr.family, src, &addr.addr); \
+ tt_int_op(rv, OP_EQ, 1); \
+ orcon->base_.addr = addr; \
+ STMT_END;
+
+#define TEST_MATCHES_ADDR(chan, addr4, addr6, rv, exp) STMT_BEGIN \
+ rv = channel_matches_target_addr_for_extend(chan, addr4, addr6); \
+ tt_int_op(rv, OP_EQ, exp); \
+ STMT_END;
+
+static void
+test_channel_matches_target_addr_for_extend(void *arg)
+{
+ (void) arg;
+
+ channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan));
+ or_connection_t *orcon = tor_malloc_zero(sizeof(*orcon));
+ channel_t *chan = &(tlschan->base_);
+ tor_addr_t addr;
+ int rv;
+
+ tlschan->conn = orcon;
+ channel_tls_common_init(tlschan);
+
+ /* Test for IPv4 addresses. */
+ addr.family = AF_INET;
+ TEST_SETUP_MATCHES_ADDR(orcon, addr, "1.2.3.4", rv);
+ TEST_MATCHES_ADDR(chan, &addr, NULL, rv, 1);
+
+ tor_inet_pton(addr.family, "2.5.3.4", &addr.addr);
+ TEST_MATCHES_ADDR(chan, &addr, NULL, rv, 0);
+
+ /* Test for IPv6 addresses. */
+ addr.family = AF_INET6;
+ TEST_SETUP_MATCHES_ADDR(orcon, addr, "3:4:7:1:9:8:09:10", rv);
+ TEST_MATCHES_ADDR(chan, NULL, &addr, rv, 1);
+
+ tor_inet_pton(addr.family, "::", &addr.addr);
+ TEST_MATCHES_ADDR(chan, NULL, &addr, rv, 0);
+
+ done:
+ circuitmux_clear_policy(chan->cmux);
+ circuitmux_free(chan->cmux);
+ tor_free(orcon);
+ tor_free(tlschan);
+}
+
struct testcase_t channel_tests[] = {
{ "inbound_cell", test_channel_inbound_cell, TT_FORK,
NULL, NULL },
@@ -1556,5 +1618,7 @@ struct testcase_t channel_tests[] = {
NULL, NULL },
{ "listener", test_channel_listener, TT_FORK,
NULL, NULL },
+ { "matches_target", test_channel_matches_target_addr_for_extend, TT_FORK,
+ NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c
index f4f5cb447e..0227779e8b 100644
--- a/src/test/test_channeltls.c
+++ b/src/test/test_channeltls.c
@@ -38,13 +38,13 @@ static or_connection_t * tlschan_connection_or_connect_mock(
const char *digest,
const ed25519_public_key_t *ed_id,
channel_tls_t *tlschan);
-static int tlschan_is_local_addr_mock(const tor_addr_t *addr);
+static bool tlschan_resolved_addr_is_local_mock(const tor_addr_t *addr);
/* Fake close method */
static void tlschan_fake_close_method(channel_t *chan);
/* Flags controlling behavior of channeltls unit test mocks */
-static int tlschan_local = 0;
+static bool tlschan_local = false;
static const buf_t * tlschan_buf_datalen_mock_target = NULL;
static size_t tlschan_buf_datalen_mock_size = 0;
@@ -67,9 +67,9 @@ test_channeltls_create(void *arg)
test_addr.addr.in_addr.s_addr = htonl(0x01020304);
/* For this test we always want the address to be treated as non-local */
- tlschan_local = 0;
- /* Install is_local_addr() mock */
- MOCK(is_local_addr, tlschan_is_local_addr_mock);
+ tlschan_local = false;
+ /* Install is_local_to_resolve_addr() mock */
+ MOCK(is_local_to_resolve_addr, tlschan_resolved_addr_is_local_mock);
/* Install mock for connection_or_connect() */
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
@@ -92,7 +92,7 @@ test_channeltls_create(void *arg)
}
UNMOCK(connection_or_connect);
- UNMOCK(is_local_addr);
+ UNMOCK(is_local_to_resolve_addr);
return;
}
@@ -116,9 +116,9 @@ test_channeltls_num_bytes_queued(void *arg)
test_addr.addr.in_addr.s_addr = htonl(0x01020304);
/* For this test we always want the address to be treated as non-local */
- tlschan_local = 0;
- /* Install is_local_addr() mock */
- MOCK(is_local_addr, tlschan_is_local_addr_mock);
+ tlschan_local = false;
+ /* Install is_local_to_resolve_addr() mock */
+ MOCK(is_local_to_resolve_addr, tlschan_resolved_addr_is_local_mock);
/* Install mock for connection_or_connect() */
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
@@ -178,7 +178,7 @@ test_channeltls_num_bytes_queued(void *arg)
}
UNMOCK(connection_or_connect);
- UNMOCK(is_local_addr);
+ UNMOCK(is_local_to_resolve_addr);
return;
}
@@ -201,9 +201,9 @@ test_channeltls_overhead_estimate(void *arg)
test_addr.addr.in_addr.s_addr = htonl(0x01020304);
/* For this test we always want the address to be treated as non-local */
- tlschan_local = 0;
- /* Install is_local_addr() mock */
- MOCK(is_local_addr, tlschan_is_local_addr_mock);
+ tlschan_local = false;
+ /* Install is_local_to_resolve_addr() mock */
+ MOCK(is_local_to_resolve_addr, tlschan_resolved_addr_is_local_mock);
/* Install mock for connection_or_connect() */
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
@@ -252,7 +252,7 @@ test_channeltls_overhead_estimate(void *arg)
}
UNMOCK(connection_or_connect);
- UNMOCK(is_local_addr);
+ UNMOCK(is_local_to_resolve_addr);
return;
}
@@ -293,7 +293,7 @@ tlschan_connection_or_connect_mock(const tor_addr_t *addr,
result->base_.port = port;
memcpy(result->identity_digest, digest, DIGEST_LEN);
result->chan = tlschan;
- memcpy(&(result->real_addr), addr, sizeof(tor_addr_t));
+ memcpy(&result->base_.addr, addr, sizeof(tor_addr_t));
result->tls = (tor_tls_t *)((void *)(&fake_tortls));
done:
@@ -321,8 +321,8 @@ tlschan_fake_close_method(channel_t *chan)
return;
}
-static int
-tlschan_is_local_addr_mock(const tor_addr_t *addr)
+static bool
+tlschan_resolved_addr_is_local_mock(const tor_addr_t *addr)
{
tt_ptr_op(addr, OP_NE, NULL);
diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c
index 03fd176ead..74824a1bc1 100644
--- a/src/test/test_circuitbuild.c
+++ b/src/test/test_circuitbuild.c
@@ -19,6 +19,7 @@
#include "core/or/channel.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
+#include "core/or/circuituse.h"
#include "core/or/onion.h"
#include "core/or/cell_st.h"
@@ -29,11 +30,13 @@
#include "feature/client/entrynodes.h"
#include "feature/nodelist/nodelist.h"
+#include "feature/nodelist/node_select.h"
#include "feature/relay/circuitbuild_relay.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/nodelist/node_st.h"
+#include "feature/nodelist/routerinfo_st.h"
/* Dummy nodes smartlist for testing */
static smartlist_t dummy_nodes;
@@ -279,10 +282,10 @@ mock_node_get_by_id(const char *identity_digest)
return mocked_node;
}
-static int mocked_supports_ed25519_link_authentication = 0;
-static int
+static bool mocked_supports_ed25519_link_authentication = 0;
+static bool
mock_node_supports_ed25519_link_authentication(const node_t *node,
- int compatible_with_us)
+ bool compatible_with_us)
{
(void)node;
(void)compatible_with_us;
@@ -821,6 +824,75 @@ test_circuit_extend_lspec_valid(void *arg)
tor_free(p_chan);
}
+#define NODE_SET_IPV4(node, ipv4_addr_str, ipv4_port) { \
+ tor_addr_parse(&node->ri->ipv4_addr, ipv4_addr_str); \
+ node->ri->ipv4_orport = ipv4_port; \
+ }
+
+#define NODE_CLEAR_IPV4(node) { \
+ tor_addr_make_unspec(&node->ri->ipv4_addr); \
+ node->ri->ipv4_orport = 0; \
+ }
+
+#define NODE_SET_IPV6(node, ipv6_addr_str, ipv6_port) { \
+ tor_addr_parse(&node->ri->ipv6_addr, ipv6_addr_str); \
+ node->ri->ipv6_orport = ipv6_port; \
+ }
+
+/* Test the different cases in circuit_extend_add_ed25519_helper(). */
+static void
+test_circuit_extend_add_ip(void *arg)
+{
+ (void) arg;
+ tor_addr_t ipv4_tmp;
+ extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
+ extend_cell_t *old_ec = tor_malloc_zero(sizeof(extend_cell_t));
+
+ node_t *fake_node = tor_malloc_zero(sizeof(node_t));
+ routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t));
+
+ MOCK(node_get_by_id, mock_node_get_by_id);
+
+ /* Set up the fake variables for the IPv4 test */
+ fake_node->ri = ri;
+ mocked_node = fake_node;
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ NODE_SET_IPV4(fake_node, PUBLIC_IPV4, VALID_PORT);
+
+ /* Do the IPv4 test */
+ tt_int_op(circuit_extend_add_ipv4_helper(ec), OP_EQ, 0);
+ tor_addr_copy(&ipv4_tmp, &fake_node->ri->ipv4_addr);
+ /* The IPv4 should match */
+ tt_int_op(tor_addr_compare(&ec->orport_ipv4.addr, &ipv4_tmp, CMP_SEMANTIC),
+ OP_EQ, 0);
+ tt_int_op(ec->orport_ipv4.port, OP_EQ, VALID_PORT);
+
+ /* Set up the fake variables for the IPv6 test */
+ memcpy(ec, old_ec, sizeof(extend_cell_t));
+ NODE_CLEAR_IPV4(fake_node);
+ NODE_SET_IPV6(fake_node, PUBLIC_IPV6, VALID_PORT);
+
+ /* Do the IPv6 test */
+ tt_int_op(circuit_extend_add_ipv6_helper(ec), OP_EQ, 0);
+ /* The IPv6 should match */
+ tt_int_op(tor_addr_compare(&ec->orport_ipv6.addr, &fake_node->ri->ipv6_addr,
+ CMP_SEMANTIC), OP_EQ, 0);
+ tt_int_op(ec->orport_ipv6.port, OP_EQ, VALID_PORT);
+
+ /* Cleanup */
+ mocked_node = NULL;
+
+ done:
+ UNMOCK(node_get_by_id);
+
+ tor_free(ec);
+ tor_free(old_ec);
+
+ tor_free(ri);
+ tor_free(fake_node);
+}
+
static bool can_extend_over_ipv6_result = false;
static int mock_router_can_extend_over_ipv6_calls = 0;
static bool
@@ -927,15 +999,9 @@ mock_circuit_mark_for_close_(circuit_t *circ, int reason,
static int mock_channel_connect_calls = 0;
static channel_t *mock_channel_connect_nchan = NULL;
static channel_t *
-mock_channel_connect_for_circuit(const tor_addr_t *addr,
- uint16_t port,
- const char *id_digest,
- const struct ed25519_public_key_t *ed_id)
+mock_channel_connect_for_circuit(const extend_info_t *ei)
{
- (void)addr;
- (void)port;
- (void)id_digest;
- (void)ed_id;
+ (void)ei;
mock_channel_connect_calls++;
return mock_channel_connect_nchan;
}
@@ -1176,6 +1242,8 @@ mock_channel_get_canonical_remote_descr(channel_t *chan)
return "mock_channel_get_canonical_remote_descr()";
}
+/* Should mock_circuit_deliver_create_cell() expect a direct connection? */
+static bool mock_circuit_deliver_create_cell_expect_direct = false;
static int mock_circuit_deliver_create_cell_calls = 0;
static int mock_circuit_deliver_create_cell_result = 0;
static int
@@ -1188,10 +1256,13 @@ mock_circuit_deliver_create_cell(circuit_t *circ,
/* circuit_deliver_create_cell() requires non-NULL arguments,
* but we only check circ and circ->n_chan here. */
tt_ptr_op(circ, OP_NE, NULL);
- tt_ptr_op(circ->n_chan, OP_NE, NULL);
+ /* We expect n_chan for relayed cells. But should we also expect it for
+ * direct connections? */
+ if (!mock_circuit_deliver_create_cell_expect_direct)
+ tt_ptr_op(circ->n_chan, OP_NE, NULL);
/* We should only ever get relayed cells from extends */
- tt_int_op(relayed, OP_EQ, 1);
+ tt_int_op(relayed, OP_EQ, !mock_circuit_deliver_create_cell_expect_direct);
mock_circuit_deliver_create_cell_calls++;
return mock_circuit_deliver_create_cell_result;
@@ -1215,7 +1286,7 @@ test_circuit_extend(void *arg)
MOCK(server_mode, mock_server_mode);
/* Mock a debug function, but otherwise ignore it */
- MOCK(channel_get_canonical_remote_descr,
+ MOCK(channel_describe_peer,
mock_channel_get_canonical_remote_descr);
setup_full_capture_of_logs(LOG_INFO);
@@ -1352,6 +1423,7 @@ test_circuit_extend(void *arg)
/* Mock circuit_deliver_create_cell(), so it doesn't crash */
mock_circuit_deliver_create_cell_calls = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
MOCK(circuit_deliver_create_cell, mock_circuit_deliver_create_cell);
/* Test circuit established, re-using channel, successful delivery */
@@ -1407,7 +1479,7 @@ test_circuit_extend(void *arg)
UNMOCK(server_mode);
server = 0;
- UNMOCK(channel_get_canonical_remote_descr);
+ UNMOCK(channel_describe_peer);
UNMOCK(extend_cell_parse);
memset(&mock_extend_cell_parse_cell_out, 0,
@@ -1516,6 +1588,355 @@ test_onionskin_answer(void *arg)
tor_free(or_circ);
}
+/* Test the different cases in origin_circuit_init(). */
+static void
+test_origin_circuit_init(void *arg)
+{
+ (void)arg;
+ origin_circuit_t *origin_circ = NULL;
+
+ /* Init with 0 purpose and 0 flags */
+ origin_circ = origin_circuit_init(0, 0);
+ tt_int_op(origin_circ->base_.purpose, OP_EQ, 0);
+ tt_int_op(origin_circ->base_.state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+ /* The circuits are automatically freed by the circuitlist. */
+
+ /* Init with a purpose */
+ origin_circ = origin_circuit_init(CIRCUIT_PURPOSE_C_GENERAL, 0);
+ tt_int_op(origin_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL);
+
+ /* Init with each flag */
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_IS_INTERNAL);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 1);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_IS_IPV6_SELFTEST);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 1);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_NEED_CAPACITY);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 1);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_NEED_UPTIME);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 1);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_ONEHOP_TUNNEL);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 1);
+
+ done:
+ /* The circuits are automatically freed by the circuitlist. */
+ ;
+}
+
+/* Test the different cases in circuit_send_next_onion_skin(). */
+static void
+test_circuit_send_next_onion_skin(void *arg)
+{
+ (void)arg;
+ origin_circuit_t *origin_circ = NULL;
+ struct timeval circ_start_time;
+ memset(&circ_start_time, 0, sizeof(circ_start_time));
+
+ extend_info_t fakehop;
+ memset(&fakehop, 0, sizeof(fakehop));
+ extend_info_t *single_fakehop = &fakehop;
+ extend_info_t *multi_fakehop[DEFAULT_ROUTE_LEN] = {&fakehop,
+ &fakehop,
+ &fakehop};
+
+ extend_info_t ipv6_hop;
+ memset(&ipv6_hop, 0, sizeof(ipv6_hop));
+ tor_addr_parse(&ipv6_hop.orports[0].addr, "1::2");
+ extend_info_t *multi_ipv6_hop[DEFAULT_ROUTE_LEN] = {&ipv6_hop,
+ &ipv6_hop,
+ &ipv6_hop};
+
+ extend_info_t ipv4_hop;
+ memset(&ipv4_hop, 0, sizeof(ipv4_hop));
+ tor_addr_from_ipv4h(&ipv4_hop.orports[0].addr, 0x20304050);
+ extend_info_t *multi_ipv4_hop[DEFAULT_ROUTE_LEN] = {&ipv4_hop,
+ &ipv4_hop,
+ &ipv4_hop};
+
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ MOCK(circuit_deliver_create_cell, mock_circuit_deliver_create_cell);
+ server = 0;
+ MOCK(server_mode, mock_server_mode);
+
+ /* Try a direct connection, and succeed on a client */
+ server = 0;
+ origin_circ = new_test_origin_circuit(false,
+ circ_start_time,
+ 1,
+ &single_fakehop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ /* Skip some of the multi-hop checks */
+ origin_circ->build_state->onehop_tunnel = 1;
+ /* This is a direct connection */
+ mock_circuit_deliver_create_cell_expect_direct = true;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ, 0);
+ /* The circuits are automatically freed by the circuitlist. */
+
+ /* Try a direct connection, and succeed on a server */
+ server = 1;
+ origin_circ = new_test_origin_circuit(false,
+ circ_start_time,
+ 1,
+ &single_fakehop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->build_state->onehop_tunnel = 1;
+ mock_circuit_deliver_create_cell_expect_direct = true;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ, 0);
+
+ /* Start capturing bugs */
+ setup_full_capture_of_logs(LOG_WARN);
+ tor_capture_bugs_(1);
+
+ /* Try an extend, but fail the client valid address family check */
+ server = 0;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_fakehop),
+ multi_fakehop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ /* Fix the state */
+ origin_circ->base_.state = 0;
+ /* This is an indirect connection */
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ /* Fail because the address family is invalid */
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("No supported address family found in extend_info.\n");
+ mock_clean_saved_logs();
+
+ /* Try an extend, but fail the server valid address check */
+ server = 1;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_fakehop),
+ multi_fakehop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("No supported address family found in extend_info.\n");
+ mock_clean_saved_logs();
+
+ /* Try an extend, but fail in the client code, with an IPv6 address */
+ server = 0;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_ipv6_hop),
+ multi_ipv6_hop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("No supported address family found in extend_info.\n");
+ mock_clean_saved_logs();
+
+ /* Stop capturing bugs, but keep capturing logs */
+ tor_end_capture_bugs_();
+
+ /* Try an extend, pass the client IPv4 check, but fail later */
+ server = 0;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_ipv4_hop),
+ multi_ipv4_hop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ /* Fail because the circuit data is invalid */
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("onion_skin_create failed.\n");
+ mock_clean_saved_logs();
+
+ /* Try an extend, pass the server IPv4 check, but fail later */
+ server = 1;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_ipv4_hop),
+ multi_ipv4_hop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("onion_skin_create failed.\n");
+ mock_clean_saved_logs();
+
+ /* Try an extend, pass the server IPv6 check, but fail later */
+ server = 1;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_ipv6_hop),
+ multi_ipv6_hop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("onion_skin_create failed.\n");
+ mock_clean_saved_logs();
+
+ /* Things we're not testing right now:
+ * - the addresses in the extend cell inside
+ * circuit_send_intermediate_onion_skin() matches the address in the
+ * supplied extend_info.
+ * - valid circuit data.
+ * - actually extending the circuit to each hop. */
+
+ done:
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ teardown_capture_of_logs();
+
+ UNMOCK(circuit_deliver_create_cell);
+ UNMOCK(server_mode);
+ server = 0;
+
+ /* The circuits are automatically freed by the circuitlist. */
+}
+
+/* Test the different cases in cpath_build_state_to_crn_flags(). */
+static void
+test_cpath_build_state_to_crn_flags(void *arg)
+{
+ (void)arg;
+
+ cpath_build_state_t state;
+ memset(&state, 0, sizeof(state));
+
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ 0);
+
+ memset(&state, 0, sizeof(state));
+ state.need_uptime = 1;
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ CRN_NEED_UPTIME);
+
+ memset(&state, 0, sizeof(state));
+ state.need_capacity = 1;
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ CRN_NEED_CAPACITY);
+
+ memset(&state, 0, sizeof(state));
+ state.need_capacity = 1;
+ state.need_uptime = 1;
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ CRN_NEED_CAPACITY | CRN_NEED_UPTIME);
+
+ /* Check that no other flags are handled */
+ memset(&state, 0xff, sizeof(state));
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ CRN_NEED_CAPACITY | CRN_NEED_UPTIME);
+
+ done:
+ ;
+}
+
+/* Test the different cases in cpath_build_state_to_crn_ipv6_extend_flag(). */
+static void
+test_cpath_build_state_to_crn_ipv6_extend_flag(void *arg)
+{
+ (void)arg;
+
+ cpath_build_state_t state;
+
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = DEFAULT_ROUTE_LEN;
+ tt_int_op(cpath_build_state_to_crn_ipv6_extend_flag(&state, 0), OP_EQ,
+ 0);
+
+ /* Pass the state flag check, but not the length check */
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = DEFAULT_ROUTE_LEN;
+ state.is_ipv6_selftest = 1;
+ tt_int_op(cpath_build_state_to_crn_ipv6_extend_flag(&state, 0), OP_EQ,
+ 0);
+
+ /* Pass the length check, but not the state flag check */
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = DEFAULT_ROUTE_LEN;
+ tt_int_op(
+ cpath_build_state_to_crn_ipv6_extend_flag(&state,
+ DEFAULT_ROUTE_LEN - 2),
+ OP_EQ, 0);
+
+ /* Pass both checks */
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = DEFAULT_ROUTE_LEN;
+ state.is_ipv6_selftest = 1;
+ tt_int_op(
+ cpath_build_state_to_crn_ipv6_extend_flag(&state,
+ DEFAULT_ROUTE_LEN - 2),
+ OP_EQ, CRN_INITIATE_IPV6_EXTEND);
+
+ /* Check that no other flags are handled */
+ memset(&state, 0xff, sizeof(state));
+ state.desired_path_len = INT_MAX;
+ tt_int_op(cpath_build_state_to_crn_ipv6_extend_flag(&state, INT_MAX), OP_EQ,
+ 0);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Start capturing bugs */
+ setup_full_capture_of_logs(LOG_INFO);
+ tor_capture_bugs_(1);
+
+ /* Now test the single hop circuit case */
+#define SINGLE_HOP_ROUTE_LEN 1
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = SINGLE_HOP_ROUTE_LEN;
+ state.is_ipv6_selftest = 1;
+ tt_int_op(
+ cpath_build_state_to_crn_ipv6_extend_flag(&state,
+ SINGLE_HOP_ROUTE_LEN - 2),
+ OP_EQ, 0);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(state->desired_path_len < 2))");
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ done:
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ teardown_capture_of_logs();
+}
+
#define TEST(name, flags, setup, cleanup) \
{ #name, test_ ## name, flags, setup, cleanup }
@@ -1525,6 +1946,9 @@ test_onionskin_answer(void *arg)
#define TEST_CIRCUIT(name, flags) \
{ #name, test_circuit_ ## name, flags, NULL, NULL }
+#define TEST_CPATH(name, flags) \
+ { #name, test_cpath_ ## name, flags, NULL, NULL }
+
#ifndef COCCI
#define TEST_CIRCUIT_PASSTHROUGH(name, flags, arg) \
{ #name "/" arg, test_circuit_ ## name, flags, \
@@ -1542,13 +1966,21 @@ struct testcase_t circuitbuild_tests[] = {
TEST_CIRCUIT(extend_state_valid, TT_FORK),
TEST_CIRCUIT(extend_add_ed25519, TT_FORK),
TEST_CIRCUIT(extend_lspec_valid, TT_FORK),
+ TEST_CIRCUIT(extend_add_ip, TT_FORK),
TEST_CIRCUIT(choose_ip_ap_for_extend, 0),
+
TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "4"),
TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "6"),
TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "dual-stack"),
+
TEST_CIRCUIT(extend, TT_FORK),
TEST(onionskin_answer, TT_FORK, NULL, NULL),
+ TEST(origin_circuit_init, TT_FORK, NULL, NULL),
+ TEST_CIRCUIT(send_next_onion_skin, TT_FORK),
+ TEST_CPATH(build_state_to_crn_flags, 0),
+ TEST_CPATH(build_state_to_crn_ipv6_extend_flag, TT_FORK),
+
END_OF_TESTCASES
};
diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c
index cfb24c032c..c3346e2e03 100644
--- a/src/test/test_circuitpadding.c
+++ b/src/test/test_circuitpadding.c
@@ -23,6 +23,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitpadding.h"
#include "core/or/circuitpadding_machines.h"
+#include "core/or/extendinfo.h"
#include "core/mainloop/netstatus.h"
#include "core/crypto/relay_crypto.h"
#include "core/or/protover.h"
@@ -1361,7 +1362,7 @@ test_circuitpadding_wronghop(void *arg)
/* 5. Test that asking to stop the wrong machine does nothing */
circpad_negotiate_padding(TO_ORIGIN_CIRCUIT(client_side),
- 255, 2, CIRCPAD_COMMAND_STOP);
+ 255, 2, CIRCPAD_COMMAND_STOP, 0);
tt_ptr_op(client_side->padding_machine[0], OP_NE, NULL);
tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
@@ -1409,7 +1410,7 @@ test_circuitpadding_wronghop(void *arg)
circpad_padding_negotiated(relay_side,
CIRCPAD_MACHINE_CIRC_SETUP,
CIRCPAD_COMMAND_START,
- CIRCPAD_RESPONSE_OK);
+ CIRCPAD_RESPONSE_OK, 0);
/* verify no padding was negotiated */
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
@@ -1418,7 +1419,7 @@ test_circuitpadding_wronghop(void *arg)
circpad_padding_negotiated(relay_side,
CIRCPAD_MACHINE_CIRC_SETUP,
CIRCPAD_COMMAND_START,
- CIRCPAD_RESPONSE_ERR);
+ CIRCPAD_RESPONSE_ERR, 0);
/* verify no padding was negotiated */
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
@@ -1521,7 +1522,7 @@ test_circuitpadding_negotiation(void *arg)
/* Force negotiate padding. */
circpad_negotiate_padding(TO_ORIGIN_CIRCUIT(client_side),
CIRCPAD_MACHINE_CIRC_SETUP,
- 2, CIRCPAD_COMMAND_START);
+ 2, CIRCPAD_COMMAND_START, 0);
/* verify no padding was negotiated */
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
@@ -1732,9 +1733,9 @@ helper_create_conditional_machines(void)
add->conditions.requires_vanguards = 0;
add->conditions.min_hops = 2;
- add->conditions.state_mask = CIRCPAD_CIRC_BUILDING|
+ add->conditions.apply_state_mask = CIRCPAD_CIRC_BUILDING|
CIRCPAD_CIRC_NO_STREAMS|CIRCPAD_CIRC_HAS_RELAY_EARLY;
- add->conditions.purpose_mask = CIRCPAD_PURPOSE_ALL;
+ add->conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
circpad_register_padding_machine(add, origin_padding_machines);
add = helper_create_conditional_machine();
@@ -1751,9 +1752,9 @@ helper_create_conditional_machines(void)
add->conditions.requires_vanguards = 1;
add->conditions.min_hops = 3;
- add->conditions.state_mask = CIRCPAD_CIRC_OPENED|
+ add->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED|
CIRCPAD_CIRC_STREAMS|CIRCPAD_CIRC_HAS_NO_RELAY_EARLY;
- add->conditions.purpose_mask = CIRCPAD_PURPOSE_ALL;
+ add->conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
circpad_register_padding_machine(add, origin_padding_machines);
add = helper_create_conditional_machine();
@@ -2727,8 +2728,8 @@ helper_create_ender_machine(void)
circ_client_machine.states[CIRCPAD_STATE_START].
next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_END;
- circ_client_machine.conditions.state_mask = CIRCPAD_STATE_ALL;
- circ_client_machine.conditions.purpose_mask = CIRCPAD_PURPOSE_ALL;
+ circ_client_machine.conditions.apply_state_mask = CIRCPAD_STATE_ALL;
+ circ_client_machine.conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
}
static time_t mocked_timeofday;
diff --git a/src/test/test_circuitstats.c b/src/test/test_circuitstats.c
index e15dec5a01..00ca1b544c 100644
--- a/src/test/test_circuitstats.c
+++ b/src/test/test_circuitstats.c
@@ -17,18 +17,13 @@
#include "core/or/circuituse.h"
#include "core/or/channel.h"
-#include "core/or/cpath_build_state_st.h"
#include "core/or/crypt_path_st.h"
#include "core/or/extend_info_st.h"
#include "core/or/origin_circuit_st.h"
-void test_circuitstats_timeout(void *arg);
-void test_circuitstats_hoplen(void *arg);
-origin_circuit_t *subtest_fourhop_circuit(struct timeval, int);
-origin_circuit_t *add_opened_threehop(void);
-origin_circuit_t *build_unopened_fourhop(struct timeval);
-
-int cpath_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
+static origin_circuit_t *add_opened_threehop(void);
+static origin_circuit_t *build_unopened_fourhop(struct timeval);
+static origin_circuit_t *subtest_fourhop_circuit(struct timeval, int);
static int marked_for_close;
/* Mock function because we are not trying to test the close circuit that does
@@ -45,85 +40,71 @@ mock_circuit_mark_for_close(circuit_t *circ, int reason, int line,
return;
}
-origin_circuit_t *
+static origin_circuit_t *
add_opened_threehop(void)
{
- origin_circuit_t *or_circ = origin_circuit_new();
+ struct timeval circ_start_time;
+ memset(&circ_start_time, 0, sizeof(circ_start_time));
extend_info_t fakehop;
memset(&fakehop, 0, sizeof(fakehop));
-
- TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
-
- or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
- or_circ->build_state->desired_path_len = DEFAULT_ROUTE_LEN;
-
- cpath_append_hop(&or_circ->cpath, &fakehop);
- cpath_append_hop(&or_circ->cpath, &fakehop);
- cpath_append_hop(&or_circ->cpath, &fakehop);
-
- or_circ->has_opened = 1;
- TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN;
- TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
-
- return or_circ;
+ extend_info_t *fakehop_list[DEFAULT_ROUTE_LEN] = {&fakehop,
+ &fakehop,
+ &fakehop};
+
+ return new_test_origin_circuit(true,
+ circ_start_time,
+ DEFAULT_ROUTE_LEN,
+ fakehop_list);
}
-origin_circuit_t *
+static origin_circuit_t *
build_unopened_fourhop(struct timeval circ_start_time)
{
- origin_circuit_t *or_circ = origin_circuit_new();
- extend_info_t *fakehop = tor_malloc_zero(sizeof(extend_info_t));
- memset(fakehop, 0, sizeof(extend_info_t));
-
- TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
- TO_CIRCUIT(or_circ)->timestamp_began = circ_start_time;
- TO_CIRCUIT(or_circ)->timestamp_created = circ_start_time;
-
- or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
- or_circ->build_state->desired_path_len = 4;
-
- cpath_append_hop(&or_circ->cpath, fakehop);
- cpath_append_hop(&or_circ->cpath, fakehop);
- cpath_append_hop(&or_circ->cpath, fakehop);
- cpath_append_hop(&or_circ->cpath, fakehop);
-
- tor_free(fakehop);
-
- return or_circ;
+ extend_info_t fakehop;
+ memset(&fakehop, 0, sizeof(fakehop));
+ extend_info_t *fakehop_list[4] = {&fakehop,
+ &fakehop,
+ &fakehop,
+ &fakehop};
+
+ return new_test_origin_circuit(false,
+ circ_start_time,
+ 4,
+ fakehop_list);
}
-origin_circuit_t *
+static origin_circuit_t *
subtest_fourhop_circuit(struct timeval circ_start_time, int should_timeout)
{
- origin_circuit_t *or_circ = build_unopened_fourhop(circ_start_time);
+ origin_circuit_t *origin_circ = build_unopened_fourhop(circ_start_time);
// Now make them open one at a time and call
// circuit_build_times_handle_completed_hop();
- or_circ->cpath->state = CPATH_STATE_OPEN;
- circuit_build_times_handle_completed_hop(or_circ);
+ origin_circ->cpath->state = CPATH_STATE_OPEN;
+ circuit_build_times_handle_completed_hop(origin_circ);
tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 0);
- or_circ->cpath->next->state = CPATH_STATE_OPEN;
- circuit_build_times_handle_completed_hop(or_circ);
+ origin_circ->cpath->next->state = CPATH_STATE_OPEN;
+ circuit_build_times_handle_completed_hop(origin_circ);
tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 0);
// Third hop: We should count it now.
- or_circ->cpath->next->next->state = CPATH_STATE_OPEN;
- circuit_build_times_handle_completed_hop(or_circ);
+ origin_circ->cpath->next->next->state = CPATH_STATE_OPEN;
+ circuit_build_times_handle_completed_hop(origin_circ);
tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ,
!should_timeout); // 1 if counted, 0 otherwise
// Fourth hop: Don't double count
- or_circ->cpath->next->next->next->state = CPATH_STATE_OPEN;
- circuit_build_times_handle_completed_hop(or_circ);
+ origin_circ->cpath->next->next->next->state = CPATH_STATE_OPEN;
+ circuit_build_times_handle_completed_hop(origin_circ);
tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ,
!should_timeout);
done:
- return or_circ;
+ return origin_circ;
}
-void
+static void
test_circuitstats_hoplen(void *arg)
{
/* Plan:
diff --git a/src/test/test_config.c b/src/test/test_config.c
index cb0d9bba28..48a7091ef6 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -53,6 +53,7 @@
#include "test/test_helpers.h"
#include "test/resolve_test_helpers.h"
+#include "test/log_test_helpers.h"
#include "feature/dirclient/dir_server_st.h"
#include "core/or/port_cfg_st.h"
@@ -989,53 +990,72 @@ test_config_fix_my_family(void *arg)
}
static int n_hostname_01010101 = 0;
+static const char *ret_addr_lookup_01010101[2] = {
+ "1.1.1.1", "0101::0101",
+};
-/** This mock function is meant to replace tor_lookup_hostname().
+/** This mock function is meant to replace tor_addr_lookup().
* It answers with 1.1.1.1 as IP adddress that resulted from lookup.
* This function increments <b>n_hostname_01010101</b> counter by one
* every time it is called.
*/
static int
-tor_lookup_hostname_01010101(const char *name, uint32_t *addr)
+tor_addr_lookup_01010101(const char *name, uint16_t family, tor_addr_t *addr)
{
n_hostname_01010101++;
- if (name && addr) {
- *addr = ntohl(0x01010101);
+ if (family == AF_INET) {
+ if (name && addr) {
+ int ret = tor_addr_parse(addr, ret_addr_lookup_01010101[0]);
+ tt_int_op(ret, OP_EQ, family);
+ }
+ } else if (family == AF_INET6) {
+ if (name && addr) {
+ int ret = tor_addr_parse(addr, ret_addr_lookup_01010101[1]);
+ tt_int_op(ret, OP_EQ, family);
+ }
}
-
+ done:
return 0;
}
static int n_hostname_localhost = 0;
-/** This mock function is meant to replace tor_lookup_hostname().
+/** This mock function is meant to replace tor_addr_lookup().
* It answers with 127.0.0.1 as IP adddress that resulted from lookup.
* This function increments <b>n_hostname_localhost</b> counter by one
* every time it is called.
*/
static int
-tor_lookup_hostname_localhost(const char *name, uint32_t *addr)
+tor_addr_lookup_localhost(const char *name, uint16_t family, tor_addr_t *addr)
{
n_hostname_localhost++;
- if (name && addr) {
- *addr = 0x7f000001;
+ if (family == AF_INET) {
+ if (name && addr) {
+ tor_addr_from_ipv4h(addr, 0x7f000001);
+ }
+ } else if (family == AF_INET6) {
+ if (name && addr) {
+ int ret = tor_addr_parse(addr, "::1");
+ tt_int_op(ret, OP_EQ, AF_INET6);
+ }
}
-
+ done:
return 0;
}
static int n_hostname_failure = 0;
-/** This mock function is meant to replace tor_lookup_hostname().
+/** This mock function is meant to replace tor_addr_lookup().
* It pretends to fail by returning -1 to caller. Also, this function
* increments <b>n_hostname_failure</b> every time it is called.
*/
static int
-tor_lookup_hostname_failure(const char *name, uint32_t *addr)
+tor_addr_lookup_failure(const char *name, uint16_t family, tor_addr_t *addr)
{
(void)name;
+ (void)family;
(void)addr;
n_hostname_failure++;
@@ -1043,6 +1063,46 @@ tor_lookup_hostname_failure(const char *name, uint32_t *addr)
return -1;
}
+/** Mock function for tor_addr_lookup().
+ *
+ * Depending on the given hostname and family, resolve either to IPv4 or IPv6.
+ *
+ * If the requested hostname family is not the same as the family provided, an
+ * error is returned.
+ *
+ * Possible hostnames:
+ * - www.torproject.org.v4 for IPv4 -> 1.1.1.1
+ * - www.torproject.org.v6 for IPv6 -> [0101::0101]
+ */
+static int
+tor_addr_lookup_mixed(const char *name, uint16_t family, tor_addr_t *addr)
+{
+ tt_assert(addr);
+ tt_assert(name);
+
+ if (!strcmp(name, "www.torproject.org.v4")) {
+ if (family == AF_INET) {
+ tor_addr_from_ipv4h(addr, 0x01010101);
+ return 0;
+ }
+ /* Resolving AF_INET but the asked family is different. Failure. */
+ return -1;
+ }
+
+ if (!strcmp(name, "www.torproject.org.v6")) {
+ if (family == AF_INET6) {
+ int ret = tor_addr_parse(addr, "0101::0101");
+ tt_int_op(ret, OP_EQ, AF_INET6);
+ return 0;
+ }
+ /* Resolving AF_INET6 but the asked family is not. Failure. */
+ return -1;
+ }
+
+ done:
+ return 0;
+}
+
static int n_gethostname_replacement = 0;
/** This mock function is meant to replace tor_gethostname(). It
@@ -1097,29 +1157,39 @@ tor_gethostname_failure(char *name, size_t namelen)
return -1;
}
-static int n_get_interface_address = 0;
+static int n_get_interface_address6 = 0;
+static sa_family_t last_address6_family;
+static const char *ret_get_interface_address6_08080808[2] = {
+ "8.8.8.8", "0808::0808",
+};
/** This mock function is meant to replace get_interface_address().
* It answers with address 8.8.8.8. This function increments
* <b>n_get_interface_address</b> by one every time it is called.
*/
static int
-get_interface_address_08080808(int severity, uint32_t *addr)
+get_interface_address6_08080808(int severity, sa_family_t family,
+ tor_addr_t *addr)
{
(void)severity;
- n_get_interface_address++;
+ n_get_interface_address6++;
- if (addr) {
- *addr = ntohl(0x08080808);
+ if (family == AF_INET) {
+ if (addr) {
+ int ret = tor_addr_parse(addr, ret_get_interface_address6_08080808[0]);
+ tt_int_op(ret, OP_EQ, AF_INET);
+ }
+ } else if (family == AF_INET6) {
+ if (addr) {
+ int ret = tor_addr_parse(addr, ret_get_interface_address6_08080808[1]);
+ tt_int_op(ret, OP_EQ, AF_INET6);
+ }
}
-
+ done:
return 0;
}
-static int n_get_interface_address6 = 0;
-static sa_family_t last_address6_family;
-
/** This mock function is meant to replace get_interface_address6().
* It answers with IP address 9.9.9.9 iff both of the following are true:
* - <b>family</b> is AF_INET
@@ -1127,6 +1197,7 @@ static sa_family_t last_address6_family;
* This function increments <b>n_get_interface_address6</b> by one every
* time it is called.
*/
+#if 0
static int
get_interface_address6_replacement(int severity, sa_family_t family,
tor_addr_t *addr)
@@ -1144,25 +1215,7 @@ get_interface_address6_replacement(int severity, sa_family_t family,
return 0;
}
-
-static int n_get_interface_address_failure = 0;
-
-/**
- * This mock function is meant to replace get_interface_address().
- * It pretends to fail getting interface address by returning -1.
- * <b>n_get_interface_address_failure</b> is incremented by one
- * every time this function is called.
- */
-static int
-get_interface_address_failure(int severity, uint32_t *addr)
-{
- (void)severity;
- (void)addr;
-
- n_get_interface_address_failure++;
-
- return -1;
-}
+#endif
static int n_get_interface_address6_failure = 0;
@@ -1185,24 +1238,44 @@ get_interface_address6_failure(int severity, sa_family_t family,
return -1;
}
+/** Helper macro: to validate the returned value from find_my_address() so we
+ * don't copy those all the time. */
+#undef VALIDATE_FOUND_ADDRESS
+#define VALIDATE_FOUND_ADDRESS(ret, method, hostname) \
+ do { \
+ tt_int_op(retval, OP_EQ, ret); \
+ tt_int_op(method, OP_EQ, method_used); \
+ if (hostname == NULL) tt_assert(!hostname_out); \
+ else tt_str_op(hostname_out, OP_EQ, hostname); \
+ if (ret == true) { \
+ tt_assert(tor_addr_eq(&resolved_addr, &test_addr)); \
+ } \
+ } while (0)
+
+/** Helper macro: Cleanup the address and variables used after a
+ * find_my_address() call. */
+#undef CLEANUP_FOUND_ADDRESS
+#define CLEANUP_FOUND_ADDRESS \
+ do { \
+ config_free_lines(options->Address); \
+ config_free_lines(options->ORPort_lines); \
+ options->AddressDisableIPv6 = 0; \
+ options->ORPort_set = 0; \
+ tor_free(options->DirAuthorities); \
+ tor_free(hostname_out); \
+ tor_addr_make_unspec(&resolved_addr); \
+ tor_addr_make_unspec(&test_addr); \
+ } while (0)
+
+/** Test both IPv4 and IPv6 coexisting together in the configuration. */
static void
-test_config_resolve_my_address(void *arg)
+test_config_find_my_address_mixed(void *arg)
{
or_options_t *options;
- uint32_t resolved_addr;
- const char *method_used;
+ tor_addr_t resolved_addr, test_addr;
+ resolved_addr_method_t method_used;
char *hostname_out = NULL;
- int retval;
- int prev_n_hostname_01010101;
- int prev_n_hostname_localhost;
- int prev_n_hostname_failure;
- int prev_n_gethostname_replacement;
- int prev_n_gethostname_failure;
- int prev_n_gethostname_localhost;
- int prev_n_get_interface_address;
- int prev_n_get_interface_address_failure;
- int prev_n_get_interface_address6;
- int prev_n_get_interface_address6_failure;
+ bool retval;
(void)arg;
@@ -1210,369 +1283,513 @@ test_config_resolve_my_address(void *arg)
options_init(options);
- /*
- * CASE 1:
- * If options->Address is a valid IPv4 address string, we want
- * the corresponding address to be parsed and returned.
- */
-
- options->Address = tor_strdup("128.52.128.105");
+ /*
+ * CASE 1: Only IPv6 address. Accepted.
+ */
+ config_line_append(&options->Address, "Address",
+ "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19");
+ tor_addr_parse(&test_addr, "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19");
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ /* IPv6 address should be found and considered configured. */
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
- tt_want(retval == 0);
- tt_want_str_op(method_used,OP_EQ,"CONFIGURED");
- tt_want(hostname_out == NULL);
- tt_assert(resolved_addr == 0x80348069);
+ CLEANUP_FOUND_ADDRESS;
- tor_free(options->Address);
+ /*
+ * Case 2: IPv4 _and_ IPv6 given. Accepted.
+ */
+ config_line_append(&options->Address, "Address",
+ "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19");
+ config_line_append(&options->Address, "Address", "1.1.1.1");
+ tor_addr_parse(&test_addr, "1.1.1.1");
-/*
- * CASE 2:
- * If options->Address is a valid DNS address, we want resolve_my_address()
- * function to ask tor_lookup_hostname() for help with resolving it
- * and return the address that was resolved (in host order).
- */
+ /* IPv4 address should be found and considered configured. */
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_01010101);
+ /* IPv6 address should be found and considered configured. */
+ tor_addr_parse(&test_addr, "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19");
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
- tor_free(options->Address);
- options->Address = tor_strdup("www.torproject.org");
+ CLEANUP_FOUND_ADDRESS;
- prev_n_hostname_01010101 = n_hostname_01010101;
+ /*
+ * Case 3: Two hostnames, IPv4 and IPv6.
+ */
+ config_line_append(&options->Address, "Address", "www.torproject.org.v4");
+ config_line_append(&options->Address, "Address", "www.torproject.org.v6");
+
+ /* Looks at specific hostname to learn which address family to use. */
+ MOCK(tor_addr_lookup, tor_addr_lookup_mixed);
+
+ /* IPv4 address should be found and considered resolved. */
+ tor_addr_parse(&test_addr, "1.1.1.1");
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED,
+ "www.torproject.org.v4");
+ tor_free(hostname_out);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ /* IPv6 address should be found and considered resolved. */
+ tor_addr_parse(&test_addr, "0101::0101");
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED,
+ "www.torproject.org.v6");
- tt_want(retval == 0);
- tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1);
- tt_want_str_op(method_used,OP_EQ,"RESOLVED");
- tt_want_str_op(hostname_out,OP_EQ,"www.torproject.org");
- tt_assert(resolved_addr == 0x01010101);
+ CLEANUP_FOUND_ADDRESS;
+ UNMOCK(tor_addr_lookup);
- UNMOCK(tor_lookup_hostname);
+ /*
+ * Case 4: IPv4 address and a hostname resolving to IPV6.
+ */
+ config_line_append(&options->Address, "Address", "1.1.1.1");
+ config_line_append(&options->Address, "Address", "www.torproject.org.v6");
+
+ /* Looks at specific hostname to learn which address family to use. */
+ MOCK(tor_addr_lookup, tor_addr_lookup_mixed);
+
+ /* IPv4 address should be found and configured. */
+ tor_addr_parse(&test_addr, "1.1.1.1");
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
+
+ /* IPv6 address should be found and considered resolved. */
+ tor_addr_parse(&test_addr, "0101::0101");
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED,
+ "www.torproject.org.v6");
+
+ CLEANUP_FOUND_ADDRESS;
+ UNMOCK(tor_addr_lookup);
- tor_free(options->Address);
+ /*
+ * Case 5: Hostname resolving to IPv4 and an IPv6 address.
+ */
+ config_line_append(&options->Address, "Address", "0101::0101");
+ config_line_append(&options->Address, "Address", "www.torproject.org.v4");
+
+ /* Looks at specific hostname to learn which address family to use. */
+ MOCK(tor_addr_lookup, tor_addr_lookup_mixed);
+
+ /* IPv4 address should be found and resolved. */
+ tor_addr_parse(&test_addr, "1.1.1.1");
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED,
+ "www.torproject.org.v4");
tor_free(hostname_out);
-/*
- * CASE 3:
- * Given that options->Address is NULL, we want resolve_my_address()
- * to try and use tor_gethostname() to get hostname AND use
- * tor_lookup_hostname() to get IP address.
- */
-
- resolved_addr = 0;
- tor_free(options->Address);
- options->Address = NULL;
+ /* IPv6 address should be found and considered resolved. */
+ tor_addr_parse(&test_addr, "0101::0101");
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
+ CLEANUP_FOUND_ADDRESS;
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_01010101);
+ UNMOCK(tor_addr_lookup);
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_hostname_01010101 = n_hostname_01010101;
+ done:
+ config_free_lines(options->Address);
+ or_options_free(options);
+ tor_free(hostname_out);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ UNMOCK(tor_addr_lookup);
+}
- tt_want(retval == 0);
- tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
- tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1);
- tt_want_str_op(method_used,OP_EQ,"GETHOSTNAME");
- tt_want_str_op(hostname_out,OP_EQ,"onionrouter!");
- tt_assert(resolved_addr == 0x01010101);
+/** Parameters for the find_my_address() test. We test both AF_INET and
+ * AF_INET6 but we have one interface to do so thus we run the same exact unit
+ * tests for both without copying them. */
+typedef struct find_my_address_params_t {
+ /* Index where the mock function results are located. For intance,
+ * tor_addr_lookup_01010101() will have its returned value depending on the
+ * family in ret_addr_lookup_01010101[].
+ *
+ * Values that can be found:
+ * AF_INET : index 0.
+ * AF_INET6: index 1.
+ */
+ int idx;
+ int family;
+ const char *public_ip;
+ const char *internal_ip;
+ const char *orport;
+} find_my_address_params_t;
+
+static find_my_address_params_t addr_param_v4 = {
+ .idx = 0,
+ .family = AF_INET,
+ .public_ip = "128.52.128.105",
+ .internal_ip = "127.0.0.1",
+};
- UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
+static find_my_address_params_t addr_param_v6 = {
+ .idx = 1,
+ .family = AF_INET6,
+ .public_ip = "[4242::4242]",
+ .internal_ip = "[::1]",
+};
- tor_free(hostname_out);
+static void
+test_config_find_my_address(void *arg)
+{
+ or_options_t *options;
+ tor_addr_t resolved_addr, test_addr;
+ resolved_addr_method_t method_used;
+ char *hostname_out = NULL;
+ bool retval;
+ int prev_n_hostname_01010101;
+ int prev_n_hostname_failure;
+ int prev_n_hostname_localhost;
+ int prev_n_gethostname_replacement;
+ int prev_n_gethostname_failure;
+ int prev_n_gethostname_localhost;
+ int prev_n_get_interface_address6;
+ int prev_n_get_interface_address6_failure;
-/*
- * CASE 4:
- * Given that options->Address is a local host address, we want
- * resolve_my_address() function to fail.
- */
+ const find_my_address_params_t *p = arg;
- resolved_addr = 0;
- tor_free(options->Address);
- options->Address = tor_strdup("127.0.0.1");
+ options = options_new();
+ options_init(options);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ /*
+ * Case 0:
+ * AddressDisableIPv6 is set.
+ *
+ * Only run this if we are in the IPv6 test.
+ */
+ if (p->family == AF_INET6) {
+ options->AddressDisableIPv6 = 1;
+ /* Set a valid IPv6. However, the discovery should still fail. */
+ config_line_append(&options->Address, "Address", p->public_ip);
+ tor_addr_parse(&test_addr, p->public_ip);
+
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL);
+ CLEANUP_FOUND_ADDRESS;
+ }
- tt_want(resolved_addr == 0);
- tt_int_op(retval, OP_EQ, -1);
+ /*
+ * Case 1:
+ * 1. Address is a valid address.
+ *
+ * Expected to succeed.
+ */
+ config_line_append(&options->Address, "Address", p->public_ip);
+ tor_addr_parse(&test_addr, p->public_ip);
- tor_free(options->Address);
- tor_free(hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
-/*
- * CASE 5:
- * We want resolve_my_address() to fail if DNS address in options->Address
- * cannot be resolved.
- */
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
+ CLEANUP_FOUND_ADDRESS;
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
+ /*
+ * Case 2: Address is a resolvable address. Expected to succeed.
+ */
+ MOCK(tor_addr_lookup, tor_addr_lookup_01010101);
- prev_n_hostname_failure = n_hostname_failure;
+ config_line_append(&options->Address, "Address", "www.torproject.org");
+ tor_addr_parse(&test_addr, ret_addr_lookup_01010101[p->idx]);
- tor_free(options->Address);
- options->Address = tor_strdup("www.tor-project.org");
+ prev_n_hostname_01010101 = n_hostname_01010101;
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
- tt_int_op(retval, OP_EQ, -1);
+ tt_int_op(n_hostname_01010101, OP_EQ, ++prev_n_hostname_01010101);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_RESOLVED, "www.torproject.org");
+ CLEANUP_FOUND_ADDRESS;
- UNMOCK(tor_lookup_hostname);
+ UNMOCK(tor_addr_lookup);
- tor_free(options->Address);
- tor_free(hostname_out);
+ /*
+ * Case 3: Address is a local addressi (internal). Expected to fail.
+ */
+ config_line_append(&options->Address, "Address", p->internal_ip);
-/*
- * CASE 6:
- * If options->Address is NULL AND gettting local hostname fails, we want
- * resolve_my_address() to fail as well.
- */
+ setup_full_capture_of_logs(LOG_NOTICE);
- MOCK(tor_gethostname,tor_gethostname_failure);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- prev_n_gethostname_failure = n_gethostname_failure;
+ expect_log_msg_containing("is a private IP address. Tor relays that "
+ "use the default DirAuthorities must have "
+ "public IP addresses.");
+ teardown_capture_of_logs();
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL);
+ CLEANUP_FOUND_ADDRESS;
- tt_want(n_gethostname_failure == prev_n_gethostname_failure + 1);
- tt_int_op(retval, OP_EQ, -1);
+ /*
+ * Case 4: Address is a local address but custom authorities. Expected to
+ * succeed.
+ */
+ config_line_append(&options->Address, "Address", p->internal_ip);
+ options->DirAuthorities = tor_malloc_zero(sizeof(config_line_t));
+ tor_addr_parse(&test_addr, p->internal_ip);
- UNMOCK(tor_gethostname);
- tor_free(hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
-/*
- * CASE 7:
- * We want resolve_my_address() to try and get network interface address via
- * get_interface_address() if hostname returned by tor_gethostname() cannot be
- * resolved into IP address.
- */
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED, NULL);
+ CLEANUP_FOUND_ADDRESS;
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
- MOCK(get_interface_address,get_interface_address_08080808);
+ /*
+ * Case 5: Multiple address in Address. Expected to fail.
+ */
+ config_line_append(&options->Address, "Address", p->public_ip);
+ config_line_append(&options->Address, "Address", p->public_ip);
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_get_interface_address = n_get_interface_address;
+ setup_full_capture_of_logs(LOG_NOTICE);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(retval == 0);
- tt_want_int_op(n_gethostname_replacement, OP_EQ,
- prev_n_gethostname_replacement + 1);
- tt_want_int_op(n_get_interface_address, OP_EQ,
- prev_n_get_interface_address + 1);
- tt_want_str_op(method_used,OP_EQ,"INTERFACE");
- tt_want(hostname_out == NULL);
- tt_assert(resolved_addr == 0x08080808);
+ expect_log_msg_containing("Found 2 Address statement of address family");
+ teardown_capture_of_logs();
- UNMOCK(get_interface_address);
- tor_free(hostname_out);
+ VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL);
+ CLEANUP_FOUND_ADDRESS;
-/*
- * CASE 8:
- * Suppose options->Address is NULL AND hostname returned by tor_gethostname()
- * is unresolvable. We want resolve_my_address to fail if
- * get_interface_address() fails.
- */
+ /*
+ * Case 8:
+ * 1. Address is NULL
+ * 2. Interface address is a valid address.
+ *
+ * Expected to succeed.
+ */
+ options->Address = NULL;
+ tor_addr_parse(&test_addr, ret_get_interface_address6_08080808[p->idx]);
- MOCK(get_interface_address,get_interface_address_failure);
+ MOCK(get_interface_address6, get_interface_address6_08080808);
- prev_n_get_interface_address_failure = n_get_interface_address_failure;
- prev_n_gethostname_replacement = n_gethostname_replacement;
+ prev_n_get_interface_address6 = n_get_interface_address6;
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_get_interface_address_failure ==
- prev_n_get_interface_address_failure + 1);
- tt_want(n_gethostname_replacement ==
- prev_n_gethostname_replacement + 1);
- tt_int_op(retval, OP_EQ, -1);
+ tt_int_op(n_get_interface_address6, OP_EQ, ++prev_n_get_interface_address6);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_INTERFACE, NULL);
+ CLEANUP_FOUND_ADDRESS;
- UNMOCK(get_interface_address);
- tor_free(hostname_out);
+ UNMOCK(get_interface_address6);
-/*
- * CASE 9:
- * Given that options->Address is NULL AND tor_lookup_hostname()
- * fails AND hostname returned by gethostname() resolves
- * to local IP address, we want resolve_my_address() function to
- * call get_interface_address6(.,AF_INET,.) and return IP address
- * the latter function has found.
- */
+ /*
+ * Case 9:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname resolves to a valid address.
+ *
+ * Expected to succeed.
+ */
+ options->Address = NULL;
+ tor_addr_parse(&test_addr, ret_addr_lookup_01010101[p->idx]);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(get_interface_address6,get_interface_address6_replacement);
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_replacement);
+ MOCK(tor_addr_lookup, tor_addr_lookup_01010101);
+ prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
+ prev_n_hostname_01010101 = n_hostname_01010101;
prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_hostname_failure = n_hostname_failure;
- prev_n_get_interface_address6 = n_get_interface_address6;
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(last_address6_family == AF_INET);
- tt_want(n_get_interface_address6 == prev_n_get_interface_address6 + 1);
- tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
- tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
- tt_want(retval == 0);
- tt_want_str_op(method_used,OP_EQ,"INTERFACE");
- tt_assert(resolved_addr == 0x09090909);
+ tt_int_op(n_get_interface_address6_failure, OP_EQ,
+ ++prev_n_get_interface_address6_failure);
+ tt_int_op(n_hostname_01010101, OP_EQ,
+ ++prev_n_hostname_01010101);
+ tt_int_op(n_gethostname_replacement, OP_EQ,
+ ++prev_n_gethostname_replacement);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_GETHOSTNAME, "onionrouter!");
+ CLEANUP_FOUND_ADDRESS;
- UNMOCK(tor_lookup_hostname);
- UNMOCK(tor_gethostname);
UNMOCK(get_interface_address6);
-
- tor_free(hostname_out);
+ UNMOCK(tor_gethostname);
+ UNMOCK(tor_addr_lookup);
/*
- * CASE 10: We want resolve_my_address() to fail if all of the following
- * are true:
- * 1. options->Address is not NULL
- * 2. ... but it cannot be converted to struct in_addr by
- * tor_inet_aton()
- * 3. ... and tor_lookup_hostname() fails to resolve the
- * options->Address
+ * Case 10:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname resolves to an internal address.
+ *
+ * Expected to fail.
*/
+ options->Address = NULL;
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
-
- prev_n_hostname_failure = n_hostname_failure;
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_localhost);
+ MOCK(tor_addr_lookup, tor_addr_lookup_localhost);
- tor_free(options->Address);
- options->Address = tor_strdup("some_hostname");
+ prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
+ prev_n_hostname_localhost = n_hostname_localhost;
+ prev_n_gethostname_localhost = n_gethostname_localhost;
- retval = resolve_my_address(LOG_NOTICE, options, &resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
- tt_int_op(retval, OP_EQ, -1);
+ tt_int_op(n_get_interface_address6_failure, OP_EQ,
+ ++prev_n_get_interface_address6_failure);
+ tt_int_op(n_hostname_localhost, OP_EQ,
+ ++prev_n_hostname_localhost);
+ tt_int_op(n_gethostname_localhost, OP_EQ,
+ ++prev_n_gethostname_localhost);
+ VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL);
+ CLEANUP_FOUND_ADDRESS;
+ UNMOCK(get_interface_address6);
UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
-
- tor_free(hostname_out);
+ UNMOCK(tor_addr_lookup);
/*
- * CASE 11:
- * Suppose the following sequence of events:
- * 1. options->Address is NULL
- * 2. tor_gethostname() succeeds to get hostname of machine Tor
- * if running on.
- * 3. Hostname from previous step cannot be converted to
- * address by using tor_inet_aton() function.
- * 4. However, tor_lookup_hostname() succeeds in resolving the
- * hostname from step 2.
- * 5. Unfortunately, tor_addr_is_internal() deems this address
- * to be internal.
- * 6. get_interface_address6(.,AF_INET,.) returns non-internal
- * IPv4
+ * Case 11:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname fails to be found.
*
- * We want resolve_my_addr() to succeed with method "INTERFACE"
- * and address from step 6.
+ * Expected to fail.
*/
-
- tor_free(options->Address);
options->Address = NULL;
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_localhost);
- MOCK(get_interface_address6,get_interface_address6_replacement);
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_failure);
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_hostname_localhost = n_hostname_localhost;
- prev_n_get_interface_address6 = n_get_interface_address6;
+ prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
+ prev_n_gethostname_failure = n_gethostname_failure;
- retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
- tt_want(n_hostname_localhost == prev_n_hostname_localhost + 1);
- tt_want(n_get_interface_address6 == prev_n_get_interface_address6 + 1);
+ tt_int_op(n_get_interface_address6_failure, OP_EQ,
+ ++prev_n_get_interface_address6_failure);
+ tt_int_op(n_gethostname_failure, OP_EQ,
+ ++prev_n_gethostname_failure);
+ VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL);
+ CLEANUP_FOUND_ADDRESS;
- tt_str_op(method_used,OP_EQ,"INTERFACE");
- tt_ptr_op(hostname_out, OP_EQ, NULL);
- tt_int_op(retval, OP_EQ, 0);
+ UNMOCK(get_interface_address6);
+ UNMOCK(tor_gethostname);
/*
- * CASE 11b:
- * 1-5 as above.
- * 6. get_interface_address6() fails.
+ * Case 12:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname can't be resolved.
*
- * In this subcase, we want resolve_my_address() to fail.
+ * Expected to fail.
*/
+ options->Address = NULL;
- UNMOCK(get_interface_address6);
- MOCK(get_interface_address6,get_interface_address6_failure);
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_replacement);
+ MOCK(tor_addr_lookup, tor_addr_lookup_failure);
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_hostname_localhost = n_hostname_localhost;
prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
+ prev_n_gethostname_replacement = n_gethostname_replacement;
+ prev_n_hostname_failure = n_hostname_failure;
- retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
- tt_want(n_hostname_localhost == prev_n_hostname_localhost + 1);
- tt_want(n_get_interface_address6_failure ==
- prev_n_get_interface_address6_failure + 1);
+ tt_int_op(n_get_interface_address6_failure, OP_EQ,
+ ++prev_n_get_interface_address6_failure);
+ tt_int_op(n_gethostname_replacement, OP_EQ,
+ ++prev_n_gethostname_replacement);
+ tt_int_op(n_hostname_failure, OP_EQ,
+ ++prev_n_hostname_failure);
+ VALIDATE_FOUND_ADDRESS(false, RESOLVED_ADDR_NONE, NULL);
+ CLEANUP_FOUND_ADDRESS;
- tt_int_op(retval, OP_EQ, -1);
+ /*
+ * Case 13:
+ * 1. Address is NULL.
+ * 2. ORPort has a valid public address.
+ */
+ {
+ char *msg = NULL;
+ int n, w, ret;
+ char *orport_line = NULL;
+
+ options->Address = NULL;
+ tor_asprintf(&orport_line, "%s:9001", p->public_ip);
+ config_line_append(&options->ORPort_lines, "ORPort", orport_line);
+ tor_free(orport_line);
+
+ if (p->family == AF_INET6) {
+ /* XXX: Tor does _not_ allow an IPv6 only ORPort thus we need to add a
+ * bogus IPv4 at the moment. */
+ config_line_append(&options->ORPort_lines, "ORPort", "1.1.1.1:9001");
+ }
- UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
- UNMOCK(get_interface_address6);
+ ret = parse_ports(options, 0, &msg, &n, &w);
+ tt_int_op(ret, OP_EQ, 0);
+ tor_addr_parse(&test_addr, p->public_ip);
+ }
- /* CASE 12:
- * Suppose the following happens:
- * 1. options->Address is NULL AND options->DirAuthorities is non-NULL
- * 2. tor_gethostname() succeeds in getting hostname of a machine ...
- * 3. ... which is successfully parsed by tor_inet_aton() ...
- * 4. into IPv4 address that tor_addr_is_inernal() considers to be
- * internal.
- *
- * In this case, we want resolve_my_address() to fail.
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_CONFIGURED_ORPORT, NULL);
+ CLEANUP_FOUND_ADDRESS;
+
+ /*
+ * Case 14:
+ * 1. Address is NULL.
+ * 2. ORPort has an internal address thus fails.
+ * 3. Interface as a valid address.
*/
+ {
+ char *msg = NULL;
+ int n, w, ret;
+ char *orport_line = NULL;
+
+ options->Address = NULL;
+ tor_asprintf(&orport_line, "%s:9001", p->internal_ip);
+ config_line_append(&options->ORPort_lines, "ORPort", orport_line);
+ tor_free(orport_line);
+
+ if (p->family == AF_INET6) {
+ /* XXX: Tor does _not_ allow an IPv6 only ORPort thus we need to add a
+ * bogus IPv4 at the moment. */
+ config_line_append(&options->ORPort_lines, "ORPort", "1.1.1.1:9001");
+ }
- tor_free(options->Address);
- options->Address = NULL;
- options->DirAuthorities = tor_malloc_zero(sizeof(config_line_t));
+ ret = parse_ports(options, 0, &msg, &n, &w);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+ tor_addr_parse(&test_addr, ret_get_interface_address6_08080808[p->idx]);
- MOCK(tor_gethostname,tor_gethostname_localhost);
+ MOCK(get_interface_address6, get_interface_address6_08080808);
- prev_n_gethostname_localhost = n_gethostname_localhost;
+ prev_n_get_interface_address6 = n_get_interface_address6;
- retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_gethostname_localhost == prev_n_gethostname_localhost + 1);
- tt_int_op(retval, OP_EQ, -1);
+ tt_int_op(n_get_interface_address6, OP_EQ, ++prev_n_get_interface_address6);
+ VALIDATE_FOUND_ADDRESS(true, RESOLVED_ADDR_INTERFACE, NULL);
+ CLEANUP_FOUND_ADDRESS;
+ UNMOCK(get_interface_address6);
UNMOCK(tor_gethostname);
+ UNMOCK(tor_addr_lookup);
done:
- tor_free(options->Address);
- tor_free(options->DirAuthorities);
or_options_free(options);
- tor_free(hostname_out);
UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
- UNMOCK(get_interface_address);
+ UNMOCK(tor_addr_lookup);
UNMOCK(get_interface_address6);
- UNMOCK(tor_gethostname);
}
static void
@@ -2071,7 +2288,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 1);
@@ -2083,7 +2300,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -2095,7 +2312,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2114,7 +2331,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 1);
@@ -2126,7 +2343,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -2138,7 +2355,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2150,7 +2367,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 1);
@@ -2162,7 +2379,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -2214,7 +2431,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 1);
@@ -2226,7 +2443,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -2238,7 +2455,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2257,7 +2474,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 1);
@@ -2269,7 +2486,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -2281,7 +2498,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2293,7 +2510,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 0);
@@ -2305,7 +2522,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -2357,7 +2574,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2369,7 +2586,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2381,7 +2598,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -2400,7 +2617,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2412,7 +2629,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2424,7 +2641,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -2436,7 +2653,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 1);
@@ -2448,7 +2665,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -2501,7 +2718,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2513,7 +2730,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2525,7 +2742,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -2544,7 +2761,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2556,7 +2773,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2568,7 +2785,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -2580,7 +2797,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 0);
@@ -2592,7 +2809,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -2655,7 +2872,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2667,7 +2884,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2679,7 +2896,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2705,7 +2922,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2717,7 +2934,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2729,7 +2946,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2741,7 +2958,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 1);
@@ -2753,7 +2970,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -2811,7 +3028,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2823,7 +3040,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2835,7 +3052,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2861,7 +3078,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2873,7 +3090,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 1);
@@ -2885,7 +3102,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -2897,7 +3114,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 0);
@@ -2909,7 +3126,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 1);
@@ -2977,7 +3194,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -2989,7 +3206,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3001,7 +3218,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -3028,7 +3245,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3040,7 +3257,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3052,7 +3269,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -3064,7 +3281,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 1);
@@ -3076,7 +3293,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -3137,7 +3354,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3149,7 +3366,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3161,7 +3378,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -3188,7 +3405,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3200,7 +3417,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3212,7 +3429,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 1);
@@ -3224,7 +3441,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 0);
@@ -3236,7 +3453,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -3304,7 +3521,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3316,7 +3533,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3328,7 +3545,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -3355,7 +3572,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3367,7 +3584,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3379,7 +3596,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -3391,7 +3608,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 1);
@@ -3403,7 +3620,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 0);
@@ -3469,7 +3686,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3481,7 +3698,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3493,7 +3710,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -3520,7 +3737,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_D0 +=
- (ds->dir_port == 60090 ?
+ (ds->ipv4_dirport == 60090 ?
1 : 0)
);
tt_int_op(found_D0, OP_EQ, 0);
@@ -3532,7 +3749,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_B1 +=
- (ds->dir_port == 60091 ?
+ (ds->ipv4_dirport == 60091 ?
1 : 0)
);
tt_int_op(found_B1, OP_EQ, 0);
@@ -3544,7 +3761,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_A2 +=
- (ds->dir_port == 60092 ?
+ (ds->ipv4_dirport == 60092 ?
1 : 0)
);
tt_int_op(found_A2, OP_EQ, 0);
@@ -3556,7 +3773,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_non_default_fallback +=
- (ds->dir_port == 60093 ?
+ (ds->ipv4_dirport == 60093 ?
1 : 0)
);
tt_int_op(found_non_default_fallback, OP_EQ, 0);
@@ -3568,7 +3785,7 @@ test_config_adding_dir_servers(void *arg)
ds,
/* increment the found counter if dir_port matches */
found_default_fallback +=
- (ds->dir_port == 60099 ?
+ (ds->ipv4_dirport == 60099 ?
1 : 0)
);
tt_int_op(found_default_fallback, OP_EQ, 1);
@@ -3647,16 +3864,17 @@ test_config_default_dir_servers(void *arg)
or_options_free(opts);
}
-static int mock_router_pick_published_address_result = 0;
+static bool mock_relay_find_addr_to_publish_result = true;
-static int
-mock_router_pick_published_address(const or_options_t *options,
- uint32_t *addr, int cache_only)
+static bool
+mock_relay_find_addr_to_publish(const or_options_t *options, int family,
+ int flags, tor_addr_t *addr_out)
{
- (void)options;
- (void)addr;
- (void)cache_only;
- return mock_router_pick_published_address_result;
+ (void) options;
+ (void) family;
+ (void) flags;
+ (void) addr_out;
+ return mock_relay_find_addr_to_publish_result;
}
static int mock_router_my_exit_policy_is_reject_star_result = 0;
@@ -3692,11 +3910,11 @@ test_config_directory_fetch(void *arg)
or_options_t *options = options_new();
routerinfo_t routerinfo;
memset(&routerinfo, 0, sizeof(routerinfo));
- mock_router_pick_published_address_result = -1;
+ mock_relay_find_addr_to_publish_result = false;
mock_router_my_exit_policy_is_reject_star_result = 1;
mock_advertised_server_mode_result = 0;
mock_router_get_my_routerinfo_result = NULL;
- MOCK(router_pick_published_address, mock_router_pick_published_address);
+ MOCK(relay_find_addr_to_publish, mock_relay_find_addr_to_publish);
MOCK(router_my_exit_policy_is_reject_star,
mock_router_my_exit_policy_is_reject_star);
MOCK(advertised_server_mode, mock_advertised_server_mode);
@@ -3752,14 +3970,14 @@ test_config_directory_fetch(void *arg)
options = options_new();
options->ORPort_set = 1;
- mock_router_pick_published_address_result = -1;
+ mock_relay_find_addr_to_publish_result = false;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 1);
tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
OP_EQ, 0);
- mock_router_pick_published_address_result = 0;
+ mock_relay_find_addr_to_publish_result = true;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
@@ -3773,7 +3991,7 @@ test_config_directory_fetch(void *arg)
options = options_new();
options->ORPort_set = 1;
options->ExitRelay = 1;
- mock_router_pick_published_address_result = 0;
+ mock_relay_find_addr_to_publish_result = true;
mock_router_my_exit_policy_is_reject_star_result = 0;
mock_advertised_server_mode_result = 1;
mock_router_get_my_routerinfo_result = &routerinfo;
@@ -3788,7 +4006,7 @@ test_config_directory_fetch(void *arg)
OP_EQ, 0);
options->RefuseUnknownExits = 0;
- mock_router_pick_published_address_result = 0;
+ mock_relay_find_addr_to_publish_result = true;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
tt_int_op(dirclient_fetches_from_authorities(options), OP_EQ, 0);
@@ -3805,11 +4023,11 @@ test_config_directory_fetch(void *arg)
options->DirPort_set = 1;
options->ORPort_set = 1;
options->DirCache = 1;
- mock_router_pick_published_address_result = 0;
+ mock_relay_find_addr_to_publish_result = true;
mock_router_my_exit_policy_is_reject_star_result = 1;
mock_advertised_server_mode_result = 1;
- routerinfo.dir_port = 1;
+ routerinfo.ipv4_dirport = 1;
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
@@ -3818,7 +4036,7 @@ test_config_directory_fetch(void *arg)
OP_EQ, 0);
mock_advertised_server_mode_result = 0;
- routerinfo.dir_port = 1;
+ routerinfo.ipv4_dirport = 1;
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
@@ -3835,7 +4053,7 @@ test_config_directory_fetch(void *arg)
OP_EQ, 0);
mock_advertised_server_mode_result = 1;
- routerinfo.dir_port = 0;
+ routerinfo.ipv4_dirport = 0;
routerinfo.supports_tunnelled_dir_requests = 0;
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
@@ -3845,7 +4063,7 @@ test_config_directory_fetch(void *arg)
OP_EQ, 0);
mock_advertised_server_mode_result = 1;
- routerinfo.dir_port = 1;
+ routerinfo.ipv4_dirport = 1;
routerinfo.supports_tunnelled_dir_requests = 1;
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
@@ -3856,7 +4074,7 @@ test_config_directory_fetch(void *arg)
done:
or_options_free(options);
- UNMOCK(router_pick_published_address);
+ UNMOCK(relay_find_addr_to_publish);
UNMOCK(router_get_my_routerinfo);
UNMOCK(advertised_server_mode);
UNMOCK(router_my_exit_policy_is_reject_star);
@@ -4947,6 +5165,44 @@ test_config_parse_port_config__ports__server_options(void *data)
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
+ /* Default address is IPv4 but pass IPv6Only flag. Should be ignored. */
+ config_free_lines(config_port_invalid); config_port_invalid = NULL;
+ SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
+ smartlist_clear(slout);
+ config_port_invalid = mock_config_line("ORPort", "9050 IPv6Only");
+ ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
+ "127.0.0.1", 0, CL_PORT_SERVER_OPTIONS);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Default address is IPv6 but pass IPv4Only flag. Should be ignored. */
+ config_free_lines(config_port_invalid); config_port_invalid = NULL;
+ SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
+ smartlist_clear(slout);
+ config_port_invalid = mock_config_line("ORPort", "9050 IPv4Only");
+ ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
+ "[::]", 0, CL_PORT_SERVER_OPTIONS);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Explicit address is IPv6 but pass IPv4Only flag. Should error. */
+ config_free_lines(config_port_invalid); config_port_invalid = NULL;
+ SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
+ smartlist_clear(slout);
+ config_port_invalid = mock_config_line("ORPort",
+ "[4242::4242]:9050 IPv4Only");
+ ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
+ "[::]", 0, CL_PORT_SERVER_OPTIONS);
+ tt_int_op(ret, OP_EQ, -1);
+
+ /* Explicit address is IPv4 but pass IPv6Only flag. Should error. */
+ config_free_lines(config_port_invalid); config_port_invalid = NULL;
+ SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
+ smartlist_clear(slout);
+ config_port_invalid = mock_config_line("ORPort",
+ "1.2.3.4:9050 IPv6Only");
+ ret = port_parse_config(slout, config_port_invalid, "ORPort", 0,
+ "127.0.0.1", 0, CL_PORT_SERVER_OPTIONS);
+ tt_int_op(ret, OP_EQ, -1);
+
done:
if (slout)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
@@ -4966,17 +5222,17 @@ test_config_get_first_advertised(void *data)
const tor_addr_t *addr;
// no ports are configured? We get NULL.
- port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER,
AF_INET);
tt_int_op(port, OP_EQ, 0);
- addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER,
AF_INET);
tt_ptr_op(addr, OP_EQ, NULL);
- port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER,
AF_INET6);
tt_int_op(port, OP_EQ, 0);
- addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER,
AF_INET6);
tt_ptr_op(addr, OP_EQ, NULL);
@@ -4990,27 +5246,27 @@ test_config_get_first_advertised(void *data)
tt_assert(r == 0);
// UNSPEC gets us nothing.
- port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER,
AF_UNSPEC);
tt_int_op(port, OP_EQ, 0);
- addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER,
AF_UNSPEC);
tt_ptr_op(addr, OP_EQ, NULL);
// Try AF_INET.
- port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER,
AF_INET);
tt_int_op(port, OP_EQ, 9911);
- addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER,
AF_INET);
tt_ptr_op(addr, OP_NE, NULL);
tt_str_op(fmt_addrport(addr,port), OP_EQ, "5.6.7.8:9911");
// Try AF_INET6
- port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER,
+ port = portconf_get_first_advertised_port(CONN_TYPE_OR_LISTENER,
AF_INET6);
tt_int_op(port, OP_EQ, 8080);
- addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER,
+ addr = portconf_get_first_advertised_addr(CONN_TYPE_OR_LISTENER,
AF_INET6);
tt_ptr_op(addr, OP_NE, NULL);
tt_str_op(fmt_addrport(addr,port), OP_EQ, "[1234::5678]:8080");
@@ -5633,6 +5889,7 @@ test_config_include_flag_both_without(void *data)
done:
tor_free(errmsg);
+ config_free_all();
}
static void
@@ -5673,6 +5930,7 @@ test_config_include_flag_torrc_only(void *data)
tor_free(errmsg);
tor_free(path);
tor_free(dir);
+ config_free_all();
}
static void
@@ -5713,6 +5971,287 @@ test_config_include_flag_defaults_only(void *data)
tor_free(errmsg);
tor_free(path);
tor_free(dir);
+ config_free_all();
+}
+
+static void
+test_config_include_wildcards(void *data)
+{
+ (void)data;
+
+ char *temp = NULL, *folder = NULL;
+ config_line_t *result = NULL;
+ char *dir = tor_strdup(get_fname("test_include_wildcards"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", dir, "01_one.conf");
+ tt_int_op(write_str_to_file(temp, "Test 1\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", dir, "02_two.conf");
+ tt_int_op(write_str_to_file(temp, "Test 2\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", dir, "aa_three.conf");
+ tt_int_op(write_str_to_file(temp, "Test 3\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", dir, "foo");
+ tt_int_op(write_str_to_file(temp, "Test 6\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ tor_asprintf(&folder, "%s"PATH_SEPARATOR"%s", dir, "folder");
+
+#ifdef _WIN32
+ tt_int_op(mkdir(folder), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(folder, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", folder, "04_four.conf");
+ tt_int_op(write_str_to_file(temp, "Test 4\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", folder, "05_five.conf");
+ tt_int_op(write_str_to_file(temp, "Test 5\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ char torrc_contents[1000];
+ int include_used;
+
+ // test pattern that matches no file
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"not-exist*\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_EQ, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+ config_free_lines(result);
+
+#ifndef _WIN32
+ // test wildcard escaping
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"\\*\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, -1);
+ tt_ptr_op(result, OP_EQ, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+ config_free_lines(result);
+#endif
+
+ // test pattern *.conf
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"*.conf\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ int len = 0;
+ config_line_t *next;
+ char expected[10];
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 3);
+ config_free_lines(result);
+
+ // test pattern that matches folder and files
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"*\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ len = 0;
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 6);
+ config_free_lines(result);
+
+ // test pattern ending in PATH_SEPARATOR, test linux path separator
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s/f*/\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ len = 0;
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1 + 3);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 2);
+ config_free_lines(result);
+
+ // test pattern with wildcards in folder and file
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"*"PATH_SEPARATOR"*.conf\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ len = 0;
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1 + 3);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 2);
+ config_free_lines(result);
+
+ done:
+ config_free_lines(result);
+ tor_free(folder);
+ tor_free(temp);
+ tor_free(dir);
+}
+
+static void
+test_config_include_hidden(void *data)
+{
+ (void)data;
+
+ char *temp = NULL, *folder = NULL;
+ config_line_t *result = NULL;
+ char *dir = tor_strdup(get_fname("test_include_hidden"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&folder, "%s"PATH_SEPARATOR"%s", dir, ".dotdir");
+
+#ifdef _WIN32
+ tt_int_op(mkdir(folder), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(folder, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", folder, ".dotfile");
+ tt_int_op(write_str_to_file(temp, "Test 1\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ tor_asprintf(&temp, "%s"PATH_SEPARATOR"%s", folder, "file");
+ tt_int_op(write_str_to_file(temp, "Test 2\n", 0), OP_EQ, 0);
+ tor_free(temp);
+
+ char torrc_contents[1000];
+ int include_used;
+ int len = 0;
+ config_line_t *next;
+ char expected[10];
+
+ // test wildcards do not expand to dot folders (except for windows)
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"*\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_int_op(include_used, OP_EQ, 1);
+#ifdef _WIN32 // wildcard expansion includes dot files on Windows
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 2);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 1);
+#else
+ tt_ptr_op(result, OP_EQ, NULL);
+#endif
+ config_free_lines(result);
+
+ // test wildcards match hidden folders when explicitly in the pattern
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR".*\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ len = 0;
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 2);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 1);
+ config_free_lines(result);
+
+ // test hidden dir when explicitly included
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR".dotdir\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ len = 0;
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 2);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 1);
+ config_free_lines(result);
+
+ // test hidden file when explicitly included
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR".dotdir"PATH_SEPARATOR".dotfile\n",
+ dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ len = 0;
+ for (next = result; next != NULL; next = next->next) {
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 1);
+ config_free_lines(result);
+
+ done:
+ config_free_lines(result);
+ tor_free(folder);
+ tor_free(temp);
+ tor_free(dir);
}
static void
@@ -5844,7 +6383,7 @@ test_config_include_opened_file_list(void *data)
smartlist_t *opened_files = smartlist_new();
char *torrcd = NULL;
char *subfolder = NULL;
- char *path = NULL;
+ char *in_subfolder = NULL;
char *empty = NULL;
char *file = NULL;
char *dot = NULL;
@@ -5873,9 +6412,9 @@ test_config_include_opened_file_list(void *data)
tt_int_op(mkdir(subfolder, 0700), OP_EQ, 0);
#endif
- tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", subfolder,
+ tor_asprintf(&in_subfolder, "%s"PATH_SEPARATOR"%s", subfolder,
"01_file_in_subfolder");
- tt_int_op(write_str_to_file(path, "Test 1\n", 0), OP_EQ, 0);
+ tt_int_op(write_str_to_file(in_subfolder, "Test 1\n", 0), OP_EQ, 0);
tor_asprintf(&empty, "%s"PATH_SEPARATOR"%s", torrcd, "empty");
tt_int_op(write_str_to_file(empty, "", 0), OP_EQ, 0);
@@ -5906,13 +6445,69 @@ test_config_include_opened_file_list(void *data)
// dot files are not opened as we ignore them when we get their name from
// their parent folder
+ // test with wildcards
+ SMARTLIST_FOREACH(opened_files, char *, f, tor_free(f));
+ smartlist_clear(opened_files);
+ config_free_lines(result);
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"*\n",
+ torrcd);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ opened_files), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+#ifdef _WIN32
+ tt_int_op(smartlist_len(opened_files), OP_EQ, 6);
+#else
+ tt_int_op(smartlist_len(opened_files), OP_EQ, 5);
+#endif
+ tt_int_op(smartlist_contains_string(opened_files, torrcd), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, subfolder), OP_EQ, 1);
+ // * will match the subfolder inside torrc.d, so it will be included
+ tt_int_op(smartlist_contains_string(opened_files, in_subfolder), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, empty), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, file), OP_EQ, 1);
+#ifdef _WIN32
+ // * matches the dot file on Windows
+ tt_int_op(smartlist_contains_string(opened_files, dot), OP_EQ, 1);
+#endif
+
+ // test with wildcards in folder and file
+ SMARTLIST_FOREACH(opened_files, char *, f, tor_free(f));
+ smartlist_clear(opened_files);
+ config_free_lines(result);
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s"PATH_SEPARATOR"*"PATH_SEPARATOR"*\n",
+ torrcd);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ opened_files), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+#ifdef _WIN32
+ tt_int_op(smartlist_len(opened_files), OP_EQ, 6);
+#else
+ tt_int_op(smartlist_len(opened_files), OP_EQ, 5);
+#endif
+ tt_int_op(smartlist_contains_string(opened_files, torrcd), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, subfolder), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, in_subfolder), OP_EQ, 1);
+ // stat is called on the following files, so they count as opened
+ tt_int_op(smartlist_contains_string(opened_files, empty), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, file), OP_EQ, 1);
+#ifdef _WIN32
+ // * matches the dot file on Windows
+ tt_int_op(smartlist_contains_string(opened_files, dot), OP_EQ, 1);
+#endif
+
done:
SMARTLIST_FOREACH(opened_files, char *, f, tor_free(f));
smartlist_free(opened_files);
config_free_lines(result);
tor_free(torrcd);
tor_free(subfolder);
- tor_free(path);
+ tor_free(in_subfolder);
tor_free(empty);
tor_free(file);
tor_free(dot);
@@ -6241,9 +6836,47 @@ test_config_getinfo_config_names(void *arg)
tor_free(answer);
}
+static void
+test_config_duplicate_orports(void *arg)
+{
+ (void)arg;
+
+ config_line_t *config_port = NULL;
+ smartlist_t *ports = smartlist_new();
+
+ // Pretend that the user has specified an implicit 0.0.0.0:9050, an implicit
+ // [::]:9050, and an explicit on [::1]:9050.
+ config_line_append(&config_port, "ORPort", "9050"); // two implicit entries.
+ config_line_append(&config_port, "ORPort", "[::1]:9050");
+
+ // Parse IPv4, then IPv6.
+ port_parse_config(ports, config_port, "OR", CONN_TYPE_OR_LISTENER, "0.0.0.0",
+ 0, CL_PORT_SERVER_OPTIONS);
+ port_parse_config(ports, config_port, "OR", CONN_TYPE_OR_LISTENER, "[::]",
+ 0, CL_PORT_SERVER_OPTIONS);
+
+ // There should be three ports at this point.
+ tt_int_op(smartlist_len(ports), OP_EQ, 3);
+
+ remove_duplicate_orports(ports);
+
+ // The explicit IPv6 port should have replaced the implicit IPv6 port.
+ tt_int_op(smartlist_len(ports), OP_EQ, 2);
+
+ done:
+ SMARTLIST_FOREACH(ports,port_cfg_t *,pf,port_cfg_free(pf));
+ smartlist_free(ports);
+ config_free_lines(config_port);
+}
+
+#ifndef COCCI
#define CONFIG_TEST(name, flags) \
{ #name, test_config_ ## name, flags, NULL, NULL }
+#define CONFIG_TEST_SETUP(suffix, name, flags, setup, setup_data) \
+ { #name#suffix, test_config_ ## name, flags, setup, setup_data }
+#endif
+
struct testcase_t config_tests[] = {
CONFIG_TEST(adding_trusted_dir_server, TT_FORK),
CONFIG_TEST(adding_fallback_dir_server, TT_FORK),
@@ -6254,7 +6887,11 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(adding_dir_servers, TT_FORK),
CONFIG_TEST(default_dir_servers, TT_FORK),
CONFIG_TEST(default_fallback_dirs, 0),
- CONFIG_TEST(resolve_my_address, TT_FORK),
+ CONFIG_TEST_SETUP(_v4, find_my_address, TT_FORK,
+ &passthrough_setup, &addr_param_v4),
+ CONFIG_TEST_SETUP(_v6, find_my_address, TT_FORK,
+ &passthrough_setup, &addr_param_v6),
+ CONFIG_TEST(find_my_address_mixed, TT_FORK),
CONFIG_TEST(addressmap, 0),
CONFIG_TEST(parse_bridge_line, 0),
CONFIG_TEST(parse_transport_options_line, 0),
@@ -6287,6 +6924,8 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(include_flag_both_without, TT_FORK),
CONFIG_TEST(include_flag_torrc_only, TT_FORK),
CONFIG_TEST(include_flag_defaults_only, TT_FORK),
+ CONFIG_TEST(include_wildcards, 0),
+ CONFIG_TEST(include_hidden, 0),
CONFIG_TEST(dup_and_filter, 0),
CONFIG_TEST(check_bridge_distribution_setting_not_a_bridge, TT_FORK),
CONFIG_TEST(check_bridge_distribution_setting_valid, 0),
@@ -6297,5 +6936,6 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(extended_fmt, 0),
CONFIG_TEST(kvline_parse, 0),
CONFIG_TEST(getinfo_config_names, 0),
+ CONFIG_TEST(duplicate_orports, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_connection.c b/src/test/test_connection.c
index fca4d884bb..954aeb82e3 100644
--- a/src/test/test_connection.c
+++ b/src/test/test_connection.c
@@ -10,6 +10,7 @@
#include "core/or/or.h"
#include "test/test.h"
+#include "app/config/config.h"
#include "app/config/or_options_st.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_edge.h"
@@ -882,10 +883,8 @@ mock_node_get_mutable_by_id(const char *digest)
test_node.ri = &node_ri;
memset(test_node.identity, 'c', sizeof(test_node.identity));
- tor_addr_t ipv4_addr;
- tor_addr_parse(&ipv4_addr, "18.0.0.1");
- node_ri.addr = tor_addr_to_ipv4h(&ipv4_addr);
- node_ri.or_port = 1;
+ tor_addr_parse(&node_ri.ipv4_addr, "18.0.0.1");
+ node_ri.ipv4_orport = 1;
return &test_node;
}
@@ -912,7 +911,8 @@ test_failed_orconn_tracker(void *arg)
/* Prepare the OR connection that will be used in this test */
or_connection_t or_conn;
- tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr, "18.0.0.1"));
+ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.canonical_orport.addr,
+ "18.0.0.1"));
tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.base_.addr, "18.0.0.1"));
or_conn.base_.port = 1;
memset(or_conn.identity_digest, 'c', sizeof(or_conn.identity_digest));
@@ -963,6 +963,114 @@ test_failed_orconn_tracker(void *arg)
;
}
+static void
+test_conn_describe(void *arg)
+{
+ (void)arg;
+ or_options_t *options = get_options_mutable();
+ options->SafeLogging_ = SAFELOG_SCRUB_ALL;
+
+ // Let's start with a listener connection since they're simple.
+ connection_t *conn = connection_new(CONN_TYPE_OR_LISTENER, AF_INET);
+ tor_addr_parse(&conn->addr, "44.22.11.11");
+ conn->port = 80;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR listener connection (ready) on 44.22.11.11:80");
+ // If the address is unspec, we should still work.
+ tor_addr_make_unspec(&conn->addr);
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR listener connection (ready) on <unset>:80");
+ // Try making the address null.
+ tor_addr_make_null(&conn->addr, AF_INET);
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR listener connection (ready) on 0.0.0.0:80");
+ // What if the address is uninitialized? (This can happen if we log about the
+ // connection before we set the address.)
+ memset(&conn->addr, 0, sizeof(conn->addr));
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR listener connection (ready) on <unset>:80");
+ connection_free_minimal(conn);
+
+ // Try a unix socket.
+ conn = connection_new(CONN_TYPE_CONTROL_LISTENER, AF_UNIX);
+ conn->address = tor_strdup("/a/path/that/could/exist");
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "Control listener connection (ready) on /a/path/that/could/exist");
+ connection_free_minimal(conn);
+
+ // Try an IPv6 address.
+ conn = connection_new(CONN_TYPE_AP_LISTENER, AF_INET6);
+ tor_addr_parse(&conn->addr, "ff00::3");
+ conn->port = 9050;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "Socks listener connection (ready) on [ff00::3]:9050");
+ connection_free_minimal(conn);
+
+ // Now let's mess with exit connections. They have some special issues.
+ options->SafeLogging_ = SAFELOG_SCRUB_NONE;
+ conn = connection_new(CONN_TYPE_EXIT, AF_INET);
+ // If address and state are unset, we should say SOMETHING.
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "Exit connection (uninitialized) to <unset> (DNS lookup pending)");
+ // Now suppose that the address is set but we haven't resolved the hostname.
+ conn->port = 443;
+ conn->address = tor_strdup("www.torproject.org");
+ conn->state = EXIT_CONN_STATE_RESOLVING;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "Exit connection (waiting for dest info) to "
+ "www.torproject.org:443 (DNS lookup pending)");
+ // Now give it a hostname!
+ tor_addr_parse(&conn->addr, "192.168.8.8");
+ conn->state = EXIT_CONN_STATE_OPEN;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "Exit connection (open) to 192.168.8.8:443");
+ // But what if safelogging is on?
+ options->SafeLogging_ = SAFELOG_SCRUB_RELAY;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "Exit connection (open) to [scrubbed]");
+ connection_free_minimal(conn);
+
+ // Now at last we look at OR addresses, which are complicated.
+ conn = connection_new(CONN_TYPE_OR, AF_INET6);
+ conn->state = OR_CONN_STATE_OPEN;
+ conn->port = 8080;
+ tor_addr_parse(&conn->addr, "[ffff:3333:1111::2]");
+ // This should get scrubbed, since the lack of a set ID means we might be
+ // talking to a client.
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR connection (open) with [scrubbed]");
+ // But now suppose we aren't safelogging? We'll get the address then.
+ options->SafeLogging_ = SAFELOG_SCRUB_NONE;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR connection (open) with [ffff:3333:1111::2]:8080");
+ // Suppose we have an ID, so we know it isn't a client.
+ TO_OR_CONN(conn)->identity_digest[3] = 7;
+ options->SafeLogging_ = SAFELOG_SCRUB_RELAY; // back to safelogging.
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR connection (open) with [ffff:3333:1111::2]:8080 "
+ "ID=0000000700000000000000000000000000000000");
+ // Add a 'canonical address' that is the same as the one we have.
+ tor_addr_parse(&TO_OR_CONN(conn)->canonical_orport.addr,
+ "[ffff:3333:1111::2]");
+ TO_OR_CONN(conn)->canonical_orport.port = 8080;
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR connection (open) with [ffff:3333:1111::2]:8080 "
+ "ID=0000000700000000000000000000000000000000");
+ // Add a different 'canonical address'
+ tor_addr_parse(&TO_OR_CONN(conn)->canonical_orport.addr,
+ "[ffff:3333:1111::8]");
+ tt_str_op(connection_describe(conn), OP_EQ,
+ "OR connection (open) with [ffff:3333:1111::2]:8080 "
+ "ID=0000000700000000000000000000000000000000 "
+ "canonical_addr=[ffff:3333:1111::8]:8080");
+
+ // Clear identity_digest so that free_minimal won't complain.
+ memset(TO_OR_CONN(conn)->identity_digest, 0, DIGEST_LEN);
+
+ done:
+ connection_free_minimal(conn);
+}
+
#ifndef COCCI
#define CONNECTION_TESTCASE(name, fork, setup) \
{ #name, test_conn_##name, fork, &setup, NULL }
@@ -997,5 +1105,6 @@ struct testcase_t connection_tests[] = {
//CONNECTION_TESTCASE(func_suffix, TT_FORK, setup_func_pair),
{ "failed_orconn_tracker", test_failed_orconn_tracker, TT_FORK, NULL, NULL },
+ { "describe", test_conn_describe, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_controller.c b/src/test/test_controller.c
index a69ec17db8..49efeb5f88 100644
--- a/src/test/test_controller.c
+++ b/src/test/test_controller.c
@@ -19,6 +19,7 @@
#include "feature/rend/rendservice.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/nodelist.h"
+#include "feature/stats/rephist.h"
#include "test/test.h"
#include "test/test_helpers.h"
#include "lib/net/resolve.h"
@@ -2112,6 +2113,91 @@ test_control_getconf(void *arg)
smartlist_free(reply_strs);
}
+static int
+mock_rep_hist_get_circuit_handshake(uint16_t type)
+{
+ int ret;
+
+ switch (type) {
+ case ONION_HANDSHAKE_TYPE_NTOR:
+ ret = 80;
+ break;
+ case ONION_HANDSHAKE_TYPE_TAP:
+ ret = 86;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+test_stats(void *arg)
+{
+ /* We just need one of these to pass, it doesn't matter what's in it */
+ control_connection_t dummy;
+ /* Get results out */
+ char *answer = NULL;
+ const char *errmsg = NULL;
+
+ (void) arg;
+
+ /* We need these for returning the (mock) rephist. */
+ MOCK(rep_hist_get_circuit_handshake_requested,
+ mock_rep_hist_get_circuit_handshake);
+ MOCK(rep_hist_get_circuit_handshake_assigned,
+ mock_rep_hist_get_circuit_handshake);
+
+ /* NTor tests */
+ getinfo_helper_rephist(&dummy, "stats/ntor/requested",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tt_str_op(answer, OP_EQ, "80");
+ tor_free(answer);
+ errmsg = NULL;
+
+ getinfo_helper_rephist(&dummy, "stats/ntor/assigned",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tt_str_op(answer, OP_EQ, "80");
+ tor_free(answer);
+ errmsg = NULL;
+
+ /* TAP tests */
+ getinfo_helper_rephist(&dummy, "stats/tap/requested",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tt_str_op(answer, OP_EQ, "86");
+ tor_free(answer);
+ errmsg = NULL;
+
+ getinfo_helper_rephist(&dummy, "stats/tap/assigned",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tt_str_op(answer, OP_EQ, "86");
+ tor_free(answer);
+ errmsg = NULL;
+
+ getinfo_helper_rephist(&dummy, "stats/tap/onion_circuits_ddosed",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_str_op(errmsg, OP_EQ, "Unrecognized handshake type");
+ errmsg = NULL;
+
+ done:
+ UNMOCK(rep_hist_get_circuit_handshake_requested);
+ UNMOCK(rep_hist_get_circuit_handshake_assigned);
+ tor_free(answer);
+
+ return;
+}
+
#ifndef COCCI
#define PARSER_TEST(type) \
{ "parse/" #type, test_controller_parse_cmd, 0, &passthrough_setup, \
@@ -2146,5 +2232,6 @@ struct testcase_t controller_tests[] = {
{ "getinfo_md_all", test_getinfo_md_all, 0, NULL, NULL },
{ "control_reply", test_control_reply, 0, NULL, NULL },
{ "control_getconf", test_control_getconf, 0, NULL, NULL },
+ { "stats", test_stats, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 0d75a212e9..ffd6a25bd5 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -2107,21 +2107,21 @@ test_crypto_curve25519_encode(void *arg)
{
curve25519_secret_key_t seckey;
curve25519_public_key_t key1, key2, key3;
- char buf[64];
+ char buf[64], buf_nopad[64];
(void)arg;
curve25519_secret_key_generate(&seckey, 0);
curve25519_public_key_generate(&key1, &seckey);
- curve25519_public_to_base64(buf, &key1);
+ curve25519_public_to_base64(buf, &key1, true);
tt_int_op(CURVE25519_BASE64_PADDED_LEN, OP_EQ, strlen(buf));
tt_int_op(0, OP_EQ, curve25519_public_from_base64(&key2, buf));
tt_mem_op(key1.public_key,OP_EQ, key2.public_key, CURVE25519_PUBKEY_LEN);
- buf[CURVE25519_BASE64_PADDED_LEN - 1] = '\0';
- tt_int_op(CURVE25519_BASE64_PADDED_LEN-1, OP_EQ, strlen(buf));
- tt_int_op(0, OP_EQ, curve25519_public_from_base64(&key3, buf));
+ curve25519_public_to_base64(buf_nopad, &key1, false);
+ tt_int_op(CURVE25519_BASE64_LEN, OP_EQ, strlen(buf_nopad));
+ tt_int_op(0, OP_EQ, curve25519_public_from_base64(&key3, buf_nopad));
tt_mem_op(key1.public_key,OP_EQ, key3.public_key, CURVE25519_PUBKEY_LEN);
/* Now try bogus parses. */
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 3a0b8237cb..88fbd5ca7d 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -203,9 +203,9 @@ basic_routerinfo_new(const char *nickname, uint32_t ipv4_addr,
r1->nickname = tor_strdup(nickname);
r1->platform = tor_strdup(platform);
- r1->addr = ipv4_addr;
- r1->or_port = or_port;
- r1->dir_port = dir_port;
+ tor_addr_from_ipv4h(&r1->ipv4_addr, ipv4_addr);
+ r1->ipv4_orport = or_port;
+ r1->ipv4_dirport = dir_port;
r1->supports_tunnelled_dir_requests = 1;
router_set_rsa_onion_pkey(pk1, &r1->onion_pkey, &r1->onion_pkey_len);
@@ -236,8 +236,8 @@ get_new_router_line(const routerinfo_t *r1)
tor_asprintf(&line,
"router %s %s %d 0 %d\n",
- r1->nickname, fmt_addr32(r1->addr),
- r1->or_port, r1->dir_port);
+ r1->nickname, fmt_addr(&r1->ipv4_addr),
+ r1->ipv4_orport, r1->ipv4_dirport);
tor_assert(line);
return line;
@@ -397,18 +397,14 @@ get_new_ntor_onion_key_line(const curve25519_public_key_t *ntor_onion_pubkey)
{
char *line = NULL;
char cert_buf[256];
- int rv = 0;
tor_assert(ntor_onion_pubkey);
- rv = base64_encode(cert_buf, sizeof(cert_buf),
- (const char*)ntor_onion_pubkey->public_key, 32,
- BASE64_ENCODE_MULTILINE);
- tor_assert(rv > 0);
+ curve25519_public_to_base64(cert_buf, ntor_onion_pubkey, false);
tor_assert(strlen(cert_buf) > 0);
tor_asprintf(&line,
- "ntor-onion-key %s",
+ "ntor-onion-key %s\n",
cert_buf);
tor_assert(line);
@@ -638,9 +634,9 @@ setup_dir_formats_options(const char *arg, or_options_t *options)
STMT_BEGIN \
tt_assert(r1); \
tt_assert(rp1); \
- tt_int_op(rp1->addr,OP_EQ, r1->addr); \
- tt_int_op(rp1->or_port,OP_EQ, r1->or_port); \
- tt_int_op(rp1->dir_port,OP_EQ, r1->dir_port); \
+ tt_assert(tor_addr_eq(&rp1->ipv4_addr, &r1->ipv4_addr)); \
+ tt_int_op(rp1->ipv4_orport,OP_EQ, r1->ipv4_orport); \
+ tt_int_op(rp1->ipv4_dirport,OP_EQ, r1->ipv4_dirport); \
tt_int_op(rp1->bandwidthrate,OP_EQ, r1->bandwidthrate); \
tt_int_op(rp1->bandwidthburst,OP_EQ, r1->bandwidthburst); \
tt_int_op(rp1->bandwidthcapacity,OP_EQ, r1->bandwidthcapacity); \
@@ -718,7 +714,7 @@ test_dir_formats_rsa(void *arg)
options->ContactInfo = tor_strdup("Magri White "
"<magri@elsewhere.example.com>");
- setup_mock_configured_ports(r1->or_port, r1->dir_port);
+ setup_mock_configured_ports(r1->ipv4_orport, r1->ipv4_dirport);
buf = router_dump_router_to_string(r1, r1->identity_pkey, NULL, NULL, NULL);
tt_assert(buf);
@@ -767,7 +763,7 @@ test_dir_formats_rsa(void *arg)
tt_str_op(buf,OP_EQ, buf2);
tor_free(buf);
- setup_mock_configured_ports(r1->or_port, r1->dir_port);
+ setup_mock_configured_ports(r1->ipv4_orport, r1->ipv4_dirport);
buf = router_dump_router_to_string(r1, r1->identity_pkey, NULL, NULL, NULL);
tt_assert(buf);
@@ -801,7 +797,7 @@ test_dir_formats_rsa(void *arg)
MOCK(tor_cert_dup, mock_tor_cert_dup_null);
/* Fake just enough of an ORPort and DirPort to get by */
- setup_mock_configured_ports(r1->or_port, r1->dir_port);
+ setup_mock_configured_ports(r1->ipv4_orport, r1->ipv4_dirport);
/* Test some of the low-level static functions. */
e1 = router_build_fresh_signed_extrainfo(r1);
@@ -947,7 +943,7 @@ test_dir_formats_rsa_ed25519(void *arg)
ed25519_secret_key_from_seed(&kp2.seckey,
(const uint8_t*)"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
ed25519_public_key_generate(&kp2.pubkey, &kp2.seckey);
- r2->cache_info.signing_key_cert = tor_cert_create(&kp1,
+ r2->cache_info.signing_key_cert = tor_cert_create_ed25519(&kp1,
CERT_TYPE_ID_SIGNING,
&kp2.pubkey,
now, 86400,
@@ -970,7 +966,7 @@ test_dir_formats_rsa_ed25519(void *arg)
smartlist_add(r2->exit_policy, ex2);
/* Fake just enough of an ORPort to get by */
- setup_mock_configured_ports(r2->or_port, 0);
+ setup_mock_configured_ports(r2->ipv4_orport, 0);
buf = router_dump_router_to_string(r2,
r2->identity_pkey, r2_onion_pkey,
@@ -1066,7 +1062,7 @@ test_dir_formats_rsa_ed25519(void *arg)
tt_str_op(buf, OP_EQ, buf2);
tor_free(buf);
- setup_mock_configured_ports(r2->or_port, 0);
+ setup_mock_configured_ports(r2->ipv4_orport, 0);
buf = router_dump_router_to_string(r2, r2->identity_pkey, NULL, NULL, NULL);
tt_assert(buf);
@@ -1112,7 +1108,7 @@ test_dir_formats_rsa_ed25519(void *arg)
MOCK(get_current_curve25519_keypair, mock_get_current_curve25519_keypair);
/* Fake just enough of an ORPort to get by */
- setup_mock_configured_ports(r2->or_port, 0);
+ setup_mock_configured_ports(r2->ipv4_orport, 0);
/* Test the high-level interface. */
rv = router_build_fresh_descriptor(&r2_out, &e2);
@@ -3061,9 +3057,9 @@ test_same_voter(networkstatus_voter_info_t *v1,
tt_str_op(v1->nickname,OP_EQ, v2->nickname);
tt_mem_op(v1->identity_digest,OP_EQ, v2->identity_digest, DIGEST_LEN);
tt_str_op(v1->address,OP_EQ, v2->address);
- tt_int_op(v1->addr,OP_EQ, v2->addr);
- tt_int_op(v1->dir_port,OP_EQ, v2->dir_port);
- tt_int_op(v1->or_port,OP_EQ, v2->or_port);
+ tt_assert(tor_addr_eq(&v1->ipv4_addr, &v2->ipv4_addr));
+ tt_int_op(v1->ipv4_dirport,OP_EQ, v2->ipv4_dirport);
+ tt_int_op(v1->ipv4_orport,OP_EQ, v2->ipv4_orport);
tt_str_op(v1->contact,OP_EQ, v2->contact);
tt_mem_op(v1->vote_digest,OP_EQ, v2->vote_digest, DIGEST_LEN);
done:
@@ -3153,9 +3149,9 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
"\x3\x3\x3\x3",
DIGEST_LEN);
tt_mem_op(rs->descriptor_digest,OP_EQ, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
- tt_int_op(rs->addr,OP_EQ, 0x99008801);
- tt_int_op(rs->or_port,OP_EQ, 443);
- tt_int_op(rs->dir_port,OP_EQ, 8000);
+ tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99008801));
+ tt_int_op(rs->ipv4_orport,OP_EQ, 443);
+ tt_int_op(rs->ipv4_dirport,OP_EQ, 8000);
/* no flags except "running" (16) and "v2dir" (64) and "valid" (128) */
tt_u64_op(vrs->flags, OP_EQ, UINT64_C(0xd0));
} else if (tor_memeq(rs->identity_digest,
@@ -3175,9 +3171,9 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
tt_str_op(rs->nickname,OP_EQ, "router1");
}
tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
- tt_int_op(rs->addr,OP_EQ, 0x99009901);
- tt_int_op(rs->or_port,OP_EQ, 443);
- tt_int_op(rs->dir_port,OP_EQ, 0);
+ tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99009901));
+ tt_int_op(rs->ipv4_orport,OP_EQ, 443);
+ tt_int_op(rs->ipv4_dirport,OP_EQ, 0);
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
tt_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
tt_int_op(rs->ipv6_orport,OP_EQ, 4711);
@@ -3269,9 +3265,9 @@ test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now)
tt_str_op(rs->nickname,OP_EQ, "router1");
tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
tt_int_op(rs->published_on,OP_EQ, now-1000);
- tt_int_op(rs->addr,OP_EQ, 0x99009901);
- tt_int_op(rs->or_port,OP_EQ, 443);
- tt_int_op(rs->dir_port,OP_EQ, 0);
+ tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99009901));
+ tt_int_op(rs->ipv4_orport,OP_EQ, 443);
+ tt_int_op(rs->ipv4_dirport,OP_EQ, 0);
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
tt_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
tt_int_op(rs->ipv6_orport,OP_EQ, 4711);
@@ -3643,9 +3639,9 @@ test_a_networkstatus(
voter = smartlist_get(v1->voters, 0);
tt_str_op(voter->nickname,OP_EQ, "Voter1");
tt_str_op(voter->address,OP_EQ, "1.2.3.4");
- tt_int_op(voter->addr,OP_EQ, 0x01020304);
- tt_int_op(voter->dir_port,OP_EQ, 80);
- tt_int_op(voter->or_port,OP_EQ, 9000);
+ tt_assert(tor_addr_eq_ipv4h(&voter->ipv4_addr, 0x01020304));
+ tt_int_op(voter->ipv4_dirport,OP_EQ, 80);
+ tt_int_op(voter->ipv4_orport,OP_EQ, 9000);
tt_str_op(voter->contact,OP_EQ, "voter@example.com");
tt_assert(v1->cert);
tt_assert(!crypto_pk_cmp_keys(sign_skey_1, v1->cert->signing_key));
@@ -4147,9 +4143,9 @@ gen_routerstatus_for_umbw(int idx, time_t now)
strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
memset(rs->identity_digest, 3, DIGEST_LEN);
memset(rs->descriptor_digest, 78, DIGEST_LEN);
- rs->addr = 0x99008801;
- rs->or_port = 443;
- rs->dir_port = 8000;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0x99008801);
+ rs->ipv4_orport = 443;
+ rs->ipv4_dirport = 8000;
/* all flags but running and valid cleared */
rs->is_flagged_running = 1;
rs->is_valid = 1;
@@ -4171,9 +4167,9 @@ gen_routerstatus_for_umbw(int idx, time_t now)
strlcpy(rs->nickname, "router1", sizeof(rs->nickname));
memset(rs->identity_digest, 5, DIGEST_LEN);
memset(rs->descriptor_digest, 77, DIGEST_LEN);
- rs->addr = 0x99009901;
- rs->or_port = 443;
- rs->dir_port = 0;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0x99009901);
+ rs->ipv4_orport = 443;
+ rs->ipv4_dirport = 0;
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
tor_addr_copy(&rs->ipv6_addr, &addr_ipv6);
rs->ipv6_orport = 4711;
@@ -4197,9 +4193,9 @@ gen_routerstatus_for_umbw(int idx, time_t now)
strlcpy(rs->nickname, "router3", sizeof(rs->nickname));
memset(rs->identity_digest, 0x33, DIGEST_LEN);
memset(rs->descriptor_digest, 79, DIGEST_LEN);
- rs->addr = 0xAA009901;
- rs->or_port = 400;
- rs->dir_port = 9999;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0xAA009901);
+ rs->ipv4_orport = 400;
+ rs->ipv4_dirport = 9999;
rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
rs->is_flagged_running = rs->is_valid =
rs->is_possible_guard = 1;
@@ -4222,9 +4218,9 @@ gen_routerstatus_for_umbw(int idx, time_t now)
strlcpy(rs->nickname, "router4", sizeof(rs->nickname));
memset(rs->identity_digest, 0x34, DIGEST_LEN);
memset(rs->descriptor_digest, 47, DIGEST_LEN);
- rs->addr = 0xC0000203;
- rs->or_port = 500;
- rs->dir_port = 1999;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0xC0000203);
+ rs->ipv4_orport = 500;
+ rs->ipv4_dirport = 1999;
/* all flags but running and valid cleared */
rs->is_flagged_running = 1;
rs->is_valid = 1;
@@ -4324,9 +4320,9 @@ test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
"\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
DIGEST_LEN);
tt_mem_op(rs->descriptor_digest,OP_EQ, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
- tt_int_op(rs->addr,OP_EQ, 0x99008801);
- tt_int_op(rs->or_port,OP_EQ, 443);
- tt_int_op(rs->dir_port,OP_EQ, 8000);
+ tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99008801));
+ tt_int_op(rs->ipv4_orport,OP_EQ, 443);
+ tt_int_op(rs->ipv4_dirport,OP_EQ, 8000);
tt_assert(rs->has_bandwidth);
tt_assert(vrs->has_measured_bw);
tt_int_op(rs->bandwidth_kb,OP_EQ, max_unmeasured_bw_kb / 2);
@@ -4348,9 +4344,9 @@ test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
DIGEST_LEN);
tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
- tt_int_op(rs->addr,OP_EQ, 0x99009901);
- tt_int_op(rs->or_port,OP_EQ, 443);
- tt_int_op(rs->dir_port,OP_EQ, 0);
+ tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99009901));
+ tt_int_op(rs->ipv4_orport,OP_EQ, 443);
+ tt_int_op(rs->ipv4_dirport,OP_EQ, 0);
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
tt_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
tt_int_op(rs->ipv6_orport,OP_EQ, 4711);
@@ -4457,9 +4453,9 @@ test_routerstatus_for_umbw(routerstatus_t *rs, time_t now)
tt_str_op(rs->nickname,OP_EQ, "router1");
tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
tt_int_op(rs->published_on,OP_EQ, now-1000);
- tt_int_op(rs->addr,OP_EQ, 0x99009901);
- tt_int_op(rs->or_port,OP_EQ, 443);
- tt_int_op(rs->dir_port,OP_EQ, 0);
+ tt_assert(tor_addr_eq_ipv4h(&rs->ipv4_addr, 0x99009901));
+ tt_int_op(rs->ipv4_orport,OP_EQ, 443);
+ tt_int_op(rs->ipv4_dirport,OP_EQ, 0);
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
tt_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
tt_int_op(rs->ipv6_orport,OP_EQ, 4711);
@@ -4560,9 +4556,9 @@ test_dir_fmt_control_ns(void *arg)
strlcpy(rs.nickname, "TetsuoMilk", sizeof(rs.nickname));
memcpy(rs.identity_digest, "Stately, plump Buck ", DIGEST_LEN);
memcpy(rs.descriptor_digest, "Mulligan came up fro", DIGEST_LEN);
- rs.addr = 0x20304050;
- rs.or_port = 9001;
- rs.dir_port = 9002;
+ tor_addr_from_ipv4h(&rs.ipv4_addr, 0x20304050);
+ rs.ipv4_orport = 9001;
+ rs.ipv4_dirport = 9002;
rs.is_exit = 1;
rs.is_fast = 1;
rs.is_flagged_running = 1;
@@ -4669,7 +4665,7 @@ reset_routerstatus(routerstatus_t *rs,
hex_identity_digest, HEX_DIGEST_LEN);
/* A zero address matches everything, so the address needs to be set.
* But the specific value is irrelevant. */
- rs->addr = ipv4_addr;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, ipv4_addr);
}
#define ROUTER_A_ID_STR "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
@@ -7277,8 +7273,8 @@ test_dir_dirserv_router_get_status(void *arg)
/* Set up the routerinfo */
ri = tor_malloc_zero(sizeof(routerinfo_t));
- ri->addr = 0xc0a80001u;
- ri->or_port = 9001;
+ tor_addr_from_ipv4h(&ri->ipv4_addr, 0xc0a80001u);
+ ri->ipv4_orport = 9001;
ri->platform = tor_strdup("0.4.0.1-alpha");
ri->nickname = tor_strdup("Jessica");
ri->identity_pkey = crypto_pk_dup_key(pk);
@@ -7294,7 +7290,7 @@ test_dir_dirserv_router_get_status(void *arg)
ed25519_secret_key_from_seed(&kp2.seckey,
(const uint8_t*)"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
ed25519_public_key_generate(&kp2.pubkey, &kp2.seckey);
- ri->cache_info.signing_key_cert = tor_cert_create(&kp1,
+ ri->cache_info.signing_key_cert = tor_cert_create_ed25519(&kp1,
CERT_TYPE_ID_SIGNING,
&kp2.pubkey,
now, 86400,
@@ -7356,8 +7352,8 @@ test_dir_dirserv_would_reject_router(void *arg)
/* Set up the routerstatus */
memset(&rs, 0, sizeof(rs));
- rs.addr = 0xc0a80001u;
- rs.or_port = 9001;
+ tor_addr_from_ipv4h(&rs.ipv4_addr, 0xc0a80001u);
+ rs.ipv4_orport = 9001;
strlcpy(rs.nickname, "Nicole", sizeof(rs.nickname));
memcpy(rs.identity_digest, "Cloud nine is great ", DIGEST_LEN);
diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c
index f2b4e8724b..6eb4fb6d43 100644
--- a/src/test/test_dir_common.c
+++ b/src/test/test_dir_common.c
@@ -97,9 +97,9 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
memset(rs->identity_digest, TEST_DIR_ROUTER_ID_1, DIGEST_LEN);
memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_1, DIGEST_LEN);
- rs->addr = 0x99008801;
- rs->or_port = 443;
- rs->dir_port = 8000;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0x99008801);
+ rs->ipv4_orport = 443;
+ rs->ipv4_dirport = 8000;
/* all flags but running and v2dir cleared */
rs->is_flagged_running = 1;
rs->is_v2_dir = 1;
@@ -114,9 +114,9 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
strlcpy(rs->nickname, "router1", sizeof(rs->nickname));
memset(rs->identity_digest, TEST_DIR_ROUTER_ID_2, DIGEST_LEN);
memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_2, DIGEST_LEN);
- rs->addr = 0x99009901;
- rs->or_port = 443;
- rs->dir_port = 0;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0x99009901);
+ rs->ipv4_orport = 443;
+ rs->ipv4_dirport = 0;
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
tor_addr_copy(&rs->ipv6_addr, &addr_ipv6);
rs->ipv6_orport = 4711;
@@ -132,9 +132,9 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
strlcpy(rs->nickname, "router3", sizeof(rs->nickname));
memset(rs->identity_digest, TEST_DIR_ROUTER_ID_3, DIGEST_LEN);
memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_3, DIGEST_LEN);
- rs->addr = 0xAA009901;
- rs->or_port = 400;
- rs->dir_port = 9999;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0xAA009901);
+ rs->ipv4_orport = 400;
+ rs->ipv4_dirport = 9999;
rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
rs->is_flagged_running = rs->is_valid = rs->is_v2_dir =
rs->is_possible_guard = 1;
@@ -148,9 +148,9 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
strlcpy(rs->nickname, "router4", sizeof(rs->nickname));
memset(rs->identity_digest, TEST_DIR_ROUTER_ID_4, DIGEST_LEN);
memset(rs->descriptor_digest, TEST_DIR_ROUTER_DD_4, DIGEST_LEN);
- rs->addr = 0xC0000203;
- rs->or_port = 500;
- rs->dir_port = 1999;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0xC0000203);
+ rs->ipv4_orport = 500;
+ rs->ipv4_dirport = 1999;
rs->is_v2_dir = 1;
/* Running flag (and others) cleared */
break;
@@ -313,9 +313,9 @@ dir_common_construct_vote_1(networkstatus_t **vote, authority_cert_t *cert,
voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
voter->nickname = tor_strdup("Voter1");
voter->address = tor_strdup("1.2.3.4");
- voter->addr = 0x01020304;
- voter->dir_port = 80;
- voter->or_port = 9000;
+ tor_addr_from_ipv4h(&voter->ipv4_addr, 0x01020304);
+ voter->ipv4_dirport = 80;
+ voter->ipv4_orport = 9000;
voter->contact = tor_strdup("voter@example.com");
crypto_pk_get_digest(cert->identity_key, voter->identity_digest);
/*
@@ -362,9 +362,9 @@ dir_common_construct_vote_2(networkstatus_t **vote, authority_cert_t *cert,
voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
voter->nickname = tor_strdup("Voter2");
voter->address = tor_strdup("2.3.4.5");
- voter->addr = 0x02030405;
- voter->dir_port = 80;
- voter->or_port = 9000;
+ tor_addr_from_ipv4h(&voter->ipv4_addr, 0x02030405);
+ voter->ipv4_dirport = 80;
+ voter->ipv4_orport = 9000;
voter->contact = tor_strdup("voter@example.com");
crypto_pk_get_digest(cert->identity_key, voter->identity_digest);
/*
@@ -412,9 +412,9 @@ dir_common_construct_vote_3(networkstatus_t **vote, authority_cert_t *cert,
voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
voter->nickname = tor_strdup("Voter2");
voter->address = tor_strdup("3.4.5.6");
- voter->addr = 0x03040506;
- voter->dir_port = 80;
- voter->or_port = 9000;
+ tor_addr_from_ipv4h(&voter->ipv4_addr, 0x03040506);
+ voter->ipv4_dirport = 80;
+ voter->ipv4_orport = 9000;
voter->contact = tor_strdup("voter@example.com");
crypto_pk_get_digest(cert->identity_key, voter->identity_digest);
memset(voter->legacy_id_digest, (int)'A', DIGEST_LEN);
diff --git a/src/test/test_dos.c b/src/test/test_dos.c
index 527e5bbe7f..850bbef59b 100644
--- a/src/test/test_dos.c
+++ b/src/test/test_dos.c
@@ -66,9 +66,9 @@ test_dos_conn_creation(void *arg)
/* Initialize test data */
or_connection_t or_conn;
time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
- tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr,
+ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr,
"18.0.0.1"));
- tor_addr_t *addr = &or_conn.real_addr;
+ tor_addr_t *addr = &TO_CONN(&or_conn)->addr;
/* Get DoS subsystem limits */
dos_init();
@@ -108,7 +108,7 @@ test_dos_conn_creation(void *arg)
/** Helper mock: Place a fake IP addr for this channel in <b>addr_out</b> */
static int
-mock_channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out)
+mock_channel_get_addr_if_possible(const channel_t *chan, tor_addr_t *addr_out)
{
(void)chan;
tt_int_op(AF_INET,OP_EQ, tor_addr_parse(addr_out, "18.0.0.1"));
@@ -139,9 +139,9 @@ test_dos_circuit_creation(void *arg)
/* Initialize test data */
or_connection_t or_conn;
time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
- tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr,
+ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr,
"18.0.0.1"));
- tor_addr_t *addr = &or_conn.real_addr;
+ tor_addr_t *addr = &TO_CONN(&or_conn)->addr;
/* Get DoS subsystem limits */
dos_init();
@@ -202,9 +202,9 @@ test_dos_bucket_refill(void *arg)
channel_init(chan);
chan->is_client = 1;
or_connection_t or_conn;
- tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&or_conn.real_addr,
+ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr,
"18.0.0.1"));
- tor_addr_t *addr = &or_conn.real_addr;
+ tor_addr_t *addr = &TO_CONN(&or_conn)->addr;
/* Initialize DoS subsystem and get relevant limits */
dos_init();
@@ -443,10 +443,10 @@ test_known_relay(void *arg)
/* Setup an OR conn so we can pass it to the DoS subsystem. */
or_connection_t or_conn;
- tor_addr_parse(&or_conn.real_addr, "42.42.42.42");
+ tor_addr_parse(&TO_CONN(&or_conn)->addr, "42.42.42.42");
rs = tor_malloc_zero(sizeof(*rs));
- rs->addr = tor_addr_to_ipv4h(&or_conn.real_addr);
+ tor_addr_copy(&rs->ipv4_addr, &TO_CONN(&or_conn)->addr);
crypto_rand(rs->identity_digest, sizeof(rs->identity_digest));
smartlist_add(dummy_ns->routerstatus_list, rs);
@@ -457,7 +457,8 @@ test_known_relay(void *arg)
/* We have now a node in our list so we'll make sure we don't count it as a
* client connection. */
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &or_conn.real_addr, NULL, 0);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &TO_CONN(&or_conn)->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, NULL);
@@ -465,18 +466,21 @@ test_known_relay(void *arg)
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);
+ entry = geoip_lookup_client(&TO_CONN(&or_conn)->addr, NULL,
+ GEOIP_CLIENT_CONNECT);
tt_assert(entry);
/* We should have a count of 0. */
tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 0);
/* To make sure that his is working properly, make a unknown client
* 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);
+ tor_addr_parse(&TO_CONN(&or_conn)->addr, "42.42.42.43");
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &TO_CONN(&or_conn)->addr,
+ NULL, 0);
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);
+ entry = geoip_lookup_client(&TO_CONN(&or_conn)->addr, NULL,
+ GEOIP_CLIENT_CONNECT);
tt_assert(entry);
/* We should have a count of 2. */
tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 2);
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index 5ddd1a3db0..589876db2a 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -171,8 +171,8 @@ big_fake_network_setup(const struct testcase_t *testcase)
/* Note: all these guards have the same address, so you'll need to
* disable EnforceDistinctSubnets when a restriction is applied. */
- n->rs->addr = 0x04020202;
- n->rs->or_port = 1234;
+ tor_addr_from_ipv4h(&n->rs->ipv4_addr, 0x04020202);
+ n->rs->ipv4_orport = 1234;
n->rs->is_v2_dir = 1;
n->rs->has_bandwidth = 1;
n->rs->bandwidth_kb = 30;
@@ -272,8 +272,8 @@ test_node_preferred_orport(void *arg)
/* Setup node_ri */
memset(&node_ri, 0, sizeof(node_ri));
- node_ri.addr = tor_addr_to_ipv4h(&ipv4_addr);
- node_ri.or_port = ipv4_port;
+ tor_addr_copy(&node_ri.ipv4_addr, &ipv4_addr);
+ node_ri.ipv4_orport = ipv4_port;
tor_addr_copy(&node_ri.ipv6_addr, &ipv6_addr);
node_ri.ipv6_orport = ipv6_port;
@@ -322,7 +322,7 @@ test_node_preferred_orport(void *arg)
* ClientUseIPv4 is 0 */
mocked_options->ClientUseIPv4 = 0;
mocked_options->ClientUseIPv6 = 1;
- node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(mocked_options);
+ node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(mocked_options);
node_get_pref_orport(&node, &ap);
tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
tt_assert(ap.port == ipv6_port);
@@ -1002,10 +1002,10 @@ test_entry_guard_node_filter(void *arg)
g[1]->pb.path_bias_disabled = 1;
/* 2: Unreachable address. */
- n[2]->rs->addr = 0;
+ tor_addr_make_unspec(&n[2]->rs->ipv4_addr);
/* 3: ExcludeNodes */
- n[3]->rs->addr = 0x90902020;
+ tor_addr_from_ipv4h(&n[3]->rs->ipv4_addr, 0x90902020);
routerset_free(get_options_mutable()->ExcludeNodes);
get_options_mutable()->ExcludeNodes = routerset_new();
routerset_parse(get_options_mutable()->ExcludeNodes, "144.144.0.0/16", "");
@@ -1014,8 +1014,8 @@ test_entry_guard_node_filter(void *arg)
get_options_mutable()->UseBridges = 1;
sweep_bridge_list();
bl = tor_malloc_zero(sizeof(bridge_line_t));
- tor_addr_from_ipv4h(&bl->addr, n[4]->rs->addr);
- bl->port = n[4]->rs->or_port;
+ tor_addr_copy(&bl->addr, &n[4]->rs->ipv4_addr);
+ bl->port = n[4]->rs->ipv4_orport;
memcpy(bl->digest, n[4]->identity, 20);
bridge_add_from_config(bl);
bl = NULL; // prevent free.
@@ -1124,7 +1124,7 @@ test_entry_guard_expand_sample(void *arg)
routerset_parse(get_options_mutable()->ExcludeNodes, "144.144.0.0/16", "");
SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n, {
if (n_sl_idx % 64 != 0) {
- n->rs->addr = 0x90903030;
+ tor_addr_from_ipv4h(&n->rs->ipv4_addr, 0x90903030);
}
});
entry_guards_update_filtered_sets(gs);
@@ -1162,7 +1162,7 @@ test_entry_guard_expand_sample_small_net(void *arg)
test_node_free(n);
SMARTLIST_DEL_CURRENT(big_fake_net_nodes, n);
} else {
- n->rs->addr = 0; // make the filter reject this.
+ tor_addr_make_unspec(&n->rs->ipv4_addr); // make the filter reject this.
}
});
diff --git a/src/test/test_guardfraction.c b/src/test/test_guardfraction.c
index 00c200e0fd..6019dfc2b1 100644
--- a/src/test/test_guardfraction.c
+++ b/src/test/test_guardfraction.c
@@ -51,9 +51,9 @@ gen_vote_routerstatus_for_tests(const char *digest_in_hex, int is_guard)
vrs->version = tor_strdup("0.1.2.14");
strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
memset(rs->descriptor_digest, 78, DIGEST_LEN);
- rs->addr = 0x99008801;
- rs->or_port = 443;
- rs->dir_port = 8000;
+ tor_addr_from_ipv4h(&rs->ipv4_addr, 0x99008801);
+ rs->ipv4_orport = 443;
+ rs->ipv4_dirport = 8000;
/* all flags but running cleared */
rs->is_flagged_running = 1;
vrs->has_measured_bw = 1;
diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c
index f31c28b24d..851946931c 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -16,30 +16,48 @@
#include "core/or/or.h"
#include "lib/buf/buffers.h"
-#include "app/config/config.h"
#include "lib/confmgt/confmgt.h"
-#include "app/main/subsysmgr.h"
-#include "core/mainloop/connection.h"
-#include "core/or/connection_or.h"
#include "lib/crypt_ops/crypto_rand.h"
-#include "core/mainloop/mainloop.h"
-#include "feature/nodelist/nodelist.h"
-#include "core/or/relay.h"
-#include "feature/nodelist/routerlist.h"
#include "lib/dispatch/dispatch.h"
#include "lib/dispatch/dispatch_naming.h"
-#include "lib/pubsub/pubsub_build.h"
-#include "lib/pubsub/pubsub_connect.h"
#include "lib/encoding/confline.h"
#include "lib/net/resolve.h"
+#include "lib/pubsub/pubsub_build.h"
+#include "lib/pubsub/pubsub_connect.h"
+
+#include "core/mainloop/connection.h"
+#include "core/mainloop/mainloop.h"
+#include "core/or/connection_or.h"
+#include "core/or/crypt_path.h"
+#include "core/or/relay.h"
+
+#include "feature/nodelist/nodelist.h"
+#include "feature/nodelist/routerlist.h"
+
+#include "app/config/config.h"
+#include "app/main/subsysmgr.h"
#include "core/or/cell_st.h"
#include "core/or/connection_st.h"
+#include "core/or/cpath_build_state_st.h"
+#include "core/or/crypt_path_st.h"
+#include "core/or/origin_circuit_st.h"
#include "core/or/or_connection_st.h"
+
#include "feature/nodelist/node_st.h"
-#include "core/or/origin_circuit_st.h"
#include "feature/nodelist/routerlist_st.h"
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef _WIN32
+/* For mkdir() */
+#include <direct.h>
+#else
+#include <dirent.h>
+#endif /* defined(_WIN32) */
+
#include "test/test.h"
#include "test/test_helpers.h"
#include "test/test_connection.h"
@@ -187,6 +205,78 @@ mock_tor_addr_lookup__fail_on_bad_addrs(const char *name,
return tor_addr_lookup__real(name, family, out);
}
+static char *
+create_directory(const char *parent_dir, const char *name)
+{
+ char *dir = NULL;
+ tor_asprintf(&dir, "%s"PATH_SEPARATOR"%s", parent_dir, name);
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+ return dir;
+
+ done:
+ tor_free(dir);
+ return NULL;
+}
+
+static char *
+create_file(const char *parent_dir, const char *name, const char *contents)
+{
+ char *path = NULL;
+ tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", parent_dir, name);
+ contents = contents == NULL ? "" : contents;
+ tt_int_op(write_str_to_file(path, contents, 0), OP_EQ, 0);
+ return path;
+
+ done:
+ tor_free(path);
+ return NULL;
+}
+
+int
+create_test_directory_structure(const char *parent_dir)
+{
+ int ret = -1;
+ char *dir1 = NULL;
+ char *dir2 = NULL;
+ char *file1 = NULL;
+ char *file2 = NULL;
+ char *dot = NULL;
+ char *empty = NULL;
+ char *forbidden = NULL;
+
+ dir1 = create_directory(parent_dir, "dir1");
+ tt_assert(dir1);
+ dir2 = create_directory(parent_dir, "dir2");
+ tt_assert(dir2);
+ file1 = create_file(parent_dir, "file1", "Test 1");
+ tt_assert(file1);
+ file2 = create_file(parent_dir, "file2", "Test 2");
+ tt_assert(file2);
+ dot = create_file(parent_dir, ".test-hidden", "Test .");
+ tt_assert(dot);
+ empty = create_file(parent_dir, "empty", NULL);
+ tt_assert(empty);
+ forbidden = create_directory(parent_dir, "forbidden");
+ tt_assert(forbidden);
+#ifndef _WIN32
+ tt_int_op(chmod(forbidden, 0), OP_EQ, 0);
+#endif
+ ret = 0;
+ done:
+ tor_free(dir1);
+ tor_free(dir2);
+ tor_free(file1);
+ tor_free(file2);
+ tor_free(dot);
+ tor_free(empty);
+ tor_free(forbidden);
+ return ret;
+}
+
/*********** Helper funcs for making new connections/streams *****************/
/* Helper for test_conn_get_connection() */
@@ -441,3 +531,36 @@ helper_cleanup_pubsub(const struct testcase_t *testcase, void *dispatcher_)
const struct testcase_setup_t helper_pubsub_setup = {
helper_setup_pubsub, helper_cleanup_pubsub
};
+
+origin_circuit_t *
+new_test_origin_circuit(bool has_opened,
+ struct timeval circ_start_time,
+ int path_len,
+ extend_info_t **ei_list)
+{
+ origin_circuit_t *origin_circ = origin_circuit_new();
+
+ TO_CIRCUIT(origin_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ origin_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ origin_circ->build_state->desired_path_len = path_len;
+
+ if (ei_list) {
+ for (int i = 0; i < path_len; i++) {
+ extend_info_t *ei = ei_list[i];
+ cpath_append_hop(&origin_circ->cpath, ei);
+ }
+ }
+
+ if (has_opened) {
+ origin_circ->has_opened = 1;
+ TO_CIRCUIT(origin_circ)->state = CIRCUIT_STATE_OPEN;
+ origin_circ->cpath->state = CPATH_STATE_OPEN;
+ } else {
+ TO_CIRCUIT(origin_circ)->timestamp_began = circ_start_time;
+ TO_CIRCUIT(origin_circ)->timestamp_created = circ_start_time;
+ origin_circ->cpath->state = CPATH_STATE_CLOSED;
+ }
+
+ return origin_circ;
+}
diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h
index eaf18e19e2..f02ecbb0ac 100644
--- a/src/test/test_helpers.h
+++ b/src/test/test_helpers.h
@@ -33,6 +33,8 @@ connection_t *test_conn_get_connection(uint8_t state,
uint8_t type, uint8_t purpose);
or_options_t *helper_parse_options(const char *conf);
+int create_test_directory_structure(const char *parent_dir);
+
extern const char TEST_DESCRIPTORS[];
void *helper_setup_pubsub(const struct testcase_t *);
@@ -40,5 +42,10 @@ int helper_cleanup_pubsub(const struct testcase_t *, void *);
extern const struct testcase_setup_t helper_pubsub_setup;
+origin_circuit_t *new_test_origin_circuit(bool has_opened,
+ struct timeval circ_start_time,
+ int path_len,
+ extend_info_t **ei_list);
+
#endif /* !defined(TOR_TEST_HELPERS_H) */
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index ae5cc5ed84..f965344ce0 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -41,6 +41,7 @@
#include "feature/rend/rendcache.h"
#include "core/or/circuitlist.h"
#include "core/or/circuitbuild.h"
+#include "core/or/extendinfo.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_edge.h"
#include "feature/nodelist/networkstatus.h"
@@ -529,7 +530,7 @@ test_client_pick_intro(void *arg)
get_options_mutable()->ClientUseIPv6 = 1;
intro_ei = hs_get_extend_info_from_lspecs(ip->link_specifiers,
&ip->onion_key, 1);
- tt_assert(tor_addr_family(&intro_ei->addr) == AF_INET6);
+ tt_assert(tor_addr_family(&intro_ei->orports[0].addr) == AF_INET6);
}
tt_assert(intro_ei);
if (intro_ei) {
@@ -537,7 +538,8 @@ test_client_pick_intro(void *arg)
char ip_addr[TOR_ADDR_BUF_LEN];
/* We need to decorate in case it is an IPv6 else routerset_parse()
* doesn't like it. */
- ptr = tor_addr_to_str(ip_addr, &intro_ei->addr, sizeof(ip_addr), 1);
+ ptr = tor_addr_to_str(ip_addr, &intro_ei->orports[0].addr,
+ sizeof(ip_addr), 1);
tt_assert(ptr == ip_addr);
ret = routerset_parse(get_options_mutable()->ExcludeNodes,
ip_addr, "");
diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c
index 9202074e25..295d9cdb62 100644
--- a/src/test/test_hs_common.c
+++ b/src/test/test_hs_common.c
@@ -293,7 +293,6 @@ helper_add_hsdir_to_networkstatus(networkstatus_t *ns,
routerstatus_t *rs = tor_malloc_zero(sizeof(routerstatus_t));
routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t));
uint8_t identity[DIGEST_LEN];
- tor_addr_t ipv4_addr;
node_t *node = NULL;
memset(identity, identity_idx, sizeof(identity));
@@ -302,9 +301,8 @@ helper_add_hsdir_to_networkstatus(networkstatus_t *ns,
rs->is_hs_dir = is_hsdir;
rs->pv.supports_v3_hsdir = 1;
strlcpy(rs->nickname, nickname, sizeof(rs->nickname));
- tor_addr_parse(&ipv4_addr, "1.2.3.4");
- ri->addr = tor_addr_to_ipv4h(&ipv4_addr);
- rs->addr = tor_addr_to_ipv4h(&ipv4_addr);
+ tor_addr_parse(&ri->ipv4_addr, "1.2.3.4");
+ tor_addr_parse(&rs->ipv4_addr, "1.2.3.4");
ri->nickname = tor_strdup(nickname);
ri->protocol_list = tor_strdup("HSDir=1-2 LinkAuth=3");
memcpy(ri->cache_info.identity_digest, identity, DIGEST_LEN);
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index 782b78306c..b6e13c79a8 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -56,7 +56,7 @@ test_cert_encoding(void *arg)
ret = ed25519_public_key_generate(&signed_key, &secret_key);
tt_int_op(ret, == , 0);
- cert = tor_cert_create(&kp, CERT_TYPE_SIGNING_AUTH, &signed_key,
+ cert = tor_cert_create_ed25519(&kp, CERT_TYPE_SIGNING_AUTH, &signed_key,
now, 3600 * 2, CERT_FLAG_INCLUDE_SIGNING_KEY);
tt_assert(cert);
@@ -706,7 +706,7 @@ test_validate_cert(void *arg)
tt_int_op(ret, OP_EQ, 0);
/* Cert of type CERT_TYPE_AUTH_HS_IP_KEY. */
- cert = tor_cert_create(&kp, CERT_TYPE_AUTH_HS_IP_KEY,
+ cert = tor_cert_create_ed25519(&kp, CERT_TYPE_AUTH_HS_IP_KEY,
&kp.pubkey, now, 3600,
CERT_FLAG_INCLUDE_SIGNING_KEY);
tt_assert(cert);
@@ -726,8 +726,9 @@ test_validate_cert(void *arg)
tor_cert_free(cert);
/* Try a cert without including the signing key. */
- cert = tor_cert_create(&kp, CERT_TYPE_AUTH_HS_IP_KEY, &kp.pubkey, now,
- 3600, 0);
+ cert = tor_cert_create_ed25519(&kp, CERT_TYPE_AUTH_HS_IP_KEY,
+ &kp.pubkey, now, 3600, 0);
+
tt_assert(cert);
/* Test with a bad type. */
ret = cert_is_valid(cert, CERT_TYPE_AUTH_HS_IP_KEY, "unicorn");
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index 80383baff8..608e738d85 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -1545,14 +1545,12 @@ test_build_update_descriptors(void *arg)
/* Now, we'll setup a node_t. */
{
- tor_addr_t ipv4_addr;
curve25519_secret_key_t curve25519_secret_key;
memset(&ri, 0, sizeof(routerinfo_t));
- tor_addr_parse(&ipv4_addr, "127.0.0.1");
- ri.addr = tor_addr_to_ipv4h(&ipv4_addr);
- ri.or_port = 1337;
+ tor_addr_parse(&ri.ipv4_addr, "127.0.0.1");
+ ri.ipv4_orport = 1337;
ri.purpose = ROUTER_PURPOSE_GENERAL;
/* Ugly yes but we never free the "ri" object so this just makes things
* easier. */
@@ -1619,7 +1617,7 @@ test_build_update_descriptors(void *arg)
/* We won't test the service IP object because there is a specific test
* already for this but we'll make sure that the state is coherent.*/
- /* Three link specifiers are mandatoy so make sure we do have them. */
+ /* Three link specifiers are mandatory so make sure we do have them. */
tt_int_op(smartlist_len(ip_cur->base.link_specifiers), OP_EQ, 3);
/* Make sure we have a valid encryption keypair generated when we pick an
* intro point in the update process. */
diff --git a/src/test/test_include.py b/src/test/test_include.py
new file mode 100644
index 0000000000..ec261da86c
--- /dev/null
+++ b/src/test/test_include.py
@@ -0,0 +1,196 @@
+# Future imports for Python 2.7, mandatory in 3.0
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import errno
+import logging
+import os
+import random
+import socket
+import subprocess
+import sys
+import time
+import re
+
+CONTROL_SOCK_TIMEOUT = 10.0
+LOG_TIMEOUT = 60.0
+LOG_WAIT = 0.1
+
+def fail(msg):
+ logging.error('FAIL')
+ sys.exit(msg)
+
+def skip(msg):
+ logging.warning('SKIP: {}'.format(msg))
+ sys.exit(77)
+
+def wait_for_log(s):
+ cutoff = time.time() + LOG_TIMEOUT
+ while time.time() < cutoff:
+ l = tor_process.stdout.readline()
+ l = l.decode('utf8', 'backslashreplace')
+ if s in l:
+ logging.info('Tor logged: "{}"'.format(l.strip()))
+ return
+ # readline() returns a blank string when there is no output
+ # avoid busy-waiting
+ if len(l) == 0:
+ logging.debug('Tor has not logged anything, waiting for "{}"'.format(s))
+ time.sleep(LOG_WAIT)
+ else:
+ logging.info('Tor logged: "{}", waiting for "{}"'.format(l.strip(), s))
+ fail('Could not find "{}" in logs after {} seconds'.format(s, LOG_TIMEOUT))
+
+def pick_random_port():
+ port = 0
+ random.seed()
+
+ for i in range(8):
+ port = random.randint(10000, 60000)
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ if s.connect_ex(('127.0.0.1', port)) == 0:
+ s.close()
+ else:
+ break
+
+ if port == 0:
+ fail('Could not find a random free port between 10000 and 60000')
+
+ return port
+
+def check_control_list(control_out_file, expected, value_name):
+ received_count = 0
+ for e in expected:
+ received = control_out_file.readline().strip()
+ received_count += 1
+ parts = re.split('[ =-]', received.strip())
+ if len(parts) != 3 or parts[0] != '250' or parts[1] != value_name or parts[2] != e:
+ fail('Unexpected value in response line "{}". Expected {} for value {}'.format(received, e, value_name))
+ if received.startswith('250 '):
+ break
+
+ if received_count != len(expected):
+ fail('Expected response with {} lines but received {} lines'.format(len(expected), received_count))
+
+
+logging.basicConfig(level=logging.DEBUG,
+ format='%(asctime)s.%(msecs)03d %(message)s',
+ datefmt='%Y-%m-%d %H:%M:%S')
+
+if sys.hexversion < 0x02070000:
+ fail("ERROR: unsupported Python version (should be >= 2.7)")
+
+if sys.hexversion > 0x03000000 and sys.hexversion < 0x03010000:
+ fail("ERROR: unsupported Python3 version (should be >= 3.1)")
+
+if 'TOR_SKIP_TEST_INCLUDE' in os.environ:
+ skip('$TOR_SKIP_TEST_INCLUDE is set')
+
+control_port = pick_random_port()
+
+assert control_port != 0
+
+if len(sys.argv) < 4:
+ fail('Usage: %s <path-to-tor> <data-dir> <torrc>' % sys.argv[0])
+
+if not os.path.exists(sys.argv[1]):
+ fail('ERROR: cannot find tor at %s' % sys.argv[1])
+if not os.path.exists(sys.argv[2]):
+ fail('ERROR: cannot find datadir at %s' % sys.argv[2])
+if not os.path.exists(sys.argv[3]):
+ fail('ERROR: cannot find torrcdir at %s' % sys.argv[3])
+
+tor_path = sys.argv[1]
+data_dir = sys.argv[2]
+torrc_dir = sys.argv[3]
+
+empty_torrc_path = os.path.join(data_dir, 'empty_torrc')
+open(empty_torrc_path, 'w').close()
+empty_defaults_torrc_path = os.path.join(data_dir, 'empty_defaults_torrc')
+open(empty_defaults_torrc_path, 'w').close()
+torrc = os.path.join(torrc_dir, 'torrc')
+
+tor_process = subprocess.Popen([tor_path,
+ '-DataDirectory', data_dir,
+ '-ControlPort', '127.0.0.1:{}'.format(control_port),
+ '-Log', 'info stdout',
+ '-LogTimeGranularity', '1',
+ '-FetchServerDescriptors', '0',
+ '-DisableNetwork', '1',
+ '-f', torrc,
+ '--defaults-torrc', empty_defaults_torrc_path,
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+if tor_process == None:
+ fail('ERROR: running tor failed')
+
+wait_for_log('Opened Control listener')
+
+control_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+if control_socket.connect_ex(('127.0.0.1', control_port)):
+ tor_process.terminate()
+ fail('Cannot connect to ControlPort')
+control_socket.settimeout(CONTROL_SOCK_TIMEOUT)
+control_out_file = control_socket.makefile('r')
+
+control_socket.sendall('AUTHENTICATE \r\n'.encode('ascii'))
+res = control_out_file.readline().strip()
+if res != '250 OK':
+ tor_process.terminate()
+ fail('Cannot authenticate. Response was: {}'.format(res))
+
+# test configuration file values and order
+control_socket.sendall('GETCONF NodeFamily\r\n'.encode('ascii'))
+check_control_list(control_out_file, ['1', '2', '3', '4', '5', '6', '4' , '5'], 'NodeFamily')
+
+# test reloading the configuration file with seccomp sandbox enabled
+foo_path = os.path.join(torrc_dir, 'torrc.d', 'foo')
+with open(foo_path, 'a') as foo:
+ foo.write('NodeFamily 7')
+
+control_socket.sendall('SIGNAL RELOAD\r\n'.encode('ascii'))
+wait_for_log('Reloading config and resetting internal state.')
+res = control_out_file.readline().strip()
+if res != '250 OK':
+ tor_process.terminate()
+ fail('Cannot reload configuration. Response was: {}'.format(res))
+
+
+control_socket.sendall('GETCONF NodeFamily\r\n'.encode('ascii'))
+check_control_list(control_out_file, ['1', '2', '3', '4', '5', '6', '7', '4' , '5'], 'NodeFamily')
+
+# test that config-can-saveconf is 0 because we have a %include
+control_socket.sendall('getinfo config-can-saveconf\r\n'.encode('ascii'))
+res = control_out_file.readline().strip()
+if res != '250-config-can-saveconf=0':
+ tor_process.terminate()
+ fail('getinfo config-can-saveconf returned wrong response: {}'.format(res))
+else:
+ res = control_out_file.readline().strip()
+ if res != '250 OK':
+ tor_process.terminate()
+ fail('getinfo failed. Response was: {}'.format(res))
+
+# test that saveconf returns error because we have a %include
+control_socket.sendall('SAVECONF\r\n'.encode('ascii'))
+res = control_out_file.readline().strip()
+if res != '551 Unable to write configuration to disk.':
+ tor_process.terminate()
+ fail('SAVECONF returned wrong response. Response was: {}'.format(res))
+
+control_socket.sendall('SIGNAL HALT\r\n'.encode('ascii'))
+
+wait_for_log('exiting cleanly')
+logging.info('OK')
+
+try:
+ tor_process.terminate()
+except OSError as e:
+ if e.errno == errno.ESRCH: # errno 3: No such process
+ # assume tor has already exited due to SIGNAL HALT
+ logging.warn("Tor has already exited")
+ else:
+ raise
diff --git a/src/test/test_include.sh b/src/test/test_include.sh
new file mode 100755
index 0000000000..6cf695fe44
--- /dev/null
+++ b/src/test/test_include.sh
@@ -0,0 +1,111 @@
+#!/bin/sh
+
+umask 077
+set -e
+set -x
+
+# emulate realpath(), in case coreutils or equivalent is not installed.
+abspath() {
+ f="$*"
+ if [ -d "$f" ]; then
+ dir="$f"
+ base=""
+ else
+ dir="$(dirname "$f")"
+ base="/$(basename "$f")"
+ fi
+ dir="$(cd "$dir" && pwd)"
+ echo "$dir$base"
+}
+
+UNAME_OS=$(uname -s | cut -d_ -f1)
+if test "$UNAME_OS" = 'CYGWIN' || \
+ test "$UNAME_OS" = 'MSYS' || \
+ test "$UNAME_OS" = 'MINGW' || \
+ test "$UNAME_OS" = 'MINGW32' || \
+ test "$UNAME_OS" = 'MINGW64'; then
+ if test "$APPVEYOR" = 'True'; then
+ echo "This test is disabled on Windows CI, as it requires firewall exemptions. Skipping." >&2
+ exit 77
+ fi
+fi
+
+# find the tor binary
+if [ $# -ge 1 ]; then
+ TOR_BINARY="${1}"
+ shift
+else
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
+fi
+
+TOR_BINARY="$(abspath "$TOR_BINARY")"
+
+echo "TOR BINARY IS ${TOR_BINARY}"
+
+if "${TOR_BINARY}" --list-modules | grep -q "relay: no"; then
+ echo "This test requires the relay module. Skipping." >&2
+ exit 77
+fi
+
+tmpdir=
+clean () {
+ if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then
+ rm -rf "$tmpdir"
+ fi
+}
+
+trap clean EXIT HUP INT TERM
+
+tmpdir="$(mktemp -d -t tor_include_test.XXXXXX)"
+if [ -z "$tmpdir" ]; then
+ echo >&2 mktemp failed
+ exit 2
+elif [ ! -d "$tmpdir" ]; then
+ echo >&2 mktemp failed to make a directory
+ exit 3
+fi
+
+datadir="$tmpdir/data"
+mkdir "$datadir"
+
+configdir="$tmpdir/config"
+mkdir "$configdir"
+
+# translate paths to windows format
+if test "$UNAME_OS" = 'CYGWIN' || \
+ test "$UNAME_OS" = 'MSYS' || \
+ test "$UNAME_OS" = 'MINGW' || \
+ test "$UNAME_OS" = 'MINGW32' || \
+ test "$UNAME_OS" = 'MINGW64'; then
+ datadir=$(cygpath --windows "$datadir")
+ configdir=$(cygpath --windows "$configdir")
+fi
+
+# create test folder structure in configdir
+torrcd="$configdir/torrc.d"
+mkdir "$torrcd"
+mkdir "$torrcd/folder"
+mkdir "$torrcd/empty_folder"
+echo "NodeFamily 1" > "$torrcd/01_one.conf"
+echo "NodeFamily 2" > "$torrcd/02_two.conf"
+echo "NodeFamily 3" > "$torrcd/aa_three.conf"
+echo "NodeFamily 42" > "$torrcd/.hidden.conf"
+echo "NodeFamily 6" > "$torrcd/foo"
+touch "$torrcd/empty.conf"
+echo "# comment" > "$torrcd/comment.conf"
+echo "NodeFamily 4" > "$torrcd/folder/04_four.conf"
+echo "NodeFamily 5" > "$torrcd/folder/05_five.conf"
+torrc="$configdir/torrc"
+echo "Sandbox 1" > "$torrc"
+echo "
+%include $torrcd/*.conf
+%include $torrcd/f*
+%include $torrcd/*/*
+%include $torrcd/empty_folder
+%include $torrcd/empty.conf
+%include $torrcd/comment.conf
+" >> "$torrc"
+
+"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/test_include.py" "${TOR_BINARY}" "$datadir" "$configdir"
+
+exit $?
diff --git a/src/test/test_key_expiration.sh b/src/test/test_key_expiration.sh
index 2238f7aa78..1ba8179aa1 100755
--- a/src/test/test_key_expiration.sh
+++ b/src/test/test_key_expiration.sh
@@ -61,6 +61,11 @@ fi
CASE1=$dflt
CASE2=$dflt
CASE3=$dflt
+CASE4=$dflt
+CASE5=$dflt
+CASE6=$dflt
+CASE7=$dflt
+CASE8=$dflt
if [ $# -ge 1 ]; then
eval "CASE${1}"=1
@@ -125,16 +130,17 @@ if [ "$CASE1" = 1 ]; then
${TOR} ${QUIETLY} --key-expiration 2>"$FN" || true
grep "No valid argument to --key-expiration found!" "$FN" >/dev/null || \
- die "Tor didn't mention supported --key-expiration argmuents"
+ die "Tor didn't mention supported --key-expiration arguments"
echo "==== Case 1: ok"
fi
if [ "$CASE2" = 1 ]; then
- echo "==== Case 2: Start Tor with --key-expiration 'sign' and make sure it prints an expiration."
+ echo "==== Case 2: Start Tor with --key-expiration 'sign' and make sure it"
+ echo " prints an expiration using ISO8601 date format."
${TOR} ${QUIETLY} --key-expiration sign 2>"$FN"
- grep "signing-cert-expiry:" "$FN" >/dev/null || \
+ grep "signing-cert-expiry: [0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\} [0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}" "$FN" >/dev/null || \
die "Tor didn't print an expiration"
echo "==== Case 2: ok"
@@ -160,3 +166,61 @@ if [ "$CASE3" = 1 ]; then
echo "==== Case 3: ok"
fi
+
+if [ "$CASE4" = 1 ]; then
+ echo "==== Case 4: Start Tor with --format iso8601 and make sure it prints an"
+ echo " error message due to missing --key-expiration argument."
+
+ ${TOR} --format iso8601 > "$FN" 2>&1 || true
+ grep -- "--format specified without --key-expiration!" "$FN" >/dev/null || \
+ die "Tor didn't print a missing --key-expiration error message"
+
+ echo "==== Case 4: ok"
+fi
+
+if [ "$CASE5" = 1 ]; then
+ echo "==== Case 5: Start Tor with --key-expiration 'sign' --format '' and"
+ echo " make sure it prints an error message due to missing value."
+
+ ${TOR} --key-expiration sign --format > "$FN" 2>&1 || true
+ grep "Command-line option '--format' with no value. Failing." "$FN" >/dev/null || \
+ die "Tor didn't print a missing format value error message"
+
+ echo "==== Case 5: ok"
+fi
+
+if [ "$CASE6" = 1 ]; then
+ echo "==== Case 6: Start Tor with --key-expiration 'sign' --format 'invalid'"
+ echo " and make sure it prints an error message due to invalid"
+ echo " value."
+
+ ${TOR} --key-expiration sign --format invalid > "$FN" 2>&1 || true
+ grep "Invalid --format value" "$FN" >/dev/null || \
+ die "Tor didn't print an invalid format value error message"
+
+ echo "==== Case 6: ok"
+fi
+
+if [ "$CASE7" = 1 ]; then
+ echo "==== Case 7: Start Tor with --key-expiration 'sign' --format 'iso8601'"
+ echo " and make sure it prints an expiration using ISO8601 date"
+ echo " format."
+
+ ${TOR} ${QUIETLY} --key-expiration sign --format iso8601 2>"$FN"
+ grep "signing-cert-expiry: [0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\} [0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}" "$FN" >/dev/null || \
+ die "Tor didn't print an expiration"
+
+ echo "==== Case 7: ok"
+fi
+
+if [ "$CASE8" = 1 ]; then
+ echo "==== Case 8: Start Tor with --key-expiration 'sign' --format 'timestamp'"
+ echo " and make sure it prints an expiration using timestamp date"
+ echo " format."
+
+ ${TOR} ${QUIETLY} --key-expiration sign --format timestamp 2>"$FN"
+ grep "signing-cert-expiry: [0-9]\{5,\}" "$FN" >/dev/null || \
+ die "Tor didn't print an expiration"
+
+ echo "==== Case 8: ok"
+fi
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
index 1566b349ed..06af299056 100644
--- a/src/test/test_link_handshake.c
+++ b/src/test/test_link_handshake.c
@@ -710,7 +710,7 @@ CERTS_FAIL(missing_signing_key, /* ed25519 */
* signing key. */
const ed25519_keypair_t *mk = get_master_identity_keypair();
const ed25519_keypair_t *sk = get_master_signing_keypair();
- tor_cert_t *bad_cert = tor_cert_create(mk, CERT_TYPE_ID_SIGNING,
+ tor_cert_t *bad_cert = tor_cert_create_ed25519(mk, CERT_TYPE_ID_SIGNING,
&sk->pubkey, time(NULL), 86400,
0 /* don't include signer */);
certs_cell_cert_setlen_body(cert, bad_cert->encoded_len);
diff --git a/src/test/test_logging.c b/src/test/test_logging.c
index e09f7a21cd..58d0f24bd3 100644
--- a/src/test/test_logging.c
+++ b/src/test/test_logging.c
@@ -160,6 +160,7 @@ test_ratelim(void *arg)
tor_free(msg);
int i;
+ time_t first_suppressed_at = now + 60;
for (i = 0; i < 9; ++i) {
now += 60; /* one minute has passed. */
msg = rate_limit_log(&ten_min, now);
@@ -167,12 +168,15 @@ test_ratelim(void *arg)
tt_int_op(ten_min.last_allowed, OP_EQ, start);
tt_int_op(ten_min.n_calls_since_last_time, OP_EQ, i + 1);
}
+ tt_i64_op(ten_min.started_limiting, OP_EQ, first_suppressed_at);
now += 240; /* Okay, we can be done. */
msg = rate_limit_log(&ten_min, now);
tt_ptr_op(msg, OP_NE, NULL);
tt_str_op(msg, OP_EQ,
- " [9 similar message(s) suppressed in last 600 seconds]");
+ " [9 similar message(s) suppressed in last 720 seconds]");
+ tt_i64_op(now, OP_EQ, first_suppressed_at + 720);
+
done:
tor_free(msg);
}
diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c
index fbbbf0a99f..c165eebb63 100644
--- a/src/test/test_nodelist.c
+++ b/src/test/test_nodelist.c
@@ -104,7 +104,7 @@ test_nodelist_node_is_dir(void *arg)
tt_assert(node_is_dir(&node));
rs.is_v2_dir = 0;
- rs.dir_port = 1;
+ rs.ipv4_dirport = 1;
tt_assert(! node_is_dir(&node));
node.rs = NULL;
@@ -113,7 +113,7 @@ test_nodelist_node_is_dir(void *arg)
ri.supports_tunnelled_dir_requests = 1;
tt_assert(node_is_dir(&node));
ri.supports_tunnelled_dir_requests = 0;
- ri.dir_port = 1;
+ ri.ipv4_dirport = 1;
tt_assert(! node_is_dir(&node));
done:
@@ -685,7 +685,7 @@ test_nodelist_format_node_description(void *arg)
mock_digest,
NULL,
NULL,
- 0);
+ NULL);
tt_ptr_op(rv, OP_EQ, ndesc);
tt_str_op(ndesc, OP_EQ, "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
@@ -694,7 +694,7 @@ test_nodelist_format_node_description(void *arg)
mock_digest,
mock_nickname,
NULL,
- 0);
+ NULL);
tt_ptr_op(rv, OP_EQ, ndesc);
tt_str_op(ndesc, OP_EQ,
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~""TestOR7890123456789");
@@ -703,8 +703,8 @@ test_nodelist_format_node_description(void *arg)
rv = format_node_description(ndesc,
mock_digest,
mock_nickname,
- &mock_null_ip,
- 0);
+ NULL,
+ &mock_null_ip);
tt_ptr_op(rv, OP_EQ, ndesc);
tt_str_op(ndesc, OP_EQ,
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789");
@@ -714,7 +714,7 @@ test_nodelist_format_node_description(void *arg)
mock_digest,
NULL,
&mock_ipv4,
- 0);
+ NULL);
tt_ptr_op(rv, OP_EQ, ndesc);
tt_str_op(ndesc, OP_EQ,
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA at 111.222.233.244");
@@ -722,8 +722,8 @@ test_nodelist_format_node_description(void *arg)
rv = format_node_description(ndesc,
mock_digest,
mock_nickname,
- &mock_ipv6,
- 0);
+ NULL,
+ &mock_ipv6);
tt_ptr_op(rv, OP_EQ, ndesc);
tt_str_op(ndesc, OP_EQ,
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
@@ -732,18 +732,18 @@ test_nodelist_format_node_description(void *arg)
rv = format_node_description(ndesc,
mock_digest,
mock_nickname,
- &mock_ipv6,
- tor_addr_to_ipv4h(&mock_ipv4));
+ &mock_ipv4,
+ &mock_ipv6);
tt_ptr_op(rv, OP_EQ, ndesc);
tt_str_op(ndesc, OP_EQ,
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR7890123456789 at "
"111.222.233.244 and [1111:2222:3333:4444:5555:6666:7777:8888]");
/* test NULL handling */
- rv = format_node_description(NULL, NULL, NULL, NULL, 0);
+ rv = format_node_description(NULL, NULL, NULL, NULL, NULL);
tt_str_op(rv, OP_EQ, "<NULL BUFFER>");
- rv = format_node_description(ndesc, NULL, NULL, NULL, 0);
+ rv = format_node_description(ndesc, NULL, NULL, NULL, NULL);
tt_ptr_op(rv, OP_EQ, ndesc);
tt_str_op(rv, OP_EQ, "<NULL ID DIGEST>");
@@ -761,7 +761,6 @@ static void
test_nodelist_router_describe(void *arg)
{
char mock_nickname[MAX_NICKNAME_LEN+1];
- tor_addr_t mock_ipv4;
routerinfo_t mock_ri_ipv4;
routerinfo_t mock_ri_ipv6;
routerinfo_t mock_ri_dual;
@@ -772,7 +771,6 @@ test_nodelist_router_describe(void *arg)
/* Clear variables */
memset(mock_nickname, 0, sizeof(mock_nickname));
- memset(&mock_ipv4, 0, sizeof(mock_ipv4));
memset(&mock_ri_ipv4, 0, sizeof(mock_ri_ipv4));
memset(&mock_ri_ipv6, 0, sizeof(mock_ri_ipv6));
memset(&mock_ri_dual, 0, sizeof(mock_ri_dual));
@@ -784,8 +782,7 @@ test_nodelist_router_describe(void *arg)
sizeof(mock_ri_dual.cache_info.identity_digest));
strlcpy(mock_nickname, "TestOR7890123456789", sizeof(mock_nickname));
mock_ri_dual.nickname = mock_nickname;
- tor_addr_parse(&mock_ipv4, "111.222.233.244");
- mock_ri_dual.addr = tor_addr_to_ipv4h(&mock_ipv4);
+ tor_addr_parse(&mock_ri_dual.ipv4_addr, "111.222.233.244");
tor_addr_parse(&mock_ri_dual.ipv6_addr,
"[1111:2222:3333:4444:5555:6666:7777:8888]");
@@ -796,7 +793,7 @@ test_nodelist_router_describe(void *arg)
memcpy(&mock_ri_ipv6, &mock_ri_dual, sizeof(mock_ri_ipv6));
/* Clear the unnecessary addresses */
memset(&mock_ri_ipv4.ipv6_addr, 0, sizeof(mock_ri_ipv4.ipv6_addr));
- mock_ri_ipv6.addr = 0;
+ tor_addr_make_unspec(&mock_ri_ipv6.ipv4_addr);
/* We don't test the no-nickname and no-IP cases, because they're covered by
* format_node_description(), and we don't expect to see them in Tor code. */
@@ -863,7 +860,6 @@ static void
test_nodelist_node_describe(void *arg)
{
char mock_nickname[MAX_NICKNAME_LEN+1];
- tor_addr_t mock_ipv4;
const char *rv = NULL;
@@ -874,7 +870,6 @@ test_nodelist_node_describe(void *arg)
/* Clear variables */
memset(mock_nickname, 0, sizeof(mock_nickname));
- memset(&mock_ipv4, 0, sizeof(mock_ipv4));
memset(&mock_ri_dual, 0, sizeof(mock_ri_dual));
/* Set up the dual-stack routerinfo */
@@ -884,8 +879,7 @@ test_nodelist_node_describe(void *arg)
sizeof(mock_ri_dual.cache_info.identity_digest));
strlcpy(mock_nickname, "TestOR7890123456789", sizeof(mock_nickname));
mock_ri_dual.nickname = mock_nickname;
- tor_addr_parse(&mock_ipv4, "111.222.233.244");
- mock_ri_dual.addr = tor_addr_to_ipv4h(&mock_ipv4);
+ tor_addr_parse(&mock_ri_dual.ipv4_addr, "111.222.233.244");
tor_addr_parse(&mock_ri_dual.ipv6_addr,
"[1111:2222:3333:4444:5555:6666:7777:8888]");
@@ -894,7 +888,6 @@ test_nodelist_node_describe(void *arg)
routerstatus_t mock_rs_dual;
/* Clear variables */
- memset(&mock_ipv4, 0, sizeof(mock_ipv4));
memset(&mock_rs_ipv4, 0, sizeof(mock_rs_ipv4));
memset(&mock_rs_dual, 0, sizeof(mock_rs_dual));
@@ -905,8 +898,7 @@ test_nodelist_node_describe(void *arg)
sizeof(mock_rs_dual.identity_digest));
strlcpy(mock_rs_dual.nickname, "Bbb",
sizeof(mock_rs_dual.nickname));
- tor_addr_parse(&mock_ipv4, "2.2.2.2");
- mock_rs_dual.addr = tor_addr_to_ipv4h(&mock_ipv4);
+ tor_addr_parse(&mock_rs_dual.ipv4_addr, "2.2.2.2");
tor_addr_parse(&mock_rs_dual.ipv6_addr,
"[bbbb::bbbb]");
@@ -1070,7 +1062,6 @@ test_nodelist_node_describe(void *arg)
static void
test_nodelist_routerstatus_describe(void *arg)
{
- tor_addr_t mock_ipv4;
routerstatus_t mock_rs_ipv4;
routerstatus_t mock_rs_ipv6;
routerstatus_t mock_rs_dual;
@@ -1080,7 +1071,6 @@ test_nodelist_routerstatus_describe(void *arg)
(void) arg;
/* Clear variables */
- memset(&mock_ipv4, 0, sizeof(mock_ipv4));
memset(&mock_rs_ipv4, 0, sizeof(mock_rs_ipv4));
memset(&mock_rs_ipv6, 0, sizeof(mock_rs_ipv6));
memset(&mock_rs_dual, 0, sizeof(mock_rs_dual));
@@ -1092,8 +1082,7 @@ test_nodelist_routerstatus_describe(void *arg)
sizeof(mock_rs_dual.identity_digest));
strlcpy(mock_rs_dual.nickname, "TestOR7890123456789",
sizeof(mock_rs_dual.nickname));
- tor_addr_parse(&mock_ipv4, "111.222.233.244");
- mock_rs_dual.addr = tor_addr_to_ipv4h(&mock_ipv4);
+ tor_addr_parse(&mock_rs_dual.ipv4_addr, "111.222.233.244");
tor_addr_parse(&mock_rs_dual.ipv6_addr,
"[1111:2222:3333:4444:5555:6666:7777:8888]");
@@ -1102,7 +1091,7 @@ test_nodelist_routerstatus_describe(void *arg)
memcpy(&mock_rs_ipv6, &mock_rs_dual, sizeof(mock_rs_ipv6));
/* Clear the unnecessary addresses */
memset(&mock_rs_ipv4.ipv6_addr, 0, sizeof(mock_rs_ipv4.ipv6_addr));
- mock_rs_ipv6.addr = 0;
+ tor_addr_make_unspec(&mock_rs_ipv6.ipv4_addr);
/* We don't test the no-nickname and no-IP cases, because they're covered by
* format_node_description(), and we don't expect to see them in Tor code. */
@@ -1182,11 +1171,11 @@ test_nodelist_extend_info_describe(void *arg)
sizeof(mock_ei_ipv4.identity_digest));
strlcpy(mock_ei_ipv4.nickname, "TestOR7890123456789",
sizeof(mock_ei_ipv4.nickname));
- tor_addr_parse(&mock_ei_ipv4.addr, "111.222.233.244");
+ tor_addr_parse(&mock_ei_ipv4.orports[0].addr, "111.222.233.244");
/* Create and modify the other extend info. */
memcpy(&mock_ei_ipv6, &mock_ei_ipv4, sizeof(mock_ei_ipv6));
- tor_addr_parse(&mock_ei_ipv6.addr,
+ tor_addr_parse(&mock_ei_ipv6.orports[0].addr,
"[1111:2222:3333:4444:5555:6666:7777:8888]");
/* We don't test the no-nickname and no-IP cases, because they're covered by
@@ -1259,8 +1248,8 @@ test_nodelist_routerstatus_has_visibly_changed(void *arg)
strlcpy(rs_orig.nickname, "friendly", sizeof(rs_orig.nickname));
memcpy(rs_orig.identity_digest, "abcdefghijklmnopqrst", 20);
memcpy(rs_orig.descriptor_digest, "abcdefghijklmnopqrst", 20);
- rs_orig.addr = 0x7f000001;
- rs_orig.or_port = 3;
+ tor_addr_from_ipv4h(&rs_orig.ipv4_addr, 0x7f000001);
+ rs_orig.ipv4_orport = 3;
rs_orig.published_on = time(NULL);
rs_orig.has_bandwidth = 1;
rs_orig.bandwidth_kb = 20;
@@ -1301,7 +1290,7 @@ test_nodelist_routerstatus_has_visibly_changed(void *arg)
COPY();
ASSERT_SAME();
- rs.addr = 0x7f000002;
+ tor_addr_from_ipv4h(&rs.ipv4_addr, 0x7f000002);
ASSERT_CHANGED();
strlcpy(rs.descriptor_digest, "hello world", sizeof(rs.descriptor_digest));
@@ -1313,10 +1302,10 @@ test_nodelist_routerstatus_has_visibly_changed(void *arg)
rs.published_on += 3600;
ASSERT_CHANGED();
- rs.or_port = 55;
+ rs.ipv4_orport = 55;
ASSERT_CHANGED();
- rs.dir_port = 9999;
+ rs.ipv4_dirport = 9999;
ASSERT_CHANGED();
tor_addr_parse(&rs.ipv6_addr, "1234::56");
diff --git a/src/test/test_options.c b/src/test/test_options.c
index 8e0d19f126..714ee4767f 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -1013,7 +1013,7 @@ test_options_validate__relay_with_hidden_services(void *ignored)
"Tor is currently configured as a relay and a hidden service. "
"That's not very secure: you should probably run your hidden servi"
"ce in a separate Tor process, at least -- see "
- "https://trac.torproject.org/8742\n");
+ "https://bugs.torproject.org/tpo/core/tor/8742.\n");
done:
teardown_capture_of_logs();
diff --git a/src/test/test_parseconf.sh b/src/test/test_parseconf.sh
index 4fe27d9f5d..c02b8b23c0 100755
--- a/src/test/test_parseconf.sh
+++ b/src/test/test_parseconf.sh
@@ -202,7 +202,7 @@ STANDARD_LIBS="libevent\\|openssl\\|zlib"
# shellcheck disable=SC2018,SC2019
TOR_LIBS_ENABLED="$("$TOR_BINARY" --verify-config \
-f "$EMPTY" --defaults-torrc "$EMPTY" \
- | sed -n 's/.* Tor .* running on .* with\(.*\)\./\1/p' \
+ | sed -n 's/.* Tor .* running on .* with\(.*\) and .* .* as libc\./\1/p' \
| tr 'A-Z' 'a-z' | tr ',' '\n' \
| grep -v "$STANDARD_LIBS" | grep -v "n/a" \
| sed 's/\( and\)* \(lib\)*\([a-z0-9]*\) .*/\3/' \
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index 7949e90e9e..0a0548d161 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -8,6 +8,7 @@
#include "app/config/config.h"
#include "core/or/circuitbuild.h"
#include "core/or/policies.h"
+#include "core/or/extendinfo.h"
#include "feature/dirparse/policy_parse.h"
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_descriptor.h"
@@ -1124,7 +1125,7 @@ test_policy_has_address_helper(const smartlist_t *policy_list,
return 0;
}
-#define TEST_IPV4_ADDR (0x01020304)
+#define TEST_IPV4_ADDR ("1.2.3.4")
#define TEST_IPV6_ADDR ("2002::abcd")
/** Run unit tests for rejecting the configured addresses on this exit relay
@@ -1137,7 +1138,7 @@ test_policies_reject_exit_address(void *arg)
smartlist_t *ipv4_list, *ipv6_list, *both_list, *dupl_list;
(void)arg;
- tor_addr_from_ipv4h(&ipv4_addr, TEST_IPV4_ADDR);
+ tor_addr_parse(&ipv4_addr, TEST_IPV4_ADDR);
tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR);
ipv4_list = smartlist_new();
@@ -1255,7 +1256,7 @@ test_policies_reject_port_address(void *arg)
test_configured_ports = smartlist_new();
ipv4_port = port_cfg_new(0);
- tor_addr_from_ipv4h(&ipv4_port->addr, TEST_IPV4_ADDR);
+ tor_addr_parse(&ipv4_port->addr, TEST_IPV4_ADDR);
smartlist_add(test_configured_ports, ipv4_port);
ipv6_port = port_cfg_new(0);
@@ -1373,7 +1374,7 @@ test_policies_reject_interface_address(void *arg)
}
/* Now do it all again, but mocked */
- tor_addr_from_ipv4h(&ipv4_addr, TEST_IPV4_ADDR);
+ tor_addr_parse(&ipv4_addr, TEST_IPV4_ADDR);
mock_ipv4_addrs = smartlist_new();
smartlist_add(mock_ipv4_addrs, (void *)&ipv4_addr);
@@ -1528,7 +1529,7 @@ mock_router_get_my_routerinfo_with_err(int *err)
}
#define DEFAULT_POLICY_STRING "reject *:*"
-#define TEST_IPV4_ADDR (0x02040608)
+#define TEST_IPV4_ADDR ("2.4.6.8")
#define TEST_IPV6_ADDR ("2003::ef01")
static or_options_t mock_options;
@@ -1607,13 +1608,13 @@ test_policies_getinfo_helper_policies(void *arg)
tt_assert(strlen(answer) == 0 || !strcasecmp(answer, DEFAULT_POLICY_STRING));
tor_free(answer);
- mock_my_routerinfo.addr = TEST_IPV4_ADDR;
+ tor_addr_parse(&mock_my_routerinfo.ipv4_addr, TEST_IPV4_ADDR);
tor_addr_parse(&mock_my_routerinfo.ipv6_addr, TEST_IPV6_ADDR);
append_exit_policy_string(&mock_my_routerinfo.exit_policy, "accept *4:*");
append_exit_policy_string(&mock_my_routerinfo.exit_policy, "reject *6:*");
mock_options.IPv6Exit = 1;
- tor_addr_from_ipv4h(
+ tor_addr_parse(
&mock_options.OutboundBindAddresses[OUTBOUND_ADDR_EXIT][0],
TEST_IPV4_ADDR);
tor_addr_parse(
@@ -1752,7 +1753,7 @@ test_policies_getinfo_helper_policies(void *arg)
#define OTHER_IPV4_ADDR_STR "6.7.8.9"
#define OTHER_IPV6_ADDR_STR "[afff::]"
-/** Run unit tests for fascist_firewall_allows_address */
+/** Run unit tests for reachable_addr_allows */
static void
test_policies_fascist_firewall_allows_address(void *arg)
{
@@ -1821,33 +1822,33 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 1;
mock_options.UseBridges = 0;
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* Preferring IPv4 */
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 1, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 1, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 1, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 1, 0),
OP_EQ, 0);
/* Preferring IPv6 */
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 1, 1),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 1, 1),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 1, 1),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 1, 1),
OP_EQ, 0);
/* Test the function's address matching with UseBridges on */
@@ -1856,45 +1857,45 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 1;
mock_options.UseBridges = 1;
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* Preferring IPv4 */
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 1, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 1, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 1, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 1, 0),
OP_EQ, 0);
/* Preferring IPv6 */
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 1, 1),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 1, 1),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 1, 1),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 1, 1),
OP_EQ, 0);
/* bridge clients always use IPv6, regardless of ClientUseIPv6 */
mock_options.ClientUseIPv4 = 1;
mock_options.ClientUseIPv6 = 0;
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* Test the function's address matching with IPv4 on */
@@ -1903,13 +1904,13 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 0;
mock_options.UseBridges = 0;
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* Test the function's address matching with IPv6 on */
@@ -1918,13 +1919,13 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 1;
mock_options.UseBridges = 0;
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* Test the function's address matching with ClientUseIPv4 0.
@@ -1934,13 +1935,13 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 0;
mock_options.UseBridges = 0;
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&r_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* Test the function's address matching for unusual inputs */
@@ -1950,27 +1951,27 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.UseBridges = 1;
/* NULL and tor_addr_is_null addresses are rejected */
- tt_int_op(fascist_firewall_allows_address(NULL, port, policy, 0, 0), OP_EQ,
+ tt_int_op(reachable_addr_allows(NULL, port, policy, 0, 0), OP_EQ,
0);
- tt_int_op(fascist_firewall_allows_address(&n_ipv4_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&n_ipv4_addr, port, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&n_ipv6_addr, port, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&n_ipv6_addr, port, policy, 0, 0),
OP_EQ, 0);
/* zero ports are rejected */
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, 0, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, 0, policy, 0, 0),
OP_EQ, 0);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, 0, policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, 0, policy, 0, 0),
OP_EQ, 0);
/* NULL and empty policies accept everything */
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, NULL, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, NULL, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, NULL, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, NULL, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, e_policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv4_addr, port, e_policy, 0, 0),
OP_EQ, 1);
- tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, e_policy, 0, 0),
+ tt_int_op(reachable_addr_allows(&ipv6_addr, port, e_policy, 0, 0),
OP_EQ, 1);
done:
@@ -1990,7 +1991,7 @@ test_policies_fascist_firewall_allows_address(void *arg)
#define TEST_IPV6_OR_PORT 61234
#define TEST_IPV6_DIR_PORT 62345
-/* Check that fascist_firewall_choose_address_rs() returns the expected
+/* Check that reachable_addr_choose_from_rs() returns the expected
* results. */
#define CHECK_CHOSEN_ADDR_RS(fake_rs, fw_connection, pref_only, expect_rv, \
expect_ap) \
@@ -1998,13 +1999,13 @@ test_policies_fascist_firewall_allows_address(void *arg)
tor_addr_port_t chosen_rs_ap; \
tor_addr_make_null(&chosen_rs_ap.addr, AF_INET); \
chosen_rs_ap.port = 0; \
- fascist_firewall_choose_address_rs(&(fake_rs), (fw_connection), \
+ reachable_addr_choose_from_rs(&(fake_rs), (fw_connection), \
(pref_only), &chosen_rs_ap); \
tt_assert(tor_addr_eq(&(expect_ap).addr, &chosen_rs_ap.addr)); \
tt_int_op((expect_ap).port, OP_EQ, chosen_rs_ap.port); \
STMT_END
-/* Check that fascist_firewall_choose_address_node() returns the expected
+/* Check that reachable_addr_choose_from_node() returns the expected
* results. */
#define CHECK_CHOSEN_ADDR_NODE(fake_node, fw_connection, pref_only, \
expect_rv, expect_ap) \
@@ -2012,14 +2013,14 @@ test_policies_fascist_firewall_allows_address(void *arg)
tor_addr_port_t chosen_node_ap; \
tor_addr_make_null(&chosen_node_ap.addr, AF_INET); \
chosen_node_ap.port = 0; \
- fascist_firewall_choose_address_node(&(fake_node),(fw_connection), \
+ reachable_addr_choose_from_node(&(fake_node),(fw_connection), \
(pref_only), &chosen_node_ap); \
tt_assert(tor_addr_eq(&(expect_ap).addr, &chosen_node_ap.addr)); \
tt_int_op((expect_ap).port, OP_EQ, chosen_node_ap.port); \
STMT_END
-/* Check that fascist_firewall_choose_address_rs and
- * fascist_firewall_choose_address_node() both return the expected results. */
+/* Check that reachable_addr_choose_from_rs and
+ * reachable_addr_choose_from_node() both return the expected results. */
#define CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, fw_connection, pref_only, \
expect_rv, expect_ap) \
STMT_BEGIN \
@@ -2029,7 +2030,7 @@ test_policies_fascist_firewall_allows_address(void *arg)
expect_ap); \
STMT_END
-/* Check that fascist_firewall_choose_address_ls() returns the expected
+/* Check that reachable_addr_choose_from_ls() returns the expected
* results. */
#define CHECK_CHOSEN_ADDR_NULL_LS() \
STMT_BEGIN \
@@ -2037,7 +2038,7 @@ test_policies_fascist_firewall_allows_address(void *arg)
tor_addr_make_null(&chosen_ls_ap.addr, AF_UNSPEC); \
chosen_ls_ap.port = 0; \
setup_full_capture_of_logs(LOG_WARN); \
- fascist_firewall_choose_address_ls(NULL, 1, &chosen_ls_ap); \
+ reachable_addr_choose_from_ls(NULL, 1, &chosen_ls_ap); \
expect_single_log_msg("Unknown or missing link specifiers"); \
teardown_capture_of_logs(); \
STMT_END
@@ -2048,7 +2049,7 @@ test_policies_fascist_firewall_allows_address(void *arg)
tor_addr_make_null(&chosen_ls_ap.addr, AF_UNSPEC); \
chosen_ls_ap.port = 0; \
setup_full_capture_of_logs(LOG_WARN); \
- fascist_firewall_choose_address_ls(fake_ls, pref_only, &chosen_ls_ap); \
+ reachable_addr_choose_from_ls(fake_ls, pref_only, &chosen_ls_ap); \
if (smartlist_len(fake_ls) == 0) { \
expect_single_log_msg("Link specifiers are empty"); \
} else { \
@@ -2065,7 +2066,7 @@ test_policies_fascist_firewall_allows_address(void *arg)
tor_addr_make_null(&chosen_ls_ap.addr, AF_UNSPEC); \
chosen_ls_ap.port = 0; \
setup_full_capture_of_logs(LOG_WARN); \
- fascist_firewall_choose_address_ls(fake_ls, 0, &chosen_ls_ap); \
+ reachable_addr_choose_from_ls(fake_ls, 0, &chosen_ls_ap); \
expect_single_log_msg("None of our link specifiers have IPv4 or IPv6"); \
teardown_capture_of_logs(); \
STMT_END
@@ -2084,8 +2085,8 @@ test_policies_fascist_firewall_allows_address(void *arg)
expect_single_log_msg("Specified link specifiers is null"); \
} else { \
expect_no_log_entry(); \
- tt_assert(tor_addr_eq(&(expect_ap).addr, &ei->addr)); \
- tt_int_op((expect_ap).port, OP_EQ, ei->port); \
+ tt_assert(tor_addr_eq(&(expect_ap).addr, &ei->orports[0].addr)); \
+ tt_int_op((expect_ap).port, OP_EQ, ei->orports[0].port); \
extend_info_free(ei); \
} \
teardown_capture_of_logs(); \
@@ -2124,7 +2125,7 @@ test_policies_fascist_firewall_allows_address(void *arg)
teardown_capture_of_logs(); \
STMT_END
-/** Run unit tests for fascist_firewall_choose_address */
+/** Run unit tests for reachable_addr_choose */
static void
test_policies_fascist_firewall_choose_address(void *arg)
{
@@ -2152,87 +2153,87 @@ test_policies_fascist_firewall_choose_address(void *arg)
tor_addr_make_null(&n_ipv6_ap.addr, AF_INET6);
n_ipv6_ap.port = 0;
- /* Sanity check fascist_firewall_choose_address with IPv4 and IPv6 on */
+ /* Sanity check reachable_addr_choose with IPv4 and IPv6 on */
memset(&mock_options, 0, sizeof(or_options_t));
mock_options.ClientUseIPv4 = 1;
mock_options.ClientUseIPv6 = 1;
mock_options.UseBridges = 0;
/* Prefer IPv4 */
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 1,
FIREWALL_OR_CONNECTION, 0, 0)
== &ipv4_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 1,
FIREWALL_OR_CONNECTION, 1, 0)
== &ipv4_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 1,
+ tt_assert(reachable_addr_choose(&ipv4_dir_ap, &ipv6_dir_ap, 1,
FIREWALL_DIR_CONNECTION, 0, 0)
== &ipv4_dir_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 1,
+ tt_assert(reachable_addr_choose(&ipv4_dir_ap, &ipv6_dir_ap, 1,
FIREWALL_DIR_CONNECTION, 1, 0)
== &ipv4_dir_ap);
/* Prefer IPv6 */
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 0,
FIREWALL_OR_CONNECTION, 0, 1)
== &ipv6_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 0,
FIREWALL_OR_CONNECTION, 1, 1)
== &ipv6_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_dir_ap, &ipv6_dir_ap, 0,
FIREWALL_DIR_CONNECTION, 0, 1)
== &ipv6_dir_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_dir_ap, &ipv6_dir_ap, 0,
FIREWALL_DIR_CONNECTION, 1, 1)
== &ipv6_dir_ap);
/* Unusual inputs */
/* null preferred OR addresses */
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &n_ipv6_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &n_ipv6_ap, 0,
FIREWALL_OR_CONNECTION, 0, 1)
== &ipv4_or_ap);
- tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &ipv6_or_ap, 1,
+ tt_assert(reachable_addr_choose(&n_ipv4_ap, &ipv6_or_ap, 1,
FIREWALL_OR_CONNECTION, 0, 0)
== &ipv6_or_ap);
/* null both OR addresses */
- tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0,
+ tt_ptr_op(reachable_addr_choose(&n_ipv4_ap, &n_ipv6_ap, 0,
FIREWALL_OR_CONNECTION, 0, 1),
OP_EQ, NULL);
- tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 1,
+ tt_ptr_op(reachable_addr_choose(&n_ipv4_ap, &n_ipv6_ap, 1,
FIREWALL_OR_CONNECTION, 0, 0),
OP_EQ, NULL);
/* null preferred Dir addresses */
- tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &n_ipv6_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_dir_ap, &n_ipv6_ap, 0,
FIREWALL_DIR_CONNECTION, 0, 1)
== &ipv4_dir_ap);
- tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &ipv6_dir_ap, 1,
+ tt_assert(reachable_addr_choose(&n_ipv4_ap, &ipv6_dir_ap, 1,
FIREWALL_DIR_CONNECTION, 0, 0)
== &ipv6_dir_ap);
/* null both Dir addresses */
- tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0,
+ tt_ptr_op(reachable_addr_choose(&n_ipv4_ap, &n_ipv6_ap, 0,
FIREWALL_DIR_CONNECTION, 0, 1),
OP_EQ, NULL);
- tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 1,
+ tt_ptr_op(reachable_addr_choose(&n_ipv4_ap, &n_ipv6_ap, 1,
FIREWALL_DIR_CONNECTION, 0, 0),
OP_EQ, NULL);
/* Prefer IPv4 but want IPv6 (contradictory) */
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 0,
FIREWALL_OR_CONNECTION, 0, 0)
== &ipv4_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 0,
FIREWALL_OR_CONNECTION, 1, 0)
== &ipv4_or_ap);
/* Prefer IPv6 but want IPv4 (contradictory) */
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 1,
FIREWALL_OR_CONNECTION, 0, 1)
== &ipv6_or_ap);
- tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1,
+ tt_assert(reachable_addr_choose(&ipv4_or_ap, &ipv6_or_ap, 1,
FIREWALL_OR_CONNECTION, 1, 1)
== &ipv6_or_ap);
@@ -2242,9 +2243,9 @@ test_policies_fascist_firewall_choose_address(void *arg)
routerstatus_t fake_rs;
memset(&fake_rs, 0, sizeof(routerstatus_t));
/* In a routerstatus, the OR and Dir addresses are the same */
- fake_rs.addr = tor_addr_to_ipv4h(&ipv4_or_ap.addr);
- fake_rs.or_port = ipv4_or_ap.port;
- fake_rs.dir_port = ipv4_dir_ap.port;
+ tor_addr_copy(&fake_rs.ipv4_addr, &ipv4_or_ap.addr);
+ fake_rs.ipv4_orport = ipv4_or_ap.port;
+ fake_rs.ipv4_dirport = ipv4_dir_ap.port;
tor_addr_copy(&fake_rs.ipv6_addr, &ipv6_or_ap.addr);
fake_rs.ipv6_orport = ipv6_or_ap.port;
@@ -2267,7 +2268,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = 0;
mock_options.ClientPreferIPv6DirPort = 0;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2283,7 +2284,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = -1;
mock_options.ClientPreferIPv6DirPort = -1;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2299,7 +2300,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = 1;
mock_options.ClientPreferIPv6DirPort = 1;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2315,7 +2316,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = 0;
mock_options.ClientPreferIPv6DirPort = 1;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2331,7 +2332,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = 1;
mock_options.ClientPreferIPv6DirPort = 0;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2353,7 +2354,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = 0;
mock_options.ClientPreferIPv6DirPort = 0;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2404,7 +2405,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6ORPort = 1;
mock_options.ClientPreferIPv6DirPort = 1;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2453,7 +2454,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientUseIPv4 = 1;
mock_options.ClientUseIPv6 = 0;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2470,7 +2471,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientUseIPv4 = 0;
mock_options.ClientUseIPv6 = 1;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2488,7 +2489,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientUseIPv4 = 0;
mock_options.ClientUseIPv6 = 0;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2510,7 +2511,7 @@ test_policies_fascist_firewall_choose_address(void *arg)
mock_options.ClientPreferIPv6DirPort = 1;
/* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ fake_node.ipv6_preferred = reachable_addr_prefer_ipv6_orport(
&mock_options);
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
@@ -2682,9 +2683,9 @@ struct testcase_t policy_tests[] = {
{ "reject_interface_address", test_policies_reject_interface_address, 0,
NULL, NULL },
{ "reject_port_address", test_policies_reject_port_address, 0, NULL, NULL },
- { "fascist_firewall_allows_address",
+ { "reachable_addr_allows",
test_policies_fascist_firewall_allows_address, 0, NULL, NULL },
- { "fascist_firewall_choose_address",
+ { "reachable_addr_choose",
test_policies_fascist_firewall_choose_address, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_process_descs.c b/src/test/test_process_descs.c
index 14865cff13..5c2301f873 100644
--- a/src/test/test_process_descs.c
+++ b/src/test/test_process_descs.c
@@ -38,10 +38,10 @@ test_process_descs_versions(void *arg)
{ "Tor 0.4.0.5", true },
{ "Tor 0.4.1.1-alpha", true },
{ "Tor 0.4.1.4-rc", true },
+ { "Tor 0.4.1.5", true },
// new enough to be supported
{ "Tor 0.3.5.7", false },
{ "Tor 0.3.5.8", false },
- { "Tor 0.4.1.5", false },
{ "Tor 0.4.2.1-alpha", false },
{ "Tor 0.4.2.4-rc", false },
{ "Tor 0.4.3.0-alpha-dev", false },
diff --git a/src/test/test_protover.c b/src/test/test_protover.c
index 8fccae1a45..4ccec73699 100644
--- a/src/test/test_protover.c
+++ b/src/test/test_protover.c
@@ -7,14 +7,18 @@
#include "orconfig.h"
#include "test/test.h"
-#include "core/or/protover.h"
+#include "lib/tls/tortls.h"
#include "core/or/or.h"
+
#include "core/or/connection_or.h"
-#include "lib/tls/tortls.h"
+#include "core/or/protover.h"
+#include "core/or/versions.h"
#include "feature/dirauth/dirvote.h"
+#include "feature/relay/relay_handshake.h"
+
static void
test_protover_parse(void *arg)
{
@@ -409,23 +413,21 @@ test_protover_supports_version(void *arg)
* Hard-coded here, because they are not in the code, or not exposed in the
* headers. */
#define PROTOVER_LINKAUTH_V1 1
-#define PROTOVER_LINKAUTH_V3 3
-
+#define PROTOVER_LINKAUTH_V2 2
#define PROTOVER_RELAY_V1 1
-#define PROTOVER_RELAY_V2 2
+/* Deprecated HSIntro versions */
+#define PROTOVER_HS_INTRO_DEPRECATED_1 1
+#define PROTOVER_HS_INTRO_DEPRECATED_2 2
/* Highest supported HSv2 introduce protocol version.
- * Hard-coded here, because it does not appear anywhere in the code.
* It's not clear if we actually support version 2, see #25068. */
-#define PROTOVER_HSINTRO_V2 3
+#define PROTOVER_HS_INTRO_V2 3
-/* HSv2 Rend and HSDir protocol versions.
- * Hard-coded here, because they do not appear anywhere in the code. */
+/* HSv2 Rend and HSDir protocol versions. */
#define PROTOVER_HS_RENDEZVOUS_POINT_V2 1
#define PROTOVER_HSDIR_V2 1
-/* DirCache, Desc, Microdesc, and Cons protocol versions.
- * Hard-coded here, because they do not appear anywhere in the code. */
+/* DirCache, Desc, Microdesc, and Cons protocol versions. */
#define PROTOVER_DIRCACHE_V1 1
#define PROTOVER_DIRCACHE_V2 2
@@ -438,6 +440,10 @@ test_protover_supports_version(void *arg)
#define PROTOVER_CONS_V1 1
#define PROTOVER_CONS_V2 2
+#define PROTOVER_PADDING_V1 1
+
+#define PROTOVER_FLOWCTRL_V1 1
+
/* Make sure we haven't forgotten any supported protocols */
static void
test_protover_supported_protocols(void *arg)
@@ -452,24 +458,27 @@ test_protover_supported_protocols(void *arg)
PRT_LINK,
MAX_LINK_PROTO));
for (uint16_t i = 0; i < MAX_PROTOCOLS_TO_TEST; i++) {
- if (is_or_protocol_version_known(i)) {
- tt_assert(protocol_list_supports_protocol(supported_protocols,
+ tt_int_op(protocol_list_supports_protocol(supported_protocols,
PRT_LINK,
- i));
- }
+ i),
+ OP_EQ,
+ is_or_protocol_version_known(i));
}
-#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
- /* Legacy LinkAuth does not appear anywhere in the code. */
- tt_assert(protocol_list_supports_protocol(supported_protocols,
- PRT_LINKAUTH,
- PROTOVER_LINKAUTH_V1));
-#endif /* defined(HAVE_WORKING_TOR_TLS_GET_TLSSECRETS) */
- /* Latest LinkAuth is not exposed in the headers. */
- tt_assert(protocol_list_supports_protocol(supported_protocols,
+ /* Legacy LinkAuth is only supported on OpenSSL and similar. */
+ tt_int_op(protocol_list_supports_protocol(supported_protocols,
PRT_LINKAUTH,
- PROTOVER_LINKAUTH_V3));
- /* Is there any way to test for new LinkAuth? */
+ PROTOVER_LINKAUTH_V1),
+ OP_EQ,
+ authchallenge_type_is_supported(AUTHTYPE_RSA_SHA256_TLSSECRET));
+ /* LinkAuth=2 is unused */
+ tt_assert(!protocol_list_supports_protocol(supported_protocols,
+ PRT_LINKAUTH,
+ PROTOVER_LINKAUTH_V2));
+ tt_assert(
+ protocol_list_supports_protocol(supported_protocols,
+ PRT_LINKAUTH,
+ PROTOVER_LINKAUTH_ED25519_HANDSHAKE));
/* Relay protovers do not appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -477,20 +486,38 @@ test_protover_supported_protocols(void *arg)
PROTOVER_RELAY_V1));
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_RELAY,
- PROTOVER_RELAY_V2));
- /* Is there any way to test for new Relay? */
+ PROTOVER_RELAY_EXTEND2));
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_RELAY,
+ PROTOVER_RELAY_ACCEPT_IPV6));
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_RELAY,
+ PROTOVER_RELAY_EXTEND_IPV6));
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_RELAY,
+ PROTOVER_RELAY_CANONICAL_IPV6));
+ /* These HSIntro versions are deprecated */
+ tt_assert(!protocol_list_supports_protocol(supported_protocols,
+ PRT_HSINTRO,
+ PROTOVER_HS_INTRO_DEPRECATED_1));
+ tt_assert(!protocol_list_supports_protocol(supported_protocols,
+ PRT_HSINTRO,
+ PROTOVER_HS_INTRO_DEPRECATED_2));
/* We could test legacy HSIntro by calling rend_service_update_descriptor(),
* and checking the protocols field. But that's unlikely to change, so
* we just use a hard-coded value. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_HSINTRO,
- PROTOVER_HSINTRO_V2));
+ PROTOVER_HS_INTRO_V2));
/* Test for HSv3 HSIntro */
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_HSINTRO,
PROTOVER_HS_INTRO_V3));
- /* Is there any way to test for new HSIntro? */
+ /* Test for HSIntro DoS */
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_HSINTRO,
+ PROTOVER_HS_INTRO_DOS));
/* Legacy HSRend does not appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -500,7 +527,6 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_HSREND,
PROTOVER_HS_RENDEZVOUS_POINT_V3));
- /* Is there any way to test for new HSRend? */
/* Legacy HSDir does not appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -510,7 +536,6 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_HSDIR,
PROTOVER_HSDIR_V3));
- /* Is there any way to test for new HSDir? */
/* No DirCache versions appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -519,7 +544,6 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_DIRCACHE,
PROTOVER_DIRCACHE_V2));
- /* Is there any way to test for new DirCache? */
/* No Desc versions appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -537,7 +561,6 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_MICRODESC,
PROTOVER_MICRODESC_V2));
- /* Is there any way to test for new Microdesc? */
/* No Cons versions appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -546,7 +569,19 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_CONS,
PROTOVER_CONS_V2));
- /* Is there any way to test for new Cons? */
+
+ /* Padding=1 is deprecated. */
+ tt_assert(!protocol_list_supports_protocol(supported_protocols,
+ PRT_PADDING,
+ PROTOVER_PADDING_V1));
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_PADDING,
+ PROTOVER_HS_SETUP_PADDING));
+
+ /* FlowCtrl */
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_FLOWCTRL,
+ PROTOVER_FLOWCTRL_V1));
done:
;
@@ -577,6 +612,10 @@ test_protover_vote_roundtrip(void *args)
{ "N-1=1,2", "N-1=1-2" },
{ "-1=4294967295", NULL },
{ "-1=3", "-1=3" },
+ { "Foo=,", NULL },
+ { "Foo=,1", NULL },
+ { "Foo=1,,3", NULL },
+ { "Foo=1,3,", NULL },
/* junk. */
{ "!!3@*", NULL },
/* Missing equals sign */
@@ -676,6 +715,228 @@ test_protover_vote_roundtrip_ours(void *args)
tor_free(result);
}
+/* Stringifies its argument.
+ * 4 -> "4" */
+#define STR(x) #x
+
+#ifdef COCCI
+#define PROTOVER(proto_string, version_macro)
+#else
+/* Generate a protocol version string using proto_string and version_macro.
+ * PROTOVER("HSIntro", PROTOVER_HS_INTRO_DOS) -> "HSIntro" "=" "5"
+ * Uses two levels of macros to turn PROTOVER_HS_INTRO_DOS into "5".
+ */
+#define PROTOVER(proto_string, version_macro) \
+ (proto_string "=" STR(version_macro))
+#endif
+
+#define DEBUG_PROTOVER(flags) \
+ STMT_BEGIN \
+ log_debug(LD_GENERAL, \
+ "protovers:\n" \
+ "protocols_known: %d,\n" \
+ "supports_extend2_cells: %d,\n" \
+ "supports_accepting_ipv6_extends: %d,\n" \
+ "supports_initiating_ipv6_extends: %d,\n" \
+ "supports_canonical_ipv6_conns: %d,\n" \
+ "supports_ed25519_link_handshake_compat: %d,\n" \
+ "supports_ed25519_link_handshake_any: %d,\n" \
+ "supports_ed25519_hs_intro: %d,\n" \
+ "supports_establish_intro_dos_extension: %d,\n" \
+ "supports_v3_hsdir: %d,\n" \
+ "supports_v3_rendezvous_point: %d,\n" \
+ "supports_hs_setup_padding: %d.", \
+ (flags).protocols_known, \
+ (flags).supports_extend2_cells, \
+ (flags).supports_accepting_ipv6_extends, \
+ (flags).supports_initiating_ipv6_extends, \
+ (flags).supports_canonical_ipv6_conns, \
+ (flags).supports_ed25519_link_handshake_compat, \
+ (flags).supports_ed25519_link_handshake_any, \
+ (flags).supports_ed25519_hs_intro, \
+ (flags).supports_establish_intro_dos_extension, \
+ (flags).supports_v3_hsdir, \
+ (flags).supports_v3_rendezvous_point, \
+ (flags).supports_hs_setup_padding); \
+ STMT_END
+
+/* Test that the proto_string version version_macro sets summary_flag. */
+#define TEST_PROTOVER(proto_string, version_macro, summary_flag) \
+ STMT_BEGIN \
+ memset(&flags, 0, sizeof(flags)); \
+ summarize_protover_flags(&flags, \
+ PROTOVER(proto_string, version_macro), \
+ NULL); \
+ DEBUG_PROTOVER(flags); \
+ tt_int_op(flags.protocols_known, OP_EQ, 1); \
+ tt_int_op(flags.summary_flag, OP_EQ, 1); \
+ flags.protocols_known = 0; \
+ flags.summary_flag = 0; \
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags)); \
+ STMT_END
+
+static void
+test_protover_summarize_flags(void *args)
+{
+ (void) args;
+ char pv[30];
+ memset(&pv, 0, sizeof(pv));
+
+ protover_summary_cache_free_all();
+
+ protover_summary_flags_t zero_flags;
+ memset(&zero_flags, 0, sizeof(zero_flags));
+ protover_summary_flags_t flags;
+
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags, NULL, NULL);
+ DEBUG_PROTOVER(flags);
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags, "", "");
+ DEBUG_PROTOVER(flags);
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* Now check version exceptions */
+
+ /* EXTEND2 cell support */
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags, NULL, "Tor 0.2.4.8-alpha");
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_extend2_cells, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_extend2_cells = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* disabling HSDir v3 support for buggy versions */
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags,
+ PROTOVER("HSDir", PROTOVER_HSDIR_V3),
+ NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_v3_hsdir, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_v3_hsdir = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags,
+ PROTOVER("HSDir", PROTOVER_HSDIR_V3),
+ "Tor 0.3.0.7");
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ /* Now clear that flag, and check the rest are zero */
+ flags.protocols_known = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* Now check standard summaries */
+
+ /* LinkAuth */
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags,
+ PROTOVER("LinkAuth",
+ PROTOVER_LINKAUTH_ED25519_HANDSHAKE),
+ NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_ed25519_link_handshake_compat, OP_EQ, 1);
+ tt_int_op(flags.supports_ed25519_link_handshake_any, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_ed25519_link_handshake_compat = 0;
+ flags.supports_ed25519_link_handshake_any = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* Test one greater */
+ memset(&flags, 0, sizeof(flags));
+ snprintf(pv, sizeof(pv),
+ "%s=%d", "LinkAuth", PROTOVER_LINKAUTH_ED25519_HANDSHAKE + 1);
+ summarize_protover_flags(&flags, pv, NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_ed25519_link_handshake_compat, OP_EQ, 0);
+ tt_int_op(flags.supports_ed25519_link_handshake_any, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_ed25519_link_handshake_compat = 0;
+ flags.supports_ed25519_link_handshake_any = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* Test one less */
+ memset(&flags, 0, sizeof(flags));
+ snprintf(pv, sizeof(pv),
+ "%s=%d", "LinkAuth", PROTOVER_LINKAUTH_ED25519_HANDSHAKE - 1);
+ summarize_protover_flags(&flags, pv, NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_ed25519_link_handshake_compat, OP_EQ, 0);
+ tt_int_op(flags.supports_ed25519_link_handshake_any, OP_EQ, 0);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_ed25519_link_handshake_compat = 0;
+ flags.supports_ed25519_link_handshake_any = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* We don't test "one more" and "one less" for each protocol version.
+ * But that could be a useful thing to add. */
+
+ /* Relay */
+ memset(&flags, 0, sizeof(flags));
+ /* This test relies on these versions being equal */
+ tt_int_op(PROTOVER_RELAY_EXTEND2, OP_EQ, PROTOVER_RELAY_ACCEPT_IPV6);
+ summarize_protover_flags(&flags,
+ PROTOVER("Relay", PROTOVER_RELAY_EXTEND2), NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_extend2_cells, OP_EQ, 1);
+ tt_int_op(flags.supports_accepting_ipv6_extends, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_extend2_cells = 0;
+ flags.supports_accepting_ipv6_extends = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ memset(&flags, 0, sizeof(flags));
+ /* This test relies on these versions being equal */
+ tt_int_op(PROTOVER_RELAY_EXTEND_IPV6, OP_EQ, PROTOVER_RELAY_CANONICAL_IPV6);
+ summarize_protover_flags(&flags,
+ PROTOVER("Relay", PROTOVER_RELAY_EXTEND_IPV6),
+ NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_accepting_ipv6_extends, OP_EQ, 1);
+ tt_int_op(flags.supports_initiating_ipv6_extends, OP_EQ, 1);
+ tt_int_op(flags.supports_canonical_ipv6_conns, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_accepting_ipv6_extends = 0;
+ flags.supports_initiating_ipv6_extends = 0;
+ flags.supports_canonical_ipv6_conns = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ TEST_PROTOVER("HSIntro", PROTOVER_HS_INTRO_V3,
+ supports_ed25519_hs_intro);
+ TEST_PROTOVER("HSIntro", PROTOVER_HS_INTRO_DOS,
+ supports_establish_intro_dos_extension);
+
+ TEST_PROTOVER("HSRend", PROTOVER_HS_RENDEZVOUS_POINT_V3,
+ supports_v3_rendezvous_point);
+
+ TEST_PROTOVER("HSDir", PROTOVER_HSDIR_V3,
+ supports_v3_hsdir);
+
+ TEST_PROTOVER("Padding", PROTOVER_HS_SETUP_PADDING,
+ supports_hs_setup_padding);
+
+ done:
+ ;
+}
+
#define PV_TEST(name, flags) \
{ #name, test_protover_ ##name, (flags), NULL, NULL }
@@ -690,5 +951,7 @@ struct testcase_t protover_tests[] = {
PV_TEST(supported_protocols, 0),
PV_TEST(vote_roundtrip, 0),
PV_TEST(vote_roundtrip_ours, 0),
+ /* fork, because we memoize flags internally */
+ PV_TEST(summarize_flags, TT_FORK),
END_OF_TESTCASES
};
diff --git a/src/test/test_rebind.py b/src/test/test_rebind.py
index 3fc3deb68e..6b72ece911 100644
--- a/src/test/test_rebind.py
+++ b/src/test/test_rebind.py
@@ -116,7 +116,7 @@ tor_process = subprocess.Popen([tor_path,
if tor_process == None:
fail('ERROR: running tor failed')
-wait_for_log('Opened Control listener on')
+wait_for_log('Opened Control listener')
try_connecting_to_socksport()
diff --git a/src/test/test_relay.c b/src/test/test_relay.c
index 066aeaa7b3..545cb4ac46 100644
--- a/src/test/test_relay.c
+++ b/src/test/test_relay.c
@@ -3,12 +3,12 @@
#define CIRCUITBUILD_PRIVATE
#define RELAY_PRIVATE
-#define REPHIST_PRIVATE
+#define BWHIST_PRIVATE
#include "core/or/or.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/channeltls.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/bwhist.h"
#include "core/or/relay.h"
#include "lib/container/order.h"
/* For init/free stuff */
@@ -17,6 +17,14 @@
#include "core/or/cell_st.h"
#include "core/or/or_circuit_st.h"
+#define RESOLVE_ADDR_PRIVATE
+#include "feature/nodelist/dirlist.h"
+#include "feature/relay/relay_find_addr.h"
+#include "feature/relay/routermode.h"
+#include "feature/dirclient/dir_server_st.h"
+
+#include "app/config/resolve_addr.h"
+
/* Test suite stuff */
#include "test/test.h"
#include "test/fakechans.h"
@@ -24,6 +32,13 @@
static void test_relay_append_cell_to_circuit_queue(void *arg);
+static int
+mock_server_mode_true(const or_options_t *options)
+{
+ (void) options;
+ return 1;
+}
+
static void
assert_circuit_ok_mock(const circuit_t *c)
{
@@ -192,10 +207,167 @@ test_relay_append_cell_to_circuit_queue(void *arg)
return;
}
+static void
+test_suggested_address(void *arg)
+{
+ int ret;
+ const char *untrusted_id = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+ dir_server_t *ds = NULL;
+ tor_addr_t ipv4_addr, ipv6_addr, cache_addr;
+ tor_addr_t trusted_addr, untrusted_addr;
+ tor_addr_port_t trusted_ap_v6 = { .port = 443 };
+
+ (void) arg;
+
+ MOCK(server_mode, mock_server_mode_true);
+
+ /* Unstrusted relay source. */
+ ret = tor_addr_parse(&untrusted_addr, "8.8.8.8");
+ tt_int_op(ret, OP_EQ, AF_INET);
+
+ /* Add gabelmoo as a trusted directory authority. */
+ ret = tor_addr_parse(&trusted_addr, "[2001:638:a000:4140::ffff:189]");
+ tt_int_op(ret, OP_EQ, AF_INET6);
+ tor_addr_copy(&trusted_ap_v6.addr, &trusted_addr);
+
+ ds = trusted_dir_server_new("gabelmoo", "131.188.40.189", 80, 443,
+ &trusted_ap_v6,
+ "F2044413DAC2E02E3D6BCF4735A19BCA1DE97281",
+ "ED03BB616EB2F60BEC80151114BB25CEF515B226",
+ V3_DIRINFO, 1.0);
+ tt_assert(ds);
+ dir_server_add(ds);
+
+ /* 1. Valid IPv4 from a trusted authority (gabelmoo). */
+ ret = tor_addr_parse(&ipv4_addr, "1.2.3.4");
+ relay_address_new_suggestion(&ipv4_addr, &ds->ipv4_addr, ds->digest);
+ resolved_addr_get_suggested(AF_INET, &cache_addr);
+ tt_assert(tor_addr_eq(&cache_addr, &ipv4_addr));
+ resolve_addr_reset_suggested(AF_INET);
+
+ /* 2. Valid IPv6 from a trusted authority (gabelmoo). */
+ ret = tor_addr_parse(&ipv6_addr, "[4242::4242]");
+ relay_address_new_suggestion(&ipv6_addr, &ds->ipv6_addr, ds->digest);
+ resolved_addr_get_suggested(AF_INET6, &cache_addr);
+ tt_assert(tor_addr_eq(&cache_addr, &ipv6_addr));
+ resolve_addr_reset_suggested(AF_INET6);
+
+ /* 3. Valid IPv4 but untrusted source. */
+ ret = tor_addr_parse(&ipv4_addr, "1.2.3.4");
+ relay_address_new_suggestion(&ipv4_addr, &untrusted_addr, untrusted_id);
+ resolved_addr_get_suggested(AF_INET, &cache_addr);
+ tt_assert(tor_addr_is_unspec(&cache_addr));
+
+ /* 4. Valid IPv6 but untrusted source. */
+ ret = tor_addr_parse(&ipv6_addr, "[4242::4242]");
+ relay_address_new_suggestion(&ipv6_addr, &untrusted_addr, untrusted_id);
+ resolved_addr_get_suggested(AF_INET6, &cache_addr);
+ tt_assert(tor_addr_is_unspec(&cache_addr));
+
+ /* 5. Internal IPv4 from a trusted authority (gabelmoo). */
+ ret = tor_addr_parse(&ipv4_addr, "127.0.0.1");
+ relay_address_new_suggestion(&ipv4_addr, &ds->ipv4_addr, ds->digest);
+ resolved_addr_get_suggested(AF_INET, &cache_addr);
+ tt_assert(tor_addr_is_unspec(&cache_addr));
+
+ /* 6. Internal IPv6 from a trusted authority (gabelmoo). */
+ ret = tor_addr_parse(&ipv6_addr, "[::1]");
+ relay_address_new_suggestion(&ipv6_addr, &ds->ipv6_addr, ds->digest);
+ resolved_addr_get_suggested(AF_INET6, &cache_addr);
+ tt_assert(tor_addr_is_unspec(&cache_addr));
+
+ /* 7. IPv4 from a trusted authority (gabelmoo). */
+ relay_address_new_suggestion(&ds->ipv4_addr, &ds->ipv4_addr, ds->digest);
+ resolved_addr_get_suggested(AF_INET, &cache_addr);
+ tt_assert(tor_addr_is_unspec(&cache_addr));
+
+ /* 8. IPv6 from a trusted authority (gabelmoo). */
+ relay_address_new_suggestion(&ds->ipv6_addr, &ds->ipv6_addr, ds->digest);
+ resolved_addr_get_suggested(AF_INET6, &cache_addr);
+ tt_assert(tor_addr_is_unspec(&cache_addr));
+
+ done:
+ dirlist_free_all();
+
+ UNMOCK(server_mode);
+}
+
+static void
+test_find_addr_to_publish(void *arg)
+{
+ int family;
+ bool ret;
+ tor_addr_t ipv4_addr, ipv6_addr, cache_addr;
+ or_options_t options;
+
+ (void) arg;
+
+ memset(&options, 0, sizeof(options));
+
+ /* Populate our resolved cache with a valid IPv4 and IPv6. */
+ family = tor_addr_parse(&ipv4_addr, "1.2.3.4");
+ tt_int_op(family, OP_EQ, AF_INET);
+ resolved_addr_set_last(&ipv4_addr, RESOLVED_ADDR_CONFIGURED, NULL);
+ resolved_addr_get_last(AF_INET, &cache_addr);
+ tt_assert(tor_addr_eq(&ipv4_addr, &cache_addr));
+
+ family = tor_addr_parse(&ipv6_addr, "[4242::4242]");
+ tt_int_op(family, OP_EQ, AF_INET6);
+ resolved_addr_set_last(&ipv6_addr, RESOLVED_ADDR_CONFIGURED, NULL);
+ resolved_addr_get_last(AF_INET6, &cache_addr);
+ tt_assert(tor_addr_eq(&ipv6_addr, &cache_addr));
+
+ /* 1. Address located in the resolved cache. */
+ ret = relay_find_addr_to_publish(&options, AF_INET,
+ RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr);
+ tt_assert(ret);
+ tt_assert(tor_addr_eq(&ipv4_addr, &cache_addr));
+
+ ret = relay_find_addr_to_publish(&options, AF_INET6,
+ RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr);
+ tt_assert(ret);
+ tt_assert(tor_addr_eq(&ipv6_addr, &cache_addr));
+ resolved_addr_reset_last(AF_INET);
+ resolved_addr_reset_last(AF_INET6);
+
+ /* 2. No IP in the resolve cache, go to the suggested cache. We will ignore
+ * the find_my_address() code path because that is extensively tested in
+ * another unit tests. */
+ resolved_addr_set_suggested(&ipv4_addr);
+ ret = relay_find_addr_to_publish(&options, AF_INET,
+ RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr);
+ tt_assert(ret);
+ tt_assert(tor_addr_eq(&ipv4_addr, &cache_addr));
+
+ resolved_addr_set_suggested(&ipv6_addr);
+ ret = relay_find_addr_to_publish(&options, AF_INET6,
+ RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr);
+ tt_assert(ret);
+ tt_assert(tor_addr_eq(&ipv6_addr, &cache_addr));
+ resolve_addr_reset_suggested(AF_INET);
+ resolve_addr_reset_suggested(AF_INET6);
+
+ /* 3. No IP anywhere. */
+ ret = relay_find_addr_to_publish(&options, AF_INET,
+ RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr);
+ tt_assert(!ret);
+ ret = relay_find_addr_to_publish(&options, AF_INET6,
+ RELAY_FIND_ADDR_CACHE_ONLY, &cache_addr);
+ tt_assert(!ret);
+
+ done:
+ ;
+}
+
struct testcase_t relay_tests[] = {
{ "append_cell_to_circuit_queue", test_relay_append_cell_to_circuit_queue,
TT_FORK, NULL, NULL },
{ "close_circ_rephist", test_relay_close_circuit,
TT_FORK, NULL, NULL },
+ { "suggested_address", test_suggested_address,
+ TT_FORK, NULL, NULL },
+ { "find_addr_to_publish", test_find_addr_to_publish,
+ TT_FORK, NULL, NULL },
+
END_OF_TESTCASES
};
diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c
index da9e791fb6..3a317be5fe 100644
--- a/src/test/test_relaycell.c
+++ b/src/test/test_relaycell.c
@@ -220,7 +220,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
int sendme_cells = (STREAMWINDOW_START-edgeconn->package_window)
/STREAMWINDOW_INCREMENT;
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
connection_edge_reached_eof(edgeconn);
/* Data cell not in the half-opened list */
@@ -272,7 +271,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* DATA cells up to limit */
while (data_cells > 0) {
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -283,7 +281,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
data_cells--;
}
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -295,7 +292,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* SENDME cells up to limit */
while (sendme_cells > 0) {
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -306,7 +302,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
sendme_cells--;
}
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -317,7 +312,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* Only one END cell */
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -327,7 +321,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
ASSERT_COUNTED_BW();
ENTRY_TO_CONN(entryconn2)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn2)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -339,7 +332,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
edgeconn = ENTRY_TO_EDGE_CONN(entryconn3);
edgeconn->base_.state = AP_CONN_STATE_OPEN;
ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0;
/* sendme cell on open entryconn with full window */
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234");
int ret =
@@ -350,7 +342,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* connected cell on a after EOF */
ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0;
edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT;
connection_edge_reached_eof(edgeconn);
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234");
@@ -362,7 +353,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
ASSERT_COUNTED_BW();
ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_CONNECTED, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -373,7 +363,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* DATA and SENDME after END cell */
ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -383,7 +372,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
ASSERT_COUNTED_BW();
ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_SENDME, "Data1234");
ret =
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
@@ -392,7 +380,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
ASSERT_UNCOUNTED_BW();
ENTRY_TO_CONN(entryconn3)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn3)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -407,11 +394,9 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
edgeconn->base_.state = AP_CONN_STATE_RESOLVE_WAIT;
edgeconn->on_circuit = TO_CIRCUIT(circ);
ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0;
connection_edge_reached_eof(edgeconn);
ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED,
"\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
@@ -422,7 +407,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
ASSERT_COUNTED_BW();
ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_RESOLVED,
"\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00");
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
@@ -431,7 +415,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* Data not counted after resolved */
ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_DATA, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -442,7 +425,6 @@ subtest_circbw_halfclosed(origin_circuit_t *circ, streamid_t init_id)
/* End not counted after resolved */
ENTRY_TO_CONN(entryconn4)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn4)->outbuf_flushlen = 0;
PACK_CELL(edgeconn->stream_id, RELAY_COMMAND_END, "Data1234");
if (circ->base_.purpose == CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
pathbias_count_valid_cells(TO_CIRCUIT(circ), &cell);
@@ -660,7 +642,6 @@ test_halfstream_wrap(void *arg)
/* Insert an opened stream on the circ with that id */
ENTRY_TO_CONN(entryconn)->marked_for_close = 0;
- ENTRY_TO_CONN(entryconn)->outbuf_flushlen = 0;
edgeconn->base_.state = AP_CONN_STATE_CONNECT_WAIT;
circ->p_streams = edgeconn;
@@ -784,14 +765,12 @@ test_circbw_relay(void *arg)
/* Sendme on valid stream: counted */
edgeconn->package_window -= STREAMWINDOW_INCREMENT;
- ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0;
PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
circ->cpath);
ASSERT_COUNTED_BW();
/* Sendme on valid stream with full window: not counted */
- ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0;
PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
edgeconn->package_window = STREAMWINDOW_START;
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
@@ -799,7 +778,6 @@ test_circbw_relay(void *arg)
ASSERT_UNCOUNTED_BW();
/* Sendme on unknown stream: not counted */
- ENTRY_TO_CONN(entryconn1)->outbuf_flushlen = 0;
PACK_CELL(1, RELAY_COMMAND_SENDME, "Data1234");
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), NULL,
circ->cpath);
diff --git a/src/test/test_router.c b/src/test/test_router.c
index cf0c2b3dd1..ddd043b941 100644
--- a/src/test/test_router.c
+++ b/src/test/test_router.c
@@ -24,7 +24,7 @@
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/routerstatus_st.h"
#include "feature/relay/router.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/bwhist.h"
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/encoding/confline.h"
@@ -61,8 +61,8 @@ rtr_tests_router_get_my_routerinfo(void)
mock_routerinfo = tor_malloc_zero(sizeof(routerinfo_t));
mock_routerinfo->nickname = tor_strdup("ConlonNancarrow");
- mock_routerinfo->addr = 123456789;
- mock_routerinfo->or_port = 443;
+ tor_addr_from_ipv4h(&mock_routerinfo->ipv4_addr, 123456789);
+ mock_routerinfo->ipv4_orport = 443;
mock_routerinfo->platform = tor_strdup("unittest");
mock_routerinfo->cache_info.published_on = now;
mock_routerinfo->identity_pkey = crypto_pk_dup_key(ident_key);
@@ -226,13 +226,13 @@ test_router_check_descriptor_bandwidth_changed(void *arg)
/* When uptime is less than 24h and bandwidthcapacity does not change
* Uptime: 10800, last_changed: x, Previous bw: 10000, Current bw: 20001 */
- MOCK(rep_hist_bandwidth_assess, mock_rep_hist_bandwidth_assess);
+ MOCK(bwhist_bandwidth_assess, mock_rep_hist_bandwidth_assess);
setup_full_capture_of_logs(LOG_INFO);
check_descriptor_bandwidth_changed(time(NULL) + 6*60*60 + 1);
expect_log_msg_containing(
"Measured bandwidth has changed; rebuilding descriptor.");
UNMOCK(get_uptime);
- UNMOCK(rep_hist_bandwidth_assess);
+ UNMOCK(bwhist_bandwidth_assess);
teardown_capture_of_logs();
/* When uptime is more than 24h */
@@ -507,13 +507,12 @@ test_router_get_advertised_or_port(void *arg)
listener_connection_t *listener = NULL;
tor_addr_port_t ipv6;
- // Test one failing case of router_get_advertised_ipv6_or_ap().
- router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ // Test one failing case of routerconf_find_ipv6_or_ap().
+ routerconf_find_ipv6_or_ap(opts, &ipv6);
tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0");
- // And one failing case of router_get_advertised_or_port().
- tt_int_op(0, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
- tt_int_op(0, OP_EQ, router_get_advertised_or_port(opts));
+ // And one failing case of routerconf_find_or_port().
+ tt_int_op(0, OP_EQ, routerconf_find_or_port(opts, AF_INET));
// Set up a couple of configured ports.
config_line_append(&opts->ORPort_lines, "ORPort", "[1234::5678]:auto");
@@ -522,13 +521,12 @@ test_router_get_advertised_or_port(void *arg)
tt_assert(r == 0);
// There are no listeners, so the "auto" case will turn up no results.
- tt_int_op(0, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
- router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_int_op(0, OP_EQ, routerconf_find_or_port(opts, AF_INET6));
+ routerconf_find_ipv6_or_ap(opts, &ipv6);
tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0");
// This will return the matching value from the configured port.
- tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
- tt_int_op(9999, OP_EQ, router_get_advertised_or_port(opts));
+ tt_int_op(9999, OP_EQ, routerconf_find_or_port(opts, AF_INET));
// Now set up a dummy listener.
MOCK(get_connection_array, mock_get_connection_array);
@@ -538,16 +536,15 @@ test_router_get_advertised_or_port(void *arg)
smartlist_add(fake_connection_array, TO_CONN(listener));
// We should get a port this time.
- tt_int_op(54321, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
+ tt_int_op(54321, OP_EQ, routerconf_find_or_port(opts, AF_INET6));
- // Test one succeeding case of router_get_advertised_ipv6_or_ap().
- router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ // Test one succeeding case of routerconf_find_ipv6_or_ap().
+ routerconf_find_ipv6_or_ap(opts, &ipv6);
tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ,
"[1234::5678]:54321");
// This will return the matching value from the configured port.
- tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
- tt_int_op(9999, OP_EQ, router_get_advertised_or_port(opts));
+ tt_int_op(9999, OP_EQ, routerconf_find_or_port(opts, AF_INET));
done:
or_options_free(opts);
@@ -573,28 +570,26 @@ test_router_get_advertised_or_port_localhost(void *arg)
tt_assert(r == 0);
// We should refuse to advertise them, since we have default dirauths.
- router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ routerconf_find_ipv6_or_ap(opts, &ipv6);
tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0");
// But the lower-level function should still report the correct value
- tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
+ tt_int_op(9999, OP_EQ, routerconf_find_or_port(opts, AF_INET6));
// The IPv4 checks are done in resolve_my_address(), which doesn't use
// ORPorts so we can't test them here. (See #33681.) Both these lower-level
// functions should still report the correct value.
- tt_int_op(8888, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
- tt_int_op(8888, OP_EQ, router_get_advertised_or_port(opts));
+ tt_int_op(8888, OP_EQ, routerconf_find_or_port(opts, AF_INET));
// Now try with a fake authority set up.
config_line_append(&opts->DirAuthorities, "DirAuthority",
"127.0.0.1:1066 "
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
- tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6));
- router_get_advertised_ipv6_or_ap(opts, &ipv6);
+ tt_int_op(9999, OP_EQ, routerconf_find_or_port(opts, AF_INET6));
+ routerconf_find_ipv6_or_ap(opts, &ipv6);
tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::1]:9999");
- tt_int_op(8888, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET));
- tt_int_op(8888, OP_EQ, router_get_advertised_or_port(opts));
+ tt_int_op(8888, OP_EQ, routerconf_find_or_port(opts, AF_INET));
done:
or_options_free(opts);
diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c
index fc437dccc0..e5314046b9 100644
--- a/src/test/test_routerkeys.c
+++ b/src/test/test_routerkeys.c
@@ -51,7 +51,7 @@ test_routerkeys_write_fingerprint(void *arg)
tt_int_op(crypto_pk_cmp_keys(get_server_identity_key(),key),OP_EQ,0);
/* Write fingerprint file */
- tt_int_op(0, OP_EQ, router_write_fingerprint(0));
+ tt_int_op(0, OP_EQ, router_write_fingerprint(0, 0));
cp = read_file_to_str(get_fname("write_fingerprint/fingerprint"),
0, NULL);
crypto_pk_get_fingerprint(key, fp, 0);
@@ -61,7 +61,7 @@ test_routerkeys_write_fingerprint(void *arg)
tor_free(cp2);
/* Write hashed-fingerprint file */
- tt_int_op(0, OP_EQ, router_write_fingerprint(1));
+ tt_int_op(0, OP_EQ, router_write_fingerprint(1, 0));
cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
0, NULL);
crypto_pk_get_hashed_fingerprint(key, fp);
@@ -73,7 +73,7 @@ test_routerkeys_write_fingerprint(void *arg)
/* Replace outdated file */
write_str_to_file(get_fname("write_fingerprint/hashed-fingerprint"),
"junk goes here", 0);
- tt_int_op(0, OP_EQ, router_write_fingerprint(1));
+ tt_int_op(0, OP_EQ, router_write_fingerprint(1, 0));
cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
0, NULL);
crypto_pk_get_hashed_fingerprint(key, fp);
@@ -90,6 +90,51 @@ test_routerkeys_write_fingerprint(void *arg)
}
static void
+test_routerkeys_write_ed25519_identity(void *arg)
+{
+ crypto_pk_t *key = pk_generate(2);
+ or_options_t *options = get_options_mutable();
+ time_t now = time(NULL);
+ const char *ddir = get_fname("write_fingerprint");
+ char *cp = NULL, *cp2 = NULL;
+ char ed25519_id[BASE64_DIGEST256_LEN + 1];
+
+ (void) arg;
+
+ tt_assert(key);
+
+ options->ORPort_set = 1; /* So that we can get the server ID key */
+ tor_free(options->DataDirectory);
+ options->DataDirectory = tor_strdup(ddir);
+ options->Nickname = tor_strdup("haflinger");
+ set_server_identity_key(key);
+ set_client_identity_key(crypto_pk_dup_key(key));
+
+ load_ed_keys(options, now);
+ tt_assert(get_master_identity_key());
+
+ tt_int_op(0, OP_EQ, check_private_dir(ddir, CPD_CREATE, NULL));
+
+ /* Write fingerprint file */
+ tt_int_op(0, OP_EQ, router_write_fingerprint(0, 1));
+ cp = read_file_to_str(get_fname("write_fingerprint/fingerprint-ed25519"),
+ 0, NULL);
+ digest256_to_base64(ed25519_id,
+ (const char *) get_master_identity_key()->pubkey);
+ tor_asprintf(&cp2, "haflinger %s\n", ed25519_id);
+ tt_str_op(cp, OP_EQ, cp2);
+ tor_free(cp);
+ tor_free(cp2);
+
+ done:
+ crypto_pk_free(key);
+ set_client_identity_key(NULL);
+ tor_free(cp);
+ tor_free(cp2);
+ routerkeys_free_all();
+}
+
+static void
test_routerkeys_ed_certs(void *args)
{
(void)args;
@@ -106,7 +151,7 @@ test_routerkeys_ed_certs(void *args)
for (int i = 0; i <= 1; ++i) {
uint32_t flags = i ? CERT_FLAG_INCLUDE_SIGNING_KEY : 0;
- cert[i] = tor_cert_create(&kp1, 5, &kp2.pubkey, now, 10000, flags);
+ cert[i] = tor_cert_create_ed25519(&kp1, 5, &kp2.pubkey, now, 10000, flags);
tt_assert(cert[i]);
tt_uint_op(cert[i]->sig_bad, OP_EQ, 0);
@@ -695,6 +740,7 @@ test_routerkeys_rsa_ed_crosscert(void *arg)
struct testcase_t routerkeys_tests[] = {
TEST(write_fingerprint, TT_FORK),
+ TEST(write_ed25519_identity, TT_FORK),
TEST(ed_certs, TT_FORK),
TEST(ed_key_create, TT_FORK),
TEST(ed_key_init_basic, TT_FORK),
diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c
index f2a83c18a3..91a75d7080 100644
--- a/src/test/test_routerlist.c
+++ b/src/test/test_routerlist.c
@@ -341,18 +341,18 @@ test_router_pick_directory_server_impl(void *arg)
node_router1->rs->is_v2_dir = 0;
node_router3->rs->is_v2_dir = 0;
- tmp_dirport1 = node_router1->rs->dir_port;
- tmp_dirport3 = node_router3->rs->dir_port;
- node_router1->rs->dir_port = 0;
- node_router3->rs->dir_port = 0;
+ tmp_dirport1 = node_router1->rs->ipv4_dirport;
+ tmp_dirport3 = node_router3->rs->ipv4_dirport;
+ node_router1->rs->ipv4_dirport = 0;
+ node_router3->rs->ipv4_dirport = 0;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router2_id, DIGEST_LEN));
rs = NULL;
node_router1->rs->is_v2_dir = 1;
node_router3->rs->is_v2_dir = 1;
- node_router1->rs->dir_port = tmp_dirport1;
- node_router3->rs->dir_port = tmp_dirport3;
+ node_router1->rs->ipv4_dirport = tmp_dirport1;
+ node_router3->rs->ipv4_dirport = tmp_dirport3;
node_router1->is_valid = 0;
node_router3->is_valid = 0;
@@ -381,23 +381,23 @@ test_router_pick_directory_server_impl(void *arg)
options->ReachableORAddresses = policy_line;
policies_parse_from_options(options);
- node_router1->rs->or_port = 444;
- node_router2->rs->or_port = 443;
- node_router3->rs->or_port = 442;
+ node_router1->rs->ipv4_orport = 444;
+ node_router2->rs->ipv4_orport = 443;
+ node_router3->rs->ipv4_orport = 442;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router3_id, DIGEST_LEN));
- node_router1->rs->or_port = 442;
- node_router2->rs->or_port = 443;
- node_router3->rs->or_port = 444;
+ node_router1->rs->ipv4_orport = 442;
+ node_router2->rs->ipv4_orport = 443;
+ node_router3->rs->ipv4_orport = 444;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router1_id, DIGEST_LEN));
/* Fascist firewall and overloaded */
- node_router1->rs->or_port = 442;
- node_router2->rs->or_port = 443;
- node_router3->rs->or_port = 442;
+ node_router1->rs->ipv4_orport = 442;
+ node_router2->rs->ipv4_orport = 443;
+ node_router3->rs->ipv4_orport = 442;
node_router3->rs->last_dir_503_at = now;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
tt_ptr_op(rs, OP_NE, NULL);
@@ -410,12 +410,12 @@ test_router_pick_directory_server_impl(void *arg)
policy_line->value = tor_strdup("accept *:80, reject *:*");
options->ReachableDirAddresses = policy_line;
policies_parse_from_options(options);
- node_router1->rs->or_port = 442;
- node_router2->rs->or_port = 441;
- node_router3->rs->or_port = 443;
- node_router1->rs->dir_port = 80;
- node_router2->rs->dir_port = 80;
- node_router3->rs->dir_port = 81;
+ node_router1->rs->ipv4_orport = 442;
+ node_router2->rs->ipv4_orport = 441;
+ node_router3->rs->ipv4_orport = 443;
+ node_router1->rs->ipv4_dirport = 80;
+ node_router2->rs->ipv4_dirport = 80;
+ node_router3->rs->ipv4_dirport = 81;
node_router1->rs->last_dir_503_at = now;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
tt_ptr_op(rs, OP_NE, NULL);
diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c
index 892ac6e210..d00eefa23f 100644
--- a/src/test/test_routerset.c
+++ b/src/test/test_routerset.c
@@ -1417,12 +1417,62 @@ test_rset_contains_router(void *arg)
ri.nickname = (char *)nickname;
r = routerset_contains_router(set, &ri, country);
-
tt_int_op(r, OP_EQ, 4);
+
done:
routerset_free(set);
}
+static void
+test_rset_contains_router_ipv4(void *arg)
+{
+ routerset_t *set;
+ routerinfo_t ri;
+ country_t country = 1;
+ int r;
+ const char *s;
+ (void) arg;
+
+ /* IPv4 address test. */
+ memset(&ri, 0, sizeof(ri));
+ set = routerset_new();
+ s = "10.0.0.1";
+ r = routerset_parse(set, s, "");
+ tor_addr_from_ipv4h(&ri.ipv4_addr, 0x0a000001);
+ ri.ipv4_orport = 1234;
+
+ r = routerset_contains_router(set, &ri, country);
+ tt_int_op(r, OP_EQ, 3);
+
+ done:
+ routerset_free(set);
+}
+
+static void
+test_rset_contains_router_ipv6(void *arg)
+{
+ routerset_t *set;
+ routerinfo_t ri;
+ country_t country = 1;
+ int r;
+ const char *s;
+ (void) arg;
+
+ /* IPv6 address test. */
+ memset(&ri, 0, sizeof(ri));
+ set = routerset_new();
+ s = "2600::1";
+ r = routerset_parse(set, s, "");
+ tor_addr_parse(&ri.ipv6_addr, "2600::1");
+ ri.ipv6_orport = 12345;
+
+ r = routerset_contains_router(set, &ri, country);
+ tt_int_op(r, OP_EQ, 3);
+
+ done:
+ routerset_free(set);
+}
+
/*
* Functional test for routerset_contains_routerstatus.
*/
@@ -2144,6 +2194,10 @@ struct testcase_t routerset_tests[] = {
{ "contains_extendinfo", test_rset_contains_extendinfo,
TT_FORK, NULL, NULL },
{ "contains_router", test_rset_contains_router, TT_FORK, NULL, NULL },
+ { "contains_router_ipv4", test_rset_contains_router_ipv4,
+ TT_FORK, NULL, NULL },
+ { "contains_router_ipv6", test_rset_contains_router_ipv6,
+ TT_FORK, NULL, NULL },
{ "contains_routerstatus", test_rset_contains_routerstatus,
TT_FORK, NULL, NULL },
{ "contains_none", test_rset_contains_none, TT_FORK, NULL, NULL },
diff --git a/src/test/test_stats.c b/src/test/test_stats.c
index 291473ebc9..b6849b0b6d 100644
--- a/src/test/test_stats.c
+++ b/src/test/test_stats.c
@@ -30,6 +30,7 @@
#define CIRCUITLIST_PRIVATE
#define MAINLOOP_PRIVATE
#define STATEFILE_PRIVATE
+#define BWHIST_PRIVATE
#include "core/or/or.h"
#include "lib/err/backtrace.h"
@@ -39,8 +40,11 @@
#include "test/test.h"
#include "core/mainloop/mainloop.h"
#include "lib/memarea/memarea.h"
+#include "feature/stats/connstats.h"
#include "feature/stats/rephist.h"
#include "app/config/statefile.h"
+#include "feature/stats/bwhist.h"
+#include "feature/stats/bw_array_st.h"
/** Run unit tests for some stats code. */
static void
@@ -111,37 +115,41 @@ test_stats(void *arg)
/* Continue with testing connection statistics; we shouldn't collect
* conn stats without initializing them. */
- rep_hist_note_or_conn_bytes(1, 20, 400, now);
- s = rep_hist_format_conn_stats(now + 86400);
+ conn_stats_note_or_conn_bytes(1, 20, 400, now, false);
+ s = conn_stats_format(now + 86400);
tt_ptr_op(s, OP_EQ, NULL);
/* Initialize stats, note bytes, and generate history string. */
- rep_hist_conn_stats_init(now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
- s = rep_hist_format_conn_stats(now + 86400);
- tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,1,0\n",OP_EQ, s);
+ conn_stats_init(now);
+ conn_stats_note_or_conn_bytes(1, 30000, 400000, now, false);
+ conn_stats_note_or_conn_bytes(1, 30000, 400000, now + 5, false);
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 10, true);
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 15, true);
+ s = conn_stats_format(now + 86400);
+ tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,1,0\n"
+ "ipv6-conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n",
+ OP_EQ, s);
tor_free(s);
/* Stop collecting stats, add some bytes, and ensure we don't generate
* a history string. */
- rep_hist_conn_stats_term();
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
- s = rep_hist_format_conn_stats(now + 86400);
+ conn_stats_terminate();
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 15, true);
+ s = conn_stats_format(now + 86400);
tt_ptr_op(s, OP_EQ, NULL);
/* Re-start stats, add some bytes, reset stats, and see what history we
* get when observing no bytes at all. */
- rep_hist_conn_stats_init(now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
- rep_hist_reset_conn_stats(now);
- s = rep_hist_format_conn_stats(now + 86400);
- tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n",OP_EQ, s);
+ conn_stats_init(now);
+ conn_stats_note_or_conn_bytes(1, 30000, 400000, now, false);
+ conn_stats_note_or_conn_bytes(1, 30000, 400000, now + 5, false);
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 10, true);
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 15, true);
+ conn_stats_reset(now);
+ s = conn_stats_format(now + 86400);
+ tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n"
+ "ipv6-conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n",
+ OP_EQ, s);
tor_free(s);
/* Continue with testing buffer statistics; we shouldn't collect buffer
@@ -245,6 +253,246 @@ test_rephist_mtbf(void *arg)
tor_free(ddir_fname);
}
+static void
+test_commit_max(void *arg)
+{
+ (void) arg;
+ bw_array_t *b = bw_array_new();
+ time_t now = b->cur_obs_time;
+
+ commit_max(b);
+ tt_int_op(b->next_period, OP_EQ, now + 2*86400);
+
+ b->total_in_period = 100;
+ b->max_total = 10;
+ commit_max(b);
+ tor_assert(b->total_in_period == 0);
+ tor_assert(b->max_total == 0);
+ tt_int_op(b->totals[1], OP_EQ, 100);
+ tt_int_op(b->maxima[1], OP_EQ, 10);
+ tt_int_op(b->next_period, OP_EQ, now + 3*86400);
+
+ commit_max(b);
+ tt_int_op(b->next_period, OP_EQ, now + 4*86400);
+
+ commit_max(b);
+ tt_int_op(b->next_period, OP_EQ, now + 5*86400);
+
+ b->total_in_period = 100;
+ b->max_total = 10;
+ commit_max(b);
+ tor_assert(!b->next_max_idx);
+ tt_int_op(b->cur_obs_idx, OP_EQ, 0);
+ tt_int_op(b->totals[4], OP_EQ, 100);
+ tt_int_op(b->maxima[4], OP_EQ, 10);
+ tt_int_op(b->next_period, OP_EQ, now + 6*86400);
+ done:
+ bw_array_free(b);
+}
+
+#define test_obs(b, idx, time, tot, max) STMT_BEGIN \
+ tt_int_op(b->cur_obs_idx, OP_EQ, idx); \
+ tt_int_op(b->cur_obs_time, OP_EQ, time); \
+ tt_int_op(b->total_obs, OP_EQ, tot); \
+ tt_int_op(b->max_total, OP_EQ, max); \
+ STMT_END;
+
+static void
+test_advance_obs(void *arg)
+{
+ (void) arg;
+ int iter, tot = 0;
+ bw_array_t *b = bw_array_new();
+ time_t now = b->cur_obs_time;
+
+ for (iter = 0; iter < 10; ++iter) {
+ b->obs[b->cur_obs_idx] += 10;
+ tot += 10;
+ advance_obs(b);
+ if (iter == 9) {
+ /* The current value under cur_obs_idx was zeroed in last iterN. */
+ test_obs(b, 0, now+iter+1, tot - 10, tot);
+ break;
+ }
+ test_obs(b, iter+1, now+iter+1, tot, tot);
+ }
+
+ b->total_in_period = 100;
+ b->cur_obs_time = now + NUM_SECS_BW_SUM_INTERVAL - 1;
+ advance_obs(b);
+ test_obs(b, 1, now+NUM_SECS_BW_SUM_INTERVAL, 80, 0);
+ tt_int_op(b->maxima[0], OP_EQ, 100);
+ tt_int_op(b->totals[0], OP_EQ, 100);
+ tt_int_op(b->num_maxes_set, OP_EQ, 1);
+ done:
+ bw_array_free(b);
+}
+
+#define test_add_obs_(b, now, checknow, bw, tot) STMT_BEGIN \
+ tot += bw; \
+ add_obs(b, now, bw); \
+ tt_int_op(b->cur_obs_time, OP_EQ, checknow); \
+ tt_int_op(b->obs[b->cur_obs_idx], OP_EQ, bw); \
+ tt_int_op(b->total_in_period, OP_EQ, tot); \
+ STMT_END;
+
+static void
+test_add_obs(void *arg)
+{
+ (void) arg;
+ bw_array_t *b = bw_array_new();
+ time_t now = b->cur_obs_time;
+ uint64_t bw = 0, tot = 0;
+ /* Requests for the past should not be entertained. */
+ test_add_obs_(b, now-1, now, bw, tot);
+ /* Test the expected functionalities for random values. */
+ now += 53;
+ bw = 97;
+ test_add_obs_(b, now, now, bw, tot);
+
+ now += 60*60;
+ bw = 90;
+ test_add_obs_(b, now, now, bw, tot);
+
+ now += 24*60*60;
+ bw = 100;
+ tot = 0;
+ test_add_obs_(b, now, now, bw, tot);
+ done:
+ bw_array_free(b);
+}
+
+static or_options_t mock_options;
+
+static const or_options_t *
+mock_get_options(void)
+{
+ return &mock_options;
+}
+
+#define MAX_HIST_VALUE_LEN 21*NUM_TOTALS
+
+#define set_test_case(b, max, idx, a1, a2, a3, a4, a5) STMT_BEGIN \
+ b->num_maxes_set = max; \
+ b->next_max_idx = idx; \
+ b->totals[0] = a1; \
+ b->totals[1] = a2; \
+ b->totals[2] = a3; \
+ b->totals[3] = a4; \
+ b->totals[4] = a5; \
+ STMT_END;
+
+#define test_fill_bw(b, buf, rv, str, checkrv) STMT_BEGIN \
+ buf = tor_malloc_zero(MAX_HIST_VALUE_LEN); \
+ rv = bwhist_fill_bandwidth_history(buf, MAX_HIST_VALUE_LEN, b); \
+ tt_str_op(buf, OP_EQ, str); \
+ tt_int_op(rv, OP_EQ, checkrv); \
+ tor_free(buf); \
+ STMT_END;
+
+static void
+test_fill_bandwidth_history(void *arg)
+{
+ (void) arg;
+ bw_array_t *b = bw_array_new();
+ char *buf;
+ size_t rv;
+ /* Remember bandwidth is rounded down to the nearest 1K. */
+ /* Day 1. */
+ set_test_case(b, 0, 0, 0, 0, 0, 0, 0);
+ buf = tor_malloc_zero(MAX_HIST_VALUE_LEN);
+ rv = bwhist_fill_bandwidth_history(buf, MAX_HIST_VALUE_LEN, b);
+ tt_int_op(rv, OP_EQ, 0);
+ tor_free(buf);
+ /* Day 2. */
+ set_test_case(b, 1, 1, 1000, 0, 0, 0, 0);
+ test_fill_bw(b, buf, rv, "0", 1);
+ /* Day 3. */
+ set_test_case(b, 2, 2, 1000, 1500, 0, 0, 0);
+ test_fill_bw(b, buf, rv, "0,1024", 6);
+ /* Day 4. */
+ set_test_case(b, 3, 3, 1000, 1500, 3500, 0, 0);
+ test_fill_bw(b, buf, rv, "0,1024,3072", 11);
+ /* Day 5. */
+ set_test_case(b, 4, 4, 1000, 1500, 3500, 8000, 0);
+ test_fill_bw(b, buf, rv, "0,1024,3072,7168", 16);
+ /* Day 6. */
+ set_test_case(b, 5, 0, 1000, 1500, 3500, 8000, 6000);
+ test_fill_bw(b, buf, rv, "0,1024,3072,7168,5120", 21);
+ /* Day 7. */
+ /* Remember oldest entry first. */
+ set_test_case(b, 5, 1, 10000, 1500, 3500, 8000, 6000);
+ test_fill_bw(b, buf, rv, "1024,3072,7168,5120,9216", 24);
+ /* Mocking get_options to manipulate RelayBandwidthRate. */
+ MOCK(get_options, mock_get_options);
+ /* Limits bandwidth to 1 KBps. */
+ /* Cutoff is set to 88473600. */
+ mock_options.RelayBandwidthRate = 1024;
+ set_test_case(b, 5, 2, 88573600, 88473600, 10000, 8000, 6000);
+ test_fill_bw(b, buf, rv, "9216,7168,5120,88473600,88473600", 32);
+ done:
+ UNMOCK(get_options);
+ bw_array_free(b);
+}
+
+#define set_test_bw_lines(r, w, dr, dw, when) STMT_BEGIN \
+ bwhist_note_bytes_read(r, when, false); \
+ bwhist_note_bytes_written(w, when, false); \
+ bwhist_note_dir_bytes_read(dr, when); \
+ bwhist_note_dir_bytes_written(dw, when); \
+ STMT_END;
+
+#define test_get_bw_lines(str, checkstr) STMT_BEGIN \
+ str = bwhist_get_bandwidth_lines(); \
+ tt_str_op(str, OP_EQ, checkstr); \
+ tor_free(str); \
+ STMT_END;
+
+static void
+test_get_bandwidth_lines(void *arg)
+{
+ (void) arg;
+ char *str = NULL, *checkstr = NULL;
+ char t[ISO_TIME_LEN+1];
+ int len = (67+MAX_HIST_VALUE_LEN)*4;
+ checkstr = tor_malloc_zero(len);
+ time_t now = time(NULL);
+ bwhist_init();
+
+ /* Day 1. */
+ now += 86400;
+ set_test_bw_lines(5000, 5500, 3000, 3500, now - 6*60*60);
+ /* Day 2. */
+ now += 86400;
+ set_test_bw_lines(50000, 55000, 30000, 35000, now - 6*60*60);
+ /* Day 3. */
+ now += 86400;
+ set_test_bw_lines(25000, 27500, 15000, 17500, now - 6*60*60);
+ /* Day 4. */
+ now += 86400;
+ set_test_bw_lines(90000, 76000, 60000, 45000, now - 6*60*60);
+ /* Day 5. */
+ now += 86400;
+ set_test_bw_lines(500, 55000, 30000, 35000, now - 6*60*60);
+ set_test_bw_lines(0, 0, 0, 0, now);
+ format_iso_time(t, now);
+ tor_snprintf(checkstr, len, "write-history %s (86400 s) "
+ "5120,54272,26624,75776,54272\n"
+ "read-history %s (86400 s) "
+ "4096,49152,24576,89088,0\n"
+ "dirreq-write-history %s (86400 s) "
+ "3072,34816,17408,44032,34816\n"
+ "dirreq-read-history %s (86400 s) "
+ "2048,29696,14336,59392,29696\n",
+ t, t, t, t);
+ test_get_bw_lines(str, checkstr);
+
+ done:
+ tor_free(str);
+ tor_free(checkstr);
+ bwhist_free_all();
+}
+
#define ENT(name) \
{ #name, test_ ## name , 0, NULL, NULL }
#define FORK(name) \
@@ -253,6 +501,11 @@ test_rephist_mtbf(void *arg)
struct testcase_t stats_tests[] = {
FORK(stats),
ENT(rephist_mtbf),
+ FORK(commit_max),
+ FORK(advance_obs),
+ FORK(add_obs),
+ FORK(fill_bandwidth_history),
+ FORK(get_bandwidth_lines),
END_OF_TESTCASES
};
diff --git a/src/test/test_status.c b/src/test/test_status.c
index 82afe0fd2a..b938b86326 100644
--- a/src/test/test_status.c
+++ b/src/test/test_status.c
@@ -26,6 +26,7 @@
#include "feature/nodelist/nodelist.h"
#include "app/config/statefile.h"
#include "lib/tls/tortls.h"
+#include "test/log_test_helpers.h"
#include "core/or/origin_circuit_st.h"
#include "app/config/or_state_st.h"
@@ -308,10 +309,6 @@ static int status_hb_not_in_consensus_public_server_mode(
static const routerinfo_t *status_hb_not_in_consensus_get_my_routerinfo(void);
static const node_t * status_hb_not_in_consensus_node_get_by_id(
const char *identity_digest);
-static void status_hb_not_in_consensus_logv(
- int severity, log_domain_mask_t domain, const char *funcname,
- const char *suffix, const char *format, va_list ap);
-static int status_hb_not_in_consensus_logv_called = 0;
static int status_hb_not_in_consensus_server_mode(const or_options_t *options);
static routerinfo_t *mock_routerinfo;
@@ -332,8 +329,6 @@ test_status_hb_not_in_consensus(void *arg)
status_hb_not_in_consensus_get_my_routerinfo);
MOCK(node_get_by_id,
status_hb_not_in_consensus_node_get_by_id);
- MOCK(logv,
- status_hb_not_in_consensus_logv);
MOCK(server_mode,
status_hb_not_in_consensus_server_mode);
@@ -344,18 +339,38 @@ test_status_hb_not_in_consensus(void *arg)
onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR] = 1;
expected = 0;
+ setup_capture_of_logs(LOG_INFO);
actual = log_heartbeat(0);
-
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(status_hb_not_in_consensus_logv_called, OP_EQ, 6);
- done:
+ expect_log_msg("Heartbeat: It seems like we are "
+ "not in the cached consensus.\n");
+ expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, "
+ "with 0 circuits open. "
+ "I've sent 0 kB and received 0 kB. "
+ "I've received 0 connections on IPv4 and 0 on IPv6. "
+ "I've made 0 connections with IPv4 and 0 with IPv6.\n");
+ expect_log_msg("Average packaged cell fullness: 100.000%. "
+ "TLS write overhead: 0%\n");
+ expect_log_msg("Circuit handshake stats since last time: 1/1 TAP, "
+ "1/1 NTor.\n");
+ expect_log_msg("Since startup we initiated 0 and received 0 v1 "
+ "connections; initiated 0 and received 0 v2 connections; "
+ "initiated 0 and received 0 v3 connections; "
+ "initiated 0 and received 0 v4 connections; "
+ "initiated 0 and received 0 v5 connections.\n");
+ expect_log_msg("DoS mitigation since startup: 0 circuits killed with "
+ "too many cells. [cc not enabled] [conn not enabled] "
+ "0 INTRODUCE2 rejected.\n");
+ tt_int_op(mock_saved_log_n_entries(), OP_EQ, 6);
+
+ done:
+ teardown_capture_of_logs();
UNMOCK(tls_get_write_overhead_ratio);
UNMOCK(we_are_hibernating);
UNMOCK(public_server_mode);
UNMOCK(router_get_my_routerinfo);
UNMOCK(node_get_by_id);
- UNMOCK(logv);
UNMOCK(server_mode);
tor_free(mock_routerinfo);
}
@@ -396,76 +411,6 @@ status_hb_not_in_consensus_node_get_by_id(const char *identity_digest)
return NULL;
}
-static void
-status_hb_not_in_consensus_logv(int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap)
-{
- switch (status_hb_not_in_consensus_logv_called)
- {
- case 0:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: It seems like we are not in the cached consensus.");
- break;
- case 1:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: Tor's uptime is %s, with %d circuits open. "
- "I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */
- break;
- case 2:
- tt_int_op(severity, OP_EQ, LOG_INFO);
- break;
- case 3:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "rep_hist_log_circuit_handshake_stats"),
- OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Circuit handshake stats since last time: %d/%d TAP, %d/%d NTor.");
- tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes assigned (TAP) */
- tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes requested (TAP) */
- tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes assigned (NTOR) */
- tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes requested (NTOR) */
- break;
- case 4:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "rep_hist_log_link_protocol_counts"),
- OP_NE, NULL);
- break;
- case 5:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_str_op(format, OP_EQ, "DoS mitigation since startup:%s%s%s%s%s");
- tt_str_op(va_arg(ap, char *), OP_EQ,
- " 0 circuits killed with too many cells.");
- tt_str_op(va_arg(ap, char *), OP_EQ, " [cc not enabled]");
- tt_str_op(va_arg(ap, char *), OP_EQ, " [conn not enabled]");
- tt_str_op(va_arg(ap, char *), OP_EQ, "");
- tt_str_op(va_arg(ap, char *), OP_EQ, " 0 INTRODUCE2 rejected.");
- break;
- default:
- tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
- break;
- }
-
- done:
- status_hb_not_in_consensus_logv_called++;
-}
-
static int
status_hb_not_in_consensus_server_mode(const or_options_t *options)
{
@@ -485,14 +430,8 @@ static int status_hb_simple_public_server_mode(const or_options_t *options);
static long status_hb_simple_get_uptime(void);
static uint64_t status_hb_simple_get_bytes_read(void);
static uint64_t status_hb_simple_get_bytes_written(void);
-static void status_hb_simple_logv(int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix,
- const char *format, va_list ap);
-ATTR_UNUSED static int status_hb_simple_logv_called = 0;
static int status_hb_simple_server_mode(const or_options_t *options);
-static int status_hb_simple_n_msgs = 0;
-
static void
test_status_hb_simple(void *arg)
{
@@ -511,27 +450,32 @@ test_status_hb_simple(void *arg)
status_hb_simple_get_bytes_read);
MOCK(get_bytes_written,
status_hb_simple_get_bytes_written);
- MOCK(logv,
- status_hb_simple_logv);
MOCK(server_mode,
status_hb_simple_server_mode);
log_global_min_severity_ = LOG_DEBUG;
+ setup_capture_of_logs(LOG_INFO);
expected = 0;
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(status_hb_simple_n_msgs, OP_EQ, 1);
+
+ expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, "
+ "with 0 circuits open. "
+ "I've sent 0 kB and received 0 kB. "
+ "I've received 0 connections on IPv4 and 0 on IPv6. "
+ "I've made 0 connections with IPv4 and 0 with IPv6. "
+ "We are currently hibernating.\n");
done:
+ teardown_capture_of_logs();
UNMOCK(tls_get_write_overhead_ratio);
UNMOCK(we_are_hibernating);
UNMOCK(public_server_mode);
UNMOCK(get_uptime);
UNMOCK(get_bytes_read);
UNMOCK(get_bytes_written);
- UNMOCK(logv);
UNMOCK(server_mode);
}
@@ -573,32 +517,6 @@ status_hb_simple_get_bytes_written(void)
return 0;
}
-static void
-status_hb_simple_logv(int severity, log_domain_mask_t domain,
- const char *funcname,
- const char *suffix, const char *format, va_list ap)
-{
- if (severity == LOG_INFO)
- return;
- ++status_hb_simple_n_msgs;
-
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: Tor's uptime is %s, with %d circuits open. "
- "I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), OP_EQ, " We are currently hibernating.");
-
- done:
- ;
-}
-
static int
status_hb_simple_server_mode(const or_options_t *options)
{
@@ -620,11 +538,6 @@ static int status_hb_calls_log_accounting_public_server_mode(
static long status_hb_calls_log_accounting_get_uptime(void);
static uint64_t status_hb_calls_log_accounting_get_bytes_read(void);
static uint64_t status_hb_calls_log_accounting_get_bytes_written(void);
-static void status_hb_calls_log_accounting_logv(
- int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix,
- const char *format, va_list ap);
-static int status_hb_calls_log_accounting_logv_called = 0;
static int status_hb_calls_log_accounting_server_mode(
const or_options_t *options);
static or_state_t * status_hb_calls_log_accounting_get_or_state(void);
@@ -653,8 +566,6 @@ test_status_hb_calls_log_accounting(void *arg)
status_hb_calls_log_accounting_get_bytes_read);
MOCK(get_bytes_written,
status_hb_calls_log_accounting_get_bytes_written);
- MOCK(logv,
- status_hb_calls_log_accounting_logv);
MOCK(server_mode,
status_hb_calls_log_accounting_server_mode);
MOCK(get_or_state,
@@ -666,20 +577,31 @@ test_status_hb_calls_log_accounting(void *arg)
log_global_min_severity_ = LOG_DEBUG;
+ setup_capture_of_logs(LOG_NOTICE);
expected = 0;
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(status_hb_calls_log_accounting_logv_called, OP_EQ, 3);
+
+ expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, "
+ "with 0 circuits open. "
+ "I've sent 0 kB and received 0 kB. "
+ "I've received 0 connections on IPv4 and 0 on IPv6. "
+ "I've made 0 connections with IPv4 and 0 with IPv6.\n");
+
+ expect_log_msg_containing("Heartbeat: Accounting enabled. Sent: 0 kB, "
+ "Received: 0 kB, Used: 0 kB / 0 kB, Rule: max. "
+ "The current accounting interval ends on ");
+ tt_int_op(mock_saved_log_n_entries(), OP_EQ, 2);
done:
+ teardown_capture_of_logs();
UNMOCK(tls_get_write_overhead_ratio);
UNMOCK(we_are_hibernating);
UNMOCK(public_server_mode);
UNMOCK(get_uptime);
UNMOCK(get_bytes_read);
UNMOCK(get_bytes_written);
- UNMOCK(logv);
UNMOCK(server_mode);
UNMOCK(accounting_is_enabled);
UNMOCK(accounting_get_end_time);
@@ -725,58 +647,6 @@ status_hb_calls_log_accounting_get_bytes_written(void)
return 0;
}
-static void
-status_hb_calls_log_accounting_logv(int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap)
-{
- switch (status_hb_calls_log_accounting_logv_called)
- {
- case 0:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: Tor's uptime is %s, with %d circuits open. "
- "I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */
- break;
- case 1:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_accounting"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: Accounting enabled. Sent: %s, Received: %s, Used: %s / "
- "%s, Rule: %s. The current accounting interval ends on %s, in %s.");
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_sent */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_rcvd */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_used */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_max */
- tt_str_op(va_arg(ap, char *), OP_EQ, "max"); /* acc_rule */
- /* format_local_iso_time uses local tz, so we can't just compare
- * the string against a constant */
- char datetime[ISO_TIME_LEN+1];
- format_local_iso_time(datetime, 60);
- tt_str_op(va_arg(ap, char *), OP_EQ, datetime); /* end_buf */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0:01 hours"); /* remaining */
- break;
- case 2:
- tt_int_op(severity, OP_EQ, LOG_INFO);
- break;
- default:
- tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
- break;
- }
-
- done:
- status_hb_calls_log_accounting_logv_called++;
-}
-
static int
status_hb_calls_log_accounting_server_mode(const or_options_t *options)
{
@@ -826,11 +696,6 @@ static int status_hb_packaged_cell_fullness_public_server_mode(
static long status_hb_packaged_cell_fullness_get_uptime(void);
static uint64_t status_hb_packaged_cell_fullness_get_bytes_read(void);
static uint64_t status_hb_packaged_cell_fullness_get_bytes_written(void);
-static void status_hb_packaged_cell_fullness_logv(
- int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix,
- const char *format, va_list ap);
-static int status_hb_packaged_cell_fullness_logv_called = 0;
static int status_hb_packaged_cell_fullness_server_mode(
const or_options_t *options);
static int status_hb_packaged_cell_fullness_accounting_is_enabled(
@@ -854,8 +719,6 @@ test_status_hb_packaged_cell_fullness(void *arg)
status_hb_packaged_cell_fullness_get_bytes_read);
MOCK(get_bytes_written,
status_hb_packaged_cell_fullness_get_bytes_written);
- MOCK(logv,
- status_hb_packaged_cell_fullness_logv);
MOCK(server_mode,
status_hb_packaged_cell_fullness_server_mode);
MOCK(accounting_is_enabled,
@@ -865,12 +728,20 @@ test_status_hb_packaged_cell_fullness(void *arg)
stats_n_data_bytes_packaged = RELAY_PAYLOAD_SIZE;
stats_n_data_cells_packaged = 2;
expected = 0;
+ setup_capture_of_logs(LOG_INFO);
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(status_hb_packaged_cell_fullness_logv_called, OP_EQ, 2);
+ expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, "
+ "with 0 circuits open. "
+ "I've sent 0 kB and received 0 kB. "
+ "I've received 0 connections on IPv4 and 0 on IPv6. "
+ "I've made 0 connections with IPv4 and 0 with IPv6.\n");
+ expect_log_msg("Average packaged cell fullness: 50.000%. "
+ "TLS write overhead: 0%\n");
done:
+ teardown_capture_of_logs();
stats_n_data_bytes_packaged = 0;
stats_n_data_cells_packaged = 0;
UNMOCK(tls_get_write_overhead_ratio);
@@ -879,7 +750,6 @@ test_status_hb_packaged_cell_fullness(void *arg)
UNMOCK(get_uptime);
UNMOCK(get_bytes_read);
UNMOCK(get_bytes_written);
- UNMOCK(logv);
UNMOCK(server_mode);
UNMOCK(accounting_is_enabled);
}
@@ -923,47 +793,6 @@ status_hb_packaged_cell_fullness_get_bytes_written(void)
return 0;
}
-static void
-status_hb_packaged_cell_fullness_logv(int severity,
- log_domain_mask_t domain, const char *funcname,
- const char *suffix, const char *format, va_list ap)
-{
- switch (status_hb_packaged_cell_fullness_logv_called)
- {
- case 0:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: Tor's uptime is %s, with %d circuits open. "
- "I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */
- break;
- case 1:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Average packaged cell fullness: %2.3f%%. "
- "TLS write overhead: %.f%%");
- tt_double_op(fabs(va_arg(ap, double) - 50.0), OP_LE, DBL_EPSILON);
- tt_double_op(fabs(va_arg(ap, double) - 0.0), OP_LE, DBL_EPSILON);
- break;
- default:
- tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
- break;
- }
-
- done:
- status_hb_packaged_cell_fullness_logv_called++;
-}
-
static int
status_hb_packaged_cell_fullness_server_mode(const or_options_t *options)
{
@@ -993,11 +822,6 @@ static int status_hb_tls_write_overhead_public_server_mode(
static long status_hb_tls_write_overhead_get_uptime(void);
static uint64_t status_hb_tls_write_overhead_get_bytes_read(void);
static uint64_t status_hb_tls_write_overhead_get_bytes_written(void);
-static void status_hb_tls_write_overhead_logv(
- int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix,
- const char *format, va_list ap);
-static int status_hb_tls_write_overhead_logv_called = 0;
static int status_hb_tls_write_overhead_server_mode(
const or_options_t *options);
static int status_hb_tls_write_overhead_accounting_is_enabled(
@@ -1021,8 +845,6 @@ test_status_hb_tls_write_overhead(void *arg)
status_hb_tls_write_overhead_get_bytes_read);
MOCK(get_bytes_written,
status_hb_tls_write_overhead_get_bytes_written);
- MOCK(logv,
- status_hb_tls_write_overhead_logv);
MOCK(server_mode,
status_hb_tls_write_overhead_server_mode);
MOCK(accounting_is_enabled,
@@ -1031,19 +853,26 @@ test_status_hb_tls_write_overhead(void *arg)
log_global_min_severity_ = LOG_DEBUG;
expected = 0;
+ setup_capture_of_logs(LOG_NOTICE);
actual = log_heartbeat(0);
tt_int_op(actual, OP_EQ, expected);
- tt_int_op(status_hb_tls_write_overhead_logv_called, OP_EQ, 2);
+ expect_log_msg("Heartbeat: Tor's uptime is 0:00 hours, "
+ "with 0 circuits open. "
+ "I've sent 0 kB and received 0 kB. "
+ "I've received 0 connections on IPv4 and 0 on IPv6. "
+ "I've made 0 connections with IPv4 and 0 with IPv6.\n");
+ expect_log_msg("Average packaged cell fullness: 100.000%. "
+ "TLS write overhead: 100%\n");
done:
+ teardown_capture_of_logs();
UNMOCK(tls_get_write_overhead_ratio);
UNMOCK(we_are_hibernating);
UNMOCK(public_server_mode);
UNMOCK(get_uptime);
UNMOCK(get_bytes_read);
UNMOCK(get_bytes_written);
- UNMOCK(logv);
UNMOCK(server_mode);
UNMOCK(accounting_is_enabled);
}
@@ -1086,46 +915,6 @@ status_hb_tls_write_overhead_get_bytes_written(void)
return 0;
}
-static void
-status_hb_tls_write_overhead_logv(int severity, log_domain_mask_t domain,
- const char *funcname, const char *suffix, const char *format, va_list ap)
-{
- switch (status_hb_tls_write_overhead_logv_called)
- {
- case 0:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Heartbeat: Tor's uptime is %s, with %d circuits open. "
- "I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */
- break;
- case 1:
- tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
- tt_ptr_op(suffix, OP_EQ, NULL);
- tt_str_op(format, OP_EQ,
- "Average packaged cell fullness: %2.3f%%. "
- "TLS write overhead: %.f%%");
- tt_int_op(fabs(va_arg(ap, double) - 100.0) <= DBL_EPSILON, OP_EQ, 1);
- tt_double_op(fabs(va_arg(ap, double) - 100.0), OP_LE, DBL_EPSILON);
- break;
- default:
- tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
- break;
- }
-
- done:
- status_hb_tls_write_overhead_logv_called++;
-}
-
static int
status_hb_tls_write_overhead_server_mode(const or_options_t *options)
{
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 7700cfa2b1..1c555e4d06 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -18,6 +18,7 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/defs/time.h"
#include "test/test.h"
+#include "test/test_helpers.h"
#include "lib/memarea/memarea.h"
#include "lib/process/waitpid.h"
#include "lib/process/process_win32.h"
@@ -77,6 +78,8 @@
#define DISABLE_PWDB_TESTS
#endif
+static void set_file_mtime(const char *fname, time_t when);
+
#define INFINITY_DBL ((double)INFINITY)
#define NAN_DBL ((double)NAN)
@@ -206,6 +209,54 @@ test_util_read_file_eof_zero_bytes(void *arg)
test_util_read_until_eof_impl("tor_test_fifo_empty", 0, 10000);
}
+static void
+test_util_read_file_endlines(void *arg)
+{
+ (void)arg;
+
+ char *fname = NULL;
+ char *read_content = NULL;
+ int r = -1;
+
+ /* Write a file that contains both \n and \r\n as line ending. */
+ const char *file_content = "foo bar\n"
+ "foo bar baz\r\n"
+ "foo bar\r\n";
+
+ const char *expected_file_content = "foo bar\n"
+ "foo bar baz\n"
+ "foo bar\n";
+
+ fname = tor_strdup(get_fname("file_with_crlf_ending"));
+
+ r = write_bytes_to_file(fname, file_content, strlen(file_content), 1);
+ tt_int_op(r, OP_EQ, 0);
+
+ /* Read the file in text mode: we strip \r's from the files on both Windows
+ * and UNIX. */
+ read_content = read_file_to_str(fname, 0, NULL);
+
+ tt_ptr_op(read_content, OP_NE, NULL);
+ tt_int_op(strlen(read_content), OP_EQ, strlen(expected_file_content));
+ tt_str_op(read_content, OP_EQ, expected_file_content);
+
+ tor_free(read_content);
+
+ /* Read the file in binary mode: we should preserve the \r here. */
+ read_content = read_file_to_str(fname, RFTS_BIN, NULL);
+
+ tt_ptr_op(read_content, OP_NE, NULL);
+ tt_int_op(strlen(read_content), OP_EQ, strlen(file_content));
+ tt_str_op(read_content, OP_EQ, file_content);
+
+ tor_free(read_content);
+
+ done:
+ unlink(fname);
+ tor_free(fname);
+ tor_free(read_content);
+}
+
/* Test the basic expected behaviour for write_chunks_to_file.
* NOTE: This will need to be updated if we ever change the tempfile location
* or extension */
@@ -307,6 +358,55 @@ test_util_write_chunks_to_file(void *arg)
tor_free(temp_str);
}
+/* Test write_str_to_file_if_not_equal(). */
+static void
+test_util_write_str_if_changed(void *arg)
+{
+ (void)arg;
+ char *fname = tor_strdup(get_fname("write_if_changed"));
+ char *s = NULL;
+ int rv;
+ const char str1[] = "The wombat lives across the seas";
+ const char str2[] = "Among the far Antipodes"; /* -- Ogden Nash */
+
+ /* We can create files. */
+ rv = write_str_to_file_if_not_equal(fname, str1);
+ tt_int_op(rv, OP_EQ, 0);
+ s = read_file_to_str(fname, 0, NULL);
+ tt_str_op(s, OP_EQ, str1);
+ tor_free(s);
+
+ /* We can replace files. */
+ rv = write_str_to_file_if_not_equal(fname, str2);
+ tt_int_op(rv, OP_EQ, 0);
+ s = read_file_to_str(fname, 0, NULL);
+ tt_str_op(s, OP_EQ, str2);
+ tor_free(s);
+
+ /* Make sure we don't replace files when they're equal. (That's the whole
+ * point of the function we're testing. */
+ /* First, change the mtime of the file so that we can tell whether we
+ * replaced it. */
+ const time_t now = time(NULL);
+ const time_t five_sec_ago = now - 5;
+ set_file_mtime(fname, five_sec_ago);
+ rv = write_str_to_file_if_not_equal(fname, str2);
+ tt_int_op(rv, OP_EQ, 0);
+ /* Make sure that the file's mtime is unchanged... */
+ struct stat st;
+ rv = stat(fname, &st);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_i64_op(st.st_mtime, OP_EQ, five_sec_ago);
+ /* And make sure its contents are unchanged. */
+ s = read_file_to_str(fname, 0, NULL);
+ tt_str_op(s, OP_EQ, str2);
+ tor_free(s);
+
+ done:
+ tor_free(fname);
+ tor_free(s);
+}
+
#ifndef COCCI
#define _TFE(a, b, f) tt_int_op((a).f, OP_EQ, (b).f)
/** test the minimum set of struct tm fields needed for a unique epoch value
@@ -4085,6 +4185,31 @@ test_util_find_str_at_start_of_line(void *ptr)
}
static void
+test_util_tor_strreplacechar(void *ptr)
+{
+ (void)ptr;
+ char empty[] = "";
+ char not_contain[] = "bbb";
+ char contains[] = "bab";
+ char contains_all[] = "aaa";
+
+ tor_strreplacechar(empty, 'a', 'b');
+ tt_str_op(empty, OP_EQ, "");
+
+ tor_strreplacechar(not_contain, 'a', 'b');
+ tt_str_op(not_contain, OP_EQ, "bbb");
+
+ tor_strreplacechar(contains, 'a', 'b');
+ tt_str_op(contains, OP_EQ, "bbb");
+
+ tor_strreplacechar(contains_all, 'a', 'b');
+ tt_str_op(contains_all, OP_EQ, "bbb");
+
+ done:
+ ;
+}
+
+static void
test_util_string_is_C_identifier(void *ptr)
{
(void)ptr;
@@ -4311,6 +4436,438 @@ test_util_listdir(void *ptr)
}
static void
+test_util_glob(void *ptr)
+{
+ (void)ptr;
+
+#ifdef HAVE_GLOB
+ smartlist_t *results = NULL;
+ int r, i;
+ char *dir1 = NULL, *dir2 = NULL, *forbidden = NULL, *dirname = NULL;
+ char *expected = NULL, *pattern = NULL;
+ // used for cleanup
+ char *dir1_forbidden = NULL, *dir2_forbidden = NULL;
+ char *forbidden_forbidden = NULL;
+
+ dirname = tor_strdup(get_fname("test_glob"));
+ tt_ptr_op(dirname, OP_NE, NULL);
+
+#ifdef _WIN32
+ r = mkdir(dirname);
+#else
+ r = mkdir(dirname, 0700);
+#endif
+ if (r) {
+ fprintf(stderr, "Can't create directory %s:", dirname);
+ perror("");
+ exit(1);
+ }
+
+ tt_int_op(0, OP_EQ, create_test_directory_structure(dirname));
+ tor_asprintf(&dir1, "%s"PATH_SEPARATOR"dir1", dirname);
+ tor_asprintf(&dir1_forbidden,
+ "%s"PATH_SEPARATOR"dir1"PATH_SEPARATOR"forbidden", dirname);
+ tt_int_op(0, OP_EQ, create_test_directory_structure(dir1));
+ tor_asprintf(&dir2, "%s"PATH_SEPARATOR"dir2", dirname);
+ tor_asprintf(&dir2_forbidden,
+ "%s"PATH_SEPARATOR"dir2"PATH_SEPARATOR"forbidden", dirname);
+ tt_int_op(0, OP_EQ, create_test_directory_structure(dir2));
+ tor_asprintf(&forbidden, "%s"PATH_SEPARATOR"forbidden", dirname);
+ tor_asprintf(&forbidden_forbidden,
+ "%s"PATH_SEPARATOR"forbidden"PATH_SEPARATOR"forbidden",dirname);
+#ifndef _WIN32
+ tt_int_op(0, OP_EQ, chmod(forbidden, 0700));
+#endif
+ tt_int_op(0, OP_EQ, create_test_directory_structure(forbidden));
+#ifndef _WIN32
+ tt_int_op(0, OP_EQ, chmod(forbidden, 0));
+#endif
+
+#define TEST(input) \
+ do { \
+ tor_asprintf(&pattern, "%s"PATH_SEPARATOR"%s", dirname, input); \
+ results = tor_glob(pattern); \
+ tor_free(pattern); \
+ tt_assert(results); \
+ smartlist_sort_strings(results); \
+ } while (0);
+
+#define EXPECT(result) \
+ do { \
+ tt_int_op(smartlist_len(results), OP_EQ, \
+ sizeof(result)/sizeof(*result)); \
+ i = 0; \
+ SMARTLIST_FOREACH_BEGIN(results, const char *, f) { \
+ tor_asprintf(&expected, "%s"PATH_SEPARATOR"%s", dirname, result[i]); \
+ tt_str_op(f, OP_EQ, expected); \
+ i++; \
+ tor_free(expected); \
+ } SMARTLIST_FOREACH_END(f); \
+ SMARTLIST_FOREACH(results, char *, f, tor_free(f)); \
+ smartlist_free(results); \
+ } while (0);
+
+#define EXPECT_EMPTY() \
+ do { \
+ tt_int_op(smartlist_len(results), OP_EQ, 0); \
+ SMARTLIST_FOREACH(results, char *, f, tor_free(f)); \
+ smartlist_free(results); \
+ } while (0);
+
+ // wilcards at beginning
+ const char *results_test1[] = {"dir2", "file2"};
+ TEST("*2");
+ EXPECT(results_test1);
+
+ // wildcards at end
+ const char *results_test2[] = {"dir1", "dir2"};
+ TEST("d*");
+ EXPECT(results_test2);
+
+ // wildcards at beginning and end
+#ifdef _WIN32
+ // dot files are not ignored on Windows
+ const char *results_test3[] = {".test-hidden", "dir1", "dir2", "file1",
+ "file2", "forbidden"};
+#else
+ const char *results_test3[] = {"dir1", "dir2", "file1", "file2",
+ "forbidden"};
+#endif
+ TEST("*i*");
+ EXPECT(results_test3);
+
+ // wildcards in middle
+ const char *results_test4[] = {"dir1", "dir2"};
+ TEST("d?r*");
+ EXPECT(results_test4);
+
+ // test file that does not exist
+ TEST("not-exist");
+ EXPECT_EMPTY();
+
+ // test wildcard that matches nothing
+ TEST("*not-exist*");
+ EXPECT_EMPTY();
+
+ // test path separator at end - no wildcards
+ const char *results_test7[] = {"dir1"};
+ TEST("dir1");
+ EXPECT(results_test7);
+
+ const char *results_test8[] = {"dir1"};
+ TEST("dir1"PATH_SEPARATOR);
+ EXPECT(results_test8);
+
+ const char *results_test9[] = {"file1"};
+ TEST("file1");
+ EXPECT(results_test9);
+
+#if defined(__APPLE__) || defined(__darwin__) || \
+ defined(__FreeBSD__) || defined(__NetBSD__) || defined(OpenBSD)
+ TEST("file1"PATH_SEPARATOR);
+ EXPECT_EMPTY();
+#else
+ const char *results_test10[] = {"file1"};
+ TEST("file1"PATH_SEPARATOR);
+ EXPECT(results_test10);
+#endif
+
+ // test path separator at end - with wildcards and linux path separator
+ const char *results_test11[] = {"dir1", "dir2", "forbidden"};
+ TEST("*/");
+ EXPECT(results_test11);
+
+#ifdef _WIN32
+ // dot files are not ignored on Windows
+ const char *results_test12[] = {".test-hidden", "dir1", "dir2", "empty",
+ "file1", "file2", "forbidden"};
+#else
+ const char *results_test12[] = {"dir1", "dir2", "empty", "file1", "file2",
+ "forbidden"};
+#endif
+ TEST("*");
+ EXPECT(results_test12);
+
+ // wildcards on folder and file and linux path separator
+ const char *results_test13[] = {"dir1"PATH_SEPARATOR"dir1",
+ "dir1"PATH_SEPARATOR"dir2",
+ "dir1"PATH_SEPARATOR"file1",
+ "dir1"PATH_SEPARATOR"file2",
+ "dir2"PATH_SEPARATOR"dir1",
+ "dir2"PATH_SEPARATOR"dir2",
+ "dir2"PATH_SEPARATOR"file1",
+ "dir2"PATH_SEPARATOR"file2"};
+ TEST("?i*/?i*");
+ EXPECT(results_test13);
+
+ // wildcards on file only
+ const char *results_test14[] = {"dir1"PATH_SEPARATOR"dir1",
+ "dir1"PATH_SEPARATOR"dir2",
+ "dir1"PATH_SEPARATOR"file1",
+ "dir1"PATH_SEPARATOR"file2"};
+ TEST("dir1"PATH_SEPARATOR"?i*");
+ EXPECT(results_test14);
+
+ // wildcards on folder only
+ const char *results_test15[] = {"dir1"PATH_SEPARATOR"file1",
+ "dir2"PATH_SEPARATOR"file1"};
+ TEST("?i*"PATH_SEPARATOR"file1");
+ EXPECT(results_test15);
+
+ // wildcards after file name
+ TEST("file1"PATH_SEPARATOR"*");
+ EXPECT_EMPTY();
+
+#ifndef _WIN32
+ // test wildcard escaping
+ TEST("\\*");
+ EXPECT_EMPTY();
+
+ if (getuid() != 0) {
+ // test forbidden directory, if we're not root.
+ // (Root will be able to see this directory anyway.)
+ tor_asprintf(&pattern, "%s"PATH_SEPARATOR"*"PATH_SEPARATOR"*", dirname);
+ results = tor_glob(pattern);
+ tor_free(pattern);
+ tt_assert(!results);
+ }
+#endif
+
+#undef TEST
+#undef EXPECT
+#undef EXPECT_EMPTY
+
+ done:
+#ifndef _WIN32
+ (void) chmod(forbidden, 0700);
+ (void) chmod(dir1_forbidden, 0700);
+ (void) chmod(dir2_forbidden, 0700);
+ (void) chmod(forbidden_forbidden, 0700);
+#endif
+ tor_free(dir1);
+ tor_free(dir2);
+ tor_free(forbidden);
+ tor_free(dirname);
+ tor_free(dir1_forbidden);
+ tor_free(dir2_forbidden);
+ tor_free(forbidden_forbidden);
+ tor_free(expected);
+ tor_free(pattern);
+ if (results) {
+ SMARTLIST_FOREACH(results, char *, f, tor_free(f));
+ smartlist_free(results);
+ }
+#else
+ tt_skip();
+ done:
+ return;
+#endif
+}
+
+static void
+test_util_get_glob_opened_files(void *ptr)
+{
+ (void)ptr;
+
+#ifdef HAVE_GLOB
+ smartlist_t *results = NULL;
+ int r, i;
+ char *dir1 = NULL, *dir2 = NULL, *forbidden = NULL, *dirname = NULL;
+ char *expected = NULL, *pattern = NULL;
+ // used for cleanup
+ char *dir1_forbidden = NULL, *dir2_forbidden = NULL;
+ char *forbidden_forbidden = NULL;
+
+ dirname = tor_strdup(get_fname("test_get_glob_opened_files"));
+ tt_ptr_op(dirname, OP_NE, NULL);
+
+#ifdef _WIN32
+ r = mkdir(dirname);
+#else
+ r = mkdir(dirname, 0700);
+#endif
+ if (r) {
+ fprintf(stderr, "Can't create directory %s:", dirname);
+ perror("");
+ exit(1);
+ }
+
+ tt_int_op(0, OP_EQ, create_test_directory_structure(dirname));
+ tor_asprintf(&dir1, "%s"PATH_SEPARATOR"dir1", dirname);
+ tor_asprintf(&dir1_forbidden,
+ "%s"PATH_SEPARATOR"dir1"PATH_SEPARATOR"forbidden", dirname);
+ tt_int_op(0, OP_EQ, create_test_directory_structure(dir1));
+ tor_asprintf(&dir2, "%s"PATH_SEPARATOR"dir2", dirname);
+ tor_asprintf(&dir2_forbidden,
+ "%s"PATH_SEPARATOR"dir2"PATH_SEPARATOR"forbidden", dirname);
+ tt_int_op(0, OP_EQ, create_test_directory_structure(dir2));
+ tor_asprintf(&forbidden, "%s"PATH_SEPARATOR"forbidden", dirname);
+ tor_asprintf(&forbidden_forbidden,
+ "%s"PATH_SEPARATOR"forbidden"PATH_SEPARATOR"forbidden",dirname);
+#ifndef _WIN32
+ chmod(forbidden, 0700);
+#endif
+ tt_int_op(0, OP_EQ, create_test_directory_structure(forbidden));
+#ifndef _WIN32
+ chmod(forbidden, 0);
+#endif
+
+#define TEST(input) \
+ do { \
+ if (*input) { \
+ tor_asprintf(&pattern, "%s"PATH_SEPARATOR"%s", dirname, input); \
+ } else { /* do not add path separator if empty string */ \
+ tor_asprintf(&pattern, "%s", dirname); \
+ } \
+ results = get_glob_opened_files(pattern); \
+ tor_free(pattern); \
+ tt_assert(results); \
+ smartlist_sort_strings(results); \
+ } while (0);
+
+#define EXPECT(result) \
+ do { \
+ tt_int_op(smartlist_len(results), OP_EQ, \
+ sizeof(result)/sizeof(*result)); \
+ i = 0; \
+ SMARTLIST_FOREACH_BEGIN(results, const char *, f) { \
+ if (*result[i]) { \
+ tor_asprintf(&expected, "%s"PATH_SEPARATOR"%s", dirname, result[i]); \
+ } else { /* do not add path separator if empty string */ \
+ tor_asprintf(&expected, "%s", dirname); \
+ } \
+ tt_str_op(f, OP_EQ, expected); \
+ i++; \
+ tor_free(expected); \
+ } SMARTLIST_FOREACH_END(f); \
+ SMARTLIST_FOREACH(results, char *, f, tor_free(f)); \
+ smartlist_free(results); \
+ } while (0);
+
+#define EXPECT_EMPTY() \
+ do { \
+ tt_int_op(smartlist_len(results), OP_EQ, 0); \
+ SMARTLIST_FOREACH(results, char *, f, tor_free(f)); \
+ smartlist_free(results); \
+ } while (0);
+
+ // all files on folder
+ const char *results_test1[] = {""}; // only the folder is read
+ TEST("*");
+ EXPECT(results_test1);
+
+ // same as before but ending in path separator
+ const char *results_test2[] = {""}; // only the folder is read
+ TEST("*"PATH_SEPARATOR);
+ EXPECT(results_test2);
+
+ // wilcards in multiple path components
+#ifndef _WIN32
+ const char *results_test3[] = {"", "dir1", "dir2", "empty", "file1", "file2",
+ "forbidden"};
+#else
+ // dot files are not special on windows
+ const char *results_test3[] = {"", ".test-hidden", "dir1", "dir2", "empty",
+ "file1", "file2", "forbidden"};
+#endif
+ TEST("*"PATH_SEPARATOR"*");
+ EXPECT(results_test3);
+
+ // same as before but ending in path separator
+#ifndef _WIN32
+ const char *results_test4[] = {"", "dir1", "dir2", "empty", "file1", "file2",
+ "forbidden"};
+#else
+ // dot files are not special on windows
+ const char *results_test4[] = {"", ".test-hidden", "dir1", "dir2", "empty",
+ "file1", "file2", "forbidden"};
+#endif
+ TEST("*"PATH_SEPARATOR"*"PATH_SEPARATOR);
+ EXPECT(results_test4);
+
+ // no glob - folder
+ TEST("");
+ EXPECT_EMPTY();
+
+ // same as before but ending in path separator
+ TEST(PATH_SEPARATOR);
+ EXPECT_EMPTY();
+
+ // no glob - file
+ TEST("file1");
+ EXPECT_EMPTY();
+
+ // same as before but ending in path separator and linux path separator
+ TEST("file1/");
+ EXPECT_EMPTY();
+
+ // file but with wildcard after
+ const char *results_test9[] = {"file1"};
+ TEST("file1"PATH_SEPARATOR"*");
+ EXPECT(results_test9);
+
+ // dir inside dir and linux path separator
+ TEST("dir1/dir1");
+ EXPECT_EMPTY();
+
+ // same as before but ending in path separator
+ TEST("dir1"PATH_SEPARATOR"dir1"PATH_SEPARATOR);
+ EXPECT_EMPTY();
+
+ // no glob - empty
+ TEST("empty");
+ EXPECT_EMPTY();
+
+ // same as before but ending in path separator
+ TEST("empty"PATH_SEPARATOR);
+ EXPECT_EMPTY();
+
+ // no glob - does not exist
+ TEST("not_exist");
+ EXPECT_EMPTY();
+
+#undef TEST
+#undef EXPECT
+#undef EXPECT_EMPTY
+
+ done:
+#ifndef _WIN32
+ {
+ int chmod_failed = 0;
+ if (forbidden)
+ chmod_failed |= chmod(forbidden, 0700);
+ if (dir1_forbidden)
+ chmod_failed |= chmod(dir1_forbidden, 0700);
+ if (dir2_forbidden)
+ chmod_failed |= chmod(dir2_forbidden, 0700);
+ if (forbidden_forbidden)
+ chmod_failed |= chmod(forbidden_forbidden, 0700);
+ if (chmod_failed) {
+ TT_FAIL(("unable to chmod a file on cleanup: %s", strerror(errno)));
+ }
+ }
+#endif
+ tor_free(dir1);
+ tor_free(dir2);
+ tor_free(forbidden);
+ tor_free(dirname);
+ tor_free(dir1_forbidden);
+ tor_free(dir2_forbidden);
+ tor_free(forbidden_forbidden);
+ tor_free(expected);
+ tor_free(pattern);
+ if (results) {
+ SMARTLIST_FOREACH(results, char *, f, tor_free(f));
+ smartlist_free(results);
+ }
+#else
+ tt_skip();
+ done:
+ return;
+#endif
+}
+
+static void
test_util_parent_dir(void *ptr)
{
char *cp;
@@ -5738,6 +6295,20 @@ test_util_get_avail_disk_space(void *arg)
;
}
+/** Helper: Change the atime and mtime of a file. */
+static void
+set_file_mtime(const char *fname, time_t when)
+{
+ struct utimbuf u = { when, when };
+ struct stat st;
+ tt_int_op(0, OP_EQ, utime(fname, &u));
+ tt_int_op(0, OP_EQ, stat(fname, &st));
+ /* Let's hope that utime/stat give the same second as a round-trip? */
+ tt_i64_op(st.st_mtime, OP_EQ, when);
+done:
+ ;
+}
+
static void
test_util_touch_file(void *arg)
{
@@ -5755,11 +6326,7 @@ test_util_touch_file(void *arg)
tt_i64_op(st.st_mtime, OP_GE, now - 1);
const time_t five_sec_ago = now - 5;
- struct utimbuf u = { five_sec_ago, five_sec_ago };
- tt_int_op(0, OP_EQ, utime(fname, &u));
- tt_int_op(0, OP_EQ, stat(fname, &st));
- /* Let's hope that utime/stat give the same second as a round-trip? */
- tt_i64_op(st.st_mtime, OP_EQ, five_sec_ago);
+ set_file_mtime(fname, five_sec_ago);
/* Finally we can touch the file */
tt_int_op(0, OP_EQ, touch_file(fname));
@@ -6472,10 +7039,13 @@ struct testcase_t util_tests[] = {
UTIL_TEST(laplace, 0),
UTIL_TEST(clamp_double_to_int64, 0),
UTIL_TEST(find_str_at_start_of_line, 0),
+ UTIL_TEST(tor_strreplacechar, 0),
UTIL_TEST(string_is_C_identifier, 0),
UTIL_TEST(string_is_utf8, 0),
UTIL_TEST(asprintf, 0),
UTIL_TEST(listdir, 0),
+ UTIL_TEST(glob, 0),
+ UTIL_TEST(get_glob_opened_files, 0),
UTIL_TEST(parent_dir, 0),
UTIL_TEST(ftruncate, 0),
UTIL_TEST(nowrap_math, 0),
@@ -6495,7 +7065,9 @@ struct testcase_t util_tests[] = {
UTIL_TEST(read_file_eof_two_loops, 0),
UTIL_TEST(read_file_eof_two_loops_b, 0),
UTIL_TEST(read_file_eof_zero_bytes, 0),
+ UTIL_TEST(read_file_endlines, 0),
UTIL_TEST(write_chunks_to_file, 0),
+ UTIL_TEST(write_str_if_changed, 0),
UTIL_TEST(mathlog, 0),
UTIL_TEST(fraction, 0),
UTIL_TEST(weak_random, 0),
diff --git a/src/test/test_voting_flags.c b/src/test/test_voting_flags.c
index ae89e43889..72f70b9865 100644
--- a/src/test/test_voting_flags.c
+++ b/src/test/test_voting_flags.c
@@ -42,10 +42,10 @@ setup_cfg(flag_vote_test_cfg_t *c)
c->ri.cache_info.published_on = c->now - 100;
c->expected.published_on = c->now - 100;
- c->ri.addr = 0x7f010105;
- c->expected.addr = 0x7f010105;
- c->ri.or_port = 9090;
- c->expected.or_port = 9090;
+ tor_addr_from_ipv4h(&c->ri.ipv4_addr, 0x7f010105);
+ tor_addr_from_ipv4h(&c->expected.ipv4_addr, 0x7f010105);
+ c->ri.ipv4_orport = 9090;
+ c->expected.ipv4_orport = 9090;
tor_addr_make_null(&c->ri.ipv6_addr, AF_INET6);
tor_addr_make_null(&c->expected.ipv6_addr, AF_INET6);
@@ -69,9 +69,9 @@ check_result(flag_vote_test_cfg_t *c)
// identity_digest and descriptor_digest are not set here.
- tt_uint_op(rs.addr, OP_EQ, c->expected.addr);
- tt_uint_op(rs.or_port, OP_EQ, c->expected.or_port);
- tt_uint_op(rs.dir_port, OP_EQ, c->expected.dir_port);
+ tt_assert(tor_addr_eq(&rs.ipv4_addr, &c->expected.ipv4_addr));
+ tt_uint_op(rs.ipv4_orport, OP_EQ, c->expected.ipv4_orport);
+ tt_uint_op(rs.ipv4_dirport, OP_EQ, c->expected.ipv4_dirport);
tt_assert(tor_addr_eq(&rs.ipv6_addr, &c->expected.ipv6_addr));
tt_uint_op(rs.ipv6_orport, OP_EQ, c->expected.ipv6_orport);
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index d68dfa4047..9b50de07a8 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -18,6 +18,7 @@
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/bwhist.h"
#include "feature/stats/rephist.h"
#include "lib/err/backtrace.h"
#include "test/test.h"
@@ -348,6 +349,7 @@ main(int c, const char **v)
return 1;
}
rep_hist_init();
+ bwhist_init();
setup_directory();
initialize_mainloop_events();
options_init(options);
diff --git a/src/tools/include.am b/src/tools/include.am
index 72dfe6017c..6daa27f6de 100644
--- a/src/tools/include.am
+++ b/src/tools/include.am
@@ -11,7 +11,7 @@ src_tools_tor_resolve_LDADD = \
$(TOR_UTIL_LIBS) \
$(TOR_CRYPTO_LIBS) $(TOR_LIBS_CRYPTLIB)\
$(rust_ldadd) \
- @TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@
+ @TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_USERENV@
if COVERAGE_ENABLED
src_tools_tor_cov_resolve_SOURCES = src/tools/tor-resolve.c
@@ -36,7 +36,7 @@ src_tools_tor_gencert_LDADD = \
$(TOR_UTIL_LIBS) \
$(rust_ldadd) \
@TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ $(TOR_LIBS_CRYPTLIB) \
- @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@
endif
src_tools_tor_print_ed_signing_cert_SOURCES = src/tools/tor-print-ed-signing-cert.c
@@ -46,7 +46,7 @@ src_tools_tor_print_ed_signing_cert_LDADD = \
$(TOR_CRYPTO_LIBS) \
$(TOR_UTIL_LIBS) \
@TOR_LIB_MATH@ $(TOR_LIBS_CRYPTLIB) \
- @TOR_LIB_WS32@ @TOR_LIB_USERENV@ @TOR_LIB_GDI@
+ @TOR_LIB_WS32@ @TOR_LIB_USERENV@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@
if USE_NSS
# ...
@@ -61,7 +61,7 @@ src_tools_tor_cov_gencert_LDADD = \
$(TOR_CRYPTO_TESTING_LIBS) \
$(TOR_UTIL_TESTING_LIBS) \
@TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ $(TOR_LIBS_CRYPTLIB) \
- @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_SHLWAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
endif
endif
diff --git a/src/trunnel/circpad_negotiation.c b/src/trunnel/circpad_negotiation.c
index 547818f2ec..4e3ee3d5bd 100644
--- a/src/trunnel/circpad_negotiation.c
+++ b/src/trunnel/circpad_negotiation.c
@@ -112,6 +112,17 @@ circpad_negotiate_set_echo_request(circpad_negotiate_t *inp, uint8_t val)
inp->echo_request = val;
return 0;
}
+uint32_t
+circpad_negotiate_get_machine_ctr(const circpad_negotiate_t *inp)
+{
+ return inp->machine_ctr;
+}
+int
+circpad_negotiate_set_machine_ctr(circpad_negotiate_t *inp, uint32_t val)
+{
+ inp->machine_ctr = val;
+ return 0;
+}
const char *
circpad_negotiate_check(const circpad_negotiate_t *obj)
{
@@ -148,6 +159,9 @@ circpad_negotiate_encoded_len(const circpad_negotiate_t *obj)
/* Length of u8 echo_request IN [0, 1] */
result += 1;
+
+ /* Length of u32 machine_ctr */
+ result += 4;
return result;
}
int
@@ -203,6 +217,13 @@ circpad_negotiate_encode(uint8_t *output, const size_t avail, const circpad_nego
trunnel_set_uint8(ptr, (obj->echo_request));
written += 1; ptr += 1;
+ /* Encode u32 machine_ctr */
+ trunnel_assert(written <= avail);
+ if (avail - written < 4)
+ goto truncated;
+ trunnel_set_uint32(ptr, trunnel_htonl(obj->machine_ctr));
+ written += 4; ptr += 4;
+
trunnel_assert(ptr == output + written);
#ifdef TRUNNEL_CHECK_ENCODED_LEN
@@ -263,6 +284,11 @@ circpad_negotiate_parse_into(circpad_negotiate_t *obj, const uint8_t *input, con
remaining -= 1; ptr += 1;
if (! (obj->echo_request == 0 || obj->echo_request == 1))
goto fail;
+
+ /* Parse u32 machine_ctr */
+ CHECK_REMAINING(4, truncated);
+ obj->machine_ctr = trunnel_ntohl(trunnel_get_uint32(ptr));
+ remaining -= 4; ptr += 4;
trunnel_assert(ptr + remaining == input + len_in);
return len_in - remaining;
@@ -372,6 +398,17 @@ circpad_negotiated_set_machine_type(circpad_negotiated_t *inp, uint8_t val)
inp->machine_type = val;
return 0;
}
+uint32_t
+circpad_negotiated_get_machine_ctr(const circpad_negotiated_t *inp)
+{
+ return inp->machine_ctr;
+}
+int
+circpad_negotiated_set_machine_ctr(circpad_negotiated_t *inp, uint32_t val)
+{
+ inp->machine_ctr = val;
+ return 0;
+}
const char *
circpad_negotiated_check(const circpad_negotiated_t *obj)
{
@@ -408,6 +445,9 @@ circpad_negotiated_encoded_len(const circpad_negotiated_t *obj)
/* Length of u8 machine_type */
result += 1;
+
+ /* Length of u32 machine_ctr */
+ result += 4;
return result;
}
int
@@ -463,6 +503,13 @@ circpad_negotiated_encode(uint8_t *output, const size_t avail, const circpad_neg
trunnel_set_uint8(ptr, (obj->machine_type));
written += 1; ptr += 1;
+ /* Encode u32 machine_ctr */
+ trunnel_assert(written <= avail);
+ if (avail - written < 4)
+ goto truncated;
+ trunnel_set_uint32(ptr, trunnel_htonl(obj->machine_ctr));
+ written += 4; ptr += 4;
+
trunnel_assert(ptr == output + written);
#ifdef TRUNNEL_CHECK_ENCODED_LEN
@@ -523,6 +570,11 @@ circpad_negotiated_parse_into(circpad_negotiated_t *obj, const uint8_t *input, c
CHECK_REMAINING(1, truncated);
obj->machine_type = (trunnel_get_uint8(ptr));
remaining -= 1; ptr += 1;
+
+ /* Parse u32 machine_ctr */
+ CHECK_REMAINING(4, truncated);
+ obj->machine_ctr = trunnel_ntohl(trunnel_get_uint32(ptr));
+ remaining -= 4; ptr += 4;
trunnel_assert(ptr + remaining == input + len_in);
return len_in - remaining;
diff --git a/src/trunnel/circpad_negotiation.h b/src/trunnel/circpad_negotiation.h
index ba9155019e..9004540d43 100644
--- a/src/trunnel/circpad_negotiation.h
+++ b/src/trunnel/circpad_negotiation.h
@@ -26,6 +26,7 @@ struct circpad_negotiate_st {
uint8_t machine_type;
/** If true, send a relay_drop reply.. */
uint8_t echo_request;
+ uint32_t machine_ctr;
uint8_t trunnel_error_code_;
};
#endif
@@ -42,6 +43,14 @@ struct circpad_negotiated_st {
/** Machine type is left unbounded because we can specify
* new machines in the consensus */
uint8_t machine_type;
+ /**
+ * This field is used for shutdown synchronization. It is OK if
+ * it wraps, because all we need to do is make sure the STOP
+ * command is actually for the currently active machine.
+ * For backward-compatibility, though, 0 has special meaning
+ * (it means match any machine).
+ */
+ uint32_t machine_ctr;
uint8_t trunnel_error_code_;
};
#endif
@@ -118,6 +127,15 @@ uint8_t circpad_negotiate_get_echo_request(const circpad_negotiate_t *inp);
* code on 'inp' on failure.
*/
int circpad_negotiate_set_echo_request(circpad_negotiate_t *inp, uint8_t val);
+/** Return the value of the machine_ctr field of the
+ * circpad_negotiate_t in 'inp'
+ */
+uint32_t circpad_negotiate_get_machine_ctr(const circpad_negotiate_t *inp);
+/** Set the value of the machine_ctr field of the circpad_negotiate_t
+ * in 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int circpad_negotiate_set_machine_ctr(circpad_negotiate_t *inp, uint32_t val);
/** Return a newly allocated circpad_negotiated with all elements set
* to zero.
*/
@@ -190,6 +208,15 @@ uint8_t circpad_negotiated_get_machine_type(const circpad_negotiated_t *inp);
* -1 and set the error code on 'inp' on failure.
*/
int circpad_negotiated_set_machine_type(circpad_negotiated_t *inp, uint8_t val);
+/** Return the value of the machine_ctr field of the
+ * circpad_negotiated_t in 'inp'
+ */
+uint32_t circpad_negotiated_get_machine_ctr(const circpad_negotiated_t *inp);
+/** Set the value of the machine_ctr field of the circpad_negotiated_t
+ * in 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int circpad_negotiated_set_machine_ctr(circpad_negotiated_t *inp, uint32_t val);
#endif
diff --git a/src/trunnel/circpad_negotiation.trunnel b/src/trunnel/circpad_negotiation.trunnel
index abbc929cc5..68fed6a013 100644
--- a/src/trunnel/circpad_negotiation.trunnel
+++ b/src/trunnel/circpad_negotiation.trunnel
@@ -27,6 +27,13 @@ struct circpad_negotiate {
// FIXME-MP-AP: Maybe we just say to transition to the first state
// here instead.. Also what about delay before responding?
u8 echo_request IN [0,1];
+
+ // This field is used for shutdown synchronization. It is OK if
+ // it wraps, because all we need to do is make sure the STOP
+ // command is actually for the currently active machine.
+ // For backward-compatibility, though, 0 has special meaning
+ // (it means match any machine).
+ u32 machine_ctr;
};
/**
@@ -41,4 +48,14 @@ struct circpad_negotiated {
/** Machine type is left unbounded because we can specify
* new machines in the consensus */
u8 machine_type;
+
+ /**
+ * This field is used for shutdown synchronization. It is OK if
+ * it wraps, because all we need to do is make sure the STOP
+ * command is actually for the currently active machine.
+ * For backward-compatibility, though, 0 has special meaning
+ * (it means match any machine).
+ */
+ u32 machine_ctr;
+
};
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index 38fbc30a5f..3c7b2ab5fc 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.4.5-dev"
+#define VERSION "0.4.5.0-alpha-dev"
#define HAVE_STRUCT_SOCKADDR_IN6
#define HAVE_STRUCT_IN6_ADDR