mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
prop224: Pick rendezvous point of protover HSRend=2
Version 3 hidden service needs rendezvous point that have the protocol version HSRend >= 2 else the rendezvous cells are rejected. Fixes #23361 Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
parent
209bfe715c
commit
c527cde82f
@ -71,7 +71,8 @@ static channel_t * channel_connect_for_circuit(const tor_addr_t *addr,
|
||||
static int circuit_deliver_create_cell(circuit_t *circ,
|
||||
const create_cell_t *create_cell,
|
||||
int relayed);
|
||||
static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit);
|
||||
static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit,
|
||||
int is_hs_v3_rp_circuit);
|
||||
static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
|
||||
static int onion_extend_cpath(origin_circuit_t *circ);
|
||||
static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
|
||||
@ -505,10 +506,15 @@ 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) < 0 ||
|
||||
if (onion_pick_cpath_exit(circ, exit_ei, is_hs_v3_rp_circuit) < 0 ||
|
||||
onion_populate_cpath(circ) < 0) {
|
||||
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NOPATH);
|
||||
return NULL;
|
||||
@ -2156,7 +2162,8 @@ pick_rendezvous_node(router_crn_flags_t flags)
|
||||
*/
|
||||
static const node_t *
|
||||
choose_good_exit_server(uint8_t purpose,
|
||||
int need_uptime, int need_capacity, int is_internal)
|
||||
int need_uptime, int need_capacity, int is_internal,
|
||||
int need_hs_v3)
|
||||
{
|
||||
const or_options_t *options = get_options();
|
||||
router_crn_flags_t flags = CRN_NEED_DESC;
|
||||
@ -2164,6 +2171,8 @@ choose_good_exit_server(uint8_t purpose,
|
||||
flags |= CRN_NEED_UPTIME;
|
||||
if (need_capacity)
|
||||
flags |= CRN_NEED_CAPACITY;
|
||||
if (need_hs_v3)
|
||||
flags |= CRN_RENDEZVOUS_V3;
|
||||
|
||||
switch (purpose) {
|
||||
case CIRCUIT_PURPOSE_C_GENERAL:
|
||||
@ -2263,9 +2272,15 @@ warn_if_last_router_excluded(origin_circuit_t *circ,
|
||||
|
||||
/** 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. Return 0 if ok, -1 if circuit should be closed. */
|
||||
* cpath.
|
||||
*
|
||||
* If <b>is_hs_v3_rp_circuit</b> is set, then this exit should be suitable to
|
||||
* be used as an HS v3 rendezvous point.
|
||||
*
|
||||
* 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)
|
||||
onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
|
||||
int is_hs_v3_rp_circuit)
|
||||
{
|
||||
cpath_build_state_t *state = circ->build_state;
|
||||
|
||||
@ -2289,7 +2304,8 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei)
|
||||
} else { /* we have to decide one */
|
||||
const node_t *node =
|
||||
choose_good_exit_server(circ->base_.purpose, state->need_uptime,
|
||||
state->need_capacity, state->is_internal);
|
||||
state->need_capacity, state->is_internal,
|
||||
is_hs_v3_rp_circuit);
|
||||
if (!node) {
|
||||
log_warn(LD_CIRC,"Failed to choose an exit server");
|
||||
return -1;
|
||||
|
@ -1609,6 +1609,30 @@ circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
|
||||
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;
|
||||
}
|
||||
|
||||
/** Return a circuit that is open, is CIRCUIT_PURPOSE_C_GENERAL,
|
||||
* has a timestamp_dirty value of 0, has flags matching the CIRCLAUNCH_*
|
||||
* flags in <b>flags</b>, and if info is defined, does not already use info
|
||||
@ -1691,6 +1715,14 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
|
||||
hop = hop->next;
|
||||
} 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: ;
|
||||
|
@ -2290,6 +2290,16 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
|
||||
if (want_onehop) flags |= CIRCLAUNCH_ONEHOP_TUNNEL;
|
||||
if (need_uptime) flags |= CIRCLAUNCH_NEED_UPTIME;
|
||||
if (need_internal) flags |= CIRCLAUNCH_IS_INTERNAL;
|
||||
|
||||
/* If we are about to pick a v3 RP right now, make sure we pick a
|
||||
* rendezvous point that supports the v3 protocol! */
|
||||
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!");
|
||||
}
|
||||
|
||||
circ = circuit_launch_by_extend_info(new_circ_purpose, extend_info,
|
||||
flags);
|
||||
}
|
||||
|
@ -44,6 +44,9 @@ 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)
|
||||
origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
|
||||
extend_info_t *info,
|
||||
int flags);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "circuitlist.h"
|
||||
#include "circuituse.h"
|
||||
#include "connection.h"
|
||||
#include "nodelist.h"
|
||||
#include "circpathbias.h"
|
||||
#include "connection.h"
|
||||
#include "hs_ntor.h"
|
||||
@ -461,9 +462,21 @@ client_rendezvous_circ_has_opened(origin_circuit_t *circ)
|
||||
tor_assert(circ);
|
||||
tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
|
||||
|
||||
const extend_info_t *rp_ei = circ->build_state->chosen_exit;
|
||||
|
||||
/* Check that we didn't accidentally choose a node that does not understand
|
||||
* the v3 rendezvous protocol */
|
||||
if (rp_ei) {
|
||||
const node_t *rp_node = node_get_by_id(rp_ei->identity_digest);
|
||||
if (rp_node) {
|
||||
if (BUG(!node_supports_v3_rendezvous_point(rp_node))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_info(LD_REND, "Rendezvous circuit has opened to %s.",
|
||||
safe_str_client(
|
||||
extend_info_describe(circ->build_state->chosen_exit)));
|
||||
safe_str_client(extend_info_describe(rp_ei)));
|
||||
|
||||
/* Ignore returned value, nothing we can really do. On failure, the circuit
|
||||
* will be marked for close. */
|
||||
|
@ -863,6 +863,28 @@ node_supports_ed25519_hs_intro(const node_t *node)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** 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)
|
||||
{
|
||||
tor_assert(node);
|
||||
|
||||
if (node->rs) {
|
||||
return node->rs->supports_v3_rendezvous_point;
|
||||
}
|
||||
if (node->ri) {
|
||||
if (node->ri->protocol_list == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return protocol_list_supports_protocol(node->ri->protocol_list,
|
||||
PRT_HSREND,
|
||||
PROTOVER_HS_RENDEZVOUS_POINT_V3);
|
||||
}
|
||||
tor_assert_nonfatal_unreached_once();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return the RSA ID key's SHA1 digest for the provided node. */
|
||||
const uint8_t *
|
||||
node_get_rsa_id_digest(const node_t *node)
|
||||
|
@ -62,6 +62,7 @@ int node_ed25519_id_matches(const node_t *node,
|
||||
int node_supports_ed25519_link_authentication(const node_t *node);
|
||||
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);
|
||||
const uint8_t *node_get_rsa_id_digest(const node_t *node);
|
||||
|
||||
int node_has_ipv6_addr(const node_t *node);
|
||||
|
10
src/or/or.h
10
src/or/or.h
@ -2321,6 +2321,11 @@ typedef struct routerstatus_t {
|
||||
* requires HSDir=2. */
|
||||
unsigned int supports_v3_hsdir : 1;
|
||||
|
||||
/** True iff this router has a protocol list that allows it to be an hidden
|
||||
* service rendezvous point supporting version 3 as seen in proposal 224.
|
||||
* This requires HSRend=2. */
|
||||
unsigned int supports_v3_rendezvous_point: 1;
|
||||
|
||||
unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */
|
||||
unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */
|
||||
unsigned int bw_is_unmeasured:1; /**< This is a consensus entry, with
|
||||
@ -5381,7 +5386,10 @@ typedef enum {
|
||||
CRN_PREF_ADDR = 1<<7,
|
||||
/* On clients, only provide nodes that we can connect to directly, based on
|
||||
* our firewall rules */
|
||||
CRN_DIRECT_CONN = 1<<8
|
||||
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,
|
||||
} router_crn_flags_t;
|
||||
|
||||
/** Return value for router_add_to_routerlist() and dirserv_add_descriptor() */
|
||||
|
@ -21,6 +21,8 @@
|
||||
#define PROTOVER_HSDIR_V3 2
|
||||
/** The protover version number that signifies HSv3 intro point support */
|
||||
#define PROTOVER_HS_INTRO_V3 4
|
||||
/** The protover version number that signifies HSv3 rendezvous point support */
|
||||
#define PROTOVER_HS_RENDEZVOUS_POINT_V3 2
|
||||
|
||||
/** List of recognized subprotocols. */
|
||||
typedef enum protocol_type_t {
|
||||
|
@ -2799,6 +2799,7 @@ router_choose_random_node(smartlist_t *excludedsmartlist,
|
||||
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;
|
||||
|
||||
smartlist_t *sl=smartlist_new(),
|
||||
*excludednodes=smartlist_new();
|
||||
@ -2810,12 +2811,19 @@ router_choose_random_node(smartlist_t *excludedsmartlist,
|
||||
rule = weight_for_exit ? WEIGHT_FOR_EXIT :
|
||||
(need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID);
|
||||
|
||||
/* 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_FOREACH(nodelist_get_list(), node_t *, node,
|
||||
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), 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);
|
||||
});
|
||||
} 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);
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(node);
|
||||
|
||||
if ((r = routerlist_find_my_routerinfo()))
|
||||
routerlist_add_node_and_family(excludednodes, r);
|
||||
|
@ -2708,6 +2708,9 @@ routerstatus_parse_entry_from_string(memarea_t *area,
|
||||
rs->supports_v3_hsdir =
|
||||
protocol_list_supports_protocol(tok->args[0], PRT_HSDIR,
|
||||
PROTOVER_HSDIR_V3);
|
||||
rs->supports_v3_rendezvous_point =
|
||||
protocol_list_supports_protocol(tok->args[0], PRT_HSDIR,
|
||||
PROTOVER_HS_RENDEZVOUS_POINT_V3);
|
||||
}
|
||||
if ((tok = find_opt_by_keyword(tokens, K_V))) {
|
||||
tor_assert(tok->n_args == 1);
|
||||
|
Loading…
Reference in New Issue
Block a user