make a relay_header_t struct and pack/unpack funcs

split 7-byte stream_id string into 2-byte recognized and 2-byte stream_id
fix two seg faults in fetch_from_buf_http
fix several lurking seg faults in handling unexpected relay cells

still need to
 * clean up relay_crypt
 * use relay dummies if there's going to be a conflict with rh.recognized
 * check for a conflict when generating stream_ids


svn:r953
This commit is contained in:
Roger Dingledine 2003-12-19 05:09:51 +00:00
parent eb730c41c8
commit 45a66c6955
5 changed files with 152 additions and 130 deletions

View File

@ -375,12 +375,12 @@ int fetch_from_buf_http(buf_t *buf,
if(headers_out) { if(headers_out) {
*headers_out = tor_malloc(headerlen+1); *headers_out = tor_malloc(headerlen+1);
memcpy(*headers_out,buf->mem,headerlen); memcpy(*headers_out,buf->mem,headerlen);
*headers_out[headerlen] = 0; /* null terminate it */ (*headers_out)[headerlen] = 0; /* null terminate it */
} }
if(body_out) { if(body_out) {
*body_out = tor_malloc(bodylen+1); *body_out = tor_malloc(bodylen+1);
memcpy(*body_out,buf->mem+headerlen,bodylen); memcpy(*body_out,buf->mem+headerlen,bodylen);
*body_out[bodylen] = 0; /* null terminate it */ (*body_out)[bodylen] = 0; /* null terminate it */
} }
buf_remove_from_front(buf, headerlen+bodylen); buf_remove_from_front(buf, headerlen+bodylen);
return 1; return 1;

View File

@ -6,6 +6,9 @@
extern or_options_t options; /* command-line and config-file options */ extern or_options_t options; /* command-line and config-file options */
static int relay_crypt(circuit_t *circ, char *in, char cell_direction,
crypt_path_t **layer_hint, char *recognized);
static connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction);
static void circuit_free_cpath_node(crypt_path_t *victim); static void circuit_free_cpath_node(crypt_path_t *victim);
static circ_id_t get_unique_circ_id_by_conn(connection_t *conn, int circ_id_type); static circ_id_t get_unique_circ_id_by_conn(connection_t *conn, int circ_id_type);
@ -310,11 +313,14 @@ int circuit_stream_is_being_handled(connection_t *conn) {
/* update digest from the payload of cell. assign integrity part to cell. */ /* update digest from the payload of cell. assign integrity part to cell. */
void relay_set_digest(crypto_digest_env_t *digest, cell_t *cell) { void relay_set_digest(crypto_digest_env_t *digest, cell_t *cell) {
uint32_t integrity; uint32_t integrity;
relay_header_t rh;
crypto_digest_add_bytes(digest, cell->payload, CELL_PAYLOAD_SIZE); crypto_digest_add_bytes(digest, cell->payload, CELL_PAYLOAD_SIZE);
crypto_digest_get_digest(digest, (char *)&integrity, 4); crypto_digest_get_digest(digest, (char *)&integrity, 4);
log_fn(LOG_DEBUG,"Putting digest of %u into relay cell.",integrity); log_fn(LOG_DEBUG,"Putting digest of %u into relay cell.",integrity);
SET_CELL_RELAY_INTEGRITY(*cell, integrity); relay_header_unpack(&rh, cell->payload);
rh.integrity = integrity;
relay_header_pack(cell->payload, &rh);
} }
/* update digest from the payload of cell (with the integrity part set /* update digest from the payload of cell (with the integrity part set
@ -322,10 +328,14 @@ 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 relay_check_digest(crypto_digest_env_t *digest, cell_t *cell) {
uint32_t received_integrity, calculated_integrity; uint32_t received_integrity, calculated_integrity;
relay_header_t rh;
relay_header_unpack(&rh, cell->payload);
received_integrity = rh.integrity;
rh.integrity = 0;
relay_header_pack(cell->payload, &rh);
received_integrity = CELL_RELAY_INTEGRITY(*cell);
log_fn(LOG_DEBUG,"Reading digest of %u from relay cell.",received_integrity); log_fn(LOG_DEBUG,"Reading digest of %u from relay cell.",received_integrity);
SET_CELL_RELAY_INTEGRITY(*cell, 0);
crypto_digest_add_bytes(digest, cell->payload, CELL_PAYLOAD_SIZE); crypto_digest_add_bytes(digest, cell->payload, CELL_PAYLOAD_SIZE);
crypto_digest_get_digest(digest, (char *)&calculated_integrity, 4); crypto_digest_get_digest(digest, (char *)&calculated_integrity, 4);
@ -346,15 +356,16 @@ int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
assert(cell && circ); assert(cell && circ);
assert(cell_direction == CELL_DIRECTION_OUT || cell_direction == CELL_DIRECTION_IN); assert(cell_direction == CELL_DIRECTION_OUT || cell_direction == CELL_DIRECTION_IN);
log_fn(LOG_DEBUG,"direction %d, streamid %d before crypt.", cell_direction, *(int*)(cell->payload+1)); log_fn(LOG_DEBUG,"direction %d, stream_id %d before crypt.", cell_direction, *(uint16_t*)(cell->payload+1));/*XXX*/
if(relay_crypt(circ, cell->payload, CELL_PAYLOAD_SIZE, cell_direction, if(relay_crypt(circ, cell->payload, cell_direction,
&layer_hint, &recognized, &conn) < 0) { &layer_hint, &recognized) < 0) {
log_fn(LOG_WARN,"relay crypt failed. Dropping connection."); log_fn(LOG_WARN,"relay crypt failed. Dropping connection.");
return -1; return -1;
} }
if(recognized) { if(recognized) {
conn = relay_lookup_conn(circ, cell, cell_direction);
if(cell_direction == CELL_DIRECTION_OUT) { if(cell_direction == CELL_DIRECTION_OUT) {
if(relay_check_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."); log_fn(LOG_WARN,"outgoing cell failed integrity check. Closing circ.");
@ -400,14 +411,14 @@ int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
return 0; return 0;
} }
int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction, static int relay_crypt(circuit_t *circ, char *in, char cell_direction,
crypt_path_t **layer_hint, char *recognized, connection_t **conn) { crypt_path_t **layer_hint, char *recognized) {
crypt_path_t *thishop; crypt_path_t *thishop;
char out[CELL_NETWORK_SIZE]; char out[CELL_PAYLOAD_SIZE]; /* 'in' must be this size too */
relay_header_t rh;
assert(circ && in && recognized && conn); assert(circ && in && recognized);
assert(cell_direction == CELL_DIRECTION_IN || cell_direction == CELL_DIRECTION_OUT);
assert(inlen < CELL_NETWORK_SIZE);
if(cell_direction == CELL_DIRECTION_IN) { if(cell_direction == CELL_DIRECTION_IN) {
if(circ->cpath) { /* we're at the beginning of the circuit. if(circ->cpath) { /* we're at the beginning of the circuit.
@ -420,16 +431,17 @@ int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction,
do { /* Remember: cpath is in forward order, that is, first hop first. */ do { /* Remember: cpath is in forward order, that is, first hop first. */
assert(thishop); assert(thishop);
log_fn(LOG_DEBUG,"before decrypt: %d",*(int*)(in+1)); log_fn(LOG_DEBUG,"before decrypt: %d",*(uint16_t*)(in+1));
/* decrypt */ /* decrypt */
if(crypto_cipher_decrypt(thishop->b_crypto, in, inlen, out)) { if(crypto_cipher_decrypt(thishop->b_crypto, in, CELL_PAYLOAD_SIZE, out)) {
log_fn(LOG_WARN,"Error performing onion decryption: %s", crypto_perror()); log_fn(LOG_WARN,"Error performing onion decryption: %s", crypto_perror());
return -1; return -1;
} }
memcpy(in,out,inlen); memcpy(in,out,CELL_PAYLOAD_SIZE);
log_fn(LOG_DEBUG,"after decrypt: %d",*(int*)(in+1)); log_fn(LOG_DEBUG,"after decrypt: %d",*(uint16_t*)(in+1));
if( (*recognized = relay_check_recognized(circ, cell_direction, in+1, conn))) { if(*(uint16_t*)(in+1) == 0) { /* XXX */
*recognized = 1;
*layer_hint = thishop; *layer_hint = thishop;
return 0; return 0;
} }
@ -440,20 +452,19 @@ int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction,
return 0; return 0;
} else { /* we're in the middle. Just one crypt. */ } else { /* we're in the middle. Just one crypt. */
log_fn(LOG_DEBUG,"before encrypt: %d",*(int*)(in+1)); log_fn(LOG_DEBUG,"before encrypt: %d",*(uint16_t*)(in+1));
if(crypto_cipher_encrypt(circ->p_crypto, in, inlen, out)) { if(crypto_cipher_encrypt(circ->p_crypto, in, CELL_PAYLOAD_SIZE, out)) {
log_fn(LOG_WARN,"Onion encryption failed for circID %u: %s", log_fn(LOG_WARN,"Onion encryption failed for circID %u: %s",
circ->p_circ_id, crypto_perror()); circ->p_circ_id, crypto_perror());
return -1; return -1;
} }
memcpy(in,out,inlen); memcpy(in,out,CELL_PAYLOAD_SIZE);
log_fn(LOG_DEBUG,"after encrypt: %d",*(int*)(in+1)); log_fn(LOG_DEBUG,"after encrypt: %d",*(uint16_t*)(in+1));
log_fn(LOG_DEBUG,"Skipping recognized check, because we're not the OP."); log_fn(LOG_DEBUG,"Skipping recognized check, because we're not the OP.");
/* don't check for recognized. only the OP can recognize a stream on the way back. */ /* don't check for recognized. only the OP can recognize a stream on the way back. */
} }
} else if(cell_direction == CELL_DIRECTION_OUT) { } else /* cell_direction == CELL_DIRECTION_OUT */ {
if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */ if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */
thishop = *layer_hint; /* we already know which layer, from when we package_raw_inbuf'ed */ thishop = *layer_hint; /* we already know which layer, from when we package_raw_inbuf'ed */
@ -461,69 +472,56 @@ int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction,
do { do {
assert(thishop); assert(thishop);
log_fn(LOG_DEBUG,"before encrypt: %d",*(int*)(in+1)); log_fn(LOG_DEBUG,"before encrypt: %d",*(uint16_t*)(in+1));
if(crypto_cipher_encrypt(thishop->f_crypto, in, inlen, out)) { if(crypto_cipher_encrypt(thishop->f_crypto, in, CELL_PAYLOAD_SIZE, out)) {
log_fn(LOG_WARN,"Error performing encryption: %s", crypto_perror()); log_fn(LOG_WARN,"Error performing encryption: %s", crypto_perror());
return -1; return -1;
} }
memcpy(in,out,inlen); memcpy(in,out,CELL_PAYLOAD_SIZE);
log_fn(LOG_DEBUG,"after encrypt: %d",*(int*)(in+1)); log_fn(LOG_DEBUG,"after encrypt: %d",*(uint16_t*)(in+1));
thishop = thishop->prev; thishop = thishop->prev;
} while(thishop != circ->cpath->prev); } while(thishop != circ->cpath->prev);
} else { /* we're in the middle. Just one crypt. */ } else { /* we're in the middle. Just one crypt. */
if(crypto_cipher_decrypt(circ->n_crypto,in, inlen, out)) { if(crypto_cipher_decrypt(circ->n_crypto,in, CELL_PAYLOAD_SIZE, out)) {
log_fn(LOG_WARN,"Decryption failed for circID %u: %s", log_fn(LOG_WARN,"Decryption failed for circID %u: %s",
circ->n_circ_id, crypto_perror()); circ->n_circ_id, crypto_perror());
return -1; return -1;
} }
memcpy(in,out,inlen); memcpy(in,out,CELL_PAYLOAD_SIZE);
if( (*recognized = relay_check_recognized(circ, cell_direction, in+1, conn))) if(*(uint16_t*)(in+1) == 0) { /* XXX */
*recognized = 1;
return 0; return 0;
}
} }
} else {
log_fn(LOG_ERR,"unknown cell direction %d.", cell_direction);
assert(0);
} }
return 0; return 0;
} }
int relay_check_recognized(circuit_t *circ, int cell_direction, char *stream, connection_t **conn) { static connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, int cell_direction) {
/* FIXME can optimize by passing thishop in */
connection_t *tmpconn; connection_t *tmpconn;
relay_header_t rh;
if(!memcmp(stream,ZERO_STREAM,STREAM_ID_SIZE)) { relay_header_unpack(&rh, cell->payload);
log_fn(LOG_DEBUG,"It's the zero stream. Recognized.");
return 1; /* the zero stream is always recognized */ if(!rh.stream_id)
} return NULL;
log_fn(LOG_DEBUG,"not the zero stream.");
if(cell_direction == CELL_DIRECTION_OUT) if(cell_direction == CELL_DIRECTION_OUT)
tmpconn = circ->n_streams; tmpconn = circ->n_streams;
else else
tmpconn = circ->p_streams; tmpconn = circ->p_streams;
if(!tmpconn) {
log_fn(LOG_DEBUG,"No conns. Not recognized.");
return 0;
}
for( ; tmpconn; tmpconn=tmpconn->next_stream) { for( ; tmpconn; tmpconn=tmpconn->next_stream) {
if(!memcmp(stream,tmpconn->stream_id, STREAM_ID_SIZE)) { if(rh.stream_id == tmpconn->stream_id) {
log_fn(LOG_DEBUG,"recognized stream %d.", *(int*)stream); log_fn(LOG_DEBUG,"found conn for stream %d.", rh.stream_id);
*conn = tmpconn; return tmpconn;
return 1;
} }
log_fn(LOG_DEBUG,"considered stream %d, not it.",*(int*)tmpconn->stream_id); log_fn(LOG_DEBUG,"considered stream %d, not it.",tmpconn->stream_id);
} }
return NULL; /* probably a begin relay cell */
log_fn(LOG_DEBUG,"Didn't recognize on this iteration of decryption.");
return 0;
} }
void circuit_resume_edge_reading(circuit_t *circ, int edge_type, crypt_path_t *layer_hint) { void circuit_resume_edge_reading(circuit_t *circ, int edge_type, crypt_path_t *layer_hint) {
@ -1060,7 +1058,7 @@ int circuit_truncated(circuit_t *circ, crypt_path_t *layer) {
for(stream = circ->p_streams; stream; stream=stream->next_stream) { for(stream = circ->p_streams; stream; stream=stream->next_stream) {
if(stream->cpath_layer == victim) { if(stream->cpath_layer == victim) {
log_fn(LOG_INFO, "Marking stream %d for close.", *(int*)stream->stream_id); log_fn(LOG_INFO, "Marking stream %d for close.", stream->stream_id);
/* no need to send 'end' relay cells, /* no need to send 'end' relay cells,
* because the other side's already dead * because the other side's already dead
*/ */

View File

@ -760,7 +760,7 @@ void assert_connection_ok(connection_t *conn, time_t now)
} }
if (conn->type != CONN_TYPE_EXIT && conn->type != CONN_TYPE_AP) { if (conn->type != CONN_TYPE_EXIT && conn->type != CONN_TYPE_AP) {
assert(!conn->stream_id[0]); assert(!conn->stream_id);
assert(!conn->next_stream); assert(!conn->next_stream);
assert(!conn->cpath_layer); assert(!conn->cpath_layer);
assert(!conn->package_window); assert(!conn->package_window);

View File

@ -20,6 +20,22 @@ static void connection_edge_consider_sending_sendme(connection_t *conn);
static uint32_t client_dns_lookup_entry(const char *address); static uint32_t client_dns_lookup_entry(const char *address);
static void client_dns_set_entry(const char *address, uint32_t val); static void client_dns_set_entry(const char *address, uint32_t val);
void relay_header_pack(char *dest, const relay_header_t *src) {
*(uint8_t*)(dest) = src->command;
*(uint16_t*)(dest+1) = htons(src->recognized);
*(uint16_t*)(dest+3) = htons(src->stream_id);
*(uint32_t*)(dest+5) = htonl(src->integrity);
*(uint16_t*)(dest+9) = htons(src->length);
}
void relay_header_unpack(relay_header_t *dest, const char *src) {
dest->command = *(uint8_t*)(src);
dest->recognized = ntohs(*(uint16_t*)(src+1));
dest->stream_id = ntohs(*(uint16_t*)(src+3));
dest->integrity = ntohl(*(uint32_t*)(src+5));
dest->length = ntohs(*(uint16_t*)(src+9));
}
int connection_edge_process_inbuf(connection_t *conn) { int connection_edge_process_inbuf(connection_t *conn) {
assert(conn); assert(conn);
@ -127,18 +143,16 @@ int connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_lay
int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int relay_command, int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int relay_command,
void *payload, int payload_len, crypt_path_t *cpath_layer) { void *payload, int payload_len, crypt_path_t *cpath_layer) {
cell_t cell; cell_t cell;
relay_header_t rh;
int cell_direction; int cell_direction;
int is_control_cell=0;
if(!circ) { if(!circ) {
log_fn(LOG_WARN,"no circ. Closing."); log_fn(LOG_WARN,"no circ. Closing.");
return -1; return -1;
} }
if(!fromconn || relay_command == RELAY_COMMAND_BEGIN) /* XXX more */
is_control_cell = 1;
memset(&cell, 0, sizeof(cell_t)); memset(&cell, 0, sizeof(cell_t));
cell.command = CELL_RELAY;
// if(fromconn && fromconn->type == CONN_TYPE_AP) { // if(fromconn && fromconn->type == CONN_TYPE_AP) {
if(cpath_layer) { if(cpath_layer) {
cell.circ_id = circ->n_circ_id; cell.circ_id = circ->n_circ_id;
@ -148,17 +162,14 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int re
cell_direction = CELL_DIRECTION_IN; cell_direction = CELL_DIRECTION_IN;
} }
cell.command = CELL_RELAY; memset(&rh, 0, sizeof(rh));
SET_CELL_RELAY_COMMAND(cell, relay_command); rh.command = relay_command;
if(is_control_cell) if(fromconn)
SET_CELL_STREAM_ID(cell, ZERO_STREAM); rh.stream_id = fromconn->stream_id; /* else it's 0 */
else rh.length = payload_len;
SET_CELL_STREAM_ID(cell, fromconn->stream_id); relay_header_pack(cell.payload, &rh);
if(payload_len)
SET_CELL_RELAY_LENGTH(cell, payload_len); memcpy(cell.payload+RELAY_HEADER_SIZE, payload, payload_len);
if(payload_len) {
memcpy(cell.payload+RELAY_HEADER_SIZE,payload,payload_len);
}
if(cell_direction == CELL_DIRECTION_OUT) /* AP */ if(cell_direction == CELL_DIRECTION_OUT) /* AP */
relay_set_digest(cpath_layer->f_digest, &cell); relay_set_digest(cpath_layer->f_digest, &cell);
@ -180,14 +191,14 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, int re
* circuit, else 0. */ * circuit, else 0. */
int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection_t *conn, int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection_t *conn,
int edge_type, crypt_path_t *layer_hint) { int edge_type, crypt_path_t *layer_hint) {
int relay_command;
static int num_seen=0; static int num_seen=0;
uint32_t addr; uint32_t addr;
relay_header_t rh;
assert(cell && circ); assert(cell && circ);
relay_command = CELL_RELAY_COMMAND(*cell); relay_header_unpack(&rh, cell->payload);
// log_fn(LOG_DEBUG,"command %d stream %d", relay_command, stream_id); // log_fn(LOG_DEBUG,"command %d stream %d", rh.command, rh.stream_id);
num_seen++; num_seen++;
log_fn(LOG_DEBUG,"Now seen %d relay cells here.", num_seen); log_fn(LOG_DEBUG,"Now seen %d relay cells here.", num_seen);
@ -195,9 +206,9 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
* conn points to the recognized stream. */ * conn points to the recognized stream. */
if(conn && conn->state != AP_CONN_STATE_OPEN && conn->state != EXIT_CONN_STATE_OPEN) { if(conn && conn->state != AP_CONN_STATE_OPEN && conn->state != EXIT_CONN_STATE_OPEN) {
if(conn->type == CONN_TYPE_EXIT && relay_command == RELAY_COMMAND_END) { if(conn->type == CONN_TYPE_EXIT && rh.command == RELAY_COMMAND_END) {
log_fn(LOG_INFO,"Exit got end (%s) before we're connected. Marking for close.", log_fn(LOG_INFO,"Exit got end (%s) before we're connected. Marking for close.",
connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, CELL_RELAY_LENGTH(*cell))); connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh.length));
if(conn->state == EXIT_CONN_STATE_RESOLVING) { if(conn->state == EXIT_CONN_STATE_RESOLVING) {
log_fn(LOG_INFO,"...and informing resolver we don't want the answer anymore."); log_fn(LOG_INFO,"...and informing resolver we don't want the answer anymore.");
dns_cancel_pending_resolve(conn->address, conn); dns_cancel_pending_resolve(conn->address, conn);
@ -207,14 +218,14 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
return 0; return 0;
} else { } else {
log_fn(LOG_WARN,"Got an unexpected relay command %d, in state %d (%s). Closing.", log_fn(LOG_WARN,"Got an unexpected relay command %d, in state %d (%s). Closing.",
relay_command, conn->state, conn_state_to_string[conn->type][conn->state]); rh.command, conn->state, conn_state_to_string[conn->type][conn->state]);
if(connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer) < 0) if(connection_edge_end(conn, END_STREAM_REASON_MISC, conn->cpath_layer) < 0)
log_fn(LOG_WARN,"1: I called connection_edge_end redundantly."); log_fn(LOG_WARN,"1: I called connection_edge_end redundantly.");
return -1; return -1;
} }
} }
switch(relay_command) { switch(rh.command) {
case RELAY_COMMAND_BEGIN: case RELAY_COMMAND_BEGIN:
if(edge_type == EDGE_AP) { if(edge_type == EDGE_AP) {
log_fn(LOG_WARN,"relay begin request unsupported at AP. Dropping."); log_fn(LOG_WARN,"relay begin request unsupported at AP. Dropping.");
@ -235,12 +246,13 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
log_fn(LOG_WARN,"2: I called connection_edge_end redundantly."); log_fn(LOG_WARN,"2: I called connection_edge_end redundantly.");
return -1; return -1;
} }
log_fn(LOG_DEBUG,"circ deliver_window now %d.", edge_type == EDGE_AP ? layer_hint->deliver_window : circ->deliver_window); log_fn(LOG_DEBUG,"circ deliver_window now %d.", edge_type == EDGE_AP ?
layer_hint->deliver_window : circ->deliver_window);
circuit_consider_sending_sendme(circ, edge_type, layer_hint); circuit_consider_sending_sendme(circ, edge_type, layer_hint);
if(!conn) { if(!conn) {
log_fn(LOG_INFO,"relay cell dropped, unknown stream %d.",*(int*)conn->stream_id); log_fn(LOG_INFO,"data cell dropped, unknown stream.");
return 0; return 0;
} }
@ -249,19 +261,18 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
return -1; /* somebody's breaking protocol. kill the whole circuit. */ return -1; /* somebody's breaking protocol. kill the whole circuit. */
} }
stats_n_data_bytes_received += CELL_RELAY_LENGTH(*cell); stats_n_data_bytes_received += rh.length;
connection_write_to_buf(cell->payload + RELAY_HEADER_SIZE, connection_write_to_buf(cell->payload + RELAY_HEADER_SIZE,
CELL_RELAY_LENGTH(*cell), conn); rh.length, conn);
connection_edge_consider_sending_sendme(conn); connection_edge_consider_sending_sendme(conn);
return 0; return 0;
case RELAY_COMMAND_END: case RELAY_COMMAND_END:
if(!conn) { if(!conn) {
log_fn(LOG_INFO,"end cell (%s) dropped, unknown stream %d.", log_fn(LOG_INFO,"end cell (%s) dropped, unknown stream.",
connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, CELL_RELAY_LENGTH(*cell)), connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh.length));
*(int*)conn->stream_id);
return 0; return 0;
} }
if(CELL_RELAY_LENGTH(*cell) >= 5 && if(rh.length >= 5 &&
*(cell->payload+RELAY_HEADER_SIZE) == END_STREAM_REASON_EXITPOLICY) { *(cell->payload+RELAY_HEADER_SIZE) == END_STREAM_REASON_EXITPOLICY) {
/* No need to close the connection. We'll hold it open while /* No need to close the connection. We'll hold it open while
* we try a new exit node. * we try a new exit node.
@ -282,8 +293,8 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
} }
} }
log_fn(LOG_INFO,"end cell (%s) for stream %d. Removing stream.", log_fn(LOG_INFO,"end cell (%s) for stream %d. Removing stream.",
connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, CELL_RELAY_LENGTH(*cell)), connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh.length),
*(int*)conn->stream_id); conn->stream_id);
#ifdef HALF_OPEN #ifdef HALF_OPEN
conn->done_sending = 1; conn->done_sending = 1;
@ -344,11 +355,11 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
return 0; return 0;
} }
if(!conn) { if(!conn) {
log_fn(LOG_INFO,"connected cell dropped, unknown stream %d.",*(int*)conn->stream_id); log_fn(LOG_INFO,"connected cell dropped, unknown stream.");
return 0; return 0;
} }
log_fn(LOG_INFO,"Connected! Notifying application."); log_fn(LOG_INFO,"Connected! Notifying application.");
if (CELL_RELAY_LENGTH(*cell) >= 4) { if (rh.length >= 4) {
addr = ntohl(*(uint32_t*)(cell->payload + RELAY_HEADER_SIZE)); addr = ntohl(*(uint32_t*)(cell->payload + RELAY_HEADER_SIZE));
client_dns_set_entry(conn->socks_request->address, addr); client_dns_set_entry(conn->socks_request->address, addr);
} }
@ -363,12 +374,14 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
if(edge_type == EDGE_AP) { if(edge_type == EDGE_AP) {
assert(layer_hint); assert(layer_hint);
layer_hint->package_window += CIRCWINDOW_INCREMENT; layer_hint->package_window += CIRCWINDOW_INCREMENT;
log_fn(LOG_DEBUG,"circ-level sendme at AP, packagewindow %d.", layer_hint->package_window); log_fn(LOG_DEBUG,"circ-level sendme at AP, packagewindow %d.",
layer_hint->package_window);
circuit_resume_edge_reading(circ, EDGE_AP, layer_hint); circuit_resume_edge_reading(circ, EDGE_AP, layer_hint);
} else { } else {
assert(!layer_hint); assert(!layer_hint);
circ->package_window += CIRCWINDOW_INCREMENT; circ->package_window += CIRCWINDOW_INCREMENT;
log_fn(LOG_DEBUG,"circ-level sendme at exit, packagewindow %d.", circ->package_window); log_fn(LOG_DEBUG,"circ-level sendme at exit, packagewindow %d.",
circ->package_window);
circuit_resume_edge_reading(circ, EDGE_EXIT, layer_hint); circuit_resume_edge_reading(circ, EDGE_EXIT, layer_hint);
} }
return 0; return 0;
@ -378,11 +391,8 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
connection_start_reading(conn); connection_start_reading(conn);
connection_edge_package_raw_inbuf(conn); /* handle whatever might still be on the inbuf */ connection_edge_package_raw_inbuf(conn); /* handle whatever might still be on the inbuf */
return 0; return 0;
default:
log_fn(LOG_WARN,"unknown relay command %d.",relay_command);
return -1;
} }
assert(0); log_fn(LOG_WARN,"unknown relay command %d.",rh.command);
return -1; return -1;
} }
@ -667,20 +677,19 @@ static void connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t
assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT); assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
assert(ap_conn->socks_request); assert(ap_conn->socks_request);
crypto_pseudo_rand(STREAM_ID_SIZE, ap_conn->stream_id); crypto_pseudo_rand(sizeof(ap_conn->stream_id), (unsigned char*) &ap_conn->stream_id);
/* FIXME check for collisions */ /* XXX check for collisions */
in.s_addr = htonl(client_dns_lookup_entry(ap_conn->socks_request->address)); in.s_addr = htonl(client_dns_lookup_entry(ap_conn->socks_request->address));
string_addr = in.s_addr ? inet_ntoa(in) : NULL; string_addr = in.s_addr ? inet_ntoa(in) : NULL;
memcpy(payload, ap_conn->stream_id, STREAM_ID_SIZE); snprintf(payload,RELAY_PAYLOAD_SIZE,
payload_len = STREAM_ID_SIZE + 1 + "%s:%d",
snprintf(payload+STREAM_ID_SIZE,CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE-STREAM_ID_SIZE, string_addr ? string_addr : ap_conn->socks_request->address,
"%s:%d", ap_conn->socks_request->port);
string_addr ? string_addr : ap_conn->socks_request->address, payload_len = strlen(payload)+1;
ap_conn->socks_request->port);
log_fn(LOG_DEBUG,"Sending relay cell to begin stream %d.",*(int *)ap_conn->stream_id); log_fn(LOG_DEBUG,"Sending relay cell to begin stream %d.",ap_conn->stream_id);
if(connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_BEGIN, if(connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_BEGIN,
payload, payload_len, ap_conn->cpath_layer) < 0) payload, payload_len, ap_conn->cpath_layer) < 0)
@ -734,18 +743,20 @@ static int connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) { static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
connection_t *n_stream; connection_t *n_stream;
relay_header_t rh;
char *colon; char *colon;
relay_header_unpack(&rh, cell->payload);
/* XXX currently we don't send an end cell back if we drop the /* XXX currently we don't send an end cell back if we drop the
* begin because it's malformed. * begin because it's malformed.
*/ */
if(!memchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE,0, if(!memchr(cell->payload+RELAY_HEADER_SIZE, 0, rh.length)) {
CELL_RELAY_LENGTH(*cell)-STREAM_ID_SIZE)) {
log_fn(LOG_WARN,"relay begin cell has no \\0. Dropping."); log_fn(LOG_WARN,"relay begin cell has no \\0. Dropping.");
return 0; return 0;
} }
colon = strchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE, ':'); colon = strchr(cell->payload+RELAY_HEADER_SIZE, ':');
if(!colon) { if(!colon) {
log_fn(LOG_WARN,"relay begin cell has no colon. Dropping."); log_fn(LOG_WARN,"relay begin cell has no colon. Dropping.");
return 0; return 0;
@ -760,8 +771,8 @@ static int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
log_fn(LOG_DEBUG,"Creating new exit connection."); log_fn(LOG_DEBUG,"Creating new exit connection.");
n_stream = connection_new(CONN_TYPE_EXIT); n_stream = connection_new(CONN_TYPE_EXIT);
memcpy(n_stream->stream_id, cell->payload + RELAY_HEADER_SIZE, STREAM_ID_SIZE); n_stream->stream_id = rh.stream_id;
n_stream->address = tor_strdup(cell->payload + RELAY_HEADER_SIZE + STREAM_ID_SIZE); n_stream->address = tor_strdup(cell->payload + RELAY_HEADER_SIZE);
n_stream->port = atoi(colon+1); n_stream->port = atoi(colon+1);
n_stream->state = EXIT_CONN_STATE_RESOLVING; n_stream->state = EXIT_CONN_STATE_RESOLVING;
/* leave n_stream->s at -1, because it's not yet valid */ /* leave n_stream->s at -1, because it's not yet valid */

View File

@ -235,36 +235,45 @@ typedef uint16_t circ_id_t;
/* /*
* Relay payload: * Relay payload:
* Relay command [1 byte] * Relay command [1 byte]
* Stream ID [7 bytes] * Recognized [2 bytes]
* Stream ID [2 bytes]
* Partial SHA-1 [4 bytes] * Partial SHA-1 [4 bytes]
* Length [2 bytes] * Length [2 bytes]
* Relay payload [495 bytes] * Relay payload [498 bytes]
*/ */
#if 0
#define CELL_RELAY_COMMAND(c) (*(uint8_t*)((c).payload)) #define CELL_RELAY_COMMAND(c) (*(uint8_t*)((c).payload))
#define SET_CELL_RELAY_COMMAND(c,cmd) (*(uint8_t*)((c).payload) = (cmd)) #define SET_CELL_RELAY_COMMAND(c,cmd) (*(uint8_t*)((c).payload) = (cmd))
#define STREAM_ID_SIZE 7 #define CELL_RELAY_RECOGNIZED(c) (ntohs(*(uint16_t*)((c).payload+1)))
#define SET_CELL_STREAM_ID(c,id) memcpy((c).payload+1,(id),STREAM_ID_SIZE) #define SET_CELL_RELAY_RECOGNIZED(c,r) (*(uint16_t*)((c).payload+1) = htons(r))
#define ZERO_STREAM "\0\0\0\0\0\0\0"
#define CELL_RELAY_COMMAND_END_REASON(c) (*(uint8_t)((c).payload+1)) #define STREAM_ID_SIZE 2
//#define SET_CELL_STREAM_ID(c,id) memcpy((c).payload+1,(id),STREAM_ID_SIZE)
#define CELL_RELAY_STREAM_ID(c) (ntohs(*(uint16_t*)((c).payload+3)))
#define SET_CELL_RELAY_STREAM_ID(c,id) (*(uint16_t*)((c).payload+3) = htons(id))
#define ZERO_STREAM 0
/* integrity is the first 32 bits (in network order) of a sha-1 of all /* 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 * cell payloads that are relay cells that have been sent / delivered
* to the hop on the * circuit (the integrity is zeroed while doing * to the hop on the * circuit (the integrity is zeroed while doing
* each calculation) * each calculation)
*/ */
#define CELL_RELAY_INTEGRITY(c) (ntohl(*(uint32_t*)((c).payload+1+STREAM_ID_SIZE))) #define CELL_RELAY_INTEGRITY(c) (ntohl(*(uint32_t*)((c).payload+5)))
#define SET_CELL_RELAY_INTEGRITY(c,i) (*(uint32_t*)((c).payload+1+STREAM_ID_SIZE) = htonl(i)) #define SET_CELL_RELAY_INTEGRITY(c,i) (*(uint32_t*)((c).payload+5) = htonl(i))
/* relay length is how many bytes are used in the cell payload past relay_header_size */ /* relay length is how many bytes are used in the cell payload past relay_header_size */
#define CELL_RELAY_LENGTH(c) (ntohs(*(uint16_t*)((c).payload+1+STREAM_ID_SIZE+4))) #define CELL_RELAY_LENGTH(c) (ntohs(*(uint16_t*)((c).payload+9)))
#define SET_CELL_RELAY_LENGTH(c,len) (*(uint16_t*)((c).payload+1+STREAM_ID_SIZE+4) = htons(len)) #define SET_CELL_RELAY_LENGTH(c,len) (*(uint16_t*)((c).payload+9) = htons(len))
#endif
#define CELL_PAYLOAD_SIZE 509 #define CELL_PAYLOAD_SIZE 509
#define CELL_NETWORK_SIZE 512 #define CELL_NETWORK_SIZE 512
#define RELAY_HEADER_SIZE (1+2+2+4+2)
#define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE)
/* cell definition */ /* cell definition */
typedef struct { typedef struct {
circ_id_t circ_id; circ_id_t circ_id;
@ -272,8 +281,13 @@ typedef struct {
unsigned char payload[CELL_PAYLOAD_SIZE]; unsigned char payload[CELL_PAYLOAD_SIZE];
} cell_t; } cell_t;
#define RELAY_HEADER_SIZE (1+STREAM_ID_SIZE+4+2) typedef struct {
#define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) uint8_t command;
uint16_t recognized;
uint16_t stream_id;
uint32_t integrity;
uint16_t length;
} relay_header_t;
typedef struct buf_t buf_t; typedef struct buf_t buf_t;
typedef struct socks_request_t socks_request_t; typedef struct socks_request_t socks_request_t;
@ -327,7 +341,7 @@ struct connection_t {
*/ */
/* Used only by edge connections: */ /* Used only by edge connections: */
char stream_id[STREAM_ID_SIZE]; uint16_t stream_id;
struct connection_t *next_stream; /* points to the next stream at this edge, if any */ struct connection_t *next_stream; /* points to the next stream at this edge, if any */
struct crypt_path_t *cpath_layer; /* a pointer to which node in the circ this conn exits at */ struct crypt_path_t *cpath_layer; /* a pointer to which node in the circ this conn exits at */
int package_window; /* how many more relay cells can i send into the circuit? */ int package_window; /* how many more relay cells can i send into the circuit? */
@ -556,9 +570,6 @@ 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 relay_check_digest(crypto_digest_env_t *digest, cell_t *cell);
int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ, int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
int cell_direction, crypt_path_t *layer_hint); int cell_direction, crypt_path_t *layer_hint);
int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction,
crypt_path_t **layer_hint, char *recognized, connection_t **conn);
int relay_check_recognized(circuit_t *circ, int cell_direction, char *stream, connection_t **conn);
void circuit_resume_edge_reading(circuit_t *circ, int edge_type, crypt_path_t *layer_hint); 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_stop_edge_reading(circuit_t *circ, int edge_type, crypt_path_t *layer_hint);
@ -648,6 +659,8 @@ void assert_connection_ok(connection_t *conn, time_t now);
/********************************* connection_edge.c ***************************/ /********************************* connection_edge.c ***************************/
void relay_header_pack(char *dest, const relay_header_t *src);
void relay_header_unpack(relay_header_t *dest, const char *src);
int connection_edge_process_inbuf(connection_t *conn); int connection_edge_process_inbuf(connection_t *conn);
int connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer); int connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer);