Prop#329: Add purposes for conflux circuits

Because UNLINKED circuits must never be used for streams, but LINKED circuits
can be, we want these separate.
This commit is contained in:
Mike Perry 2023-02-09 01:43:14 +00:00
parent cf715a56f1
commit a4ee0c29ee
6 changed files with 74 additions and 8 deletions

View File

@ -1444,6 +1444,7 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei)
switch (purpose) { switch (purpose) {
/* These purposes connect to a router that we chose, so DEFAULT_ROUTE_LEN /* These purposes connect to a router that we chose, so DEFAULT_ROUTE_LEN
* is safe: */ * is safe: */
case CIRCUIT_PURPOSE_CONFLUX_UNLINKED:
case CIRCUIT_PURPOSE_TESTING: case CIRCUIT_PURPOSE_TESTING:
/* router reachability testing */ /* router reachability testing */
known_purpose = 1; known_purpose = 1;
@ -1927,6 +1928,7 @@ choose_good_exit_server(origin_circuit_t *circ,
* since it should be random. */ * since it should be random. */
tor_assert_nonfatal(is_internal); tor_assert_nonfatal(is_internal);
FALLTHROUGH; FALLTHROUGH;
case CIRCUIT_PURPOSE_CONFLUX_UNLINKED:
case CIRCUIT_PURPOSE_C_GENERAL: case CIRCUIT_PURPOSE_C_GENERAL:
if (is_internal) /* pick it like a middle hop */ if (is_internal) /* pick it like a middle hop */
return router_choose_random_node(NULL, options->ExcludeNodes, flags); return router_choose_random_node(NULL, options->ExcludeNodes, flags);
@ -1974,6 +1976,8 @@ warn_if_last_router_excluded(origin_circuit_t *circ,
case CIRCUIT_PURPOSE_S_HSDIR_POST: case CIRCUIT_PURPOSE_S_HSDIR_POST:
case CIRCUIT_PURPOSE_C_HSDIR_GET: case CIRCUIT_PURPOSE_C_HSDIR_GET:
case CIRCUIT_PURPOSE_C_GENERAL: case CIRCUIT_PURPOSE_C_GENERAL:
case CIRCUIT_PURPOSE_CONFLUX_UNLINKED:
case CIRCUIT_PURPOSE_CONFLUX_LINKED:
if (circ->build_state->is_internal) if (circ->build_state->is_internal)
return; return;
description = "requested exit node"; description = "requested exit node";
@ -2109,8 +2113,11 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
} }
exit_ei = extend_info_from_node(node, state->onehop_tunnel, exit_ei = extend_info_from_node(node, state->onehop_tunnel,
/* for_exit_use */ /* for_exit_use */
!state->is_internal && TO_CIRCUIT(circ)->purpose == !state->is_internal && (
CIRCUIT_PURPOSE_C_GENERAL); TO_CIRCUIT(circ)->purpose ==
CIRCUIT_PURPOSE_C_GENERAL ||
TO_CIRCUIT(circ)->purpose ==
CIRCUIT_PURPOSE_CONFLUX_UNLINKED));
if (BUG(exit_ei == NULL)) if (BUG(exit_ei == NULL))
return -1; return -1;
} }

View File

@ -841,6 +841,11 @@ circuit_purpose_to_controller_string(uint8_t purpose)
case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING:
return "CIRCUIT_PADDING"; return "CIRCUIT_PADDING";
case CIRCUIT_PURPOSE_CONFLUX_UNLINKED:
return "CONFLUX_UNLINKED";
case CIRCUIT_PURPOSE_CONFLUX_LINKED:
return "CONFLUX_LINKED";
default: default:
tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose);
return buf; return buf;
@ -870,6 +875,8 @@ circuit_purpose_to_controller_hs_state_string(uint8_t purpose)
case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: case CIRCUIT_PURPOSE_PATH_BIAS_TESTING:
case CIRCUIT_PURPOSE_HS_VANGUARDS: case CIRCUIT_PURPOSE_HS_VANGUARDS:
case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING:
case CIRCUIT_PURPOSE_CONFLUX_UNLINKED:
case CIRCUIT_PURPOSE_CONFLUX_LINKED:
return NULL; return NULL;
case CIRCUIT_PURPOSE_INTRO_POINT: case CIRCUIT_PURPOSE_INTRO_POINT:
@ -973,6 +980,12 @@ circuit_purpose_to_string(uint8_t purpose)
case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING:
return "Circuit kept open for padding"; return "Circuit kept open for padding";
case CIRCUIT_PURPOSE_CONFLUX_UNLINKED:
return "Unlinked conflux circuit";
case CIRCUIT_PURPOSE_CONFLUX_LINKED:
return "Linked conflux circuit";
default: default:
tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose);
return buf; return buf;
@ -1841,6 +1854,9 @@ get_circuit_purpose_needed_to_cannibalize(uint8_t purpose)
* circuits so that we get the same path construction logic. */ * circuits so that we get the same path construction logic. */
return CIRCUIT_PURPOSE_HS_VANGUARDS; return CIRCUIT_PURPOSE_HS_VANGUARDS;
} else { } else {
/* Conflux purposes should never get here */
tor_assert_nonfatal(purpose != CIRCUIT_PURPOSE_CONFLUX_UNLINKED &&
purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED);
/* If no vanguards are used just get a general circuit! */ /* If no vanguards are used just get a general circuit! */
return CIRCUIT_PURPOSE_C_GENERAL; return CIRCUIT_PURPOSE_C_GENERAL;
} }
@ -1886,6 +1902,10 @@ circuit_find_to_cannibalize(uint8_t purpose_to_produce, extend_info_t *info,
tor_assert_nonfatal(purpose_to_search_for == CIRCUIT_PURPOSE_C_GENERAL || tor_assert_nonfatal(purpose_to_search_for == CIRCUIT_PURPOSE_C_GENERAL ||
purpose_to_search_for == CIRCUIT_PURPOSE_HS_VANGUARDS); purpose_to_search_for == CIRCUIT_PURPOSE_HS_VANGUARDS);
tor_assert_nonfatal(purpose_to_search_for !=
CIRCUIT_PURPOSE_CONFLUX_UNLINKED);
tor_assert_nonfatal(purpose_to_produce != CIRCUIT_PURPOSE_CONFLUX_UNLINKED);
log_debug(LD_CIRC, log_debug(LD_CIRC,
"Hunting for a circ to cannibalize: purpose %d, uptime %d, " "Hunting for a circ to cannibalize: purpose %d, uptime %d, "
"capacity %d, internal %d", "capacity %d, internal %d",

View File

@ -130,7 +130,14 @@
* actual needed HS purpose. */ * actual needed HS purpose. */
#define CIRCUIT_PURPOSE_HS_VANGUARDS 24 #define CIRCUIT_PURPOSE_HS_VANGUARDS 24
#define CIRCUIT_PURPOSE_MAX_ 24 /**
* These two purposes are for conflux. The first is for circuits that are
* being built, but not yet linked. The second is for circuits that are
* linked and ready to use for streams. */
#define CIRCUIT_PURPOSE_CONFLUX_UNLINKED 25
#define CIRCUIT_PURPOSE_CONFLUX_LINKED 26
#define CIRCUIT_PURPOSE_MAX_ 26
/** A catch-all for unrecognized purposes. Currently we don't expect /** A catch-all for unrecognized purposes. Currently we don't expect
* to make or see any circuits with this purpose. */ * to make or see any circuits with this purpose. */
#define CIRCUIT_PURPOSE_UNKNOWN 255 #define CIRCUIT_PURPOSE_UNKNOWN 255

View File

@ -138,7 +138,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
purpose == CIRCUIT_PURPOSE_C_HSDIR_GET || purpose == CIRCUIT_PURPOSE_C_HSDIR_GET ||
purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||
purpose == CIRCUIT_PURPOSE_HS_VANGUARDS || purpose == CIRCUIT_PURPOSE_HS_VANGUARDS ||
purpose == CIRCUIT_PURPOSE_C_REND_JOINED) { purpose == CIRCUIT_PURPOSE_C_REND_JOINED ||
purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED) {
if (circ->timestamp_dirty && if (circ->timestamp_dirty &&
circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now) circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now)
return 0; return 0;
@ -162,6 +163,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
return 0; return 0;
if (purpose == CIRCUIT_PURPOSE_C_GENERAL || if (purpose == CIRCUIT_PURPOSE_C_GENERAL ||
purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED ||
purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED ||
purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||
purpose == CIRCUIT_PURPOSE_C_HSDIR_GET) { purpose == CIRCUIT_PURPOSE_C_HSDIR_GET) {
tor_addr_t addr; tor_addr_t addr;
@ -1003,7 +1006,8 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) { SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (CIRCUIT_IS_ORIGIN(circ) && if (CIRCUIT_IS_ORIGIN(circ) &&
!circ->marked_for_close && !circ->marked_for_close &&
circ->purpose == CIRCUIT_PURPOSE_C_GENERAL && (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL ||
circ->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED) &&
(!circ->timestamp_dirty || (!circ->timestamp_dirty ||
circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) { circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) {
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ); origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
@ -1450,6 +1454,8 @@ circuit_expire_old_circuits_clientside(void)
if (timercmp(&circ->timestamp_began, &cutoff, OP_LT)) { if (timercmp(&circ->timestamp_began, &cutoff, OP_LT)) {
if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL || if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL ||
circ->purpose == CIRCUIT_PURPOSE_C_HSDIR_GET || circ->purpose == CIRCUIT_PURPOSE_C_HSDIR_GET ||
circ->purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED ||
circ->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED ||
circ->purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || circ->purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||
circ->purpose == CIRCUIT_PURPOSE_HS_VANGUARDS || circ->purpose == CIRCUIT_PURPOSE_HS_VANGUARDS ||
circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT || circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT ||
@ -1655,6 +1661,8 @@ circuit_has_opened(origin_circuit_t *circ)
hs_client_circuit_has_opened(circ); hs_client_circuit_has_opened(circ);
break; break;
case CIRCUIT_PURPOSE_C_GENERAL: case CIRCUIT_PURPOSE_C_GENERAL:
circuit_try_attaching_streams(circ);
break;
case CIRCUIT_PURPOSE_C_HSDIR_GET: case CIRCUIT_PURPOSE_C_HSDIR_GET:
case CIRCUIT_PURPOSE_S_HSDIR_POST: case CIRCUIT_PURPOSE_S_HSDIR_POST:
/* Tell any AP connections that have been waiting for a new /* Tell any AP connections that have been waiting for a new
@ -2030,6 +2038,11 @@ circuit_should_cannibalize_to_build(uint8_t purpose_to_build,
return 0; return 0;
} }
/* Do not cannibalize for conflux circuits */
if (purpose_to_build == CIRCUIT_PURPOSE_CONFLUX_UNLINKED) {
return 0;
}
return 1; return 1;
} }
@ -2607,6 +2620,8 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
exitnode = node_get_by_id(cpath->extend_info->identity_digest); exitnode = node_get_by_id(cpath->extend_info->identity_digest);
/* See if we can use optimistic data on this circuit */ /* See if we can use optimistic data on this circuit */
// TODO-329-PURPOSE: Can conflux use optimistic data? Does
// anything use optimistic data? Does anything use this?
if (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL || if (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL ||
circ->base_.purpose == CIRCUIT_PURPOSE_C_HSDIR_GET || circ->base_.purpose == CIRCUIT_PURPOSE_C_HSDIR_GET ||
circ->base_.purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || circ->base_.purpose == CIRCUIT_PURPOSE_S_HSDIR_POST ||

View File

@ -1236,6 +1236,7 @@ connection_ap_expire_beginning(void)
} }
if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL && if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL &&
circ->purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED &&
circ->purpose != CIRCUIT_PURPOSE_CONTROLLER && circ->purpose != CIRCUIT_PURPOSE_CONTROLLER &&
circ->purpose != CIRCUIT_PURPOSE_C_HSDIR_GET && circ->purpose != CIRCUIT_PURPOSE_C_HSDIR_GET &&
circ->purpose != CIRCUIT_PURPOSE_S_HSDIR_POST && circ->purpose != CIRCUIT_PURPOSE_S_HSDIR_POST &&
@ -3112,6 +3113,8 @@ connection_ap_supports_optimistic_data(const entry_connection_t *conn)
const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn); const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(conn);
/* We can only send optimistic data if we're connected to an open /* We can only send optimistic data if we're connected to an open
general circuit. */ general circuit. */
// TODO-329-PURPOSE: Can conflux circuits use optimistic data?
// Does anything use optimistic data?
if (edge_conn->on_circuit == NULL || if (edge_conn->on_circuit == NULL ||
edge_conn->on_circuit->state != CIRCUIT_STATE_OPEN || edge_conn->on_circuit->state != CIRCUIT_STATE_OPEN ||
(edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL && (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL &&
@ -3138,7 +3141,8 @@ connection_ap_get_begincell_flags(entry_connection_t *ap_conn)
return 0; return 0;
/* No flags for hidden services. */ /* No flags for hidden services. */
if (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL) if (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL &&
edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED)
return 0; return 0;
/* If only IPv4 is supported, no flags */ /* If only IPv4 is supported, no flags */
@ -3222,6 +3226,7 @@ connection_ap_handshake_send_begin,(entry_connection_t *ap_conn))
tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d", tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d",
(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL || (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL ||
circ->base_.purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED ||
circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER) ? circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER) ?
ap_conn->socks_request->address : "", ap_conn->socks_request->address : "",
ap_conn->socks_request->port); ap_conn->socks_request->port);
@ -3323,7 +3328,8 @@ connection_ap_handshake_send_resolve(entry_connection_t *ap_conn)
tor_assert(base_conn->type == CONN_TYPE_AP); tor_assert(base_conn->type == CONN_TYPE_AP);
tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); tor_assert(base_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
tor_assert(ap_conn->socks_request); tor_assert(ap_conn->socks_request);
tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL); tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL ||
circ->base_.purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED);
command = ap_conn->socks_request->command; command = ap_conn->socks_request->command;
tor_assert(SOCKS_COMMAND_IS_RESOLVE(command)); tor_assert(SOCKS_COMMAND_IS_RESOLVE(command));

View File

@ -334,12 +334,23 @@ pathbias_should_count(origin_circuit_t *circ)
* endpoint could be chosen maliciously. * endpoint could be chosen maliciously.
* Similarly, we can't count client-side intro attempts, * Similarly, we can't count client-side intro attempts,
* because clients can be manipulated into connecting to * because clients can be manipulated into connecting to
* malicious intro points. */ * malicious intro points.
*
* Finally, avoid counting conflux circuits for now, because
* a malicious exit could cause us to reconnect and blame
* our guard...
*
* TODO-329-PURPOSE: This is not quite right, we could
* instead avoid sending usable probes on conflux circs,
* and count only linked circs as failures, but it is
* not 100% clear that would result in accurate counts. */
if (get_options()->UseEntryGuards == 0 || if (get_options()->UseEntryGuards == 0 ||
circ->base_.purpose == CIRCUIT_PURPOSE_TESTING || circ->base_.purpose == CIRCUIT_PURPOSE_TESTING ||
circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER || circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER ||
circ->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND || circ->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND ||
circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED || circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED ||
circ->base_.purpose == CIRCUIT_PURPOSE_CONFLUX_UNLINKED ||
circ->base_.purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED ||
(circ->base_.purpose >= CIRCUIT_PURPOSE_C_INTRODUCING && (circ->base_.purpose >= CIRCUIT_PURPOSE_C_INTRODUCING &&
circ->base_.purpose <= CIRCUIT_PURPOSE_C_INTRODUCE_ACKED)) { circ->base_.purpose <= CIRCUIT_PURPOSE_C_INTRODUCE_ACKED)) {