[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