entirely when the service is not overloaded.
(Default: 0)
+[[HiddenServicePoWQueueRate]] **HiddenServicePoWQueueRate** __NUM__::
+
+ The sustained rate of rendezvous requests to dispatch per second from
+ the priority queue. Has no effect when proof-of-work is disabled.
+ If this is set to 0 there's no explicit limit and we will process
+ requests as quickly as possible.
+ (Default: 250)
+
+[[HiddenServicePoWQueueBurst]] **HiddenServicePoWQueueBurst** __NUM__::
+
+ The maximum burst size for rendezvous requests handled from the
+ priority queue at once. (Default: 2500)
+
== DIRECTORY AUTHORITY SERVER OPTIONS
VAR("HiddenServiceOnionBalanceInstance",
LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServicePoWDefensesEnabled", LINELIST_S, RendConfigLines, NULL),
+ VAR("HiddenServicePoWQueueRate", LINELIST_S, RendConfigLines, NULL),
+ VAR("HiddenServicePoWQueueBurst", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceStatistics", BOOL, HiddenServiceStatistics_option, "1"),
V(ClientOnionAuthDir, FILENAME, NULL),
OBSOLETE("CloseHSClientCircuitsImmediatelyOnTimeout"),
return; /* done here! no cleanup needed. */
}
+ if (pow_state->using_pqueue_bucket) {
+ token_bucket_ctr_refill(&pow_state->pqueue_bucket,
+ (uint32_t) approx_time());
+
+ if (token_bucket_ctr_get(&pow_state->pqueue_bucket) > 0) {
+ token_bucket_ctr_dec(&pow_state->pqueue_bucket, 1);
+ } else {
+ /* Waiting for pqueue rate limit to refill, come back later */
+ const struct timeval delay_tv = { 0, 100000 };
+ mainloop_event_schedule(pow_state->pop_pqueue_ev, &delay_tv);
+ return;
+ }
+ }
+
/* Pop next request by effort. */
pending_rend_t *req =
smartlist_pqueue_pop(pow_state->rend_request_pqueue,
++pow_state->rend_handled;
++in_flight;
+ if (pow_state->using_pqueue_bucket &&
+ token_bucket_ctr_get(&pow_state->pqueue_bucket) < 1) {
+ break;
+ }
+
if (++count == MAX_REND_REQUEST_PER_MAINLOOP) {
break;
}
config->intro_dos_burst_per_sec, config->intro_dos_rate_per_sec);
goto invalid;
}
+ if (config->has_pow_defenses_enabled &&
+ (config->pow_queue_burst < config->pow_queue_rate)) {
+ log_warn(LD_CONFIG, "Hidden service PoW queue burst (%" PRIu32 ") can "
+ "not be smaller than the rate value (%" PRIu32 ").",
+ config->pow_queue_burst, config->pow_queue_rate);
+ goto invalid;
+ }
/* Valid. */
return 0;
/* Are the PoW anti-DoS defenses enabled? */
config->has_pow_defenses_enabled = hs_opts->HiddenServicePoWDefensesEnabled;
- log_info(LD_REND, "Service PoW defenses are %s.",
+ config->pow_queue_rate = hs_opts->HiddenServicePoWQueueRate;
+ config->pow_queue_burst = hs_opts->HiddenServicePoWQueueBurst;
+
+ log_info(LD_REND, "Service PoW defenses are %s",
config->has_pow_defenses_enabled ? "enabled" : "disabled");
+ if (config->has_pow_defenses_enabled) {
+ log_info(LD_REND, "Service PoW queue rate set to: %" PRIu32,
+ config->pow_queue_rate);
+ log_info(LD_REND, "Service PoW queue burst set to: %" PRIu32,
+ config->pow_queue_burst);
+ }
/* We do not load the key material for the service at this stage. This is
* done later once tor can confirm that it is in a running state. */
CONF_VAR(HiddenServiceEnableIntroDoSBurstPerSec, POSINT, 0, "200")
CONF_VAR(HiddenServiceOnionBalanceInstance, BOOL, 0, "0")
CONF_VAR(HiddenServicePoWDefensesEnabled, BOOL, 0, "0")
+CONF_VAR(HiddenServicePoWQueueRate, POSINT, 0, "250")
+CONF_VAR(HiddenServicePoWQueueBurst, POSINT, 0, "2500")
END_CONF_STRUCT(hs_opts_t)
#include "ext/equix/include/equix.h"
#include "lib/evloop/compat_libevent.h"
+#include "lib/evloop/token_bucket.h"
#include "lib/smartlist_core/smartlist_core.h"
#define HS_POW_SUGGESTED_EFFORT_DEFAULT 20 // HRPR TODO 5000
* the service's priority queue; higher effort is higher priority. */
mainloop_event_t *pop_pqueue_ev;
+ /* Token bucket for rate limiting the priority queue */
+ token_bucket_ctr_t pqueue_bucket;
+
/* The current seed being used in the PoW defenses. */
uint8_t seed_current[HS_POW_SEED_LEN];
time_t next_effort_update;
/* Sum of effort of all valid requests received since the last update. */
uint64_t total_effort;
+
/* Did we have elements waiting in the queue during this period? */
bool had_queue;
+ /* Are we using pqueue_bucket to rate limit the pqueue? */
+ bool using_pqueue_bucket;
+
} hs_pow_service_state_t;
/* Struct to store a solution to the PoW challenge. */
pow_state->rend_request_pqueue = smartlist_new();
pow_state->pop_pqueue_ev = NULL;
+ if (service->config.pow_queue_rate > 0 &&
+ service->config.pow_queue_burst >= service->config.pow_queue_rate) {
+ pow_state->using_pqueue_bucket = 1;
+ token_bucket_ctr_init(&pow_state->pqueue_bucket,
+ service->config.pow_queue_rate,
+ service->config.pow_queue_burst,
+ (uint32_t) approx_time());
+ }
+
pow_state->min_effort = service->config.pow_min_effort;
/* We recalculate and update the suggested effort every HS_UPDATE_PERIOD
/** True iff PoW anti-DoS defenses are enabled. */
unsigned int has_pow_defenses_enabled : 1;
uint32_t pow_min_effort;
+ uint32_t pow_queue_rate;
+ uint32_t pow_queue_burst;
/** If set, contains the Onion Balance master ed25519 public key (taken from
* an .onion addresses) that this tor instance serves as backend. */