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.
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 */
/* ========== */
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;
+}
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,