[tor-commits] [tor/master] hs-v3: Parse ESTABLISH_INTRO cell extension

nickm at torproject.org nickm at torproject.org
Mon Sep 9 16:35:37 UTC 2019


commit 724d9eb84be4c9a8b6cd34f08dc7b5d00f69f09e
Author: David Goulet <dgoulet at torproject.org>
Date:   Mon Aug 12 13:34:09 2019 -0400

    hs-v3: Parse ESTABLISH_INTRO cell extension
    
    Signed-off-by: David Goulet <dgoulet at torproject.org>
---
 src/core/or/or_circuit_st.h    |   4 ++
 src/feature/hs/hs_intropoint.c | 122 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 121 insertions(+), 5 deletions(-)

diff --git a/src/core/or/or_circuit_st.h b/src/core/or/or_circuit_st.h
index 8f319585a..f3eb86161 100644
--- a/src/core/or/or_circuit_st.h
+++ b/src/core/or/or_circuit_st.h
@@ -72,6 +72,10 @@ struct or_circuit_t {
    * buffer stats to disk. */
   uint64_t total_cell_waiting_time;
 
+  /** If set, the DoS defenses are enabled on this circuit meaning that the
+   * introduce2_bucket is initialized and used. */
+  unsigned int introduce2_dos_defense_enabled : 1;
+
   /** INTRODUCE2 cell bucket controlling how much can go on this circuit. Only
    * used if this is a service introduction circuit at the intro point
    * (purpose = CIRCUIT_PURPOSE_INTRO_POINT). */
diff --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c
index a53ca0d6b..bafd3d1f4 100644
--- a/src/feature/hs/hs_intropoint.c
+++ b/src/feature/hs/hs_intropoint.c
@@ -26,6 +26,7 @@
 
 #include "feature/hs/hs_circuitmap.h"
 #include "feature/hs/hs_common.h"
+#include "feature/hs/hs_config.h"
 #include "feature/hs/hs_descriptor.h"
 #include "feature/hs/hs_dos.h"
 #include "feature/hs/hs_intropoint.h"
@@ -181,6 +182,110 @@ hs_intro_send_intro_established_cell,(or_circuit_t *circ))
   return ret;
 }
 
+static void
+handle_establish_intro_cell_dos_extension(
+                                const trn_cell_extension_field_t *field,
+                                or_circuit_t *circ)
+{
+  ssize_t ret;
+  uint64_t intro2_rate_per_sec = 0, intro2_burst_per_sec = 0;
+  trn_cell_extension_dos_t *dos = NULL;
+
+  tor_assert(field);
+  tor_assert(circ);
+
+  ret = trn_cell_extension_dos_parse(&dos,
+                 trn_cell_extension_field_getconstarray_field(field),
+                 trn_cell_extension_field_getlen_field(field));
+  if (ret < 0) {
+    goto end;
+  }
+
+  for (size_t i = 0; i < trn_cell_extension_dos_get_n_params(dos); i++) {
+    const trn_cell_extension_dos_param_t *param =
+      trn_cell_extension_dos_getconst_params(dos, i);
+    if (BUG(param == NULL)) {
+      goto end;
+    }
+
+    switch (trn_cell_extension_dos_param_get_type(param)) {
+    case TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC:
+      intro2_rate_per_sec = trn_cell_extension_dos_param_get_value(param);
+      break;
+    case TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC:
+      intro2_burst_per_sec = trn_cell_extension_dos_param_get_value(param);
+      break;
+    default:
+      goto end;
+    }
+  }
+
+  /* Validation. A value of 0 on either of them means the defenses are
+   * disabled so we ignore. */
+  if ((intro2_rate_per_sec > HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX ||
+       intro2_rate_per_sec <= HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN) ||
+      (intro2_burst_per_sec > HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX ||
+       intro2_burst_per_sec <= HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN) ||
+      (intro2_burst_per_sec < intro2_rate_per_sec)) {
+    circ->introduce2_dos_defense_enabled = 0;
+    log_info(LD_REND, "Intro point DoS defenses disabled due to bad values");
+  } else {
+    circ->introduce2_dos_defense_enabled = 1;
+
+    /* Initialize the INTRODUCE2 token bucket for the rate limiting. */
+    token_bucket_ctr_init(&circ->introduce2_bucket,
+                          (uint32_t) intro2_rate_per_sec,
+                          (uint32_t) intro2_burst_per_sec,
+                          (uint32_t) approx_time());
+    log_debug(LD_REND, "Intro point DoS defenses enabled. Rate is %" PRIu64
+                       " and Burst is %" PRIu64, intro2_rate_per_sec,
+                       intro2_burst_per_sec);
+  }
+
+ end:
+  trn_cell_extension_dos_free(dos);
+  return;
+}
+
+static void
+handle_establish_intro_cell_extensions(
+                            const trn_cell_establish_intro_t *parsed_cell,
+                            or_circuit_t *circ)
+{
+  const trn_cell_extension_t *extensions;
+
+  tor_assert(parsed_cell);
+  tor_assert(circ);
+
+  extensions = trn_cell_establish_intro_getconst_extensions(parsed_cell);
+  if (extensions == NULL) {
+    goto end;
+  }
+
+  /* Go over all extensions. */
+  for (size_t idx = 0; idx < trn_cell_extension_get_num(extensions); idx++) {
+    const trn_cell_extension_field_t *field =
+      trn_cell_extension_getconst_fields(extensions, idx);
+    if (BUG(field == NULL)) {
+      /* The number of extensions should match the number of fields. */
+      break;
+    }
+
+    switch (trn_cell_extension_field_get_field_type(field)) {
+    case TRUNNEL_CELL_EXTENSION_TYPE_DOS:
+      /* After this, the circuit should be set for DoS defenses. */
+      handle_establish_intro_cell_dos_extension(field, circ);
+      break;
+    default:
+      /* Unknown extension. Skip over. */
+      break;
+    }
+  }
+
+ end:
+  return;
+}
+
 /** We received an ESTABLISH_INTRO <b>parsed_cell</b> on <b>circ</b>. It's
  *  well-formed and passed our verifications. Perform appropriate actions to
  *  establish an intro point. */
@@ -193,6 +298,18 @@ handle_verified_establish_intro_cell(or_circuit_t *circ,
   get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO,
                          parsed_cell);
 
+  /* Initialize the INTRODUCE2 token bucket for the DoS defenses using the
+   * consensus/default values. We might get a cell extension that changes
+   * those but if we don't, the default or consensus parameters are used. */
+  circ->introduce2_dos_defense_enabled = hs_dos_get_intro2_enabled_param();
+  token_bucket_ctr_init(&circ->introduce2_bucket,
+                        hs_dos_get_intro2_rate_param(),
+                        hs_dos_get_intro2_burst_param(),
+                        (uint32_t) approx_time());
+
+  /* Handle cell extension if any. */
+  handle_establish_intro_cell_extensions(parsed_cell, circ);
+
   /* Then notify the hidden service that the intro point is established by
      sending an INTRO_ESTABLISHED cell */
   if (hs_intro_send_intro_established_cell(circ)) {
@@ -204,11 +321,6 @@ handle_verified_establish_intro_cell(or_circuit_t *circ,
   hs_circuitmap_register_intro_circ_v3_relay_side(circ, &auth_key);
   /* Repurpose this circuit into an intro circuit. */
   circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT);
-  /* Initialize the INTRODUCE2 token bucket for the rate limiting. */
-  token_bucket_ctr_init(&circ->introduce2_bucket,
-                        hs_dos_get_intro2_rate_param(),
-                        hs_dos_get_intro2_burst_param(),
-                        (uint32_t) approx_time());
 
   return 0;
 }





More information about the tor-commits mailing list