[tor-commits] [tor/master] Introduce per-service HiddenServiceExportCircuitID torrc option.

nickm at torproject.org nickm at torproject.org
Fri Sep 21 13:40:22 UTC 2018


commit 27d7491f5a761c58fc687f0b816b80ff9f7a1a1d
Author: George Kadianakis <desnacked at riseup.net>
Date:   Wed Sep 12 14:40:19 2018 +0300

    Introduce per-service HiddenServiceExportCircuitID torrc option.
    
    Moves code to a function, better viewed with --color-moved.
---
 changes/bug4700               |  5 +++++
 src/app/config/config.c       |  1 +
 src/core/or/connection_edge.c | 52 ++++++++++++++++++++++++++-----------------
 src/feature/hs/hs_config.c    | 20 ++++++++++++++++-
 src/feature/hs/hs_service.c   | 13 +++++++++++
 src/feature/hs/hs_service.h   |  5 +++++
 6 files changed, 75 insertions(+), 21 deletions(-)

diff --git a/changes/bug4700 b/changes/bug4700
new file mode 100644
index 000000000..3c8d9b19b
--- /dev/null
+++ b/changes/bug4700
@@ -0,0 +1,5 @@
+  o Minor features (onion services):
+    - Version 3 onion services can now use the per-service
+      HiddenServiceExportCircuitID option to differentiate client circuits by
+      using the HAProxy proxy protocol which assigns IP addresses to inbound client
+      circuits. Closes ticket 4700. Patch by Mahrud Sayrafi.
diff --git a/src/app/config/config.c b/src/app/config/config.c
index 1adeb75c9..13421f103 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -457,6 +457,7 @@ static config_var_t option_vars_[] = {
   VAR("HiddenServiceMaxStreams",LINELIST_S, RendConfigLines, NULL),
   VAR("HiddenServiceMaxStreamsCloseCircuit",LINELIST_S, RendConfigLines, NULL),
   VAR("HiddenServiceNumIntroductionPoints", LINELIST_S, RendConfigLines, NULL),
+  VAR("HiddenServiceExportCircuitID", LINELIST_S,  RendConfigLines, NULL),
   VAR("HiddenServiceStatistics", BOOL, HiddenServiceStatistics_option, "1"),
   V(HidServAuth,                 LINELIST, NULL),
   V(ClientOnionAuthDir,          FILENAME, NULL),
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
index a85419376..8b333a6f4 100644
--- a/src/core/or/connection_edge.c
+++ b/src/core/or/connection_edge.c
@@ -597,6 +597,33 @@ connected_cell_format_payload(uint8_t *payload_out,
   return connected_payload_len;
 }
 
+/* DOCDOCDOC */
+static void
+send_ha_proxy_header(const edge_connection_t *edge_conn,
+                     connection_t *conn)
+{
+  char buf[512];
+  char dst_ipv6[39] = "::1";
+  /* See RFC4193 regarding fc00::/7 */
+  char src_ipv6_prefix[34] = "fc00:dead:beef:4dad:";
+  /* TODO: retain virtual port and use as destination port */
+  uint16_t dst_port = 443;
+  uint16_t src_port = 0;
+  uint32_t gid = 0;
+
+  if (edge_conn->on_circuit != NULL) {
+    gid = TO_ORIGIN_CIRCUIT(edge_conn->on_circuit)->global_identifier;
+    src_port = gid & 0x0000ffff;
+  }
+
+  gid = (gid == 0) ? 1 : gid;
+  src_port = (src_port == 0) ? 1 : src_port;
+
+  tor_snprintf(buf, sizeof(buf), "PROXY TCP6 %s:%x %s %d %d\r\n",
+	       src_ipv6_prefix, gid, dst_ipv6, src_port, dst_port);
+  connection_buf_add(buf, strlen(buf), conn);
+}
+
 /** Connected handler for exit connections: start writing pending
  * data, deliver 'CONNECTED' relay cells as appropriate, and check
  * any pending data that may have been received. */
@@ -618,28 +645,13 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn)
 
   conn->state = EXIT_CONN_STATE_OPEN;
 
-  /* Include Proxy Protocol header. */
-  char buf[512];
-  char dst_ipv6[39] = "::1";
-  /* See RFC4193 regarding fc00::/7 */
-  char src_ipv6_prefix[34] = "fc00:dead:beef:4dad:";
-  /* TODO: retain virtual port and use as destination port */
-  uint16_t dst_port = 443;
-  uint16_t src_port = 0;
-  uint32_t gid = 0;
-
-  if (edge_conn->on_circuit != NULL) {
-    gid = TO_ORIGIN_CIRCUIT(edge_conn->on_circuit)->global_identifier;
-    src_port = gid & 0x0000ffff;
+  /* If it's an onion service connection, we might want to include the proxy
+   * protocol header */
+  if (edge_conn->hs_ident &&
+      hs_service_exports_circuit_id(&edge_conn->hs_ident->identity_pk)) {
+    send_ha_proxy_header(edge_conn, conn);
   }
 
-  gid = (gid == 0) ? 1 : gid;
-  src_port = (src_port == 0) ? 1 : src_port;
-
-  tor_snprintf(buf, sizeof(buf), "PROXY TCP6 %s:%x %s %d %d\r\n",
-	       src_ipv6_prefix, gid, dst_ipv6, src_port, dst_port);
-  connection_buf_add(buf, strlen(buf), conn);
-
   connection_watch_events(conn, READ_EVENT); /* stop writing, keep reading */
   if (connection_get_outbuf_len(conn)) /* in case there are any queued relay
                                         * cells */
diff --git a/src/feature/hs/hs_config.c b/src/feature/hs/hs_config.c
index eaeb58829..16bfe7c54 100644
--- a/src/feature/hs/hs_config.c
+++ b/src/feature/hs/hs_config.c
@@ -188,6 +188,11 @@ config_has_invalid_options(const config_line_t *line_,
     NULL /* End marker. */
   };
 
+  const char *opts_exclude_v2[] = {
+    "HiddenServiceExportCircuitID",
+    NULL /* End marker. */
+  };
+
   /* Defining the size explicitly allows us to take advantage of the compiler
    * which warns us if we ever bump the max version but forget to grow this
    * array. The plus one is because we have a version 0 :). */
@@ -196,7 +201,7 @@ config_has_invalid_options(const config_line_t *line_,
   } exclude_lists[HS_VERSION_MAX + 1] = {
     { NULL }, /* v0. */
     { NULL }, /* v1. */
-    { NULL }, /* v2 */
+    { opts_exclude_v2 }, /* v2 */
     { opts_exclude_v3 }, /* v3. */
   };
 
@@ -262,6 +267,7 @@ config_service_v3(const config_line_t *line_,
                   hs_service_config_t *config)
 {
   int have_num_ip = 0;
+  bool export_circuit_id = false; /* just to detect duplicate options */
   const char *dup_opt_seen = NULL;
   const config_line_t *line;
 
@@ -288,6 +294,18 @@ config_service_v3(const config_line_t *line_,
       have_num_ip = 1;
       continue;
     }
+    if (!strcasecmp(line->key, "HiddenServiceExportCircuitID")) {
+      config->export_circuit_id =
+        (unsigned int) helper_parse_uint64(line->key, line->value, 0, 1, &ok);
+      if (!ok || export_circuit_id) {
+        if (export_circuit_id) {
+          dup_opt_seen = line->key;
+        }
+        goto err;
+      }
+      export_circuit_id = true;
+      continue;
+    }
   }
 
   /* We do not load the key material for the service at this stage. This is
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index 30d23eb77..75d7cb75e 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -3762,6 +3762,19 @@ hs_service_set_conn_addr_port(const origin_circuit_t *circ,
   return -1;
 }
 
+/** Does the service with identity pubkey <b>pk</b> export the circuit IDs of
+ *  its clients?  */
+bool
+hs_service_exports_circuit_id(const ed25519_public_key_t *pk)
+{
+  hs_service_t *service = find_service(hs_service_map, pk);
+  if (!service) {
+    return 0;
+  }
+
+  return service->config.export_circuit_id;
+}
+
 /* Add to file_list every filename used by a configured hidden service, and to
  * dir_list every directory path used by a configured hidden service. This is
  * used by the sandbox subsystem to whitelist those. */
diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h
index 735266071..e541cb28b 100644
--- a/src/feature/hs/hs_service.h
+++ b/src/feature/hs/hs_service.h
@@ -210,6 +210,9 @@ typedef struct hs_service_config_t {
 
   /* Is this service ephemeral? */
   unsigned int is_ephemeral : 1;
+
+  /* Does this service export the circuit ID of its clients? */
+  bool export_circuit_id;
 } hs_service_config_t;
 
 /* Service state. */
@@ -316,6 +319,8 @@ void hs_service_upload_desc_to_dir(const char *encoded_desc,
                                    const ed25519_public_key_t *blinded_pk,
                                    const routerstatus_t *hsdir_rs);
 
+bool hs_service_exports_circuit_id(const ed25519_public_key_t *pk);
+
 #ifdef HS_SERVICE_PRIVATE
 
 #ifdef TOR_UNIT_TESTS





More information about the tor-commits mailing list