mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
infrastructure for integrity-checks in relay cells
make circuit_consider_sending_sendme use connection_edge_send_command fix endian bug in relay length handling (maybe) svn:r946
This commit is contained in:
parent
d3a2067584
commit
21cc01299b
@ -194,7 +194,7 @@ circuit_t *circuit_get_by_conn(connection_t *conn) {
|
||||
}
|
||||
|
||||
/* Find the newest circ that conn can use, preferably one which is
|
||||
* dirty and not too old.
|
||||
* dirty. Circ must not be too old.
|
||||
* If !conn, return newest.
|
||||
*
|
||||
* If must_be_open, ignore circs not in CIRCUIT_STATE_OPEN.
|
||||
@ -303,6 +303,35 @@ int circuit_stream_is_being_handled(connection_t *conn) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* update digest from the payload of cell. assign integrity part to cell. */
|
||||
void relay_set_digest(crypto_digest_env_t *digest, cell_t *cell) {
|
||||
uint32_t integrity;
|
||||
|
||||
crypto_digest_add_bytes(digest, cell->payload, CELL_PAYLOAD_SIZE);
|
||||
crypto_digest_get_digest(digest, (char *)&integrity, 4);
|
||||
SET_CELL_RELAY_INTEGRITY(*cell, integrity);
|
||||
}
|
||||
|
||||
/* update digest from the payload of cell (with the integrity part set
|
||||
* to 0). If the integrity part is valid return 0, else return -1.
|
||||
*/
|
||||
int relay_check_digest(crypto_digest_env_t *digest, cell_t *cell) {
|
||||
uint32_t received_integrity, calculated_integrity;
|
||||
|
||||
received_integrity = CELL_RELAY_INTEGRITY(*cell);
|
||||
SET_CELL_RELAY_INTEGRITY(*cell, 0);
|
||||
|
||||
crypto_digest_add_bytes(digest, cell->payload, CELL_PAYLOAD_SIZE);
|
||||
crypto_digest_get_digest(digest, (char *)&calculated_integrity, 4);
|
||||
|
||||
if(received_integrity != calculated_integrity) {
|
||||
log_fn(LOG_WARN,"Integrity check on cell payload failed. Bug or attack. (%d vs %d).",
|
||||
received_integrity, calculated_integrity);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
int cell_direction, crypt_path_t *layer_hint) {
|
||||
connection_t *conn=NULL;
|
||||
@ -321,12 +350,10 @@ int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
|
||||
if(recognized) {
|
||||
if(cell_direction == CELL_DIRECTION_OUT) {
|
||||
#if 0
|
||||
if(relay_update_digest(circ->n_digest, cell) < 0) {
|
||||
if(relay_check_digest(circ->n_digest, cell) < 0) {
|
||||
log_fn(LOG_WARN,"outgoing cell failed integrity check. Closing circ.");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
++stats_n_relay_cells_delivered;
|
||||
log_fn(LOG_DEBUG,"Sending to exit.");
|
||||
if (connection_edge_process_relay_cell(cell, circ, conn, EDGE_EXIT, NULL) < 0) {
|
||||
@ -335,12 +362,10 @@ int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
}
|
||||
}
|
||||
if(cell_direction == CELL_DIRECTION_IN) {
|
||||
#if 0
|
||||
if(relay_update_digest(layer_hint->p_digest, cell) < 0) {
|
||||
if(relay_check_digest(layer_hint->b_digest, cell) < 0) {
|
||||
log_fn(LOG_WARN,"outgoing cell failed integrity check. Closing circ.");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
++stats_n_relay_cells_delivered;
|
||||
log_fn(LOG_DEBUG,"Sending to AP.");
|
||||
if (connection_edge_process_relay_cell(cell, circ, conn, EDGE_AP, layer_hint) < 0) {
|
||||
@ -545,39 +570,20 @@ int circuit_consider_stop_edge_reading(circuit_t *circ, int edge_type, crypt_pat
|
||||
return 1;
|
||||
}
|
||||
|
||||
int circuit_consider_sending_sendme(circuit_t *circ, int edge_type, crypt_path_t *layer_hint) {
|
||||
cell_t cell;
|
||||
|
||||
assert(circ);
|
||||
|
||||
memset(&cell, 0, sizeof(cell_t));
|
||||
cell.command = CELL_RELAY;
|
||||
SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_SENDME);
|
||||
SET_CELL_STREAM_ID(cell, ZERO_STREAM);
|
||||
SET_CELL_RELAY_LENGTH(cell, 0);
|
||||
|
||||
if(edge_type == EDGE_AP) { /* i'm the AP */
|
||||
cell.circ_id = circ->n_circ_id;
|
||||
while(layer_hint->deliver_window < CIRCWINDOW_START-CIRCWINDOW_INCREMENT) {
|
||||
log_fn(LOG_DEBUG,"deliver_window %d, Queueing sendme forward.", layer_hint->deliver_window);
|
||||
void circuit_consider_sending_sendme(circuit_t *circ, int edge_type, crypt_path_t *layer_hint) {
|
||||
while((edge_type == EDGE_AP ? layer_hint->deliver_window : circ->deliver_window) <
|
||||
CIRCWINDOW_START - CIRCWINDOW_INCREMENT) {
|
||||
log_fn(LOG_DEBUG,"Queueing circuit sendme.");
|
||||
if(edge_type == EDGE_AP)
|
||||
layer_hint->deliver_window += CIRCWINDOW_INCREMENT;
|
||||
if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_OUT, layer_hint) < 0) {
|
||||
log_fn(LOG_WARN,"At AP: circuit_deliver_relay_cell failed.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if(edge_type == EDGE_EXIT) { /* i'm the exit */
|
||||
cell.circ_id = circ->p_circ_id;
|
||||
while(circ->deliver_window < CIRCWINDOW_START-CIRCWINDOW_INCREMENT) {
|
||||
log_fn(LOG_DEBUG,"deliver_window %d, Queueing sendme back.", circ->deliver_window);
|
||||
else
|
||||
circ->deliver_window += CIRCWINDOW_INCREMENT;
|
||||
if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_IN, layer_hint) < 0) {
|
||||
log_fn(LOG_WARN,"At exit: circuit_deliver_relay_cell failed.");
|
||||
return -1;
|
||||
}
|
||||
if(connection_edge_send_command(NULL, circ, RELAY_COMMAND_SENDME,
|
||||
NULL, 0, layer_hint) < 0) {
|
||||
log_fn(LOG_WARN,"connection_edge_send_command failed. Returning.");
|
||||
return; /* the circuit's closed, don't continue */
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void circuit_close(circuit_t *circ) {
|
||||
@ -602,6 +608,8 @@ void circuit_close(circuit_t *circ) {
|
||||
if (circ->state == CIRCUIT_STATE_BUILDING ||
|
||||
circ->state == CIRCUIT_STATE_OR_WAIT) {
|
||||
/* If we never built the circuit, note it as a failure. */
|
||||
/* Note that we can't just check circ->cpath here, because if
|
||||
* circuit-building failed immediately, it won't be set yet. */
|
||||
circuit_increment_failure_count();
|
||||
}
|
||||
circuit_free(circ);
|
||||
|
@ -371,7 +371,7 @@ int connection_read_to_buf(connection_t *conn) {
|
||||
if(connection_speaks_cells(conn)) {
|
||||
at_most = 30*(CELL_NETWORK_SIZE);
|
||||
} else {
|
||||
at_most = 30*(CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE);
|
||||
at_most = 30*(RELAY_PAYLOAD_SIZE);
|
||||
}
|
||||
|
||||
if(at_most > global_read_bucket)
|
||||
|
@ -132,18 +132,18 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int re
|
||||
|
||||
if(!circ) {
|
||||
log_fn(LOG_WARN,"no circ. Closing.");
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!fromconn || relay_command == RELAY_COMMAND_BEGIN) /* XXX more */
|
||||
is_control_cell = 1;
|
||||
|
||||
memset(&cell, 0, sizeof(cell_t));
|
||||
if(fromconn && fromconn->type == CONN_TYPE_AP) {
|
||||
// if(fromconn && fromconn->type == CONN_TYPE_AP) {
|
||||
if(cpath_layer) {
|
||||
cell.circ_id = circ->n_circ_id;
|
||||
cell_direction = CELL_DIRECTION_OUT;
|
||||
} else {
|
||||
/* NOTE: if !fromconn, we assume that it's heading towards the OP */
|
||||
cell.circ_id = circ->p_circ_id;
|
||||
cell_direction = CELL_DIRECTION_IN;
|
||||
}
|
||||
@ -159,6 +159,12 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int re
|
||||
if(payload_len) {
|
||||
memcpy(cell.payload+RELAY_HEADER_SIZE,payload,payload_len);
|
||||
}
|
||||
|
||||
if(cell_direction == CELL_DIRECTION_OUT) /* AP */
|
||||
relay_set_digest(cpath_layer->f_digest, &cell);
|
||||
else /* exit */
|
||||
relay_set_digest(circ->p_digest, &cell);
|
||||
|
||||
log_fn(LOG_DEBUG,"delivering %d cell %s.", relay_command,
|
||||
cell_direction == CELL_DIRECTION_OUT ? "forward" : "backward");
|
||||
|
||||
@ -231,11 +237,7 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
|
||||
}
|
||||
log_fn(LOG_DEBUG,"circ deliver_window now %d.", edge_type == EDGE_AP ? layer_hint->deliver_window : circ->deliver_window);
|
||||
|
||||
if(circuit_consider_sending_sendme(circ, edge_type, layer_hint) < 0) {
|
||||
log_fn(LOG_WARN,"circuit_consider_sending_sendme() failed.");
|
||||
conn->has_sent_end = 1; /* we failed because conn is broken. can't send end. */
|
||||
return -1;
|
||||
}
|
||||
circuit_consider_sending_sendme(circ, edge_type, layer_hint);
|
||||
|
||||
if(!conn) {
|
||||
log_fn(LOG_INFO,"relay cell dropped, unknown stream %d.",*(int*)conn->stream_id);
|
||||
@ -247,7 +249,6 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
|
||||
return -1; /* somebody's breaking protocol. kill the whole circuit. */
|
||||
}
|
||||
|
||||
// printf("New text for buf (%d bytes): '%s'", cell->length - RELAY_HEADER_SIZE, cell->payload + RELAY_HEADER_SIZE);
|
||||
stats_n_data_bytes_received += CELL_RELAY_LENGTH(*cell);
|
||||
connection_write_to_buf(cell->payload + RELAY_HEADER_SIZE,
|
||||
CELL_RELAY_LENGTH(*cell), conn);
|
||||
@ -416,7 +417,7 @@ int connection_edge_finished_flushing(connection_t *conn) {
|
||||
/* deliver a 'connected' relay cell back through the circuit. */
|
||||
*(uint32_t*)connected_payload = htonl(conn->addr);
|
||||
if(connection_edge_send_command(conn, circuit_get_by_conn(conn),
|
||||
RELAY_COMMAND_CONNECTED, NULL, 0, conn->cpath_layer) < 0)
|
||||
RELAY_COMMAND_CONNECTED, NULL, 0, NULL) < 0)
|
||||
return 0; /* circuit is closed, don't continue */
|
||||
assert(conn->package_window > 0);
|
||||
return connection_edge_process_inbuf(conn); /* in case the server has written anything */
|
||||
@ -541,10 +542,10 @@ void connection_ap_attach_pending(void)
|
||||
|
||||
static void connection_edge_consider_sending_sendme(connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
|
||||
|
||||
if(connection_outbuf_too_full(conn))
|
||||
return;
|
||||
|
||||
|
||||
circ = circuit_get_by_conn(conn);
|
||||
if(!circ) {
|
||||
/* this can legitimately happen if the destroy has already
|
||||
@ -552,7 +553,7 @@ static void connection_edge_consider_sending_sendme(connection_t *conn) {
|
||||
log_fn(LOG_INFO,"No circuit associated with conn. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
while(conn->deliver_window < STREAMWINDOW_START - STREAMWINDOW_INCREMENT) {
|
||||
log_fn(LOG_DEBUG,"Outbuf %d, Queueing stream sendme.", conn->outbuf_flushlen);
|
||||
conn->deliver_window += STREAMWINDOW_INCREMENT;
|
||||
@ -828,7 +829,7 @@ void connection_exit_connect(connection_t *conn) {
|
||||
/* also, deliver a 'connected' cell back through the circuit. */
|
||||
*((uint32_t*) connected_payload) = htonl(conn->addr);
|
||||
connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_CONNECTED,
|
||||
connected_payload, 4, conn->cpath_layer);
|
||||
connected_payload, 4, NULL);
|
||||
}
|
||||
|
||||
int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)
|
||||
|
16
src/or/or.h
16
src/or/or.h
@ -250,9 +250,17 @@ typedef uint16_t circ_id_t;
|
||||
|
||||
#define CELL_RELAY_COMMAND_END_REASON(c) (*(uint8_t)((c).payload+1))
|
||||
|
||||
/* integrity is the first 32 bits (in network order) of a sha-1 of all
|
||||
* cell payloads that are relay cells that have been sent / delivered
|
||||
* to the hop on the * circuit (the integrity is zeroed while doing
|
||||
* each calculation)
|
||||
*/
|
||||
#define CELL_RELAY_INTEGRITY(c) (ntohl(*(uint32_t*)((c).payload+1+STREAM_ID_SIZE)))
|
||||
#define SET_CELL_RELAY_INTEGRITY(c,i) (*(uint32_t*)((c).payload+1+STREAM_ID_SIZE) = htonl(i))
|
||||
|
||||
/* relay length is how many bytes are used in the cell payload past relay_header_size */
|
||||
#define CELL_RELAY_LENGTH(c) (*(uint16_t*)((c).payload+1+STREAM_ID_SIZE+4))
|
||||
#define SET_CELL_RELAY_LENGTH(c,len) (*(uint16_t*)((c).payload+1+STREAM_ID_SIZE+4) = (len))
|
||||
#define CELL_RELAY_LENGTH(c) (ntohs(*(uint16_t*)((c).payload+1+STREAM_ID_SIZE+4)))
|
||||
#define SET_CELL_RELAY_LENGTH(c,len) (*(uint16_t*)((c).payload+1+STREAM_ID_SIZE+4) = htons(len))
|
||||
|
||||
#define CELL_PAYLOAD_SIZE 509
|
||||
#define CELL_NETWORK_SIZE 512
|
||||
@ -544,6 +552,8 @@ void circuit_expire_building(void);
|
||||
int circuit_count_building(void);
|
||||
int circuit_stream_is_being_handled(connection_t *conn);
|
||||
|
||||
void relay_set_digest(crypto_digest_env_t *digest, cell_t *cell);
|
||||
int relay_check_digest(crypto_digest_env_t *digest, cell_t *cell);
|
||||
int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
int cell_direction, crypt_path_t *layer_hint);
|
||||
int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction,
|
||||
@ -552,7 +562,7 @@ int relay_check_recognized(circuit_t *circ, int cell_direction, char *stream, co
|
||||
|
||||
void circuit_resume_edge_reading(circuit_t *circ, int edge_type, crypt_path_t *layer_hint);
|
||||
int circuit_consider_stop_edge_reading(circuit_t *circ, int edge_type, crypt_path_t *layer_hint);
|
||||
int circuit_consider_sending_sendme(circuit_t *circ, int edge_type, crypt_path_t *layer_hint);
|
||||
void circuit_consider_sending_sendme(circuit_t *circ, int edge_type, crypt_path_t *layer_hint);
|
||||
|
||||
void circuit_close(circuit_t *circ);
|
||||
void circuit_about_to_close_connection(connection_t *conn);
|
||||
|
Loading…
Reference in New Issue
Block a user