commit 26e44beb690d785f70201a89e2c180911aeedbbc
parent a252601ff0b83c28684c3a536efa877463ba8e2a
Author: David Goulet <dgoulet@torproject.org>
Date: Thu, 20 Mar 2025 09:53:16 -0400
Merge branch 'maint-0.4.8'
Diffstat:
15 files changed, 65 insertions(+), 80 deletions(-)
diff --git a/changes/bug41023 b/changes/bug41023
@@ -0,0 +1,5 @@
+ o Minor bugfixes (relay flag usage):
+ - Fix client usage of the MiddleOnly flag so that MiddleOnly relays are
+ not used as HS IP or RP by clients or services. Additionally, give
+ dirauths the ability to remove specific flags, as an alternative to
+ MiddleOnly. Fixes bug 41023; bugfix on 0.4.7.2-alpha
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
@@ -478,15 +478,10 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *exit_ei, int flags)
{
origin_circuit_t *circ;
int err_reason = 0;
- int is_hs_v3_rp_circuit = 0;
-
- if (flags & CIRCLAUNCH_IS_V3_RP) {
- is_hs_v3_rp_circuit = 1;
- }
circ = origin_circuit_init(purpose, flags);
- if (onion_pick_cpath_exit(circ, exit_ei, is_hs_v3_rp_circuit) < 0 ||
+ if (onion_pick_cpath_exit(circ, exit_ei) < 0 ||
onion_populate_cpath(circ) < 0) {
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NOPATH);
return NULL;
@@ -527,7 +522,7 @@ circuit_establish_circuit_conflux,(const uint8_t *conflux_nonce,
TO_CIRCUIT(circ)->conflux_pending_nonce =
tor_memdup(conflux_nonce, DIGEST256_LEN);
- if (onion_pick_cpath_exit(circ, exit_ei, 0) < 0 ||
+ if (onion_pick_cpath_exit(circ, exit_ei) < 0 ||
onion_populate_cpath(circ) < 0) {
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NOPATH);
return NULL;
@@ -1657,10 +1652,6 @@ choose_good_exit_server_general(router_crn_flags_t flags)
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)
@@ -1834,14 +1825,6 @@ choose_good_exit_server_general(router_crn_flags_t flags)
return NULL;
}
-/* Pick a Rendezvous Point for our HS circuits according to <b>flags</b>. */
-static const node_t *
-pick_rendezvous_node(router_crn_flags_t flags)
-{
- const or_options_t *options = get_options();
- return router_choose_random_node(NULL, options->ExcludeNodes, flags);
-}
-
/*
* Helper function to pick a configured restricted middle node
* (either HSLayer2Nodes or HSLayer3Nodes).
@@ -1949,9 +1932,12 @@ choose_good_exit_server(origin_circuit_t *circ,
case CIRCUIT_PURPOSE_C_HSDIR_GET:
case CIRCUIT_PURPOSE_S_HSDIR_POST:
case CIRCUIT_PURPOSE_HS_VANGUARDS:
+ case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
/* For these three, we want to pick the exit like a middle hop,
* since it should be random. */
tor_assert_nonfatal(is_internal);
+ /* We want to avoid picking certain nodes for HS purposes. */
+ flags |= CRN_FOR_HS;
FALLTHROUGH;
case CIRCUIT_PURPOSE_CONFLUX_UNLINKED:
case CIRCUIT_PURPOSE_C_GENERAL:
@@ -1959,14 +1945,6 @@ choose_good_exit_server(origin_circuit_t *circ,
return router_choose_random_node(NULL, options->ExcludeNodes, flags);
else
return choose_good_exit_server_general(flags);
- case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
- {
- /* Pick a new RP */
- const node_t *rendezvous_node = pick_rendezvous_node(flags);
- log_info(LD_REND, "Picked new RP: %s",
- safe_str_client(node_describe(rendezvous_node)));
- return rendezvous_node;
- }
}
log_warn(LD_BUG,"Unhandled purpose %d", TO_CIRCUIT(circ)->purpose);
tor_fragile_assert();
@@ -2099,8 +2077,7 @@ cpath_build_state_to_crn_ipv6_extend_flag(const cpath_build_state_t *state,
*
* Return 0 if ok, -1 if circuit should be closed. */
STATIC int
-onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
- int is_hs_v3_rp_circuit)
+onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei)
{
cpath_build_state_t *state = circ->build_state;
@@ -2128,8 +2105,6 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
* (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;
if (state->need_conflux)
flags |= CRN_CONFLUX;
const node_t *node =
diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h
@@ -84,8 +84,7 @@ MOCK_DECL(STATIC int, count_acceptable_nodes, (const smartlist_t *nodes,
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);
+onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei);
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,
diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c
@@ -1828,30 +1828,6 @@ circuit_get_next_by_purpose(origin_circuit_t *start, uint8_t purpose)
return NULL;
}
-/** We might cannibalize this circuit: Return true if its last hop can be used
- * as a v3 rendezvous point. */
-static int
-circuit_can_be_cannibalized_for_v3_rp(const origin_circuit_t *circ)
-{
- if (!circ->build_state) {
- return 0;
- }
-
- extend_info_t *chosen_exit = circ->build_state->chosen_exit;
- if (BUG(!chosen_exit)) {
- return 0;
- }
-
- const node_t *rp_node = node_get_by_id(chosen_exit->identity_digest);
- if (rp_node) {
- if (node_supports_v3_rendezvous_point(rp_node)) {
- return 1;
- }
- }
-
- return 0;
-}
-
/** We are trying to create a circuit of purpose <b>purpose</b> and we are
* looking for cannibalizable circuits. Return the circuit purpose we would be
* willing to cannibalize. */
@@ -1981,13 +1957,6 @@ circuit_find_to_cannibalize(uint8_t purpose_to_produce, extend_info_t *info,
} while (hop != circ->cpath);
}
- if ((flags & CIRCLAUNCH_IS_V3_RP) &&
- !circuit_can_be_cannibalized_for_v3_rp(circ)) {
- log_debug(LD_GENERAL, "Skipping uncannibalizable circuit for v3 "
- "rendezvous point.");
- goto next;
- }
-
if (!best || (best->build_state->need_uptime && !need_uptime))
best = circ;
next: ;
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
@@ -2523,7 +2523,6 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_REND_JOINED &&
new_circ_purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
ENTRY_TO_EDGE_CONN(conn)->hs_ident) {
- flags |= CIRCLAUNCH_IS_V3_RP;
log_info(LD_GENERAL, "Getting rendezvous circuit to v3 service!");
}
diff --git a/src/core/or/circuituse.h b/src/core/or/circuituse.h
@@ -44,9 +44,6 @@ void circuit_build_failed(origin_circuit_t *circ);
/** Flag to set when the last hop of a circuit doesn't need to be an
* exit node. */
#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)
/** 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
diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c
@@ -228,6 +228,12 @@ dirserv_load_fingerprint_file(void)
add_status = RTR_INVALID;
} else if (!strcasecmp(nickname, "!middleonly")) {
add_status = RTR_MIDDLEONLY;
+ } else if (!strcasecmp(nickname, "!stripexit")) {
+ add_status = RTR_STRIPGUARD;
+ } else if (!strcasecmp(nickname, "!striphsdir")) {
+ add_status = RTR_STRIPHSDIR;
+ } else if (!strcasecmp(nickname, "!stripv2dir")) {
+ add_status = RTR_STRIPV2DIR;
}
/* Check if fingerprint is RSA or ed25519 by verifying it. */
@@ -627,6 +633,9 @@ dirserv_set_node_flags_from_authoritative_status(node_t *node,
node->is_valid = (authstatus & RTR_INVALID) ? 0 : 1;
node->is_bad_exit = (authstatus & RTR_BADEXIT) ? 1 : 0;
node->is_middle_only = (authstatus & RTR_MIDDLEONLY) ? 1 : 0;
+ node->strip_guard = (authstatus & RTR_STRIPGUARD) ? 1 : 0;
+ node->strip_hsdir = (authstatus & RTR_STRIPHSDIR) ? 1 : 0;
+ node->strip_v2dir = (authstatus & RTR_STRIPV2DIR) ? 1 : 0;
}
/** True iff <b>a</b> is more severe than <b>b</b>. */
@@ -975,6 +984,21 @@ directory_remove_invalid(void)
(r & RTR_MIDDLEONLY) ? "" : "not");
node->is_middle_only = (r&RTR_MIDDLEONLY) ? 1: 0;
}
+ if (bool_neq((r & RTR_STRIPGUARD), node->strip_guard)) {
+ log_info(LD_DIRSERV, "Router '%s' is now %s guard", description,
+ (r & RTR_STRIPGUARD) ? "stripped of" : "not");
+ node->strip_guard = (r&RTR_STRIPGUARD) ? 1: 0;
+ }
+ if (bool_neq((r & RTR_STRIPHSDIR), node->strip_hsdir)) {
+ log_info(LD_DIRSERV, "Router '%s' is now %s hidden service directory",
+ description, (r & RTR_STRIPHSDIR) ? "stripped of" : "not");
+ node->strip_hsdir = (r&RTR_STRIPHSDIR) ? 1: 0;
+ }
+ if (bool_neq((r & RTR_STRIPV2DIR), node->strip_v2dir)) {
+ log_info(LD_DIRSERV, "Router '%s' is now %s v2 directory",
+ description, (r & RTR_STRIPV2DIR) ? "stripped of" : "not");
+ node->strip_v2dir = (r&RTR_STRIPV2DIR) ? 1: 0;
+ }
} SMARTLIST_FOREACH_END(node);
routerlist_assert_ok(rl);
diff --git a/src/feature/dirauth/process_descs.h b/src/feature/dirauth/process_descs.h
@@ -47,6 +47,9 @@ typedef struct authdir_config_t {
#define RTR_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */
/** We'll vote to only use this router as a midpoint. */
#define RTR_MIDDLEONLY 32
+#define RTR_STRIPGUARD 64
+#define RTR_STRIPHSDIR 128
+#define RTR_STRIPV2DIR 256
#endif /* defined(PROCESS_DESCS_PRIVATE) || defined(TOR_UNIT_TESTS) */
diff --git a/src/feature/dirauth/voteflags.c b/src/feature/dirauth/voteflags.c
@@ -610,6 +610,17 @@ dirauth_set_routerstatus_from_routerinfo(routerstatus_t *rs,
rs->is_exit = rs->is_possible_guard = rs->is_hs_dir = rs->is_v2_dir = 0;
}
+ /* Strip rs flags based on node flags. */
+ if (node->strip_guard) {
+ rs->is_possible_guard = 0;
+ }
+ if (node->strip_hsdir) {
+ rs->is_hs_dir = 0;
+ }
+ if (node->strip_v2dir) {
+ rs->is_v2_dir = 0;
+ }
+
/* Set rs->is_staledesc. */
rs->is_staledesc =
(ri->cache_info.published_on + DESC_IS_STALE_INTERVAL) < now;
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
@@ -44,6 +44,7 @@
#include "core/or/congestion_control_st.h"
#include "core/or/cpath_build_state_st.h"
#include "core/or/crypt_path_st.h"
+#include "core/or/extend_info_st.h"
#include "feature/nodelist/node_st.h"
#include "core/or/origin_circuit_st.h"
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
@@ -2193,7 +2193,7 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes)
const node_t *node;
hs_service_intro_point_t *ip = NULL;
/* Normal 3-hop introduction point flags. */
- router_crn_flags_t flags = CRN_NEED_UPTIME | CRN_NEED_DESC;
+ router_crn_flags_t flags = CRN_NEED_UPTIME | CRN_NEED_DESC | CRN_FOR_HS;
/* Single onion flags. */
router_crn_flags_t direct_flags = flags | CRN_PREF_ADDR | CRN_DIRECT_CONN;
diff --git a/src/feature/nodelist/node_select.h b/src/feature/nodelist/node_select.h
@@ -29,9 +29,9 @@ typedef enum router_crn_flags_t {
/* 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, indiate that we need a HS related circuit (IP, HSDir or RP).
+ * This is used in order to avoid certain nodes for these purposes. */
+ CRN_FOR_HS = 1<<6,
/* On clients, only provide nodes that can initiate IPv6 extends. */
CRN_INITIATE_IPV6_EXTEND = 1<<7,
/* On clients, only provide nodes that support Conflux (Relay=5). */
diff --git a/src/feature/nodelist/node_st.h b/src/feature/nodelist/node_st.h
@@ -74,6 +74,9 @@ struct node_t {
unsigned int is_middle_only:1;
unsigned int is_hs_dir:1; /**< True iff this router is a hidden service
* directory according to the authorities. */
+ unsigned int strip_guard:1; /**< True iff we should strip the Guard flag. */
+ unsigned int strip_hsdir:1; /**< True iff we should strip the HSDir flag. */
+ unsigned int strip_v2dir:1; /**< True iff we should strip the V2Dir flag. */
/* Local info: warning state. */
diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c
@@ -556,9 +556,9 @@ router_can_choose_node(const node_t *node, int flags)
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 bool need_conflux = (flags & CRN_CONFLUX) != 0;
+ const bool for_hs = (flags & CRN_FOR_HS) != 0;
const or_options_t *options = get_options();
const bool check_reach =
@@ -588,11 +588,6 @@ router_can_choose_node(const node_t *node, int flags)
* 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;
/* Exclude relay that don't do conflux if requested. */
if (need_conflux && !node_supports_conflux(node)) {
return false;
@@ -605,6 +600,10 @@ router_can_choose_node(const node_t *node, int flags)
return false;
if (initiate_ipv6_extend && !node_supports_initiating_ipv6_extends(node))
return false;
+ /* MiddleOnly node should never be used for HS ndpoints (IP, RP, HSDir). */
+ if (for_hs && node->is_middle_only) {
+ return false;
+ }
return true;
}
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
@@ -3054,7 +3054,7 @@ test_entry_guard_basic_path_selection(void *arg)
oc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
/* First pick the exit and pin it on the build_state */
- retval = onion_pick_cpath_exit(oc, NULL, 0);
+ retval = onion_pick_cpath_exit(oc, NULL);
tt_int_op(retval, OP_EQ, 0);
/* Extend path 3 times. First we pick guard, then middle, then exit. */
@@ -3122,7 +3122,7 @@ test_entry_guard_vanguard_path_selection(void *arg)
/* First pick the exit and pin it on the build_state */
tt_int_op(oc->build_state->desired_path_len, OP_EQ, 0);
- retval = onion_pick_cpath_exit(oc, NULL, 0);
+ retval = onion_pick_cpath_exit(oc, NULL);
tt_int_op(retval, OP_EQ, 0);
/* Ensure that vanguards make 4-hop circuits by default */