diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c index 257d33f1ab..8089f438a7 100644 --- a/src/core/or/circuitbuild.c +++ b/src/core/or/circuitbuild.c @@ -1444,6 +1444,7 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei) switch (purpose) { /* These purposes connect to a router that we chose, so DEFAULT_ROUTE_LEN * is safe: */ + case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: case CIRCUIT_PURPOSE_TESTING: /* router reachability testing */ known_purpose = 1; @@ -1927,6 +1928,7 @@ choose_good_exit_server(origin_circuit_t *circ, * since it should be random. */ tor_assert_nonfatal(is_internal); FALLTHROUGH; + case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: case CIRCUIT_PURPOSE_C_GENERAL: if (is_internal) /* pick it like a middle hop */ 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_C_HSDIR_GET: case CIRCUIT_PURPOSE_C_GENERAL: + case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: + case CIRCUIT_PURPOSE_CONFLUX_LINKED: if (circ->build_state->is_internal) return; 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, /* for_exit_use */ - !state->is_internal && TO_CIRCUIT(circ)->purpose == - CIRCUIT_PURPOSE_C_GENERAL); + !state->is_internal && ( + TO_CIRCUIT(circ)->purpose == + CIRCUIT_PURPOSE_C_GENERAL || + TO_CIRCUIT(circ)->purpose == + CIRCUIT_PURPOSE_CONFLUX_UNLINKED)); if (BUG(exit_ei == NULL)) return -1; } diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c index 4ea55968ab..01baf7c795 100644 --- a/src/core/or/circuitlist.c +++ b/src/core/or/circuitlist.c @@ -841,6 +841,11 @@ circuit_purpose_to_controller_string(uint8_t purpose) case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: return "CIRCUIT_PADDING"; + case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: + return "CONFLUX_UNLINKED"; + case CIRCUIT_PURPOSE_CONFLUX_LINKED: + return "CONFLUX_LINKED"; + default: tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); 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_HS_VANGUARDS: case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: + case CIRCUIT_PURPOSE_CONFLUX_UNLINKED: + case CIRCUIT_PURPOSE_CONFLUX_LINKED: return NULL; case CIRCUIT_PURPOSE_INTRO_POINT: @@ -973,6 +980,12 @@ circuit_purpose_to_string(uint8_t purpose) case CIRCUIT_PURPOSE_C_CIRCUIT_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: tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); 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. */ return CIRCUIT_PURPOSE_HS_VANGUARDS; } 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! */ 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 || 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, "Hunting for a circ to cannibalize: purpose %d, uptime %d, " "capacity %d, internal %d", diff --git a/src/core/or/circuitlist.h b/src/core/or/circuitlist.h index 49ded11f12..ca3c5bd0ee 100644 --- a/src/core/or/circuitlist.h +++ b/src/core/or/circuitlist.h @@ -130,7 +130,14 @@ * actual needed HS purpose. */ #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 * to make or see any circuits with this purpose. */ #define CIRCUIT_PURPOSE_UNKNOWN 255 diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c index 77c5deaafb..9110252976 100644 --- a/src/core/or/circuituse.c +++ b/src/core/or/circuituse.c @@ -138,7 +138,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, purpose == CIRCUIT_PURPOSE_C_HSDIR_GET || purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || 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 && circ->timestamp_dirty+get_options()->MaxCircuitDirtiness <= now) return 0; @@ -162,6 +163,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, return 0; 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_C_HSDIR_GET) { 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) { if (CIRCUIT_IS_ORIGIN(circ) && !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 + get_options()->MaxCircuitDirtiness > now)) { 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 (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL || 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_HS_VANGUARDS || circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT || @@ -1655,6 +1661,8 @@ circuit_has_opened(origin_circuit_t *circ) hs_client_circuit_has_opened(circ); break; case CIRCUIT_PURPOSE_C_GENERAL: + circuit_try_attaching_streams(circ); + break; case CIRCUIT_PURPOSE_C_HSDIR_GET: case CIRCUIT_PURPOSE_S_HSDIR_POST: /* 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; } + /* Do not cannibalize for conflux circuits */ + if (purpose_to_build == CIRCUIT_PURPOSE_CONFLUX_UNLINKED) { + return 0; + } + 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); /* 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 || circ->base_.purpose == CIRCUIT_PURPOSE_C_HSDIR_GET || circ->base_.purpose == CIRCUIT_PURPOSE_S_HSDIR_POST || diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c index 7dd0935b47..b0ccedc27f 100644 --- a/src/core/or/connection_edge.c +++ b/src/core/or/connection_edge.c @@ -1236,6 +1236,7 @@ connection_ap_expire_beginning(void) } if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL && + circ->purpose != CIRCUIT_PURPOSE_CONFLUX_LINKED && circ->purpose != CIRCUIT_PURPOSE_CONTROLLER && circ->purpose != CIRCUIT_PURPOSE_C_HSDIR_GET && 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); /* We can only send optimistic data if we're connected to an open general circuit. */ + // TODO-329-PURPOSE: Can conflux circuits use optimistic data? + // Does anything use optimistic data? if (edge_conn->on_circuit == NULL || edge_conn->on_circuit->state != CIRCUIT_STATE_OPEN || (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; /* 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; /* 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", (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL || + circ->base_.purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED || circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER) ? ap_conn->socks_request->address : "", 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->state == AP_CONN_STATE_CIRCUIT_WAIT); 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; tor_assert(SOCKS_COMMAND_IS_RESOLVE(command)); diff --git a/src/feature/client/circpathbias.c b/src/feature/client/circpathbias.c index ff9e05a645..144a53c972 100644 --- a/src/feature/client/circpathbias.c +++ b/src/feature/client/circpathbias.c @@ -334,12 +334,23 @@ pathbias_should_count(origin_circuit_t *circ) * endpoint could be chosen maliciously. * Similarly, we can't count client-side intro attempts, * 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 || circ->base_.purpose == CIRCUIT_PURPOSE_TESTING || circ->base_.purpose == CIRCUIT_PURPOSE_CONTROLLER || circ->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND || 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_INTRODUCE_ACKED)) {