EndGame/tor-patch/minwork.patch
2024-07-08 14:09:12 -06:00

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_);