mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-24 06:48:05 +01:00
Add "HiddenServiceMaxStreams" as a per-HS tunable.
When set, this limits the maximum number of simultaneous streams per rendezvous circuit on the server side of a HS, with further RELAY_BEGIN cells being silently ignored. This can be modified via "HiddenServiceMaxStreamsCloseCircuit", which if set will cause offending rendezvous circuits to be torn down instead. Addresses part of #16052.
This commit is contained in:
parent
32bd533dda
commit
db7bde08be
7 changed files with 94 additions and 8 deletions
5
changes/feature16052
Normal file
5
changes/feature16052
Normal file
|
@ -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
|
not an authorization mechanism; it is instead meant to be a mild
|
||||||
inconvenience to port-scanners.) (Default: 0)
|
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**::
|
[[RendPostPeriod]] **RendPostPeriod** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**::
|
||||||
Every time the specified period elapses, Tor uploads any rendezvous
|
Every time the specified period elapses, Tor uploads any rendezvous
|
||||||
service descriptors to the directory servers. This information is also
|
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)) {
|
if (CIRCUIT_IS_ORIGIN(circ)) {
|
||||||
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
|
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
|
||||||
|
int removed = 0;
|
||||||
if (conn == origin_circ->p_streams) {
|
if (conn == origin_circ->p_streams) {
|
||||||
origin_circ->p_streams = conn->next_stream;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (removed) {
|
||||||
for (prevconn = origin_circ->p_streams;
|
/* If the stream was removed, and it was a rend stream, decrement the
|
||||||
prevconn && prevconn->next_stream && prevconn->next_stream != conn;
|
* number of streams on the circuit associated with the rend service.
|
||||||
prevconn = prevconn->next_stream)
|
*/
|
||||||
;
|
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
|
||||||
if (prevconn && prevconn->next_stream) {
|
tor_assert(origin_circ->rend_data);
|
||||||
prevconn->next_stream = conn->next_stream;
|
origin_circ->rend_data->nr_streams--;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -286,6 +286,8 @@ static config_var_t option_vars_[] = {
|
||||||
VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines, NULL),
|
VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines, NULL),
|
||||||
VAR("HiddenServiceAuthorizeClient",LINELIST_S,RendConfigLines, NULL),
|
VAR("HiddenServiceAuthorizeClient",LINELIST_S,RendConfigLines, NULL),
|
||||||
VAR("HiddenServiceAllowUnknownPorts",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(HiddenServiceStatistics, BOOL, "0"),
|
||||||
V(HidServAuth, LINELIST, NULL),
|
V(HidServAuth, LINELIST, NULL),
|
||||||
V(CloseHSClientCircuitsImmediatelyOnTimeout, BOOL, "0"),
|
V(CloseHSClientCircuitsImmediatelyOnTimeout, BOOL, "0"),
|
||||||
|
|
|
@ -2860,6 +2860,8 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
|
||||||
origin_circ->p_streams = n_stream;
|
origin_circ->p_streams = n_stream;
|
||||||
assert_circuit_ok(circ);
|
assert_circuit_ok(circ);
|
||||||
|
|
||||||
|
origin_circ->rend_data->nr_streams++;
|
||||||
|
|
||||||
connection_exit_connect(n_stream);
|
connection_exit_connect(n_stream);
|
||||||
|
|
||||||
/* For path bias: This circuit was used successfully */
|
/* For path bias: This circuit was used successfully */
|
||||||
|
|
|
@ -818,6 +818,9 @@ typedef struct rend_data_t {
|
||||||
/** List of HSDir fingerprints on which this request has been sent to.
|
/** List of HSDir fingerprints on which this request has been sent to.
|
||||||
* This contains binary identity digest of the directory. */
|
* This contains binary identity digest of the directory. */
|
||||||
smartlist_t *hsdirs_fp;
|
smartlist_t *hsdirs_fp;
|
||||||
|
|
||||||
|
/** Number of streams associated with this rendezvous circuit. */
|
||||||
|
int nr_streams;
|
||||||
} rend_data_t;
|
} rend_data_t;
|
||||||
|
|
||||||
/** Time interval for tracking replays of DH public keys received in
|
/** 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
|
/** If true, we don't close circuits for making requests to unsupported
|
||||||
* ports. */
|
* ports. */
|
||||||
int allow_unknown_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;
|
} rend_service_t;
|
||||||
|
|
||||||
/** Returns a escaped string representation of the service, <b>s</b>.
|
/** Returns a escaped string representation of the service, <b>s</b>.
|
||||||
|
@ -539,6 +546,33 @@ rend_config_services(const or_options_t *options, int validate_only)
|
||||||
log_info(LD_CONFIG,
|
log_info(LD_CONFIG,
|
||||||
"HiddenServiceDirGroupReadable=%d for %s",
|
"HiddenServiceDirGroupReadable=%d for %s",
|
||||||
service->dir_group_readable, service->directory);
|
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")) {
|
} else if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) {
|
||||||
/* Parse auth type and comma-separated list of client names and add a
|
/* 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
|
* rend_authorized_client_t for each client to the service's list
|
||||||
|
@ -3795,6 +3829,25 @@ rend_service_set_connection_addr_port(edge_connection_t *conn,
|
||||||
serviceid, (unsigned)circ->base_.n_circ_id);
|
serviceid, (unsigned)circ->base_.n_circ_id);
|
||||||
return -2;
|
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();
|
matching_ports = smartlist_new();
|
||||||
SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p,
|
SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p,
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue