Prop#329 Pool: Handle linking, unlinking, and relaunching conflux circuit legs.

Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
David Goulet 2023-02-01 22:41:03 +00:00 committed by Mike Perry
parent 2f865b4bba
commit 336a24754d
17 changed files with 1972 additions and 3 deletions

View File

@ -23,6 +23,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuitmux_ewma.h"
#include "core/or/circuitpadding.h"
#include "core/or/conflux_pool.h"
#include "core/or/connection_edge.h"
#include "core/or/dos.h"
#include "core/or/scheduler.h"
@ -120,6 +121,7 @@ tor_free_all(int postfork)
rep_hist_free_all();
bwhist_free_all();
circuit_free_all();
conflux_pool_free_all();
circpad_machines_free();
entry_guards_free_all();
pt_free_all();

View File

@ -14,6 +14,7 @@
#include "lib/cc/torint.h"
#include "core/mainloop/mainloop_sys.h"
#include "core/or/conflux_sys.h"
#include "core/or/dos_sys.h"
#include "core/or/or_sys.h"
#include "feature/control/btrack_sys.h"
@ -64,6 +65,7 @@ const subsys_fns_t *tor_subsystems[] = {
&sys_process,
&sys_mainloop,
&sys_conflux,
&sys_or,
&sys_dos,

View File

@ -261,6 +261,14 @@ struct circuit_t {
* CIRCUIT_PURPOSE_CONFLUX_UNLINKED.
*/
struct conflux_t *conflux;
/** If set, this circuit is considered *unlinked* and in the pending pool.
* The nonce value is used to find the other legs. Origin circuits that
* have this set are in the CIRCUIT_PURPOSE_CONFLUX_UNLINKED purpose.
*
* If this is NULL, and conflux object is set, it means this circuit is
* linked and thus part of a usable set. */
uint8_t *conflux_pending_nonce;
};
#endif /* !defined(CIRCUIT_ST_H) */

View File

@ -465,6 +465,8 @@ origin_circuit_init(uint8_t purpose, int flags)
((flags & CIRCLAUNCH_IS_INTERNAL) ? 1 : 0);
circ->build_state->is_ipv6_selftest =
((flags & CIRCLAUNCH_IS_IPV6_SELFTEST) ? 1 : 0);
circ->build_state->need_conflux =
((flags & CIRCLAUNCH_NEED_CONFLUX) ? 1 : 0);
circ->base_.purpose = purpose;
return circ;
}
@ -507,6 +509,47 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *exit_ei, int flags)
return circ;
}
/**
* Build a new conflux circuit for <b>purpose</b>. If <b>exit</b> is defined,
* then use that as your exit router, else choose a suitable exit node.
* The <b>flags</b> argument is a bitfield of CIRCLAUNCH_* flags, see
* circuit_launch_by_extend_info() for more details.
*
* Also launch a connection to the first OR in the chosen path, if
* it's not open already.
*/
MOCK_IMPL(origin_circuit_t *,
circuit_establish_circuit_conflux,(const uint8_t *conflux_nonce,
uint8_t purpose, extend_info_t *exit_ei,
int flags))
{
origin_circuit_t *circ;
int err_reason = 0;
/* Right now, only conflux client circuits use this function */
tor_assert(purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED);
circ = origin_circuit_init(purpose, flags);
TO_CIRCUIT(circ)->conflux_pending_nonce =
tor_memdup(conflux_nonce, DIGEST256_LEN);
if (onion_pick_cpath_exit(circ, exit_ei, 0) < 0 ||
onion_populate_cpath(circ) < 0) {
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_NOPATH);
return NULL;
}
circuit_event_status(circ, CIRC_EVENT_LAUNCHED, 0);
if ((err_reason = circuit_handle_first_hop(circ)) < 0) {
circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason);
return NULL;
}
tor_trace(TR_SUBSYS(circuit), TR_EV(establish), circ);
return circ;
}
/** Return the guard state associated with <b>circ</b>, which may be NULL. */
circuit_guard_state_t *
origin_circuit_get_guard_state(origin_circuit_t *circ)
@ -2105,6 +2148,8 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
flags |= CRN_DIRECT_CONN;
if (is_hs_v3_rp_circuit)
flags |= CRN_RENDEZVOUS_V3;
if (state->need_conflux)
flags |= CRN_CONFLUX;
const node_t *node =
choose_good_exit_server(circ, flags, state->is_internal);
if (!node) {

View File

@ -24,6 +24,12 @@ origin_circuit_t *origin_circuit_init(uint8_t purpose, int flags);
origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
extend_info_t *exit,
int flags);
MOCK_DECL(origin_circuit_t *, circuit_establish_circuit_conflux, (
const uint8_t *nonce,
uint8_t purpose,
extend_info_t *exit,
int flags));
struct circuit_guard_state_t *origin_circuit_get_guard_state(
origin_circuit_t *circ);
int circuit_handle_first_hop(origin_circuit_t *circ);

View File

@ -62,6 +62,8 @@
#include "core/or/circuituse.h"
#include "core/or/circuitstats.h"
#include "core/or/circuitpadding.h"
#include "core/or/conflux.h"
#include "core/or/conflux_pool.h"
#include "core/or/crypt_path.h"
#include "core/or/extendinfo.h"
#include "core/or/status.h"
@ -118,6 +120,7 @@
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
#include "core/or/conflux_util.h"
/********* START VARIABLES **********/
/** A global list of all circuits at this hop. */
@ -2254,6 +2257,11 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
/* Notify the HS subsystem that this circuit is closing. */
hs_circ_cleanup_on_close(circ);
/* Specific actions if this is a conflux related circuit. */
if (CIRCUIT_IS_CONFLUX(circ)) {
conflux_circuit_has_closed(circ);
}
/* Update stats. */
if (circ->ccontrol) {
if (circ->ccontrol->in_slow_start) {
@ -2297,6 +2305,8 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
static void
circuit_about_to_free_atexit(circuit_t *circ)
{
/* Cleanup conflux specifics. */
conflux_circuit_about_to_free(circ);
if (circ->n_chan) {
circuit_clear_cell_queue(circ, circ->n_chan);
@ -2326,6 +2336,9 @@ circuit_about_to_free(circuit_t *circ)
int reason = circ->marked_for_close_reason;
int orig_reason = circ->marked_for_close_orig_reason;
/* Cleanup conflux specifics. */
conflux_circuit_about_to_free(circ);
if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
onion_pending_remove(TO_OR_CIRCUIT(circ));
}

View File

@ -36,6 +36,7 @@
#include "core/or/circuitstats.h"
#include "core/or/circuituse.h"
#include "core/or/circuitpadding.h"
#include "core/or/conflux_pool.h"
#include "core/or/connection_edge.h"
#include "core/or/extendinfo.h"
#include "core/or/policies.h"
@ -74,6 +75,8 @@
#include "core/or/origin_circuit_st.h"
#include "core/or/socks_request_st.h"
#include "core/or/conflux_util.h"
STATIC void circuit_expire_old_circuits_clientside(void);
static void circuit_increment_failure_count(void);
@ -1217,6 +1220,7 @@ circuit_predict_and_launch_new(void)
log_info(LD_CIRC,
"Have %d clean circs (%d internal), need another exit circ.",
num, num_internal);
circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
return;
}
@ -1664,6 +1668,9 @@ circuit_has_opened(origin_circuit_t *circ)
case CIRCUIT_PURPOSE_C_INTRODUCING:
hs_client_circuit_has_opened(circ);
break;
case CIRCUIT_PURPOSE_CONFLUX_UNLINKED:
conflux_circuit_has_opened(circ);
break;
case CIRCUIT_PURPOSE_C_GENERAL:
circuit_try_attaching_streams(circ);
break;
@ -3063,6 +3070,13 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
if (circ->purpose == new_purpose) return;
/* If this is a conflux circuit, a purpose change means we have closed */
if (CIRCUIT_IS_CONFLUX(circ)) {
/* If we're not transitioning to the linked purpose, we're closed. */
if (new_purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED)
conflux_circuit_has_closed(circ);
}
if (CIRCUIT_IS_ORIGIN(circ)) {
char old_purpose_desc[80] = "";

View File

@ -52,6 +52,8 @@ void circuit_build_failed(origin_circuit_t *circ);
* node in the circuit. (We are both the client and the last node in the
* circuit.) */
#define CIRCLAUNCH_IS_IPV6_SELFTEST (1<<5)
/** Flag to set when a circuit needs the exit to support conflux. */
#define CIRCLAUNCH_NEED_CONFLUX (1<<6)
origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
extend_info_t *info,
@ -77,7 +79,6 @@ 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_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);

1745
src/core/or/conflux_pool.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
/* Copyright (c) 2023, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file conflux_pool.h
* \brief Header file for conflux_pool.c.
**/
#ifndef TOR_CONFLUX_POOL_H
#define TOR_CONFLUX_POOL_H
#include "core/or/or.h"
void conflux_pool_init(void);
void conflux_pool_free_all(void);
origin_circuit_t *conflux_get_circ_for_conn(const entry_connection_t *conn,
time_t now);
void conflux_predict_new(time_t now);
bool conflux_launch_leg(const uint8_t *nonce);
void conflux_circuit_has_closed(circuit_t *circ);
void conflux_circuit_has_opened(origin_circuit_t *orig_circ);
void conflux_circuit_about_to_free(circuit_t *circ);
void conflux_process_link(circuit_t *circ, const cell_t *cell,
const uint16_t cell_len);
void conflux_process_linked(circuit_t *circ, crypt_path_t *layer_hint,
const cell_t *cell, const uint16_t cell_len);
void conflux_process_linked_ack(circuit_t *circ);
#ifdef TOR_UNIT_TESTS
bool launch_new_set(int num_legs);
digest256map_t *get_linked_pool(bool is_client);
digest256map_t *get_unlinked_pool(bool is_client);
#endif /* defined(UNIT_TESTS) */
#endif /* TOR_CONFLUX_POOL_H */

37
src/core/or/conflux_sys.c Normal file
View File

@ -0,0 +1,37 @@
/* Copyright (c) 2023, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file conflux_sys.c
* \brief Register the conflux pool for early initialization.
**/
#include "core/or/conflux_pool.h"
#include "core/or/conflux_sys.h"
#include "lib/subsys/subsys.h"
static int
subsys_conflux_initialize(void)
{
conflux_pool_init();
return 0;
}
static void
subsys_conflux_shutdown(void)
{
/* The conflux pool free all must be called before the circuit free all and
* so we are not calling it from subsys shutdown. */
}
const subsys_fns_t sys_conflux = {
SUBSYS_DECLARE_LOCATION(),
.name = "conflux",
.supported = true,
.level = CONFLUX_SUBSYS_LEVEL,
.initialize = subsys_conflux_initialize,
.shutdown = subsys_conflux_shutdown,
};

23
src/core/or/conflux_sys.h Normal file
View File

@ -0,0 +1,23 @@
/* Copyright (c) 2023, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file conflux_sys.h
* \brief Header file for conflux_sys.c.
**/
#ifndef TOR_CONFLUX_SYS_H
#define TOR_CONFLUX_SYS_H
extern const struct subsys_fns_t sys_conflux;
/**
* Subsystem level.
*
* Defined here so that it can be shared between the real and stub
* definitions.
**/
#define CONFLUX_SUBSYS_LEVEL (10)
#endif /* TOR_CONFLUX_SYS_H */

View File

@ -30,6 +30,8 @@ struct cpath_build_state_t {
* These are for encrypted dir conns that exit to this router, not
* for arbitrary exits from the circuit. */
unsigned int onehop_tunnel : 1;
/** Indicating the exit needs to support Conflux. */
unsigned int need_conflux: 1;
/** How many times has building a circuit for this task failed? */
int failure_count;
/** At what time should we give up on this task? */

View File

@ -185,18 +185,27 @@ struct curve25519_public_key_t;
#define RELAY_COMMAND_DATA 2
#define RELAY_COMMAND_END 3
#define RELAY_COMMAND_CONNECTED 4
#define RELAY_COMMAND_SENDME 5
#define RELAY_COMMAND_EXTEND 6
#define RELAY_COMMAND_EXTENDED 7
#define RELAY_COMMAND_TRUNCATE 8
#define RELAY_COMMAND_TRUNCATED 9
#define RELAY_COMMAND_DROP 10
#define RELAY_COMMAND_RESOLVE 11
#define RELAY_COMMAND_RESOLVED 12
#define RELAY_COMMAND_BEGIN_DIR 13
#define RELAY_COMMAND_EXTEND2 14
#define RELAY_COMMAND_EXTENDED2 15
/* Conflux */
#define RELAY_COMMAND_CONFLUX_LINK 19
#define RELAY_COMMAND_CONFLUX_LINKED 20
#define RELAY_COMMAND_CONFLUX_LINKED_ACK 21
#define RELAY_COMMAND_CONFLUX_SWITCH 22
#define RELAY_COMMAND_ESTABLISH_INTRO 32
#define RELAY_COMMAND_ESTABLISH_RENDEZVOUS 33
#define RELAY_COMMAND_INTRODUCE1 34

View File

@ -100,6 +100,8 @@
#include "core/or/congestion_control_common.h"
#include "core/or/congestion_control_flow.h"
#include "core/or/conflux.h"
#include "core/or/conflux_util.h"
#include "core/or/conflux_pool.h"
static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell,
cell_direction_t cell_direction,
@ -450,7 +452,6 @@ relay_lookup_conn(circuit_t *circ, cell_t *cell,
/* IN or OUT cells could have come from either direction, now
* that we allow rendezvous *to* an OP.
*/
if (CIRCUIT_IS_ORIGIN(circ)) {
for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
tmpconn=tmpconn->next_stream) {
@ -544,6 +545,10 @@ relay_command_to_string(uint8_t command)
case RELAY_COMMAND_EXTENDED2: return "EXTENDED2";
case RELAY_COMMAND_PADDING_NEGOTIATE: return "PADDING_NEGOTIATE";
case RELAY_COMMAND_PADDING_NEGOTIATED: return "PADDING_NEGOTIATED";
case RELAY_COMMAND_CONFLUX_LINK: return "CONFLUX_LINK";
case RELAY_COMMAND_CONFLUX_LINKED: return "CONFLUX_LINKED";
case RELAY_COMMAND_CONFLUX_LINKED_ACK: return "CONFLUX_LINKED_ACK";
case RELAY_COMMAND_CONFLUX_SWITCH: return "CONFLUX_SWITCH";
default:
tor_snprintf(buf, sizeof(buf), "Unrecognized relay command %u",
(unsigned)command);
@ -782,6 +787,7 @@ connection_edge_send_command(edge_connection_t *fromconn,
circuit_t *circ;
crypt_path_t *cpath_layer = fromconn->cpath_layer;
tor_assert(fromconn);
circ = fromconn->on_circuit;
if (fromconn->base_.marked_for_close) {
@ -1653,6 +1659,15 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ,
/* Now handle all the other commands */
switch (rh->command) {
case RELAY_COMMAND_CONFLUX_LINK:
conflux_process_link(circ, cell, rh->length);
return 0;
case RELAY_COMMAND_CONFLUX_LINKED:
conflux_process_linked(circ, layer_hint, cell, rh->length);
return 0;
case RELAY_COMMAND_CONFLUX_LINKED_ACK:
conflux_process_linked_ack(circ);
return 0;
case RELAY_COMMAND_CONFLUX_SWITCH:
return conflux_process_switch_command(circ, layer_hint, cell, rh);
case RELAY_COMMAND_BEGIN:
@ -1713,7 +1728,6 @@ handle_relay_cell_command(cell_t *cell, circuit_t *circ,
/* Update our stream-level deliver window that we just received a DATA
* cell. Going below 0 means we have a protocol level error so the
* stream and circuit are closed. */
if (sendme_stream_data_received(conn) < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"(relay data) conn deliver_window below 0. Killing.");

View File

@ -34,6 +34,8 @@ typedef enum router_crn_flags_t {
CRN_RENDEZVOUS_V3 = 1<<6,
/* On clients, only provide nodes that can initiate IPv6 extends. */
CRN_INITIATE_IPV6_EXTEND = 1<<7,
/* On clients, only provide nodes that support Conflux (Relay=5). */
CRN_CONFLUX = 1<<8,
} router_crn_flags_t;
/** Possible ways to weight routers when choosing one randomly. See

View File

@ -558,6 +558,7 @@ router_can_choose_node(const node_t *node, int flags)
const bool direct_conn = (flags & CRN_DIRECT_CONN) != 0;
const bool rendezvous_v3 = (flags & CRN_RENDEZVOUS_V3) != 0;
const bool initiate_ipv6_extend = (flags & CRN_INITIATE_IPV6_EXTEND) != 0;
const bool need_conflux = (flags & CRN_CONFLUX) != 0;
const or_options_t *options = get_options();
const bool check_reach =
@ -592,6 +593,10 @@ router_can_choose_node(const node_t *node, int flags)
if (rendezvous_v3 &&
!node_supports_v3_rendezvous_point(node))
return false;
/* Exclude relay that don't do conflux if requested. */
if (need_conflux && !node_supports_conflux(node)) {
return false;
}
/* Choose a node with an OR address that matches the firewall rules */
if (direct_conn && check_reach &&
!reachable_addr_allows_node(node,