summaryrefslogtreecommitdiff
path: root/src/feature
diff options
context:
space:
mode:
Diffstat (limited to 'src/feature')
-rw-r--r--src/feature/control/control_getinfo.c17
-rw-r--r--src/feature/nodelist/node_select.c152
-rw-r--r--src/feature/nodelist/node_select.h28
-rw-r--r--src/feature/nodelist/node_st.h5
-rw-r--r--src/feature/nodelist/nodelist.c76
-rw-r--r--src/feature/nodelist/nodelist.h16
-rw-r--r--src/feature/nodelist/routerinfo.c35
-rw-r--r--src/feature/nodelist/routerinfo.h5
-rw-r--r--src/feature/nodelist/routerlist.c150
-rw-r--r--src/feature/nodelist/routerlist.h14
-rw-r--r--src/feature/relay/relay_periodic.c4
-rw-r--r--src/feature/relay/router.c21
-rw-r--r--src/feature/relay/selftest.c231
-rw-r--r--src/feature/relay/selftest.h10
-rw-r--r--src/feature/stats/predict_ports.c4
15 files changed, 524 insertions, 244 deletions
diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c
index 0823acbe07..c2557e164c 100644
--- a/src/feature/control/control_getinfo.c
+++ b/src/feature/control/control_getinfo.c
@@ -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/")) {
diff --git a/src/feature/nodelist/node_select.c b/src/feature/nodelist/node_select.c
index e831248413..25904d4c63 100644
--- a/src/feature/nodelist/node_select.c
+++ b/src/feature/nodelist/node_select.c
@@ -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,64 +930,67 @@ nodelist_subtract(smartlist_t *sl, const smartlist_t *excluded)
bitarray_free(excluded_idx);
}
-/** Return a random running node from the nodelist. Never
- * pick a node that is in
- * <b>excludedsmartlist</b>, or which matches <b>excludedset</b>,
- * even if they are the only nodes available.
- * If <b>CRN_NEED_UPTIME</b> is set in flags and any router has more than
- * a minimum uptime, return one of those.
- * If <b>CRN_NEED_CAPACITY</b> is set in flags, weight your choice by the
- * advertised capacity of each router.
- * If <b>CRN_NEED_GUARD</b> is set in flags, consider only Guard routers.
- * If <b>CRN_WEIGHT_AS_EXIT</b> is set in flags, we weight bandwidths as if
- * picking an exit node, otherwise we weight bandwidths for picking a relay
- * node (that is, possibly discounting exit nodes).
- * If <b>CRN_NEED_DESC</b> is set in flags, we only consider nodes that
- * have a routerinfo or microdescriptor -- that is, enough info to be
- * used to build a circuit.
- * If <b>CRN_PREF_ADDR</b> is set in flags, we only consider nodes that
- * have an address that is preferred by the ClientPreferIPv6ORPort setting
- * (regardless of this flag, we exclude nodes that aren't allowed by the
- * firewall, including ClientUseIPv4 0 and fascist_firewall_use_ipv6() == 0).
+/* Node selection helper for router_choose_random_node().
+ *
+ * Populates a node list based on <b>flags</b>, ignoring nodes in
+ * <b>excludednodes</b> and <b>excludedset</b>. Chooses the node based on
+ * <b>rule</b>. */
+static const node_t *
+router_choose_random_node_helper(smartlist_t *excludednodes,
+ routerset_t *excludedset,
+ router_crn_flags_t flags,
+ bandwidth_weight_rule_t rule)
+{
+ smartlist_t *sl=smartlist_new();
+ const node_t *choice = NULL;
+
+ router_add_running_nodes_to_smartlist(sl, flags);
+ log_debug(LD_CIRC,
+ "We found %d running nodes.",
+ smartlist_len(sl));
+
+ nodelist_subtract(sl, excludednodes);
+
+ if (excludedset) {
+ routerset_subtract_nodes(sl,excludedset);
+ log_debug(LD_CIRC,
+ "We removed excludedset, leaving %d nodes.",
+ smartlist_len(sl));
+ }
+
+ // Always weight by bandwidth
+ choice = node_sl_choose_by_bandwidth(sl, rule);
+
+ smartlist_free(sl);
+
+ return choice;
+}
+
+/** Return a random running node from the nodelist. Never pick a node that is
+ * in <b>excludedsmartlist</b>, or which matches <b>excludedset</b>, even if
+ * they are the only nodes available.
+ *
+ * <b>flags</b> is a set of CRN_* flags, see
+ * router_add_running_nodes_to_smartlist() for details.
*/
const node_t *
router_choose_random_node(smartlist_t *excludedsmartlist,
routerset_t *excludedset,
router_crn_flags_t flags)
-{ /* XXXX MOVE */
- const int need_uptime = (flags & CRN_NEED_UPTIME) != 0;
- const int need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
- const int need_guard = (flags & CRN_NEED_GUARD) != 0;
- const int weight_for_exit = (flags & CRN_WEIGHT_AS_EXIT) != 0;
- const int need_desc = (flags & CRN_NEED_DESC) != 0;
- const int pref_addr = (flags & CRN_PREF_ADDR) != 0;
- const int direct_conn = (flags & CRN_DIRECT_CONN) != 0;
- const int rendezvous_v3 = (flags & CRN_RENDEZVOUS_V3) != 0;
-
- const smartlist_t *node_list = nodelist_get_list();
- smartlist_t *sl=smartlist_new(),
- *excludednodes=smartlist_new();
+{
+ /* A limited set of flags, used for fallback node selection.
+ */
+ const bool need_uptime = (flags & CRN_NEED_UPTIME) != 0;
+ const bool need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
+ const bool need_guard = (flags & CRN_NEED_GUARD) != 0;
+ const bool pref_addr = (flags & CRN_PREF_ADDR) != 0;
+
+ smartlist_t *excludednodes=smartlist_new();
const node_t *choice = NULL;
const routerinfo_t *r;
bandwidth_weight_rule_t rule;
- tor_assert(!(weight_for_exit && need_guard));
- rule = weight_for_exit ? WEIGHT_FOR_EXIT :
- (need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID);
-
- SMARTLIST_FOREACH_BEGIN(node_list, const node_t *, node) {
- if (node_allows_single_hop_exits(node)) {
- /* Exclude relays that allow single hop exit circuits. This is an
- * obsolete option since 0.2.9.2-alpha and done by default in
- * 0.3.1.0-alpha. */
- smartlist_add(excludednodes, (node_t*)node);
- } else if (rendezvous_v3 &&
- !node_supports_v3_rendezvous_point(node)) {
- /* Exclude relays that do not support to rendezvous for a hidden service
- * version 3. */
- smartlist_add(excludednodes, (node_t*)node);
- }
- } SMARTLIST_FOREACH_END(node);
+ rule = (need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID);
/* If the node_t is not found we won't be to exclude ourself but we
* won't be able to pick ourself in router_choose_random_node() so
@@ -991,41 +998,30 @@ router_choose_random_node(smartlist_t *excludedsmartlist,
if ((r = router_get_my_routerinfo()))
routerlist_add_node_and_family(excludednodes, r);
- router_add_running_nodes_to_smartlist(sl, need_uptime, need_capacity,
- need_guard, need_desc, pref_addr,
- direct_conn);
- log_debug(LD_CIRC,
- "We found %d running nodes.",
- smartlist_len(sl));
-
if (excludedsmartlist) {
smartlist_add_all(excludednodes, excludedsmartlist);
}
- nodelist_subtract(sl, excludednodes);
- if (excludedset) {
- routerset_subtract_nodes(sl,excludedset);
- log_debug(LD_CIRC,
- "We removed excludedset, leaving %d nodes.",
- smartlist_len(sl));
- }
+ choice = router_choose_random_node_helper(excludednodes,
+ excludedset,
+ flags,
+ rule);
- // Always weight by bandwidth
- choice = node_sl_choose_by_bandwidth(sl, rule);
-
- smartlist_free(sl);
if (!choice && (need_uptime || need_capacity || need_guard || pref_addr)) {
- /* try once more -- recurse but with fewer restrictions. */
+ /* try once more, with fewer restrictions. */
log_info(LD_CIRC,
- "We couldn't find any live%s%s%s routers; falling back "
+ "We couldn't find any live%s%s%s%s routers; falling back "
"to list of all routers.",
need_capacity?", fast":"",
need_uptime?", stable":"",
- need_guard?", guard":"");
+ need_guard?", guard":"",
+ pref_addr?", preferred address":"");
flags &= ~ (CRN_NEED_UPTIME|CRN_NEED_CAPACITY|CRN_NEED_GUARD|
CRN_PREF_ADDR);
- choice = router_choose_random_node(
- excludedsmartlist, excludedset, flags);
+ choice = router_choose_random_node_helper(excludednodes,
+ excludedset,
+ flags,
+ rule);
}
smartlist_free(excludednodes);
if (!choice) {
@@ -1120,8 +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)
diff --git a/src/feature/nodelist/node_select.h b/src/feature/nodelist/node_select.h
index 2e67f990f6..1776d8ea1a 100644
--- a/src/feature/nodelist/node_select.h
+++ b/src/feature/nodelist/node_select.h
@@ -14,20 +14,26 @@
/** Flags to be passed to control router_choose_random_node() to indicate what
* kind of nodes to pick according to what algorithm. */
typedef enum router_crn_flags_t {
+ /* Try to choose stable nodes. */
CRN_NEED_UPTIME = 1<<0,
+ /* Try to choose nodes with a reasonable amount of bandwidth. */
CRN_NEED_CAPACITY = 1<<1,
- CRN_NEED_GUARD = 1<<2,
- /* XXXX not used, apparently. */
- CRN_WEIGHT_AS_EXIT = 1<<5,
- CRN_NEED_DESC = 1<<6,
- /* On clients, only provide nodes that satisfy ClientPreferIPv6OR */
- CRN_PREF_ADDR = 1<<7,
+ /* Only choose nodes if we have downloaded their descriptor or
+ * microdescriptor. */
+ CRN_NEED_DESC = 1<<2,
+ /* Choose nodes that can be used as Guard relays. */
+ CRN_NEED_GUARD = 1<<3,
/* On clients, only provide nodes that we can connect to directly, based on
- * our firewall rules */
- CRN_DIRECT_CONN = 1<<8,
- /* On clients, only provide nodes with HSRend >= 2 protocol version which
- * is required for hidden service version >= 3. */
- CRN_RENDEZVOUS_V3 = 1<<9,
+ * our firewall rules. */
+ CRN_DIRECT_CONN = 1<<4,
+ /* On clients, if choosing a node for a direct connection, only provide
+ * nodes that satisfy ClientPreferIPv6OR. */
+ CRN_PREF_ADDR = 1<<5,
+ /* On clients, only provide nodes with HSRend=2 protocol version which
+ * is required for hidden service version 3. */
+ CRN_RENDEZVOUS_V3 = 1<<6,
+ /* On clients, only provide nodes that can initiate IPv6 extends. */
+ CRN_INITIATE_IPV6_EXTEND = 1<<7,
} router_crn_flags_t;
/** Possible ways to weight routers when choosing one randomly. See
diff --git a/src/feature/nodelist/node_st.h b/src/feature/nodelist/node_st.h
index b1ec4db202..3769f9dc84 100644
--- a/src/feature/nodelist/node_st.h
+++ b/src/feature/nodelist/node_st.h
@@ -84,12 +84,11 @@ struct node_t {
/* Local info: derived. */
- /** True if the IPv6 OR port is preferred over the IPv4 OR port.
- * XX/teor - can this become out of date if the torrc changes? */
+ /** True if the IPv6 OR port is preferred over the IPv4 OR port. */
unsigned int ipv6_preferred:1;
/** According to the geoip db what country is this router in? */
- /* XXXprop186 what is this suppose to mean with multiple OR ports? */
+ /* IPv6: what is this supposed to mean with multiple OR ports? */
country_t country;
/* The below items are used only by authdirservers for
diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c
index 7454f342f9..6b2c0d2016 100644
--- a/src/feature/nodelist/nodelist.c
+++ b/src/feature/nodelist/nodelist.c
@@ -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,9 +1193,24 @@ node_supports_ed25519_hs_intro(const node_t *node)
return node_get_protover_summary_flags(node)->supports_ed25519_hs_intro;
}
+/** Return true iff <b>node</b> can be a rendezvous point for hidden
+ * service version 3 (HSRend=2). */
+bool
+node_supports_v3_rendezvous_point(const node_t *node)
+{
+ tor_assert(node);
+
+ /* We can't use a v3 rendezvous point without the curve25519 onion pk. */
+ if (!node_get_curve25519_onion_key(node)) {
+ return 0;
+ }
+
+ return node_get_protover_summary_flags(node)->supports_v3_rendezvous_point;
+}
+
/** Return true iff <b>node</b> supports the DoS ESTABLISH_INTRO cell
* extenstion. */
-int
+bool
node_supports_establish_intro_dos_extension(const node_t *node)
{
tor_assert(node);
@@ -1204,19 +1219,54 @@ node_supports_establish_intro_dos_extension(const node_t *node)
supports_establish_intro_dos_extension;
}
-/** Return true iff <b>node</b> supports to be a rendezvous point for hidden
- * service version 3 (HSRend=2). */
-int
-node_supports_v3_rendezvous_point(const node_t *node)
+/** Return true iff <b>node</b> can initiate IPv6 extends (Relay=3).
+ *
+ * This check should only be performed by client path selection code.
+ *
+ * Extending relays should check their own IPv6 support using
+ * router_can_extend_over_ipv6(). Like other extends, they should not verify
+ * the link specifiers in the extend cell against the consensus, because it
+ * may be out of date. */
+bool
+node_supports_initiating_ipv6_extends(const node_t *node)
{
tor_assert(node);
- /* We can't use a v3 rendezvous point without the curve25519 onion pk. */
- if (!node_get_curve25519_onion_key(node)) {
+ /* Relays can't initiate an IPv6 extend, unless they have an IPv6 ORPort. */
+ if (!node_has_ipv6_orport(node)) {
return 0;
}
- return node_get_protover_summary_flags(node)->supports_v3_rendezvous_point;
+ /* Initiating relays also need to support the relevant protocol version. */
+ return
+ node_get_protover_summary_flags(node)->supports_initiating_ipv6_extends;
+}
+
+/** Return true iff <b>node</b> can accept IPv6 extends (Relay=2 or Relay=3)
+ * from other relays. If <b>need_canonical_ipv6_conn</b> is true, also check
+ * if the relay supports canonical IPv6 connections (Relay=3 only).
+ *
+ * This check should only be performed by client path selection code.
+ */
+bool
+node_supports_accepting_ipv6_extends(const node_t *node,
+ bool need_canonical_ipv6_conn)
+{
+ tor_assert(node);
+
+ /* Relays can't accept an IPv6 extend, unless they have an IPv6 ORPort. */
+ if (!node_has_ipv6_orport(node)) {
+ return 0;
+ }
+
+ /* Accepting relays also need to support the relevant protocol version. */
+ if (need_canonical_ipv6_conn) {
+ return
+ node_get_protover_summary_flags(node)->supports_canonical_ipv6_conns;
+ } else {
+ return
+ node_get_protover_summary_flags(node)->supports_accepting_ipv6_extends;
+ }
}
/** Return the RSA ID key's SHA1 digest for the provided node. */
diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h
index 57ab2d5913..4ba699d69d 100644
--- a/src/feature/nodelist/nodelist.h
+++ b/src/feature/nodelist/nodelist.h
@@ -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));
diff --git a/src/feature/nodelist/routerinfo.c b/src/feature/nodelist/routerinfo.c
index 0bf2a977f5..55f21dfe67 100644
--- a/src/feature/nodelist/routerinfo.c
+++ b/src/feature/nodelist/routerinfo.c
@@ -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
diff --git a/src/feature/nodelist/routerinfo.h b/src/feature/nodelist/routerinfo.h
index 604e478999..2e12cbeba3 100644
--- a/src/feature/nodelist/routerinfo.h
+++ b/src/feature/nodelist/routerinfo.h
@@ -12,8 +12,9 @@
#ifndef TOR_ROUTERINFO_H
#define TOR_ROUTERINFO_H
-void router_get_prim_orport(const routerinfo_t *router,
- tor_addr_port_t *addr_port_out);
+int router_get_orport(const routerinfo_t *router,
+ tor_addr_port_t *addr_port_out,
+ int family);
int router_has_orport(const routerinfo_t *router,
const tor_addr_port_t *orport);
diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c
index 80c1aa6893..ece3379fa5 100644
--- a/src/feature/nodelist/routerlist.c
+++ b/src/feature/nodelist/routerlist.c
@@ -465,11 +465,20 @@ router_reload_router_list(void)
return 0;
}
-/* When iterating through the routerlist, can OR address/port preference
- * and reachability checks be skipped?
+/* When selecting a router for a direct connection, can OR address/port
+ * preference and reachability checks be skipped?
+ *
+ * Servers never check ReachableAddresses or ClientPreferIPv6. Returns
+ * true for servers.
+ *
+ * Otherwise, if <b>try_ip_pref</b> is true, returns false. Used to make
+ * clients check ClientPreferIPv6, even if ReachableAddresses is not set.
+ * Finally, return true if ReachableAddresses is set.
*/
int
-router_skip_or_reachability(const or_options_t *options, int try_ip_pref)
+router_or_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref)
{
/* Servers always have and prefer IPv4.
* And if clients are checking against the firewall for reachability only,
@@ -477,11 +486,15 @@ router_skip_or_reachability(const or_options_t *options, int try_ip_pref)
return server_mode(options) || (!try_ip_pref && !firewall_is_fascist_or());
}
-/* When iterating through the routerlist, can Dir address/port preference
+/* When selecting a router for a direct connection, can Dir address/port
* and reachability checks be skipped?
+ *
+ * This function is obsolete, because clients only use ORPorts.
*/
int
-router_skip_dir_reachability(const or_options_t *options, int try_ip_pref)
+router_dir_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref)
{
/* Servers always have and prefer IPv4.
* And if clients are checking against the firewall for reachability only,
@@ -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)
-{
- const int check_reach = !router_skip_or_reachability(get_options(),
- pref_addr);
- /* XXXX MOVE */
+router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags)
+{
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
- if (!node->is_running || !node->is_valid)
- continue;
- if (need_desc && !node_has_preferred_descriptor(node, direct_conn))
- continue;
- if (node->ri && node->ri->purpose != ROUTER_PURPOSE_GENERAL)
+ if (!router_can_choose_node(node, flags))
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);
}
diff --git a/src/feature/nodelist/routerlist.h b/src/feature/nodelist/routerlist.h
index 81a2343540..98472b2771 100644
--- a/src/feature/nodelist/routerlist.h
+++ b/src/feature/nodelist/routerlist.h
@@ -50,14 +50,16 @@ typedef enum was_router_added_t {
int router_reload_router_list(void);
-int router_skip_or_reachability(const or_options_t *options, int try_ip_pref);
-int router_skip_dir_reachability(const or_options_t *options, int try_ip_pref);
+int router_or_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref);
+int router_dir_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref);
void router_reset_status_download_failures(void);
int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2);
-void router_add_running_nodes_to_smartlist(smartlist_t *sl, int need_uptime,
- int need_capacity, int need_guard,
- int need_desc, int pref_addr,
- int direct_conn);
+bool router_can_choose_node(const node_t *node, int flags);
+void router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags);
const routerinfo_t *routerlist_find_my_routerinfo(void);
uint32_t router_get_advertised_bandwidth(const routerinfo_t *router);
diff --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c
index 08ad110cf6..6a92f49d2e 100644
--- a/src/feature/relay/relay_periodic.c
+++ b/src/feature/relay/relay_periodic.c
@@ -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,
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index 34d8163c36..6914946729 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -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))
{
diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c
index 18fe25b989..2b0fc951b7 100644
--- a/src/feature/relay/selftest.c
+++ b/src/feature/relay/selftest.c
@@ -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);
+ "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. */
+ }
+ /* IPv4 DirPort (there are no advertised IPv6 DirPorts) */
if (me->dir_port) {
- tor_snprintf(dirbuf, sizeof(dirbuf), " and DirPort %s:%d",
- address, 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:%d",
- address, me->dir_port);
+ "CHECKING_REACHABILITY DIRADDRESS=%s",
+ ipv4_dir_buf);
}
- log_notice(LD_OR, "Now checking whether ORPort %s:%d%s %s reachable... "
- "(this may take up to %d minutes -- look for log "
- "messages indicating success)",
- address, me->or_port,
- me->dir_port ? dirbuf : "",
- me->dir_port ? "are" : "is",
- TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
-
- tor_free(address);
+ 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);
+
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)
{
diff --git a/src/feature/relay/selftest.h b/src/feature/relay/selftest.h
index f5babc95da..5799a6ca33 100644
--- a/src/feature/relay/selftest.h
+++ b/src/feature/relay/selftest.h
@@ -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
diff --git a/src/feature/stats/predict_ports.c b/src/feature/stats/predict_ports.c
index d728f106a2..440cea6725 100644
--- a/src/feature/stats/predict_ports.c
+++ b/src/feature/stats/predict_ports.c
@@ -270,10 +270,10 @@ rep_hist_circbuilding_dormant(time_t now)
/* see if we'll still need to build testing circuits */
if (server_mode(options) &&
- (!check_whether_orport_reachable(options) ||
+ (!router_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;