#define HS_DOS_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
#include "core/or/circuitlist.h"
#include "feature/hs/hs_circuitmap.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/relay/routermode.h"
#include "lib/evloop/token_bucket.h"
#include "feature/hs/hs_dos.h"
#define HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC 25
#define HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC 200
#define HS_DOS_INTRODUCE_ENABLED_DEFAULT 0
static uint64_t intro2_rejected_count = 0;
static uint32_t consensus_param_introduce_rate_per_sec =
HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC;
static uint32_t consensus_param_introduce_burst_per_sec =
HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC;
static uint32_t consensus_param_introduce_defense_enabled =
HS_DOS_INTRODUCE_ENABLED_DEFAULT;
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);
}
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,
0, INT32_MAX);
}
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,
0, INT32_MAX);
}
static void
update_intro_circuits(void)
{
smartlist_t *intro_circs = hs_circuitmap_get_all_intro_circ_relay_side();
SMARTLIST_FOREACH_BEGIN(intro_circs, circuit_t *, circ) {
if (TO_OR_CIRCUIT(circ)->introduce2_dos_defense_explicit) {
continue;
}
TO_OR_CIRCUIT(circ)->introduce2_dos_defense_enabled =
consensus_param_introduce_defense_enabled;
token_bucket_ctr_adjust(&TO_OR_CIRCUIT(circ)->introduce2_bucket,
consensus_param_introduce_rate_per_sec,
consensus_param_introduce_burst_per_sec);
} SMARTLIST_FOREACH_END(circ);
smartlist_free(intro_circs);
}
static void
set_consensus_parameters(const networkstatus_t *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);
update_intro_circuits();
}
void
hs_dos_setup_default_intro2_defenses(or_circuit_t *circ)
{
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());
}
void
hs_dos_consensus_has_changed(const networkstatus_t *ns)
{
if (!public_server_mode(get_options())) {
return;
}
set_consensus_parameters(ns);
}
bool
hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
{
tor_assert(s_intro_circ);
if (!s_intro_circ->introduce2_dos_defense_enabled) {
goto allow;
}
if (BUG(TO_CIRCUIT(s_intro_circ)->purpose != CIRCUIT_PURPOSE_INTRO_POINT)) {
goto disallow;
}
token_bucket_ctr_refill(&s_intro_circ->introduce2_bucket,
(uint32_t) approx_time());
if (token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0) {
token_bucket_ctr_dec(&s_intro_circ->introduce2_bucket, 1);
}
if (token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0) {
goto allow;
}
disallow:
intro2_rejected_count++;
return false;
allow:
return true;
}
uint64_t
hs_dos_get_intro2_rejected_count(void)
{
return intro2_rejected_count;
}
void
hs_dos_init(void)
{
set_consensus_parameters(NULL);
}