238 lines
10 KiB
Diff
238 lines
10 KiB
Diff
diff --git a/doc/man/tor.1.txt b/doc/man/tor.1.txt
|
|
index 1589809b1a..71178e65c9 100644
|
|
--- a/doc/man/tor.1.txt
|
|
+++ b/doc/man/tor.1.txt
|
|
@@ -3121,6 +3121,15 @@ The following options are per onion service:
|
|
|
|
These options are applicable to both onion services and their clients:
|
|
|
|
+[[HiddenServicePoWEffort]] **HiddenServicePoWEffort** __NUM__::
|
|
+
|
|
+ The minimum required proof-of-work effort level needed to reach the given
|
|
+ Hidden Service. When this option is set to an integer larger than -1, the
|
|
+ service will no longer automatically increase its effort level, but will always
|
|
+ use the specified effort level as its effort. If this option is set to -1 (the
|
|
+ default), Tor will automatically tune the effort level to an appropriate value.
|
|
+ (Default: -1)
|
|
+
|
|
[[CompiledProofOfWorkHash]] **CompiledProofOfWorkHash** **0**|**1**|**auto**::
|
|
When proof-of-work DoS mitigation is active, both the services themselves
|
|
and the clients which connect will use a dynamically generated hash
|
|
diff --git a/src/app/config/config.c b/src/app/config/config.c
|
|
index a10329c552..1cacae4454 100644
|
|
--- a/src/app/config/config.c
|
|
+++ b/src/app/config/config.c
|
|
@@ -517,6 +517,7 @@ static const config_var_t option_vars_[] = {
|
|
VAR("HiddenServicePoWDefensesEnabled", LINELIST_S, RendConfigLines, NULL),
|
|
VAR("HiddenServicePoWQueueRate", LINELIST_S, RendConfigLines, NULL),
|
|
VAR("HiddenServicePoWQueueBurst", LINELIST_S, RendConfigLines, NULL),
|
|
+ VAR("HiddenServicePoWEffort", LINELIST_S, RendConfigLines, NULL),
|
|
VAR("HiddenServiceStatistics", BOOL, HiddenServiceStatistics_option, "1"),
|
|
V(ClientOnionAuthDir, FILENAME, NULL),
|
|
OBSOLETE("CloseHSClientCircuitsImmediatelyOnTimeout"),
|
|
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
|
|
index f21779a80c..2230162fd3 100644
|
|
--- a/src/core/or/connection_edge.c
|
|
+++ b/src/core/or/connection_edge.c
|
|
@@ -983,8 +983,9 @@ export_hs_client_circuit_id(edge_connection_t *edge_conn,
|
|
|
|
char *buf = NULL;
|
|
const char dst_ipv6[] = "::1";
|
|
+
|
|
/* See RFC4193 regarding fc00::/7 */
|
|
- const char src_ipv6_prefix[] = "fc00:dead:beef:4dad:";
|
|
+ const char src_ipv6_prefix[] = "fc00:dead:beef:4dad";
|
|
uint16_t dst_port = 0;
|
|
uint16_t src_port = 1; /* default value */
|
|
uint32_t gid = 0; /* default value */
|
|
@@ -1000,9 +1001,24 @@ export_hs_client_circuit_id(edge_connection_t *edge_conn,
|
|
dst_port = edge_conn->hs_ident->orig_virtual_port;
|
|
}
|
|
|
|
+ /* Include PoW effort (if any?) in the proxy string. */
|
|
+ uint16_t pow_effort_low = 0;
|
|
+ uint16_t pow_effort_high = 0;
|
|
+
|
|
+ if (edge_conn->on_circuit) {
|
|
+ origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(edge_conn->on_circuit);
|
|
+
|
|
+ if (circ) {
|
|
+ const uint32_t effort = circ->hs_pow_effort;
|
|
+ pow_effort_low = effort & 0x0000ffff;
|
|
+ pow_effort_high = effort >> 16;
|
|
+ }
|
|
+ }
|
|
+
|
|
/* Build the string */
|
|
- tor_asprintf(&buf, "PROXY TCP6 %s:%x:%x %s %d %d\r\n",
|
|
+ tor_asprintf(&buf, "PROXY TCP6 %s:%x:%x:%x:%x %s %d %d\r\n",
|
|
src_ipv6_prefix,
|
|
+ pow_effort_high, pow_effort_low,
|
|
gid >> 16, gid & 0x0000ffff,
|
|
dst_ipv6, src_port, dst_port);
|
|
|
|
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
|
|
index 4904f3ddf9..0b0a9eeafd 100644
|
|
--- a/src/feature/hs/hs_circuit.c
|
|
+++ b/src/feature/hs/hs_circuit.c
|
|
@@ -830,6 +830,19 @@ handle_rend_pqueue_cb(mainloop_event_t *ev, void *arg)
|
|
continue; /* do not increment count, this one's free */
|
|
}
|
|
|
|
+ /* We check if the effort is above our min. manually set value, if any. */
|
|
+ const uint32_t min_effort = service->config.pow_effort;
|
|
+
|
|
+ if (! service->config.pow_effort_auto &&
|
|
+ req->rdv_data.pow_effort < min_effort) {
|
|
+ log_info(LD_REND,
|
|
+ "Top rend request didn't meet minimum required "
|
|
+ "manually specified effort level; discarding and "
|
|
+ "moving to the next one.");
|
|
+ free_pending_rend(req);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
/* Launch the rendezvous circuit. */
|
|
launch_rendezvous_point_circuit(service, &req->ip_auth_pubkey,
|
|
&req->ip_enc_key_kp, &req->rdv_data, now);
|
|
diff --git a/src/feature/hs/hs_config.c b/src/feature/hs/hs_config.c
|
|
index 296941138b..08627f96c0 100644
|
|
--- a/src/feature/hs/hs_config.c
|
|
+++ b/src/feature/hs/hs_config.c
|
|
@@ -409,6 +409,8 @@ config_service_v3(const hs_opts_t *hs_opts,
|
|
config->has_pow_defenses_enabled = hs_opts->HiddenServicePoWDefensesEnabled;
|
|
config->pow_queue_rate = hs_opts->HiddenServicePoWQueueRate;
|
|
config->pow_queue_burst = hs_opts->HiddenServicePoWQueueBurst;
|
|
+ config->pow_effort_auto = hs_opts->HiddenServicePoWEffort == -1;
|
|
+ config->pow_effort = hs_opts->HiddenServicePoWEffort;
|
|
|
|
log_info(LD_REND, "Service PoW defenses are %s",
|
|
config->has_pow_defenses_enabled ? "enabled" : "disabled");
|
|
@@ -417,6 +419,11 @@ config_service_v3(const hs_opts_t *hs_opts,
|
|
config->pow_queue_rate);
|
|
log_info(LD_REND, "Service PoW queue burst set to: %" PRIu32,
|
|
config->pow_queue_burst);
|
|
+
|
|
+ if (! config->pow_effort_auto) {
|
|
+ log_info(LD_REND, "Service PoW minimum effort manually set to: %" PRIu32,
|
|
+ config->pow_effort);
|
|
+ }
|
|
}
|
|
|
|
/* We do not load the key material for the service at this stage. This is
|
|
diff --git a/src/feature/hs/hs_options.inc b/src/feature/hs/hs_options.inc
|
|
index 4ec62d592b..4de1d9ad88 100644
|
|
--- a/src/feature/hs/hs_options.inc
|
|
+++ b/src/feature/hs/hs_options.inc
|
|
@@ -35,4 +35,7 @@ CONF_VAR(HiddenServicePoWDefensesEnabled, BOOL, 0, "0")
|
|
CONF_VAR(HiddenServicePoWQueueRate, POSINT, 0, "250")
|
|
CONF_VAR(HiddenServicePoWQueueBurst, POSINT, 0, "2500")
|
|
|
|
+// "-1" implies "automatic".
|
|
+CONF_VAR(HiddenServicePoWEffort, INT, 0, "-1")
|
|
+
|
|
END_CONF_STRUCT(hs_opts_t)
|
|
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
|
|
index 3cc8c23e0b..d0d34a5521 100644
|
|
--- a/src/feature/hs/hs_service.c
|
|
+++ b/src/feature/hs/hs_service.c
|
|
@@ -301,7 +301,8 @@ initialize_pow_defenses(hs_service_t *service)
|
|
|
|
/* We recalculate and update the suggested effort every HS_UPDATE_PERIOD
|
|
* seconds. */
|
|
- pow_state->suggested_effort = 0;
|
|
+ pow_state->suggested_effort = service->config.pow_effort;
|
|
+
|
|
pow_state->rend_handled = 0;
|
|
pow_state->total_effort = 0;
|
|
pow_state->next_effort_update = (time(NULL) + HS_UPDATE_PERIOD);
|
|
@@ -2704,6 +2705,13 @@ update_suggested_effort(hs_service_t *service, time_t now)
|
|
/* Make life easier */
|
|
hs_pow_service_state_t *pow_state = service->state.pow_state;
|
|
|
|
+ /* If the operator have manually specified the effort, we simply return that
|
|
+ * here. */
|
|
+ if (! service->config.pow_effort_auto) {
|
|
+ pow_state->suggested_effort = service->config.pow_effort;
|
|
+ return;
|
|
+ }
|
|
+
|
|
/* Calculate the new suggested effort, using an additive-increase
|
|
* multiplicative-decrease estimation scheme. */
|
|
enum {
|
|
diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h
|
|
index 36d67719ca..bf993bb0bb 100644
|
|
--- a/src/feature/hs/hs_service.h
|
|
+++ b/src/feature/hs/hs_service.h
|
|
@@ -271,6 +271,12 @@ typedef struct hs_service_config_t {
|
|
uint32_t pow_queue_rate;
|
|
uint32_t pow_queue_burst;
|
|
|
|
+ /** PoW effort is set manually or automatically by the service? */
|
|
+ bool pow_effort_auto;
|
|
+
|
|
+ /** PoW min. required effort if pow_effort_auto is false. */
|
|
+ uint32_t pow_effort;
|
|
+
|
|
/** If set, contains the Onion Balance master ed25519 public key (taken from
|
|
* an .onion addresses) that this tor instance serves as backend. */
|
|
smartlist_t *ob_master_pubkeys;
|
|
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
|
|
index dc60c7ca29..588e8c4228 100644
|
|
--- a/src/test/test_hs_service.c
|
|
+++ b/src/test/test_hs_service.c
|
|
@@ -2197,7 +2197,7 @@ test_export_client_circuit_id(void *arg)
|
|
/* Check contents */
|
|
cp1 = buf_get_contents(conn->outbuf, &sz);
|
|
tt_str_op(cp1, OP_EQ,
|
|
- "PROXY TCP6 fc00:dead:beef:4dad::0:29a ::1 666 42\r\n");
|
|
+ "PROXY TCP6 fc00:dead:beef:4dad:0:0:0:29a ::1 666 42\r\n");
|
|
|
|
/* Change circ GID and see that the reported circuit ID also changes */
|
|
or_circ->global_identifier = 22;
|
|
@@ -2214,7 +2214,7 @@ test_export_client_circuit_id(void *arg)
|
|
export_hs_client_circuit_id(edge_conn, service->config.circuit_id_protocol);
|
|
cp1 = buf_get_contents(conn->outbuf, &sz);
|
|
tt_str_op(cp1, OP_EQ,
|
|
- "PROXY TCP6 fc00:dead:beef:4dad::ffff:ffff ::1 65535 42\r\n");
|
|
+ "PROXY TCP6 fc00:dead:beef:4dad:0:0:ffff:ffff ::1 65535 42\r\n");
|
|
tor_free(cp1);
|
|
|
|
/* Check that GID with UINT16_MAX works. */
|
|
@@ -2223,7 +2223,7 @@ test_export_client_circuit_id(void *arg)
|
|
export_hs_client_circuit_id(edge_conn, service->config.circuit_id_protocol);
|
|
cp1 = buf_get_contents(conn->outbuf, &sz);
|
|
tt_str_op(cp1, OP_EQ,
|
|
- "PROXY TCP6 fc00:dead:beef:4dad::0:ffff ::1 65535 42\r\n");
|
|
+ "PROXY TCP6 fc00:dead:beef:4dad:0:0:0:ffff ::1 65535 42\r\n");
|
|
tor_free(cp1);
|
|
|
|
/* Check that GID with UINT16_MAX + 7 works. */
|
|
@@ -2231,7 +2231,25 @@ test_export_client_circuit_id(void *arg)
|
|
|
|
export_hs_client_circuit_id(edge_conn, service->config.circuit_id_protocol);
|
|
cp1 = buf_get_contents(conn->outbuf, &sz);
|
|
- tt_str_op(cp1, OP_EQ, "PROXY TCP6 fc00:dead:beef:4dad::1:6 ::1 6 42\r\n");
|
|
+ tt_str_op(cp1, OP_EQ, "PROXY TCP6 fc00:dead:beef:4dad:0:0:1:6 ::1 6 42\r\n");
|
|
+
|
|
+ /* Check that GID UINT32_MAX works and set a PoW effort. */
|
|
+ or_circ->global_identifier = UINT32_MAX;
|
|
+ or_circ->hs_pow_effort = 1337;
|
|
+
|
|
+ export_hs_client_circuit_id(edge_conn, service->config.circuit_id_protocol);
|
|
+ cp1 = buf_get_contents(conn->outbuf, &sz);
|
|
+ tt_str_op(cp1, OP_EQ,
|
|
+ "PROXY TCP6 fc00:dead:beef:4dad:0:539:ffff:ffff ::1 65535 42\r\n");
|
|
+
|
|
+ /* Check that GID UINT32_MAX works and set a PoW effort to UINT16_MAX + 7. */
|
|
+ or_circ->global_identifier = UINT32_MAX;
|
|
+ or_circ->hs_pow_effort = UINT16_MAX + 7;
|
|
+
|
|
+ export_hs_client_circuit_id(edge_conn, service->config.circuit_id_protocol);
|
|
+ cp1 = buf_get_contents(conn->outbuf, &sz);
|
|
+ tt_str_op(cp1, OP_EQ,
|
|
+ "PROXY TCP6 fc00:dead:beef:4dad:1:6:ffff:ffff ::1 65535 42\r\n");
|
|
|
|
done:
|
|
UNMOCK(connection_write_to_buf_impl_);
|