Commit 6846d148 authored by Nick Mathewson's avatar Nick Mathewson 🎨
Browse files

Merge branch 'ticket30924_042_04_squashed_merged'

parents f16fc262 a642a4cb
o Major features (onion service v3, denial of service):
- Add onion service introduction denial of service defenses. They consist of
rate limiting client introduction at the intro point using parameters that
can be sent by the service within the ESTABLISH_INTRO cell. If the cell
extension for this is not used, the intro point will honor the consensus
parameters. Closes ticket 30924.
......@@ -2915,7 +2915,13 @@ on the public Tor network.
HIDDEN SERVICE OPTIONS
----------------------
The following options are used to configure a hidden service.
The following options are used to configure a hidden service. Some options
apply per service and some apply for the whole tor instance.
The next section describes the per service options that can only be set
**after** the **HiddenServiceDir** directive
**PER SERVICE OPTIONS:**
[[HiddenServiceDir]] **HiddenServiceDir** __DIRECTORY__::
Store data files for a hidden service in DIRECTORY. Every hidden service
......@@ -2941,12 +2947,6 @@ The following options are used to configure a hidden service.
connects to that VIRTPORT, one of the TARGETs from those lines will be
chosen at random. Note that address-port pairs have to be comma-separated.
[[PublishHidServDescriptors]] **PublishHidServDescriptors** **0**|**1**::
If set to 0, Tor will run any hidden services you configure, but it won't
advertise them to the rendezvous directory. This option is only useful if
you're using a Tor controller that handles hidserv publishing for you.
(Default: 1)
[[HiddenServiceVersion]] **HiddenServiceVersion** **2**|**3**::
A list of rendezvous service descriptor versions to publish for the hidden
service. Currently, versions 2 and 3 are supported. (Default: 3)
......@@ -3025,6 +3025,38 @@ The following options are used to configure a hidden service.
Number of introduction points the hidden service will have. You can't
have more than 10 for v2 service and 20 for v3. (Default: 3)
[[HiddenServiceEnableIntroDoSDefense]] **HiddenServiceEnableIntroDoSDefense** **0**|**1**::
Enable DoS defense at the intropoint level. When this is enabled, the
rate and burst parameter (see below) will be sent to the intro point which
will then use them to apply rate limiting for introduction request to this
service.
+
The introduction point honors the consensus parameters except if this is
specifically set by the service operator using this option. The service
never looks at the consensus parameters in order to enable or disable this
defense. (Default: 0)
[[HiddenServiceEnableIntroDoSRatePerSec]] **HiddenServiceEnableIntroDoSRatePerSec** __NUM__::
The allowed client introduction rate per second at the introduction
point. If this option is 0, it is considered infinite and thus if
**HiddenServiceEnableIntroDoSDefense** is set, it then effectively
disables the defenses. (Default: 25)
[[HiddenServiceEnableIntroDoSBurstPerSec]] **HiddenServiceEnableIntroDoSBurstPerSec** __NUM__::
The allowed client introduction burst per second at the introduction
point. If this option is 0, it is considered infinite and thus if
**HiddenServiceEnableIntroDoSDefense** is set, it then effectively
disables the defenses. (Default: 200)
**PER INSTANCE OPTIONS:**
[[PublishHidServDescriptors]] **PublishHidServDescriptors** **0**|**1**::
If set to 0, Tor will run any hidden services you configure, but it won't
advertise them to the rendezvous directory. This option is only useful if
you're using a Tor controller that handles hidserv publishing for you.
(Default: 1)
[[HiddenServiceSingleHopMode]] **HiddenServiceSingleHopMode** **0**|**1**::
**Experimental - Non Anonymous** Hidden Services on a tor instance in
HiddenServiceSingleHopMode make one-hop (direct) circuits between the onion
......
......@@ -44,7 +44,6 @@ problem function-size /src/app/config/config.c:parse_dir_authority_line() 150
problem function-size /src/app/config/config.c:parse_dir_fallback_line() 101
problem function-size /src/app/config/config.c:parse_port_config() 446
problem function-size /src/app/config/config.c:parse_ports() 168
problem function-size /src/app/config/config.c:getinfo_helper_config() 113
problem file-size /src/app/config/or_options_st.h 1112
problem include-count /src/app/main/main.c 68
problem function-size /src/app/main/main.c:dumpstats() 102
......@@ -81,8 +80,8 @@ problem dependency-violation /src/core/mainloop/netstatus.c 4
problem dependency-violation /src/core/mainloop/periodic.c 2
problem dependency-violation /src/core/or/address_set.c 1
problem file-size /src/core/or/channel.c 3487
problem file-size /src/core/or/channel.h 780
problem dependency-violation /src/core/or/channel.c 9
problem file-size /src/core/or/channel.h 780
problem dependency-violation /src/core/or/channelpadding.c 6
problem function-size /src/core/or/channeltls.c:channel_tls_handle_var_cell() 160
problem function-size /src/core/or/channeltls.c:channel_tls_process_versions_cell() 170
......@@ -105,10 +104,10 @@ problem dependency-violation /src/core/or/circuitlist.c 19
problem function-size /src/core/or/circuitmux.c:circuitmux_set_policy() 109
problem function-size /src/core/or/circuitmux.c:circuitmux_attach_circuit() 113
problem dependency-violation /src/core/or/circuitmux_ewma.c 2
problem file-size /src/core/or/circuitpadding.c 3043
problem function-size /src/core/or/circuitpadding.c:circpad_machine_schedule_padding() 107
problem file-size /src/core/or/circuitpadding.h 809
problem file-size /src/core/or/circuitpadding.c 3096
problem function-size /src/core/or/circuitpadding.c:circpad_machine_schedule_padding() 113
problem dependency-violation /src/core/or/circuitpadding.c 6
problem file-size /src/core/or/circuitpadding.h 813
problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_relay_hide_intro_circuits() 103
problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_client_hide_rend_circuits() 112
problem dependency-violation /src/core/or/circuitpadding_machines.c 1
......@@ -142,19 +141,19 @@ problem include-count /src/core/or/connection_or.c 51
problem function-size /src/core/or/connection_or.c:connection_or_group_set_badness_() 105
problem function-size /src/core/or/connection_or.c:connection_or_client_learned_peer_id() 142
problem function-size /src/core/or/connection_or.c:connection_or_compute_authenticate_cell_body() 231
problem file-size /src/core/or/or.h 1103
problem include-count /src/core/or/or.h 49
problem dependency-violation /src/core/or/connection_or.c 20
problem dependency-violation /src/core/or/dos.c 5
problem dependency-violation /src/core/or/onion.c 2
problem file-size /src/core/or/or.h 1107
problem include-count /src/core/or/or.h 49
problem dependency-violation /src/core/or/or_periodic.c 1
problem file-size /src/core/or/policies.c 3249
problem function-size /src/core/or/policies.c:policy_summarize() 107
problem dependency-violation /src/core/or/policies.c 14
problem function-size /src/core/or/protover.c:protover_all_supported() 117
problem function-size /src/core/or/relay.c:circuit_receive_relay_cell() 127
problem file-size /src/core/or/relay.c 3263
problem dependency-violation /src/core/or/reasons.c 2
problem file-size /src/core/or/relay.c 3264
problem function-size /src/core/or/relay.c:circuit_receive_relay_cell() 127
problem function-size /src/core/or/relay.c:relay_send_command_from_edge_() 109
problem function-size /src/core/or/relay.c:connection_ap_process_end_not_open() 192
problem function-size /src/core/or/relay.c:connection_edge_process_relay_cell_not_open() 137
......@@ -237,18 +236,19 @@ problem function-size /src/feature/dirparse/parsecommon.c:get_next_token() 158
problem function-size /src/feature/dirparse/routerparse.c:router_parse_entry_from_string() 554
problem function-size /src/feature/dirparse/routerparse.c:extrainfo_parse_entry_from_string() 208
problem function-size /src/feature/hibernate/hibernate.c:accounting_parse_options() 109
problem function-size /src/feature/hs/hs_cell.c:hs_cell_build_establish_intro() 113
problem function-size /src/feature/hs/hs_cell.c:hs_cell_build_establish_intro() 115
problem function-size /src/feature/hs/hs_cell.c:hs_cell_parse_introduce2() 152
problem function-size /src/feature/hs/hs_client.c:send_introduce1() 103
problem function-size /src/feature/hs/hs_client.c:hs_config_client_authorization() 107
problem function-size /src/feature/hs/hs_common.c:hs_get_responsible_hsdirs() 102
problem function-size /src/feature/hs/hs_config.c:config_service_v3() 107
problem function-size /src/feature/hs/hs_config.c:config_generic_service() 138
problem function-size /src/feature/hs/hs_descriptor.c:desc_encode_v3() 101
problem function-size /src/feature/hs/hs_descriptor.c:decrypt_desc_layer() 105
problem function-size /src/feature/hs/hs_descriptor.c:decode_introduction_point() 122
problem function-size /src/feature/hs/hs_descriptor.c:desc_decode_superencrypted_v3() 107
problem function-size /src/feature/hs/hs_descriptor.c:desc_decode_encrypted_v3() 107
problem file-size /src/feature/hs/hs_service.c 4109
problem file-size /src/feature/hs/hs_service.c 4116
problem function-size /src/feature/keymgt/loadkey.c:ed_key_init_from_file() 326
problem function-size /src/feature/nodelist/authcert.c:trusted_dirs_load_certs_from_string() 123
problem function-size /src/feature/nodelist/authcert.c:authority_certs_fetch_missing() 295
......@@ -261,7 +261,7 @@ problem function-size /src/feature/nodelist/node_select.c:router_pick_directory_
problem function-size /src/feature/nodelist/node_select.c:compute_weighted_bandwidths() 203
problem function-size /src/feature/nodelist/node_select.c:router_pick_trusteddirserver_impl() 112
problem function-size /src/feature/nodelist/nodelist.c:compute_frac_paths_available() 190
problem file-size /src/feature/nodelist/routerlist.c 3239
problem file-size /src/feature/nodelist/routerlist.c 3241
problem function-size /src/feature/nodelist/routerlist.c:router_rebuild_store() 148
problem function-size /src/feature/nodelist/routerlist.c:router_add_to_routerlist() 168
problem function-size /src/feature/nodelist/routerlist.c:routerlist_remove_old_routers() 121
......@@ -280,7 +280,7 @@ problem function-size /src/feature/relay/routerkeys.c:load_ed_keys() 294
problem function-size /src/feature/rend/rendcache.c:rend_cache_store_v2_desc_as_client() 190
problem function-size /src/feature/rend/rendclient.c:rend_client_send_introduction() 219
problem function-size /src/feature/rend/rendcommon.c:rend_encode_v2_descriptors() 221
problem function-size /src/feature/rend/rendmid.c:rend_mid_establish_intro_legacy() 103
problem function-size /src/feature/rend/rendmid.c:rend_mid_establish_intro_legacy() 104
problem function-size /src/feature/rend/rendparse.c:rend_parse_v2_service_descriptor() 181
problem function-size /src/feature/rend/rendparse.c:rend_parse_introduction_points() 129
problem file-size /src/feature/rend/rendservice.c 4511
......
......@@ -496,6 +496,11 @@ static const config_var_t option_vars_[] = {
VAR("HiddenServiceMaxStreamsCloseCircuit",LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceNumIntroductionPoints", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceExportCircuitID", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceEnableIntroDoSDefense", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceEnableIntroDoSRatePerSec",
LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceEnableIntroDoSBurstPerSec",
LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceStatistics", BOOL, HiddenServiceStatistics_option, "1"),
V(HidServAuth, LINELIST, NULL),
V(ClientOnionAuthDir, FILENAME, NULL),
......
......@@ -843,6 +843,10 @@ typedef struct protover_summary_flags_t {
/** True iff this router has a protocol list that allows clients to
* negotiate hs circuit setup padding. Requires Padding>=2. */
unsigned int supports_hs_setup_padding : 1;
/** True iff this router has a protocol list that allows it to support the
* ESTABLISH_INTRO DoS cell extension. Requires HSIntro>=5. */
unsigned int supports_establish_intro_dos_extension : 1;
} protover_summary_flags_t;
typedef struct routerinfo_t routerinfo_t;
......
......@@ -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). */
......
......@@ -392,7 +392,7 @@ protover_get_supported_protocols(void)
"Desc=1-2 "
"DirCache=1-2 "
"HSDir=1-2 "
"HSIntro=3-4 "
"HSIntro=3-5 "
"HSRend=1-2 "
"Link=1-5 "
#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
......
......@@ -450,7 +450,9 @@ memoize_protover_summary(protover_summary_flags_t *out,
PROTOVER_HS_RENDEZVOUS_POINT_V3);
out->supports_hs_setup_padding =
protocol_list_supports_protocol(protocols, PRT_PADDING,
PROTOVER_HS_SETUP_PADDING);
PROTOVER_HS_SETUP_PADDING);
out->supports_establish_intro_dos_extension =
protocol_list_supports_protocol(protocols, PRT_HSINTRO, 5);
protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out));
cached = strmap_set(protover_summary_map, protocols, new_cached);
......
......@@ -473,10 +473,110 @@ introduce1_set_legacy_id(trn_cell_introduce1_t *cell,
}
}
/* Build and add to the given DoS cell extension the given parameter type and
* value. */
static void
build_establish_intro_dos_param(trn_cell_extension_dos_t *dos_ext,
uint8_t param_type, uint64_t param_value)
{
trn_cell_extension_dos_param_t *dos_param =
trn_cell_extension_dos_param_new();
/* Extra safety. We should never send an unknown parameter type. */
tor_assert(param_type == TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC ||
param_type == TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC);
trn_cell_extension_dos_param_set_type(dos_param, param_type);
trn_cell_extension_dos_param_set_value(dos_param, param_value);
trn_cell_extension_dos_add_params(dos_ext, dos_param);
/* Not freeing the trunnel object because it is now owned by dos_ext. */
}
/* Build the DoS defense cell extension and put it in the given extensions
* object. This can't fail. */
static void
build_establish_intro_dos_extension(const hs_service_config_t *service_config,
trn_cell_extension_t *extensions)
{
ssize_t ret, dos_ext_encoded_len;
uint8_t *field_array;
trn_cell_extension_field_t *field;
trn_cell_extension_dos_t *dos_ext;
tor_assert(service_config);
tor_assert(extensions);
/* We are creating a cell extension field of the type DoS. */
field = trn_cell_extension_field_new();
trn_cell_extension_field_set_field_type(field,
TRUNNEL_CELL_EXTENSION_TYPE_DOS);
/* Build DoS extension field. We will put in two parameters. */
dos_ext = trn_cell_extension_dos_new();
trn_cell_extension_dos_set_n_params(dos_ext, 2);
/* Build DoS parameter INTRO2 rate per second. */
build_establish_intro_dos_param(dos_ext,
TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC,
service_config->intro_dos_rate_per_sec);
/* Build DoS parameter INTRO2 burst per second. */
build_establish_intro_dos_param(dos_ext,
TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC,
service_config->intro_dos_burst_per_sec);
/* Set the field with the encoded DoS extension. */
dos_ext_encoded_len = trn_cell_extension_dos_encoded_len(dos_ext);
/* Set length field and the field array size length. */
trn_cell_extension_field_set_field_len(field, dos_ext_encoded_len);
trn_cell_extension_field_setlen_field(field, dos_ext_encoded_len);
/* Encode the DoS extension into the cell extension field. */
field_array = trn_cell_extension_field_getarray_field(field);
ret = trn_cell_extension_dos_encode(field_array,
trn_cell_extension_field_getlen_field(field), dos_ext);
tor_assert(ret == dos_ext_encoded_len);
/* Finally, encode field into the cell extension. */
trn_cell_extension_add_fields(extensions, field);
/* We've just add an extension field to the cell extensions so increment the
* total number. */
trn_cell_extension_set_num(extensions,
trn_cell_extension_get_num(extensions) + 1);
/* Cleanup. DoS extension has been encoded at this point. */
trn_cell_extension_dos_free(dos_ext);
}
/* ========== */
/* Public API */
/* ========== */
/* Allocate and build all the ESTABLISH_INTRO cell extension. The given
* extensions pointer is always set to a valid cell extension object. */
STATIC trn_cell_extension_t *
build_establish_intro_extensions(const hs_service_config_t *service_config,
const hs_service_intro_point_t *ip)
{
trn_cell_extension_t *extensions;
tor_assert(service_config);
tor_assert(ip);
extensions = trn_cell_extension_new();
trn_cell_extension_set_num(extensions, 0);
/* If the defense has been enabled service side (by the operator with a
* torrc option) and the intro point does support it. */
if (service_config->has_dos_defense_enabled &&
ip->support_intro2_dos_defense) {
/* This function takes care to increment the number of extensions. */
build_establish_intro_dos_extension(service_config, extensions);
}
return extensions;
}
/* Build an ESTABLISH_INTRO cell with the given circuit nonce and intro point
* object. The encoded cell is put in cell_out that MUST at least be of the
* size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on success else
......@@ -484,15 +584,17 @@ introduce1_set_legacy_id(trn_cell_introduce1_t *cell,
* legacy cell creation. */
ssize_t
hs_cell_build_establish_intro(const char *circ_nonce,
const hs_service_config_t *service_config,
const hs_service_intro_point_t *ip,
uint8_t *cell_out)
{
ssize_t cell_len = -1;
uint16_t sig_len = ED25519_SIG_LEN;
trn_cell_extension_t *ext;
trn_cell_establish_intro_t *cell = NULL;
trn_cell_extension_t *extensions;
tor_assert(circ_nonce);
tor_assert(service_config);
tor_assert(ip);
/* Quickly handle the legacy IP. */
......@@ -505,11 +607,12 @@ hs_cell_build_establish_intro(const char *circ_nonce,
goto done;
}
/* Build the extensions, if any. */
extensions = build_establish_intro_extensions(service_config, ip);
/* Set extension data. None used here. */
ext = trn_cell_extension_new();
trn_cell_extension_set_num(ext, 0);
cell = trn_cell_establish_intro_new();
trn_cell_establish_intro_set_extensions(cell, ext);
trn_cell_establish_intro_set_extensions(cell, extensions);
/* Set signature size. Array is then allocated in the cell. We need to do
* this early so we can use trunnel API to get the signature length. */
trn_cell_establish_intro_set_sig_len(cell, sig_len);
......
......@@ -79,6 +79,7 @@ typedef struct hs_cell_introduce2_data_t {
/* Build cell API. */
ssize_t hs_cell_build_establish_intro(const char *circ_nonce,
const hs_service_config_t *config,
const hs_service_intro_point_t *ip,
uint8_t *cell_out);
ssize_t hs_cell_build_rendezvous1(const uint8_t *rendezvous_cookie,
......@@ -105,5 +106,15 @@ int hs_cell_parse_rendezvous2(const uint8_t *payload, size_t payload_len,
/* Util API. */
void hs_cell_introduce1_data_clear(hs_cell_introduce1_data_t *data);
#ifdef TOR_UNIT_TESTS
#include "trunnel/hs/cell_common.h"
STATIC trn_cell_extension_t *
build_establish_intro_extensions(const hs_service_config_t *service_config,
const hs_service_intro_point_t *ip);
#endif /* defined(TOR_UNIT_TESTS) */
#endif /* !defined(TOR_HS_CELL_H) */
......@@ -317,7 +317,7 @@ send_establish_intro(const hs_service_t *service,
/* Encode establish intro cell. */
cell_len = hs_cell_build_establish_intro(circ->cpath->prev->rend_circ_nonce,
ip, payload);
&service->config, ip, payload);
if (cell_len < 0) {
log_warn(LD_REND, "Unable to encode ESTABLISH_INTRO cell for service %s "
"on circuit %u. Closing circuit.",
......
......@@ -218,6 +218,9 @@ config_has_invalid_options(const config_line_t *line_,
const char *opts_exclude_v2[] = {
"HiddenServiceExportCircuitID",
"HiddenServiceEnableIntroDoSDefense",
"HiddenServiceEnableIntroDoSRatePerSec",
"HiddenServiceEnableIntroDoSBurstPerSec",
NULL /* End marker. */
};
......@@ -276,6 +279,15 @@ config_validate_service(const hs_service_config_t *config)
goto invalid;
}
/* DoS validation values. */
if (config->has_dos_defense_enabled &&
(config->intro_dos_burst_per_sec < config->intro_dos_rate_per_sec)) {
log_warn(LD_CONFIG, "Hidden service DoS defenses burst (%" PRIu32 ") can "
"not be smaller than the rate value (%" PRIu32 ").",
config->intro_dos_burst_per_sec, config->intro_dos_rate_per_sec);
goto invalid;
}
/* Valid. */
return 0;
invalid:
......@@ -296,6 +308,8 @@ config_service_v3(const config_line_t *line_,
{
int have_num_ip = 0;
bool export_circuit_id = false; /* just to detect duplicate options */
bool dos_enabled = false, dos_rate_per_sec = false;
bool dos_burst_per_sec = false;
const char *dup_opt_seen = NULL;
const config_line_t *line;
......@@ -334,6 +348,52 @@ config_service_v3(const config_line_t *line_,
export_circuit_id = true;
continue;
}
if (!strcasecmp(line->key, "HiddenServiceEnableIntroDoSDefense")) {
config->has_dos_defense_enabled =
(unsigned int) helper_parse_uint64(line->key, line->value,
HS_CONFIG_V3_DOS_DEFENSE_DEFAULT,
1, &ok);
if (!ok || dos_enabled) {
if (dos_enabled) {
dup_opt_seen = line->key;
}
goto err;
}
dos_enabled = true;
continue;
}
if (!strcasecmp(line->key, "HiddenServiceEnableIntroDoSRatePerSec")) {
config->intro_dos_rate_per_sec =
(unsigned int) helper_parse_uint64(line->key, line->value,
HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN,
HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX, &ok);
if (!ok || dos_rate_per_sec) {
if (dos_rate_per_sec) {
dup_opt_seen = line->key;
}
goto err;
}
dos_rate_per_sec = true;
log_info(LD_REND, "Service INTRO2 DoS defenses rate set to: %" PRIu32,
config->intro_dos_rate_per_sec);
continue;
}
if (!strcasecmp(line->key, "HiddenServiceEnableIntroDoSBurstPerSec")) {
config->intro_dos_burst_per_sec =
(unsigned int) helper_parse_uint64(line->key, line->value,
HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN,
HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX, &ok);
if (!ok || dos_burst_per_sec) {
if (dos_burst_per_sec) {
dup_opt_seen = line->key;
}
goto err;
}
dos_burst_per_sec = true;
log_info(LD_REND, "Service INTRO2 DoS defenses burst set to: %" PRIu32,
config->intro_dos_burst_per_sec);
continue;
}
}
/* We do not load the key material for the service at this stage. This is
......
......@@ -15,6 +15,15 @@
#define HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT 65535
/* Maximum number of intro points per version 3 services. */
#define HS_CONFIG_V3_MAX_INTRO_POINTS 20
/* Default value for the introduction DoS defenses. The MIN/MAX are inclusive
* meaning they can be used as valid values. */
#define HS_CONFIG_V3_DOS_DEFENSE_DEFAULT 0
#define HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_DEFAULT 25
#define HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MIN 0
#define HS_CONFIG_V3_DOS_DEFENSE_RATE_PER_SEC_MAX INT32_MAX
#define HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_DEFAULT 200
#define HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MIN 0
#define HS_CONFIG_V3_DOS_DEFENSE_BURST_PER_SEC_MAX INT32_MAX
/* API */
......
......@@ -45,24 +45,26 @@
* introduction DoS defense. Disabled by default. */
#define HS_DOS_INTRODUCE_ENABLED_DEFAULT 0
/* Consensus parameters. */
static uint32_t hs_dos_introduce_rate_per_sec =
/* Consensus parameters. The ESTABLISH_INTRO DoS cell extension have higher
* priority than these values. If no extension is sent, these are used only by
* the introduction point. */
static uint32_t consensus_param_introduce_rate_per_sec =
HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC;
static uint32_t hs_dos_introduce_burst_per_sec =
static uint32_t consensus_param_introduce_burst_per_sec =
HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC;
static uint32_t hs_dos_introduce_enabled =
static uint32_t consensus_param_introduce_defense_enabled =
HS_DOS_INTRODUCE_ENABLED_DEFAULT;
static uint32_t
get_param_intro_dos_enabled(const networkstatus_t *ns)
STATIC uint32_t
get_intro2_enable_consensus_param(const networkstatus_t *ns)
{
return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSDefense",
HS_DOS_INTRODUCE_ENABLED_DEFAULT, 0, 1);
}
/* Return the parameter for the introduction rate per sec. */
static uint32_t
get_param_rate_per_sec(const networkstatus_t *ns)
STATIC uint32_t
get_intro2_rate_consensus_param(const networkstatus_t *ns)
{
return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSRatePerSec",
HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC,
......@@ -70,8 +72,8 @@ get_param_rate_per_sec(const networkstatus_t *ns)
}
/* Return the parameter for the introduction burst per sec. */
static uint32_t
get_param_burst_per_sec(const networkstatus_t *ns)
STATIC uint32_t
get_intro2_burst_consensus_param(const networkstatus_t *ns)
{
return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSBurstPerSec",
HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC,
......@@ -88,10 +90,13 @@ update_intro_circuits(void)
smartlist_t *intro_circs = hs_circuitmap_get_all_intro_circ_relay_side();
SMARTLIST_FOREACH_BEGIN(intro_circs, circuit_t *, circ) {
/* Defenses might have been enabled or disabled. */
TO_OR_CIRCUIT(circ)->introduce2_dos_defense_enabled =
consensus_param_introduce_defense_enabled;
/* Adjust the rate/burst value that might have changed. */
token_bucket_ctr_adjust(&TO_OR_CIRCUIT(circ)->introduce2_bucket,
hs_dos_get_intro2_rate(),
hs_dos_get_intro2_burst());
consensus_param_introduce_rate_per_sec,
consensus_param_introduce_burst_per_sec);
} SMARTLIST_FOREACH_END(circ);
smartlist_free(intro_circs);
......@@ -101,9 +106,12 @@ update_intro_circuits(void)
static void
set_consensus_parameters(const networkstatus_t *ns)
{
hs_dos_introduce_rate_per_sec = get_param_rate_per_sec(ns);
hs_dos_introduce_burst_per_sec = get_param_burst_per_sec(ns);
hs_dos_introduce_enabled = get_param_intro_dos_enabled(ns);
consensus_param_introduce_rate_per_sec =
get_intro2_rate_consensus_param(ns);
consensus_param_introduce_burst_per_sec =
get_intro2_burst_consensus_param(ns);
consensus_param_introduce_defense_enabled =
get_intro2_enable_consensus_param(ns);
/* The above might have changed which means we need to go through all
* introduction circuits (relay side) and update the token buckets. */
......@@ -114,18 +122,20 @@ set_consensus_parameters(const networkstatus_t *ns)
* Public API.
*/
/* Return the INTRODUCE2 cell rate per second. */
uint32_t
hs_dos_get_intro2_rate(void)
{
return hs_dos_introduce_rate_per_sec;
}
/* Return the INTRODUCE2 cell burst per second. */
uint32_t
hs_dos_get_intro2_burst(void)
/* Initialize the INTRODUCE2 token bucket for the DoS defenses using the
* consensus/default values. We might get a cell extension that changes those
* later but if we don't, the default or consensus parameters are used. */
void
hs_dos_setup_default_intro2_defenses(or_circuit_t *circ)
{
return hs_dos_introduce_burst_per_sec;
tor_assert(circ);
circ->introduce2_dos_defense_enabled =
consensus_param_introduce_defense_enabled;
token_bucket_ctr_init(&circ->introduce2_bucket,
consensus_param_introduce_rate_per_sec,
consensus_param_introduce_burst_per_sec,
(uint32_t) approx_time());
}
/* Called when the consensus has changed. We might have new consensus
......@@ -149,8 +159,10 @@ hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
{
tor_assert(s_intro_circ);
/* Always allowed if the defense is disabled. */
if (!hs_dos_introduce_enabled) {
/* Allow to send the cell if the DoS defenses are disabled on the circuit.
* This can be set by the consensus, the ESTABLISH_INTRO cell extension or
* the hardcoded values in tor code. */
if (!s_intro_circ->introduce2_dos_defense_enabled) {
return true;