Loading src/core/or/circuituse.c +15 −2 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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); Loading @@ -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; Loading @@ -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 Loading Loading @@ -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)) Loading src/core/or/circuituse.h +6 −0 Original line number Diff line number Diff line Loading @@ -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); Loading src/core/or/conflux_pool.c +131 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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 Loading
src/core/or/circuituse.c +15 −2 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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); Loading @@ -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; Loading @@ -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 Loading Loading @@ -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)) Loading
src/core/or/circuituse.h +6 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
src/core/or/conflux_pool.c +131 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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