mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
comment and doxygenate connection_edge.c
svn:r1833
This commit is contained in:
+213
-23
@@ -2,11 +2,16 @@
|
||||
/* See LICENSE for licensing information */
|
||||
/* $Id$ */
|
||||
|
||||
/**
|
||||
* \file connection_edge.c
|
||||
* \brief Handle edge streams and relay cells.
|
||||
**/
|
||||
|
||||
#include "or.h"
|
||||
#include "tree.h"
|
||||
|
||||
extern or_options_t options; /* command-line and config-file options */
|
||||
extern char *conn_state_to_string[][_CONN_TYPE_MAX+1];
|
||||
extern char *conn_state_to_string[][_CONN_TYPE_MAX+1]; /* from connection.c */
|
||||
|
||||
static int connection_ap_handshake_process_socks(connection_t *conn);
|
||||
|
||||
@@ -17,6 +22,10 @@ static uint32_t client_dns_lookup_entry(const char *address);
|
||||
static void client_dns_set_entry(const char *address, uint32_t val);
|
||||
static int client_dns_incr_failures(const char *address);
|
||||
|
||||
/** Pack the relay_header_t host-order structure <b>src</b> into
|
||||
* network-order in the buffer <b>dest</b>. See tor-spec.txt for details
|
||||
* about the wire format.
|
||||
*/
|
||||
void relay_header_pack(char *dest, const relay_header_t *src) {
|
||||
*(uint8_t*)(dest) = src->command;
|
||||
|
||||
@@ -26,6 +35,9 @@ void relay_header_pack(char *dest, const relay_header_t *src) {
|
||||
set_uint16(dest+9, htons(src->length));
|
||||
}
|
||||
|
||||
/** Unpack the network-order buffer <b>src</b> into a host-order
|
||||
* relay_header_t structure <b>dest</b>.
|
||||
*/
|
||||
void relay_header_unpack(relay_header_t *dest, const char *src) {
|
||||
dest->command = *(uint8_t*)(src);
|
||||
|
||||
@@ -35,7 +47,18 @@ void relay_header_unpack(relay_header_t *dest, const char *src) {
|
||||
dest->length = ntohs(get_uint16(src+9));
|
||||
}
|
||||
|
||||
/* mark and return -1 if there was an unexpected error with the conn,
|
||||
/** Handle new bytes on conn->inbuf, or notification of eof.
|
||||
*
|
||||
* If there was an EOF, then send an end and mark the connection
|
||||
* for close.
|
||||
*
|
||||
* Otherwise handle it based on state:
|
||||
* - If it's waiting for socks info, try to read another step of the
|
||||
* socks handshake out of conn->inbuf.
|
||||
* - If it's open, then package more relay cells from the stream.
|
||||
* - Else, leave the bytes on inbuf alone for now.
|
||||
*
|
||||
* Mark and return -1 if there was an unexpected error with the conn,
|
||||
* else return 0.
|
||||
*/
|
||||
int connection_edge_process_inbuf(connection_t *conn) {
|
||||
@@ -98,6 +121,9 @@ int connection_edge_process_inbuf(connection_t *conn) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** This edge needs to be closed, because its circuit has closed.
|
||||
* Mark it for close and return 0.
|
||||
*/
|
||||
int connection_edge_destroy(uint16_t circ_id, connection_t *conn) {
|
||||
tor_assert(conn->type == CONN_TYPE_AP || conn->type == CONN_TYPE_EXIT);
|
||||
|
||||
@@ -111,7 +137,12 @@ int connection_edge_destroy(uint16_t circ_id, connection_t *conn) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *connection_edge_end_reason(char *payload, uint16_t length) {
|
||||
/** Translate the <b>payload</b> of length <b>length</b>, which
|
||||
* came from a relay 'end' cell, into a static const string describing
|
||||
* why the stream is closing.
|
||||
*/
|
||||
static const char *
|
||||
connection_edge_end_reason(char *payload, uint16_t length) {
|
||||
if(length < 1) {
|
||||
log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1.");
|
||||
return "MALFORMED";
|
||||
@@ -133,6 +164,14 @@ static char *connection_edge_end_reason(char *payload, uint16_t length) {
|
||||
return "";
|
||||
}
|
||||
|
||||
/** Send a relay end cell from stream <b>conn</b> to conn's circuit,
|
||||
* with a destination of cpath_layer. (If cpath_layer is NULL, the
|
||||
* destination is the circuit's origin.) Mark the relay end cell as
|
||||
* closing because of <b>reason</b>.
|
||||
*
|
||||
* Return -1 if this function has already been called on this conn,
|
||||
* else return 0.
|
||||
*/
|
||||
int connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer) {
|
||||
char payload[5];
|
||||
int payload_len=1;
|
||||
@@ -164,10 +203,10 @@ int connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_lay
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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
|
||||
/** Make a relay cell out of <b>relay_command</b> and <b>payload</b>, and
|
||||
* send it onto the open circuit <b>circ</b>. <b>fromconn</b> is the stream
|
||||
* that's sending the relay cell, or NULL if it's a control cell.
|
||||
* <b>cpath_layer</b> 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
|
||||
@@ -217,9 +256,20 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** How many times will I retry a stream that fails due to DNS
|
||||
* resolve failure?
|
||||
*/
|
||||
#define MAX_RESOLVE_FAILURES 3
|
||||
|
||||
int connection_edge_process_relay_cell_not_open(
|
||||
/** An incoming relay cell has arrived from circuit <b>circ</b> to
|
||||
* stream <b>conn</b>.
|
||||
*
|
||||
* The arguments here are the same as in
|
||||
* connection_edge_process_relay_cell() below; this function is called
|
||||
* from there when <b>conn</b> is defined and not in an open state.
|
||||
*/
|
||||
static int
|
||||
connection_edge_process_relay_cell_not_open(
|
||||
relay_header_t *rh, cell_t *cell, circuit_t *circ,
|
||||
connection_t *conn, crypt_path_t *layer_hint) {
|
||||
uint32_t addr;
|
||||
@@ -293,8 +343,15 @@ int connection_edge_process_relay_cell_not_open(
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* an incoming relay cell has arrived. return -1 if you want to tear down the
|
||||
* circuit, else 0. */
|
||||
/** An incoming relay cell has arrived on circuit <b>circ</b>. If
|
||||
* <b>conn</b> is NULL this is a control cell, else <b>cell</b> is
|
||||
* destined for <b>conn</b>.
|
||||
*
|
||||
* If <b>layer_hint</b> is defined, then we're the origin of the
|
||||
* circuit, and it specifies the hop that packaged <b>cell</b>.
|
||||
*
|
||||
* Return -1 if you want to tear down the circuit, else 0.
|
||||
*/
|
||||
int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
connection_t *conn,
|
||||
crypt_path_t *layer_hint) {
|
||||
@@ -474,6 +531,20 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Connection <b>conn</b> has finished writing and has no bytes left on
|
||||
* its outbuf.
|
||||
*
|
||||
* If it's in state 'connecting', then take a look at the socket, and
|
||||
* take appropriate actions (such as sending back a relay 'connected'
|
||||
* cell) if the connect succeeded.
|
||||
*
|
||||
* If it's in state 'open', stop writing, consider responding with a
|
||||
* sendme, and return.
|
||||
* Otherwise, stop writing and return.
|
||||
*
|
||||
* If <b>conn</b> is broken, mark it for close and return -1, else
|
||||
* return 0.
|
||||
*/
|
||||
int connection_edge_finished_flushing(connection_t *conn) {
|
||||
unsigned char connected_payload[4];
|
||||
int e, len=sizeof(e);
|
||||
@@ -539,6 +610,12 @@ uint64_t stats_n_data_bytes_packaged = 0;
|
||||
uint64_t stats_n_data_cells_received = 0;
|
||||
uint64_t stats_n_data_bytes_received = 0;
|
||||
|
||||
/** While conn->inbuf has an entire relay payload of bytes on it,
|
||||
* and the appropriate package windows aren't empty, grab a cell
|
||||
* and send it down the circuit.
|
||||
*
|
||||
* Return -1 if conn should be marked for close, else return 0.
|
||||
*/
|
||||
int connection_edge_package_raw_inbuf(connection_t *conn) {
|
||||
int amount_to_process, length;
|
||||
char payload[CELL_PAYLOAD_SIZE];
|
||||
@@ -606,7 +683,21 @@ repeat_connection_edge_package_raw_inbuf:
|
||||
goto repeat_connection_edge_package_raw_inbuf;
|
||||
}
|
||||
|
||||
/** How many times do we retry a general-purpose stream (detach it from
|
||||
* one circuit and try another, after we wait a while with no 'connected'
|
||||
* cell) before giving up?
|
||||
*/
|
||||
#define MAX_STREAM_RETRIES 4
|
||||
|
||||
/** Find all general-purpose AP streams in state connect_wait that sent
|
||||
* their begin cell >=15 seconds ago. Detach from their current circuit,
|
||||
* and mark their current circuit as unsuitable for new streams. Then call
|
||||
* connection_ap_handshake_attach_circuit() to attach to a new circuit (if
|
||||
* available) or launch a new one.
|
||||
*
|
||||
* For rendezvous streams, simply give up after 45 seconds (with no
|
||||
* retry attempt).
|
||||
*/
|
||||
void connection_ap_expire_beginning(void) {
|
||||
connection_t **carray;
|
||||
connection_t *conn;
|
||||
@@ -672,7 +763,9 @@ void connection_ap_expire_beginning(void) {
|
||||
} /* end for */
|
||||
}
|
||||
|
||||
/* Tell any APs that are waiting for a new circuit that one is available */
|
||||
/** Tell any AP streamss that are waiting for a new circuit that one is
|
||||
* available.
|
||||
*/
|
||||
void connection_ap_attach_pending(void)
|
||||
{
|
||||
connection_t **carray;
|
||||
@@ -694,6 +787,12 @@ void connection_ap_attach_pending(void)
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when we've just received a relay data cell, or when
|
||||
* we've just finished flushing all bytes to stream <b>conn</b>.
|
||||
*
|
||||
* If conn->outbuf is not too full, and our deliver window is
|
||||
* low, send back a suitable number of stream-level sendme cells.
|
||||
*/
|
||||
static void connection_edge_consider_sending_sendme(connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
|
||||
@@ -719,7 +818,19 @@ static void connection_edge_consider_sending_sendme(connection_t *conn) {
|
||||
}
|
||||
}
|
||||
|
||||
/* return -1 if an unexpected error with conn, else 0. */
|
||||
/** connection_edge_process_inbuf() found a conn in state
|
||||
* socks_wait. See if conn->inbuf has the right bytes to proceed with
|
||||
* the socks handshake.
|
||||
*
|
||||
* If the handshake is complete, and it's for a general circuit, then
|
||||
* try to attach it to a circuit (or launch one as needed). If it's for
|
||||
* a rendezvous circuit, then fetch a rendezvous descriptor first (or
|
||||
* attach/launch a circuit if the rendezvous descriptor is already here
|
||||
* and fresh enough).
|
||||
*
|
||||
* Return -1 if an unexpected error with conn (and it should be marked
|
||||
* for close), else return 0.
|
||||
*/
|
||||
static int connection_ap_handshake_process_socks(connection_t *conn) {
|
||||
socks_request_t *socks;
|
||||
int sockshere;
|
||||
@@ -789,10 +900,11 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find an open circ that we're happy with: return 1. if there isn't
|
||||
* one, and there isn't one on the way, launch one and return 0. if it
|
||||
/** Find an open circ that we're happy with: return 1. If there isn't
|
||||
* one, and there isn't one on the way, launch one and return 0. If it
|
||||
* will never work, return -1.
|
||||
* write the found or in-progress or launched circ into *circp.
|
||||
*
|
||||
* Write the found or in-progress or launched circ into *circp.
|
||||
*/
|
||||
static int
|
||||
circuit_get_open_circ_or_launch(connection_t *conn,
|
||||
@@ -866,6 +978,10 @@ circuit_get_open_circ_or_launch(connection_t *conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Attach the AP stream <b>apconn</b> to circ's linked list of
|
||||
* p_streams. Also set apconn's cpath_layer to the last hop in
|
||||
* circ's cpath.
|
||||
*/
|
||||
void link_apconn_to_circ(connection_t *apconn, circuit_t *circ) {
|
||||
/* add it into the linked list of streams on this circuit */
|
||||
log_fn(LOG_DEBUG,"attaching new conn to circ. n_circ_id %d.", circ->n_circ_id);
|
||||
@@ -878,7 +994,7 @@ void link_apconn_to_circ(connection_t *apconn, circuit_t *circ) {
|
||||
apconn->cpath_layer = circ->cpath->prev;
|
||||
}
|
||||
|
||||
/* Try to find a safe live circuit for CONN_TYPE_AP connection conn. If
|
||||
/** Try to find a safe live circuit for CONN_TYPE_AP connection conn. If
|
||||
* we don't find one: if conn cannot be handled by any known nodes,
|
||||
* warn and return -1 (conn needs to die);
|
||||
* else launch new circuit (if necessary) and return 0.
|
||||
@@ -990,8 +1106,8 @@ int connection_ap_handshake_attach_circuit(connection_t *conn) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate over the two bytes of stream_id until we get one that is not
|
||||
* already in use. Return 0 if can't get a unique stream_id.
|
||||
/** Iterate over the two bytes of stream_id until we get one that is not
|
||||
* already in use; return it. Return 0 if can't get a unique stream_id.
|
||||
*/
|
||||
static uint16_t get_unique_stream_id_by_circ(circuit_t *circ) {
|
||||
connection_t *tmpconn;
|
||||
@@ -1013,7 +1129,11 @@ again:
|
||||
return test_stream_id;
|
||||
}
|
||||
|
||||
/* deliver the destaddr:destport in a relay cell */
|
||||
/** Write a relay begin cell, using destaddr and destport from ap_conn's
|
||||
* socks_request field, and send it down circ.
|
||||
*
|
||||
* If ap_conn is broken, mark it for close and return -1. Else return 0.
|
||||
*/
|
||||
int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
|
||||
{
|
||||
char payload[CELL_PAYLOAD_SIZE];
|
||||
@@ -1060,9 +1180,10 @@ int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* make an ap connection_t, do a socketpair and attach one side
|
||||
/** Make an AP connection_t, do a socketpair and attach one side
|
||||
* to the conn, connection_add it, initialize it to circuit_wait,
|
||||
* and call connection_ap_handshake_attach_circuit(conn) on it.
|
||||
*
|
||||
* Return the other end of the socketpair, or -1 if error.
|
||||
*/
|
||||
int connection_ap_make_bridge(char *address, uint16_t port) {
|
||||
@@ -1115,6 +1236,14 @@ int connection_ap_make_bridge(char *address, uint16_t port) {
|
||||
return fd[1];
|
||||
}
|
||||
|
||||
/** Send a socks reply to stream <b>conn</b>, using the appropriate
|
||||
* socks version, etc.
|
||||
*
|
||||
* If <b>reply</b> is defined, then write <b>replylen</b> bytes of it
|
||||
* to conn and return.
|
||||
*
|
||||
* Otherwise, send back a reply based on whether <b>success</b> is 1 or 0.
|
||||
*/
|
||||
void connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
|
||||
int replylen, char success) {
|
||||
char buf[256];
|
||||
@@ -1148,6 +1277,22 @@ void connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
|
||||
return;
|
||||
}
|
||||
|
||||
/** A relay 'begin' cell has arrived, and either we are an exit hop
|
||||
* for the circuit, or we are the origin and it is a rendezvous begin.
|
||||
*
|
||||
* Launch a new exit connection and initialize things appropriately.
|
||||
*
|
||||
* If it's a rendezvous stream, call connection_exit_connect() on
|
||||
* it.
|
||||
*
|
||||
* For general streams, call dns_resolve() on it first, and only call
|
||||
* connection_exit_connect() if the dns answer is already known.
|
||||
*
|
||||
* Note that we don't call connection_add() on the new stream! We wait
|
||||
* for connection_exit_connect() to do that.
|
||||
*
|
||||
* Return -1 if we want to tear down <b>circ</b>. Else return 0.
|
||||
*/
|
||||
static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
|
||||
connection_t *n_stream;
|
||||
relay_header_t rh;
|
||||
@@ -1241,6 +1386,13 @@ static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Connect to conn's specified addr and port. If it worked, conn
|
||||
* has now been added to the connection_array.
|
||||
*
|
||||
* Send back a connected cell. Include the resolved IP of the destination
|
||||
* address, but <em>only</em> if it's a general exit stream. (Rendezvous
|
||||
* streams must not reveal what IP they connected to.)
|
||||
*/
|
||||
void connection_exit_connect(connection_t *conn) {
|
||||
unsigned char connected_payload[4];
|
||||
|
||||
@@ -1290,6 +1442,9 @@ void connection_exit_connect(connection_t *conn) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Return 1 if <b>conn</b> is a rendezvous stream, or 0 if
|
||||
* it is a general stream.
|
||||
*/
|
||||
int connection_edge_is_rendezvous_stream(connection_t *conn) {
|
||||
tor_assert(conn);
|
||||
if(*conn->rend_query) /* XXX */
|
||||
@@ -1297,6 +1452,11 @@ int connection_edge_is_rendezvous_stream(connection_t *conn) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Return 1 if router <b>exit</b> might allow stream <b>conn</b>
|
||||
* to exit from it, or 0 if it definitely will not allow it.
|
||||
* (We might be uncertain if conn's destination address has not yet been
|
||||
* resolved.)
|
||||
*/
|
||||
int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
|
||||
{
|
||||
uint32_t addr;
|
||||
@@ -1321,19 +1481,31 @@ int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
|
||||
* by answering funny things to stream begin requests, and later
|
||||
* other clients would reuse those funny addr's. Hm.
|
||||
*/
|
||||
|
||||
/** A client-side struct to remember the resolved IP (addr) for
|
||||
* a given address. These structs make up a tree, with client_dns_map
|
||||
* below as its root.
|
||||
*/
|
||||
struct client_dns_entry {
|
||||
uint32_t addr;
|
||||
time_t expires;
|
||||
int n_failures;
|
||||
uint32_t addr; /**< The resolved IP of this entry */
|
||||
time_t expires; /**< At what second does addr expire? */
|
||||
int n_failures; /**< How many times has this entry failed to resolve so far? */
|
||||
};
|
||||
|
||||
/** How many elements are in the client dns cache currently? */
|
||||
static int client_dns_size = 0;
|
||||
/** The tree of client-side cached DNS resolves. */
|
||||
static strmap_t *client_dns_map = NULL;
|
||||
|
||||
/** Initialize client_dns_map and client_dns_size. */
|
||||
void client_dns_init(void) {
|
||||
client_dns_map = strmap_new();
|
||||
client_dns_size = 0;
|
||||
}
|
||||
|
||||
/** Return the client_dns_entry that corresponds to <b>address</b>.
|
||||
* If it's not there, allocate and return a new entry for <b>address</b>.
|
||||
*/
|
||||
static struct client_dns_entry *
|
||||
_get_or_create_ent(const char *address)
|
||||
{
|
||||
@@ -1348,6 +1520,9 @@ _get_or_create_ent(const char *address)
|
||||
return ent;
|
||||
}
|
||||
|
||||
/** Return the IP associated with <b>address</b>, if we know it
|
||||
* and it's still fresh enough. Otherwise return 0.
|
||||
*/
|
||||
static uint32_t client_dns_lookup_entry(const char *address)
|
||||
{
|
||||
struct client_dns_entry *ent;
|
||||
@@ -1381,6 +1556,10 @@ static uint32_t client_dns_lookup_entry(const char *address)
|
||||
}
|
||||
}
|
||||
|
||||
/** An attempt to resolve <b>address</b> failed at some OR.
|
||||
* Increment the number of resolve failures we have on record
|
||||
* for it, and then return that number.
|
||||
*/
|
||||
static int client_dns_incr_failures(const char *address)
|
||||
{
|
||||
struct client_dns_entry *ent;
|
||||
@@ -1391,6 +1570,11 @@ static int client_dns_incr_failures(const char *address)
|
||||
return ent->n_failures;
|
||||
}
|
||||
|
||||
/** Record the fact that <b>address</b> resolved to <b>val</b>.
|
||||
* We can now use this in subsequent streams in client_dns_lookup_entry(),
|
||||
* so we can more correctly choose a router that will allow <b>address</b>
|
||||
* to exit from him.
|
||||
*/
|
||||
static void client_dns_set_entry(const char *address, uint32_t val)
|
||||
{
|
||||
struct client_dns_entry *ent;
|
||||
@@ -1412,6 +1596,9 @@ static void client_dns_set_entry(const char *address, uint32_t val)
|
||||
ent->n_failures = 0;
|
||||
}
|
||||
|
||||
/** A helper function for client_dns_clean() below. If ent is too old,
|
||||
* then remove it from the tree and return NULL, else return ent.
|
||||
*/
|
||||
static void* _remove_if_expired(const char *addr,
|
||||
struct client_dns_entry *ent,
|
||||
time_t *nowp)
|
||||
@@ -1425,6 +1612,9 @@ static void* _remove_if_expired(const char *addr,
|
||||
}
|
||||
}
|
||||
|
||||
/** Clean out entries from the client-side DNS cache that were
|
||||
* resolved long enough ago that they are no longer valid.
|
||||
*/
|
||||
void client_dns_clean(void)
|
||||
{
|
||||
time_t now;
|
||||
|
||||
Reference in New Issue
Block a user