tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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:
Achanges/bug41023 | 5+++++
Msrc/core/or/circuitbuild.c | 37++++++-------------------------------
Msrc/core/or/circuitbuild.h | 3+--
Msrc/core/or/circuitlist.c | 31-------------------------------
Msrc/core/or/circuituse.c | 1-
Msrc/core/or/circuituse.h | 3---
Msrc/feature/dirauth/process_descs.c | 24++++++++++++++++++++++++
Msrc/feature/dirauth/process_descs.h | 3+++
Msrc/feature/dirauth/voteflags.c | 11+++++++++++
Msrc/feature/hs/hs_circuit.c | 1+
Msrc/feature/hs/hs_service.c | 2+-
Msrc/feature/nodelist/node_select.h | 6+++---
Msrc/feature/nodelist/node_st.h | 3+++
Msrc/feature/nodelist/routerlist.c | 11+++++------
Msrc/test/test_entrynodes.c | 4++--
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 */