Commit c527cde8 authored by David Goulet's avatar David Goulet 🐼 Committed by Nick Mathewson
Browse files

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's avatarDavid Goulet <dgoulet@torproject.org>
parent 209bfe71
Loading
Loading
Loading
Loading
+22 −6
Original line number Diff line number Diff line
@@ -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;
+32 −0
Original line number Diff line number Diff line
@@ -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: ;
+10 −0
Original line number Diff line number Diff line
@@ -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);
    }
+3 −0
Original line number Diff line number Diff line
@@ -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);
+15 −2
Original line number Diff line number Diff line
@@ -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. */
Loading