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 conflux_relay_msg_free(cell));
201 smartlist_free(cfx->
ooo_q);
208#define conflux_free(cfx) \
209 FREE_AND_NULL(conflux_t, conflux_free_, cfx)
224 leg_t *leg = tor_malloc_zero(
sizeof(*leg));
253 unlinked->is_client = is_client;
254 memcpy(unlinked->cfx->
nonce, nonce,
sizeof(unlinked->cfx->
nonce));
269 if (!unlinked->is_for_linked_set) {
273 smartlist_free(unlinked->legs);
375 if (leg->circ == circ) {
378 } SMARTLIST_FOREACH_END(leg);
402 if (leg->circ == circ) {
407 } SMARTLIST_FOREACH_END(leg);
423 "Unlinked Conflux circuit %u has attached streams.",
429 "Unlinked conflux circ %u has half streams.",
437 "Unlinked conflux circuit has attached streams.");
442 "Unlinked conflux circuit has resolving streams.");
455 uint8_t *nonce = NULL;
461 nonce = leg->link->nonce;
462 version = leg->link->version;
465 valid &= (leg->link->version == version &&
466 tor_memeq(leg->link->nonce, nonce,
sizeof(leg->link->nonce)));
473 "Data loss detected while trying to add a conflux leg.");
483 } SMARTLIST_FOREACH_END(leg);
502 cleg->
circ = leg->circ;
560 bool full_teardown =
false;
575 full_teardown =
true;
576 log_info(
LD_CIRC,
"Conflux current circuit has closed with "
577 "data in flight, tearing down entire set.");
590 full_teardown =
true;
591 log_info(
LD_CIRC,
"Conflux sequence number check failed, "
592 "tearing down entire set.");
599 full_teardown =
true;
600 log_info(
LD_CIRC,
"Conflux current circuit has closed, "
601 "tearing down entire set.");
610 return full_teardown;
622 if (smartlist_len(unlinked->legs) == 0) {
642 circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
644 } SMARTLIST_FOREACH_END(circ);
647 smartlist_free(circ_to_close);
666 if (smartlist_len(unlinked->legs) > 0) {
709 circuit_mark_for_close(circ, reason));
712 smartlist_free(circ_to_close);
740 if (BUG(smartlist_len(unlinked->legs) == 0)) {
741 err = ERR_LINK_CIRC_MISSING_LEG;
746 if (smartlist_len(unlinked->legs) +
749 "Conflux set has too many legs to link. "
750 "Rejecting this circuit.");
751 conflux_log_set(LOG_PROTOCOL_WARN, unlinked->cfx, unlinked->is_client);
752 err = ERR_LINK_CIRC_INVALID_LEG;
761 "Conflux unlinked set legs are not validating. Tearing it down.");
763 END_CIRC_REASON_TORPROTOCOL);
764 err = ERR_LINK_CIRC_INVALID_LEG;
773 log_info(
LD_CIRC,
"Can't finalize conflux set, still waiting on at "
774 "least one leg to link up.");
778 } SMARTLIST_FOREACH_END(leg);
790 leg->circ->conflux = unlinked->cfx;
794 } SMARTLIST_FOREACH_END(leg);
796 is_client = unlinked->is_client;
812 unlinked->cfx = NULL;
816 "Successfully linked a conflux %s set which is now usable.",
817 is_client ?
"client" :
"relay");
836 if (BUG(!leg || leg->link_sent_usec == 0)) {
838 "Conflux: Trying to record client RTT without a timestamp");
843 tor_assert_nonfatal(now >= leg->link_sent_usec);
844 leg->rtt_usec = now - leg->link_sent_usec;
845 if (leg->rtt_usec == 0) {
846 log_warn(
LD_CIRC,
"Clock appears stalled for conflux.");
852 return leg->rtt_usec;
857 leg->rtt_usec = UINT64_MAX;
877 "Conflux: Trying to record exit RTT without a timestamp");
886 log_warn(
LD_CIRC,
"Clock appears stalled for conflux.");
911 if (rtt_usec == UINT64_MAX)
915 log_info(
LD_CIRC,
"Conflux leg RTT is above circuit build time out "
916 "currently at %f msec. Relaunching.",
938 bool is_client =
false;
947 if (BUG(!unlinked)) {
948 log_warn(
LD_BUG,
"Failed to find the unlinked set %s when linking. "
951 err = ERR_LINK_CIRC_MISSING_SET;
959 log_warn(
LD_BUG,
"Failed to find leg for the unlinked set %s when "
960 "linking. Closing circuit.",
962 err = ERR_LINK_CIRC_MISSING_LEG;
987 for (
int i = 0; i < num_legs; i++) {
1002unlinked_get_or_create(
const uint8_t *nonce,
bool is_client)
1018 unlinked->cfx = cfx;
1019 unlinked->is_for_linked_set =
true;
1059 if (smartlist_len(unlinked->legs) > 0) {
1061 leg_t *leg = smartlist_get(unlinked->legs, 0);
1080#ifdef TOR_UNIT_TESTS
1081 return DEFAULT_CLIENT_UX;
1085 (void)DEFAULT_CLIENT_UX;
1088 return opt->ConfluxClientUX;
1103 unsigned int max_num_launch =
1109 log_info(
LD_CIRC,
"Maximum number of leg launch reached for nonce %s",
1140 unlinked = unlinked_get_or_create(nonce,
true);
1152 log_info(
LD_CIRC,
"Launching conflux leg for nonce %s.",
fmt_nonce(nonce));
1154 log_info(
LD_CIRC,
"Launching new conflux set for nonce %s.",
1188 conflux_cell_new_link(nonce,
1189 last_seq_sent, last_seq_recv,
1216 if (!CIRCUIT_IS_CONFLUX(circ)) {
1245 } CONFLUX_FOR_EACH_LEG_END(leg);
1260 } SMARTLIST_FOREACH_END(leg);
1284 if (!CIRCUIT_IS_CONFLUX(circ)) {
1307 } CONFLUX_FOR_EACH_LEG_END(leg);
1324 } SMARTLIST_FOREACH_END(leg);
1336 if (BUG(!leg->
circ)) {
1337 log_warn(
LD_BUG,
"Client conflux linked set leg without a circuit");
1343 if (!CONST_TO_ORIGIN_CIRCUIT(leg->
circ)->unusable_for_new_conns &&
1348 } DIGEST256MAP_FOREACH_END;
1365 if (!conflux_is_enabled(NULL) ||
1381 int num_set = num_unlinked + num_linked;
1384 if (num_set >= max_prebuilt) {
1388 log_info(
LD_CIRC,
"Preemptively launching new conflux circuit set(s). "
1389 "We have %d linked and %d unlinked.",
1390 num_linked, num_unlinked);
1392 for (
int i = 0; i < (max_prebuilt - num_set); i++) {
1417 if (BUG(leg->
circ->
purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED)) {
1428 CIRCUIT_PURPOSE_CONFLUX_LINKED,
1436 } DIGEST256MAP_FOREACH_END;
1449 bool is_client =
false;
1471 log_info(
LD_CIRC,
"Conflux unlinked circuit with nonce %s has closed",
1475 unlinked_leg_del_and_free(unlinked, circ);
1479 if (smartlist_len(unlinked->legs) == 0) {
1481 }
else if (!shutting_down) {
1503 tor_assert_nonfatal(circ->
conflux);
1507 tor_assert_nonfatal(circ->
purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED);
1512 stream->on_circuit = circ;
1513 stream->cpath_layer = ocirc->
cpath->
prev;
1521 stream->on_circuit = circ;
1527 stream->on_circuit = circ;
1554 bool is_client =
false;
1555 bool full_teardown =
false;
1562 tor_assert_nonfatal(circ->
purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED);
1605 if (full_teardown) {
1634 if (BUG(!shutting_down)) {
1636 "Conflux circuit %p being freed without being marked for "
1637 "full teardown via close, with shutdown state %d. "
1638 "Please report this.", circ, shutting_down);
1667 unlinked->is_for_linked_set =
false;
1727 if (!conflux_is_enabled(circ)) {
1728 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1729 static ratelim_t conflux_ratelim = RATELIM_INIT(600);
1731 "Conflux circuit opened without negotiating "
1732 "congestion control");
1741 log_info(
LD_CIRC,
"Conflux circuit has opened with nonce %s",
1746 log_warn(
LD_CIRC,
"Unable to find conflux leg in unlinked set.");
1752 if (!conflux_cell_send_link(leg->link, orig_circ)) {
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(msg);
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);
1902 if (!conflux_is_enabled(circ)) {
1903 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
1911 "Received CONFLUX_LINKED cell on a non origin circuit.");
1917 "Received a CONFLUX_LINKED cell without having sent a "
1918 "CONFLUX_LINK cell. Closing circuit.");
1924 "Received a CONFLUX_LINKED cell on a circuit that is already "
1925 "linked. Closing circuit.");
1931 "Got a CONFLUX_LINKED from wrong hop on circuit. Closing circuit.");
1938 link = conflux_cell_parse_link(msg);
1943 log_info(
LD_CIRC,
"Processing a CONFLUX_LINKED for set %s",
1949 sizeof(*link->nonce))) {
1951 "Received CONFLUX_LINKED but circuit nonce doesn't match "
1952 "cell nonce. Closing circuit.");
1959 log_warn(
LD_CIRC,
"Received CONFLUX_LINKED but can't find "
1960 "associated leg. Closing circuit.");
1964 log_info(
LD_CIRC,
"Successfully processed a CONFLUX_LINKED cell.");
1982 case ERR_LINK_CIRC_OK:
1985 case ERR_LINK_CIRC_INVALID_LEG:
1986 case ERR_LINK_CIRC_MISSING_SET:
1990 case ERR_LINK_CIRC_BAD_RTT:
1991 case ERR_LINK_CIRC_MISSING_LEG:
2015 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
2027 if (!conflux_is_enabled(circ)) {
2033 "Received CONFLUX_LINKED_ACK cell on an origin circuit. Closing.");
2039 "Got a CONFLUX_LINKED_ACK with further hops. Closing circuit.");
2045 "Received a CONFLUX_LINKED_ACK cell on a circuit that is not"
2046 "linked. Closing circuit.");
2050 log_info(
LD_CIRC,
"Processing a CONFLUX_LINKED_ACK for set %s",
2061 circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
2119 "Conflux %s: %d linked, %d launched. Delivered: %"PRIu64
"; "
2120 "teardown: %d; Current: %p, Previous: %p",
2131 " - Linked Leg %d purpose=%d; RTT %"PRIu64
", sent: %"PRIu64
2132 "; sent: %"PRIu64
", recv: %"PRIu64
", infl: %"PRIu64
", "
2133 "ptr: %p, idx: %d, marked: %d",
2134 legs, leg->circ->purpose, leg->circ_rtts_usec,
2135 leg->linked_sent_usec, leg->last_seq_recv,
2136 leg->last_seq_sent, cc->
inflight, leg->circ,
2137 leg->circ->global_circuitlist_idx,
2138 leg->circ->marked_for_close);
2140 } CONFLUX_FOR_EACH_LEG_END(leg);
2146 log_fn(loglevel,
LD_BUG,
" - Unlinked set: %d legs, for link: %d",
2147 smartlist_len(unlinked->legs), unlinked->is_for_linked_set);
2151 " Unlinked Leg: %d purpose=%d; linked: %d, RTT %"PRIu64
", "
2152 "sent: %"PRIu64
" link ptr %p, circ ptr: %p, idx: %d, marked: %d",
2153 legs, leg->circ->purpose, leg->linked,
2154 leg->rtt_usec, leg->link_sent_usec,
2155 leg->link, leg->circ,
2156 leg->circ->global_circuitlist_idx,
2157 leg->circ->marked_for_close);
2159 } SMARTLIST_FOREACH_END(leg);
2173 shutting_down =
true;
2176#ifdef TOR_UNIT_TESTS
2181conflux_clear_shutdown(
void)
2183 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)
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)
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)
void conflux_process_link(circuit_t *circ, const relay_msg_t *msg)
void conflux_process_linked(circuit_t *circ, crypt_path_t *layer_hint, const relay_msg_t *msg)
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()