[tor-commits] [tor/master] prop224: Handle service INTRO_ESTABLISHED cell
nickm at torproject.org
nickm at torproject.org
Wed Aug 9 00:36:37 UTC 2017
commit 79e8d113d5ebfbc5ccf76f5db7bc0259a29520fc
Author: David Goulet <dgoulet at torproject.org>
Date: Tue Mar 7 14:33:03 2017 -0500
prop224: Handle service INTRO_ESTABLISHED cell
Signed-off-by: David Goulet <dgoulet at torproject.org>
---
src/or/hs_cell.c | 22 ++++++++++++
src/or/hs_cell.h | 3 ++
src/or/hs_circuit.c | 42 ++++++++++++++++++++++-
src/or/hs_circuit.h | 5 +++
src/or/hs_service.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++----
src/or/hs_service.h | 3 ++
src/or/rendcommon.c | 2 +-
7 files changed, 168 insertions(+), 8 deletions(-)
diff --git a/src/or/hs_cell.c b/src/or/hs_cell.c
index e15f4e3e5..0d34ef596 100644
--- a/src/or/hs_cell.c
+++ b/src/or/hs_cell.c
@@ -161,3 +161,25 @@ hs_cell_build_establish_intro(const char *circ_nonce,
return cell_len;
}
+/* Parse the INTRO_ESTABLISHED cell in the payload of size payload_len. If we
+ * are successful at parsing it, return the length of the parsed cell else a
+ * negative value on error. */
+ssize_t
+hs_cell_parse_intro_established(const uint8_t *payload, size_t payload_len)
+{
+ ssize_t ret;
+ trn_cell_intro_established_t *cell = NULL;
+
+ tor_assert(payload);
+
+ /* Try to parse the payload into a cell making sure we do actually have a
+ * valid cell. */
+ ret = trn_cell_intro_established_parse(&cell, payload, payload_len);
+ if (ret >= 0) {
+ /* On success, we do not keep the cell, we just notify the caller that it
+ * was successfully parsed. */
+ trn_cell_intro_established_free(cell);
+ }
+ return ret;
+}
+
diff --git a/src/or/hs_cell.h b/src/or/hs_cell.h
index 9cc6109eb..8e3402889 100644
--- a/src/or/hs_cell.h
+++ b/src/or/hs_cell.h
@@ -15,5 +15,8 @@ ssize_t hs_cell_build_establish_intro(const char *circ_nonce,
const hs_service_intro_point_t *ip,
uint8_t *cell_out);
+ssize_t hs_cell_parse_intro_established(const uint8_t *payload,
+ size_t payload_len);
+
#endif /* TOR_HS_CELL_H */
diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c
index 01fd86483..51c07c0ba 100644
--- a/src/or/hs_circuit.c
+++ b/src/or/hs_circuit.c
@@ -428,6 +428,46 @@ hs_circ_service_intro_has_opened(hs_service_t *service,
return ret;
}
+/* Handle an INTRO_ESTABLISHED cell payload of length payload_len arriving on
+ * the given introduction circuit circ. The service is only used for logging
+ * purposes. Return 0 on success else a negative value. */
+int
+hs_circ_handle_intro_established(const hs_service_t *service,
+ const hs_service_intro_point_t *ip,
+ origin_circuit_t *circ,
+ const uint8_t *payload, size_t payload_len)
+{
+ int ret = -1;
+
+ tor_assert(service);
+ tor_assert(ip);
+ tor_assert(circ);
+ tor_assert(payload);
+
+ /* Try to parse the payload into a cell making sure we do actually have a
+ * valid cell. For a legacy node, it's an empty payload so as long as we
+ * have the cell, we are good. */
+ if (!ip->base.is_only_legacy &&
+ hs_cell_parse_intro_established(payload, payload_len) < 0) {
+ log_warn(LD_REND, "Unable to parse the INTRO_ESTABLISHED cell on "
+ "circuit %u for service %s",
+ TO_CIRCUIT(circ)->n_circ_id,
+ safe_str_client(service->onion_address));
+ goto done;
+ }
+
+ /* Switch the purpose to a fully working intro point. */
+ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_S_INTRO);
+ /* Getting a valid INTRODUCE_ESTABLISHED means we've successfully used the
+ * circuit so update our pathbias subsystem. */
+ pathbias_mark_use_success(circ);
+ /* Success. */
+ ret = 0;
+
+ done:
+ return ret;
+}
+
/* Circuit <b>circ</b> just finished the rend ntor key exchange. Use the key
* exchange output material at <b>ntor_key_seed</b> and setup <b>circ</b> to
* serve as a rendezvous end-to-end circuit between the client and the
@@ -435,7 +475,7 @@ hs_circ_service_intro_has_opened(hs_service_t *service,
* and the other side is the client.
*
* Return 0 if the operation went well; in case of error return -1. */
- int
+int
hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
const uint8_t *ntor_key_seed, size_t seed_len,
int is_service_side)
diff --git a/src/or/hs_circuit.h b/src/or/hs_circuit.h
index 35eab7569..bc29781d8 100644
--- a/src/or/hs_circuit.h
+++ b/src/or/hs_circuit.h
@@ -28,6 +28,11 @@ int hs_circ_launch_intro_point(hs_service_t *service,
void hs_circ_send_establish_intro(const hs_service_t *service,
hs_service_intro_point_t *ip,
origin_circuit_t *circ);
+int hs_circ_handle_intro_established(const hs_service_t *service,
+ const hs_service_intro_point_t *ip,
+ origin_circuit_t *circ,
+ const uint8_t *payload,
+ size_t payload_len);
/* e2e circuit API. */
diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index 4cd808133..5edfdd5b3 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -1725,14 +1725,8 @@ service_intro_circ_has_opened(origin_circuit_t *circ)
goto err;
}
- /* From the service object, get the intro point object of that circuit. The
- * following will query both descriptors intro points list. */
ip = service_intro_point_find(service, &circ->hs_ident->intro_auth_pk);
if (ip == NULL) {
- log_warn(LD_REND, "Unknown authentication key on the introduction "
- "circuit %u for service %s",
- TO_CIRCUIT(circ)->n_circ_id,
- safe_str_client(service->onion_address));
/* Closing this circuit because we don't recognize the key. */
close_reason = END_CIRC_REASON_NOSUCHSERVICE;
goto err;
@@ -1764,10 +1758,103 @@ service_rendezvous_circ_has_opened(origin_circuit_t *circ)
/* XXX: Implement rendezvous support. */
}
+/* Handle an INTRO_ESTABLISHED cell arriving on the given introduction
+ * circuit. Return 0 on success else a negative value. */
+static int
+service_handle_intro_established(origin_circuit_t *circ,
+ const uint8_t *payload,
+ size_t payload_len)
+{
+ hs_service_t *service = NULL;
+ hs_service_intro_point_t *ip = NULL;
+
+ tor_assert(circ);
+ tor_assert(payload);
+ tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
+
+ /* Get service object from the circuit identifier. */
+ service = find_service(hs_service_map, &circ->hs_ident->identity_pk);
+ if (service == NULL) {
+ log_warn(LD_REND, "Unknown service identity key %s on the introduction "
+ "circuit %u. Can't find onion service.",
+ safe_str_client(ed25519_fmt(&circ->hs_ident->identity_pk)),
+ TO_CIRCUIT(circ)->n_circ_id);
+ goto err;
+ }
+
+ /* From the service object, get the intro point object of that circuit. The
+ * following will query both descriptors intro points list. */
+ ip = service_intro_point_find(service, &circ->hs_ident->intro_auth_pk);
+ if (ip == NULL) {
+ /* We don't recognize the key. */
+ log_warn(LD_REND, "Introduction circuit established without an intro "
+ "point object on circuit %u for service %s",
+ TO_CIRCUIT(circ)->n_circ_id,
+ safe_str_client(service->onion_address));
+ goto err;
+ }
+
+ /* Try to parse the payload into a cell making sure we do actually have a
+ * valid cell. On success, the ip object is updated. */
+ if (hs_circ_handle_intro_established(service, ip, circ, payload,
+ payload_len) < 0) {
+ goto err;
+ }
+
+ /* Flag that we have an established circuit for this intro point. This value
+ * is what indicates the upload scheduled event if we are ready to build the
+ * intro point into the descriptor and upload. */
+ ip->circuit_established = 1;
+
+ log_info(LD_REND, "Successfully received an INTRO_ESTABLISHED cell "
+ "on circuit %u for service %s",
+ TO_CIRCUIT(circ)->n_circ_id,
+ safe_str_client(service->onion_address));
+ return 0;
+
+ err:
+ return -1;
+}
+
/* ========== */
/* Public API */
/* ========== */
+/* Called when we get an INTRO_ESTABLISHED cell. Mark the circuit as an
+ * established introduction point. Return 0 on success else a negative value
+ * and the circuit is closed. */
+int
+hs_service_receive_intro_established(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_S_ESTABLISH_INTRO) {
+ log_warn(LD_PROTOCOL, "Received an INTRO_ESTABLISHED cell on a "
+ "non introduction circuit of purpose %d",
+ TO_CIRCUIT(circ)->purpose);
+ goto err;
+ }
+
+ /* Handle both version. v2 uses rend_data and v3 uses the hs circuit
+ * identifier hs_ident. Can't be both. */
+ ret = (circ->hs_ident) ? service_handle_intro_established(circ, payload,
+ payload_len) :
+ rend_service_intro_established(circ, payload,
+ payload_len);
+ if (ret < 0) {
+ goto err;
+ }
+ return 0;
+ err:
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
+ return -1;
+}
+
/* Called when any kind of hidden service circuit is done building thus
* opened. This is the entry point from the circuit subsystem. */
void
diff --git a/src/or/hs_service.h b/src/or/hs_service.h
index 96df09493..3de96d64e 100644
--- a/src/or/hs_service.h
+++ b/src/or/hs_service.h
@@ -232,6 +232,9 @@ int hs_service_load_all_keys(void);
void hs_service_run_scheduled_events(time_t now);
void hs_service_circuit_has_opened(origin_circuit_t *circ);
+int hs_service_receive_intro_established(origin_circuit_t *circ,
+ const uint8_t *payload,
+ size_t payload_len);
/* These functions are only used by unit tests and we need to expose them else
* hs_service.o ends up with no symbols in libor.a which makes clang throw a
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 986bfde75..2cd66cb9c 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -793,7 +793,7 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
break;
case RELAY_COMMAND_INTRO_ESTABLISHED:
if (origin_circ)
- r = rend_service_intro_established(origin_circ,payload,length);
+ r = hs_service_receive_intro_established(origin_circ,payload,length);
break;
case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
if (origin_circ)
More information about the tor-commits
mailing list