Merge remote-tracking branch 'tor-github/pr/1888/head'

This commit is contained in:
Nick Mathewson
2020-06-09 15:44:58 -04:00
40 changed files with 1603 additions and 493 deletions
+4
View File
@@ -0,0 +1,4 @@
o Minor bugfixes (rust, protocol versions):
- Declare support for the onion service introduction point denial of
service extensions, when building tor with Rust.
Fixes bug 34248; bugfix on 0.4.2.1-alpha.
+4
View File
@@ -0,0 +1,4 @@
o Minor bugfixes (rust, protocol versions):
- Make Rust protocol version support checks consistent with the
undocumented error behaviour of the corresponding C code.
Fixes bug 34251; bugfix on 0.3.3.5-rc.
+8
View File
@@ -0,0 +1,8 @@
o Major features (IPv6, relay):
- Launch IPv4 and IPv6 ORPort self-test circuits on relays and bridges.
Closes ticket 33222.
o Minor features (IPv6, relay):
- Allow relays to send IPv6-only extend cells. Closes ticket 33222.
- Declare support for the Relay=3 subprotocol version. Closes ticket 33226.
- When launching IPv6 ORPort self-test circuits, make sure that the
second-last hop can initiate an IPv6 extend. Closes ticket 33222.
+3
View File
@@ -0,0 +1,3 @@
o Code simplification and refactoring:
- Refactor some common node selection code into a single function.
Closes ticket 34200.
+3 -3
View File
@@ -2038,12 +2038,12 @@ different from other Tor clients:
A list of identity fingerprints and country codes of nodes
to use for "middle" hops in your normal circuits.
Normal circuits include all circuits except for direct connections
to directory servers. Middle hops are all hops other than exit and entry. +
to directory servers. Middle hops are all hops other than exit and entry.
+
This is an **experimental** feature that is meant to be used by researchers
and developers to test new features in the Tor network safely. Using it
without care will strongly influence your anonymity. This feature might get
removed in the future.
without care will strongly influence your anonymity. Other tor features may
not work with MiddleNodes. This feature might get removed in the future.
+
The HSLayer2Node and HSLayer3Node options override this option for onion
service circuits, if they are set. The vanguards addon will read this
+7 -7
View File
@@ -96,7 +96,7 @@ problem function-size /src/core/or/channeltls.c:channel_tls_process_authenticate
problem dependency-violation /src/core/or/channeltls.c 11
problem include-count /src/core/or/circuitbuild.c 53
problem function-size /src/core/or/circuitbuild.c:get_unique_circ_id_by_chan() 128
problem function-size /src/core/or/circuitbuild.c:choose_good_exit_server_general() 206
problem function-size /src/core/or/circuitbuild.c:choose_good_exit_server_general() 196
problem dependency-violation /src/core/or/circuitbuild.c 25
problem include-count /src/core/or/circuitlist.c 55
problem function-size /src/core/or/circuitlist.c:HT_PROTOTYPE() 109
@@ -117,7 +117,7 @@ problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_cli
problem dependency-violation /src/core/or/circuitpadding_machines.c 1
problem function-size /src/core/or/circuitstats.c:circuit_build_times_parse_state() 123
problem dependency-violation /src/core/or/circuitstats.c 11
problem file-size /src/core/or/circuituse.c 3195
problem file-size /src/core/or/circuituse.c 3250
problem function-size /src/core/or/circuituse.c:circuit_is_acceptable() 128
problem function-size /src/core/or/circuituse.c:circuit_expire_building() 389
problem function-size /src/core/or/circuituse.c:circuit_log_ancient_one_hop_circuits() 126
@@ -146,7 +146,7 @@ problem function-size /src/core/or/connection_or.c:connection_or_client_learned_
problem dependency-violation /src/core/or/connection_or.c 21
problem dependency-violation /src/core/or/dos.c 6
problem dependency-violation /src/core/or/onion.c 2
problem file-size /src/core/or/or.h 1105
problem file-size /src/core/or/or.h 1150
problem include-count /src/core/or/or.h 48
problem dependency-violation /src/core/or/or.h 1
problem dependency-violation /src/core/or/or_periodic.c 1
@@ -198,7 +198,7 @@ problem function-size /src/feature/control/control_events.c:control_event_stream
problem include-count /src/feature/control/control_getinfo.c 56
problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_misc() 108
problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_dir() 297
problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_events() 234
problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_events() 237
problem function-size /src/feature/dirauth/bwauth.c:dirserv_read_measured_bandwidths() 121
problem file-size /src/feature/dirauth/dirvote.c 4734
problem include-count /src/feature/dirauth/dirvote.c 55
@@ -255,11 +255,11 @@ problem function-size /src/feature/nodelist/microdesc.c:microdesc_cache_rebuild(
problem include-count /src/feature/nodelist/networkstatus.c 65
problem function-size /src/feature/nodelist/networkstatus.c:networkstatus_check_consensus_signature() 175
problem function-size /src/feature/nodelist/networkstatus.c:networkstatus_set_current_consensus() 289
problem function-size /src/feature/nodelist/node_select.c:router_pick_directory_server_impl() 122
problem function-size /src/feature/nodelist/node_select.c:router_pick_directory_server_impl() 126
problem function-size /src/feature/nodelist/node_select.c:compute_weighted_bandwidths() 204
problem function-size /src/feature/nodelist/node_select.c:router_pick_trusteddirserver_impl() 112
problem function-size /src/feature/nodelist/node_select.c:router_pick_trusteddirserver_impl() 116
problem function-size /src/feature/nodelist/nodelist.c:compute_frac_paths_available() 190
problem file-size /src/feature/nodelist/routerlist.c 3247
problem file-size /src/feature/nodelist/routerlist.c 3350
problem function-size /src/feature/nodelist/routerlist.c:router_rebuild_store() 148
problem function-size /src/feature/nodelist/routerlist.c:router_add_to_routerlist() 168
problem function-size /src/feature/nodelist/routerlist.c:routerlist_remove_old_routers() 121
+112 -78
View File
@@ -439,7 +439,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 +456,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.
@@ -1050,7 +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)) {
if (server_mode(options) &&
!router_should_skip_orport_reachability_check(options)) {
inform_testing_reachability();
router_do_reachability_checks(1, 1);
}
@@ -1074,14 +1079,25 @@ circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
crypt_path_t *hop)
{
int len;
int family = tor_addr_family(&hop->extend_info->addr);
extend_cell_t ec;
memset(&ec, 0, sizeof(ec));
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;
/* Relays and bridges can send IPv6 extends. But for clients, it's an
* obvious version distinguisher. */
if (server_mode(get_options())) {
if (family != AF_INET && family != AF_INET6) {
log_warn(LD_BUG, "Server trying to extend to an invalid address "
"family.");
return - END_CIRC_REASON_INTERNAL;
}
} else {
if (family != AF_INET) {
log_warn(LD_BUG, "Client trying to extend to a non-IPv4 address.");
return - END_CIRC_REASON_INTERNAL;
}
}
circuit_pick_extend_handshake(&ec.cell_type,
@@ -1089,9 +1105,17 @@ circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
&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);
/* At the moment, extend_info only has one ORPort address. We'll add a
* second address in #34069, to support dual-stack extend cells. */
if (family == AF_INET) {
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);
} else {
tor_addr_copy(&ec.orport_ipv6.addr, &hop->extend_info->addr);
ec.orport_ipv6.port = hop->extend_info->port;
tor_addr_make_unspec(&ec.orport_ipv4.addr);
}
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. */
@@ -1539,7 +1563,23 @@ choose_good_exit_server_general(router_crn_flags_t flags)
const node_t *selected_node=NULL;
const int need_uptime = (flags & CRN_NEED_UPTIME) != 0;
const int need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
const int direct_conn = (flags & CRN_DIRECT_CONN) != 0;
/* We should not require guard flags on exits. */
IF_BUG_ONCE(flags & CRN_NEED_GUARD)
return NULL;
/* We reject single-hop exits for all node positions. */
IF_BUG_ONCE(flags & CRN_DIRECT_CONN)
return NULL;
/* This isn't the function for picking rendezvous nodes. */
IF_BUG_ONCE(flags & CRN_RENDEZVOUS_V3)
return NULL;
/* We only want exits to extend if we cannibalize the circuit.
* But we don't require IPv6 extends yet. */
IF_BUG_ONCE(flags & CRN_INITIATE_IPV6_EXTEND)
return NULL;
connections = get_connection_array();
@@ -1572,19 +1612,14 @@ choose_good_exit_server_general(router_crn_flags_t flags)
*/
continue;
}
if (!node_has_preferred_descriptor(node, direct_conn)) {
if (!router_can_choose_node(node, flags)) {
n_supported[i] = -1;
continue;
}
if (!node->is_running || node->is_bad_exit) {
if (node->is_bad_exit) {
n_supported[i] = -1;
continue; /* skip routers that are known to be down or bad exits */
}
if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) {
/* never pick a non-general node as a random exit. */
n_supported[i] = -1;
continue;
}
if (routerset_contains_node(options->ExcludeExitNodesUnion_, node)) {
n_supported[i] = -1;
continue; /* user asked us not to use it, no matter what */
@@ -1594,27 +1629,6 @@ choose_good_exit_server_general(router_crn_flags_t flags)
n_supported[i] = -1;
continue; /* not one of our chosen exit nodes */
}
if (node_is_unreliable(node, need_uptime, need_capacity, 0)) {
n_supported[i] = -1;
continue; /* skip routers that are not suitable. Don't worry if
* this makes us reject all the possible routers: if so,
* we'll retry later in this function with need_update and
* need_capacity set to 0. */
}
if (!(node->is_valid)) {
/* if it's invalid and we don't want it */
n_supported[i] = -1;
// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- invalid router.",
// router->nickname, i);
continue; /* skip invalid routers */
}
/* We do not allow relays that allow single hop exits by default. Option
* was deprecated in 0.2.9.2-alpha and removed in 0.3.1.0-alpha. */
if (node_allows_single_hop_exits(node)) {
n_supported[i] = -1;
continue;
}
if (node_exit_policy_rejects_all(node)) {
n_supported[i] = -1;
// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- it rejects all.",
@@ -1771,13 +1785,7 @@ pick_restricted_middle_node(router_crn_flags_t flags,
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);
router_add_running_nodes_to_smartlist(all_live_nodes, flags);
/* Filter all_live_nodes to only add live *and* whitelisted middles
* to the list whitelisted_live_middles. */
@@ -1957,6 +1965,43 @@ warn_if_last_router_excluded(origin_circuit_t *circ,
return;
}
/* Return a set of generic CRN_* flags based on <b>state</b>.
*
* Called for every position in the circuit. */
STATIC int
cpath_build_state_to_crn_flags(const cpath_build_state_t *state)
{
router_crn_flags_t flags = 0;
/* These flags apply to entry, middle, and exit nodes.
* If a flag only applies to a specific position, it should be checked in
* that function. */
if (state->need_uptime)
flags |= CRN_NEED_UPTIME;
if (state->need_capacity)
flags |= CRN_NEED_CAPACITY;
return flags;
}
/* Return the CRN_INITIATE_IPV6_EXTEND flag, based on <b>state</b> and
* <b>cur_len</b>.
*
* Only called for middle nodes (for now). Must not be called on single-hop
* circuits. */
STATIC int
cpath_build_state_to_crn_ipv6_extend_flag(const cpath_build_state_t *state,
int cur_len)
{
IF_BUG_ONCE(state->desired_path_len < 2)
return 0;
/* The last node is the relay doing the self-test. So we want to extend over
* IPv6 from the second-last node. */
if (state->is_ipv6_selftest && cur_len == state->desired_path_len - 2)
return CRN_INITIATE_IPV6_EXTEND;
else
return 0;
}
/** Decide a suitable length for circ's cpath, and pick an exit
* router (or use <b>exit</b> if provided). Store these in the
* cpath.
@@ -1990,14 +2035,13 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
exit_ei = extend_info_dup(exit_ei);
} else { /* we have to decide one */
router_crn_flags_t flags = CRN_NEED_DESC;
if (state->need_uptime)
flags |= CRN_NEED_UPTIME;
if (state->need_capacity)
flags |= CRN_NEED_CAPACITY;
if (is_hs_v3_rp_circuit)
flags |= CRN_RENDEZVOUS_V3;
flags |= cpath_build_state_to_crn_flags(state);
/* Some internal exits are one hop, for example directory connections.
* (Guards are always direct, middles are never direct.) */
if (state->onehop_tunnel)
flags |= CRN_DIRECT_CONN;
if (is_hs_v3_rp_circuit)
flags |= CRN_RENDEZVOUS_V3;
const node_t *node =
choose_good_exit_server(circ, flags, state->is_internal);
if (!node) {
@@ -2059,32 +2103,27 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit_ei)
return 0;
}
/** Return the number of routers in <b>routers</b> that are currently up
* and available for building circuits through.
/** Return the number of routers in <b>nodes</b> that are currently up and
* available for building circuits through.
*
* (Note that this function may overcount or undercount, if we have
* descriptors that are not the type we would prefer to use for some
* particular router. See bug #25885.)
* If <b>direct</b> is true, only count nodes that are suitable for direct
* connections. Counts nodes regardless of whether their addresses are
* preferred.
*/
MOCK_IMPL(STATIC int,
count_acceptable_nodes, (const smartlist_t *nodes, int direct))
{
int num=0;
int flags = CRN_NEED_DESC;
if (direct)
flags |= CRN_DIRECT_CONN;
SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) {
// log_debug(LD_CIRC,
// "Contemplating whether router %d (%s) is a new option.",
// i, r->nickname);
if (! node->is_running)
// log_debug(LD_CIRC,"Nope, the directory says %d is not running.",i);
continue;
if (! node->is_valid)
// log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i);
continue;
if (! node_has_preferred_descriptor(node, direct))
continue;
/* The node has a descriptor, so we can just check the ntor key directly */
if (!node_has_curve25519_onion_key(node))
// "Contemplating whether router %d (%s) is a new option.",
// i, r->nickname);
if (!router_can_choose_node(node, flags))
continue;
++num;
} SMARTLIST_FOREACH_END(node);
@@ -2278,10 +2317,8 @@ choose_good_middle_server(uint8_t purpose,
excluded = build_middle_exclude_list(purpose, state, head, cur_len);
if (state->need_uptime)
flags |= CRN_NEED_UPTIME;
if (state->need_capacity)
flags |= CRN_NEED_CAPACITY;
flags |= cpath_build_state_to_crn_flags(state);
flags |= cpath_build_state_to_crn_ipv6_extend_flag(state, cur_len);
/** If a hidden service circuit wants a specific middle node, pin it. */
if (middle_node_must_be_vanguard(options, purpose, cur_len)) {
@@ -2357,10 +2394,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state,
}
if (state) {
if (state->need_uptime)
flags |= CRN_NEED_UPTIME;
if (state->need_capacity)
flags |= CRN_NEED_CAPACITY;
flags |= cpath_build_state_to_crn_flags(state);
}
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
+4
View File
@@ -97,6 +97,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) */
+1 -1
View File
@@ -1944,7 +1944,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;
}
+15 -7
View File
@@ -1642,7 +1642,7 @@ static void
circuit_testing_opened(origin_circuit_t *circ)
{
if (have_performed_bandwidth_test ||
!check_whether_orport_reachable(get_options())) {
!router_should_skip_orport_reachability_check(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 +1660,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_should_skip_orport_reachability_check(options))
return;
log_info(LD_GENERAL,
@@ -2092,11 +2093,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,
+11 -5
View File
@@ -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);
+2
View File
@@ -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. */
+17 -4
View File
@@ -815,6 +815,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 +842,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 +857,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;
+10 -1
View File
@@ -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,
@@ -403,7 +409,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 +746,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.
+22 -2
View File
@@ -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
+45 -10
View File
@@ -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, 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,
+10 -7
View File
@@ -1278,15 +1278,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_should_skip_orport_reachability_check(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_should_skip_dirport_reachability_check(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_should_skip_orport_reachability_check(options) ? 1 : 0,
router_should_skip_dirport_reachability_check(options) ? 1 : 0);
} else if (!strcmp(question, "status/bootstrap-phase")) {
*answer = control_event_boot_last_msg();
} else if (!strcmpstart(question, "status/version/")) {
+78 -78
View File
@@ -321,8 +321,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. */
@@ -926,81 +930,25 @@ 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).
*/
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();
/* 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;
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);
/* 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
* this is fine to at least try with our routerinfo_t object. */
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);
router_add_running_nodes_to_smartlist(sl, flags);
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) {
@@ -1014,18 +962,66 @@ router_choose_random_node(smartlist_t *excludedsmartlist,
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)
{
/* 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;
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
* this is fine to at least try with our routerinfo_t object. */
if ((r = router_get_my_routerinfo()))
routerlist_add_node_and_family(excludednodes, r);
if (excludedsmartlist) {
smartlist_add_all(excludednodes, excludedsmartlist);
}
choice = router_choose_random_node_helper(excludednodes,
excludedset,
flags,
rule);
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 +1116,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)
+17 -11
View File
@@ -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
+2 -3
View File
@@ -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
+68 -18
View File
@@ -1133,7 +1133,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 +1158,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 +1175,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 +1185,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,20 +1193,9 @@ 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> supports the DoS ESTABLISH_INTRO cell
* extenstion. */
int
node_supports_establish_intro_dos_extension(const node_t *node)
{
tor_assert(node);
return node_get_protover_summary_flags(node)->
supports_establish_intro_dos_extension;
}
/** Return true iff <b>node</b> supports to be a rendezvous point for hidden
/** Return true iff <b>node</b> can be a rendezvous point for hidden
* service version 3 (HSRend=2). */
int
bool
node_supports_v3_rendezvous_point(const node_t *node)
{
tor_assert(node);
@@ -1219,6 +1208,67 @@ node_supports_v3_rendezvous_point(const node_t *node)
return node_get_protover_summary_flags(node)->supports_v3_rendezvous_point;
}
/** Return true iff <b>node</b> supports the DoS ESTABLISH_INTRO cell
* extenstion. */
bool
node_supports_establish_intro_dos_extension(const node_t *node)
{
tor_assert(node);
return node_get_protover_summary_flags(node)->
supports_establish_intro_dos_extension;
}
/** 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);
/* Relays can't initiate an IPv6 extend, unless they have an IPv6 ORPort. */
if (!node_has_ipv6_orport(node)) {
return 0;
}
/* 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. */
const uint8_t *
node_get_rsa_id_digest(const node_t *node)
+10 -6
View File
@@ -74,13 +74,17 @@ 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));
+29 -6
View File
@@ -17,14 +17,37 @@
#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_from_ipv4h(&ap_out->addr, router->addr);
ap_out->port = router->or_port;
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
+3 -2
View File
@@ -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);
+115 -33
View File
@@ -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,
@@ -498,40 +511,109 @@ routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2)
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)
router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags)
{
const int check_reach = !router_skip_or_reachability(get_options(),
pref_addr);
/* XXXX MOVE */
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
if (!node->is_running || !node->is_valid)
if (!router_can_choose_node(node, flags))
continue;
if (need_desc && !node_has_preferred_descriptor(node, direct_conn))
continue;
if (node->ri && node->ri->purpose != ROUTER_PURPOSE_GENERAL)
continue;
if (node_is_unreliable(node, need_uptime, need_capacity, need_guard))
continue;
/* Don't choose nodes if we are certain they can't do EXTEND2 cells */
if (node->rs && !routerstatus_version_supports_extend2_cells(node->rs, 1))
continue;
/* Don't choose nodes if we are certain they can't do ntor. */
if ((node->ri || node->md) && !node_has_curve25519_onion_key(node))
continue;
/* Choose a node with an OR address that matches the firewall rules */
if (direct_conn && check_reach &&
!fascist_firewall_allows_node(node,
FIREWALL_OR_CONNECTION,
pref_addr))
continue;
smartlist_add(sl, (void *)node);
} SMARTLIST_FOREACH_END(node);
}
+8 -6
View File
@@ -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);
+2 -2
View File
@@ -201,7 +201,7 @@ 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)) {
if (me && !router_should_skip_orport_reachability_check(options)) {
char *address = tor_dup_ip(me->addr);
if (address) {
log_warn(LD_CONFIG,
@@ -217,7 +217,7 @@ reachability_warnings_callback(time_t now, const or_options_t *options)
}
}
if (me && !check_whether_dirport_reachable(options)) {
if (me && !router_should_skip_dirport_reachability_check(options)) {
char *address = tor_dup_ip(me->addr);
if (address) {
log_warn(LD_CONFIG,
+18 -3
View File
@@ -1363,14 +1363,14 @@ decide_if_publishable_server(void)
return 1;
if (!router_get_advertised_or_port(options))
return 0;
if (!check_whether_orport_reachable(options))
if (!router_should_skip_orport_reachability_check(options))
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_should_skip_dirport_reachability_check(options);
}
}
@@ -1501,7 +1501,22 @@ router_has_advertised_ipv6_orport(const or_options_t *options)
return tor_addr_port_is_valid_ap(&ipv6_ap, 0);
}
/** 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))
{
+163 -70
View File
@@ -15,24 +15,31 @@
#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/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"
@@ -70,7 +77,7 @@ router_reachability_checks_disabled(const or_options_t *options)
* - the network is disabled.
*/
int
check_whether_orport_reachable(const or_options_t *options)
router_should_skip_orport_reachability_check(const or_options_t *options)
{
int reach_checks_disabled = router_reachability_checks_disabled(options);
return reach_checks_disabled ||
@@ -87,7 +94,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_should_skip_dirport_reachability_check(const or_options_t *options)
{
int reach_checks_disabled = router_reachability_checks_disabled(options) ||
!options->DirPort_set;
@@ -107,6 +114,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
@@ -126,18 +134,28 @@ router_should_check_reachability(int test_or, int test_dir)
}
/** 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 +163,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 +176,69 @@ 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);
log_info(LD_CIRC, "Testing %s of my %s ORPort: %s.",
!orport_reachable ? "reachability" : "bandwidth",
family_name, fmt_addrport(&ei->addr, ei->port));
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_from_ipv4h(&my_dirport.addr, me->addr);
my_dirport.port = me->dir_port;
/* 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);
}
}
/** 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,83 +255,89 @@ 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 = router_should_skip_orport_reachability_check(options);
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);
/* At the moment, tor relays believe that they are reachable when they
* receive any create cell on an inbound connection. We'll do separate
* IPv4 and IPv6 reachability checks in #34067, and make them more
* precise. */
router_do_orport_reachability_checks(me, AF_INET, orport_reachable);
router_do_orport_reachability_checks(me, AF_INET6, orport_reachable);
}
/* 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_should_skip_dirport_reachability_check(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. */
/** If reachability testing is in progress, let the user know that it's
* happening.
*
* If all is set, log a notice-level message. Return 1 if we did, or 0 if
* we chose not to log anything, because we were unable to test reachability.
*/
int
inform_testing_reachability(void)
{
char dirbuf[128];
char *address;
char ipv4_or_buf[TOR_ADDRPORT_BUF_LEN];
char ipv6_or_buf[TOR_ADDRPORT_BUF_LEN];
char ipv4_dir_buf[TOR_ADDRPORT_BUF_LEN];
/* There's a race condition here, between:
* - tor launching reachability tests,
* - any circuits actually completing,
* - routerinfo updates, and
* - these log messages.
* In rare cases, we might log the wrong ports, log when we didn't actually
* start reachability tests, or fail to log after we actually started
* reachability tests.
*
* After we separate the IPv4 and IPv6 reachability flags in #34067, tor
* will test any IPv6 address that it discovers after launching reachability
* checks. We'll deal with late disabled IPv6 ORPorts and IPv4 DirPorts, and
* extra or skipped log messages in #34137.
*/
const routerinfo_t *me = router_get_my_routerinfo();
if (!me)
return 0;
address = tor_dup_ip(me->addr);
if (!address)
return 0;
/* IPv4 ORPort */
strlcpy(ipv4_or_buf, fmt_addr32_port(me->addr, me->or_port),
sizeof(ipv4_or_buf));
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);
"CHECKING_REACHABILITY ORADDRESS=%s",
ipv4_or_buf);
/* IPv6 ORPort */
const bool has_ipv6 = tor_addr_port_is_valid(&me->ipv6_addr,
me->ipv6_orport, 0);
if (has_ipv6) {
strlcpy(ipv6_or_buf, fmt_addrport(&me->ipv6_addr, me->ipv6_orport),
sizeof(ipv6_or_buf));
/* We'll add an IPv6 control event in #34068. */
}
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);
/* IPv4 DirPort (there are no advertised IPv6 DirPorts) */
if (me->dir_port) {
strlcpy(ipv4_dir_buf, fmt_addr32_port(me->addr, me->dir_port),
sizeof(ipv4_dir_buf));
control_event_server_status(LOG_NOTICE,
"CHECKING_REACHABILITY DIRADDRESS=%s",
ipv4_dir_buf);
}
log_notice(LD_OR, "Now checking whether ORPort%s %s%s%s%s%s %s reachable... "
"(this may take up to %d minutes -- look for log "
"messages indicating success)",
has_ipv6 ? "s" : "",
ipv4_or_buf,
has_ipv6 ? " and " : "",
has_ipv6 ? ipv6_or_buf : "",
me->dir_port ? " and DirPort " : "",
me->dir_port ? ipv4_dir_buf : "",
has_ipv6 || me->dir_port ? "are" : "is",
TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
tor_free(address);
return 1;
}
@@ -266,7 +356,7 @@ router_orport_found_reachable(void)
log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
"the outside. Excellent.%s",
options->PublishServerDescriptor_ != NO_DIRINFO
&& check_whether_dirport_reachable(options) ?
&& router_should_skip_dirport_reachability_check(options) ?
" Publishing server descriptor." : "");
can_reach_or_port = 1;
mark_my_descriptor_dirty("ORPort found reachable");
@@ -275,6 +365,7 @@ router_orport_found_reachable(void)
if (options->TestingTorNetwork == 1) {
reschedule_descriptor_update_check();
}
/* We'll add an IPv6 event in #34068. */
control_event_server_status(LOG_NOTICE,
"REACHABILITY_SUCCEEDED ORADDRESS=%s:%d",
address, me->or_port);
@@ -297,7 +388,7 @@ router_dirport_found_reachable(void)
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) ?
&& router_should_skip_orport_reachability_check(options) ?
" Publishing server descriptor." : "");
can_reach_dir_port = 1;
if (router_should_advertise_dirport(options, me->dir_port)) {
@@ -316,7 +407,9 @@ router_dirport_found_reachable(void)
}
/** 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)
{
+6 -4
View File
@@ -15,8 +15,10 @@
#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);
int router_should_skip_orport_reachability_check(
const struct or_options_t *options);
int router_should_skip_dirport_reachability_check(
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);
@@ -29,9 +31,9 @@ void router_reset_reachability(void);
#else /* !defined(HAVE_MODULE_RELAY) */
#define check_whether_orport_reachable(opts) \
#define router_should_skip_orport_reachability_check(opts) \
((void)(opts), 0)
#define check_whether_dirport_reachable(opts) \
#define router_should_skip_dirport_reachability_check(opts) \
((void)(opts), 0)
static inline void
+2 -2
View File
@@ -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_should_skip_orport_reachability_check(options) ||
!circuit_enough_testing_circs()))
return 0;
if (!check_whether_dirport_reachable(options))
if (!router_should_skip_dirport_reachability_check(options))
return 0;
return 1;
+29 -7
View File
@@ -1217,20 +1217,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 +1250,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 +1258,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.
*
+2
View File
@@ -236,6 +236,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,
+5 -5
View File
@@ -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) {
+4 -4
View File
@@ -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"
)
}
}
+372 -5
View File
@@ -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,6 +30,7 @@
#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"
@@ -279,10 +281,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;
@@ -1176,6 +1178,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 +1192,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;
@@ -1352,6 +1359,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 */
@@ -1516,6 +1524,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_make_null(&ipv6_hop.addr, AF_INET6);
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_make_null(&ipv4_hop.addr, AF_INET);
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("Client trying to extend to a non-IPv4 address.\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("Server trying to extend to an invalid address family.\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("Client trying to extend to a non-IPv4 address.\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 +1882,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, \
@@ -1543,12 +1903,19 @@ struct testcase_t circuitbuild_tests[] = {
TEST_CIRCUIT(extend_add_ed25519, TT_FORK),
TEST_CIRCUIT(extend_lspec_valid, 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
};
+36 -55
View File
@@ -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));
extend_info_t *fakehop_list[DEFAULT_ROUTE_LEN] = {&fakehop,
&fakehop,
&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;
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));
extend_info_t fakehop;
memset(&fakehop, 0, sizeof(fakehop));
extend_info_t *fakehop_list[4] = {&fakehop,
&fakehop,
&fakehop,
&fakehop};
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;
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:
+52 -12
View File
@@ -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/or_connection_st.h"
#include "feature/nodelist/node_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 "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;
}
+5
View File
@@ -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) */
+299 -36
View File
@@ -7,14 +7,18 @@
#include "orconfig.h"
#include "test/test.h"
#include "core/or/protover.h"
#include "core/or/or.h"
#include "core/or/connection_or.h"
#include "lib/tls/tortls.h"
#include "core/or/or.h"
#include "core/or/connection_or.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,
/* Legacy LinkAuth is only supported on OpenSSL and similar. */
tt_int_op(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,
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:
;
@@ -676,6 +711,232 @@ 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));
/* "" sets the protocols_known flag */
memset(&flags, 0, sizeof(flags));
summarize_protover_flags(&flags, "", "");
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 version exceptions */
/* EXTEND2 cell support */
memset(&flags, 0, sizeof(flags));
summarize_protover_flags(&flags, NULL, "Tor 0.2.4.8-alpha");
DEBUG_PROTOVER(flags);
tt_int_op(flags.protocols_known, OP_EQ, 1);
tt_int_op(flags.supports_extend2_cells, OP_EQ, 1);
/* Now clear those flags, and check the rest are zero */
flags.protocols_known = 0;
flags.supports_extend2_cells = 0;
tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
/* disabling HSDir v3 support for buggy versions */
memset(&flags, 0, sizeof(flags));
summarize_protover_flags(&flags,
PROTOVER("HSDir", PROTOVER_HSDIR_V3),
NULL);
DEBUG_PROTOVER(flags);
tt_int_op(flags.protocols_known, OP_EQ, 1);
tt_int_op(flags.supports_v3_hsdir, OP_EQ, 1);
/* Now clear those flags, and check the rest are zero */
flags.protocols_known = 0;
flags.supports_v3_hsdir = 0;
tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
memset(&flags, 0, sizeof(flags));
summarize_protover_flags(&flags,
PROTOVER("HSDir", PROTOVER_HSDIR_V3),
"Tor 0.3.0.7");
DEBUG_PROTOVER(flags);
tt_int_op(flags.protocols_known, OP_EQ, 1);
/* Now clear that flag, and check the rest are zero */
flags.protocols_known = 0;
tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
/* Now check standard summaries */
/* LinkAuth */
memset(&flags, 0, sizeof(flags));
summarize_protover_flags(&flags,
PROTOVER("LinkAuth",
PROTOVER_LINKAUTH_ED25519_HANDSHAKE),
NULL);
DEBUG_PROTOVER(flags);
tt_int_op(flags.protocols_known, OP_EQ, 1);
tt_int_op(flags.supports_ed25519_link_handshake_compat, OP_EQ, 1);
tt_int_op(flags.supports_ed25519_link_handshake_any, OP_EQ, 1);
/* Now clear those flags, and check the rest are zero */
flags.protocols_known = 0;
flags.supports_ed25519_link_handshake_compat = 0;
flags.supports_ed25519_link_handshake_any = 0;
tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
/* Test one greater */
memset(&flags, 0, sizeof(flags));
snprintf(pv, sizeof(pv),
"%s=%d", "LinkAuth", PROTOVER_LINKAUTH_ED25519_HANDSHAKE + 1);
summarize_protover_flags(&flags, pv, NULL);
DEBUG_PROTOVER(flags);
tt_int_op(flags.protocols_known, OP_EQ, 1);
tt_int_op(flags.supports_ed25519_link_handshake_compat, OP_EQ, 0);
tt_int_op(flags.supports_ed25519_link_handshake_any, OP_EQ, 1);
/* Now clear those flags, and check the rest are zero */
flags.protocols_known = 0;
flags.supports_ed25519_link_handshake_compat = 0;
flags.supports_ed25519_link_handshake_any = 0;
tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
/* Test one less */
memset(&flags, 0, sizeof(flags));
snprintf(pv, sizeof(pv),
"%s=%d", "LinkAuth", PROTOVER_LINKAUTH_ED25519_HANDSHAKE - 1);
summarize_protover_flags(&flags, pv, NULL);
DEBUG_PROTOVER(flags);
tt_int_op(flags.protocols_known, OP_EQ, 1);
tt_int_op(flags.supports_ed25519_link_handshake_compat, OP_EQ, 0);
tt_int_op(flags.supports_ed25519_link_handshake_any, OP_EQ, 0);
/* Now clear those flags, and check the rest are zero */
flags.protocols_known = 0;
flags.supports_ed25519_link_handshake_compat = 0;
flags.supports_ed25519_link_handshake_any = 0;
tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
/* We don't test "one more" and "one less" for each protocol version.
* But that could be a useful thing to add. */
/* Relay */
memset(&flags, 0, sizeof(flags));
/* This test relies on these versions being equal */
tt_int_op(PROTOVER_RELAY_EXTEND2, OP_EQ, PROTOVER_RELAY_ACCEPT_IPV6);
summarize_protover_flags(&flags,
PROTOVER("Relay", PROTOVER_RELAY_EXTEND2), NULL);
DEBUG_PROTOVER(flags);
tt_int_op(flags.protocols_known, OP_EQ, 1);
tt_int_op(flags.supports_extend2_cells, OP_EQ, 1);
tt_int_op(flags.supports_accepting_ipv6_extends, OP_EQ, 1);
/* Now clear those flags, and check the rest are zero */
flags.protocols_known = 0;
flags.supports_extend2_cells = 0;
flags.supports_accepting_ipv6_extends = 0;
tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
memset(&flags, 0, sizeof(flags));
/* This test relies on these versions being equal */
tt_int_op(PROTOVER_RELAY_EXTEND_IPV6, OP_EQ, PROTOVER_RELAY_CANONICAL_IPV6);
summarize_protover_flags(&flags,
PROTOVER("Relay", PROTOVER_RELAY_EXTEND_IPV6),
NULL);
DEBUG_PROTOVER(flags);
tt_int_op(flags.protocols_known, OP_EQ, 1);
tt_int_op(flags.supports_accepting_ipv6_extends, OP_EQ, 1);
tt_int_op(flags.supports_initiating_ipv6_extends, OP_EQ, 1);
tt_int_op(flags.supports_canonical_ipv6_conns, OP_EQ, 1);
/* Now clear those flags, and check the rest are zero */
flags.protocols_known = 0;
flags.supports_accepting_ipv6_extends = 0;
flags.supports_initiating_ipv6_extends = 0;
flags.supports_canonical_ipv6_conns = 0;
tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
TEST_PROTOVER("HSIntro", PROTOVER_HS_INTRO_V3,
supports_ed25519_hs_intro);
TEST_PROTOVER("HSIntro", PROTOVER_HS_INTRO_DOS,
supports_establish_intro_dos_extension);
TEST_PROTOVER("HSRend", PROTOVER_HS_RENDEZVOUS_POINT_V3,
supports_v3_rendezvous_point);
TEST_PROTOVER("HSDir", PROTOVER_HSDIR_V3,
supports_v3_hsdir);
TEST_PROTOVER("Padding", PROTOVER_HS_SETUP_PADDING,
supports_hs_setup_padding);
done:
;
}
#define PV_TEST(name, flags) \
{ #name, test_protover_ ##name, (flags), NULL, NULL }
@@ -690,5 +951,7 @@ struct testcase_t protover_tests[] = {
PV_TEST(supported_protocols, 0),
PV_TEST(vote_roundtrip, 0),
PV_TEST(vote_roundtrip_ours, 0),
/* fork, because we memoize flags internally */
PV_TEST(summarize_flags, TT_FORK),
END_OF_TESTCASES
};