]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
prop224: Add service replay cache
authorDavid Goulet <dgoulet@torproject.org>
Thu, 6 Apr 2017 18:58:13 +0000 (14:58 -0400)
committerNick Mathewson <nickm@torproject.org>
Wed, 9 Aug 2017 00:29:33 +0000 (20:29 -0400)
Signed-off-by: David Goulet <dgoulet@torproject.org>
src/or/hs_circuit.c
src/or/hs_service.c
src/or/hs_service.h

index ee43406c0d56b7960e9cf6b6946676073ce19c79..d9e96c63306e2d7ae4fc26b0c63ece66bba351c4 100644 (file)
@@ -794,6 +794,7 @@ hs_circ_handle_introduce2(const hs_service_t *service,
                           const uint8_t *payload, size_t payload_len)
 {
   int ret = -1;
+  time_t elapsed;
   hs_cell_introduce2_data_t data;
 
   tor_assert(service);
@@ -817,6 +818,22 @@ hs_circ_handle_introduce2(const hs_service_t *service,
     goto done;
   }
 
+  /* Check whether we've seen this REND_COOKIE before to detect repeats. */
+  if (replaycache_add_test_and_elapsed(
+           service->state.replay_cache_rend_cookie,
+           data.rendezvous_cookie, sizeof(data.rendezvous_cookie),
+           &elapsed)) {
+    /* A Tor client will send a new INTRODUCE1 cell with the same REND_COOKIE
+     * as its previous one if its intro circ times out while in state
+     * CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT. If we received the first
+     * INTRODUCE1 cell (the intro-point relay converts it into an INTRODUCE2
+     * cell), we are already trying to connect to that rend point (and may
+     * have already succeeded); drop this cell. */
+    log_info(LD_REND, "We received an INTRODUCE2 cell with same REND_COOKIE "
+                      "field %ld seconds ago. Dropping cell.", elapsed);
+    goto done;
+  }
+
   /* At this point, we just confirmed that the full INTRODUCE2 cell is valid
    * so increment our counter that we've seen one on this intro point. */
   ip->introduce2_count++;
index 48724e45cf7d13f6e8f4e56a3961870bca113adc..567ca0be03acb482cb443da58364fe6e891ae799 100644 (file)
@@ -2080,6 +2080,9 @@ hs_service_new(const or_options_t *options)
   set_service_default_config(&service->config, options);
   /* Set the default service version. */
   service->config.version = HS_SERVICE_DEFAULT_VERSION;
+  /* Allocate the CLIENT_PK replay cache in service state. */
+  service->state.replay_cache_rend_cookie =
+    replaycache_new(REND_REPLAY_TIME_INTERVAL, REND_REPLAY_TIME_INTERVAL);
   return service;
 }
 
@@ -2101,6 +2104,11 @@ hs_service_free(hs_service_t *service)
   /* Free service configuration. */
   service_clear_config(&service->config);
 
+  /* Free replay cache from state. */
+  if (service->state.replay_cache_rend_cookie) {
+    replaycache_free(service->state.replay_cache_rend_cookie);
+  }
+
   /* Wipe service keys. */
   memwipe(&service->keys.identity_sk, 0, sizeof(service->keys.identity_sk));
 
index f12094a927733a3f36bc8a497bed7bb7fde5239f..8776a4412c2f8dc6ccafb841e2225c14510a0cfe 100644 (file)
@@ -181,6 +181,13 @@ typedef struct hs_service_state_t {
   /* Indicate that the service has entered the overlap period. We use this
    * flag to check for descriptor rotation. */
   unsigned int in_overlap_period : 1;
+
+  /* Replay cache tracking the REND_COOKIE found in INTRODUCE2 cell to detect
+   * repeats. Clients may send INTRODUCE1 cells for the same rendezvous point
+   * through two or more different introduction points; when they do, this
+   * keeps us from launching multiple simultaneous attempts to connect to the
+   * same rend point. */
+  replaycache_t *replay_cache_rend_cookie;
 } hs_service_state_t;
 
 /* Representation of a service running on this tor instance. */