tor
master
|
Handle relay cell encryption/decryption, plus packaging and receiving from circuits, plus queuing on circuits. More...
#include "or.h"
#include "addressmap.h"
#include "backtrace.h"
#include "buffers.h"
#include "channel.h"
#include "circpathbias.h"
#include "circuitbuild.h"
#include "circuitlist.h"
#include "circuituse.h"
#include "compress.h"
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
#include "crypto_rand.h"
#include "crypto_util.h"
#include "geoip.h"
#include "hs_cache.h"
#include "main.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "onion.h"
#include "policies.h"
#include "reasons.h"
#include "relay.h"
#include "relay_crypto.h"
#include "rendcache.h"
#include "rendcommon.h"
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
#include "scheduler.h"
#include "rephist.h"
Macros | |
#define | RELAY_PRIVATE |
#define | CELL_QUEUE_HIGHWATER_SIZE 256 |
#define | CELL_QUEUE_LOWWATER_SIZE 64 |
#define | MAX_RESOLVE_FAILURES 3 |
#define | EARLY_WARNING_INTERVAL 3600 |
#define | MEMORY_PRESSURE_INTERVAL (30*60) |
#define | RELAY_CIRC_CELL_QUEUE_SIZE_MIN CIRCWINDOW_START_MAX |
#define | RELAY_CIRC_CELL_QUEUE_SIZE_MAX INT32_MAX |
#define | RELAY_CIRC_CELL_QUEUE_SIZE_DEFAULT (50 * RELAY_CIRC_CELL_QUEUE_SIZE_MIN) |
Functions | |
int | circuit_receive_relay_cell (cell_t *cell, circuit_t *circ, cell_direction_t cell_direction) |
void | relay_header_pack (uint8_t *dest, const relay_header_t *src) |
void | relay_header_unpack (relay_header_t *dest, const uint8_t *src) |
MOCK_IMPL (int, relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *circ, uint8_t relay_command, const char *payload, size_t payload_len, crypt_path_t *cpath_layer, const char *filename, int lineno)) | |
int | connection_edge_send_command (edge_connection_t *fromconn, uint8_t relay_command, const char *payload, size_t payload_len) |
STATIC int | connected_cell_parse (const relay_header_t *rh, const cell_t *cell, tor_addr_t *addr_out, int *ttl_out) |
STATIC void | address_ttl_free_ (address_ttl_t *addr) |
STATIC int | resolved_cell_parse (const cell_t *cell, const relay_header_t *rh, smartlist_t *addresses_out, int *errcode_out) |
STATIC int | connection_edge_process_resolved_cell (edge_connection_t *conn, const cell_t *cell, const relay_header_t *rh) |
STATIC int | connection_edge_process_relay_cell (cell_t *cell, circuit_t *circ, edge_connection_t *conn, crypt_path_t *layer_hint) |
int | connection_edge_package_raw_inbuf (edge_connection_t *conn, int package_partial, int *max_cells) |
void | connection_edge_consider_sending_sendme (edge_connection_t *conn) |
void | stream_choice_seed_weak_rng (void) |
STATIC packed_cell_t * | packed_cell_new (void) |
void | packed_cell_free_ (packed_cell_t *cell) |
void | dump_cell_pool_usage (int severity) |
void | cell_queue_append (cell_queue_t *queue, packed_cell_t *cell) |
void | cell_queue_append_packed_copy (circuit_t *circ, cell_queue_t *queue, int exitward, const cell_t *cell, int wide_circ_ids, int use_stats) |
void | cell_queue_init (cell_queue_t *queue) |
void | cell_queue_clear (cell_queue_t *queue) |
STATIC packed_cell_t * | cell_queue_pop (cell_queue_t *queue) |
void | destroy_cell_queue_init (destroy_cell_queue_t *queue) |
void | destroy_cell_queue_clear (destroy_cell_queue_t *queue) |
STATIC destroy_cell_t * | destroy_cell_queue_pop (destroy_cell_queue_t *queue) |
void | destroy_cell_queue_append (destroy_cell_queue_t *queue, circid_t circid, uint8_t reason) |
size_t | packed_cell_mem_cost (void) |
size_t | cell_queues_get_total_allocation (void) |
STATIC int | cell_queues_check_size (void) |
int | have_been_under_memory_pressure (void) |
void | update_circuit_on_cmux_ (circuit_t *circ, cell_direction_t direction, const char *file, int lineno) |
void | channel_unlink_all_circuits (channel_t *chan, smartlist_t *circuits_out) |
circid_t | packed_cell_get_circid (const packed_cell_t *cell, int wide_circ_ids) |
MOCK_IMPL (int, channel_flush_from_first_active_circuit,(channel_t *chan, int max)) | |
void | relay_consensus_has_changed (const networkstatus_t *ns) |
void | append_cell_to_circuit_queue (circuit_t *circ, channel_t *chan, cell_t *cell, cell_direction_t direction, streamid_t fromstream) |
int | append_address_to_payload (uint8_t *payload_out, const tor_addr_t *addr) |
const uint8_t * | decode_address_from_payload (tor_addr_t *addr_out, const uint8_t *payload, int payload_len) |
void | circuit_clear_cell_queue (circuit_t *circ, channel_t *chan) |
Variables | |
uint64_t | stats_n_relay_cells_relayed = 0 |
uint64_t | stats_n_relay_cells_delivered = 0 |
uint64_t | stats_n_circ_max_cell_reached = 0 |
uint64_t | stats_n_data_cells_packaged = 0 |
uint64_t | stats_n_data_bytes_packaged = 0 |
uint64_t | stats_n_data_cells_received = 0 |
uint64_t | stats_n_data_bytes_received = 0 |
Handle relay cell encryption/decryption, plus packaging and receiving from circuits, plus queuing on circuits.
This is a core modules that makes Tor work. It's responsible for dealing with RELAY cells (the ones that travel more than one hop along a circuit), by:
RELAY cells are generated throughout the code at the client or relay side, using relay_send_command_from_edge() or one of the functions like connection_edge_send_command() that calls it. Of particular interest is connection_edge_package_raw_inbuf(), which takes information that has arrived on an edge connection socket, and packages it as a RELAY_DATA cell – this is how information is actually sent across the Tor network. The cryptography for these functions is handled deep in circuit_package_relay_cell(), which either adds a single layer of encryption (if we're an exit), or multiple layers (if we're the origin of the circuit). After construction and encryption, the RELAY cells are passed to append_cell_to_circuit_queue(), which queues them for transmission and tells the circuitmux (see circuitmux.c) that the circuit is waiting to send something.
Incoming RELAY cells arrive at circuit_receive_relay_cell(), called from command.c. There they are decrypted and, if they are for us, are passed to connection_edge_process_relay_cell(). If they're not for us, they're re-queued for retransmission again with append_cell_to_circuit_queue().
The connection_edge_process_relay_cell() function handles all the different types of relay cells, launching requests or transmitting data as needed.
#define CELL_QUEUE_HIGHWATER_SIZE 256 |
Stop reading on edge connections when we have this many cells waiting on the appropriate queue.
#define CELL_QUEUE_LOWWATER_SIZE 64 |
Start reading from edge connections again when we get down to this many cells.
#define MAX_RESOLVE_FAILURES 3 |
How many times will I retry a stream that fails due to DNS resolve failure or misc error?
#define MEMORY_PRESSURE_INTERVAL (30*60) |
How long after we've been low on memory should we try to conserve it?
STATIC void address_ttl_free_ | ( | address_ttl_t * | addr | ) |
Drop all storage held by addr.
int append_address_to_payload | ( | uint8_t * | payload_out, |
const tor_addr_t * | addr | ||
) |
Append an encoded value of addr to payload_out, which must have at least 18 bytes of free space. The encoding is, as specified in tor-spec.txt: RESOLVED_TYPE_IPV4 or RESOLVED_TYPE_IPV6 [1 byte] LENGTH [1 byte] ADDRESS [length bytes] Return the number of bytes added, or -1 on error
void append_cell_to_circuit_queue | ( | circuit_t * | circ, |
channel_t * | chan, | ||
cell_t * | cell, | ||
cell_direction_t | direction, | ||
streamid_t | fromstream | ||
) |
Add cell to the queue of circ writing to chan transmitting in direction.
The given cell is copied onto the circuit queue so the caller must cleanup the memory.
This function is part of the fast path.
void cell_queue_append | ( | cell_queue_t * | queue, |
packed_cell_t * | cell | ||
) |
Append cell to the end of queue.
void cell_queue_append_packed_copy | ( | circuit_t * | circ, |
cell_queue_t * | queue, | ||
int | exitward, | ||
const cell_t * | cell, | ||
int | wide_circ_ids, | ||
int | use_stats | ||
) |
Append a newly allocated copy of cell to the end of the exitward (or app-ward) queue of circ. If use_stats is true, record statistics about the cell.
void cell_queue_clear | ( | cell_queue_t * | queue | ) |
Remove and free every cell in queue.
void cell_queue_init | ( | cell_queue_t * | queue | ) |
Initialize queue as an empty cell queue.
STATIC packed_cell_t* cell_queue_pop | ( | cell_queue_t * | queue | ) |
Extract and return the cell at the head of queue; return NULL if queue is empty.
STATIC int cell_queues_check_size | ( | void | ) |
Check whether we've got too much space used for cells. If so, call the OOM handler and return 1. Otherwise, return 0.
void channel_unlink_all_circuits | ( | channel_t * | chan, |
smartlist_t * | circuits_out | ||
) |
Remove all circuits from the cmux on chan.
If circuits_out is non-NULL, add all detached circuits to circuits_out.
Remove all the cells queued on circ for chan.
int circuit_receive_relay_cell | ( | cell_t * | cell, |
circuit_t * | circ, | ||
cell_direction_t | cell_direction | ||
) |
Receive a relay cell:
Return -reason on failure.
STATIC int connected_cell_parse | ( | const relay_header_t * | rh, |
const cell_t * | cell, | ||
tor_addr_t * | addr_out, | ||
int * | ttl_out | ||
) |
Extract the contents of a connected cell in cell, whose relay header has already been parsed into rh. On success, set addr_out to the address we're connected to, and ttl_out to the ttl of that address, in seconds, and return 0. On failure, return -1.
Note that the resulting address can be UNSPEC if the connected cell had no address (as for a stream to an union service or a tunneled directory connection), and that the ttl can be absent (in which case ttl_out is set to -1).
void connection_edge_consider_sending_sendme | ( | edge_connection_t * | conn | ) |
Called when we've just received a relay data cell, when we've just finished flushing all bytes to stream conn, or when we've flushed some bytes to the stream conn.
If conn->outbuf is not too full, and our deliver window is low, send back a suitable number of stream-level sendme cells.
int connection_edge_package_raw_inbuf | ( | edge_connection_t * | conn, |
int | package_partial, | ||
int * | max_cells | ||
) |
If conn has an entire relay payload of bytes on its inbuf (or package_partial is true), and the appropriate package windows aren't empty, grab a cell and send it down the circuit.
If *max_cells is given, package no more than max_cells. Decrement *max_cells by the number of cells packaged.
Return -1 (and send a RELAY_COMMAND_END cell if necessary) if conn should be marked for close, else return 0.
STATIC int connection_edge_process_relay_cell | ( | cell_t * | cell, |
circuit_t * | circ, | ||
edge_connection_t * | conn, | ||
crypt_path_t * | layer_hint | ||
) |
An incoming relay cell has arrived on circuit circ. If conn is NULL this is a control cell, else cell is destined for conn.
If layer_hint is defined, then we're the origin of the circuit, and it specifies the hop that packaged cell.
Return -reason if you want to warn and tear down the circuit, else 0.
STATIC int connection_edge_process_resolved_cell | ( | edge_connection_t * | conn, |
const cell_t * | cell, | ||
const relay_header_t * | rh | ||
) |
Handle a RELAY_COMMAND_RESOLVED cell that we received on a non-open AP stream.
int connection_edge_send_command | ( | edge_connection_t * | fromconn, |
uint8_t | relay_command, | ||
const char * | payload, | ||
size_t | payload_len | ||
) |
Make a relay cell out of relay_command and payload, and send it onto the open circuit circ. fromconn is the stream that's sending the relay cell, or NULL if it's a control cell. cpath_layer is NULL for OR->OP cells, or the destination hop for OP->OR cells.
If you can't send the cell, mark the circuit for close and return -1. Else return 0.
const uint8_t* decode_address_from_payload | ( | tor_addr_t * | addr_out, |
const uint8_t * | payload, | ||
int | payload_len | ||
) |
Given payload_len bytes at payload, starting with an address encoded as by append_address_to_payload(), try to decode the address into *addr_out. Return the next byte in the payload after the address on success, or NULL on failure.
void destroy_cell_queue_append | ( | destroy_cell_queue_t * | queue, |
circid_t | circid, | ||
uint8_t | reason | ||
) |
Append a destroy cell for circid to queue.
void destroy_cell_queue_clear | ( | destroy_cell_queue_t * | queue | ) |
Remove and free every cell in queue.
void destroy_cell_queue_init | ( | destroy_cell_queue_t * | queue | ) |
Initialize queue as an empty cell queue.
STATIC destroy_cell_t* destroy_cell_queue_pop | ( | destroy_cell_queue_t * | queue | ) |
Extract and return the cell at the head of queue; return NULL if queue is empty.
void dump_cell_pool_usage | ( | int | severity | ) |
Log current statistics for cell pool allocation at log level severity.
int have_been_under_memory_pressure | ( | void | ) |
Return true if we've been under memory pressure in the last MEMORY_PRESSURE_INTERVAL seconds.
MOCK_IMPL | ( | int | , |
relay_send_command_from_edge_ | , | ||
(streamid_t stream_id, circuit_t *circ, uint8_t relay_command, const char *payload, size_t payload_len, crypt_path_t *cpath_layer, const char *filename, int lineno) | |||
) |
Make a relay cell out of relay_command and payload, and send it onto the open circuit circ. stream_id is the ID on circ for the stream that's sending the relay cell, or 0 if it's a control cell. cpath_layer is NULL for OR->OP cells, or the destination hop for OP->OR cells.
If you can't send the cell, mark the circuit for close and return -1. Else return 0.
MOCK_IMPL | ( | int | , |
channel_flush_from_first_active_circuit | , | ||
(channel_t *chan, int max) | |||
) |
Pull as many cells as possible (but no more than max) from the queue of the first active circuit on chan, and write them to chan->outbuf. Return the number of cells written. Advance the active circuit pointer to the next active circuit in the ring.
void packed_cell_free_ | ( | packed_cell_t * | cell | ) |
Return a packed cell used outside by channel_t lower layer
circid_t packed_cell_get_circid | ( | const packed_cell_t * | cell, |
int | wide_circ_ids | ||
) |
Extract the circuit ID from a packed cell.
size_t packed_cell_mem_cost | ( | void | ) |
Return the total number of bytes used for each packed_cell in a queue. Approximate.
STATIC packed_cell_t* packed_cell_new | ( | void | ) |
Allocate and return a new packed_cell_t.
void relay_header_pack | ( | uint8_t * | dest, |
const relay_header_t * | src | ||
) |
Pack the relay_header_t host-order structure src into network-order in the buffer dest. See tor-spec.txt for details about the wire format.
void relay_header_unpack | ( | relay_header_t * | dest, |
const uint8_t * | src | ||
) |
Unpack the network-order buffer src into a host-order relay_header_t structure dest.
STATIC int resolved_cell_parse | ( | const cell_t * | cell, |
const relay_header_t * | rh, | ||
smartlist_t * | addresses_out, | ||
int * | errcode_out | ||
) |
Parse a resolved cell in cell, with parsed header in rh. Return -1 on parse error. On success, add one or more newly allocated address_ttl_t to addresses_out; set *errcode_out to one of 0, RESOLVED_TYPE_ERROR, or RESOLVED_TYPE_ERROR_TRANSIENT, and return 0.
void update_circuit_on_cmux_ | ( | circuit_t * | circ, |
cell_direction_t | direction, | ||
const char * | file, | ||
int | lineno | ||
) |
Update the number of cells available on the circuit's n_chan or p_chan's circuit mux.
uint64_t stats_n_circ_max_cell_reached = 0 |
Stats: how many circuits have we closed due to the cell queue limit being reached (see append_cell_to_circuit_queue())
uint64_t stats_n_data_bytes_packaged = 0 |
How many bytes of data have we put in relay_data cells have we built, ever? This would be RELAY_PAYLOAD_SIZE*stats_n_data_cells_packaged if every relay cell we ever sent were completely full of data.
uint64_t stats_n_data_bytes_received = 0 |
How many bytes of data have we received relay_data cells, ever? This would be RELAY_PAYLOAD_SIZE*stats_n_data_cells_packaged if every relay cell we ever received were completely full of data.
uint64_t stats_n_data_cells_packaged = 0 |
How many relay_data cells have we built, ever?
uint64_t stats_n_data_cells_received = 0 |
How many relay_data cells have we received, ever?
uint64_t stats_n_relay_cells_delivered = 0 |
Stats: how many relay cells have been delivered to streams at this hop?
uint64_t stats_n_relay_cells_relayed = 0 |
Stats: how many relay cells have originated at this hop, or have been relayed onward (not recognized at this hop)?