9#define TOR_CONFLUX_PRIVATE
10#define CONFLUX_CELL_PRIVATE
23#include "trunnel/conflux.h"
32#include "core/or/or_circuit_st.h"
46static bool shutting_down =
false;
81 uint64_t link_sent_usec;
96 bool is_for_linked_set;
109 ERR_LINK_CIRC_OK = 0,
111 ERR_LINK_CIRC_BAD_RTT = 1,
113 ERR_LINK_CIRC_MISSING_LEG = 2,
115 ERR_LINK_CIRC_MISSING_SET = 3,
117 ERR_LINK_CIRC_INVALID_LEG = 4,
122get_unlinked_pool(
bool is_client)
128get_linked_pool(
bool is_client)
136STATIC uint8_t DEFAULT_CLIENT_UX = CONFLUX_UX_HIGH_THROUGHPUT;
137STATIC uint8_t DEFAULT_EXIT_UX = CONFLUX_UX_MIN_LATENCY;
140static inline const char *
143 return hex_str((
char *) nonce, 8);
152 switch (desired_ux) {
153 case CONFLUX_UX_NO_OPINION:
154 return CONFLUX_ALG_LOWRTT;
155 case CONFLUX_UX_MIN_LATENCY:
156 return CONFLUX_ALG_MINRTT;
157 case CONFLUX_UX_HIGH_THROUGHPUT:
158 return CONFLUX_ALG_LOWRTT;
162 case CONFLUX_UX_LOW_MEM_THROUGHPUT:
163 case CONFLUX_UX_LOW_MEM_LATENCY:
164 return CONFLUX_ALG_MINRTT;
168 return CONFLUX_ALG_LOWRTT;
176 conflux_t *cfx = tor_malloc_zero(
sizeof(*cfx));
196 } SMARTLIST_FOREACH_END(leg);
197 smartlist_free(cfx->
legs);
200 smartlist_free(cfx->
ooo_q);
207#define conflux_free(cfx) \
208 FREE_AND_NULL(conflux_t, conflux_free_, cfx)
223 leg_t *leg = tor_malloc_zero(
sizeof(*leg));
252 unlinked->is_client = is_client;
253 memcpy(unlinked->cfx->
nonce, nonce,
sizeof(unlinked->cfx->
nonce));
268 if (!unlinked->is_for_linked_set) {
272 smartlist_free(unlinked->legs);
374 if (leg->circ == circ) {
377 } SMARTLIST_FOREACH_END(leg);
401 if (leg->circ == circ) {
406 } SMARTLIST_FOREACH_END(leg);
422 "Unlinked Conflux circuit %u has attached streams.",
428 "Unlinked conflux circ %u has half streams.",
436 "Unlinked conflux circuit has attached streams.");
441 "Unlinked conflux circuit has resolving streams.");
454 uint8_t *nonce = NULL;
460 nonce = leg->link->nonce;
461 version = leg->link->version;
464 valid &= (leg->link->version == version &&
465 tor_memeq(leg->link->nonce, nonce,
sizeof(leg->link->nonce)));
472 "Data loss detected while trying to add a conflux leg.");
482 } SMARTLIST_FOREACH_END(leg);
501 cleg->
circ = leg->circ;
559 bool full_teardown =
false;
574 full_teardown =
true;
575 log_info(
LD_CIRC,
"Conflux current circuit has closed with "
576 "data in flight, tearing down entire set.");
589 full_teardown =
true;
590 log_info(
LD_CIRC,
"Conflux sequence number check failed, "
591 "tearing down entire set.");
598 full_teardown =
true;
599 log_info(
LD_CIRC,
"Conflux current circuit has closed, "
600 "tearing down entire set.");
609 return full_teardown;
621 if (smartlist_len(unlinked->legs) == 0) {
641 circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
643 } SMARTLIST_FOREACH_END(circ);
646 smartlist_free(circ_to_close);
665 if (smartlist_len(unlinked->legs) > 0) {
708 circuit_mark_for_close(circ, reason));
711 smartlist_free(circ_to_close);
739 if (BUG(smartlist_len(unlinked->legs) == 0)) {
740 err = ERR_LINK_CIRC_MISSING_LEG;
745 if (smartlist_len(unlinked->legs) +
748 "Conflux set has too many legs to link. "
749 "Rejecting this circuit.");
750 conflux_log_set(LOG_PROTOCOL_WARN, unlinked->cfx, unlinked->is_client);
751 err = ERR_LINK_CIRC_INVALID_LEG;
760 "Conflux unlinked set legs are not validating. Tearing it down.");
762 END_CIRC_REASON_TORPROTOCOL);
763 err = ERR_LINK_CIRC_INVALID_LEG;
772 log_info(
LD_CIRC,
"Can't finalize conflux set, still waiting on at "
773 "least one leg to link up.");
777 } SMARTLIST_FOREACH_END(leg);
789 leg->circ->conflux = unlinked->cfx;
793 } SMARTLIST_FOREACH_END(leg);
795 is_client = unlinked->is_client;
811 unlinked->cfx = NULL;
815 "Successfully linked a conflux %s set which is now usable.",
816 is_client ?
"client" :
"relay");
835 if (BUG(!leg || leg->link_sent_usec == 0)) {
837 "Conflux: Trying to record client RTT without a timestamp");
842 tor_assert_nonfatal(now >= leg->link_sent_usec);
843 leg->rtt_usec = now - leg->link_sent_usec;
844 if (leg->rtt_usec == 0) {
845 log_warn(
LD_CIRC,
"Clock appears stalled for conflux.");
851 return leg->rtt_usec;
856 leg->rtt_usec = UINT64_MAX;
876 "Conflux: Trying to record exit RTT without a timestamp");
885 log_warn(
LD_CIRC,
"Clock appears stalled for conflux.");
910 if (rtt_usec == UINT64_MAX)
914 log_info(
LD_CIRC,
"Conflux leg RTT is above circuit build time out "
915 "currently at %f msec. Relaunching.",
937 bool is_client =
false;
946 if (BUG(!unlinked)) {
947 log_warn(
LD_BUG,
"Failed to find the unlinked set %s when linking. "
950 err = ERR_LINK_CIRC_MISSING_SET;
958 log_warn(
LD_BUG,
"Failed to find leg for the unlinked set %s when "
959 "linking. Closing circuit.",
961 err = ERR_LINK_CIRC_MISSING_LEG;
986 for (
int i = 0; i < num_legs; i++) {
1001unlinked_get_or_create(
const uint8_t *nonce,
bool is_client)
1017 unlinked->cfx = cfx;
1018 unlinked->is_for_linked_set =
true;
1058 if (smartlist_len(unlinked->legs) > 0) {
1060 leg_t *leg = smartlist_get(unlinked->legs, 0);
1079#ifdef TOR_UNIT_TESTS
1080 return DEFAULT_CLIENT_UX;
1084 (void)DEFAULT_CLIENT_UX;
1087 return opt->ConfluxClientUX;
1102 unsigned int max_num_launch =
1108 log_info(
LD_CIRC,
"Maximum number of leg launch reached for nonce %s",
1139 unlinked = unlinked_get_or_create(nonce,
true);
1151 log_info(
LD_CIRC,
"Launching conflux leg for nonce %s.",
fmt_nonce(nonce));
1153 log_info(
LD_CIRC,
"Launching new conflux set for nonce %s.",
1187 conflux_cell_new_link(nonce,
1188 last_seq_sent, last_seq_recv,
1215 if (!CIRCUIT_IS_CONFLUX(circ)) {
1244 } CONFLUX_FOR_EACH_LEG_END(leg);
1259 } SMARTLIST_FOREACH_END(leg);
1283 if (!CIRCUIT_IS_CONFLUX(circ)) {
1306 } CONFLUX_FOR_EACH_LEG_END(leg);
1323 } SMARTLIST_FOREACH_END(leg);
1335 if (BUG(!leg->
circ)) {
1336 log_warn(
LD_BUG,
"Client conflux linked set leg without a circuit");
1342 if (!CONST_TO_ORIGIN_CIRCUIT(leg->
circ)->unusable_for_new_conns &&
1347 } DIGEST256MAP_FOREACH_END;
1364 if (!conflux_is_enabled(NULL) ||
1380 int num_set = num_unlinked + num_linked;
1383 if (num_set >= max_prebuilt) {
1387 log_info(
LD_CIRC,
"Preemptively launching new conflux circuit set(s). "
1388 "We have %d linked and %d unlinked.",
1389 num_linked, num_unlinked);
1391 for (
int i = 0; i < (max_prebuilt - num_set); i++) {
1416 if (BUG(leg->
circ->
purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED)) {
1427 CIRCUIT_PURPOSE_CONFLUX_LINKED,
1435 } DIGEST256MAP_FOREACH_END;
1448 bool is_client =
false;
1470 log_info(
LD_CIRC,
"Conflux unlinked circuit with nonce %s has closed",
1474 unlinked_leg_del_and_free(unlinked, circ);
1478 if (smartlist_len(unlinked->legs) == 0) {
1480 }
else if (!shutting_down) {
1502 tor_assert_nonfatal(circ->
conflux);
1506 tor_assert_nonfatal(circ->
purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED);
1511 stream->on_circuit = circ;
1512 stream->cpath_layer = ocirc->
cpath->
prev;
1520 stream->on_circuit = circ;
1526 stream->on_circuit = circ;
1553 bool is_client =
false;
1554 bool full_teardown =
false;
1561 tor_assert_nonfatal(circ->
purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED);
1604 if (full_teardown) {
1633 if (BUG(!shutting_down)) {
1635 "Conflux circuit %p being freed without being marked for "
1636 "full teardown via close, with shutdown state %d. "
1637 "Please report this.", circ, shutting_down);
1666 unlinked->is_for_linked_set =
false;
1726 if (!conflux_is_enabled(circ)) {
1727 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1728 static ratelim_t conflux_ratelim = RATELIM_INIT(600);
1730 "Conflux circuit opened without negotiating "
1731 "congestion control");
1740 log_info(
LD_CIRC,
"Conflux circuit has opened with nonce %s",
1745 log_warn(
LD_CIRC,
"Unable to find conflux leg in unlinked set.");
1751 if (!conflux_cell_send_link(leg->link, orig_circ)) {
1767 const uint16_t cell_len)
1775 if (!conflux_is_enabled(circ)) {
1776 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1784 "Got a CONFLUX_LINK cell on an origin circuit. Closing circuit.");
1785 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1791 "Got a CONFLUX_LINK with further hops. Closing circuit.");
1792 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1798 "Got a CONFLUX_LINK on a circuit with a pending nonce. "
1799 "Closing circuit.");
1800 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1806 "Got a CONFLUX_LINK on an already linked circuit "
1807 "Closing circuit.");
1808 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1813 link = conflux_cell_parse_link(cell, cell_len);
1816 "CONFLUX_LINK cell. Closing circuit.");
1817 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1821 log_info(
LD_CIRC,
"Processing a CONFLUX_LINK for set %s",
1827 unlinked = unlinked_get_or_create(link->nonce,
false);
1835 sizeof(leg->link->nonce));
1859 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1879 const uint16_t cell_len)
1903 if (!conflux_is_enabled(circ)) {
1904 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1912 "Received CONFLUX_LINKED cell on a non origin circuit.");
1918 "Received a CONFLUX_LINKED cell without having sent a "
1919 "CONFLUX_LINK cell. Closing circuit.");
1925 "Received a CONFLUX_LINKED cell on a circuit that is already "
1926 "linked. Closing circuit.");
1932 "Got a CONFLUX_LINKED from wrong hop on circuit. Closing circuit.");
1939 link = conflux_cell_parse_link(cell, cell_len);
1944 log_info(
LD_CIRC,
"Processing a CONFLUX_LINKED for set %s",
1950 sizeof(*link->nonce))) {
1952 "Received CONFLUX_LINKED but circuit nonce doesn't match "
1953 "cell nonce. Closing circuit.");
1960 log_warn(
LD_CIRC,
"Received CONFLUX_LINKED but can't find "
1961 "associated leg. Closing circuit.");
1965 log_info(
LD_CIRC,
"Successfully processed a CONFLUX_LINKED cell.");
1983 case ERR_LINK_CIRC_OK:
1986 case ERR_LINK_CIRC_INVALID_LEG:
1987 case ERR_LINK_CIRC_MISSING_SET:
1991 case ERR_LINK_CIRC_BAD_RTT:
1992 case ERR_LINK_CIRC_MISSING_LEG:
2016 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
2028 if (!conflux_is_enabled(circ)) {
2034 "Received CONFLUX_LINKED_ACK cell on an origin circuit. Closing.");
2040 "Got a CONFLUX_LINKED_ACK with further hops. Closing circuit.");
2046 "Received a CONFLUX_LINKED_ACK cell on a circuit that is not"
2047 "linked. Closing circuit.");
2051 log_info(
LD_CIRC,
"Processing a CONFLUX_LINKED_ACK for set %s",
2062 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
2120 "Conflux %s: %d linked, %d launched. Delivered: %"PRIu64
"; "
2121 "teardown: %d; Current: %p, Previous: %p",
2132 " - Linked Leg %d purpose=%d; RTT %"PRIu64
", sent: %"PRIu64
2133 "; sent: %"PRIu64
", recv: %"PRIu64
", infl: %"PRIu64
", "
2134 "ptr: %p, idx: %d, marked: %d",
2135 legs, leg->circ->purpose, leg->circ_rtts_usec,
2136 leg->linked_sent_usec, leg->last_seq_recv,
2137 leg->last_seq_sent, cc->
inflight, leg->circ,
2138 leg->circ->global_circuitlist_idx,
2139 leg->circ->marked_for_close);
2141 } CONFLUX_FOR_EACH_LEG_END(leg);
2147 log_fn(loglevel,
LD_BUG,
" - Unlinked set: %d legs, for link: %d",
2148 smartlist_len(unlinked->legs), unlinked->is_for_linked_set);
2152 " Unlinked Leg: %d purpose=%d; linked: %d, RTT %"PRIu64
", "
2153 "sent: %"PRIu64
" link ptr %p, circ ptr: %p, idx: %d, marked: %d",
2154 legs, leg->circ->purpose, leg->linked,
2155 leg->rtt_usec, leg->link_sent_usec,
2156 leg->link, leg->circ,
2157 leg->circ->global_circuitlist_idx,
2158 leg->circ->marked_for_close);
2160 } SMARTLIST_FOREACH_END(leg);
2174 shutting_down =
true;
2177#ifdef TOR_UNIT_TESTS
2182conflux_clear_shutdown(
void)
2184 shutting_down =
false;
const char * hex_str(const char *from, size_t fromlen)
bool conflux_can_exclude_used_bridges(void)
Header file for circuitbuild.c.
origin_circuit_t * circuit_establish_circuit_conflux(const uint8_t *conflux_nonce, uint8_t purpose, extend_info_t *exit_ei, int flags)
Header file for circuitbuild.c.
origin_circuit_t * TO_ORIGIN_CIRCUIT(circuit_t *x)
or_circuit_t * TO_OR_CIRCUIT(circuit_t *x)
Header file for circuitlist.c.
#define CIRCUIT_IS_ORCIRC(c)
#define CIRCUIT_IS_ORIGIN(c)
#define CIRCUIT_PURPOSE_CONFLUX_UNLINKED
double get_circuit_build_timeout_ms(void)
Header file for circuitstats.c.
void circuit_read_valid_data(origin_circuit_t *circ, uint16_t relay_body_len)
void circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
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)
Header file for circuituse.c.
#define CIRCLAUNCH_NEED_CAPACITY
#define CIRCLAUNCH_NEED_UPTIME
#define CIRCLAUNCH_NEED_CONFLUX
uint64_t monotime_absolute_usec(void)
const or_options_t * get_options(void)
Header file for config.c.
const congestion_control_t * circuit_ccontrol(const circuit_t *circ)
uint64_t conflux_get_max_seq_recv(const conflux_t *cfx)
uint64_t conflux_get_max_seq_sent(const conflux_t *cfx)
conflux_leg_t * conflux_get_leg(conflux_t *cfx, const circuit_t *circ)
Public APIs for conflux multipath support.
#define CONFLUX_FOR_EACH_LEG_BEGIN(cfx, var)
#define CONFLUX_NUM_LEGS(cfx)
Header file for conflux_cell.c.
Header file for conflux_params.c.
uint8_t conflux_params_get_max_legs_set(void)
uint8_t conflux_params_get_max_prebuilt(void)
uint8_t conflux_params_get_max_unlinked_leg_retry(void)
uint8_t conflux_params_get_num_legs_set(void)
uint8_t conflux_params_get_max_linked_set(void)
static void unlinked_pool_del(unlinked_circuits_t *unlinked, bool is_client)
static const char * fmt_nonce(const uint8_t *nonce)
static link_circ_err_t link_circuit(circuit_t *circ)
static unlinked_circuits_t * unlinked_pool_get(const uint8_t *nonce, bool is_client)
static leg_t * leg_find(const unlinked_circuits_t *unlinked, const circuit_t *circ)
static void linked_circuit_closed(circuit_t *circ)
void conflux_circuit_has_opened(origin_circuit_t *orig_circ)
void conflux_process_linked_ack(circuit_t *circ)
static void unlinked_close_all_legs(unlinked_circuits_t *unlinked)
static void leg_free(leg_t *leg)
#define conflux_free(cfx)
static bool cfx_del_leg(conflux_t *cfx, const circuit_t *circ)
void conflux_log_set(int loglevel, const conflux_t *cfx, bool is_client)
void conflux_circuit_has_closed(circuit_t *circ)
static void linked_circuit_free(circuit_t *circ, bool is_client)
static void free_conflux_void_(void *ptr)
static void cfx_add_leg(conflux_t *cfx, leg_t *leg)
static extend_info_t * get_exit_for_nonce(const uint8_t *nonce)
void conflux_process_linked(circuit_t *circ, crypt_path_t *layer_hint, const cell_t *cell, const uint16_t cell_len)
static uint64_t record_rtt_client(const circuit_t *circ)
STATIC bool launch_new_set(int num_legs)
static bool validate_unlinked_legs(unlinked_circuits_t *unlinked)
static bool record_rtt(const circuit_t *circ, bool is_client)
void conflux_process_link(circuit_t *circ, const cell_t *cell, const uint16_t cell_len)
static leg_t * leg_new(circuit_t *circ, conflux_cell_link_t *link)
void conflux_predict_new(time_t now)
static void linked_nullify_streams(circuit_t *circ)
static bool launch_leg_is_allowed(const conflux_t *cfx)
static digest256map_t * server_unlinked_pool
void conflux_notify_shutdown(void)
static uint8_t conflux_choose_algorithm(uint8_t desired_ux)
static void linked_pool_del(const uint8_t *nonce, bool is_client)
static link_circ_err_t try_finalize_set(unlinked_circuits_t *unlinked)
static void unlinked_pool_add(unlinked_circuits_t *unlinked, bool is_client)
static digest256map_t * client_linked_pool
static void linked_update_stream_backpointers(circuit_t *circ)
static void unlinked_pool_del_and_free(unlinked_circuits_t *unlinked, bool is_client)
void conflux_pool_init(void)
static void unlinked_circuit_free(circuit_t *circ, bool is_client)
static void conflux_mark_all_for_close(const uint8_t *nonce, bool is_client, int reason)
static conflux_t * linked_pool_get(const uint8_t *nonce, bool is_client)
void conflux_add_middles_to_exclude_list(const origin_circuit_t *orig_circ, smartlist_t *excluded)
static void unlinked_close_or_free(unlinked_circuits_t *unlinked)
void conflux_circuit_about_to_free(circuit_t *circ)
static unlinked_circuits_t * unlinked_new(const uint8_t *nonce, bool is_client)
static uint64_t record_rtt_exit(const circuit_t *circ)
static void free_unlinked_void_(void *ptr)
static digest256map_t * client_unlinked_pool
static digest256map_t * server_linked_pool
static void linked_pool_add(conflux_t *cfx, bool is_client)
bool conflux_launch_leg(const uint8_t *nonce)
static void unlinked_leg_add(unlinked_circuits_t *unlinked, leg_t *leg)
static int count_client_usable_sets(void)
static void unlinked_free(unlinked_circuits_t *unlinked)
void conflux_pool_free_all(void)
void conflux_add_guards_to_exclude_list(const origin_circuit_t *orig_circ, smartlist_t *excluded)
origin_circuit_t * conflux_get_circ_for_conn(const entry_connection_t *conn, time_t now)
static conflux_t * conflux_new(void)
static void validate_circ_has_no_streams(circuit_t *circ)
static uint8_t get_client_ux(void)
static void unlinked_circuit_closed(circuit_t *circ)
static leg_t * unlinked_leg_find(const circuit_t *circ, bool is_client)
Header file for conflux_pool.c.
Structure definitions for conflux multipath.
void conflux_validate_stream_lists(const conflux_t *cfx)
bool conflux_validate_source_hop(circuit_t *in_circ, crypt_path_t *layer_hint)
void conflux_sync_circ_fields(conflux_t *cfx, origin_circuit_t *ref_circ)
Header file for conflux_util.c.
Structure definitions for congestion control.
void connection_ap_attach_pending(int retry)
Header file for connection_edge.c.
Path structures for origin circuits.
void crypto_rand(char *to, size_t n)
Common functions for using (pseudo-)random number generators.
void memwipe(void *mem, uint8_t byte, size_t sz)
Common functions for cryptographic routines.
int tor_memeq(const void *a, const void *b, size_t sz)
#define tor_memneq(a, b, sz)
Edge-connection structure.
#define log_fn(severity, domain, args,...)
#define log_fn_ratelim(ratelim, severity, domain, args,...)
consensus_path_type_t router_have_consensus_path(void)
node_t * node_get_mutable_by_id(const char *identity_digest)
Header file for nodelist.c.
Master header file for Tor-specific functionality.
Origin circuit structure.
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
void smartlist_remove(smartlist_t *sl, const void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
#define SMARTLIST_DEL_CURRENT(sl, var)
uint16_t marked_for_close
struct conflux_t * conflux
uint8_t * conflux_pending_nonce
uint64_t linked_sent_usec
struct conflux_leg_t * curr_leg
struct conflux_params_t params
struct conflux_leg_t * prev_leg
uint8_t nonce[DIGEST256_LEN]
uint64_t last_seq_delivered
unsigned int num_leg_launch
struct crypt_path_t * prev
struct crypt_path_t * next
extend_info_t * extend_info
struct edge_connection_t * next_stream
char identity_digest[DIGEST_LEN]
edge_connection_t * resolving_streams
edge_connection_t * n_streams
uint32_t global_identifier
edge_connection_t * p_streams
unsigned int isolation_values_set
smartlist_t * half_streams
#define tor_assert_nonfatal_unreached()