mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-22 22:25:51 +01:00
Prop#329 Pool: Handle pre-building and using conflux sets.
Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
parent
46e473f43e
commit
39c2927d6f
3 changed files with 152 additions and 2 deletions
|
@ -103,7 +103,7 @@ circuit_matches_with_rend_stream(const edge_connection_t *edge_conn,
|
|||
/** Return 1 if <b>circ</b> could be returned by circuit_get_best().
|
||||
* Else return 0.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
circuit_is_acceptable(const origin_circuit_t *origin_circ,
|
||||
const entry_connection_t *conn,
|
||||
int must_be_open, uint8_t purpose,
|
||||
|
@ -338,6 +338,7 @@ circuit_get_best(const entry_connection_t *conn,
|
|||
{
|
||||
origin_circuit_t *best=NULL;
|
||||
struct timeval now;
|
||||
time_t now_sec;
|
||||
|
||||
tor_assert(conn);
|
||||
|
||||
|
@ -349,6 +350,14 @@ circuit_get_best(const entry_connection_t *conn,
|
|||
purpose == CIRCUIT_PURPOSE_C_REND_JOINED);
|
||||
|
||||
tor_gettimeofday(&now);
|
||||
now_sec = now.tv_sec;
|
||||
|
||||
// Prefer pre-built conflux circuits here, if available but only for general
|
||||
// purposes. We don't have onion service conflux support at the moment.
|
||||
if (purpose == CIRCUIT_PURPOSE_C_GENERAL &&
|
||||
(best = conflux_get_circ_for_conn(conn, now_sec))) {
|
||||
return best;
|
||||
}
|
||||
|
||||
SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
|
||||
origin_circuit_t *origin_circ;
|
||||
|
@ -357,7 +366,7 @@ circuit_get_best(const entry_connection_t *conn,
|
|||
origin_circ = TO_ORIGIN_CIRCUIT(circ);
|
||||
|
||||
if (!circuit_is_acceptable(origin_circ,conn,must_be_open,purpose,
|
||||
need_uptime,need_internal, (time_t)now.tv_sec))
|
||||
need_uptime,need_internal, now_sec))
|
||||
continue;
|
||||
|
||||
/* now this is an acceptable circ to hand back. but that doesn't
|
||||
|
@ -1192,6 +1201,10 @@ circuit_predict_and_launch_new(void)
|
|||
time_t now = time(NULL);
|
||||
int flags = 0;
|
||||
|
||||
/* Attempt to launch predicted conflux circuits. This is outside the HS or
|
||||
* Exit preemptive circuit set. */
|
||||
conflux_predict_new(now);
|
||||
|
||||
/* Count how many of each type of circuit we currently have. */
|
||||
SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
|
||||
if (!circuit_is_available_for_use(circ))
|
||||
|
|
|
@ -79,6 +79,12 @@ bool circuit_purpose_is_hs_service(const uint8_t purpose);
|
|||
bool circuit_purpose_is_hs_vanguards(const uint8_t purpose);
|
||||
|
||||
bool circuit_is_hs_v3(const circuit_t *circ);
|
||||
int circuit_is_acceptable(const origin_circuit_t *origin_circ,
|
||||
const entry_connection_t *conn,
|
||||
int must_be_open, uint8_t purpose,
|
||||
int need_uptime, int need_internal,
|
||||
time_t now);
|
||||
|
||||
int circuit_should_use_vanguards(uint8_t);
|
||||
void circuit_sent_valid_data(origin_circuit_t *circ, uint16_t relay_body_len);
|
||||
void circuit_read_valid_data(origin_circuit_t *circ, uint16_t relay_body_len);
|
||||
|
|
|
@ -916,6 +916,32 @@ link_circuit(circuit_t *circ)
|
|||
return err;
|
||||
}
|
||||
|
||||
/** Launch a brand new set.
|
||||
*
|
||||
* Return true if all legs successfully launched or false if one failed. */
|
||||
STATIC bool
|
||||
launch_new_set(int num_legs)
|
||||
{
|
||||
uint8_t nonce[DIGEST256_LEN];
|
||||
|
||||
/* Brand new nonce for this set. */
|
||||
crypto_rand((char *) nonce, sizeof(nonce));
|
||||
|
||||
/* Launch all legs. */
|
||||
for (int i = 0; i < num_legs; i++) {
|
||||
if (!conflux_launch_leg(nonce)) {
|
||||
/* This function cleans up entirely the unlinked set if a leg is unable
|
||||
* to be launched. The recovery would be complex here. */
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
err:
|
||||
return false;
|
||||
}
|
||||
|
||||
static unlinked_circuits_t *
|
||||
unlinked_get_or_create(const uint8_t *nonce, bool is_client)
|
||||
{
|
||||
|
@ -1215,6 +1241,111 @@ conflux_add_middles_to_exclude_list(const origin_circuit_t *orig_circ,
|
|||
}
|
||||
}
|
||||
|
||||
/** Return the number of unused client linked set. */
|
||||
static int
|
||||
count_client_usable_sets(void)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
DIGEST256MAP_FOREACH(client_linked_pool, key, conflux_t *, cfx) {
|
||||
conflux_leg_t *leg = smartlist_get(cfx->legs, 0);
|
||||
if (BUG(!leg->circ)) {
|
||||
log_warn(LD_BUG, "Client conflux linked set leg without a circuit");
|
||||
continue;
|
||||
}
|
||||
if (!CONST_TO_ORIGIN_CIRCUIT(leg->circ)->unusable_for_new_conns) {
|
||||
count++;
|
||||
}
|
||||
} DIGEST256MAP_FOREACH_END;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/** Determine if we need to launch new conflux circuits for our preemptive
|
||||
* pool.
|
||||
*
|
||||
* This is called once a second from the mainloop from
|
||||
* circuit_predict_and_launch_new(). */
|
||||
void
|
||||
conflux_predict_new(time_t now)
|
||||
{
|
||||
(void) now;
|
||||
|
||||
if (!conflux_is_enabled(NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't attempt to build a new set if we are above our allowed maximum of
|
||||
* linked sets. */
|
||||
if (digest256map_size(client_linked_pool) >=
|
||||
conflux_params_get_max_linked_set()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Count the linked and unlinked to get the total number of sets we have
|
||||
* (will have). */
|
||||
int num_linked = count_client_usable_sets();
|
||||
int num_unlinked = digest256map_size(client_unlinked_pool);
|
||||
int num_set = num_unlinked + num_linked;
|
||||
int max_prebuilt = conflux_params_get_max_prebuilt();
|
||||
|
||||
if (num_set >= max_prebuilt) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_info(LD_CIRC, "Preemptively launching new conflux circuit set(s). "
|
||||
"We have %d linked and %d unlinked.",
|
||||
num_linked, num_unlinked);
|
||||
|
||||
for (int i = 0; i < (max_prebuilt - num_set); i++) {
|
||||
if (!launch_new_set(conflux_params_get_num_legs_set())) {
|
||||
/* Failing once likely means we'll fail next attempt so stop for now and
|
||||
* we'll try later. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the first circuit from the linked pool that will work with the conn.
|
||||
* If no such circuit exists, return NULL. */
|
||||
origin_circuit_t *
|
||||
conflux_get_circ_for_conn(const entry_connection_t *conn, time_t now)
|
||||
{
|
||||
/* Use conn to check the exit policy of the first circuit
|
||||
* of each set in the linked pool. */
|
||||
tor_assert(conn);
|
||||
|
||||
DIGEST256MAP_FOREACH(client_linked_pool, key, conflux_t *, cfx) {
|
||||
/* Get the first circuit of the set. */
|
||||
conflux_leg_t *leg = smartlist_get(cfx->legs, 0);
|
||||
tor_assert(leg);
|
||||
tor_assert(leg->circ);
|
||||
|
||||
/* Bug on these but we can recover. */
|
||||
if (BUG(leg->circ->purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED)) {
|
||||
continue;
|
||||
}
|
||||
if (BUG(!CIRCUIT_IS_ORIGIN(leg->circ))) {
|
||||
continue;
|
||||
}
|
||||
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(leg->circ);
|
||||
|
||||
/* Make sure the connection conforms with the exit policy and the isolation
|
||||
* flags also allows it. */
|
||||
if (!circuit_is_acceptable(ocirc, conn, 1 /* Must be open */,
|
||||
CIRCUIT_PURPOSE_CONFLUX_LINKED,
|
||||
1 /* Need uptime */,
|
||||
0 /* No need for internal */, now)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Found a circuit that works. */
|
||||
return ocirc;
|
||||
} DIGEST256MAP_FOREACH_END;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** The given circuit is conflux pending and has closed. This deletes the leg
|
||||
* from the set, attempt to finalize it and relaunch a new leg. If the set is
|
||||
* empty after removing this leg, it is deleted. */
|
||||
|
|
Loading…
Add table
Reference in a new issue