[tor-commits] [tor/master] prop224: Add service rendezvous circuit relaunch

nickm at torproject.org nickm at torproject.org
Wed Aug 9 00:36:37 UTC 2017


commit 713eb08bc9582b49e8073122fb68c3fac5bae188
Author: David Goulet <dgoulet at torproject.org>
Date:   Tue May 30 16:11:59 2017 -0400

    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 at torproject.org>
---
 src/or/circuituse.c  |   5 ++-
 src/or/hs_circuit.c  | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/or/hs_circuit.h  |   1 +
 src/or/hs_ident.c    |  10 +++++
 src/or/hs_ident.h    |   1 +
 src/or/rendservice.c |  23 ----------
 6 files changed, 136 insertions(+), 25 deletions(-)

diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 247c5bbbb..b19f9ed46 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -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
diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c
index d9e96c633..ce8522947 100644
--- a/src/or/hs_circuit.c
+++ b/src/or/hs_circuit.c
@@ -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
diff --git a/src/or/hs_circuit.h b/src/or/hs_circuit.h
index ca8f1b2f6..8301dea22 100644
--- a/src/or/hs_circuit.h
+++ b/src/or/hs_circuit.h
@@ -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,
diff --git a/src/or/hs_ident.c b/src/or/hs_ident.c
index c3f789db5..e69350d82 100644
--- a/src/or/hs_ident.c
+++ b/src/or/hs_ident.c
@@ -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 *
diff --git a/src/or/hs_ident.h b/src/or/hs_ident.h
index ca1fa3d70..a3ebd07da 100644
--- a/src/or/hs_ident.h
+++ b/src/or/hs_ident.h
@@ -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);
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 7c4c6edc4..a205b00c6 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -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);
 





More information about the tor-commits mailing list