Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
base repository: Yawning/tor
base: master
head repository: Yawning/tor
compare: bug16052a
Checking mergeability… Don’t worry, you can still create the pull request.
  • 7 commits
  • 9 files changed
  • 0 comments
  • 1 contributor
Commits on May 19, 2015
When set, this limits the maximum number of simultanious streams per
rendezvous circuit on the server side of a HS, with further RELAY_BEGIN
cells being silently ignored.

`ADD_ONION` also supports the parameter with the optional `MaxStreams=`
argument.

Addresses part of #16052.
Commits on May 20, 2015
Add "HiddenServiceMaxStreamsCloseCircuit" that will close the circuit
if "HiddenServiceMaxStreams" is exceeded instead of merely ignoring
further RELAY_BEGIN cells.
Add a changes file and update the man page.
Showing with 141 additions and 10 deletions.
  1. +5 −0 changes/feature16052
  2. +10 −0 doc/tor.1.txt
  3. +19 −8 src/or/circuituse.c
  4. +2 −0 src/or/config.c
  5. +2 −0 src/or/connection_edge.c
  6. +20 −1 src/or/control.c
  7. +3 −0 src/or/or.h
  8. +78 −1 src/or/rendservice.c
  9. +2 −0 src/or/rendservice.h
@@ -0,0 +1,5 @@
o Minor features (hidden service):
- Add the new options "HiddenServiceMaxStreams" and
"HiddenServiceMaxStreamsCloseCircuit" to allow hidden services to limit
the maximum number of simultaneous streams per circuit, and optionally
tear down the circuit when the limit is exceeded. Part of ticket 16052.
@@ -2149,6 +2149,16 @@ The following options are used to configure a hidden service.
not an authorization mechanism; it is instead meant to be a mild
inconvenience to port-scanners.) (Default: 0)

[[HiddenServiceMaxStreams]] **HiddenServiceMaxStreams** __N__::
The maximum number of simultaneous streams (connections) per rendezvous
circuit. (Setting this to 0 will allow an unlimited number of simultanous
streams.) (Default: 0)

[[HiddenServiceMaxStreamsCloseCircuit]] **HiddenServiceMaxStreamsCloseCircuit** **0**|**1**::
If set to 1, then exceeding **HiddenServiceMaxStreams** will cause the
offending rendezvous circuit to be torn down, as opposed to stream creation
requests that exceed the limit being silently ignored. (Default: 0)

[[RendPostPeriod]] **RendPostPeriod** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**::
Every time the specified period elapses, Tor uploads any rendezvous
service descriptors to the directory servers. This information is also
@@ -1189,17 +1189,28 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)

if (CIRCUIT_IS_ORIGIN(circ)) {
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
int removed = 0;
if (conn == origin_circ->p_streams) {
origin_circ->p_streams = conn->next_stream;
return;
removed = 1;
} else {
for (prevconn = origin_circ->p_streams;
prevconn && prevconn->next_stream && prevconn->next_stream != conn;
prevconn = prevconn->next_stream)
;
if (prevconn && prevconn->next_stream) {
prevconn->next_stream = conn->next_stream;
removed = 1;
}
}

for (prevconn = origin_circ->p_streams;
prevconn && prevconn->next_stream && prevconn->next_stream != conn;
prevconn = prevconn->next_stream)
;
if (prevconn && prevconn->next_stream) {
prevconn->next_stream = conn->next_stream;
if (removed) {
/* If the stream was removed, and it was a rend stream, decrement the
* number of streams on the circuit associated with the rend service.
*/
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
tor_assert(origin_circ->rend_data);
origin_circ->rend_data->nr_streams--;
}
return;
}
} else {
@@ -286,6 +286,8 @@ static config_var_t option_vars_[] = {
VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceAuthorizeClient",LINELIST_S,RendConfigLines, NULL),
VAR("HiddenServiceAllowUnknownPorts",LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceMaxStreams",LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceMaxStreamsCloseCircuit",LINELIST_S, RendConfigLines, NULL),
V(HiddenServiceStatistics, BOOL, "0"),
V(HidServAuth, LINELIST, NULL),
V(CloseHSClientCircuitsImmediatelyOnTimeout, BOOL, "0"),
@@ -2860,6 +2860,8 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
origin_circ->p_streams = n_stream;
assert_circuit_ok(circ);

origin_circ->rend_data->nr_streams++;

connection_exit_connect(n_stream);

/* For path bias: This circuit was used successfully */
@@ -3566,9 +3566,12 @@ handle_control_add_onion(control_connection_t *conn,
smartlist_t *port_cfgs = smartlist_new();
int discard_pk = 0;
int detach = 0;
int max_streams = 0;
int max_streams_close_circuit = 0;
for (size_t i = 1; i < arg_len; i++) {
static const char *port_prefix = "Port=";
static const char *flags_prefix = "Flags=";
static const char *max_s_prefix = "MaxStreams=";

const char *arg = smartlist_get(args, i);
if (!strcasecmpstart(arg, port_prefix)) {
@@ -3582,15 +3585,27 @@ handle_control_add_onion(control_connection_t *conn,
goto out;
}
smartlist_add(port_cfgs, cfg);
} else if (!strcasecmpstart(arg, max_s_prefix)) {
/* "MaxStreams=[0..65535]". */
const char *max_s_str = arg + strlen(max_s_prefix);
int ok = 0;
max_streams = (int)tor_parse_long(max_s_str, 10, 0, 65535, &ok, NULL);
if (!ok) {
connection_printf_to_buf(conn, "512 Invalid MaxStreams\r\n");
goto out;
}
} else if (!strcasecmpstart(arg, flags_prefix)) {
/* "Flags=Flag[,Flag]", where Flag can be:
* * 'DiscardPK' - If tor generates the keypair, do not include it in
* the response.
* * 'Detach' - Do not tie this onion service to any particular control
* connection.
* * 'MaxStreamsCloseCircuit' - Close the circuit if MaxStreams is
* exceeded.
*/
static const char *discard_flag = "DiscardPK";
static const char *detach_flag = "Detach";
static const char *max_s_close_flag = "MaxStreamsCloseCircuit";

smartlist_t *flags = smartlist_new();
int bad = 0;
@@ -3607,6 +3622,8 @@ handle_control_add_onion(control_connection_t *conn,
discard_pk = 1;
} else if (!strcasecmp(flag, detach_flag)) {
detach = 1;
} else if (!strcasecmp(flag, max_s_close_flag)) {
max_streams_close_circuit = 1;
} else {
connection_printf_to_buf(conn,
"512 Invalid 'Flags' argument: %s\r\n",
@@ -3652,7 +3669,9 @@ handle_control_add_onion(control_connection_t *conn,
* regardless of success/failure.
*/
char *service_id = NULL;
int ret = rend_service_add_ephemeral(pk, port_cfgs, &service_id);
int ret = rend_service_add_ephemeral(pk, port_cfgs, max_streams,
max_streams_close_circuit,
&service_id);
port_cfgs = NULL; /* port_cfgs is now owned by the rendservice code. */
switch (ret) {
case RSAE_OKAY:
@@ -818,6 +818,9 @@ typedef struct rend_data_t {
/** List of HSDir fingerprints on which this request has been sent to.
* This contains binary identity digest of the directory. */
smartlist_t *hsdirs_fp;

/** Number of streams associated with this rendezvous circuit. */
int nr_streams;
} rend_data_t;

/** Time interval for tracking replays of DH public keys received in
@@ -147,6 +147,13 @@ typedef struct rend_service_t {
/** If true, we don't close circuits for making requests to unsupported
* ports. */
int allow_unknown_ports;
/** The maximum number of simultanious streams-per-circuit that are allowed
* to be established, or 0 if no limit is set.
*/
int max_streams_per_circuit;
/** If true, we close circuits that exceed the max_streams_per_circuit
* limit. */
int max_streams_close_circuit;
} rend_service_t;

/** Returns a escaped string representation of the service, <b>s</b>.
@@ -259,6 +266,23 @@ rend_add_service(rend_service_t *service)

service->intro_nodes = smartlist_new();

if (service->max_streams_per_circuit < 0) {
log_warn(LD_CONFIG, "Hidden service (%s) configured with negative max "
"streams per circuit; ignoring.",
rend_service_escaped_dir(service));
rend_service_free(service);
return -1;
}

if (service->max_streams_close_circuit < 0 ||
service->max_streams_close_circuit > 1) {
log_warn(LD_CONFIG, "Hidden service (%s) configured with invalid "
"max streams handling; ignoring.",
rend_service_escaped_dir(service));
rend_service_free(service);
return -1;
}

if (service->auth_type != REND_NO_AUTH &&
smartlist_len(service->clients) == 0) {
log_warn(LD_CONFIG, "Hidden service (%s) with client authorization but no "
@@ -539,6 +563,33 @@ rend_config_services(const or_options_t *options, int validate_only)
log_info(LD_CONFIG,
"HiddenServiceDirGroupReadable=%d for %s",
service->dir_group_readable, service->directory);
} else if (!strcasecmp(line->key, "HiddenServiceMaxStreams")) {
service->max_streams_per_circuit = (int)tor_parse_long(line->value,
10, 0, 65535, &ok, NULL);
if (!ok) {
log_warn(LD_CONFIG,
"HiddenServiceMaxStreams should be between 0 and %d, not %s",
65535, line->value);
rend_service_free(service);
return -1;
}
log_info(LD_CONFIG,
"HiddenServiceMaxStreams=%d for %s",
service->max_streams_per_circuit, service->directory);
} else if (!strcasecmp(line->key, "HiddenServiceMaxStreamsCloseCircuit")) {
service->max_streams_close_circuit = (int)tor_parse_long(line->value,
10, 0, 1, &ok, NULL);
if (!ok) {
log_warn(LD_CONFIG,
"HiddenServiceMaxStreamsCloseCircuit should be 0 or 1, not %s",
line->value);
rend_service_free(service);
return -1;
}
log_info(LD_CONFIG,
"HiddenServiceMaxStreamsCloseCircuit=%d for %s",
(int)service->max_streams_close_circuit, service->directory);

} else if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) {
/* Parse auth type and comma-separated list of client names and add a
* rend_authorized_client_t for each client to the service's list
@@ -758,7 +809,10 @@ rend_config_services(const or_options_t *options, int validate_only)
return 0;
}

/** Add the ephemeral service <b>pk</b>/<b>ports</b> if possible.
/** Add the ephemeral service <b>pk</b>/<b>ports</b> if possible, with
* <b>max_streams_per_circuit</b> streams allowed per rendezvous circuit,
* and circuit closure on max streams being exceeded set by
* <b>max_streams_close_circuit</b>.
*
* Regardless of sucess/failure, callers should not touch pk/ports after
* calling this routine, and may assume that correct cleanup has been done
@@ -769,6 +823,8 @@ rend_config_services(const or_options_t *options, int validate_only)
rend_service_add_ephemeral_status_t
rend_service_add_ephemeral(crypto_pk_t *pk,
smartlist_t *ports,
int max_streams_per_circuit,
int max_streams_close_circuit,
char **service_id_out)
{
*service_id_out = NULL;
@@ -782,6 +838,8 @@ rend_service_add_ephemeral(crypto_pk_t *pk,
s->ports = ports;
s->intro_period_started = time(NULL);
s->n_intro_points_wanted = NUM_INTRO_POINTS_DEFAULT;
s->max_streams_per_circuit = max_streams_per_circuit;
s->max_streams_close_circuit = max_streams_close_circuit;
if (rend_service_derive_key_digests(s) < 0) {
rend_service_free(s);
return RSAE_BADPRIVKEY;
@@ -3795,6 +3853,25 @@ rend_service_set_connection_addr_port(edge_connection_t *conn,
serviceid, (unsigned)circ->base_.n_circ_id);
return -2;
}
if (service->max_streams_per_circuit > 0) {
/* Enforce the streams-per-circuit limit, and refuse to provide a
* mapping if this circuit will exceed the limit. */
#define MAX_STREAM_WARN_INTERVAL 600
static struct ratelim_t stream_ratelim =
RATELIM_INIT(MAX_STREAM_WARN_INTERVAL);
if (circ->rend_data->nr_streams >= service->max_streams_per_circuit) {
log_fn_ratelim(&stream_ratelim, LOG_WARN, LD_REND,
"Maximum streams per circuit limit reached on rendezvous "
"circuit %u; %s. Circuit has %d out of %d streams.",
(unsigned)circ->base_.n_circ_id,
service->max_streams_close_circuit ?
"closing circuit" :
"ignoring open stream request",
circ->rend_data->nr_streams,
service->max_streams_per_circuit);
return service->max_streams_close_circuit ? -2 : -1;
}
}
matching_ports = smartlist_new();
SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p,
{
@@ -117,6 +117,8 @@ typedef enum {
} rend_service_add_ephemeral_status_t;
rend_service_add_ephemeral_status_t rend_service_add_ephemeral(crypto_pk_t *pk,
smartlist_t *ports,
int max_streams_per_circuit,
int max_streams_close_circuit,
char **service_id_out);
int rend_service_del_ephemeral(const char *service_id);

No commit comments for this range