mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-06 19:41:15 +01:00
r16438@catbus: nickm | 2007-11-05 16:45:45 -0500
Initial code for variable-length cells. CERT and VERSIONS need to use them. svn:r12390
This commit is contained in:
@@ -30,8 +30,8 @@ Things we'd like to do in 0.2.0.x:
|
||||
act-on-netinfo logic separate so it can get called _after_
|
||||
negotiation.
|
||||
- Variable-length cells
|
||||
- Add structure
|
||||
- Add parse logic
|
||||
o Add structure
|
||||
o Add parse logic
|
||||
- Make CERT and VERSIONS variable.
|
||||
- CERT cells
|
||||
- functions to parse x509 certs
|
||||
|
||||
@@ -993,6 +993,42 @@ fetch_from_buf(char *string, size_t string_len, buf_t *buf)
|
||||
return buf->datalen;
|
||||
}
|
||||
|
||||
/** DOCDOC Returns 0 on "not a var-length cell."; 1 whether it's all here
|
||||
* yet or not. */
|
||||
int
|
||||
fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out)
|
||||
{
|
||||
char hdr[VAR_CELL_HEADER_SIZE];
|
||||
var_cell_t *result;
|
||||
uint8_t command;
|
||||
uint16_t length;
|
||||
check();
|
||||
*out = NULL;
|
||||
if (buf->datalen < VAR_CELL_HEADER_SIZE)
|
||||
return 0;
|
||||
peek_from_buf(hdr, sizeof(hdr), buf);
|
||||
|
||||
command = *(uint8_t*)(hdr+2);
|
||||
if (!(CELL_COMMAND_IS_VAR_LENGTH(command)))
|
||||
return 0;
|
||||
|
||||
length = ntohs(get_uint16(hdr+3));
|
||||
if (buf->datalen < (size_t)(VAR_CELL_HEADER_SIZE+length))
|
||||
return 1;
|
||||
result = tor_malloc(sizeof(var_cell_t)+length-1);
|
||||
result->command = command;
|
||||
result->payload_len = length;
|
||||
result->circ_id = ntohs(*(uint16_t*)hdr);
|
||||
|
||||
buf_remove_from_front(buf, VAR_CELL_HEADER_SIZE);
|
||||
peek_from_buf(result->payload, length, buf);
|
||||
buf_remove_from_front(buf, length);
|
||||
check();
|
||||
|
||||
*out = result;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Move up to *<b>buf_flushlen</b> bytes from <b>buf_in</b> to
|
||||
* <b>buf_out</b>, and modify *<b>buf_flushlen</b> appropriately.
|
||||
* Return the number of bytes actually copied.
|
||||
|
||||
+56
-8
@@ -35,9 +35,10 @@ static void command_process_create_cell(cell_t *cell, or_connection_t *conn);
|
||||
static void command_process_created_cell(cell_t *cell, or_connection_t *conn);
|
||||
static void command_process_relay_cell(cell_t *cell, or_connection_t *conn);
|
||||
static void command_process_destroy_cell(cell_t *cell, or_connection_t *conn);
|
||||
static void command_process_versions_cell(cell_t *cell, or_connection_t *conn);
|
||||
static void command_process_versions_cell(var_cell_t *cell,
|
||||
or_connection_t *conn);
|
||||
static void command_process_netinfo_cell(cell_t *cell, or_connection_t *conn);
|
||||
static void command_process_cert_cell(cell_t *cell, or_connection_t *conn);
|
||||
static void command_process_cert_cell(var_cell_t *cell, or_connection_t *conn);
|
||||
static void command_process_link_auth_cell(cell_t *cell,or_connection_t *conn);
|
||||
|
||||
#ifdef KEEP_TIMING_STATS
|
||||
@@ -143,16 +144,14 @@ command_process_cell(cell_t *cell, or_connection_t *conn)
|
||||
PROCESS_CELL(destroy, cell, conn);
|
||||
break;
|
||||
case CELL_VERSIONS:
|
||||
++stats_n_versions_cells_processed;
|
||||
PROCESS_CELL(versions, cell, conn);
|
||||
tor_fragile_assert();
|
||||
break;
|
||||
case CELL_NETINFO:
|
||||
++stats_n_netinfo_cells_processed;
|
||||
PROCESS_CELL(netinfo, cell, conn);
|
||||
break;
|
||||
case CELL_CERT:
|
||||
++stats_n_cert_cells_processed;
|
||||
PROCESS_CELL(cert, cell, conn);
|
||||
tor_fragile_assert();
|
||||
break;
|
||||
case CELL_LINK_AUTH:
|
||||
++stats_n_link_auth_cells_processed;
|
||||
@@ -165,6 +164,55 @@ command_process_cell(cell_t *cell, or_connection_t *conn)
|
||||
}
|
||||
}
|
||||
|
||||
/** Process a <b>cell</b> that was just received on <b>conn</b>. Keep internal
|
||||
* statistics about how many of each cell we've processed so far
|
||||
* this second, and the total number of microseconds it took to
|
||||
* process each type of cell.
|
||||
*/
|
||||
void
|
||||
command_process_var_cell(var_cell_t *cell, or_connection_t *conn)
|
||||
{
|
||||
#ifdef KEEP_TIMING_STATS
|
||||
/* how many of each cell have we seen so far this second? needs better
|
||||
* name. */
|
||||
static int num_versions=0, num_cert=0;
|
||||
|
||||
time_t now = time(NULL);
|
||||
|
||||
if (now > current_second) { /* the second has rolled over */
|
||||
/* print stats */
|
||||
log_info(LD_OR,
|
||||
"At end of second: %d versions (%d ms), %d cert (%d ms)",
|
||||
num_versions, versions_time/1000,
|
||||
cert, cert_time/1000);
|
||||
|
||||
num_versions = num_cert = 0;
|
||||
versions_time = cert_time = 0;
|
||||
|
||||
/* remember which second it is, for next time */
|
||||
current_second = now;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*XXXX020 reject all when not handshaking. */
|
||||
switch (cell->command) {
|
||||
case CELL_VERSIONS:
|
||||
++stats_n_versions_cells_processed;
|
||||
PROCESS_CELL(versions, cell, conn);
|
||||
break;
|
||||
case CELL_CERT:
|
||||
++stats_n_cert_cells_processed;
|
||||
PROCESS_CELL(cert, cell, conn);
|
||||
break;
|
||||
default:
|
||||
log_warn(LD_BUG,
|
||||
"Variable-length cell of unknown type (%d) received.",
|
||||
cell->command);
|
||||
tor_fragile_assert();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Process a 'create' <b>cell</b> that just arrived from <b>conn</b>. Make a
|
||||
* new circuit with the p_circ_id specified in cell. Put the circuit in state
|
||||
* onionskin_pending, and pass the onionskin to the cpuworker. Circ will get
|
||||
@@ -404,7 +452,7 @@ command_process_destroy_cell(cell_t *cell, or_connection_t *conn)
|
||||
/** Process a 'versions' cell. The current link protocol version must be 0
|
||||
* to indicate that no version has yet been negotiated. DOCDOC say more. */
|
||||
static void
|
||||
command_process_versions_cell(cell_t *cell, or_connection_t *conn)
|
||||
command_process_versions_cell(var_cell_t *cell, or_connection_t *conn)
|
||||
{
|
||||
uint16_t versionslen;
|
||||
int highest_supported_version = 0;
|
||||
@@ -560,7 +608,7 @@ connection_or_act_on_netinfo(or_connection_t *conn)
|
||||
}
|
||||
|
||||
static void
|
||||
command_process_cert_cell(cell_t *cell, or_connection_t *conn)
|
||||
command_process_cert_cell(var_cell_t *cell, or_connection_t *conn)
|
||||
{
|
||||
(void) cell;
|
||||
(void) conn;
|
||||
|
||||
+47
-17
@@ -147,6 +147,22 @@ cell_unpack(cell_t *dest, const char *src)
|
||||
memcpy(dest->payload, src+3, CELL_PAYLOAD_SIZE);
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
void
|
||||
var_cell_pack_header(var_cell_t *cell, char *hdr_out)
|
||||
{
|
||||
*(uint16_t*)(hdr_out) = htons(cell->circ_id);
|
||||
*(uint8_t*)(hdr_out+2) = cell->command;
|
||||
set_uint16(hdr_out+3, htons(cell->payload_len));
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
void
|
||||
var_cell_free(var_cell_t *cell)
|
||||
{
|
||||
tor_free(cell);
|
||||
}
|
||||
|
||||
int
|
||||
connection_or_reached_eof(or_connection_t *conn)
|
||||
{
|
||||
@@ -825,6 +841,13 @@ connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn)
|
||||
connection_write_to_buf(networkcell.body, CELL_NETWORK_SIZE, TO_CONN(conn));
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
static int
|
||||
connection_fetch_var_cell_from_buf(or_connection_t *conn, var_cell_t **out)
|
||||
{
|
||||
return fetch_var_cell_from_buf(conn->_base.inbuf, out);
|
||||
}
|
||||
|
||||
/** Process cells from <b>conn</b>'s inbuf.
|
||||
*
|
||||
* Loop: while inbuf contains a cell, pull it off the inbuf, unpack it,
|
||||
@@ -835,27 +858,34 @@ connection_or_write_cell_to_buf(const cell_t *cell, or_connection_t *conn)
|
||||
static int
|
||||
connection_or_process_cells_from_inbuf(or_connection_t *conn)
|
||||
{
|
||||
char buf[CELL_NETWORK_SIZE];
|
||||
cell_t cell;
|
||||
var_cell_t *var_cell;
|
||||
|
||||
loop:
|
||||
log_debug(LD_OR,
|
||||
"%d: starting, inbuf_datalen %d (%d pending in tls object).",
|
||||
conn->_base.s,(int)buf_datalen(conn->_base.inbuf),
|
||||
tor_tls_get_pending_bytes(conn->tls));
|
||||
if (buf_datalen(conn->_base.inbuf) < CELL_NETWORK_SIZE) /* whole response
|
||||
available? */
|
||||
return 0; /* not yet */
|
||||
while (1) {
|
||||
log_debug(LD_OR,
|
||||
"%d: starting, inbuf_datalen %d (%d pending in tls object).",
|
||||
conn->_base.s,(int)buf_datalen(conn->_base.inbuf),
|
||||
tor_tls_get_pending_bytes(conn->tls));
|
||||
if (connection_fetch_var_cell_from_buf(conn, &var_cell)) {
|
||||
if (!var_cell)
|
||||
return 0; /* not yet. */
|
||||
command_process_var_cell(var_cell, conn);
|
||||
var_cell_free(var_cell);
|
||||
} else {
|
||||
char buf[CELL_NETWORK_SIZE];
|
||||
cell_t cell;
|
||||
if (buf_datalen(conn->_base.inbuf) < CELL_NETWORK_SIZE) /* whole response
|
||||
available? */
|
||||
return 0; /* not yet */
|
||||
|
||||
connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, TO_CONN(conn));
|
||||
connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, TO_CONN(conn));
|
||||
|
||||
/* retrieve cell info from buf (create the host-order struct from the
|
||||
* network-order string) */
|
||||
cell_unpack(&cell, buf);
|
||||
/* retrieve cell info from buf (create the host-order struct from the
|
||||
* network-order string) */
|
||||
cell_unpack(&cell, buf);
|
||||
|
||||
command_process_cell(&cell, conn);
|
||||
|
||||
goto loop; /* process the remainder of the buffer */
|
||||
command_process_cell(&cell, conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Write a destroy cell with circ ID <b>circ_id</b> and reason <b>reason</b>
|
||||
|
||||
+23
-8
@@ -660,6 +660,9 @@ typedef enum {
|
||||
#define CELL_CERT 9
|
||||
#define CELL_LINK_AUTH 10
|
||||
|
||||
#define CELL_COMMAND_IS_VAR_LENGTH(x) \
|
||||
((x) == CELL_CERT || (x) == CELL_VERSIONS)
|
||||
|
||||
/** How long to test reachability before complaining to the user. */
|
||||
#define TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT (20*60)
|
||||
|
||||
@@ -701,28 +704,36 @@ typedef enum {
|
||||
/** Number of bytes in a cell transmitted over the network. */
|
||||
#define CELL_NETWORK_SIZE 512
|
||||
|
||||
#define VAR_CELL_HEADER_SIZE 5
|
||||
|
||||
/** Number of bytes in a relay cell's header (not including general cell
|
||||
* header). */
|
||||
#define RELAY_HEADER_SIZE (1+2+2+4+2)
|
||||
/** Largest number of bytes that can fit in a relay cell payload. */
|
||||
#define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE)
|
||||
|
||||
typedef struct cell_t cell_t;
|
||||
/** Parsed onion routing cell. All communication between nodes
|
||||
* is via cells. */
|
||||
struct cell_t {
|
||||
typedef struct cell_t {
|
||||
uint16_t circ_id; /**< Circuit which received the cell. */
|
||||
uint8_t command; /**< Type of the cell: one of PADDING, CREATE, RELAY,
|
||||
* or DESTROY. */
|
||||
uint8_t command; /**< Type of the cell: one of CELL_PADDING, CELL_CREATE,
|
||||
* CELL_DESTROY, etc */
|
||||
char payload[CELL_PAYLOAD_SIZE]; /**< Cell body. */
|
||||
};
|
||||
} cell_t;
|
||||
|
||||
/** Parsed variable-length onion routing cell. */
|
||||
typedef struct var_cell_t {
|
||||
uint8_t command;
|
||||
uint16_t circ_id;
|
||||
uint16_t payload_len;
|
||||
char payload[1];
|
||||
} var_cell_t;
|
||||
|
||||
typedef struct packed_cell_t packed_cell_t;
|
||||
/** A cell as packed for writing to the network. */
|
||||
struct packed_cell_t {
|
||||
typedef struct packed_cell_t {
|
||||
struct packed_cell_t *next; /**< Next cell queued on this circuit. */
|
||||
char body[CELL_NETWORK_SIZE]; /**< Cell as packed for network. */
|
||||
};
|
||||
} packed_cell_t;
|
||||
|
||||
/** A queue of cells on a circuit, waiting to be added to the
|
||||
* or_connection_t's outbuf. */
|
||||
@@ -2387,6 +2398,7 @@ int write_to_buf_zlib(buf_t *buf, tor_zlib_state_t *state,
|
||||
const char *data, size_t data_len, int done);
|
||||
int move_buf_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen);
|
||||
int fetch_from_buf(char *string, size_t string_len, buf_t *buf);
|
||||
int fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out);
|
||||
int fetch_from_buf_http(buf_t *buf,
|
||||
char **headers_out, size_t max_headerlen,
|
||||
char **body_out, size_t *body_used, size_t max_bodylen,
|
||||
@@ -2546,6 +2558,7 @@ int connection_ap_handshake_attach_circuit(edge_connection_t *conn);
|
||||
/********************************* command.c ***************************/
|
||||
|
||||
void command_process_cell(cell_t *cell, or_connection_t *conn);
|
||||
void command_process_var_cell(var_cell_t *cell, or_connection_t *conn);
|
||||
void connection_or_act_on_netinfo(or_connection_t *conn);
|
||||
|
||||
extern uint64_t stats_n_padding_cells_processed;
|
||||
@@ -2786,6 +2799,8 @@ int connection_or_compute_link_auth_hmac(or_connection_t *conn,
|
||||
char *hmac_out);
|
||||
|
||||
void cell_pack(packed_cell_t *dest, const cell_t *src);
|
||||
void var_cell_pack_header(var_cell_t *cell, char *hdr_out);
|
||||
void var_cell_free(var_cell_t *cell);
|
||||
|
||||
/********************************* control.c ***************************/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user