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/config.c129
-rw-r--r--src/app/config/config.h15
-rw-r--r--src/app/config/fallback_dirs.inc6
-rw-r--r--src/app/config/or_options_st.h18
-rw-r--r--src/app/config/or_state_st.h8
-rw-r--r--src/app/config/resolve_addr.c953
-rw-r--r--src/app/config/resolve_addr.h29
-rw-r--r--src/app/config/statefile.c14
-rw-r--r--src/app/config/testnet.inc3
-rw-r--r--src/app/include.am4
-rw-r--r--src/app/main/main.c51
-rw-r--r--src/app/main/ntmain.c2
-rw-r--r--src/app/main/shutdown.c2
-rw-r--r--src/app/main/subsystem_list.c3
-rw-r--r--src/config/mmdb-convert.py2
-rw-r--r--src/core/crypto/onion_crypto.c2
-rw-r--r--src/core/mainloop/connection.c286
-rw-r--r--src/core/mainloop/connection.h5
-rw-r--r--src/core/mainloop/mainloop.c3
-rw-r--r--src/core/or/channel.c114
-rw-r--r--src/core/or/channel.h31
-rw-r--r--src/core/or/channelpadding.c6
-rw-r--r--src/core/or/channelpadding.h3
-rw-r--r--src/core/or/channeltls.c363
-rw-r--r--src/core/or/channeltls.h4
-rw-r--r--src/core/or/circuit_st.h6
-rw-r--r--src/core/or/circuitbuild.c451
-rw-r--r--src/core/or/circuitbuild.h27
-rw-r--r--src/core/or/circuitlist.c24
-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.c79
-rw-r--r--src/core/or/circuitstats.h6
-rw-r--r--src/core/or/circuituse.c46
-rw-r--r--src/core/or/circuituse.h16
-rw-r--r--src/core/or/command.c12
-rw-r--r--src/core/or/connection_edge.c94
-rw-r--r--src/core/or/connection_edge.h4
-rw-r--r--src/core/or/connection_or.c174
-rw-r--r--src/core/or/connection_or.h1
-rw-r--r--src/core/or/connection_st.h55
-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.h24
-rw-r--r--src/core/or/or_connection_st.h17
-rw-r--r--src/core/or/policies.c136
-rw-r--r--src/core/or/policies.h8
-rw-r--r--src/core/or/port_cfg_st.h2
-rw-r--r--src/core/or/protover.c16
-rw-r--r--src/core/or/protover.h24
-rw-r--r--src/core/or/reasons.c4
-rw-r--r--src/core/or/relay.c1
-rw-r--r--src/core/or/scheduler.c4
-rw-r--r--src/core/or/scheduler_kist.c7
-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/stA1RajU0
-rw-r--r--src/core/stiysZNDbin19083264 -> 0 bytes
-rw-r--r--src/ext/README79
-rw-r--r--src/ext/ext.md88
-rw-r--r--src/ext/include.am2
-rw-r--r--src/feature/client/bridges.c113
-rw-r--r--src/feature/client/entrynodes.c294
-rw-r--r--src/feature/client/entrynodes.h25
-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.c36
-rw-r--r--src/feature/control/control_events.c59
-rw-r--r--src/feature/control/control_events.h2
-rw-r--r--src/feature/control/control_getinfo.c68
-rw-r--r--src/feature/control/control_getinfo.h4
-rw-r--r--src/feature/control/control_hs.c3
-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.c57
-rw-r--r--src/feature/dirauth/dirvote.h12
-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.c229
-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.c22
-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.c49
-rw-r--r--src/feature/hs/hs_common.c1
-rw-r--r--src/feature/hs/hs_service.c6
-rw-r--r--src/feature/nodelist/authcert.c24
-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.c172
-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.c246
-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.c165
-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/relay/circuitbuild_relay.c67
-rw-r--r--src/feature/relay/circuitbuild_relay.h2
-rw-r--r--src/feature/relay/relay_config.c108
-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.c72
-rw-r--r--src/feature/relay/router.c432
-rw-r--r--src/feature/relay/router.h14
-rw-r--r--src/feature/relay/selftest.c358
-rw-r--r--src/feature/relay/selftest.h18
-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.c43
-rw-r--r--src/feature/stats/bwhist.c592
-rw-r--r--src/feature/stats/bwhist.h40
-rw-r--r--src/feature/stats/connstats.c283
-rw-r--r--src/feature/stats/connstats.h25
-rw-r--r--src/feature/stats/include.am4
-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/evloop/timers.c2
-rw-r--r--src/lib/fs/files.c8
-rw-r--r--src/lib/log/log.c2
-rw-r--r--src/lib/math/laplace.c2
-rw-r--r--src/lib/net/address.c57
-rw-r--r--src/lib/net/address.h14
-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/restrict.c6
-rw-r--r--src/lib/sandbox/sandbox.c149
-rw-r--r--src/lib/sandbox/sandbox.h7
-rw-r--r--src/lib/tls/buffers_tls.c5
-rw-r--r--src/lib/tls/tortls.h1
-rw-r--r--src/lib/tls/tortls_nss.c70
-rw-r--r--src/lib/tls/tortls_openssl.c20
-rw-r--r--src/lib/tls/tortls_st.h3
-rw-r--r--src/lib/tls/x509.c3
-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.rs8
-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.am2
-rw-r--r--src/test/include.am18
-rw-r--r--src/test/rend_test_helpers.c13
-rw-r--r--src/test/slow_ed25519.py2
-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.c1106
-rw-r--r--src/test/test_connection.c119
-rw-r--r--src/test/test_controller.c87
-rw-r--r--src/test/test_crypto_slow.c2
-rw-r--r--src/test/test_dir.c116
-rw-r--r--src/test/test_dir_common.c42
-rw-r--r--src/test/test_dos.c32
-rw-r--r--src/test/test_entrynodes.c167
-rw-r--r--src/test/test_guardfraction.c6
-rw-r--r--src/test/test_helpers.c62
-rw-r--r--src/test/test_helpers.h5
-rw-r--r--src/test/test_hs_client.c6
-rw-r--r--src/test/test_hs_common.c14
-rw-r--r--src/test/test_hs_control.c2
-rw-r--r--src/test/test_hs_service.c8
-rw-r--r--src/test/test_nodelist.c63
-rw-r--r--src/test/test_options.c4
-rwxr-xr-xsrc/test/test_parseconf.sh2
-rw-r--r--src/test/test_policy.c25
-rw-r--r--src/test/test_prob_distr.c2
-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_router.c49
-rw-r--r--src/test/test_routerkeys.c52
-rw-r--r--src/test/test_routerlist.c42
-rw-r--r--src/test/test_routerset.c56
-rw-r--r--src/test/test_stats.c45
-rw-r--r--src/test/test_tortls.c73
-rw-r--r--src/test/test_tortls_openssl.c70
-rw-r--r--src/test/test_util.c51
-rw-r--r--src/test/test_voting_flags.c14
-rw-r--r--src/test/testing_common.c2
-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
250 files changed, 9861 insertions, 4692 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/config.c b/src/app/config/config.c
index 71f8c18ca2..a70c1d651e 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);
});
@@ -2771,10 +2774,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 +3228,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);
@@ -3436,7 +3439,7 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
"UseEntryGuards is disabled, but you have configured one or more "
"hidden services on this Tor instance. Your hidden services "
"will be very easy to locate using a well-known attack -- see "
- "http://freehaven.net/anonbib/#hs-attack06 for details.");
+ "https://freehaven.net/anonbib/#hs-attack06 for details.");
}
if (options->NumPrimaryGuards && options->NumEntryGuards &&
@@ -4028,7 +4031,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);
@@ -4364,6 +4367,12 @@ options_init_from_torrc(int argc, char **argv)
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?
return 1;
}
@@ -5610,7 +5619,7 @@ port_cfg_new(size_t namelen)
/* entry_cfg flags */
cfg->entry_cfg.ipv4_traffic = 1;
cfg->entry_cfg.ipv6_traffic = 1;
- cfg->entry_cfg.prefer_ipv6 = 1;
+ cfg->entry_cfg.prefer_ipv6 = 0;
cfg->entry_cfg.dns_request = 1;
cfg->entry_cfg.onion_traffic = 1;
cfg->entry_cfg.prefer_ipv6_virtaddr = 1;
@@ -5822,6 +5831,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) {
@@ -5898,8 +5916,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;
@@ -5915,14 +5933,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);
@@ -5933,6 +5957,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;
@@ -5975,15 +6000,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 */
@@ -6196,9 +6231,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);
@@ -6495,14 +6531,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) {
@@ -6510,33 +6545,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 17caa0e3ff..ee39490072 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/fallback_dirs.inc b/src/app/config/fallback_dirs.inc
index 793f65ce88..ba7e848715 100644
--- a/src/app/config/fallback_dirs.inc
+++ b/src/app/config/fallback_dirs.inc
@@ -3,10 +3,10 @@
/* timestamp=20190625114911 */
/* timestamp0=20190625114911 */
/* timestamp1=20190628085927 */
-/* source=whitelist */
+/* source=allowlist */
/* ===== */
-/* 0: Whitelist excluded 1550 of 1711 candidates. */
-/* 1: Whitelist excluded 1601 of 1765 candidates. */
+/* 0: Allowlist excluded 1550 of 1711 candidates. */
+/* 1: Allowlist excluded 1601 of 1765 candidates. */
/* Checked IPv4 DirPorts served a consensus within 15.0s. */
/*
0:
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
index bf58205f89..68be5711ce 100644
--- a/src/app/config/or_options_st.h
+++ b/src/app/config/or_options_st.h
@@ -71,7 +71,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 +199,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? */
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..798c703f0a 100644
--- a/src/app/config/resolve_addr.c
+++ b/src/app/config/resolve_addr.c
@@ -14,301 +14,766 @@
#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);
+
+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)
+/** 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
+resolved_addr_get_suggested(int family, tor_addr_t *addr_out)
{
- return last_resolved_addr;
+ tor_addr_copy(addr_out, &last_suggested_addrs[af_to_idx(family)]);
}
-/** Reset last_resolved_addr from outside this file. */
+/** Set the last suggested address into our cache. This is called when we get
+ * a new NETINFO cell from a trusted source. */
void
-reset_last_resolved_addr(void)
+resolved_addr_set_suggested(const tor_addr_t *addr)
{
- last_resolved_addr = 0;
+ 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);
}
-/**
- * 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
+/** 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: String denoting by which method 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, const char **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 = NULL;
- 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 = "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";
+ 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: String denoting by which method 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, const char **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 = NULL;
+
+ 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 = "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 "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, const char **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 = NULL;
+ *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;
+ }
+
+ *method_out = "INTERFACE";
+
+ /* Found it! */
+ log_info(LD_CONFIG, "Address found from interface: %s", fmt_addr(addr_out));
+ return FN_RET_OK;
+}
- if (last_resolved_addr && last_resolved_addr != *addr_out) {
+/** @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 "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, const char **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);
+
+ 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 = "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 char *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);
+ tor_assert(method_used);
+
+ /* 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), 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), method_used,
+ have_hostname ? " HOSTNAME=" : "",
+ have_hostname ? hostname_used : "");
+ /* Copy address to cache. */
+ tor_addr_copy(last_resolved, addr);
+ *done_one_resolve = 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,
+ const char **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 "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" 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 "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 "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) String denoting by which method 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 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, const char **method_out,
+ char **hostname_out)
+{
+ const char *method_used = NULL;
+ 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 = NULL;
+ 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[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..c279d19f6e 100644
--- a/src/app/config/resolve_addr.h
+++ b/src/app/config/resolve_addr.h
@@ -9,19 +9,36 @@
#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);
+#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,
+ const char **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 char *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));
+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..3caa0bab1c 100644
--- a/src/app/include.am
+++ b/src/app/include.am
@@ -20,7 +20,7 @@ src_app_tor_LDADD = $(TOR_INTERNAL_LIBS) \
@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_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)
@@ -31,5 +31,5 @@ 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@ \
@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 dc39611f98..e09b003b42 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.
*/
@@ -822,6 +830,9 @@ sandbox_init_filter(void)
#define OPEN(name) \
sandbox_cfg_allow_open_filename(&cfg, tor_strdup(name))
+#define OPENDIR(dir) \
+ sandbox_cfg_allow_opendir_dirname(&cfg, tor_strdup(dir))
+
#define OPEN_DATADIR(name) \
sandbox_cfg_allow_open_filename(&cfg, get_datadir_fname(name))
@@ -839,7 +850,7 @@ sandbox_init_filter(void)
} while (0)
#define OPEN_KEY_DIRECTORY() \
- sandbox_cfg_allow_open_filename(&cfg, tor_strdup(options->KeyDirectory))
+ OPENDIR(options->KeyDirectory)
#define OPEN_CACHEDIR(name) \
sandbox_cfg_allow_open_filename(&cfg, get_cachedir_fname(name))
#define OPEN_CACHEDIR_SUFFIX(name, suffix) do { \
@@ -853,7 +864,7 @@ sandbox_init_filter(void)
OPEN_KEYDIR(name suffix); \
} while (0)
- OPEN(options->DataDirectory);
+ OPENDIR(options->DataDirectory);
OPEN_KEY_DIRECTORY();
OPEN_CACHEDIR_SUFFIX("cached-certs", ".tmp");
@@ -900,7 +911,11 @@ sandbox_init_filter(void)
}
SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, {
- OPEN(f);
+ if (file_status(f) == FN_DIR) {
+ OPENDIR(f);
+ } else {
+ OPEN(f);
+ }
});
#define RENAME_SUFFIX(name, suffix) \
@@ -1013,7 +1028,7 @@ sandbox_init_filter(void)
* directory that holds it. */
char *dirname = tor_strdup(port->unix_addr);
if (get_parent_directory(dirname) == 0) {
- OPEN(dirname);
+ OPENDIR(dirname);
}
tor_free(dirname);
sandbox_cfg_allow_chmod_filename(&cfg, tor_strdup(port->unix_addr));
@@ -1054,12 +1069,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/ntmain.c b/src/app/main/ntmain.c
index 4941199759..5dc0edd591 100644
--- a/src/app/main/ntmain.c
+++ b/src/app/main/ntmain.c
@@ -603,7 +603,7 @@ nt_service_install(int argc, char **argv)
/* Genericity is apparently _so_ last year in Redmond, where some
* accounts are accounts that you can look up, and some accounts
* are magic and undetectable via the security subsystem. See
- * http://msdn2.microsoft.com/en-us/library/ms684188.aspx
+ * https://msdn2.microsoft.com/en-us/library/ms684188.aspx
*/
printf("Running on a Post-Win2K OS, so we'll assume that the "
"LocalService account exists.\n");
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/mmdb-convert.py b/src/config/mmdb-convert.py
index a58f5d43e1..4acfea6c0e 100644
--- a/src/config/mmdb-convert.py
+++ b/src/config/mmdb-convert.py
@@ -9,7 +9,7 @@
#
# You should have received a copy of the CC0 legalcode along with this
# work in doc/cc0.txt. If not, see
-# <http://creativecommons.org/publicdomain/zero/1.0/>.
+# <https://creativecommons.org/publicdomain/zero/1.0/>.
# Nick Mathewson is responsible for this kludge, but takes no
# responsibility for it.
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 a8417e46d9..efde9df7ed 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -105,7 +105,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 +220,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 +233,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 +368,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 +566,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)
@@ -1545,13 +1730,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:
@@ -2069,16 +2249,7 @@ connection_connect_log_client_use_ip_version(const connection_t *conn)
? fascist_firewall_prefer_ipv6_orport(options)
: fascist_firewall_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)
@@ -2604,8 +2775,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;
}
@@ -2614,8 +2785,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;
}
@@ -2831,16 +3002,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;
@@ -2997,10 +3168,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)
@@ -3031,8 +3202,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,10 +3219,11 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol)
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) */
@@ -3069,10 +3241,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,
@@ -3344,9 +3515,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
@@ -3361,15 +3532,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);
@@ -3858,17 +4030,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);
@@ -4205,6 +4374,7 @@ connection_handle_write_impl(connection_t *conn, int force)
switch (result) {
CASE_TOR_TLS_ERROR_ANY:
case TOR_TLS_CLOSE:
+ or_conn->tls_error = result;
log_info(LD_NET, result != TOR_TLS_CLOSE ?
"tls error. breaking.":"TLS connection closed on flush");
/* Don't flush; connection is dead. */
@@ -4720,7 +4890,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;
}
@@ -4870,7 +5040,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);
}
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..3bf9be566b 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"
@@ -1950,7 +1951,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 a05554472f..5a42d452f2 100644
--- a/src/core/or/channel.c
+++ b/src/core/or/channel.c
@@ -71,6 +71,7 @@
#include "core/or/relay.h"
#include "core/or/scheduler.h"
#include "feature/client/entrynodes.h"
+#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
@@ -83,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 */
@@ -755,6 +749,7 @@ channel_check_for_duplicates(void)
{
channel_idmap_entry_t **iter;
channel_t *chan;
+ int total_dirauth_connections = 0, total_dirauths = 0;
int total_relay_connections = 0, total_relays = 0, total_canonical = 0;
int total_half_canonical = 0;
int total_gt_one_connection = 0, total_gt_two_connections = 0;
@@ -762,13 +757,18 @@ channel_check_for_duplicates(void)
HT_FOREACH(iter, channel_idmap, &channel_identity_map) {
int connections_to_relay = 0;
+ const char *id_digest = (char *) (*iter)->digest;
/* Only consider relay connections */
- if (!connection_or_digest_is_known_relay((char*)(*iter)->digest))
+ if (!connection_or_digest_is_known_relay(id_digest))
continue;
total_relays++;
+ const bool is_dirauth = router_digest_is_trusted_dir(id_digest);
+ if (is_dirauth)
+ total_dirauths++;
+
for (chan = TOR_LIST_FIRST(&(*iter)->channel_list); chan;
chan = channel_next_with_rsa_identity(chan)) {
@@ -777,6 +777,8 @@ channel_check_for_duplicates(void)
connections_to_relay++;
total_relay_connections++;
+ if (is_dirauth)
+ total_dirauth_connections++;
if (chan->is_canonical(chan, 0)) total_canonical++;
@@ -791,11 +793,28 @@ channel_check_for_duplicates(void)
if (connections_to_relay > 4) total_gt_four_connections++;
}
-#define MIN_RELAY_CONNECTIONS_TO_WARN 5
+ /* Don't bother warning about excessive connections unless we have
+ * at least this many connections, total.
+ */
+#define MIN_RELAY_CONNECTIONS_TO_WARN 25
+ /* If the average number of connections for a regular relay is more than
+ * this, that's too high.
+ */
+#define MAX_AVG_RELAY_CONNECTIONS 1.5
+ /* If the average number of connections for a dirauth is more than
+ * this, that's too high.
+ */
+#define MAX_AVG_DIRAUTH_CONNECTIONS 4
+
+ /* How many connections total would be okay, given the number of
+ * relays and dirauths that we have connections to? */
+ const int max_tolerable_connections = (int)(
+ (total_relays-total_dirauths) * MAX_AVG_RELAY_CONNECTIONS +
+ total_dirauths * MAX_AVG_DIRAUTH_CONNECTIONS);
/* If we average 1.5 or more connections per relay, something is wrong */
if (total_relays > MIN_RELAY_CONNECTIONS_TO_WARN &&
- total_relay_connections >= 1.5*total_relays) {
+ total_relay_connections > max_tolerable_connections) {
log_notice(LD_OR,
"Your relay has a very large number of connections to other relays. "
"Is your outbound address the same as your relay address? "
@@ -2560,7 +2579,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"
@@ -2568,18 +2587,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);
}
@@ -2789,75 +2808,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);
}
/**
@@ -3296,6 +3281,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)
@@ -3317,7 +3305,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 4968c8714a..d52ebdf619 100644
--- a/src/core/or/channel.h
+++ b/src/core/or/channel.h
@@ -329,24 +329,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 *);
/**
@@ -562,7 +556,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 */
@@ -721,11 +718,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 395fbf3455..ae60038c34 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, int req);
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;
}
/**
@@ -683,6 +667,9 @@ channel_tls_is_canonical_method(channel_t *chan, int req)
*
* 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,
@@ -702,9 +689,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);
}
/**
@@ -732,8 +729,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
@@ -744,7 +741,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);
}
/**
@@ -1353,7 +1350,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",
@@ -1517,7 +1514,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;
}
@@ -1529,10 +1526,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);
@@ -1552,10 +1548,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" : "",
@@ -1688,6 +1683,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
*
@@ -1713,20 +1787,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;
@@ -1741,30 +1807,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);
}
}
}
@@ -1807,7 +1856,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 &&
@@ -1841,7 +1890,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;
}
@@ -1851,8 +1900,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 "
@@ -1861,7 +1910,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. */
@@ -1875,8 +1924,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
@@ -1890,18 +1943,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) ?
@@ -1986,9 +2037,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)
@@ -2036,9 +2087,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);
@@ -2054,9 +2104,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);
@@ -2166,9 +2215,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())) {
@@ -2180,11 +2229,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? */
}
@@ -2233,9 +2281,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)
@@ -2280,10 +2328,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) {
@@ -2294,10 +2341,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) {
@@ -2337,9 +2383,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; \
@@ -2500,9 +2546,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");
@@ -2515,10 +2561,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 83ce9f882b..6ad19eebad 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);
@@ -980,6 +983,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);
@@ -1050,8 +1054,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);
}
}
@@ -1075,23 +1079,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. */
@@ -1126,6 +1147,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;
}
@@ -1539,7 +1561,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();
@@ -1572,19 +1610,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 */
@@ -1594,27 +1627,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.",
@@ -1765,35 +1777,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);
}
/**
@@ -1809,9 +1815,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,
@@ -1819,17 +1825,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;
@@ -1957,6 +1963,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.
@@ -1990,14 +2033,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) {
@@ -2059,32 +2101,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);
@@ -2278,10 +2315,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)) {
@@ -2357,10 +2392,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);
@@ -2429,143 +2461,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.
@@ -2601,43 +2496,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. */
@@ -2672,15 +2530,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..af98af362a 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;
}
@@ -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
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 822e5bd308..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));
@@ -972,7 +969,7 @@ circuit_build_times_update_state(const circuit_build_times_t *cbt,
/**
* Shuffle the build times array.
*
- * Adapted from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
+ * Adapted from https://en.wikipedia.org/wiki/Fisher-Yates_shuffle
*/
static void
circuit_build_times_shuffle_and_store_array(circuit_build_times_t *cbt,
@@ -1183,7 +1180,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
/**
* Estimates the Xm and Alpha parameters using
- * http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation
+ * https://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation
*
* The notable difference is that we use mode instead of min to estimate Xm.
* This is because our distribution is frechet-like. We claim this is
@@ -1198,7 +1195,7 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
int n=0,i=0,abandoned_count=0;
build_time_t max_time=0;
- /* http://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */
+ /* https://en.wikipedia.org/wiki/Pareto_distribution#Parameter_estimation */
/* We sort of cheat here and make our samples slightly more pareto-like
* and less frechet-like. */
cbt->Xm = circuit_build_times_get_xm(cbt);
@@ -1270,9 +1267,9 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
* We use it to calculate the timeout and also to generate synthetic
* values of time for circuits that timeout before completion.
*
- * See http://en.wikipedia.org/wiki/Quantile_function,
- * http://en.wikipedia.org/wiki/Inverse_transform_sampling and
- * http://en.wikipedia.org/wiki/Pareto_distribution#Generating_a_
+ * See https://en.wikipedia.org/wiki/Quantile_function,
+ * https://en.wikipedia.org/wiki/Inverse_transform_sampling and
+ * https://en.wikipedia.org/wiki/Pareto_distribution#Generating_a_
* random_sample_from_Pareto_distribution
* That's right. I'll cite wikipedia all day long.
*
@@ -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..3c8a7c4a89 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,7 +1651,7 @@ static void
circuit_testing_opened(origin_circuit_t *circ)
{
if (have_performed_bandwidth_test ||
- !check_whether_orport_reachable(get_options())) {
+ !router_all_orports_seem_reachable(get_options())) {
/* 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
@@ -1660,7 +1669,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 +1691,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 +1857,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 +2103,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 +2213,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 +3146,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 fc77db8334..ed27fb1b57 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 "
@@ -1663,6 +1713,9 @@ parse_extended_hostname(char *address, hostname_type_t *type_out)
log_warn(LD_APP, "Invalid %shostname %s; rejecting",
is_onion ? "onion " : "",
safe_str_client(address));
+ if (*type_out == ONION_V3_HOSTNAME) {
+ *type_out = BAD_HOSTNAME;
+ }
return false;
}
@@ -2139,7 +2192,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
if (!parse_extended_hostname(socks->address, &addresstype)) {
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
escaped(socks->address));
- if (addresstype == ONION_V3_HOSTNAME) {
+ if (addresstype == BAD_HOSTNAME) {
conn->socks_request->socks_extended_error_code = SOCKS5_HS_BAD_ADDRESS;
}
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
@@ -3836,8 +3889,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,
@@ -3972,7 +4025,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,
@@ -3995,10 +4048,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. */
@@ -4188,8 +4244,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..9b2cbb8532 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
diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c
index 5d71b363f8..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 */
@@ -745,10 +757,16 @@ connection_or_about_to_close(or_connection_t *or_conn)
int reason = tls_error_to_orconn_end_reason(or_conn->tls_error);
connection_or_event_status(or_conn, OR_CONN_EVENT_FAILED,
reason);
- if (!authdir_mode_tests_reachability(options))
- control_event_bootstrap_prob_or(
- orconn_end_reason_to_control_string(reason),
- reason, or_conn);
+ if (!authdir_mode_tests_reachability(options)) {
+ const char *warning = NULL;
+ if (reason == END_OR_CONN_REASON_TLS_ERROR && or_conn->tls) {
+ warning = tor_tls_get_last_error_msg(or_conn->tls);
+ }
+ if (warning == NULL) {
+ warning = orconn_end_reason_to_control_string(reason);
+ }
+ control_event_bootstrap_prob_or(warning, reason, or_conn);
+ }
}
}
} else if (conn->hold_open_until_flushed) {
@@ -875,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);
}
@@ -887,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;
@@ -918,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);
}
/*
@@ -1004,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);
}
@@ -1071,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;
@@ -1115,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);
@@ -1154,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
@@ -1253,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;
}
@@ -1458,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;
}
@@ -1501,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(
@@ -1510,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));
@@ -1632,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,
@@ -1692,7 +1699,8 @@ connection_tls_continue_handshake(or_connection_t *conn)
switch (result) {
CASE_TOR_TLS_ERROR_ANY:
- log_info(LD_OR,"tls error [%s]. breaking connection.",
+ conn->tls_error = result;
+ log_info(LD_OR,"tls error [%s]. breaking connection.",
tor_tls_err_to_string(result));
return -1;
case TOR_TLS_DONE:
@@ -1724,6 +1732,7 @@ connection_tls_continue_handshake(or_connection_t *conn)
log_debug(LD_OR,"wanted read");
return 0;
case TOR_TLS_CLOSE:
+ conn->tls_error = result;
log_info(LD_OR,"tls closed. breaking connection.");
return -1;
}
@@ -1778,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. "
@@ -1801,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 "
@@ -1811,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();
}
@@ -1883,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));
@@ -1899,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,
@@ -1975,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 */
@@ -2004,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);
}
@@ -2049,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,
@@ -2485,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);
@@ -2499,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 55d94d9451..9cc06d1ef3 100644
--- a/src/core/or/connection_st.h
+++ b/src/core/or/connection_st.h
@@ -109,10 +109,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. */
@@ -122,12 +151,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..ffc88295cf
--- /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)
+ 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;
+}
+
+/* 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 5b35cbe7f1..d80c41371e 100644
--- a/src/core/or/or.h
+++ b/src/core/or/or.h
@@ -220,7 +220,8 @@ struct curve25519_public_key_t;
#define END_OR_CONN_REASON_IO_ERROR 7 /* read/write error */
#define END_OR_CONN_REASON_RESOURCE_LIMIT 8 /* sockets, buffers, etc */
#define END_OR_CONN_REASON_PT_MISSING 9 /* PT failed or not available */
-#define END_OR_CONN_REASON_MISC 10
+#define END_OR_CONN_REASON_TLS_ERROR 10 /* Problem in TLS protocol */
+#define END_OR_CONN_REASON_MISC 11
/* Reasons why we (or a remote OR) might close a stream. See tor-spec.txt for
* documentation of these. The values must match. */
@@ -815,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. */
@@ -830,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. */
@@ -841,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..020eb0a152 100644
--- a/src/core/or/policies.c
+++ b/src/core/or/policies.c
@@ -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.
*
@@ -576,25 +563,6 @@ fascist_firewall_allows_address_ap(const tor_addr_port_t *ap,
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,
- fw_connection, pref_only,
- pref_ipv6);
-}
-
/** Return true iff we think our firewall will let us make a connection to
* ipv4h_addr/ipv6_addr. Uses ipv4_orport/ipv6_orport/ReachableORAddresses or
* ipv4_dirport/ipv6_dirport/ReachableDirAddresses based on IPv4/IPv6 and
@@ -602,14 +570,14 @@ fascist_firewall_allows_address_ipv4h(uint32_t ipv4h_or_addr,
* pref_only and pref_ipv6 work as in fascist_firewall_allows_address_addr().
*/
static int
-fascist_firewall_allows_base(uint32_t ipv4h_addr, uint16_t ipv4_orport,
+fascist_firewall_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 (fascist_firewall_allows_address_addr(ipv4_addr,
(fw_connection == FIREWALL_OR_CONNECTION
? ipv4_orport
: ipv4_dirport),
@@ -641,10 +609,10 @@ 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 fascist_firewall_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. */
@@ -658,10 +626,10 @@ 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 fascist_firewall_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.
@@ -892,34 +860,6 @@ 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>.
* 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
@@ -951,12 +891,11 @@ fascist_firewall_choose_address_rs(const routerstatus_t *rs,
? fascist_firewall_prefer_ipv6_orport(options)
: fascist_firewall_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);
+ fascist_firewall_choose_address_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);
}
}
@@ -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..1ac6f87dcf 100644
--- a/src/core/or/policies.h
+++ b/src/core/or/policies.h
@@ -102,9 +102,9 @@ void fascist_firewall_choose_address_dir_server(const dir_server_t *ds,
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;
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..1ac264925c 100644
--- a/src/core/or/protover.c
+++ b/src/core/or/protover.c
@@ -326,6 +326,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 +351,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 +393,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 +414,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 +751,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..2950147d1b 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
diff --git a/src/core/or/reasons.c b/src/core/or/reasons.c
index 7da7843cab..708f43a689 100644
--- a/src/core/or/reasons.c
+++ b/src/core/or/reasons.c
@@ -244,6 +244,8 @@ orconn_end_reason_to_control_string(int r)
return "IOERROR";
case END_OR_CONN_REASON_RESOURCE_LIMIT:
return "RESOURCELIMIT";
+ case END_OR_CONN_REASON_TLS_ERROR:
+ return "TLS_ERROR";
case END_OR_CONN_REASON_MISC:
return "MISC";
case END_OR_CONN_REASON_PT_MISSING:
@@ -276,6 +278,8 @@ tls_error_to_orconn_end_reason(int e)
case TOR_TLS_CLOSE:
case TOR_TLS_DONE:
return END_OR_CONN_REASON_DONE;
+ case TOR_TLS_ERROR_MISC:
+ return END_OR_CONN_REASON_TLS_ERROR;
default:
return END_OR_CONN_REASON_MISC;
}
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 ff58f9ca5b..18f11487d9 100644
--- a/src/core/or/scheduler.c
+++ b/src/core/or/scheduler.c
@@ -42,7 +42,7 @@
* circuit scheduler. It was supposed to prioritize circuits across many
* channels, but wasn't effective. It is preserved in scheduler_vanilla.c.
*
- * [0]: http://www.robgjansen.com/publications/kist-sec2014.pdf
+ * [0]: https://www.robgjansen.com/publications/kist-sec2014.pdf
*
* Then we actually got around to implementing KIST for real. We decided to
* modularize the scheduler so new ones can be implemented. You can find KIST
@@ -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/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/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/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..6892c4a25f 100644
--- a/src/feature/client/bridges.c
+++ b/src/feature/client/bridges.c
@@ -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;
}
@@ -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;
@@ -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);
diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c
index ded7db969a..9b20684bf7 100644
--- a/src/feature/client/entrynodes.c
+++ b/src/feature/client/entrynodes.c
@@ -47,8 +47,7 @@
* As a persistent ordered list whose elements are taken from the
* sampled set, we track a CONFIRMED GUARDS LIST. A guard becomes
* confirmed when we successfully build a circuit through it, and decide
- * to use that circuit. We order the guards on this list by the order
- * in which they became confirmed.
+ * to use that circuit.
*
* And as a final group, we have an ordered list of PRIMARY GUARDS,
* whose elements are taken from the filtered set. We prefer
@@ -59,7 +58,7 @@
*
* To build circuits, we take a primary guard if possible -- or a
* reachable filtered confirmed guard if no primary guard is possible --
- * or a random reachable filtered guard otherwise. If the guard is
+ * or the first (by sampled order) filtered guard otherwise. If the guard is
* primary, we can use the circuit immediately on success. Otherwise,
* the guard is now "pending" -- we won't use its circuit unless all
* of the circuits we're trying to build through better guards have
@@ -92,14 +91,18 @@
* [x] Whenever we remove a guard from the sample, remove it from the primary
* and confirmed lists.
*
- * [x] When we make a guard confirmed, update the primary list.
+ * [x] When we make a guard confirmed, update the primary list, and sort them
+ * by sampled order.
*
* [x] When we make a guard filtered or unfiltered, update the primary list.
*
* [x] When we are about to pick a guard, make sure that the primary list is
* full.
*
- * [x] Before calling sample_reachable_filtered_entry_guards(), make sure
+ * [x] When we update the confirmed list, or when we re-build the primary list
+ * and detect a change, we sort those lists by sampled_idx
+ *
+ * [x] Before calling first_reachable_filtered_entry_guard(), make sure
* that the filtered, primary, and confirmed flags are up-to-date.
*
* [x] Call entry_guard_consider_retry every time we are about to check
@@ -172,6 +175,7 @@ static entry_guard_t *get_sampled_guard_by_bridge_addr(guard_selection_t *gs,
const tor_addr_port_t *addrport);
static int entry_guard_obeys_restriction(const entry_guard_t *guard,
const entry_guard_restriction_t *rst);
+static int compare_guards_by_sampled_idx(const void **a_, const void **b_);
/** Return 0 if we should apply guardfraction information found in the
* consensus. A specific consensus can be specified with the
@@ -890,6 +894,7 @@ entry_guard_add_to_sample_impl(guard_selection_t *gs,
tor_free(guard->sampled_by_version);
guard->sampled_by_version = tor_strdup(VERSION);
guard->currently_listed = 1;
+ guard->sampled_idx = gs->next_sampled_idx++;
guard->confirmed_idx = -1;
/* non-persistent fields */
@@ -901,6 +906,11 @@ entry_guard_add_to_sample_impl(guard_selection_t *gs,
guard->in_selection = gs;
entry_guard_set_filtered_flags(get_options(), gs, guard);
entry_guards_changed_for_guard_selection(gs);
+
+ /* Just added this guard to the sampled set and hence it might be used as a
+ * guard in the future: send GUARD NEW control event. */
+ control_event_guard(guard->nickname, guard->identity, "NEW");
+
return guard;
}
@@ -1383,7 +1393,7 @@ sampled_guards_prune_obsolete_entries(guard_selection_t *gs,
if (rmv) {
++n_changes;
- SMARTLIST_DEL_CURRENT(gs->sampled_entry_guards, guard);
+ SMARTLIST_DEL_CURRENT_KEEPORDER(gs->sampled_entry_guards, guard);
remove_guard_from_confirmed_and_primary_lists(gs, guard);
entry_guard_free(guard);
}
@@ -1544,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;
}
@@ -1566,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)
{
@@ -1707,7 +1717,7 @@ entry_guards_update_filtered_sets(guard_selection_t *gs)
}
/**
- * Return a random guard from the reachable filtered sample guards
+ * Return the first sampled guard from the reachable filtered sample guards
* in <b>gs</b>, subject to the exclusion rules listed in <b>flags</b>.
* Return NULL if no such guard can be found.
*
@@ -1718,7 +1728,7 @@ entry_guards_update_filtered_sets(guard_selection_t *gs)
* violate it.
**/
STATIC entry_guard_t *
-sample_reachable_filtered_entry_guards(guard_selection_t *gs,
+first_reachable_filtered_entry_guard(guard_selection_t *gs,
const entry_guard_restriction_t *rst,
unsigned flags)
{
@@ -1771,7 +1781,17 @@ sample_reachable_filtered_entry_guards(guard_selection_t *gs,
flags, smartlist_len(reachable_filtered_sample));
if (smartlist_len(reachable_filtered_sample)) {
- result = smartlist_choose(reachable_filtered_sample);
+ /**
+ * Get the first guard of the filtered set builds from
+ * sampled_entry_guards. Proposal 310 suggests this design to overcome
+ * performance and security issues linked to the previous selection
+ * method. The guard selected here should be filtered out if this function
+ * is called again in the same context. I.e., if we filter guards to add
+ * them into some list X, then the guards from list X will be filtered out
+ * when this function is called again. Hence it requires setting exclude
+ * flags in a appropriate way (depending of the context of the caller).
+ */
+ result = smartlist_get(reachable_filtered_sample, 0);
log_info(LD_GUARD, " (Selected %s.)",
result ? entry_guard_describe(result) : "<null>");
}
@@ -1780,10 +1800,6 @@ sample_reachable_filtered_entry_guards(guard_selection_t *gs,
return result;
}
-/**
- * Helper: compare two entry_guard_t by their confirmed_idx values.
- * Used to sort the confirmed list.
- */
static int
compare_guards_by_confirmed_idx(const void **a_, const void **b_)
{
@@ -1795,6 +1811,21 @@ compare_guards_by_confirmed_idx(const void **a_, const void **b_)
else
return 0;
}
+/**
+ * Helper: compare two entry_guard_t by their sampled_idx values.
+ * Used to sort the sampled list
+ */
+static int
+compare_guards_by_sampled_idx(const void **a_, const void **b_)
+{
+ const entry_guard_t *a = *a_, *b = *b_;
+ if (a->sampled_idx < b->sampled_idx)
+ return -1;
+ else if (a->sampled_idx > b->sampled_idx)
+ return 1;
+ else
+ return 0;
+}
/**
* Find the confirmed guards from among the sampled guards in <b>gs</b>,
@@ -1811,7 +1842,7 @@ entry_guards_update_confirmed(guard_selection_t *gs)
} SMARTLIST_FOREACH_END(guard);
smartlist_sort(gs->confirmed_entry_guards, compare_guards_by_confirmed_idx);
-
+ /** Needed to keep a dense array of confirmed_idx */
int any_changed = 0;
SMARTLIST_FOREACH_BEGIN(gs->confirmed_entry_guards, entry_guard_t *, guard) {
if (guard->confirmed_idx != guard_sl_idx) {
@@ -1821,6 +1852,8 @@ entry_guards_update_confirmed(guard_selection_t *gs)
} SMARTLIST_FOREACH_END(guard);
gs->next_confirmed_idx = smartlist_len(gs->confirmed_entry_guards);
+ // We need the confirmed list to always be give guards in sampled order
+ smartlist_sort(gs->confirmed_entry_guards, compare_guards_by_sampled_idx);
if (any_changed) {
entry_guards_changed_for_guard_selection(gs);
@@ -1849,6 +1882,9 @@ make_guard_confirmed(guard_selection_t *gs, entry_guard_t *guard)
guard->confirmed_idx = gs->next_confirmed_idx++;
smartlist_add(gs->confirmed_entry_guards, guard);
+ /** The confirmation ordering might not be the sample ording. We need to
+ * reorder */
+ smartlist_sort(gs->confirmed_entry_guards, compare_guards_by_sampled_idx);
// This confirmed guard might kick something else out of the primary
// guards.
@@ -1912,7 +1948,7 @@ entry_guards_update_primary(guard_selection_t *gs)
/* Finally, fill out the list with sampled guards. */
while (smartlist_len(new_primary_guards) < N_PRIMARY_GUARDS) {
- entry_guard_t *guard = sample_reachable_filtered_entry_guards(gs, NULL,
+ entry_guard_t *guard = first_reachable_filtered_entry_guard(gs, NULL,
SAMPLE_EXCLUDE_CONFIRMED|
SAMPLE_EXCLUDE_PRIMARY|
SAMPLE_NO_UPDATE_PRIMARY);
@@ -1943,6 +1979,7 @@ entry_guards_update_primary(guard_selection_t *gs)
g->confirmed_idx >= 0 ? " (confirmed)" : "",
g->is_filtered_guard ? "" : " (excluded by filter)");
} SMARTLIST_FOREACH_END(g);
+ smartlist_sort(new_primary_guards, compare_guards_by_sampled_idx);
}
smartlist_free(old_primary_guards);
@@ -2055,10 +2092,15 @@ select_primary_guard_for_circuit(guard_selection_t *gs,
SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards, entry_guard_t *, guard) {
entry_guard_consider_retry(guard);
- if (! entry_guard_obeys_restriction(guard, rst))
+ if (!entry_guard_obeys_restriction(guard, rst)) {
+ log_info(LD_GUARD, "Entry guard %s doesn't obey restriction, we test the"
+ " next one", entry_guard_describe(guard));
continue;
+ }
if (guard->is_reachable != GUARD_REACHABLE_NO) {
if (need_descriptor && !guard_has_descriptor(guard)) {
+ log_info(LD_GUARD, "Guard %s does not have a descriptor",
+ entry_guard_describe(guard));
continue;
}
*state_out = GUARD_CIRC_STATE_USABLE_ON_COMPLETION;
@@ -2071,9 +2113,11 @@ select_primary_guard_for_circuit(guard_selection_t *gs,
if (smartlist_len(usable_primary_guards)) {
chosen_guard = smartlist_choose(usable_primary_guards);
+ log_info(LD_GUARD,
+ "Selected primary guard %s for circuit from a list size of %d.",
+ entry_guard_describe(chosen_guard),
+ smartlist_len(usable_primary_guards));
smartlist_free(usable_primary_guards);
- log_info(LD_GUARD, "Selected primary guard %s for circuit.",
- entry_guard_describe(chosen_guard));
}
smartlist_free(usable_primary_guards);
@@ -2118,10 +2162,10 @@ select_confirmed_guard_for_circuit(guard_selection_t *gs,
}
/**
- * For use with a circuit, pick a confirmed usable filtered guard
- * at random. Update the <b>last_tried_to_connect</b> time and the
- * <b>is_pending</b> fields of the guard as appropriate. Set <b>state_out</b>
- * to the new guard-state of the circuit.
+ * For use with a circuit, pick a usable filtered guard. Update the
+ * <b>last_tried_to_connect</b> time and the <b>is_pending</b> fields of the
+ * guard as appropriate. Set <b>state_out</b> to the new guard-state of the
+ * circuit.
*/
static entry_guard_t *
select_filtered_guard_for_circuit(guard_selection_t *gs,
@@ -2134,7 +2178,7 @@ select_filtered_guard_for_circuit(guard_selection_t *gs,
unsigned flags = 0;
if (need_descriptor)
flags |= SAMPLE_EXCLUDE_NO_DESCRIPTOR;
- chosen_guard = sample_reachable_filtered_entry_guards(gs,
+ chosen_guard = first_reachable_filtered_entry_guard(gs,
rst,
SAMPLE_EXCLUDE_CONFIRMED |
SAMPLE_EXCLUDE_PRIMARY |
@@ -2148,7 +2192,7 @@ select_filtered_guard_for_circuit(guard_selection_t *gs,
chosen_guard->last_tried_to_connect = approx_time();
*state_out = GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD;
log_info(LD_GUARD, "No primary or confirmed guards available. Selected "
- "random guard %s for circuit. Will try other guards before "
+ "guard %s for circuit. Will try other guards before "
"using this circuit.",
entry_guard_describe(chosen_guard));
return chosen_guard;
@@ -2189,8 +2233,8 @@ select_entry_guard_for_circuit(guard_selection_t *gs,
if (chosen_guard)
return chosen_guard;
- /* "Otherwise, if there is no such entry, select a member at
- random from {USABLE_FILTERED_GUARDS}." */
+ /* "Otherwise, if there is no such entry, select a member
+ * {USABLE_FILTERED_GUARDS} following the sample ordering" */
chosen_guard = select_filtered_guard_for_circuit(gs, usage, rst, state_out);
if (chosen_guard == NULL) {
@@ -2220,6 +2264,9 @@ entry_guards_note_guard_failure(guard_selection_t *gs,
if (guard->failing_since == 0)
guard->failing_since = approx_time();
+ /* This guard not reachable: send GUARD DOWN event */
+ control_event_guard(guard->nickname, guard->identity, "DOWN");
+
log_info(LD_GUARD, "Recorded failure for %s%sguard %s",
guard->is_primary?"primary ":"",
guard->confirmed_idx>=0?"confirmed ":"",
@@ -2245,6 +2292,11 @@ entry_guards_note_guard_success(guard_selection_t *gs,
const time_t last_time_on_internet = gs->last_time_on_internet;
gs->last_time_on_internet = approx_time();
+ /* If guard was not already marked as reachable, send a GUARD UP signal */
+ if (guard->is_reachable != GUARD_REACHABLE_YES) {
+ control_event_guard(guard->nickname, guard->identity, "UP");
+ }
+
guard->is_reachable = GUARD_REACHABLE_YES;
guard->failing_since = 0;
guard->is_pending = 0;
@@ -2773,10 +2825,12 @@ entry_guards_update_all(guard_selection_t *gs)
/**
* Return a newly allocated string for encoding the persistent parts of
- * <b>guard</b> to the state file.
+ * <b>guard</b> to the state file. <b>dense_sampled_idx</b> refers to the
+ * sampled_idx made dense for this <b>guard</b>. Encoding all guards should
+ * lead to a dense array of sampled_idx in the state file.
*/
STATIC char *
-entry_guard_encode_for_state(entry_guard_t *guard)
+entry_guard_encode_for_state(entry_guard_t *guard, int dense_sampled_idx)
{
/*
* The meta-format we use is K=V K=V K=V... where K can be any
@@ -2805,7 +2859,8 @@ entry_guard_encode_for_state(entry_guard_t *guard)
format_iso_time_nospace(tbuf, guard->sampled_on_date);
smartlist_add_asprintf(result, "sampled_on=%s", tbuf);
-
+ // Replacing the sampled_idx by dense array
+ smartlist_add_asprintf(result, "sampled_idx=%d", dense_sampled_idx);
if (guard->sampled_by_version) {
smartlist_add_asprintf(result, "sampled_by=%s",
guard->sampled_by_version);
@@ -2861,6 +2916,78 @@ entry_guard_encode_for_state(entry_guard_t *guard)
}
/**
+ * Extract key=val from the state string <b>s</b> and duplicate the value to
+ * some string target declared in entry_guard_parse_from_state
+ */
+static void
+parse_from_state_set_vals(const char *s, smartlist_t *entries, smartlist_t
+ *extra, strmap_t *vals)
+{
+ smartlist_split_string(entries, s, " ",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+
+ SMARTLIST_FOREACH_BEGIN(entries, char *, entry) {
+ const char *eq = strchr(entry, '=');
+ if (!eq) {
+ smartlist_add(extra, entry);
+ continue;
+ }
+ char *key = tor_strndup(entry, eq-entry);
+ char **target = strmap_get(vals, key);
+ if (target == NULL || *target != NULL) {
+ /* unrecognized or already set */
+ smartlist_add(extra, entry);
+ tor_free(key);
+ continue;
+ }
+
+ *target = tor_strdup(eq+1);
+ tor_free(key);
+ tor_free(entry);
+ } SMARTLIST_FOREACH_END(entry);
+}
+
+/**
+ * Handle part of the parsing state file logic, focused on time related things
+ */
+static void
+parse_from_state_handle_time(entry_guard_t *guard, char *sampled_on, char
+ *unlisted_since, char *confirmed_on)
+{
+#define HANDLE_TIME(field) do { \
+ if (field) { \
+ int r = parse_iso_time_nospace(field, &field ## _time); \
+ if (r < 0) { \
+ log_warn(LD_CIRC, "Unable to parse %s %s from guard", \
+ #field, escaped(field)); \
+ field##_time = -1; \
+ } \
+ } \
+ } while (0)
+
+ time_t sampled_on_time = 0;
+ time_t unlisted_since_time = 0;
+ time_t confirmed_on_time = 0;
+
+ HANDLE_TIME(sampled_on);
+ HANDLE_TIME(unlisted_since);
+ HANDLE_TIME(confirmed_on);
+
+ if (sampled_on_time <= 0)
+ sampled_on_time = approx_time();
+ if (unlisted_since_time < 0)
+ unlisted_since_time = 0;
+ if (confirmed_on_time < 0)
+ confirmed_on_time = 0;
+
+ #undef HANDLE_TIME
+
+ guard->sampled_on_date = sampled_on_time;
+ guard->unlisted_since_date = unlisted_since_time;
+ guard->confirmed_on_date = confirmed_on_time;
+}
+
+/**
* Given a string generated by entry_guard_encode_for_state(), parse it
* (if possible) and return an entry_guard_t object for it. Return NULL
* on complete failure.
@@ -2876,6 +3003,7 @@ entry_guard_parse_from_state(const char *s)
char *rsa_id = NULL;
char *nickname = NULL;
char *sampled_on = NULL;
+ char *sampled_idx = NULL;
char *sampled_by = NULL;
char *unlisted_since = NULL;
char *listed = NULL;
@@ -2892,6 +3020,7 @@ entry_guard_parse_from_state(const char *s)
char *pb_collapsed_circuits = NULL;
char *pb_unusable_circuits = NULL;
char *pb_timeouts = NULL;
+ int invalid_sampled_idx = get_max_sample_size_absolute();
/* Split up the entries. Put the ones we know about in strings and the
* rest in "extra". */
@@ -2905,6 +3034,7 @@ entry_guard_parse_from_state(const char *s)
FIELD(rsa_id);
FIELD(nickname);
FIELD(sampled_on);
+ FIELD(sampled_idx);
FIELD(sampled_by);
FIELD(unlisted_since);
FIELD(listed);
@@ -2920,29 +3050,8 @@ entry_guard_parse_from_state(const char *s)
FIELD(pb_unusable_circuits);
FIELD(pb_timeouts);
#undef FIELD
-
- smartlist_split_string(entries, s, " ",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
-
- SMARTLIST_FOREACH_BEGIN(entries, char *, entry) {
- const char *eq = strchr(entry, '=');
- if (!eq) {
- smartlist_add(extra, entry);
- continue;
- }
- char *key = tor_strndup(entry, eq-entry);
- char **target = strmap_get(vals, key);
- if (target == NULL || *target != NULL) {
- /* unrecognized or already set */
- smartlist_add(extra, entry);
- tor_free(key);
- continue;
- }
-
- *target = tor_strdup(eq+1);
- tor_free(key);
- tor_free(entry);
- } SMARTLIST_FOREACH_END(entry);
+ /* Extract from s the key=val that we recognize, put the others in extra*/
+ parse_from_state_set_vals(s, entries, extra, vals);
smartlist_free(entries);
strmap_free(vals, NULL);
@@ -2990,43 +3099,12 @@ entry_guard_parse_from_state(const char *s)
}
/* Process the various time fields. */
-
-#define HANDLE_TIME(field) do { \
- if (field) { \
- int r = parse_iso_time_nospace(field, &field ## _time); \
- if (r < 0) { \
- log_warn(LD_CIRC, "Unable to parse %s %s from guard", \
- #field, escaped(field)); \
- field##_time = -1; \
- } \
- } \
- } while (0)
-
- time_t sampled_on_time = 0;
- time_t unlisted_since_time = 0;
- time_t confirmed_on_time = 0;
-
- HANDLE_TIME(sampled_on);
- HANDLE_TIME(unlisted_since);
- HANDLE_TIME(confirmed_on);
-
- if (sampled_on_time <= 0)
- sampled_on_time = approx_time();
- if (unlisted_since_time < 0)
- unlisted_since_time = 0;
- if (confirmed_on_time < 0)
- confirmed_on_time = 0;
-
- #undef HANDLE_TIME
-
- guard->sampled_on_date = sampled_on_time;
- guard->unlisted_since_date = unlisted_since_time;
- guard->confirmed_on_date = confirmed_on_time;
+ parse_from_state_handle_time(guard, sampled_on, unlisted_since,
+ confirmed_on);
/* Take sampled_by_version verbatim. */
guard->sampled_by_version = sampled_by;
sampled_by = NULL; /* prevent free */
-
/* Listed is a boolean */
if (listed && strcmp(listed, "0"))
guard->currently_listed = 1;
@@ -3044,6 +3122,29 @@ entry_guard_parse_from_state(const char *s)
}
}
+ if (sampled_idx) {
+ int ok = 1;
+ long idx = tor_parse_long(sampled_idx, 10, 0, INT_MAX, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_GUARD, "Guard has invalid sampled_idx %s",
+ escaped(sampled_idx));
+ /* set it to a idx higher than the max sample size */
+ guard->sampled_idx = invalid_sampled_idx++;
+ } else {
+ guard->sampled_idx = (int)idx;
+ }
+ } else if (confirmed_idx) {
+ /* This state has been written by an older Tor version which did not have
+ * sample ordering */
+
+ guard->sampled_idx = guard->confirmed_idx;
+ } else {
+ log_warn(LD_GUARD, "The state file seems to be into a status that could"
+ " yield to weird entry node selection: we're missing both a"
+ " sampled_idx and a confirmed_idx.");
+ guard->sampled_idx = invalid_sampled_idx++;
+ }
+
/* Anything we didn't recognize gets crammed together */
if (smartlist_len(extra) > 0) {
guard->extra_state_fields = smartlist_join_strings(extra, " ", 0, NULL);
@@ -3098,6 +3199,7 @@ entry_guard_parse_from_state(const char *s)
tor_free(listed);
tor_free(confirmed_on);
tor_free(confirmed_idx);
+ tor_free(sampled_idx);
tor_free(bridge_addr);
tor_free(pb_use_attempts);
tor_free(pb_use_successes);
@@ -3127,13 +3229,15 @@ entry_guards_update_guards_in_state(or_state_t *state)
config_line_t **nextline = &lines;
SMARTLIST_FOREACH_BEGIN(guard_contexts, guard_selection_t *, gs) {
+ int i = 0;
SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, guard) {
if (guard->is_persistent == 0)
continue;
*nextline = tor_malloc_zero(sizeof(config_line_t));
(*nextline)->key = tor_strdup("Guard");
- (*nextline)->value = entry_guard_encode_for_state(guard);
+ (*nextline)->value = entry_guard_encode_for_state(guard, i);
nextline = &(*nextline)->next;
+ i++;
} SMARTLIST_FOREACH_END(guard);
} SMARTLIST_FOREACH_END(gs);
@@ -3186,6 +3290,14 @@ entry_guards_load_guards_from_state(or_state_t *state, int set)
tor_assert(gs);
smartlist_add(gs->sampled_entry_guards, guard);
guard->in_selection = gs;
+ /* Recompute the next_sampled_id from the state. We do not assume that
+ * sampled guards appear in the correct order within the file, and we
+ * need to know what would be the next sampled idx to give to any
+ * new sampled guard (i.e., max of guard->sampled_idx + 1)*/
+ if (gs->next_sampled_idx <= guard->sampled_idx) {
+ gs->next_sampled_idx = guard->sampled_idx + 1;
+ }
+
} else {
entry_guard_free(guard);
}
@@ -3193,6 +3305,10 @@ entry_guards_load_guards_from_state(or_state_t *state, int set)
if (set) {
SMARTLIST_FOREACH_BEGIN(guard_contexts, guard_selection_t *, gs) {
+ /** Guards should be in sample order within the file, but it is maybe
+ * better NOT to assume that. Let's order them before updating lists
+ */
+ smartlist_sort(gs->sampled_entry_guards, compare_guards_by_sampled_idx);
entry_guards_update_all(gs);
} SMARTLIST_FOREACH_END(gs);
}
diff --git a/src/feature/client/entrynodes.h b/src/feature/client/entrynodes.h
index 6eede2c8d4..4b236dc80c 100644
--- a/src/feature/client/entrynodes.h
+++ b/src/feature/client/entrynodes.h
@@ -117,6 +117,13 @@ struct entry_guard_t {
* confirmed guard. */
time_t confirmed_on_date; /* 0 if not confirmed */
/**
+ * In what order was this guard sampled? Guards with
+ * lower indices appear earlier on the sampled list, the confirmed list and
+ * the primary list as a result of Prop 310
+ */
+ int sampled_idx;
+
+ /**
* In what order was this guard confirmed? Guards with lower indices
* appear earlier on the confirmed list. If the confirmed list is compacted,
* this field corresponds to the index of this guard on the confirmed list.
@@ -242,8 +249,9 @@ struct guard_selection_t {
* Ordered list (from highest to lowest priority) of guards that we
* have successfully contacted and decided to use. Every member of
* this list is a member of sampled_entry_guards. Every member should
- * have confirmed_on_date set, and have confirmed_idx greater than
- * any earlier member of the list.
+ * have confirmed_on_date set.
+ * The ordering of the list should be by sampled idx. The reasoning behind
+ * it is linked to Proposal 310.
*
* This list is persistent. It is a subset of the elements in
* sampled_entry_guards, and its pointers point to elements of
@@ -271,6 +279,12 @@ struct guard_selection_t {
* confirmed_entry_guards receive? */
int next_confirmed_idx;
+ /** What sampled_idx value should the next-added member of
+ * sampled_entry_guards receive? This should follow the size of the sampled
+ * list until sampled relays get pruned for some reason
+ */
+ int next_sampled_idx;
+
};
struct entry_guard_handle_t;
@@ -515,7 +529,8 @@ MOCK_DECL(STATIC circuit_guard_state_t *,
STATIC entry_guard_t *entry_guard_add_to_sample(guard_selection_t *gs,
const node_t *node);
STATIC entry_guard_t *entry_guards_expand_sample(guard_selection_t *gs);
-STATIC char *entry_guard_encode_for_state(entry_guard_t *guard);
+STATIC char *entry_guard_encode_for_state(entry_guard_t *guard, int
+ dense_sampled_index);
STATIC entry_guard_t *entry_guard_parse_from_state(const char *s);
#define entry_guard_free(e) \
FREE_AND_NULL(entry_guard_t, entry_guard_free_, (e))
@@ -523,7 +538,7 @@ STATIC void entry_guard_free_(entry_guard_t *e);
STATIC void entry_guards_update_filtered_sets(guard_selection_t *gs);
STATIC int entry_guards_all_primary_guards_are_down(guard_selection_t *gs);
/**
- * @name Flags for sample_reachable_filtered_entry_guards()
+ * @name Flags for first_reachable_filtered_entry_guard()
*/
/**@{*/
#define SAMPLE_EXCLUDE_CONFIRMED (1u<<0)
@@ -532,7 +547,7 @@ STATIC int entry_guards_all_primary_guards_are_down(guard_selection_t *gs);
#define SAMPLE_NO_UPDATE_PRIMARY (1u<<3)
#define SAMPLE_EXCLUDE_NO_DESCRIPTOR (1u<<4)
/**@}*/
-STATIC entry_guard_t *sample_reachable_filtered_entry_guards(
+STATIC entry_guard_t *first_reachable_filtered_entry_guard(
guard_selection_t *gs,
const entry_guard_restriction_t *rst,
unsigned flags);
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..a8926c0b79 100644
--- a/src/feature/control/control_cmd.c
+++ b/src/feature/control/control_cmd.c
@@ -20,9 +20,12 @@
#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"
+#include "feature/control/control_events.h"
#include "feature/control/control.h"
#include "feature/control/control_auth.h"
#include "feature/control/control_cmd.h"
@@ -55,6 +58,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);
@@ -1396,6 +1401,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 +1463,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 +2364,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..8e69c772f6 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
diff --git a/src/feature/control/control_events.h b/src/feature/control/control_events.h
index 4a5492b510..0c8448e0f8 100644
--- a/src/feature/control/control_events.h
+++ b/src/feature/control/control_events.h
@@ -223,6 +223,8 @@ 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);
void control_events_free_all(void);
diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c
index 0823acbe07..3e4feadded 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"
@@ -131,12 +132,13 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
} 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) {
+ 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, "traffic/read")) {
tor_asprintf(answer, "%"PRIu64, (get_bytes_read()));
@@ -1278,15 +1280,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 +1442,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
@@ -1661,6 +1699,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/control/control_hs.c b/src/feature/control/control_hs.c
index f5b331de9a..c8de03b318 100644
--- a/src/feature/control/control_hs.c
+++ b/src/feature/control/control_hs.c
@@ -291,7 +291,8 @@ handle_control_onion_client_auth_view(control_connection_t *conn,
if (argc >= 1) {
hsaddress = smartlist_get(args->args, 0);
if (!hs_address_is_valid(hsaddress)) {
- control_printf_endreply(conn, 512, "Invalid v3 addr \"%s\"", hsaddress);
+ control_printf_endreply(conn, 512, "Invalid v3 address \"%s\"",
+ hsaddress);
goto err;
}
}
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 a1a530b7fa..080edd92f1 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;
@@ -4220,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
@@ -4276,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;
@@ -4287,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);
@@ -4464,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;
@@ -4493,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) {
@@ -4680,9 +4681,9 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
/* These are hardwired, to avoid disaster. */
v3_out->recommended_relay_protocols =
- tor_strdup(DIRVOTE_RECCOMEND_RELAY_PROTO);
+ tor_strdup(DIRVOTE_RECOMMEND_RELAY_PROTO);
v3_out->recommended_client_protocols =
- tor_strdup(DIRVOTE_RECCOMEND_CLIENT_PROTO);
+ tor_strdup(DIRVOTE_RECOMMEND_CLIENT_PROTO);
v3_out->required_relay_protocols =
tor_strdup(DIRVOTE_REQUIRE_RELAY_PROTO);
@@ -4723,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 3ab40367ae..9cc87489b4 100644
--- a/src/feature/dirauth/dirvote.h
+++ b/src/feature/dirauth/dirvote.h
@@ -242,15 +242,15 @@ STATIC microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri,
/** The recommended relay protocols for this authority's votes.
* Recommending a new protocol causes old tor versions to log a warning.
*/
-#define DIRVOTE_RECCOMEND_RELAY_PROTO \
- "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " \
- "Link=4 Microdesc=1-2 Relay=2"
+#define DIRVOTE_RECOMMEND_RELAY_PROTO \
+ "Cons=1-2 Desc=1-2 DirCache=2 HSDir=2 HSIntro=4 HSRend=2 " \
+ "Link=5 LinkAuth=3 Microdesc=1-2 Relay=2"
/** The recommended client protocols for this authority's votes.
* Recommending a new protocol causes old tor versions to log a warning.
*/
-#define DIRVOTE_RECCOMEND_CLIENT_PROTO \
- "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " \
- "Link=4 Microdesc=1-2 Relay=2"
+#define DIRVOTE_RECOMMEND_CLIENT_PROTO \
+ "Cons=1-2 Desc=1-2 DirCache=2 HSDir=2 HSIntro=4 HSRend=2 " \
+ "Link=5 LinkAuth=3 Microdesc=1-2 Relay=2"
/** The required relay protocols for this authority's votes.
* WARNING: Requiring a new protocol causes old tor versions to shut down.
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..337fa4c965 100644
--- a/src/feature/dirclient/dirclient.c
+++ b/src/feature/dirclient/dirclient.c
@@ -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) {
@@ -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);
}
}
@@ -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..d4bcdae973 100644
--- a/src/feature/dirparse/ns_parse.c
+++ b/src/feature/dirparse/ns_parse.c
@@ -384,12 +384,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);
@@ -563,7 +563,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);
}
}
@@ -1354,8 +1354,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 +1367,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;
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 c3697d0c1d..23768213f3 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"
@@ -704,8 +705,11 @@ send_introduce1(origin_circuit_t *intro_circ,
}
/** Using the introduction circuit circ, setup the authentication key of the
- * intro point this circuit has extended to. */
-static void
+ * intro point this circuit has extended to.
+ *
+ * Return 0 if everything went well, otherwise return -1 in the case of errors.
+ */
+static int
setup_intro_circ_auth_key(origin_circuit_t *circ)
{
const hs_descriptor_t *desc;
@@ -719,27 +723,28 @@ setup_intro_circ_auth_key(origin_circuit_t *circ)
* and the client descriptor cache that gets purged (NEWNYM) or the
* cleaned up because it expired. Mark the circuit for close so a new
* descriptor fetch can occur. */
- circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
- goto end;
+ goto err;
}
/* We will go over every intro point and try to find which one is linked to
* that circuit. Those lists are small so it's not that expensive. */
ip = find_desc_intro_point_by_legacy_id(
circ->build_state->chosen_exit->identity_digest, desc);
- if (ip) {
- /* We got it, copy its authentication key to the identifier. */
- ed25519_pubkey_copy(&circ->hs_ident->intro_auth_pk,
- &ip->auth_key_cert->signed_key);
- goto end;
+ if (!ip) {
+ /* Reaching this point means we didn't find any intro point for this
+ * circuit which is not supposed to happen. */
+ log_info(LD_REND,"Could not match opened intro circuit with intro point.");
+ goto err;
}
- /* Reaching this point means we didn't find any intro point for this circuit
- * which is not supposed to happen. */
- tor_assert_nonfatal_unreached();
+ /* We got it, copy its authentication key to the identifier. */
+ ed25519_pubkey_copy(&circ->hs_ident->intro_auth_pk,
+ &ip->auth_key_cert->signed_key);
+ return 0;
- end:
- return;
+ err:
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
+ return -1;
}
/** Called when an introduction circuit has opened. */
@@ -754,7 +759,9 @@ client_intro_circ_has_opened(origin_circuit_t *circ)
/* This is an introduction circuit so we'll attach the correct
* authentication key to the circuit identifier so it can be identified
* properly later on. */
- setup_intro_circ_auth_key(circ);
+ if (setup_intro_circ_auth_key(circ) < 0) {
+ return;
+ }
connection_ap_attach_pending(1);
}
@@ -1059,8 +1066,10 @@ close_or_reextend_intro_circ(origin_circuit_t *intro_circ)
tor_assert(intro_circ);
desc = hs_cache_lookup_as_client(&intro_circ->hs_ident->identity_pk);
- if (BUG(desc == NULL)) {
- /* We can't continue without a descriptor. */
+ if (desc == NULL) {
+ /* We can't continue without a descriptor. This is possible if the cache
+ * was cleaned up between the intro point established and the reception of
+ * the introduce ack. */
goto close;
}
/* We still have the descriptor, great! Let's try to see if we can
@@ -1545,9 +1554,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..706b42529f 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"
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index a42879a48f..b56b7f4368 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"
@@ -2873,6 +2874,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 +3904,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/nodelist/authcert.c b/src/feature/nodelist/authcert.c
index 97e44d53e3..26713d7149 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;
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..a7c02f64d8 100644
--- a/src/feature/nodelist/node_select.c
+++ b/src/feature/nodelist/node_select.c
@@ -217,13 +217,15 @@ router_picked_poor_directory_log(const routerstatus_t *rs)
) {
/* 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;
@@ -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;
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..c30684d2d8 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);
@@ -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';
}
@@ -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 */
}
@@ -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 80c1aa6893..72824f2dd2 100644
--- a/src/feature/nodelist/routerlist.c
+++ b/src/feature/nodelist/routerlist.c
@@ -465,11 +465,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 +486,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 +506,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
+ * fascist_firewall_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 &&
+ !fascist_firewall_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))
+ if (!router_can_choose_node(node, flags))
continue;
- /* Don't choose nodes if we are certain they can't do EXTEND2 cells */
- if (node->rs && !routerstatus_version_supports_extend2_cells(node->rs, 1))
- continue;
- /* Don't choose nodes if we are certain they can't do ntor. */
- if ((node->ri || node->md) && !node_has_curve25519_onion_key(node))
- continue;
- /* Choose a node with an OR address that matches the firewall rules */
- if (direct_conn && check_reach &&
- !fascist_firewall_allows_node(node,
- FIREWALL_OR_CONNECTION,
- pref_addr))
- continue;
-
smartlist_add(sl, (void *)node);
} SMARTLIST_FOREACH_END(node);
}
@@ -1088,7 +1171,11 @@ extrainfo_insert,(routerlist_t *rl, extrainfo_t *ei, int warn_if_incompatible))
* This just won't work. */;
static ratelim_t no_sd_ratelim = RATELIM_INIT(1800);
r = ROUTER_BAD_EI;
- log_fn_ratelim(&no_sd_ratelim, severity, LD_BUG,
+ /* This is a DEBUG because it can happen naturally, if we tried
+ * to add an extrainfo for which we no longer have the
+ * corresponding routerinfo.
+ */
+ log_fn_ratelim(&no_sd_ratelim, LOG_DEBUG, LD_DIR,
"No entry found in extrainfo map.");
goto done;
}
@@ -2878,12 +2965,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/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c
index b89866b477..ad20e143be 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;
@@ -542,7 +591,11 @@ onionskin_answer(struct or_circuit_t *circ,
/* 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();
+ tor_addr_t remote_addr;
+ if (channel_get_addr_if_possible(circ->p_chan, &remote_addr)) {
+ int family = tor_addr_family(&remote_addr);
+ 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..9273a7cef0 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,96 @@ port_warn_nonlocal_ext_orports(const smartlist_t *ports, const char *portname)
} SMARTLIST_FOREACH_END(port);
}
+/** 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%d",
+ type, addr, (strlen(addr) > 0) ? ":" : "", 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)
+{
+ for (int i = 0; i < smartlist_len(ports); ++i) {
+ port_cfg_t *current = smartlist_get(ports, i);
+
+ /* Skip non ORPorts. */
+ if (current->type != CONN_TYPE_OR_LISTENER) {
+ continue;
+ }
+
+ for (int j = 0; j < smartlist_len(ports); ++j) {
+ port_cfg_t *next = smartlist_get(ports, j);
+
+ /* Avoid comparing the same object. */
+ if (current == next) {
+ 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. */
+ smartlist_del_keeporder(ports, i--);
+ 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);
+ port_cfg_free(current);
+ }
+ }
+ }
+}
+
/** 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 +243,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 +358,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 +382,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;
}
@@ -1029,7 +1125,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 +1210,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 +1403,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 +1433,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_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 08ad110cf6..cc346bc3fc 100644
--- a/src/feature/relay/relay_periodic.c
+++ b/src/feature/relay/relay_periodic.c
@@ -201,36 +201,60 @@ 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) {
+ 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" : "";
+
log_warn(LD_CONFIG,
- "Your server (%s:%d) has not managed to confirm that "
- "its ORPort is reachable. Relays do not publish descriptors "
+ "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.",
- address, me->or_port);
- control_event_server_status(LOG_WARN,
- "REACHABILITY_FAILED ORADDRESS=%s:%d",
- address, me->or_port);
- tor_free(address);
+ 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 ffaf7c3cc5..206545bdec 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"
@@ -831,30 +833,37 @@ 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;
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;
+ }
}
}
@@ -865,15 +874,17 @@ router_write_fingerprint(int hashed)
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 " : "");
+ 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:
@@ -1109,15 +1120,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 +1150,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 +1306,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 +1353,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 +1390,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 +1459,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. */
-uint16_t
-router_get_advertised_or_port(const or_options_t *options)
-{
- return router_get_advertised_or_port_by_af(options, AF_INET);
-}
-
-/** As router_get_advertised_or_port(), but allows an address family argument.
- */
+/** 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_by_af(const or_options_t *options,
- sa_family_t family)
+routerconf_find_or_port(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 +1479,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 +1494,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 +1524,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 +1568,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)
@@ -1704,16 +1756,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 +1811,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 +1868,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 +2025,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 +2086,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 +2107,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 +2397,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 +2424,24 @@ 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;
+}
+
/** 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 +2500,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 +2545,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 +2589,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 routerinfo_t *my_ri = router_get_my_routerinfo();
const char *method = NULL;
char *hostname = NULL;
- const routerinfo_t *my_ri = router_get_my_routerinfo();
+ 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",
+ method ? method : "UNKNOWN",
+ 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
@@ -2783,7 +2865,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 +2889,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,
@@ -3133,7 +3215,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..c4e9af039f 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,6 +80,7 @@ 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);
@@ -124,7 +124,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/selftest.c b/src/feature/relay/selftest.c
index 18fe25b989..d24748b297 100644
--- a/src/feature/relay/selftest.c
+++ b/src/feature/relay/selftest.c
@@ -15,38 +15,53 @@
#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;
/** 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;
}
/** Return 1 if we won't do reachability checks, because:
@@ -68,13 +83,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 +132,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 +152,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 +171,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 +223,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 +236,78 @@ 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));
+ if (!orport_reachable) {
+ /* This is only a 'reachability test' if we don't already think that
+ * the port is reachable. If we _do_ think it's reachable, then
+ * it counts as a 'bandwidth test'. */
+ 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,104 +324,104 @@ 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 @a is_dirport is true, then the port is a DirPort; otherwise it is an
+ * ORPort. */
+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;
+ 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 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);
- }
- 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;
+ "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);
+}
+
+/**
+ * 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)
+ 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;
+ address,
+ ready_to_publish(options) ?
+ " Publishing server descriptor." : "");
+
mark_my_descriptor_dirty("ORPort found reachable");
/* This is a significant enough change to upload immediately,
* at least in a test network */
@@ -276,8 +429,8 @@ router_orport_found_reachable(void)
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 +441,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 +464,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/rendclient.c b/src/feature/rend/rendclient.c
index 09db7045fa..e171562d17 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 a88c2080fd..1ac88d0eb7 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"
@@ -132,6 +133,22 @@ static smartlist_t *rend_service_list = NULL;
* service on config reload. */
static smartlist_t *rend_service_staging_list = NULL;
+/** Helper: log the deprecation warning for version 2 only once. */
+static void
+log_once_deprecation_warning(void)
+{
+ static bool logged_once = false;
+ if (!logged_once) {
+ log_warn(LD_REND, "DEPRECATED: Onion service version 2 are deprecated. "
+ "Please use version 3 which is the default now. "
+ "Currently, version 2 is planned to be obsolete in "
+ "the Tor version 0.4.6 stable series.");
+ logged_once = true;
+ }
+}
+/** Macro to make it very explicit that we are warning about deprecation. */
+#define WARN_ONCE_DEPRECATION() log_once_deprecation_warning()
+
/* Like rend_get_service_list_mutable, but returns a read-only list. */
static const smartlist_t*
rend_get_service_list(const smartlist_t* substitute_service_list)
@@ -731,6 +748,9 @@ rend_config_service(const hs_opts_t *hs_opts,
tor_assert(hs_opts);
tor_assert(config);
+ /* We are about to configure a version 2 service. Warn of deprecation. */
+ WARN_ONCE_DEPRECATION();
+
/* Use the staging service list so that we can check then do the pruning
* process using the main list at the end. */
if (rend_service_staging_list == NULL) {
@@ -1831,8 +1851,11 @@ rend_service_use_direct_connection(const or_options_t* options,
/* We'll connect directly all reachable addresses, whether preferred or not.
* The prefer_ipv6 argument to fascist_firewall_allows_address_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,
+ fascist_firewall_allows_address_addr(&ap->addr, ap->port,
FIREWALL_OR_CONNECTION, 0, 0));
}
@@ -2261,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.");
@@ -2530,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,
@@ -3714,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 "
@@ -3725,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);
}
@@ -3820,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/bwhist.c b/src/feature/stats/bwhist.c
new file mode 100644
index 0000000000..e74a2881f5
--- /dev/null
+++ b/src/feature/stats/bwhist.c
@@ -0,0 +1,592 @@
+/* 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 "app/config/or_state_st.h"
+#include "app/config/or_options_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];
+};
+
+/** 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));
+ 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;
+ }
+
+ 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..d556f5a026
--- /dev/null
+++ b/src/feature/stats/bwhist.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 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);
+#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..bc13882f4b 100644
--- a/src/feature/stats/include.am
+++ b/src/feature/stats/include.am
@@ -1,12 +1,16 @@
# 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/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/evloop/timers.c b/src/lib/evloop/timers.c
index 7be9bae08e..11418e93fd 100644
--- a/src/lib/evloop/timers.c
+++ b/src/lib/evloop/timers.c
@@ -11,7 +11,7 @@
* The main advantage of tor_timer_t over using libevent's timers is that
* they're way more efficient if we need to have thousands or millions of
* them. For more information, see
- * http://www.25thandclement.com/~william/projects/timeout.c.html
+ * https://www.25thandclement.com/~william/projects/timeout.c.html
*
* Periodic timers are available in the backend, but I've turned them off.
* We can turn them back on if needed.
diff --git a/src/lib/fs/files.c b/src/lib/fs/files.c
index aeaeb5daea..a0b5a40aac 100644
--- a/src/lib/fs/files.c
+++ b/src/lib/fs/files.c
@@ -607,6 +607,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 +688,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 +697,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 +709,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));
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/math/laplace.c b/src/lib/math/laplace.c
index 5c1d686a9c..a0e67384e6 100644
--- a/src/lib/math/laplace.c
+++ b/src/lib/math/laplace.c
@@ -29,7 +29,7 @@ sample_laplace_distribution(double mu, double b, double p)
tor_assert(p >= 0.0 && p < 1.0);
/* This is the "inverse cumulative distribution function" from:
- * http://en.wikipedia.org/wiki/Laplace_distribution */
+ * https://en.wikipedia.org/wiki/Laplace_distribution */
if (p <= 0.0) {
/* Avoid taking log(0.0) == -INFINITY, as some processors or compiler
* options can cause the program to trap. */
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/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/restrict.c b/src/lib/process/restrict.c
index a3ce52deaa..cd2a1c57b5 100644
--- a/src/lib/process/restrict.c
+++ b/src/lib/process/restrict.c
@@ -85,7 +85,7 @@ tor_set_max_memlock(void)
{
/* Future consideration for Windows is probably SetProcessWorkingSetSize
* This is similar to setting the memory rlimit of RLIMIT_MEMLOCK
- * http://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx
+ * https://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx
*/
struct rlimit limit;
@@ -128,7 +128,7 @@ tor_mlockall(void)
* Future consideration for Windows may be VirtualLock
* VirtualLock appears to implement mlock() but not mlockall()
*
- * http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx
+ * https://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx
*/
#ifdef HAVE_UNIX_MLOCKALL
@@ -190,7 +190,7 @@ set_max_file_descriptors(rlim_t limit, int *max_out)
/* Define some maximum connections values for systems where we cannot
* automatically determine a limit. Re Cygwin, see
- * http://archives.seul.org/or/talk/Aug-2006/msg00210.html
+ * https://archives.seul.org/or/talk/Aug-2006/msg00210.html
* For an iPhone, 9999 should work. For Windows and all other unknown
* systems we use 15000 as the default. */
#ifndef HAVE_GETRLIMIT
diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c
index b917912f4d..a6eea9daca 100644
--- a/src/lib/sandbox/sandbox.c
+++ b/src/lib/sandbox/sandbox.c
@@ -117,6 +117,10 @@
#endif /* defined(__i386__) || ... */
+#ifdef M_SYSCALL
+#define SYSCALL_NAME_DEBUGGING
+#endif
+
/**Determines if at least one sandbox is active.*/
static int sandbox_active = 0;
/** Holds the parameter list configuration for the sandbox.*/
@@ -133,6 +137,10 @@ static sandbox_cfg_t *filter_dynamic = NULL;
* the high bits of the value might get masked out improperly. */
#define SCMP_CMP_MASKED(a,b,c) \
SCMP_CMP4((a), SCMP_CMP_MASKED_EQ, ~(scmp_datum_t)(b), (c))
+/* For negative constants, the rule to add depends on the glibc version. */
+#define SCMP_CMP_NEG(a,op,b) (libc_negative_constant_needs_cast() ? \
+ (SCMP_CMP((a), (op), (unsigned int)(b))) : \
+ (SCMP_CMP_STR((a), (op), (b))))
/** Variable used for storing all syscall numbers that will be allowed with the
* stage 1 general Tor sandbox.
@@ -275,9 +283,18 @@ static int filter_nopar_gen[] = {
SCMP_SYS(recvfrom),
SCMP_SYS(sendto),
SCMP_SYS(unlink),
+#ifdef __NR_unlinkat
+ SCMP_SYS(unlinkat),
+#endif
SCMP_SYS(poll)
};
+/* opendir is not a syscall but it will use either open or openat. We do not
+ * want the decision to allow open/openat to be the callers reponsability, so
+ * we create a phony syscall number for opendir and sb_opendir will choose the
+ * correct syscall. */
+#define PHONY_OPENDIR_SYSCALL -2
+
/* These macros help avoid the error where the number of filters we add on a
* single rule don't match the arg_cnt param. */
#define seccomp_rule_add_0(ctx,act,call) \
@@ -431,31 +448,59 @@ sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
#endif
#endif
-/* Return true if we think we're running with a libc that always uses
- * openat on linux. */
+/* Return true the libc version is greater or equal than
+ * <b>major</b>.<b>minor</b>. Returns false otherwise. */
static int
-libc_uses_openat_for_everything(void)
+is_libc_at_least(int major, int minor)
{
#ifdef CHECK_LIBC_VERSION
const char *version = gnu_get_libc_version();
if (version == NULL)
return 0;
- int major = -1;
- int minor = -1;
+ int libc_major = -1;
+ int libc_minor = -1;
- tor_sscanf(version, "%d.%d", &major, &minor);
- if (major >= 3)
+ tor_sscanf(version, "%d.%d", &libc_major, &libc_minor);
+ if (libc_major > major)
return 1;
- else if (major == 2 && minor >= 26)
+ else if (libc_major == major && libc_minor >= minor)
return 1;
else
return 0;
#else /* !defined(CHECK_LIBC_VERSION) */
+ (void)major;
+ (void)minor;
return 0;
#endif /* defined(CHECK_LIBC_VERSION) */
}
+/* Return true if we think we're running with a libc that uses openat for the
+ * open function on linux. */
+static int
+libc_uses_openat_for_open(void)
+{
+ return is_libc_at_least(2, 26);
+}
+
+/* Return true if we think we're running with a libc that uses openat for the
+ * opendir function on linux. */
+static int
+libc_uses_openat_for_opendir(void)
+{
+ // libc 2.27 and above or between 2.15 (inclusive) and 2.22 (exclusive)
+ return is_libc_at_least(2, 27) ||
+ (is_libc_at_least(2, 15) && !is_libc_at_least(2, 22));
+}
+
+/* Return true if we think we're running with a libc that needs to cast
+ * negative arguments like AT_FDCWD for seccomp rules. */
+static int
+libc_negative_constant_needs_cast(void)
+{
+ return is_libc_at_least(2, 27);
+}
+
/** Allow a single file to be opened. If <b>use_openat</b> is true,
* we're using a libc that remaps all the opens into openats. */
static int
@@ -463,7 +508,7 @@ allow_file_open(scmp_filter_ctx ctx, int use_openat, const char *file)
{
if (use_openat) {
return seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat),
- SCMP_CMP(0, SCMP_CMP_EQ, (unsigned int)AT_FDCWD),
+ SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD),
SCMP_CMP_STR(1, SCMP_CMP_EQ, file));
} else {
return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open),
@@ -481,7 +526,7 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
int rc;
sandbox_cfg_t *elem = NULL;
- int use_openat = libc_uses_openat_for_everything();
+ int use_openat = libc_uses_openat_for_open();
// for each dynamic parameter filters
for (elem = filter; elem != NULL; elem = elem->next) {
@@ -599,7 +644,7 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
if (param != NULL && param->prot == 1 && param->syscall
== SCMP_SYS(openat)) {
rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat),
- SCMP_CMP(0, SCMP_CMP_EQ, AT_FDCWD),
+ SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD),
SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value),
SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|
O_CLOEXEC));
@@ -614,6 +659,38 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
return 0;
}
+static int
+sb_opendir(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
+{
+ int rc;
+ sandbox_cfg_t *elem = NULL;
+
+ // for each dynamic parameter filters
+ for (elem = filter; elem != NULL; elem = elem->next) {
+ smp_param_t *param = elem->param;
+
+ if (param != NULL && param->prot == 1 && param->syscall
+ == PHONY_OPENDIR_SYSCALL) {
+ if (libc_uses_openat_for_opendir()) {
+ rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat),
+ SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD),
+ SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value),
+ SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE|
+ O_DIRECTORY|O_CLOEXEC));
+ } else {
+ rc = allow_file_open(ctx, 0, param->value);
+ }
+ if (rc != 0) {
+ log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received "
+ "libseccomp error %d", rc);
+ return rc;
+ }
+ }
+ }
+
+ return 0;
+}
+
/**
* Function responsible for setting up the socket syscall for
* the seccomp filter sandbox.
@@ -928,7 +1005,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)
@@ -1128,6 +1205,7 @@ static sandbox_filter_func_t filter_func[] = {
sb_chmod,
sb_open,
sb_openat,
+ sb_opendir,
sb_rename,
#ifdef __NR_fcntl64
sb_fcntl64,
@@ -1447,6 +1525,19 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file)
return 0;
}
+int
+sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir)
+{
+ sandbox_cfg_t *elem = NULL;
+
+ elem = new_element(PHONY_OPENDIR_SYSCALL, dir);
+
+ elem->next = *cfg;
+ *cfg = elem;
+
+ return 0;
+}
+
/**
* Function responsible for going through the parameter syscall filters and
* call each function pointer in the list.
@@ -1545,8 +1636,10 @@ install_syscall_filter(sandbox_cfg_t* cfg)
return (rc < 0 ? -rc : rc);
}
+#ifdef SYSCALL_NAME_DEBUGGING
#include "lib/sandbox/linux_syscalls.inc"
+/** Return a string containing the name of a given syscall (if we know it) */
static const char *
get_syscall_name(int syscall_num)
{
@@ -1564,6 +1657,28 @@ get_syscall_name(int syscall_num)
}
}
+/** Return the syscall number from a ucontext_t that we got in a signal
+ * handler (if we know how to do that). */
+static int
+get_syscall_from_ucontext(const ucontext_t *ctx)
+{
+ return (int) ctx->uc_mcontext.M_SYSCALL;
+}
+#else
+static const char *
+get_syscall_name(int syscall_num)
+{
+ (void) syscall_num;
+ return "unknown";
+}
+static int
+get_syscall_from_ucontext(const ucontext_t *ctx)
+{
+ (void) ctx;
+ return -1;
+}
+#endif
+
#ifdef USE_BACKTRACE
#define MAX_DEPTH 256
static void *syscall_cb_buf[MAX_DEPTH];
@@ -1579,7 +1694,6 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context)
{
ucontext_t *ctx = (ucontext_t *) (void_context);
const char *syscall_name;
- int syscall;
#ifdef USE_BACKTRACE
size_t depth;
int n_fds, i;
@@ -1594,7 +1708,7 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context)
if (!ctx)
return;
- syscall = (int) ctx->uc_mcontext.M_SYSCALL;
+ int syscall = get_syscall_from_ucontext(ctx);
#ifdef USE_BACKTRACE
depth = backtrace(syscall_cb_buf, MAX_DEPTH);
@@ -1752,6 +1866,13 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file)
}
int
+sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir)
+{
+ (void)cfg; (void)dir;
+ return 0;
+}
+
+int
sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file)
{
(void)cfg; (void)file;
diff --git a/src/lib/sandbox/sandbox.h b/src/lib/sandbox/sandbox.h
index b50df48255..a2b3227b90 100644
--- a/src/lib/sandbox/sandbox.h
+++ b/src/lib/sandbox/sandbox.h
@@ -136,6 +136,13 @@ int sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2);
int sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file);
/**
+ * Function used to add a opendir allowed filename to a supplied configuration.
+ * The (char*) specifies the path to the allowed dir; we steal the pointer to
+ * that dir.
+ */
+int sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir);
+
+/**
* Function used to add a stat/stat64 allowed filename to a configuration.
* The (char*) specifies the path to the allowed file; that pointer is stolen.
*/
diff --git a/src/lib/tls/buffers_tls.c b/src/lib/tls/buffers_tls.c
index b92a14d6a1..1b99467d2b 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;
}
diff --git a/src/lib/tls/tortls.h b/src/lib/tls/tortls.h
index e8dbbf5279..517cdc17dd 100644
--- a/src/lib/tls/tortls.h
+++ b/src/lib/tls/tortls.h
@@ -81,6 +81,7 @@ void tor_tls_free_all(void);
void tor_tls_init(void);
void tls_log_errors(tor_tls_t *tls, int severity, int domain,
const char *doing);
+const char *tor_tls_get_last_error_msg(const tor_tls_t *tls);
int tor_tls_context_init(unsigned flags,
crypto_pk_t *client_identity,
crypto_pk_t *server_identity,
diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c
index 62e8262115..c873367f6f 100644
--- a/src/lib/tls/tortls_nss.c
+++ b/src/lib/tls/tortls_nss.c
@@ -369,6 +369,8 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain,
(void)tls;
PRErrorCode code = PORT_GetError();
+ if (tls)
+ tls->last_error = code;
const char *addr = tls ? tls->address : NULL;
const char *string = PORT_ErrorToString(code);
@@ -391,6 +393,17 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain,
with, addr);
}
}
+const char *
+tor_tls_get_last_error_msg(const tor_tls_t *tls)
+{
+ IF_BUG_ONCE(!tls) {
+ return NULL;
+ }
+ if (tls->last_error == 0) {
+ return NULL;
+ }
+ return PORT_ErrorToString((PRErrorCode)tls->last_error);
+}
tor_tls_t *
tor_tls_new(tor_socket_t sock, int is_server)
@@ -418,6 +431,16 @@ tor_tls_new(tor_socket_t sock, int is_server)
return NULL;
}
+ /* even if though the socket is already nonblocking, we need to tell NSS
+ * about the fact, so that it knows what to do when it says EAGAIN. */
+ PRSocketOptionData data;
+ data.option = PR_SockOpt_Nonblocking;
+ data.value.non_blocking = 1;
+ if (PR_SetSocketOption(ssl, &data) != PR_SUCCESS) {
+ PR_Close(ssl);
+ return NULL;
+ }
+
tor_tls_t *tls = tor_malloc_zero(sizeof(tor_tls_t));
tls->magic = TOR_TLS_MAGIC;
tls->context = ctx;
@@ -713,23 +736,58 @@ MOCK_IMPL(int,
tor_tls_cert_matches_key,(const tor_tls_t *tls,
const struct tor_x509_cert_t *cert))
{
- tor_assert(tls);
tor_assert(cert);
+ tor_assert(cert->cert);
+
int rv = 0;
- CERTCertificate *peercert = SSL_PeerCertificate(tls->ssl);
- if (!peercert)
+ tor_x509_cert_t *peercert = tor_tls_get_peer_cert((tor_tls_t *)tls);
+
+ if (!peercert || !peercert->cert)
goto done;
- CERTSubjectPublicKeyInfo *peer_info = &peercert->subjectPublicKeyInfo;
+
+ CERTSubjectPublicKeyInfo *peer_info = &peercert->cert->subjectPublicKeyInfo;
CERTSubjectPublicKeyInfo *cert_info = &cert->cert->subjectPublicKeyInfo;
+
+ /* NSS stores the `len` field in bits, instead of bytes, for the
+ * `subjectPublicKey` field in CERTSubjectPublicKeyInfo, but
+ * `SECITEM_ItemsAreEqual()` compares the two bitstrings using a length field
+ * defined in bytes.
+ *
+ * We convert the `len` field from bits to bytes, do our comparison with
+ * `SECITEM_ItemsAreEqual()`, and reset the length field from bytes to bits
+ * again.
+ *
+ * See also NSS's own implementation of `SECKEY_CopySubjectPublicKeyInfo()`
+ * in seckey.c in the NSS source tree. This function also does the conversion
+ * between bits and bytes.
+ */
+ const unsigned int peer_info_orig_len = peer_info->subjectPublicKey.len;
+ const unsigned int cert_info_orig_len = cert_info->subjectPublicKey.len;
+
+ /* We convert the length from bits to bytes, but instead of using NSS's
+ * `DER_ConvertBitString()` macro on both of peer_info->subjectPublicKey and
+ * cert_info->subjectPublicKey, we have to do the conversion explicitly since
+ * both of the two subjectPublicKey fields are allowed to point to the same
+ * memory address. Otherwise, the bits to bytes conversion would potentially
+ * be applied twice, which would lead to us comparing too few of the bytes
+ * when we call SECITEM_ItemsAreEqual(), which would be catastrophic.
+ */
+ peer_info->subjectPublicKey.len = ((peer_info_orig_len + 7) >> 3);
+ cert_info->subjectPublicKey.len = ((cert_info_orig_len + 7) >> 3);
+
rv = SECOID_CompareAlgorithmID(&peer_info->algorithm,
&cert_info->algorithm) == 0 &&
SECITEM_ItemsAreEqual(&peer_info->subjectPublicKey,
&cert_info->subjectPublicKey);
+ /* Convert from bytes back to bits. */
+ peer_info->subjectPublicKey.len = peer_info_orig_len;
+ cert_info->subjectPublicKey.len = cert_info_orig_len;
+
done:
- if (peercert)
- CERT_DestroyCertificate(peercert);
+ tor_x509_cert_free(peercert);
+
return rv;
}
diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c
index 68d6e2aa50..2269714141 100644
--- a/src/lib/tls/tortls_openssl.c
+++ b/src/lib/tls/tortls_openssl.c
@@ -245,10 +245,30 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing)
unsigned long err;
while ((err = ERR_get_error()) != 0) {
+ if (tls)
+ tls->last_error = err;
tor_tls_log_one_error(tls, err, severity, domain, doing);
}
}
+/**
+ * Return a string representing more detail about the last error received
+ * on TLS.
+ *
+ * May return null if no error was found.
+ **/
+const char *
+tor_tls_get_last_error_msg(const tor_tls_t *tls)
+{
+ IF_BUG_ONCE(!tls) {
+ return NULL;
+ }
+ if (tls->last_error == 0) {
+ return NULL;
+ }
+ return (const char*)ERR_reason_error_string(tls->last_error);
+}
+
#define CATCH_SYSCALL 1
#define CATCH_ZERO 2
diff --git a/src/lib/tls/tortls_st.h b/src/lib/tls/tortls_st.h
index 925896d493..34abe52ee3 100644
--- a/src/lib/tls/tortls_st.h
+++ b/src/lib/tls/tortls_st.h
@@ -67,6 +67,8 @@ struct tor_tls_t {
*/
unsigned long last_write_count;
unsigned long last_read_count;
+ /** Most recent error value from ERR_get_error(). */
+ unsigned long last_error;
/** If set, a callback to invoke whenever the client tries to renegotiate
* the handshake. */
void (*negotiated_callback)(tor_tls_t *tls, void *arg);
@@ -77,6 +79,7 @@ struct tor_tls_t {
/** Last values retried from tor_get_prfiledesc_byte_counts(). */
uint64_t last_write_count;
uint64_t last_read_count;
+ long last_error;
#endif
};
diff --git a/src/lib/tls/x509.c b/src/lib/tls/x509.c
index 793fa8b9c3..2515499298 100644
--- a/src/lib/tls/x509.c
+++ b/src/lib/tls/x509.c
@@ -23,6 +23,7 @@ tor_tls_pick_certificate_lifetime(time_t now,
time_t *start_time_out,
time_t *end_time_out)
{
+ tor_assert(cert_lifetime < INT_MAX);
time_t start_time, end_time;
/* Make sure we're part-way through the certificate lifetime, rather
* than having it start right now. Don't choose quite uniformly, since
@@ -36,7 +37,7 @@ tor_tls_pick_certificate_lifetime(time_t now,
const time_t start_granularity = 24*3600;
time_t earliest_start_time;
/* Don't actually start in the future! */
- if (cert_lifetime <= min_real_lifetime + start_granularity) {
+ if ((int)cert_lifetime <= min_real_lifetime + start_granularity) {
earliest_start_time = now - 1;
} else {
earliest_start_time = now + min_real_lifetime + start_granularity
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..076cd5301e 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"
)
}
}
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..f3f7202ce2 100644
--- a/src/test/fuzz/include.am
+++ b/src/test/fuzz/include.am
@@ -14,7 +14,7 @@ FUZZING_LIBS = \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @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/include.am b/src/test/include.am
index e7647260c5..d7be1a5f77 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -297,7 +297,7 @@ src_test_test_switch_id_LDADD = \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
@@ -307,7 +307,7 @@ src_test_test_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_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)
@@ -336,7 +336,7 @@ src_test_bench_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_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@
@@ -346,7 +346,7 @@ src_test_test_workqueue_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_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)
@@ -358,7 +358,7 @@ src_test_test_timers_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_LZMA_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_TRACE_LIBS@
src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS)
# ADD_C_FILE: INSERT HEADERS HERE.
@@ -394,7 +394,7 @@ src_test_test_ntor_cl_LDADD = \
$(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@
+ @CURVE25519_LIBS@ @TOR_LZMA_LIBS@ @TOR_TRACE_LIBS@
src_test_test_ntor_cl_AM_CPPFLAGS = \
$(AM_CPPFLAGS)
@@ -403,7 +403,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_GDI@ \
+ @CURVE25519_LIBS@ @TOR_TRACE_LIBS@
src_test_test_hs_ntor_cl_AM_CPPFLAGS = \
$(AM_CPPFLAGS)
@@ -415,7 +416,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_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
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/slow_ed25519.py b/src/test/slow_ed25519.py
index afad678000..be4eeab857 100644
--- a/src/test/slow_ed25519.py
+++ b/src/test/slow_ed25519.py
@@ -1,5 +1,5 @@
# This is the ed25519 implementation from
-# http://ed25519.cr.yp.to/python/ed25519.py .
+# https://ed25519.cr.yp.to/python/ed25519.py .
# It is in the public domain.
#
# It isn't constant-time. Don't use it except for testing. Also, see
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 849cc497fc..c7d4343ede 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"
@@ -157,16 +163,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);
@@ -262,7 +275,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;
@@ -1537,6 +1551,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 },
@@ -1558,5 +1620,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 095eb24c49..121b51e925 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,45 @@ 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); \
+ if (method == NULL) tt_assert(!method_used); \
+ else tt_str_op(method_used, OP_EQ, method); \
+ 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;
+ tor_addr_t resolved_addr, test_addr;
const char *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 +1284,509 @@ 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, "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, "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, "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");
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ /* Looks at specific hostname to learn which address family to use. */
+ MOCK(tor_addr_lookup, tor_addr_lookup_mixed);
- 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);
+ /* 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", "www.torproject.org.v4");
+ tor_free(hostname_out);
- UNMOCK(tor_lookup_hostname);
+ /* 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", "www.torproject.org.v6");
- tor_free(options->Address);
- tor_free(hostname_out);
+ CLEANUP_FOUND_ADDRESS;
+ UNMOCK(tor_addr_lookup);
-/*
- * 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.
- */
+ /*
+ * 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");
- resolved_addr = 0;
- tor_free(options->Address);
- options->Address = NULL;
+ /* Looks at specific hostname to learn which address family to use. */
+ MOCK(tor_addr_lookup, tor_addr_lookup_mixed);
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_01010101);
+ /* 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, "CONFIGURED", NULL);
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_hostname_01010101 = n_hostname_01010101;
+ /* 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", "www.torproject.org.v6");
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ CLEANUP_FOUND_ADDRESS;
+ 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);
+ /*
+ * 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");
- UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
+ /* 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", "www.torproject.org.v4");
tor_free(hostname_out);
-/*
- * CASE 4:
- * Given that options->Address is a local host address, we want
- * resolve_my_address() function to fail.
- */
+ /* 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, "CONFIGURED", NULL);
+ CLEANUP_FOUND_ADDRESS;
- resolved_addr = 0;
- tor_free(options->Address);
- options->Address = tor_strdup("127.0.0.1");
+ UNMOCK(tor_addr_lookup);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ done:
+ config_free_lines(options->Address);
+ or_options_free(options);
+ tor_free(hostname_out);
- tt_want(resolved_addr == 0);
- tt_int_op(retval, OP_EQ, -1);
+ UNMOCK(tor_addr_lookup);
+}
- tor_free(options->Address);
- tor_free(hostname_out);
+/** 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",
+};
-/*
- * CASE 5:
- * We want resolve_my_address() to fail if DNS address in options->Address
- * cannot be resolved.
- */
+static find_my_address_params_t addr_param_v6 = {
+ .idx = 1,
+ .family = AF_INET6,
+ .public_ip = "[4242::4242]",
+ .internal_ip = "[::1]",
+};
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
+static void
+test_config_find_my_address(void *arg)
+{
+ or_options_t *options;
+ tor_addr_t resolved_addr, test_addr;
+ const char *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;
- prev_n_hostname_failure = n_hostname_failure;
+ const find_my_address_params_t *p = arg;
- tor_free(options->Address);
- options->Address = tor_strdup("www.tor-project.org");
+ 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, NULL, NULL);
+ CLEANUP_FOUND_ADDRESS;
+ }
- tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
- 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);
- UNMOCK(tor_lookup_hostname);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tor_free(options->Address);
- tor_free(hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL);
+ CLEANUP_FOUND_ADDRESS;
-/*
- * CASE 6:
- * If options->Address is NULL AND gettting local hostname fails, we want
- * resolve_my_address() to fail as well.
- */
+ /*
+ * Case 2: Address is a resolvable address. Expected to succeed.
+ */
+ MOCK(tor_addr_lookup, tor_addr_lookup_01010101);
- MOCK(tor_gethostname,tor_gethostname_failure);
+ config_line_append(&options->Address, "Address", "www.torproject.org");
+ tor_addr_parse(&test_addr, ret_addr_lookup_01010101[p->idx]);
- prev_n_gethostname_failure = n_gethostname_failure;
+ 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_gethostname_failure == prev_n_gethostname_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", "www.torproject.org");
+ CLEANUP_FOUND_ADDRESS;
- UNMOCK(tor_gethostname);
- tor_free(hostname_out);
+ UNMOCK(tor_addr_lookup);
-/*
- * 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.
- */
+ /*
+ * Case 3: Address is a local addressi (internal). Expected to fail.
+ */
+ config_line_append(&options->Address, "Address", p->internal_ip);
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
- MOCK(get_interface_address,get_interface_address_08080808);
+ setup_full_capture_of_logs(LOG_NOTICE);
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_get_interface_address = n_get_interface_address;
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ 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();
- 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);
+ VALIDATE_FOUND_ADDRESS(false, NULL, NULL);
+ CLEANUP_FOUND_ADDRESS;
- UNMOCK(get_interface_address);
- tor_free(hostname_out);
+ /*
+ * 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);
-/*
- * 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.
- */
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- MOCK(get_interface_address,get_interface_address_failure);
+ VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL);
+ CLEANUP_FOUND_ADDRESS;
- prev_n_get_interface_address_failure = n_get_interface_address_failure;
- prev_n_gethostname_replacement = n_gethostname_replacement;
+ /*
+ * 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);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ setup_full_capture_of_logs(LOG_NOTICE);
- 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);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- UNMOCK(get_interface_address);
- tor_free(hostname_out);
+ expect_log_msg_containing("Found 2 Address statement of address family");
+ teardown_capture_of_logs();
-/*
- * 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.
- */
+ VALIDATE_FOUND_ADDRESS(false, NULL, NULL);
+ CLEANUP_FOUND_ADDRESS;
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(get_interface_address6,get_interface_address6_replacement);
+ /*
+ * 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_address6, get_interface_address6_08080808);
- 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, OP_EQ, ++prev_n_get_interface_address6);
+ VALIDATE_FOUND_ADDRESS(true, "INTERFACE", NULL);
+ CLEANUP_FOUND_ADDRESS;
- UNMOCK(tor_lookup_hostname);
- UNMOCK(tor_gethostname);
UNMOCK(get_interface_address6);
- tor_free(hostname_out);
-
/*
- * 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 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);
-
- prev_n_hostname_failure = n_hostname_failure;
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_replacement);
+ MOCK(tor_addr_lookup, tor_addr_lookup_01010101);
- tor_free(options->Address);
- options->Address = tor_strdup("some_hostname");
+ 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;
- 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_01010101, OP_EQ,
+ ++prev_n_hostname_01010101);
+ tt_int_op(n_gethostname_replacement, OP_EQ,
+ ++prev_n_gethostname_replacement);
+ VALIDATE_FOUND_ADDRESS(true, "GETHOSTNAME", "onionrouter!");
+ 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 10:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname resolves to an internal address.
*
- * 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_localhost);
+ MOCK(tor_addr_lookup, tor_addr_lookup_localhost);
- prev_n_gethostname_replacement = n_gethostname_replacement;
+ prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
prev_n_hostname_localhost = n_hostname_localhost;
- prev_n_get_interface_address6 = n_get_interface_address6;
+ prev_n_gethostname_localhost = n_gethostname_localhost;
- 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_hostname_localhost, OP_EQ,
+ ++prev_n_hostname_localhost);
+ tt_int_op(n_gethostname_localhost, OP_EQ,
+ ++prev_n_gethostname_localhost);
+ VALIDATE_FOUND_ADDRESS(false, NULL, 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);
+ UNMOCK(tor_addr_lookup);
/*
- * CASE 11b:
- * 1-5 as above.
- * 6. get_interface_address6() fails.
+ * Case 11:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname fails to be found.
*
- * 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_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_failure = n_gethostname_failure;
- retval = resolve_my_address(LOG_DEBUG, options, &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);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- 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_gethostname_failure, OP_EQ,
+ ++prev_n_gethostname_failure);
+ VALIDATE_FOUND_ADDRESS(false, NULL, NULL);
+ CLEANUP_FOUND_ADDRESS;
- UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
UNMOCK(get_interface_address6);
+ UNMOCK(tor_gethostname);
- /* 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.
+ /*
+ * Case 12:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname can't be resolved.
*
- * In this case, we want resolve_my_address() to fail.
+ * Expected to fail.
*/
-
- tor_free(options->Address);
options->Address = NULL;
- options->DirAuthorities = tor_malloc_zero(sizeof(config_line_t));
- MOCK(tor_gethostname,tor_gethostname_localhost);
+ 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_localhost = n_gethostname_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 = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+
+ 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, NULL, NULL);
+ CLEANUP_FOUND_ADDRESS;
+
+ /*
+ * 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");
+ }
+
+ ret = parse_ports(options, 0, &msg, &n, &w);
+ tt_int_op(ret, OP_EQ, 0);
+ tor_addr_parse(&test_addr, p->public_ip);
+ }
- 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);
+ VALIDATE_FOUND_ADDRESS(true, "CONFIGURED_ORPORT", NULL);
+ CLEANUP_FOUND_ADDRESS;
- tt_want(n_gethostname_localhost == prev_n_gethostname_localhost + 1);
- tt_int_op(retval, OP_EQ, -1);
+ /*
+ * 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");
+ }
+
+ 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(get_interface_address6, get_interface_address6_08080808);
+ prev_n_get_interface_address6 = n_get_interface_address6;
+
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+
+ tt_int_op(n_get_interface_address6, OP_EQ, ++prev_n_get_interface_address6);
+ VALIDATE_FOUND_ADDRESS(true, "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 +2285,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 +2297,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 +2309,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 +2328,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 +2340,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 +2352,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 +2364,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 +2376,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 +2428,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 +2440,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 +2452,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 +2471,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 +2483,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 +2495,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 +2507,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 +2519,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 +2571,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 +2583,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 +2595,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 +2614,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 +2626,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 +2638,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 +2650,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 +2662,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 +2715,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 +2727,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 +2739,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 +2758,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 +2770,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 +2782,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 +2794,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 +2806,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 +2869,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 +2881,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 +2893,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 +2919,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 +2931,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 +2943,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 +2955,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 +2967,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 +3025,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 +3037,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 +3049,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 +3075,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 +3087,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 +3099,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 +3111,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 +3123,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 +3191,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 +3203,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 +3215,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 +3242,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 +3254,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 +3266,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 +3278,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 +3290,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 +3351,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 +3363,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 +3375,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 +3402,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 +3414,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 +3426,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 +3438,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 +3450,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 +3518,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 +3530,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 +3542,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 +3569,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 +3581,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 +3593,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 +3605,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 +3617,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 +3683,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 +3695,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 +3707,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 +3734,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 +3746,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 +3758,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 +3770,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 +3782,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 +3861,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 +3907,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 +3967,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 +3988,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 +4003,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 +4020,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 +4033,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 +4050,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 +4060,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 +4071,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);
@@ -4160,8 +4375,6 @@ test_config_parse_port_config__ports__ports_given(void *data)
/* Test entry port defaults as initialised in port_parse_config */
tt_int_op(port_cfg->entry_cfg.dns_request, OP_EQ, 1);
tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 1);
- tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 1);
- tt_int_op(port_cfg->entry_cfg.prefer_ipv6, OP_EQ, 1);
tt_int_op(port_cfg->entry_cfg.onion_traffic, OP_EQ, 1);
tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.prefer_ipv6_virtaddr, OP_EQ, 1);
@@ -4949,6 +5162,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));
@@ -4968,17 +5219,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);
@@ -4992,27 +5243,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");
@@ -6243,9 +6494,14 @@ test_config_getinfo_config_names(void *arg)
tor_free(answer);
}
+#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),
@@ -6256,7 +6512,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),
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_slow.c b/src/test/test_crypto_slow.c
index 56319f2c72..1702427b08 100644
--- a/src/test/test_crypto_slow.c
+++ b/src/test/test_crypto_slow.c
@@ -342,7 +342,7 @@ test_crypto_scrypt_vectors(void *arg)
#endif
/* Test vectors from
- http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00 section 11.
+ https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00 section 11.
Note that the names of 'r' and 'N' are switched in that section. Or
possibly in libscrypt.
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index f6a21c804e..ab0315aa2d 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;
@@ -634,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); \
@@ -714,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);
@@ -763,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);
@@ -797,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);
@@ -966,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,
@@ -1062,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);
@@ -1108,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);
@@ -3057,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:
@@ -3149,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,
@@ -3171,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);
@@ -3265,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);
@@ -3639,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));
@@ -4143,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;
@@ -4167,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;
@@ -4193,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;
@@ -4218,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;
@@ -4320,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);
@@ -4344,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);
@@ -4453,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);
@@ -4556,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;
@@ -4665,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"
@@ -7273,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);
@@ -7352,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 12b4fcde3c..7da7ea66e4 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;
@@ -390,12 +390,13 @@ test_entry_guard_encode_for_state_minimal(void *arg)
eg->confirmed_idx = -1;
char *s = NULL;
- s = entry_guard_encode_for_state(eg);
+ s = entry_guard_encode_for_state(eg, 0);
tt_str_op(s, OP_EQ,
"in=wubwub "
"rsa_id=706C75727079666C75727079736C75727079646F "
"sampled_on=2016-11-14T00:00:00 "
+ "sampled_idx=0 "
"listed=0");
done:
@@ -421,10 +422,11 @@ test_entry_guard_encode_for_state_maximal(void *arg)
eg->currently_listed = 1;
eg->confirmed_on_date = 1479081690;
eg->confirmed_idx = 333;
+ eg->sampled_idx = 42;
eg->extra_state_fields = tor_strdup("and the green grass grew all around");
char *s = NULL;
- s = entry_guard_encode_for_state(eg);
+ s = entry_guard_encode_for_state(eg, 0);
tt_str_op(s, OP_EQ,
"in=default "
@@ -432,6 +434,7 @@ test_entry_guard_encode_for_state_maximal(void *arg)
"bridge_addr=8.8.4.4:9999 "
"nickname=Fred "
"sampled_on=2016-11-14T00:00:00 "
+ "sampled_idx=0 "
"sampled_by=1.2.3 "
"unlisted_since=2016-11-14T00:00:45 "
"listed=1 "
@@ -621,39 +624,47 @@ test_entry_guard_parse_from_state_full(void *arg)
const char STATE[] =
"Guard in=default rsa_id=214F44BD5B638E8C817D47FF7C97397790BF0345 "
"nickname=TotallyNinja sampled_on=2016-11-12T19:32:49 "
+ "sampled_idx=0 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1\n"
"Guard in=default rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 "
"nickname=5OfNovember sampled_on=2016-11-20T04:32:05 "
+ "sampled_idx=1 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1 confirmed_on=2016-11-22T08:13:28 confirmed_idx=0 "
"pb_circ_attempts=4.000000 pb_circ_successes=2.000000 "
"pb_successful_circuits_closed=2.000000\n"
"Guard in=default rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
"nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_idx=2 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1 confirmed_on=2016-11-24T08:45:30 confirmed_idx=4 "
"pb_circ_attempts=5.000000 pb_circ_successes=5.000000 "
"pb_successful_circuits_closed=5.000000\n"
"Guard in=wobblesome rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
"nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_idx=0 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1\n"
"Guard in=default rsa_id=E9025AD60D86875D5F11548D536CC6AF60F0EF5E "
"nickname=maibrunn sampled_on=2016-11-25T22:36:38 "
+ "sampled_idx=3 "
"sampled_by=0.3.0.0-alpha-dev listed=1\n"
"Guard in=default rsa_id=DCD30B90BA3A792DA75DC54A327EF353FB84C38E "
"nickname=Unnamed sampled_on=2016-11-25T14:34:00 "
+ "sampled_idx=10 "
"sampled_by=0.3.0.0-alpha-dev listed=1\n"
"Guard in=bridges rsa_id=8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E "
"bridge_addr=24.1.1.1:443 sampled_on=2016-11-25T06:44:14 "
+ "sampled_idx=0 "
"sampled_by=0.3.0.0-alpha-dev listed=1 "
"confirmed_on=2016-11-29T10:36:06 confirmed_idx=0 "
"pb_circ_attempts=8.000000 pb_circ_successes=8.000000 "
"pb_successful_circuits_closed=13.000000\n"
"Guard in=bridges rsa_id=5800000000000000000000000000000000000000 "
"bridge_addr=37.218.246.143:28366 "
- "sampled_on=2016-11-18T15:07:34 sampled_by=0.3.0.0-alpha-dev listed=1\n";
+ "sampled_on=2016-11-18T15:07:34 sampled_idx=1 "
+ "sampled_by=0.3.0.0-alpha-dev listed=1\n";
config_line_t *lines = NULL;
or_state_t *state = tor_malloc_zero(sizeof(or_state_t));
@@ -729,35 +740,42 @@ test_entry_guard_parse_from_state_full(void *arg)
tt_str_op(joined, OP_EQ,
"Guard in=default rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 "
"nickname=5OfNovember sampled_on=2016-11-20T04:32:05 "
+ "sampled_idx=0 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1 confirmed_on=2016-11-22T08:13:28 confirmed_idx=0 "
"pb_circ_attempts=4.000000 pb_circ_successes=2.000000 "
"pb_successful_circuits_closed=2.000000\n"
"Guard in=default rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
"nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_idx=1 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1 confirmed_on=2016-11-24T08:45:30 confirmed_idx=1 "
"pb_circ_attempts=5.000000 pb_circ_successes=5.000000 "
"pb_successful_circuits_closed=5.000000\n"
"Guard in=default rsa_id=E9025AD60D86875D5F11548D536CC6AF60F0EF5E "
"nickname=maibrunn sampled_on=2016-11-25T22:36:38 "
+ "sampled_idx=2 "
"sampled_by=0.3.0.0-alpha-dev listed=1\n"
"Guard in=default rsa_id=DCD30B90BA3A792DA75DC54A327EF353FB84C38E "
"nickname=Unnamed sampled_on=2016-11-25T14:34:00 "
+ "sampled_idx=3 "
"sampled_by=0.3.0.0-alpha-dev listed=1\n"
"Guard in=wobblesome rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
"nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_idx=0 "
"sampled_by=0.3.0.0-alpha-dev "
"listed=1\n"
"Guard in=bridges rsa_id=8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E "
"bridge_addr=24.1.1.1:443 sampled_on=2016-11-25T06:44:14 "
+ "sampled_idx=0 "
"sampled_by=0.3.0.0-alpha-dev listed=1 "
"confirmed_on=2016-11-29T10:36:06 confirmed_idx=0 "
"pb_circ_attempts=8.000000 pb_circ_successes=8.000000 "
"pb_successful_circuits_closed=13.000000\n"
"Guard in=bridges rsa_id=5800000000000000000000000000000000000000 "
"bridge_addr=37.218.246.143:28366 "
- "sampled_on=2016-11-18T15:07:34 sampled_by=0.3.0.0-alpha-dev listed=1\n");
+ "sampled_on=2016-11-18T15:07:34 sampled_idx=1 "
+ "sampled_by=0.3.0.0-alpha-dev listed=1\n");
done:
config_free_lines(lines);
@@ -984,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", "");
@@ -996,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.
@@ -1106,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);
@@ -1144,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.
}
});
@@ -1461,8 +1479,8 @@ test_entry_guard_confirming_guards(void *arg)
tt_i64_op(g1->confirmed_on_date, OP_EQ, start+10);
tt_i64_op(g2->confirmed_on_date, OP_EQ, start);
tt_i64_op(g3->confirmed_on_date, OP_EQ, start+10);
- tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g2);
- tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g1);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g1);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g2);
tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 2), OP_EQ, g3);
/* Now make sure we can regenerate the confirmed_entry_guards list. */
@@ -1474,8 +1492,8 @@ test_entry_guard_confirming_guards(void *arg)
tt_int_op(g1->confirmed_idx, OP_EQ, 1);
tt_int_op(g2->confirmed_idx, OP_EQ, 0);
tt_int_op(g3->confirmed_idx, OP_EQ, 2);
- tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g2);
- tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g1);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g1);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g2);
tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 2), OP_EQ, g3);
/* Now make sure we can regenerate the confirmed_entry_guards list if
@@ -1492,9 +1510,9 @@ test_entry_guard_confirming_guards(void *arg)
g1 = smartlist_get(gs->confirmed_entry_guards, 0);
g2 = smartlist_get(gs->confirmed_entry_guards, 1);
g3 = smartlist_get(gs->confirmed_entry_guards, 2);
- tt_int_op(g1->confirmed_idx, OP_EQ, 0);
- tt_int_op(g2->confirmed_idx, OP_EQ, 1);
- tt_int_op(g3->confirmed_idx, OP_EQ, 2);
+ tt_int_op(g1->sampled_idx, OP_EQ, 0);
+ tt_int_op(g2->sampled_idx, OP_EQ, 1);
+ tt_int_op(g3->sampled_idx, OP_EQ, 8);
tt_assert(g1 != g2);
tt_assert(g1 != g3);
tt_assert(g2 != g3);
@@ -1510,9 +1528,6 @@ test_entry_guard_sample_reachable_filtered(void *arg)
(void)arg;
guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
entry_guards_expand_sample(gs);
- const int N = 10000;
- bitarray_t *selected = NULL;
- int i, j;
/* We've got a sampled list now; let's make one non-usable-filtered; some
* confirmed, some primary, some pending.
@@ -1547,32 +1562,21 @@ test_entry_guard_sample_reachable_filtered(void *arg)
{ SAMPLE_EXCLUDE_PENDING, 0 },
{ -1, -1},
};
-
+ int j;
for (j = 0; tests[j].flag >= 0; ++j) {
- selected = bitarray_init_zero(n_guards);
const int excluded_flags = tests[j].flag;
const int excluded_idx = tests[j].idx;
- for (i = 0; i < N; ++i) {
- g = sample_reachable_filtered_entry_guards(gs, NULL, excluded_flags);
- tor_assert(g);
- int pos = smartlist_pos(gs->sampled_entry_guards, g);
- tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_guards);
- tt_int_op(pos, OP_GE, 0);
- tt_int_op(pos, OP_LT, n_guards);
- bitarray_set(selected, pos);
- }
- for (i = 0; i < n_guards; ++i) {
- const int should_be_set = (i != excluded_idx &&
- i != 3); // filtered out.
- tt_int_op(!!bitarray_is_set(selected, i), OP_EQ, should_be_set);
- }
- bitarray_free(selected);
- selected = NULL;
+ g = first_reachable_filtered_entry_guard(gs, NULL, excluded_flags);
+ tor_assert(g);
+ int pos = smartlist_pos(gs->sampled_entry_guards, g);
+ tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_guards);
+ const int should_be_set = (pos != excluded_idx &&
+ pos != 3); // filtered out.
+ tt_int_op(1, OP_EQ, should_be_set);
}
done:
guard_selection_free(gs);
- bitarray_free(selected);
}
static void
@@ -1584,7 +1588,7 @@ test_entry_guard_sample_reachable_filtered_empty(void *arg)
SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n,
n->is_possible_guard = 0);
- entry_guard_t *g = sample_reachable_filtered_entry_guards(gs, NULL, 0);
+ entry_guard_t *g = first_reachable_filtered_entry_guard(gs, NULL, 0);
tt_ptr_op(g, OP_EQ, NULL);
done:
@@ -1675,10 +1679,13 @@ test_entry_guard_manage_primary(void *arg)
tt_ptr_op(g, OP_EQ, smartlist_get(prev_guards, g_sl_idx));
});
- /* If we have one confirmed guard, that guards becomes the first primary
- * guard, and the other primary guards get kept. */
+ /**
+ * If we have one confirmed guard, that guards becomes the first primary
+ * only if its sampled_idx is smaller
+ * */
- /* find a non-primary guard... */
+ /* find a non-primary guard... it should have a sampled_idx higher than
+ * existing primary guards */
entry_guard_t *confirmed = NULL;
SMARTLIST_FOREACH(gs->sampled_entry_guards, entry_guard_t *, g, {
if (! g->is_primary) {
@@ -1694,15 +1701,13 @@ test_entry_guard_manage_primary(void *arg)
smartlist_add_all(prev_guards, gs->primary_entry_guards);
entry_guards_update_primary(gs);
- /* and see what's primary now! */
+ /* the confirmed guard should be at the end of the primary list! Hopefully,
+ * one of the primary guards with a lower sampled_idx will confirm soon :)
+ * Doing this won't make the client switches between primaries depending on
+ * the order of confirming events */
tt_int_op(smartlist_len(gs->primary_entry_guards), OP_EQ, n_primary);
- tt_ptr_op(smartlist_get(gs->primary_entry_guards, 0), OP_EQ, confirmed);
- SMARTLIST_FOREACH(gs->primary_entry_guards, entry_guard_t *, g, {
- tt_assert(g->is_primary);
- if (g_sl_idx == 0)
- continue;
- tt_ptr_op(g, OP_EQ, smartlist_get(prev_guards, g_sl_idx - 1));
- });
+ tt_ptr_op(smartlist_get(gs->primary_entry_guards,
+ smartlist_len(gs->primary_entry_guards)-1), OP_EQ, confirmed);
{
entry_guard_t *prev_last_guard = smartlist_get(prev_guards, n_primary-1);
tt_assert(! prev_last_guard->is_primary);
@@ -1793,6 +1798,57 @@ test_entry_guard_guard_preferred(void *arg)
}
static void
+test_entry_guard_correct_cascading_order(void *arg)
+{
+ (void)arg;
+ smartlist_t *old_primary_guards = smartlist_new();
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ entry_guards_expand_sample(gs);
+ /** First, a test in which the primary guards need be pulled from different
+ * lists to fill up the primary list -- this may happen, if for example, not
+ * enough guards have confirmed yet */
+ entry_guard_t *g;
+ /** just one confirmed */
+ g = smartlist_get(gs->sampled_entry_guards, 2);
+ make_guard_confirmed(gs, g);
+ entry_guards_update_primary(gs);
+ g = smartlist_get(gs->primary_entry_guards, 0);
+ tt_int_op(g->sampled_idx, OP_EQ, 0);
+ g = smartlist_get(gs->primary_entry_guards, 1);
+ tt_int_op(g->sampled_idx, OP_EQ, 1);
+ g = smartlist_get(gs->primary_entry_guards, 2);
+ tt_int_op(g->sampled_idx, OP_EQ, 2);
+
+ /** Now the primaries get all confirmed, and the primary list should not
+ * change */
+ make_guard_confirmed(gs, smartlist_get(gs->primary_entry_guards, 0));
+ make_guard_confirmed(gs, smartlist_get(gs->primary_entry_guards, 1));
+ smartlist_add_all(old_primary_guards, gs->primary_entry_guards);
+ entry_guards_update_primary(gs);
+ smartlist_ptrs_eq(gs->primary_entry_guards, old_primary_guards);
+ /** the confirmed guards should also have the same set of guards, in the same
+ * order :-) */
+ smartlist_ptrs_eq(gs->confirmed_entry_guards, gs->primary_entry_guards);
+ /** Now select a guard for a circuit, and make sure it is the first primary
+ * guard */
+ unsigned state = 9999;
+ g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ tt_ptr_op(g, OP_EQ, smartlist_get(gs->primary_entry_guards, 0));
+ /** Now, let's mark this guard as unreachable and let's update the lists */
+ g->is_reachable = GUARD_REACHABLE_NO;
+ g->failing_since = approx_time() - 10;
+ g->last_tried_to_connect = approx_time() - 10;
+ state = 9999;
+ entry_guards_update_primary(gs);
+ g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ /** we should have switched to the next one is sampled order */
+ tt_int_op(g->sampled_idx, OP_EQ, 1);
+ done:
+ smartlist_free(old_primary_guards);
+ guard_selection_free(gs);
+}
+
+static void
test_entry_guard_select_for_circuit_no_confirmed(void *arg)
{
/* Simpler cases: no gaurds are confirmed yet. */
@@ -3094,6 +3150,7 @@ struct testcase_t entrynodes_tests[] = {
BFN_TEST(sample_reachable_filtered_empty),
BFN_TEST(retry_unreachable),
BFN_TEST(manage_primary),
+ BFN_TEST(correct_cascading_order),
EN_TEST_FORK(guard_preferred),
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..14913b4b40 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -16,28 +16,35 @@
#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"
#include "test/test.h"
@@ -441,3 +448,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..66007873d1 100644
--- a/src/test/test_helpers.h
+++ b/src/test/test_helpers.h
@@ -40,5 +40,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 4a161db334..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);
@@ -792,6 +790,8 @@ test_parse_extended_hostname(void *arg)
"www.25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion";
char address9[] =
"www.15njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion";
+ char address10[] =
+ "15njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid7jdl.onion";
tt_assert(!parse_extended_hostname(address1, &type));
tt_int_op(type, OP_EQ, BAD_HOSTNAME);
@@ -824,7 +824,11 @@ test_parse_extended_hostname(void *arg)
/* Invalid v3 address. */
tt_assert(!parse_extended_hostname(address9, &type));
- tt_int_op(type, OP_EQ, ONION_V3_HOSTNAME);
+ tt_int_op(type, OP_EQ, BAD_HOSTNAME);
+
+ /* Invalid v3 address: too long */
+ tt_assert(!parse_extended_hostname(address10, &type));
+ tt_int_op(type, OP_EQ, BAD_HOSTNAME);
done: ;
}
diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c
index 8ba9f1173c..1f574179e9 100644
--- a/src/test/test_hs_control.c
+++ b/src/test/test_hs_control.c
@@ -393,7 +393,7 @@ test_hs_control_good_onion_client_auth_add(void *arg)
retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
tt_int_op(retval, OP_EQ, 0);
cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
- tt_str_op(cp1, OP_EQ, "512 Invalid v3 addr \"house\"\r\n");
+ tt_str_op(cp1, OP_EQ, "512 Invalid v3 address \"house\"\r\n");
done:
tor_free(args);
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_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 9cd1d11d29..8e0d19f126 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -2362,7 +2362,7 @@ test_options_validate__rend(void *ignored)
expect_log_msg("UseEntryGuards is disabled, but you"
" have configured one or more hidden services on this Tor "
"instance. Your hidden services will be very easy to locate using"
- " a well-known attack -- see http://freehaven.net/anonbib/#hs-"
+ " a well-known attack -- see https://freehaven.net/anonbib/#hs-"
"attack06 for details.\n");
tor_free(msg);
@@ -2378,7 +2378,7 @@ test_options_validate__rend(void *ignored)
expect_no_log_msg("UseEntryGuards is disabled, but you"
" have configured one or more hidden services on this Tor "
"instance. Your hidden services will be very easy to locate using"
- " a well-known attack -- see http://freehaven.net/anonbib/#hs-"
+ " a well-known attack -- see https://freehaven.net/anonbib/#hs-"
"attack06 for details.\n");
free_options_test_data(tdata);
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..3559c0dda8 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(
@@ -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(); \
@@ -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;
diff --git a/src/test/test_prob_distr.c b/src/test/test_prob_distr.c
index c5423ce14a..541a81df3a 100644
--- a/src/test/test_prob_distr.c
+++ b/src/test/test_prob_distr.c
@@ -893,7 +893,7 @@ test_uniform_interval(void *arg)
*
* NIST/SEMATECH e-Handbook of Statistical Methods, Section
* 1.3.6.7.4 `Critical Values of the Chi-Square Distribution',
- * <http://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm>,
+ * <https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm>,
* retrieved 2018-10-28.
*/
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 c33fbcae2c..5e74265550 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:
;
@@ -645,8 +680,8 @@ test_protover_vote_roundtrip_ours(void *args)
(void) args;
const char *examples[] = {
protover_get_supported_protocols(),
- DIRVOTE_RECCOMEND_RELAY_PROTO,
- DIRVOTE_RECCOMEND_CLIENT_PROTO,
+ DIRVOTE_RECOMMEND_RELAY_PROTO,
+ DIRVOTE_RECOMMEND_CLIENT_PROTO,
DIRVOTE_REQUIRE_RELAY_PROTO,
DIRVOTE_REQUIRE_CLIENT_PROTO,
};
@@ -676,6 +711,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 +947,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..ee704ceb8c 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, "NA", 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, "NA", 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_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..8d653e44a2 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;
@@ -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..f0715c2e45 100644
--- a/src/test/test_stats.c
+++ b/src/test/test_stats.c
@@ -39,6 +39,7 @@
#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"
@@ -111,37 +112,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
diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c
index a822bc5ad8..12ba873650 100644
--- a/src/test/test_tortls.c
+++ b/src/test/test_tortls.c
@@ -105,6 +105,17 @@ const char* caCertString = "-----BEGIN CERTIFICATE-----\n"
"Yy1RT69d0rwYc5u/vnqODz1IjvT90smsrkBumGt791FAFeg=\n"
"-----END CERTIFICATE-----\n";
+static tor_x509_cert_t *fixed_x509_cert = NULL;
+static tor_x509_cert_t *
+get_peer_cert_mock_return_fixed(tor_tls_t *tls)
+{
+ (void)tls;
+ if (fixed_x509_cert)
+ return tor_x509_cert_dup(fixed_x509_cert);
+ else
+ return NULL;
+}
+
tor_x509_cert_impl_t *
read_cert_from(const char *str)
{
@@ -513,6 +524,67 @@ test_tortls_verify(void *ignored)
crypto_pk_free(k);
}
+static void
+test_tortls_cert_matches_key(void *ignored)
+{
+ (void)ignored;
+
+ tor_x509_cert_impl_t *cert1 = NULL,
+ *cert2 = NULL,
+ *cert3 = NULL,
+ *cert4 = NULL;
+ tor_x509_cert_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL;
+ crypto_pk_t *k1 = NULL, *k2 = NULL, *k3 = NULL;
+
+ k1 = pk_generate(1);
+ k2 = pk_generate(2);
+ k3 = pk_generate(3);
+
+ cert1 = tor_tls_create_certificate(k1, k2, "A", "B", 1000);
+ cert2 = tor_tls_create_certificate(k1, k3, "C", "D", 1000);
+ cert3 = tor_tls_create_certificate(k2, k3, "C", "D", 1000);
+ cert4 = tor_tls_create_certificate(k3, k2, "E", "F", 1000);
+
+ tt_assert(cert1 && cert2 && cert3 && cert4);
+
+ c1 = tor_x509_cert_new(cert1); cert1 = NULL;
+ c2 = tor_x509_cert_new(cert2); cert2 = NULL;
+ c3 = tor_x509_cert_new(cert3); cert3 = NULL;
+ c4 = tor_x509_cert_new(cert4); cert4 = NULL;
+
+ tt_assert(c1 && c2 && c3 && c4);
+
+ MOCK(tor_tls_get_peer_cert, get_peer_cert_mock_return_fixed);
+
+ fixed_x509_cert = NULL;
+ /* If the peer has no certificate, it shouldn't match anything. */
+ tt_assert(! tor_tls_cert_matches_key(NULL, c1));
+ tt_assert(! tor_tls_cert_matches_key(NULL, c2));
+ tt_assert(! tor_tls_cert_matches_key(NULL, c3));
+ tt_assert(! tor_tls_cert_matches_key(NULL, c4));
+ fixed_x509_cert = c1;
+ /* If the peer has a certificate, it should match every cert with the same
+ * subject key. */
+ tt_assert(tor_tls_cert_matches_key(NULL, c1));
+ tt_assert(tor_tls_cert_matches_key(NULL, c2));
+ tt_assert(! tor_tls_cert_matches_key(NULL, c3));
+ tt_assert(! tor_tls_cert_matches_key(NULL, c4));
+
+ done:
+ tor_x509_cert_free(c1);
+ tor_x509_cert_free(c2);
+ tor_x509_cert_free(c3);
+ tor_x509_cert_free(c4);
+ if (cert1) tor_x509_cert_impl_free(cert1);
+ if (cert2) tor_x509_cert_impl_free(cert2);
+ if (cert3) tor_x509_cert_impl_free(cert3);
+ if (cert4) tor_x509_cert_impl_free(cert4);
+ crypto_pk_free(k1);
+ crypto_pk_free(k2);
+ crypto_pk_free(k3);
+ UNMOCK(tor_tls_get_peer_cert);
+}
+
#define LOCAL_TEST_CASE(name, flags) \
{ #name, test_tortls_##name, (flags|TT_FORK), NULL, NULL }
@@ -533,5 +605,6 @@ struct testcase_t tortls_tests[] = {
LOCAL_TEST_CASE(is_server, 0),
LOCAL_TEST_CASE(bridge_init, TT_FORK),
LOCAL_TEST_CASE(verify, TT_FORK),
+ LOCAL_TEST_CASE(cert_matches_key, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_tortls_openssl.c b/src/test/test_tortls_openssl.c
index 4318f7f1eb..e20b0d1ede 100644
--- a/src/test/test_tortls_openssl.c
+++ b/src/test/test_tortls_openssl.c
@@ -475,75 +475,6 @@ fake_x509_free(X509 *cert)
}
#endif /* !defined(OPENSSL_OPAQUE) */
-static tor_x509_cert_t *fixed_x509_cert = NULL;
-static tor_x509_cert_t *
-get_peer_cert_mock_return_fixed(tor_tls_t *tls)
-{
- (void)tls;
- if (fixed_x509_cert)
- return tor_x509_cert_dup(fixed_x509_cert);
- else
- return NULL;
-}
-
-static void
-test_tortls_cert_matches_key(void *ignored)
-{
- (void)ignored;
-
- X509 *cert1 = NULL, *cert2 = NULL, *cert3 = NULL, *cert4 = NULL;
- tor_x509_cert_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL;
- crypto_pk_t *k1 = NULL, *k2 = NULL, *k3 = NULL;
-
- k1 = pk_generate(1);
- k2 = pk_generate(2);
- k3 = pk_generate(3);
-
- cert1 = tor_tls_create_certificate(k1, k2, "A", "B", 1000);
- cert2 = tor_tls_create_certificate(k1, k3, "C", "D", 1000);
- cert3 = tor_tls_create_certificate(k2, k3, "C", "D", 1000);
- cert4 = tor_tls_create_certificate(k3, k2, "E", "F", 1000);
-
- tt_assert(cert1 && cert2 && cert3 && cert4);
-
- c1 = tor_x509_cert_new(cert1); cert1 = NULL;
- c2 = tor_x509_cert_new(cert2); cert2 = NULL;
- c3 = tor_x509_cert_new(cert3); cert3 = NULL;
- c4 = tor_x509_cert_new(cert4); cert4 = NULL;
-
- tt_assert(c1 && c2 && c3 && c4);
-
- MOCK(tor_tls_get_peer_cert, get_peer_cert_mock_return_fixed);
-
- fixed_x509_cert = NULL;
- /* If the peer has no certificate, it shouldn't match anything. */
- tt_assert(! tor_tls_cert_matches_key(NULL, c1));
- tt_assert(! tor_tls_cert_matches_key(NULL, c2));
- tt_assert(! tor_tls_cert_matches_key(NULL, c3));
- tt_assert(! tor_tls_cert_matches_key(NULL, c4));
- fixed_x509_cert = c1;
- /* If the peer has a certificate, it should match every cert with the same
- * subject key. */
- tt_assert(tor_tls_cert_matches_key(NULL, c1));
- tt_assert(tor_tls_cert_matches_key(NULL, c2));
- tt_assert(! tor_tls_cert_matches_key(NULL, c3));
- tt_assert(! tor_tls_cert_matches_key(NULL, c4));
-
- done:
- tor_x509_cert_free(c1);
- tor_x509_cert_free(c2);
- tor_x509_cert_free(c3);
- tor_x509_cert_free(c4);
- if (cert1) X509_free(cert1);
- if (cert2) X509_free(cert2);
- if (cert3) X509_free(cert3);
- if (cert4) X509_free(cert4);
- crypto_pk_free(k1);
- crypto_pk_free(k2);
- crypto_pk_free(k3);
- UNMOCK(tor_tls_get_peer_cert);
-}
-
#ifndef OPENSSL_OPAQUE
static void
test_tortls_cert_get_key(void *ignored)
@@ -2275,7 +2206,6 @@ struct testcase_t tortls_openssl_tests[] = {
INTRUSIVE_TEST_CASE(get_error, TT_FORK),
LOCAL_TEST_CASE(always_accept_verify_cb, 0),
INTRUSIVE_TEST_CASE(x509_cert_free, 0),
- LOCAL_TEST_CASE(cert_matches_key, 0),
INTRUSIVE_TEST_CASE(cert_get_key, 0),
LOCAL_TEST_CASE(get_my_client_auth_key, TT_FORK),
INTRUSIVE_TEST_CASE(get_ciphersuite_name, 0),
diff --git a/src/test/test_util.c b/src/test/test_util.c
index b2ee7cd35c..2aee07a26a 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -206,6 +206,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 */
@@ -5651,7 +5699,7 @@ test_util_hostname_validation(void *arg)
tt_assert(string_is_valid_nonrfc_hostname("luck.y13."));
// We allow punycode TLDs. For examples, see
- // http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+ // https://data.iana.org/TLD/tlds-alpha-by-domain.txt
tt_assert(string_is_valid_nonrfc_hostname("example.xn--l1acc"));
done:
@@ -6495,6 +6543,7 @@ 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(mathlog, 0),
UTIL_TEST(fraction, 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 b3337f24b0..cd93055dfb 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"
@@ -333,6 +334,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/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 3c8f91d53b..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.0-alpha-dev"
+#define VERSION "0.4.5.0-alpha-dev"
#define HAVE_STRUCT_SOCKADDR_IN6
#define HAVE_STRUCT_IN6_ADDR