tor
master
|
Manage global structures that list and index circuits, and look up circuits within them. More...
#include "torint.h"
#include "or.h"
#include "channel.h"
#include "circpathbias.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "circuituse.h"
#include "circuitstats.h"
#include "connection.h"
#include "config.h"
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
#include "crypto_rand.h"
#include "crypto_util.h"
#include "entrynodes.h"
#include "main.h"
#include "hs_circuit.h"
#include "hs_circuitmap.h"
#include "hs_ident.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "onion.h"
#include "onion_fast.h"
#include "policies.h"
#include "relay.h"
#include "relay_crypto.h"
#include "rendclient.h"
#include "rendcommon.h"
#include "rephist.h"
#include "routerlist.h"
#include "routerset.h"
#include "channelpadding.h"
#include "compress_lzma.h"
#include "compress_zlib.h"
#include "compress_zstd.h"
#include "ht.h"
Data Structures | |
struct | chan_circid_circuit_map_t |
Macros | |
#define | CIRCUITLIST_PRIVATE |
#define | DFLT_IDLE_TIMEOUT_WHILE_LEARNING (3*60) |
#define | MIN_IDLE_TIMEOUT_WHILE_LEARNING (10) |
#define | MAX_IDLE_TIMEOUT_WHILE_LEARNING (1000*60) |
#define | FRACTION_OF_DATA_TO_RETAIN_ON_OOM 0.90 |
Typedefs | |
typedef struct chan_circid_circuit_map_t | chan_circid_circuit_map_t |
Manage global structures that list and index circuits, and look up circuits within them.
One of the most frequent operations in Tor occurs every time that a relay cell arrives on a channel. When that happens, we need to find which circuit it is associated with, based on the channel and the circuit ID in the relay cell.
To handle that, we maintain a global list of circuits, and a hashtable mapping [channel,circID] pairs to circuits. Circuits are added to and removed from this mapping using circuit_set_p_circid_chan() and circuit_set_n_circid_chan(). To look up a circuit from this map, most callers should use circuit_get_by_circid_channel(), though circuit_get_by_circid_channel_even_if_marked() is appropriate under some circumstances.
We also need to allow for the possibility that we have blocked use of a circuit ID (because we are waiting to send a DESTROY cell), but the circuit is not there any more. For that case, we allow placeholder entries in the table, using channel_mark_circid_unusable().
To efficiently handle a channel that has just opened, we also maintain a list of the circuits waiting for channels, so we can attach them as needed without iterating through the whole list of circuits, using circuit_get_all_pending_on_channel().
In this module, we also handle the list of circuits that have been marked for close elsewhere, and close them as needed. (We use this "mark now, close later" pattern here and elsewhere to avoid unpredictable recursion if we closed every circuit immediately upon realizing it needed to close.) See circuit_mark_for_close() for the mark function, and circuit_close_all_marked() for the close function.
For hidden services, we need to be able to look up introduction point circuits and rendezvous circuits by cookie, key, etc. These are currently handled with linear searches in circuit_get_ready_rend_circuit_by_rend_data(), circuit_get_next_by_pk_and_purpose(), and with hash lookups in circuit_get_rendezvous() and circuit_get_intro_point().
This module is also the entry point for our out-of-memory handler logic, which was originally circuit-focused.
#define DFLT_IDLE_TIMEOUT_WHILE_LEARNING (3*60) |
If we haven't yet decided on a good timeout value for circuit building, we close idle circuits aggressively so we can get more data points. These are the default, min, and max consensus values
typedef struct chan_circid_circuit_map_t chan_circid_circuit_map_t |
A map from channel and circuit ID to circuit. (Lookup performance is very important here, since we need to do it every time a cell arrives.)
void assert_cpath_layer_ok | ( | const crypt_path_t * | cp | ) |
Verify that cpath layer cp has all of its invariants correct. Trigger an assert if anything is invalid.
Mark that circuit id id shouldn't be used on channel chan, even if there is no circuit on the channel. We use this to keep the circuit id from getting re-used while we have queued but not yet sent a destroy cell.
Mark that a circuit id id can be used again on chan. We use this to re-enable the circuit ID after we've sent a destroy cell.
Called to indicate that a DESTROY is pending on chan with circuit ID id, but hasn't been sent yet.
int circuit_any_opened_circuits | ( | void | ) |
Return true if we have any opened general-purpose 3 hop origin circuits.
The result from this function is cached for use by circuit_any_opened_circuits_cached().
int circuit_any_opened_circuits_cached | ( | void | ) |
Return true if there were any opened circuits since the last call to circuit_any_opened_circuits(), or since circuit_expire_building() last ran (it runs roughly once per second).
void circuit_cache_opened_circuit_state | ( | int | circuits_are_opened | ) |
Cache the "any circuits opened" state, as specified in param circuits_are_opened. This is a helper function to update the circuit opened status whenever we happen to look at the circuit list.
void circuit_clear_cpath | ( | origin_circuit_t * | circ | ) |
Deallocate the linked list circ->cpath, and remove the cpath from circ.
void circuit_clear_testing_cell_stats | ( | circuit_t * | circ | ) |
Free all storage held in circ->testing_cell_stats
void circuit_close_all_marked | ( | void | ) |
Detach from the global circuit list, and deallocate, all circuits that have been marked for close.
int circuit_count_pending_on_channel | ( | channel_t * | chan | ) |
Return the number of circuits in state CHAN_WAIT, waiting for the given channel.
void circuit_dump_by_conn | ( | connection_t * | conn, |
int | severity | ||
) |
Log, at severity severity, information about each circuit that is connected to conn.
smartlist_t* circuit_find_circuits_to_upgrade_from_guard_wait | ( | void | ) |
Check whether any of the origin circuits that are waiting to see if their guard is good enough to use can be upgraded to "ready". If so, return a new smartlist containing them. Otherwise return NULL.
origin_circuit_t* circuit_find_to_cannibalize | ( | uint8_t | purpose_to_produce, |
extend_info_t * | info, | ||
int | flags | ||
) |
Return a circuit that is open, is CIRCUIT_PURPOSE_C_GENERAL, has a timestamp_dirty value of 0, has flags matching the CIRCLAUNCH_* flags in flags, and if info is defined, does not already use info as any of its hops; or NULL if no circuit fits this description.
The purpose argument refers to the purpose of the circuit we want to create, not the purpose of the circuit we want to cannibalize.
If !CIRCLAUNCH_NEED_UPTIME, prefer returning non-uptime circuits.
To "cannibalize" a circuit means to extend it an extra hop, and use it for some other purpose than we had originally intended. We do this when we want to perform some low-bandwidth task at a specific relay, and we would like the circuit to complete as soon as possible. (If we were going to use a lot of bandwidth, we wouldn't want a circuit with an extra hop. If we didn't care about circuit completion latency, we would just build a new circuit.)
STATIC void circuit_free_ | ( | circuit_t * | circ | ) |
Deallocate space associated with circ.
void circuit_free_all | ( | void | ) |
Release all storage held by circuits.
void circuit_get_all_pending_on_channel | ( | smartlist_t * | out, |
channel_t * | chan | ||
) |
Append to out all circuits in state CHAN_WAIT waiting for the given connection.
Return a circ such that:
Return a circ such that:
circuit_t* circuit_get_by_edge_conn | ( | edge_connection_t * | conn | ) |
Return the circuit that a given edge connection is using.
origin_circuit_t* circuit_get_by_global_id | ( | uint32_t | id | ) |
Return the circuit whose global ID is id, or NULL if no such circuit exists.
crypt_path_t* circuit_get_cpath_hop | ( | origin_circuit_t * | circ, |
int | hopnum | ||
) |
Return the hopnumth hop in circ->cpath, or NULL if there aren't that many hops in the list. hopnum starts at 1. Returns NULL if hopnum is 0 or negative.
int circuit_get_cpath_len | ( | origin_circuit_t * | circ | ) |
Return the number of hops in circuit's path. If circ has no entries, or is NULL, returns 0.
int circuit_get_cpath_opened_len | ( | const origin_circuit_t * | circ | ) |
Return the number of opened hops in circuit's path. If circ has no entries, or is NULL, returns 0.
smartlist_t* circuit_get_global_origin_circuit_list | ( | void | ) |
Return a pointer to the global list of origin circuits.
origin_circuit_t* circuit_get_next_by_pk_and_purpose | ( | origin_circuit_t * | start, |
const uint8_t * | digest, | ||
uint8_t | purpose | ||
) |
Return the first circuit originating here in global_circuitlist after start whose purpose is purpose, and where digest (if set) matches the private key digest of the rend data associated with the circuit. Return NULL if no circuit is found. If start is NULL, begin at the start of the list.
origin_circuit_t* circuit_get_next_service_intro_circ | ( | origin_circuit_t * | start | ) |
Return the first service introduction circuit originating from the global circuit list after start or at the start of the list if start is NULL. Return NULL if no circuit is found.
A service introduction point circuit has a purpose of either CIRCUIT_PURPOSE_S_ESTABLISH_INTRO or CIRCUIT_PURPOSE_S_INTRO. This does not return a circuit marked for close and its state must be open.
origin_circuit_t* circuit_get_next_service_rp_circ | ( | origin_circuit_t * | start | ) |
Return the first service rendezvous circuit originating from the global circuit list after start or at the start of the list if start is NULL. Return NULL if no circuit is found.
A service rendezvous point circuit has a purpose of either CIRCUIT_PURPOSE_S_CONNECT_REND or CIRCUIT_PURPOSE_S_REND_JOINED. This does not return a circuit marked for close and its state must be open.
origin_circuit_t* circuit_get_ready_rend_circ_by_rend_data | ( | const rend_data_t * | rend_data | ) |
Return a circ such that
Return NULL if no such circuit exists.
Return true iff the circuit ID circ_id is currently used by a circuit, marked or not, on chan, or if the circ ID is reserved until a queued destroy cell can be sent.
(Return 1 if the circuit is present, marked or not; Return 2 if the circuit ID is pending a destroy.)
Helper for debugging 12184. Returns the time since which 'circ_id' has been marked unusable on 'chan'.
int32_t circuit_initial_package_window | ( | void | ) |
Pick a reasonable package_window to start out for our circuits. Originally this was hard-coded at 1000, but now the consensus votes on the answer. See proposal 168.
void circuit_mark_all_dirty_circs_as_unusable | ( | void | ) |
Go through the circuitlist; for each circuit that starts at us and is dirty, frob its timestamp_dirty so we won't use it for any new streams.
This is useful for letting the user change pseudonyms, so new streams will not be linkable to old streams.
void circuit_mark_all_unused_circs | ( | void | ) |
Go through the circuitlist; mark-for-close each circuit that starts at us but has not yet been used.
STATIC uint32_t circuit_max_queued_cell_age | ( | const circuit_t * | c, |
uint32_t | now | ||
) |
Return the age of the oldest cell queued on c, in timestamp units. Return 0 if there are no cells queued on c. Requires that now be the current coarse timestamp.
This function will return incorrect results if the oldest cell queued on the circuit is older than about 2**32 msec (about 49 days) old.
STATIC uint32_t circuit_max_queued_data_age | ( | const circuit_t * | c, |
uint32_t | now | ||
) |
Return the age in timestamp units of the oldest buffer chunk on any stream attached to the circuit c, where age is taken before the timestamp now.
STATIC uint32_t circuit_max_queued_item_age | ( | const circuit_t * | c, |
uint32_t | now | ||
) |
Return the age of the oldest cell or stream buffer chunk on the circuit c, where age is taken in timestamp units before the timestamp now
const char* circuit_purpose_to_controller_hs_state_string | ( | uint8_t | purpose | ) |
Return a string specifying the state of the hidden-service circuit purpose purpose, or NULL if purpose is not a hidden-service-related circuit purpose.
const char* circuit_purpose_to_controller_string | ( | uint8_t | purpose | ) |
Map a circuit purpose to a string suitable to be displayed to a controller.
const char* circuit_purpose_to_string | ( | uint8_t | purpose | ) |
Return a human-readable string for the circuit purpose purpose.
Set the n_conn field of a circuit circ, along with the corresponding circuit ID, and add the circuit as appropriate to the (chan,id)->circuit map.
void circuit_set_p_circid_chan | ( | or_circuit_t * | or_circ, |
circid_t | id, | ||
channel_t * | chan | ||
) |
Set the p_conn field of a circuit circ, along with the corresponding circuit ID, and add the circuit as appropriate to the (chan,id)->circuit map.
void circuit_set_state | ( | circuit_t * | circ, |
uint8_t | state | ||
) |
Change the state of circ to state, adding it to or removing it from lists as appropriate.
const char* circuit_state_to_string | ( | int | state | ) |
Function to make circ->state human-readable
void circuit_unlink_all_from_channel | ( | channel_t * | chan, |
int | reason | ||
) |
For each circuit that has chan as n_chan or p_chan, unlink the circuit from the chan,circid map, and mark it for close if it hasn't been marked already.
void circuits_handle_oom | ( | size_t | current_allocation | ) |
We're out of memory for cells, having allocated current_allocation bytes' worth. Kill the 'worst' circuits until we're under FRACTION_OF_DATA_TO_RETAIN_ON_OOM of our maximum usage.
Called to indicate that a DESTROY is no longer pending on chan with circuit ID id – typically, because it has been sent.
MOCK_IMPL | ( | smartlist_t * | , |
circuit_get_global_list | , | ||
(void) | |||
) |
Return a pointer to the global list of circuits.
MOCK_IMPL | ( | void | , |
circuit_mark_for_close_ | , | ||
(circuit_t *circ, int reason, int line, const char *file) | |||
) |
Mark circ to be closed next time we call circuit_close_all_marked(). Do any cleanup needed:
MOCK_IMPL | ( | void | , |
assert_circuit_ok | , | ||
(const circuit_t *c) | |||
) |
Verify that circuit c has all of its invariants correct. Trigger an assert if anything is invalid.
STATIC size_t n_cells_in_circ_queues | ( | const circuit_t * | c | ) |
Return the number of cells used by the circuit c's cell queues.
or_circuit_t* or_circuit_new | ( | circid_t | p_circ_id, |
channel_t * | p_chan | ||
) |
Allocate a new or_circuit_t, connected to p_chan as p_circ_id. If p_chan is NULL, the circuit is unattached.
origin_circuit_t* origin_circuit_new | ( | void | ) |
Allocate space for a new circuit, initializing with p_circ_id and p_conn. Add it to the global circuit list.