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:
David Goulet 2017-08-30 10:13:22 -04:00 committed by Nick Mathewson
parent 209bfe715c
commit c527cde82f
11 changed files with 131 additions and 13 deletions

View File

@ -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;

View File

@ -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: ;

View File

@ -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);
}

View File

@ -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);

View File

@ -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. */

View File

@ -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)

View File

@ -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);

View File

@ -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() */

View File

@ -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 {

View File

@ -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);

View File

@ -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);