mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 21:23:58 +01:00
prop224: Handle INTRODUCE_ACK cell
The client is now able to handle an INTRODUCE_ACK cell and do the appropriate actions. An intro point failure cache is missing and a way to close all intro point that were launched in parallel. Some notes are in the comment for that. Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
parent
cb336a7062
commit
fca2f64e2f
@ -1498,6 +1498,33 @@ circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return an origin circuit such that:
|
||||
* - Identifier identity key matches,
|
||||
* - Rendezvous cookie matches
|
||||
* - Circuit is not marked for close
|
||||
* - Circuit has purpose CIRCUIT_PURPOSE_C_REND_READY.
|
||||
*
|
||||
* Return NULL if no such circuit exits. */
|
||||
origin_circuit_t *
|
||||
circuit_get_ready_rend_by_hs_ident(const hs_ident_circuit_t *ident)
|
||||
{
|
||||
SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
|
||||
if (!circ->marked_for_close &&
|
||||
circ->purpose == CIRCUIT_PURPOSE_C_REND_READY) {
|
||||
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
|
||||
if (ocirc->hs_ident &&
|
||||
ed25519_pubkey_eq(&ident->identity_pk,
|
||||
ô->hs_ident->identity_pk) &&
|
||||
tor_memeq(ident->rendezvous_cookie,
|
||||
ocirc->hs_ident->rendezvous_cookie,
|
||||
HS_REND_COOKIE_LEN)) {
|
||||
return ocirc;
|
||||
}
|
||||
}
|
||||
} SMARTLIST_FOREACH_END(circ);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Return the first service introduction circuit originating from the global
|
||||
* circuit list after <b>start</b> or at the start of the list if <b>start</b>
|
||||
* is NULL. Return NULL if no circuit is found.
|
||||
|
@ -13,6 +13,7 @@
|
||||
#define TOR_CIRCUITLIST_H
|
||||
|
||||
#include "testsupport.h"
|
||||
#include "hs_ident.h"
|
||||
|
||||
MOCK_DECL(smartlist_t *, circuit_get_global_list, (void));
|
||||
smartlist_t *circuit_get_global_origin_circuit_list(void);
|
||||
@ -45,6 +46,8 @@ void circuit_unlink_all_from_channel(channel_t *chan, int reason);
|
||||
origin_circuit_t *circuit_get_by_global_id(uint32_t id);
|
||||
origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data(
|
||||
const rend_data_t *rend_data);
|
||||
origin_circuit_t *circuit_get_ready_rend_by_hs_ident(
|
||||
const hs_ident_circuit_t *ident);
|
||||
origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
|
||||
const uint8_t *digest, uint8_t purpose);
|
||||
origin_circuit_t *circuit_get_next_service_intro_circ(origin_circuit_t *start);
|
||||
|
@ -875,6 +875,18 @@ hs_cell_parse_introduce_ack(const uint8_t *payload, size_t payload_len)
|
||||
|
||||
tor_assert(payload);
|
||||
|
||||
/* If it is a legacy IP, rend-spec.txt specifies that a ACK is 0 byte and a
|
||||
* NACK is 1 byte. We can't use the legacy function for this so we have to
|
||||
* do a special case. */
|
||||
if (payload_len <= 1) {
|
||||
if (payload_len == 0) {
|
||||
ret = HS_CELL_INTRO_ACK_SUCCESS;
|
||||
} else {
|
||||
ret = HS_CELL_INTRO_ACK_FAILURE;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (trn_cell_introduce_ack_parse(&cell, payload, payload_len) < 0) {
|
||||
log_info(LD_REND, "Invalid INTRODUCE_ACK cell. Unable to parse it.");
|
||||
goto end;
|
||||
|
@ -111,6 +111,9 @@ ssize_t hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data,
|
||||
const origin_circuit_t *circ,
|
||||
const hs_service_t *service);
|
||||
int hs_cell_parse_introduce_ack(const uint8_t *payload, size_t payload_len);
|
||||
int hs_cell_parse_rendezvous2(const uint8_t *payload, size_t payload_len,
|
||||
uint8_t *handshake_info,
|
||||
size_t handshake_info_len);
|
||||
|
||||
#endif /* TOR_HS_CELL_H */
|
||||
|
||||
|
@ -491,6 +491,99 @@ client_get_random_intro(const ed25519_public_key_t *service_pk)
|
||||
return ei;
|
||||
}
|
||||
|
||||
/* Called when we get an INTRODUCE_ACK success status code. Do the appropriate
|
||||
* actions for the rendezvous point and finally close intro_circ. */
|
||||
static void
|
||||
handle_introduce_ack_success(origin_circuit_t *intro_circ)
|
||||
{
|
||||
origin_circuit_t *rend_circ = NULL;
|
||||
|
||||
tor_assert(intro_circ);
|
||||
|
||||
log_info(LD_REND, "Received INTRODUCE_ACK ack! Informing rendezvous");
|
||||
|
||||
/* Get the rendezvous circuit matching this intro point circuit.
|
||||
* XXX Replace this by our hs circuitmap to support client? */
|
||||
rend_circ = circuit_get_ready_rend_by_hs_ident(intro_circ->hs_ident);
|
||||
if (rend_circ == NULL) {
|
||||
log_warn(LD_REND, "Can't find any rendezvous circuit. Stopping");
|
||||
goto end;
|
||||
}
|
||||
|
||||
assert_circ_anonymity_ok(rend_circ, get_options());
|
||||
circuit_change_purpose(TO_CIRCUIT(rend_circ),
|
||||
CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED);
|
||||
/* Set timestamp_dirty, because circuit_expire_building expects it to
|
||||
* specify when a circuit entered the
|
||||
* CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED state. */
|
||||
TO_CIRCUIT(rend_circ)->timestamp_dirty = time(NULL);
|
||||
|
||||
end:
|
||||
/* We don't need the intro circuit anymore. It did what it had to do! */
|
||||
circuit_change_purpose(TO_CIRCUIT(intro_circ),
|
||||
CIRCUIT_PURPOSE_C_INTRODUCE_ACKED);
|
||||
circuit_mark_for_close(TO_CIRCUIT(intro_circ), END_CIRC_REASON_FINISHED);
|
||||
|
||||
/* XXX: Close pending intro circuits we might have in parallel. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Called when we get an INTRODUCE_ACK failure status code. Depending on our
|
||||
* failure cache status, either close the circuit or re-extend to a new
|
||||
* introduction point. */
|
||||
static void
|
||||
handle_introduce_ack_bad(origin_circuit_t *circ, int status)
|
||||
{
|
||||
tor_assert(circ);
|
||||
|
||||
log_info(LD_REND, "Received INTRODUCE_ACK nack by %s. Reason: %u",
|
||||
safe_str_client(extend_info_describe(circ->build_state->chosen_exit)),
|
||||
status);
|
||||
|
||||
/* It's a NAK. The introduction point didn't relay our request. */
|
||||
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_C_INTRODUCING);
|
||||
|
||||
/* XXX: Report this failure for the intro point failure cache. Depending on
|
||||
* how many times we've tried this intro point, close it or reextend. */
|
||||
}
|
||||
|
||||
/* Called when we get an INTRODUCE_ACK on the intro circuit circ. The encoded
|
||||
* cell is in payload of length payload_len. Return 0 on success else a
|
||||
* negative value. The circuit is either close or reuse to re-extend to a new
|
||||
* introduction point. */
|
||||
static int
|
||||
handle_introduce_ack(origin_circuit_t *circ, const uint8_t *payload,
|
||||
size_t payload_len)
|
||||
{
|
||||
int status, ret = -1;
|
||||
|
||||
tor_assert(circ);
|
||||
tor_assert(circ->build_state);
|
||||
tor_assert(circ->build_state->chosen_exit);
|
||||
assert_circ_anonymity_ok(circ, get_options());
|
||||
tor_assert(payload);
|
||||
|
||||
status = hs_cell_parse_introduce_ack(payload, payload_len);
|
||||
switch (status) {
|
||||
case HS_CELL_INTRO_ACK_SUCCESS:
|
||||
ret = 0;
|
||||
handle_introduce_ack_success(circ);
|
||||
break;
|
||||
case HS_CELL_INTRO_ACK_FAILURE:
|
||||
case HS_CELL_INTRO_ACK_BADFMT:
|
||||
case HS_CELL_INTRO_ACK_NORELAY:
|
||||
handle_introduce_ack_bad(circ, status);
|
||||
break;
|
||||
default:
|
||||
log_info(LD_PROTOCOL, "Unknown INTRODUCE_ACK status code %u from %s",
|
||||
status,
|
||||
safe_str_client(extend_info_describe(circ->build_state->chosen_exit)));
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ========== */
|
||||
/* Public API */
|
||||
/* ========== */
|
||||
@ -759,4 +852,32 @@ hs_client_get_random_intro_from_edge(const edge_connection_t *edge_conn)
|
||||
client_get_random_intro(&edge_conn->hs_ident->identity_pk) :
|
||||
rend_client_get_random_intro(edge_conn->rend_data);
|
||||
}
|
||||
/* Called when get an INTRODUCE_ACK cell on the introduction circuit circ.
|
||||
* Return 0 on success else a negative value is returned. The circuit will be
|
||||
* closed or reuse to extend again to another intro point. */
|
||||
int
|
||||
hs_client_receive_introduce_ack(origin_circuit_t *circ,
|
||||
const uint8_t *payload, size_t payload_len)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
tor_assert(circ);
|
||||
tor_assert(payload);
|
||||
|
||||
if (TO_CIRCUIT(circ)->purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
|
||||
log_warn(LD_PROTOCOL, "Unexpected INTRODUCE_ACK on circuit %u.",
|
||||
(unsigned int) TO_CIRCUIT(circ)->n_circ_id);
|
||||
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = (circ->hs_ident) ? handle_introduce_ack(circ, payload, payload_len) :
|
||||
rend_client_introduction_acked(circ, payload,
|
||||
payload_len);
|
||||
/* For path bias: This circuit was used successfully. NACK or ACK counts. */
|
||||
pathbias_mark_use_success(circ);
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,10 @@ void hs_client_circuit_has_opened(origin_circuit_t *circ);
|
||||
int hs_client_receive_rendezvous_acked(origin_circuit_t *circ,
|
||||
const uint8_t *payload,
|
||||
size_t payload_len);
|
||||
int hs_client_receive_introduce_ack(origin_circuit_t *circ,
|
||||
const uint8_t *payload,
|
||||
size_t payload_len);
|
||||
|
||||
void hs_client_desc_has_arrived(const hs_ident_dir_conn_t *ident);
|
||||
|
||||
extend_info_t *hs_client_get_random_intro_from_edge(
|
||||
|
@ -391,23 +391,11 @@ rend_client_introduction_acked(origin_circuit_t *circ,
|
||||
origin_circuit_t *rendcirc;
|
||||
(void) request; // XXXX Use this.
|
||||
|
||||
if (circ->base_.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
|
||||
log_warn(LD_PROTOCOL,
|
||||
"Received REND_INTRODUCE_ACK on unexpected circuit %u.",
|
||||
(unsigned)circ->base_.n_circ_id);
|
||||
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tor_assert(circ->build_state);
|
||||
tor_assert(circ->build_state->chosen_exit);
|
||||
assert_circ_anonymity_ok(circ, options);
|
||||
tor_assert(circ->rend_data);
|
||||
|
||||
/* For path bias: This circuit was used successfully. Valid
|
||||
* nacks and acks count. */
|
||||
pathbias_mark_use_success(circ);
|
||||
|
||||
if (request_len == 0) {
|
||||
/* It's an ACK; the introduction point relayed our introduction request. */
|
||||
/* Locate the rend circ which is waiting to hear about this ack,
|
||||
|
@ -782,7 +782,7 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
|
||||
break;
|
||||
case RELAY_COMMAND_INTRODUCE_ACK:
|
||||
if (origin_circ)
|
||||
r = rend_client_introduction_acked(origin_circ,payload,length);
|
||||
r = hs_client_receive_introduce_ack(origin_circ,payload,length);
|
||||
break;
|
||||
case RELAY_COMMAND_RENDEZVOUS1:
|
||||
if (or_circ)
|
||||
|
Loading…
Reference in New Issue
Block a user