Commit 96759a60 authored by Roger Dingledine's avatar Roger Dingledine
Browse files

streams are now 8 bytes, and are recognized by intermediate hops

the OP only crypts the appropriate number of times depending on which
layer (hop on the path) it's for/from.


svn:r262
parent bb75b142
......@@ -281,7 +281,8 @@ circuit_t *circuit_get_newest_ap(void) {
return bestcirc;
}
int circuit_deliver_relay_cell_from_edge(cell_t *cell, circuit_t *circ, char edge_type) {
int circuit_deliver_relay_cell_from_edge(cell_t *cell, circuit_t *circ,
char edge_type, crypt_path_t *layer_hint) {
int cell_direction;
static int numsent_ap=0, numsent_exit=0;
......@@ -293,7 +294,7 @@ int circuit_deliver_relay_cell_from_edge(cell_t *cell, circuit_t *circ, char edg
log(LOG_DEBUG,"circuit_deliver_relay_cell_from_edge(): now sent %d relay cells from ap", numsent_ap);
if(circ->p_receive_circwindow <= 0) {
log(LOG_DEBUG,"circuit_deliver_relay_cell_from_edge(): pwindow 0, queueing for later.");
circ->relay_queue = relay_queue_add(circ->relay_queue, cell);
circ->relay_queue = relay_queue_add(circ->relay_queue, cell, layer_hint);
return 0;
}
circ->p_receive_circwindow--;
......@@ -304,13 +305,13 @@ int circuit_deliver_relay_cell_from_edge(cell_t *cell, circuit_t *circ, char edg
log(LOG_DEBUG,"circuit_deliver_relay_cell_from_edge(): now sent %d relay cells from exit", numsent_exit);
if(circ->n_receive_circwindow <= 0) {
log(LOG_DEBUG,"circuit_deliver_relay_cell_from_edge(): nwindow 0, queueing for later.");
circ->relay_queue = relay_queue_add(circ->relay_queue, cell);
circ->relay_queue = relay_queue_add(circ->relay_queue, cell, layer_hint);
return 0;
}
circ->n_receive_circwindow--;
}
if(circuit_deliver_relay_cell(cell, circ, cell_direction) < 0) {
if(circuit_deliver_relay_cell(cell, circ, cell_direction, layer_hint) < 0) {
return -1;
}
......@@ -318,113 +319,168 @@ int circuit_deliver_relay_cell_from_edge(cell_t *cell, circuit_t *circ, char edg
return 0;
}
int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction) {
connection_t *conn;
int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
int cell_direction, crypt_path_t *layer_hint) {
connection_t *conn=NULL;
char recognized=0;
char buf[256];
assert(cell && circ);
assert(cell_direction == CELL_DIRECTION_OUT || cell_direction == CELL_DIRECTION_IN);
if(cell_direction == CELL_DIRECTION_OUT)
conn = circ->n_conn;
else
conn = circ->p_conn;
/* first crypt cell->length */
if(circuit_crypt(circ, &(cell->length), 1, cell_direction) < 0) {
log(LOG_DEBUG,"circuit_deliver_relay_cell(): length crypt failed. Dropping connection.");
return -1;
}
buf[0] = cell->length;
memcpy(buf+1, cell->payload, CELL_PAYLOAD_SIZE);
/* then crypt the payload */
if(circuit_crypt(circ, (char *)&(cell->payload), CELL_PAYLOAD_SIZE, cell_direction) < 0) {
log(LOG_DEBUG,"circuit_deliver_relay_cell(): payload crypt failed. Dropping connection.");
log(LOG_DEBUG,"circuit_deliver_relay_cell(): streamid %d before crypt.", *(int*)(cell->payload+1));
if(relay_crypt(circ, buf, 1+CELL_PAYLOAD_SIZE, cell_direction, layer_hint, &recognized, &conn) < 0) {
log(LOG_DEBUG,"circuit_deliver_relay_cell(): relay crypt failed. Dropping connection.");
return -1;
}
if(cell_direction == CELL_DIRECTION_OUT && (!conn || conn->type == CONN_TYPE_EXIT)) {
log(LOG_DEBUG,"circuit_deliver_relay_cell(): Sending to exit.");
return connection_edge_process_relay_cell(cell, circ, EDGE_EXIT);
cell->length = buf[0];
memcpy(cell->payload, buf+1, CELL_PAYLOAD_SIZE);
if(recognized) {
if(cell_direction == CELL_DIRECTION_OUT) {
log(LOG_DEBUG,"circuit_deliver_relay_cell(): Sending to exit.");
return connection_edge_process_relay_cell(cell, circ, conn, EDGE_EXIT);
}
if(cell_direction == CELL_DIRECTION_IN) {
log(LOG_DEBUG,"circuit_deliver_relay_cell(): Sending to AP.");
return connection_edge_process_relay_cell(cell, circ, conn, EDGE_AP);
}
}
if(cell_direction == CELL_DIRECTION_IN && (!conn || conn->type == CONN_TYPE_AP)) {
log(LOG_DEBUG,"circuit_deliver_relay_cell(): Sending to AP.");
return connection_edge_process_relay_cell(cell, circ, EDGE_AP);
/* not recognized. pass it on. */
if(cell_direction == CELL_DIRECTION_OUT)
conn = circ->n_conn;
else
conn = circ->p_conn;
if(!conn || !connection_speaks_cells(conn)) {
log(LOG_INFO,"circuit_deliver_relay_cell(): Didn't recognize cell (%d), but circ stops here! Dropping.", *(int *)(cell->payload+1));
return 0;
}
/* else send it as a cell */
assert(conn);
//log(LOG_DEBUG,"circuit_deliver_relay_cell(): Sending to connection.");
return connection_write_cell_to_buf(cell, conn);
}
int circuit_crypt(circuit_t *circ, char *in, int inlen, char cell_direction) {
char *out;
int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction,
crypt_path_t *layer_hint, char *recognized, connection_t **conn) {
crypt_path_t *thishop;
char out[256];
assert(circ && in);
assert(circ && in && recognized && conn);
out = (char *)malloc(inlen);
if(!out)
return -1;
assert(inlen < 256);
if(cell_direction == CELL_DIRECTION_IN) {
if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */
thishop = circ->cpath;
/* Remember: cpath is in forward order, that is, first hop first. */
do {
do { /* Remember: cpath is in forward order, that is, first hop first. */
assert(thishop);
/* decrypt */
if(crypto_cipher_decrypt(thishop->b_crypto, in, inlen, out)) {
log(LOG_ERR,"Error performing decryption:%s",crypto_perror());
free(out);
return -1;
}
/* copy ciphertext back to buf */
memcpy(in,out,inlen);
if( (*recognized = relay_check_recognized(circ, cell_direction, in+2, conn)))
return 0;
thishop = thishop->next;
} while(thishop != circ->cpath);
log(LOG_INFO,"relay_crypt(): in-cell at OP not recognized. Killing circuit.");
return -1;
} else { /* we're in the middle. Just one crypt. */
if(crypto_cipher_encrypt(circ->p_crypto,in, inlen, out)) {
if(crypto_cipher_encrypt(circ->p_crypto, in, inlen, out)) {
log(LOG_ERR,"circuit_encrypt(): Encryption failed for ACI : %u (%s).",
circ->p_aci, crypto_perror());
free(out);
return -1;
}
memcpy(in,out,inlen);
/* don't check for recognized. only the OP can recognize a stream on the way back. */
}
} else if(cell_direction == CELL_DIRECTION_OUT) {
if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */
thishop = circ->cpath->prev;
thishop = layer_hint; /* we already know which layer, from when we package_raw_inbuf'ed */
/* moving from last to first hop */
do {
assert(thishop);
/* encrypt */
if(crypto_cipher_encrypt(thishop->f_crypto, in, inlen, (unsigned char *)out)) {
if(crypto_cipher_encrypt(thishop->f_crypto, in, inlen, out)) {
log(LOG_ERR,"Error performing encryption:%s",crypto_perror());
free(out);
return -1;
}
/* copy ciphertext back to buf */
memcpy(in,out,inlen);
thishop = thishop->prev;
} while(thishop != circ->cpath->prev);
} else { /* we're in the middle. Just one crypt. */
if(crypto_cipher_decrypt(circ->n_crypto,in, inlen, out)) {
log(LOG_ERR,"circuit_crypt(): Decryption failed for ACI : %u (%s).",
circ->n_aci, crypto_perror());
free(out);
return -1;
}
memcpy(in,out,inlen);
if( (*recognized = relay_check_recognized(circ, cell_direction, in+2, conn)))
return 0;
}
} else {
log(LOG_ERR,"circuit_crypt(): unknown cell direction %d.", cell_direction);
assert(0);
}
free(out);
return 0;
}
int relay_check_recognized(circuit_t *circ, int cell_direction, char *stream, connection_t **conn) {
/* FIXME can optimize by passing thishop in */
connection_t *tmpconn;
log(LOG_DEBUG,"relay_check_recognized(): entering");
if(!memcmp(stream,ZERO_STREAM,STREAM_ID_SIZE))
return 1; /* the zero stream is always recognized */
if(cell_direction == CELL_DIRECTION_OUT)
tmpconn = circ->n_conn;
else
tmpconn = circ->p_conn;
log(LOG_DEBUG,"relay_check_recognized(): not the zero stream.");
if(!tmpconn)
return 0; /* no conns? don't recognize it */
while(tmpconn && tmpconn->type == CONN_TYPE_OR) {
log(LOG_DEBUG,"relay_check_recognized(): skipping over an OR conn");
tmpconn = tmpconn->next_stream;
}
for( ; tmpconn; tmpconn=tmpconn->next_stream) {
if(!memcmp(stream,tmpconn->stream_id, STREAM_ID_SIZE)) {
log(LOG_DEBUG,"relay_check_recognized(): recognized stream %d.", *(int*)stream);
*conn = tmpconn;
return 1;
}
log(LOG_DEBUG,"relay_check_recognized(): considered stream %d, not it.",*(int*)tmpconn->stream_id);
}
log(LOG_DEBUG,"relay_check_recognized(): Didn't recognize. Giving up.");
return 0;
}
void circuit_resume_edge_reading(circuit_t *circ, int edge_type) {
connection_t *conn;
struct relay_queue_t *tmpd;
......@@ -438,7 +494,7 @@ void circuit_resume_edge_reading(circuit_t *circ, int edge_type) {
circ->n_receive_circwindow--;
assert(circ->n_receive_circwindow >= 0);
if(circuit_deliver_relay_cell(circ->relay_queue->cell, circ, CELL_DIRECTION_IN) < 0) {
if(circuit_deliver_relay_cell(circ->relay_queue->cell, circ, CELL_DIRECTION_IN, circ->relay_queue->layer_hint) < 0) {
circuit_close(circ);
return;
}
......@@ -446,7 +502,7 @@ void circuit_resume_edge_reading(circuit_t *circ, int edge_type) {
circ->p_receive_circwindow--;
assert(circ->p_receive_circwindow >= 0);
if(circuit_deliver_relay_cell(circ->relay_queue->cell, circ, CELL_DIRECTION_OUT) < 0) {
if(circuit_deliver_relay_cell(circ->relay_queue->cell, circ, CELL_DIRECTION_OUT, circ->relay_queue->layer_hint) < 0) {
circuit_close(circ);
return;
}
......
......@@ -241,14 +241,14 @@ void command_process_relay_cell(cell_t *cell, connection_t *conn) {
if(cell->aci == circ->p_aci) { /* it's an outgoing cell */
cell->aci = circ->n_aci; /* switch it */
if(circuit_deliver_relay_cell(cell, circ, CELL_DIRECTION_OUT) < 0) {
if(circuit_deliver_relay_cell(cell, circ, CELL_DIRECTION_OUT, conn->cpath_layer) < 0) {
log(LOG_INFO,"command_process_relay_cell(): circuit_deliver_relay_cell (forward) failed. Closing.");
circuit_close(circ);
return;
}
} else { /* it's an ingoing cell */
cell->aci = circ->p_aci; /* switch it */
if(circuit_deliver_relay_cell(cell, circ, CELL_DIRECTION_IN) < 0) {
if(circuit_deliver_relay_cell(cell, circ, CELL_DIRECTION_IN, NULL) < 0) {
log(LOG_DEBUG,"command_process_relay_cell(): circuit_deliver_relay_cell (backward) failed. Closing.");
circuit_close(circ);
return;
......
......@@ -706,7 +706,7 @@ repeat_connection_package_raw_inbuf:
if(conn->type == CONN_TYPE_EXIT) {
cell.aci = circ->p_aci;
if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_EXIT) < 0) {
if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_EXIT, NULL) < 0) {
log(LOG_DEBUG,"connection_package_raw_inbuf(): circuit_deliver_relay_cell_from_edge (backward) failed. Closing.");
circuit_close(circ);
return 0;
......@@ -721,7 +721,7 @@ repeat_connection_package_raw_inbuf:
} else { /* send it forward. we're an AP */
assert(conn->type == CONN_TYPE_AP);
cell.aci = circ->n_aci;
if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_AP) < 0) {
if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_AP, conn->cpath_layer) < 0) {
log(LOG_DEBUG,"connection_package_raw_inbuf(): circuit_deliver_relay_cell_from_edge (forward) failed. Closing.");
circuit_close(circ);
return 0;
......@@ -763,7 +763,7 @@ int connection_consider_sending_sendme(connection_t *conn, int edge_type) {
log(LOG_DEBUG,"connection_consider_sending_sendme(): Outbuf %d, Queueing stream sendme back.", conn->outbuf_flushlen);
conn->p_receive_streamwindow += STREAMWINDOW_INCREMENT;
cell.aci = circ->p_aci;
if(circuit_deliver_relay_cell_from_edge(&cell, circ, edge_type) < 0) {
if(circuit_deliver_relay_cell_from_edge(&cell, circ, edge_type, NULL) < 0) {
log(LOG_DEBUG,"connection_consider_sending_sendme(): circuit_deliver_relay_cell_from_edge (backward) failed. Closing.");
circuit_close(circ);
return 0;
......@@ -775,7 +775,7 @@ int connection_consider_sending_sendme(connection_t *conn, int edge_type) {
log(LOG_DEBUG,"connection_consider_sending_sendme(): Outbuf %d, Queueing stream sendme forward.", conn->outbuf_flushlen);
conn->n_receive_streamwindow += STREAMWINDOW_INCREMENT;
cell.aci = circ->n_aci;
if(circuit_deliver_relay_cell_from_edge(&cell, circ, edge_type) < 0) {
if(circuit_deliver_relay_cell_from_edge(&cell, circ, edge_type, conn->cpath_layer) < 0) {
log(LOG_DEBUG,"connection_consider_sending_sendme(): circuit_deliver_relay_cell_from_edge (forward) failed. Closing.");
circuit_close(circ);
return 0;
......
......@@ -108,6 +108,10 @@ int ap_handshake_process_socks(connection_t *conn) {
conn->next_stream = circ->p_conn;
circ->p_conn = conn;
assert(circ->cpath && circ->cpath->prev);
assert(circ->cpath->prev->state == CPATH_STATE_OPEN);
conn->cpath_layer = circ->cpath->prev;
if(ap_handshake_send_begin(conn, circ) < 0) {
circuit_close(circ);
return -1;
......@@ -118,23 +122,24 @@ int ap_handshake_process_socks(connection_t *conn) {
int ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ) {
cell_t cell;
uint16_t stream_id;
memset(&cell, 0, sizeof(cell_t));
/* deliver the dest_addr in a relay cell */
cell.command = CELL_RELAY;
cell.aci = circ->n_aci;
SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_BEGIN);
if (CRYPTO_PSEUDO_RAND_INT(stream_id))
if(crypto_pseudo_rand(STREAM_ID_SIZE, ap_conn->stream_id) < 0)
return -1;
SET_CELL_STREAM_ID(cell, stream_id);
/* FIXME check for collisions */
ap_conn->stream_id = stream_id;
snprintf(cell.payload+4, CELL_PAYLOAD_SIZE-4, "%s:%d", ap_conn->dest_addr, ap_conn->dest_port);
cell.length = strlen(cell.payload+RELAY_HEADER_SIZE)+1+RELAY_HEADER_SIZE;
log(LOG_DEBUG,"ap_handshake_send_begin(): Sending relay cell to begin stream %d.", ap_conn->stream_id);
if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_AP) < 0) {
SET_CELL_STREAM_ID(cell, ZERO_STREAM);
memcpy(cell.payload+RELAY_HEADER_SIZE, ap_conn->stream_id, STREAM_ID_SIZE);
cell.length =
snprintf(cell.payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE, CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE-STREAM_ID_SIZE,
"%s:%d", ap_conn->dest_addr, ap_conn->dest_port) +
1 + STREAM_ID_SIZE + RELAY_HEADER_SIZE;
log(LOG_DEBUG,"ap_handshake_send_begin(): Sending relay cell (id %d) to begin stream %d.", *(int *)(cell.payload+1),*(int *)ap_conn->stream_id);
if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_AP, ap_conn->cpath_layer) < 0) {
log(LOG_DEBUG,"ap_handshake_send_begin(): failed to deliver begin cell. Closing.");
return -1;
}
......
......@@ -31,7 +31,7 @@ int connection_edge_process_inbuf(connection_t *conn) {
SET_CELL_STREAM_ID(cell, conn->stream_id);
cell.aci = circ->n_aci;
if (circuit_deliver_relay_cell_from_edge(&cell, circ, conn->type) < 0) {
if (circuit_deliver_relay_cell_from_edge(&cell, circ, conn->type, conn->cpath_layer) < 0) {
log(LOG_DEBUG,"connection_edge_process_inbuf: circuit_deliver_relay_cell_from_edge failed. Closing");
circuit_close(circ);
}
......@@ -82,18 +82,16 @@ int connection_edge_send_command(connection_t *conn, circuit_t *circ, int relay_
cell.length = RELAY_HEADER_SIZE;
log(LOG_INFO,"connection_edge_send_command(): delivering %d cell %s.", relay_command, conn->type == CONN_TYPE_AP ? "forward" : "backward");
if(circuit_deliver_relay_cell_from_edge(&cell, circ, conn->type) < 0) {
log(LOG_DEBUG,"connection_edge_send_command(): circuit_deliver_relay_cell failed. Closing.");
if(circuit_deliver_relay_cell_from_edge(&cell, circ, conn->type, conn->cpath_layer) < 0) {
log(LOG_DEBUG,"connection_edge_send_command(): circuit_deliver_relay_cell_from_edge failed. Closing.");
circuit_close(circ);
return 0;
}
return 0;
}
int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, int edge_type) {
connection_t *conn;
int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection_t *conn, int edge_type) {
int relay_command;
int stream_id;
static int num_seen=0;
/* an incoming relay cell has arrived */
......@@ -101,23 +99,14 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, int edge_t
assert(cell && circ);
relay_command = CELL_RELAY_COMMAND(*cell);
stream_id = CELL_STREAM_ID(*cell);
log(LOG_DEBUG,"connection_edge_process_relay_cell(): command %d stream %d", relay_command, stream_id);
// log(LOG_DEBUG,"connection_edge_process_relay_cell(): command %d stream %d", relay_command, stream_id);
num_seen++;
log(LOG_DEBUG,"connection_edge_process_relay_cell(): Now seen %d relay cells here.", num_seen);
circuit_consider_sending_sendme(circ, edge_type);
if(edge_type == EDGE_AP)
conn = circ->p_conn;
else
conn = circ->n_conn;
for( ; conn && conn->stream_id != stream_id; conn = conn->next_stream) ;
/* now conn is either NULL, in which case we don't recognize the stream_id, or
* it is set, in which case cell is talking about this conn.
*/
/* either conn is NULL, in which case we've got a control cell, or else
* conn points to the recognized stream. */
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) {
......@@ -143,7 +132,7 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, int edge_t
}
case RELAY_COMMAND_DATA:
if(!conn) {
log(LOG_DEBUG,"connection_edge_process_relay_cell(): relay cell dropped, unknown stream %d.",stream_id);
log(LOG_DEBUG,"connection_edge_process_relay_cell(): relay cell dropped, unknown stream %d.",*(int*)conn->stream_id);
return 0;
}
if((edge_type == EDGE_AP && --conn->n_receive_streamwindow < 0) ||
......@@ -172,10 +161,10 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, int edge_t
return 0;
case RELAY_COMMAND_END:
if(!conn) {
log(LOG_DEBUG,"connection_edge_process_relay_cell(): end cell dropped, unknown stream %d.",stream_id);
log(LOG_DEBUG,"connection_edge_process_relay_cell(): end cell dropped, unknown stream %d.",*(int*)conn->stream_id);
return 0;
}
log(LOG_DEBUG,"connection_edge_process_relay_cell(): end cell for stream %d. Removing stream.",stream_id);
log(LOG_DEBUG,"connection_edge_process_relay_cell(): end cell for stream %d. Removing stream.",*(int*)conn->stream_id);
/* go through and identify who points to conn. remove conn from the list. */
#if 0
......@@ -199,7 +188,7 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, int edge_t
return 0;
}
if(!conn) {
log(LOG_DEBUG,"connection_edge_process_relay_cell(): connected cell dropped, unknown stream %d.",stream_id);
log(LOG_DEBUG,"connection_edge_process_relay_cell(): connected cell dropped, unknown stream %d.",*(int*)conn->stream_id);
break;
}
log(LOG_DEBUG,"connection_edge_process_relay_cell(): Connected! Notifying application.");
......@@ -209,7 +198,7 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, int edge_t
break;
case RELAY_COMMAND_SENDME:
if(!conn) {
log(LOG_DEBUG,"connection_edge_process_relay_cell(): sendme cell dropped, unknown stream %d.",stream_id);
log(LOG_DEBUG,"connection_edge_process_relay_cell(): sendme cell dropped, unknown stream %d.",*(int*)conn->stream_id);
return 0;
}
if(edge_type == EDGE_AP)
......
......@@ -8,11 +8,11 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
connection_t *n_conn;
char *colon;
if(!memchr(cell->payload + RELAY_HEADER_SIZE,0,cell->length - RELAY_HEADER_SIZE)) {
if(!memchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE,0,cell->length-RELAY_HEADER_SIZE-STREAM_ID_SIZE)) {
log(LOG_WARNING,"connection_exit_begin_conn(): relay begin cell has no \\0. Dropping.");
return 0;
}
colon = strchr(cell->payload + RELAY_HEADER_SIZE, ':');
colon = strchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE, ':');
if(!colon) {
log(LOG_WARNING,"connection_exit_begin_conn(): relay begin cell has no colon. Dropping.");
return 0;
......@@ -31,10 +31,8 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
return 0;
}
// cell->payload[0] = 0;
n_conn->stream_id = CELL_STREAM_ID(*cell);
n_conn->address = strdup(cell->payload + RELAY_HEADER_SIZE);
memcpy(n_conn->stream_id, cell->payload + RELAY_HEADER_SIZE, STREAM_ID_SIZE);
n_conn->address = strdup(cell->payload + RELAY_HEADER_SIZE + STREAM_ID_SIZE);
n_conn->port = atoi(colon+1);
n_conn->state = EXIT_CONN_STATE_RESOLVING;
n_conn->receiver_bucket = -1; /* edge connections don't do receiver buckets */
......
......@@ -141,13 +141,14 @@ void onion_pending_remove(circuit_t *circ) {
}
struct relay_queue_t *relay_queue_add(struct relay_queue_t *list, cell_t *cell) {
struct relay_queue_t *relay_queue_add(struct relay_queue_t *list, cell_t *cell, crypt_path_t *layer_hint) {
struct relay_queue_t *tmpd, *newd;
newd = malloc(sizeof(struct relay_queue_t));
memset(newd, 0, sizeof(struct relay_queue_t));
newd->cell = malloc(sizeof(cell_t));
memcpy(newd->cell, cell, sizeof(cell_t));
newd->layer_hint = layer_hint;
if(!list) {
return newd;
......@@ -167,7 +168,7 @@ void onion_pending_relay_add(circuit_t *circ, cell_t *cell) {
for(tmpo=ol_list; tmpo; tmpo=tmpo->next) {
if(tmpo->circ == circ) {
tmpo->relay_cells = relay_queue_add(tmpo->relay_cells, cell);
tmpo->relay_cells = relay_queue_add(tmpo->relay_cells, cell, NULL);
return;
}
}
......
......@@ -128,7 +128,7 @@
#define RELAY_COMMAND_CONNECTED 4
#define RELAY_COMMAND_SENDME 5
#define RELAY_HEADER_SIZE 4
#define RELAY_HEADER_SIZE 8
#define RELAY_STATE_RESOLVING
......@@ -195,15 +195,17 @@ typedef uint16_t aci_t;
typedef struct {
aci_t aci; /* Anonymous Connection Identifier */
unsigned char command;
unsigned char length; /* of payload if relay cell, else value of sendme */
unsigned char length; /* of payload if relay cell */
uint32_t seq; /* sequence number */
unsigned char payload[CELL_PAYLOAD_SIZE];
} cell_t;
#define CELL_RELAY_COMMAND(c) (*(uint8_t*)((c).payload))
#define SET_CELL_RELAY_COMMAND(c,cmd) (*(uint8_t*)((c).payload) = (cmd))
#define CELL_STREAM_ID(c) ntohs(*(uint16_t*)((c).payload+2))
#define SET_CELL_STREAM_ID(c,id) (*(uint16_t*)((c).payload+2) = htons(id))
#define STREAM_ID_SIZE 7
#define SET_CELL_STREAM_ID(c,id) memcpy((c).payload+1,(id),STREAM_ID_SIZE)
#define ZERO_STREAM "\0\0\0\0\0\0\0\0"
#define SOCKS4_REQUEST_GRANTED 90
#define SOCKS4_REQUEST_REJECT 91
......@@ -265,8 +267,9 @@ struct connection_t {
uint16_t port;
/* used by exit and ap: */
uint16_t stream_id;
char stream_id[STREAM_ID_SIZE];
struct connection_t *next_stream;
struct crypt_path_t *cpath_layer; /* a pointer to which node in the circ this conn exits at */
int n_receive_streamwindow;
int p_receive_streamwindow;
int done_sending;
......@@ -335,7 +338,7 @@ typedef struct {
void *next;
} routerinfo_t;
typedef struct {
struct crypt_path_t {
char digest2[20]; /* second SHA output for onion_layer_t.keyseed */
char digest3[20]; /* third SHA output for onion_layer_t.keyseed */
......@@ -347,13 +350,16 @@ typedef struct {
#define CPATH_STATE_CLOSED 0
#define CPATH_STATE_AWAITING_KEY 1
#define CPATH_STATE_OPEN 2
void *next;
void *prev; /* doubly linked list */
struct crypt_path_t *next;
struct crypt_path_t *prev; /* doubly linked list */
};
} crypt_path_t;
typedef struct crypt_path_t crypt_path_t;
struct relay_queue_t {
cell_t *cell;
crypt_path_t *layer_hint;
struct relay_queue_t *next;
};
......@@ -506,9 +512,13 @@ circuit_t *circuit_get_by_conn(connection_t *conn);
circuit_t *circuit_get_newest_ap(void);
circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *start, uint32_t naddr, uint16_t nport);
int circuit_deliver_relay_cell_from_edge(cell_t *cell, circuit_t *circ, char edge_type);
int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ, int crypt_type);
int circuit_crypt(circuit_t *circ, char *in, int inlen, char crypt_type);
int circuit_deliver_relay_cell_from_edge(cell_t *cell, circuit_t *circ,
char edge_type, crypt_path_t *layer_hint);
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,
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);
int circuit_consider_stop_edge_reading(circuit_t *circ, int edge_type);
......@@ -645,7 +655,7 @@ int connection_ap_handle_listener_read(connection_t *conn);
int connection_edge_process_inbuf(connection_t *conn);
int connection_edge_send_command(connection_t *conn, circuit_t *circ, int relay_command);
int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, int edge_type);
int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection_t *conn, int edge_type);
int connection_edge_finished_flushing(connection_t *conn);
/********************************* connection_exit.c ***************************/
......@@ -753,7 +763,7 @@ int onion_pending_add(circuit_t *circ);
int onion_pending_check(void);
void onion_pending_process_one(void);
void onion_pending_remove(circuit_t *circ);
struct relay_queue_t *relay_queue_add(struct relay_queue_t *list, cell_t *cell);
struct relay_queue_t *relay_queue_add(struct relay_queue_t