Commit 27d7491f authored by George Kadianakis's avatar George Kadianakis
Browse files

Introduce per-service HiddenServiceExportCircuitID torrc option.

Moves code to a function, better viewed with --color-moved.
parent be142194
Loading
Loading
Loading
Loading

changes/bug4700

0 → 100644
+5 −0
Original line number Diff line number Diff line
  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.
+1 −0
Original line number Diff line number Diff line
@@ -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),
+32 −20
Original line number Diff line number Diff line
@@ -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 */
+19 −1
Original line number Diff line number Diff line
@@ -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
+13 −0
Original line number Diff line number Diff line
@@ -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. */
Loading