mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
prop224: Add service rendezvous circuit relaunch
This introduces a callback to relaunch a service rendezvous circuit when a previous one failed to build or expired. It unifies the legacy function rend_service_relaunch_rendezvous() with one for specific to prop224. There is now only one entry point for that which is hs_circ_retry_service_rendezvous_point() supporting both legacy and prop224 circuits. Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
committed by
Nick Mathewson
parent
1b403a8382
commit
713eb08bc9
+3
-2
@@ -43,6 +43,7 @@
|
||||
#include "entrynodes.h"
|
||||
#include "hs_common.h"
|
||||
#include "hs_client.h"
|
||||
#include "hs_circuit.h"
|
||||
#include "hs_ident.h"
|
||||
#include "nodelist.h"
|
||||
#include "networkstatus.h"
|
||||
@@ -782,7 +783,7 @@ circuit_expire_building(void)
|
||||
victim->state, circuit_state_to_string(victim->state),
|
||||
victim->purpose);
|
||||
TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1;
|
||||
rend_service_relaunch_rendezvous(TO_ORIGIN_CIRCUIT(victim));
|
||||
hs_circ_retry_service_rendezvous_point(TO_ORIGIN_CIRCUIT(victim));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1790,7 +1791,7 @@ circuit_build_failed(origin_circuit_t *circ)
|
||||
"(%s hop failed).",
|
||||
escaped(build_state_get_exit_nickname(circ->build_state)),
|
||||
failed_at_last_hop?"last":"non-last");
|
||||
rend_service_relaunch_rendezvous(circ);
|
||||
hs_circ_retry_service_rendezvous_point(circ);
|
||||
break;
|
||||
/* default:
|
||||
* This won't happen in normal operation, but might happen if the
|
||||
|
||||
@@ -566,10 +566,131 @@ launch_rendezvous_point_circuit(const hs_service_t *service,
|
||||
extend_info_free(info);
|
||||
}
|
||||
|
||||
/* Return true iff the given service rendezvous circuit circ is allowed for a
|
||||
* relaunch to the rendezvous point. */
|
||||
static int
|
||||
can_relaunch_service_rendezvous_point(const origin_circuit_t *circ)
|
||||
{
|
||||
tor_assert(circ);
|
||||
/* This is initialized when allocating an origin circuit. */
|
||||
tor_assert(circ->build_state);
|
||||
tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
|
||||
|
||||
/* XXX: Retrying under certain condition. This is related to #22455. */
|
||||
|
||||
/* Avoid to relaunch twice a circuit to the same rendezvous point at the
|
||||
* same time. */
|
||||
if (circ->hs_service_side_rend_circ_has_been_relaunched) {
|
||||
log_info(LD_REND, "Rendezvous circuit to %s has already been retried. "
|
||||
"Skipping retry.",
|
||||
safe_str_client(
|
||||
extend_info_describe(circ->build_state->chosen_exit)));
|
||||
goto disallow;
|
||||
}
|
||||
|
||||
/* A failure count that has reached maximum allowed or circuit that expired,
|
||||
* we skip relaunching. */
|
||||
if (circ->build_state->failure_count > MAX_REND_FAILURES ||
|
||||
circ->build_state->expiry_time <= time(NULL)) {
|
||||
log_info(LD_REND, "Attempt to build a rendezvous circuit to %s has "
|
||||
"failed with %d attempts and expiry time %ld. "
|
||||
"Giving up building.",
|
||||
safe_str_client(
|
||||
extend_info_describe(circ->build_state->chosen_exit)),
|
||||
circ->build_state->failure_count,
|
||||
circ->build_state->expiry_time);
|
||||
goto disallow;
|
||||
}
|
||||
|
||||
/* Allowed to relaunch. */
|
||||
return 1;
|
||||
disallow:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Retry the rendezvous point of circ by launching a new circuit to it. */
|
||||
static void
|
||||
retry_service_rendezvous_point(const origin_circuit_t *circ)
|
||||
{
|
||||
int flags = 0;
|
||||
origin_circuit_t *new_circ;
|
||||
cpath_build_state_t *bstate;
|
||||
|
||||
tor_assert(circ);
|
||||
/* This is initialized when allocating an origin circuit. */
|
||||
tor_assert(circ->build_state);
|
||||
tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
|
||||
|
||||
/* Ease our life. */
|
||||
bstate = circ->build_state;
|
||||
|
||||
log_info(LD_REND, "Retrying rendezvous point circuit to %s",
|
||||
safe_str_client(extend_info_describe(bstate->chosen_exit)));
|
||||
|
||||
/* Get the current build state flags for the next circuit. */
|
||||
flags |= (bstate->need_uptime) ? CIRCLAUNCH_NEED_UPTIME : 0;
|
||||
flags |= (bstate->need_capacity) ? CIRCLAUNCH_NEED_CAPACITY : 0;
|
||||
flags |= (bstate->is_internal) ? CIRCLAUNCH_IS_INTERNAL : 0;
|
||||
|
||||
/* We do NOT add the onehop tunnel flag even though it might be a single
|
||||
* onion service. The reason is that if we failed once to connect to the RP
|
||||
* with a direct connection, we consider that chances are that we will fail
|
||||
* again so try a 3-hop circuit and hope for the best. Because the service
|
||||
* has no anonymity (single onion), this change of behavior won't affect
|
||||
* security directly. */
|
||||
|
||||
/* Help predict this next time */
|
||||
rep_hist_note_used_internal(time(NULL), bstate->need_uptime,
|
||||
bstate->need_capacity);
|
||||
|
||||
new_circ = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND,
|
||||
bstate->chosen_exit, flags);
|
||||
if (new_circ == NULL) {
|
||||
log_warn(LD_REND, "Failed to launch rendezvous circuit to %s",
|
||||
safe_str_client(extend_info_describe(bstate->chosen_exit)));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Transfer build state information to the new circuit state in part to
|
||||
* catch any other failures. */
|
||||
new_circ->build_state->failure_count = bstate->failure_count++;
|
||||
new_circ->build_state->expiry_time = bstate->expiry_time;
|
||||
new_circ->hs_ident = hs_ident_circuit_dup(circ->hs_ident);
|
||||
|
||||
done:
|
||||
return;
|
||||
}
|
||||
|
||||
/* ========== */
|
||||
/* Public API */
|
||||
/* ========== */
|
||||
|
||||
/* Called when we fail building a rendezvous circuit at some point other than
|
||||
* the last hop: launches a new circuit to the same rendezvous point. This
|
||||
* supports legacy service. */
|
||||
void
|
||||
hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ)
|
||||
{
|
||||
tor_assert(circ);
|
||||
tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
|
||||
|
||||
/* Check if we are allowed to relaunch to the rendezvous point of circ. */
|
||||
if (!can_relaunch_service_rendezvous_point(circ)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Flag the circuit that we are relaunching so to avoid to relaunch twice a
|
||||
* circuit to the same rendezvous point at the same time. */
|
||||
circ->hs_service_side_rend_circ_has_been_relaunched = 1;
|
||||
|
||||
/* Legacy service don't have an hidden service ident. */
|
||||
(circ->hs_ident) ? retry_service_rendezvous_point(circ) :
|
||||
rend_service_relaunch_rendezvous(circ);
|
||||
|
||||
done:
|
||||
return;
|
||||
}
|
||||
|
||||
/* For a given service and a service intro point, launch a circuit to the
|
||||
* extend info ei. If the service is a single onion, a one-hop circuit will be
|
||||
* requested. Return 0 if the circuit was successfully launched and tagged
|
||||
|
||||
@@ -28,6 +28,7 @@ int hs_circ_launch_intro_point(hs_service_t *service,
|
||||
int hs_circ_launch_rendezvous_point(const hs_service_t *service,
|
||||
const curve25519_public_key_t *onion_key,
|
||||
const uint8_t *rendezvous_cookie);
|
||||
void hs_circ_retry_service_rendezvous_point(origin_circuit_t *circ);
|
||||
|
||||
/* Cell API. */
|
||||
int hs_circ_handle_intro_established(const hs_service_t *service,
|
||||
|
||||
@@ -34,6 +34,16 @@ hs_ident_circuit_free(hs_ident_circuit_t *ident)
|
||||
tor_free(ident);
|
||||
}
|
||||
|
||||
/* For a given circuit identifier src, return a newly allocated copy of it.
|
||||
* This can't fail. */
|
||||
hs_ident_circuit_t *
|
||||
hs_ident_circuit_dup(const hs_ident_circuit_t *src)
|
||||
{
|
||||
hs_ident_circuit_t *ident = tor_malloc_zero(sizeof(*ident));
|
||||
memcpy(ident, src, sizeof(*ident));
|
||||
return ident;
|
||||
}
|
||||
|
||||
/* For a given directory connection identifier src, return a newly allocated
|
||||
* copy of it. This can't fail. */
|
||||
hs_ident_dir_conn_t *
|
||||
|
||||
@@ -113,6 +113,7 @@ hs_ident_circuit_t *hs_ident_circuit_new(
|
||||
const ed25519_public_key_t *identity_pk,
|
||||
hs_ident_circuit_type_t circuit_type);
|
||||
void hs_ident_circuit_free(hs_ident_circuit_t *ident);
|
||||
hs_ident_circuit_t *hs_ident_circuit_dup(const hs_ident_circuit_t *src);
|
||||
|
||||
/* Directory connection identifier API. */
|
||||
hs_ident_dir_conn_t *hs_ident_dir_conn_dup(const hs_ident_dir_conn_t *src);
|
||||
|
||||
@@ -2892,29 +2892,6 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc)
|
||||
|
||||
tor_assert(oldcirc->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
|
||||
|
||||
/* Don't relaunch the same rend circ twice. */
|
||||
if (oldcirc->hs_service_side_rend_circ_has_been_relaunched) {
|
||||
log_info(LD_REND, "Rendezvous circuit to %s has already been relaunched; "
|
||||
"not relaunching it again.",
|
||||
oldcirc->build_state ?
|
||||
safe_str(extend_info_describe(oldcirc->build_state->chosen_exit))
|
||||
: "*unknown*");
|
||||
return;
|
||||
}
|
||||
oldcirc->hs_service_side_rend_circ_has_been_relaunched = 1;
|
||||
|
||||
if (!oldcirc->build_state ||
|
||||
oldcirc->build_state->failure_count > MAX_REND_FAILURES ||
|
||||
oldcirc->build_state->expiry_time < time(NULL)) {
|
||||
log_info(LD_REND,
|
||||
"Attempt to build circuit to %s for rendezvous has failed "
|
||||
"too many times or expired; giving up.",
|
||||
oldcirc->build_state ?
|
||||
safe_str(extend_info_describe(oldcirc->build_state->chosen_exit))
|
||||
: "*unknown*");
|
||||
return;
|
||||
}
|
||||
|
||||
oldstate = oldcirc->build_state;
|
||||
tor_assert(oldstate);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user