mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-20 10:12:15 +01:00
incremental path building in; uses ephemeral DH; onions are gone
still need to change circuit-level sendmes svn:r264
This commit is contained in:
parent
44b4efe34d
commit
d7f50337c1
368
src/or/circuit.c
368
src/or/circuit.c
@ -65,7 +65,7 @@ circuit_t *circuit_new(aci_t p_aci, connection_t *p_conn) {
|
||||
circ->p_aci = p_aci;
|
||||
circ->p_conn = p_conn;
|
||||
|
||||
circ->state = CIRCUIT_STATE_ONION_WAIT;
|
||||
circ->state = CIRCUIT_STATE_ONIONSKIN_PENDING;
|
||||
|
||||
/* ACIs */
|
||||
circ->p_aci = p_aci;
|
||||
@ -87,8 +87,6 @@ void circuit_free(circuit_t *circ) {
|
||||
if (circ->p_crypto)
|
||||
crypto_free_cipher_env(circ->p_crypto);
|
||||
|
||||
if(circ->onion)
|
||||
free(circ->onion);
|
||||
circuit_free_cpath(circ->cpath);
|
||||
while(circ->relay_queue) {
|
||||
tmpd = circ->relay_queue;
|
||||
@ -122,6 +120,8 @@ void circuit_free_cpath_node(crypt_path_t *victim) {
|
||||
crypto_free_cipher_env(victim->f_crypto);
|
||||
if(victim->b_crypto)
|
||||
crypto_free_cipher_env(victim->b_crypto);
|
||||
if(victim->handshake_state)
|
||||
crypto_dh_free(victim->handshake_state);
|
||||
free(victim);
|
||||
}
|
||||
|
||||
@ -155,66 +155,6 @@ try_again:
|
||||
return test_aci;
|
||||
}
|
||||
|
||||
int circuit_init(circuit_t *circ, int aci_type, onion_layer_t *layer) {
|
||||
unsigned char iv[16];
|
||||
unsigned char digest1[20];
|
||||
unsigned char digest2[20];
|
||||
struct timeval start, end;
|
||||
long time_passed;
|
||||
|
||||
assert(circ && circ->onion);
|
||||
|
||||
log(LOG_DEBUG,"circuit_init(): starting");
|
||||
circ->n_port = layer->port;
|
||||
log(LOG_DEBUG,"circuit_init(): Set port to %u.",circ->n_port);
|
||||
circ->n_addr = layer->addr;
|
||||
circ->state = CIRCUIT_STATE_OPEN;
|
||||
|
||||
log(LOG_DEBUG,"circuit_init(): aci_type = %u.",aci_type);
|
||||
|
||||
my_gettimeofday(&start);
|
||||
|
||||
circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, aci_type);
|
||||
if(!circ->n_aci) {
|
||||
log(LOG_ERR,"circuit_init(): failed to get unique aci.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
my_gettimeofday(&end);
|
||||
|
||||
time_passed = tv_udiff(&start, &end);
|
||||
if (time_passed > 1000) {/* more than 1ms */
|
||||
log(LOG_NOTICE,"circuit_init(): get_unique_aci just took %d us!",time_passed);
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"circuit_init(): Chosen ACI %u.",circ->n_aci);
|
||||
|
||||
/* keys */
|
||||
memset(iv, 0, 16);
|
||||
crypto_SHA_digest(layer->keyseed,16,digest1);
|
||||
crypto_SHA_digest(digest1,20,digest2);
|
||||
crypto_SHA_digest(digest2,20,digest1);
|
||||
log(LOG_DEBUG,"circuit_init(): Computed keys.");
|
||||
|
||||
if (!(circ->p_crypto =
|
||||
crypto_create_init_cipher(DEFAULT_CIPHER,digest2,iv,1))) {
|
||||
log(LOG_ERR,"Cipher initialization failed (ACI %u).",circ->n_aci);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(circ->n_crypto =
|
||||
crypto_create_init_cipher(DEFAULT_CIPHER,digest1,iv,0))) {
|
||||
log(LOG_ERR,"Cipher initialization failed (ACI %u).",circ->n_aci);
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"circuit_init(): Cipher initialization complete.");
|
||||
|
||||
circ->expire = layer->expire;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
circuit_t *circuit_enumerate_by_naddr_nport(circuit_t *circ, uint32_t naddr, uint16_t nport) {
|
||||
|
||||
if(!circ) /* use circ if it's defined, else start from the beginning */
|
||||
@ -269,13 +209,11 @@ circuit_t *circuit_get_newest_ap(void) {
|
||||
circuit_t *circ, *bestcirc=NULL;
|
||||
|
||||
for(circ=global_circuitlist;circ;circ = circ->next) {
|
||||
if(!circ->p_conn || circ->p_conn->type == CONN_TYPE_AP) {
|
||||
if(circ->state == CIRCUIT_STATE_OPEN && (!bestcirc ||
|
||||
bestcirc->timestamp_created < circ->timestamp_created)) {
|
||||
log(LOG_DEBUG,"circuit_get_newest_ap(): Choosing n_aci %d.", circ->n_aci);
|
||||
assert(circ->n_aci);
|
||||
bestcirc = circ;
|
||||
}
|
||||
if(circ->cpath && circ->state == CIRCUIT_STATE_OPEN && (!bestcirc ||
|
||||
bestcirc->timestamp_created < circ->timestamp_created)) {
|
||||
log(LOG_DEBUG,"circuit_get_newest_ap(): Choosing n_aci %d.", circ->n_aci);
|
||||
assert(circ->n_aci);
|
||||
bestcirc = circ;
|
||||
}
|
||||
}
|
||||
return bestcirc;
|
||||
@ -331,7 +269,7 @@ int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
buf[0] = cell->length;
|
||||
memcpy(buf+1, cell->payload, CELL_PAYLOAD_SIZE);
|
||||
|
||||
log(LOG_DEBUG,"circuit_deliver_relay_cell(): streamid %d before crypt.", *(int*)(cell->payload+1));
|
||||
log(LOG_DEBUG,"circuit_deliver_relay_cell(): direction %d, streamid %d before crypt.", cell_direction, *(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.");
|
||||
@ -363,6 +301,7 @@ int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
|
||||
return 0;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"circuit_deliver_relay_cell(): Passing on unrecognized cell.");
|
||||
return connection_write_cell_to_buf(cell, conn);
|
||||
}
|
||||
|
||||
@ -378,32 +317,42 @@ int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction,
|
||||
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;
|
||||
if(thishop->state != CPATH_STATE_OPEN) {
|
||||
log(LOG_INFO,"relay_crypt(): Relay cell before first created cell?");
|
||||
return -1;
|
||||
}
|
||||
do { /* Remember: cpath is in forward order, that is, first hop first. */
|
||||
assert(thishop);
|
||||
|
||||
log(LOG_DEBUG,"relay_crypt(): before decrypt: %d",*(int*)(in+2));
|
||||
/* decrypt */
|
||||
if(crypto_cipher_decrypt(thishop->b_crypto, in, inlen, out)) {
|
||||
log(LOG_ERR,"Error performing decryption:%s",crypto_perror());
|
||||
return -1;
|
||||
}
|
||||
memcpy(in,out,inlen);
|
||||
log(LOG_DEBUG,"relay_crypt(): after decrypt: %d",*(int*)(in+2));
|
||||
|
||||
if( (*recognized = relay_check_recognized(circ, cell_direction, in+2, conn)))
|
||||
return 0;
|
||||
|
||||
thishop = thishop->next;
|
||||
} while(thishop != circ->cpath);
|
||||
} while(thishop != circ->cpath && thishop->state == CPATH_STATE_OPEN);
|
||||
log(LOG_INFO,"relay_crypt(): in-cell at OP not recognized. Killing circuit.");
|
||||
return -1;
|
||||
return 0;
|
||||
// return -1;
|
||||
} else { /* we're in the middle. Just one crypt. */
|
||||
|
||||
log(LOG_DEBUG,"relay_crypt(): before encrypt: %d",*(int*)(in+2));
|
||||
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());
|
||||
return -1;
|
||||
}
|
||||
memcpy(in,out,inlen);
|
||||
log(LOG_DEBUG,"relay_crypt(): after encrypt: %d",*(int*)(in+2));
|
||||
|
||||
log(LOG_DEBUG,"circuit_encrypt(): 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. */
|
||||
|
||||
}
|
||||
@ -415,12 +364,13 @@ int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction,
|
||||
do {
|
||||
assert(thishop);
|
||||
|
||||
/* encrypt */
|
||||
log(LOG_DEBUG,"relay_crypt(): before encrypt: %d",*(int*)(in+2));
|
||||
if(crypto_cipher_encrypt(thishop->f_crypto, in, inlen, out)) {
|
||||
log(LOG_ERR,"Error performing encryption:%s",crypto_perror());
|
||||
return -1;
|
||||
}
|
||||
memcpy(in,out,inlen);
|
||||
log(LOG_DEBUG,"relay_crypt(): after encrypt: %d",*(int*)(in+2));
|
||||
|
||||
thishop = thishop->prev;
|
||||
} while(thishop != circ->cpath->prev);
|
||||
@ -450,8 +400,10 @@ int relay_check_recognized(circuit_t *circ, int cell_direction, char *stream, co
|
||||
connection_t *tmpconn;
|
||||
|
||||
log(LOG_DEBUG,"relay_check_recognized(): entering");
|
||||
if(!memcmp(stream,ZERO_STREAM,STREAM_ID_SIZE))
|
||||
if(!memcmp(stream,ZERO_STREAM,STREAM_ID_SIZE)) {
|
||||
log(LOG_DEBUG,"relay_check_recognized(): It's the zero stream. Recognized.");
|
||||
return 1; /* the zero stream is always recognized */
|
||||
}
|
||||
|
||||
if(cell_direction == CELL_DIRECTION_OUT)
|
||||
tmpconn = circ->n_conn;
|
||||
@ -459,8 +411,10 @@ int relay_check_recognized(circuit_t *circ, int cell_direction, char *stream, co
|
||||
tmpconn = circ->p_conn;
|
||||
|
||||
log(LOG_DEBUG,"relay_check_recognized(): not the zero stream.");
|
||||
if(!tmpconn)
|
||||
if(!tmpconn) {
|
||||
log(LOG_DEBUG,"relay_check_recognized(): No conns. Not recognized.");
|
||||
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");
|
||||
@ -723,7 +677,7 @@ retry_circuit:
|
||||
return;
|
||||
}
|
||||
|
||||
if(circuit_create_onion() < 0) {
|
||||
if(circuit_establish_circuit() < 0) {
|
||||
failures++;
|
||||
goto retry_circuit;
|
||||
}
|
||||
@ -732,50 +686,21 @@ retry_circuit:
|
||||
return;
|
||||
}
|
||||
|
||||
int circuit_create_onion(void) {
|
||||
int routelen; /* length of the route */
|
||||
unsigned int *route; /* hops in the route as an array of indexes into rarray */
|
||||
unsigned char *onion; /* holds the onion */
|
||||
int onionlen; /* onion length in host order */
|
||||
crypt_path_t *cpath; /* defines the crypt operations that need to be performed on incoming/outgoing data */
|
||||
|
||||
/* choose a route */
|
||||
route = (unsigned int *)router_new_route(&routelen);
|
||||
if (!route) {
|
||||
log(LOG_ERR,"circuit_create_onion(): Error choosing a route through the OR network.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"circuit_create_onion(): Chosen a route of length %u : ",routelen);
|
||||
|
||||
/* create an onion and calculate crypto keys */
|
||||
onion = router_create_onion(route,routelen,&onionlen, &cpath);
|
||||
if (!onion) {
|
||||
log(LOG_ERR,"circuit_create_onion(): Error creating an onion.");
|
||||
free(route);
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"circuit_create_onion(): Created an onion of size %u bytes.",onionlen);
|
||||
// log(LOG_DEBUG,"circuit_create_onion(): Crypt path :");
|
||||
|
||||
return circuit_establish_circuit(route, routelen, onion, onionlen, cpath);
|
||||
}
|
||||
|
||||
int circuit_establish_circuit(unsigned int *route, int routelen, char *onion,
|
||||
int onionlen, crypt_path_t *cpath) {
|
||||
int circuit_establish_circuit(void) {
|
||||
routerinfo_t *firsthop;
|
||||
connection_t *n_conn;
|
||||
circuit_t *circ;
|
||||
|
||||
/* now see if we're already connected to the first OR in 'route' */
|
||||
firsthop = router_get_first_in_route(route, routelen);
|
||||
assert(firsthop); /* should always be defined */
|
||||
free(route); /* we don't need it anymore */
|
||||
|
||||
circ = circuit_new(0, NULL); /* sets circ->p_aci and circ->p_conn */
|
||||
circ->state = CIRCUIT_STATE_OR_WAIT;
|
||||
circ->onion = onion;
|
||||
circ->onionlen = onionlen;
|
||||
circ->cpath = cpath;
|
||||
circ->cpath = onion_generate_cpath(&firsthop);
|
||||
if(!circ->cpath) {
|
||||
log(LOG_DEBUG,"circuit_establish_circuit(): Generating cpath failed.");
|
||||
circuit_close(circ);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now see if we're already connected to the first OR in 'route' */
|
||||
|
||||
log(LOG_DEBUG,"circuit_establish_circuit(): Looking for firsthop '%s:%u'",
|
||||
firsthop->address,firsthop->or_port);
|
||||
@ -798,14 +723,22 @@ int circuit_establish_circuit(unsigned int *route, int routelen, char *onion,
|
||||
}
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"circuit_establish_circuit(): connecting in progress (or finished). Good.");
|
||||
return 0; /* return success. The onion/circuit/etc will be taken care of automatically
|
||||
* (may already have been) whenever n_conn reaches OR_CONN_STATE_OPEN.
|
||||
*/
|
||||
} else { /* it (or a twin) is already open. use it. */
|
||||
circ->n_addr = n_conn->addr;
|
||||
circ->n_port = n_conn->port;
|
||||
return circuit_send_onion(n_conn, circ);
|
||||
circ->n_conn = n_conn;
|
||||
log(LOG_DEBUG,"circuit_establish_circuit(): Conn open. Delivering first onion skin.");
|
||||
if(circuit_send_next_onion_skin(circ) < 0) {
|
||||
log(LOG_DEBUG,"circuit_establish_circuit(): circuit_send_next_onion_skin failed.");
|
||||
circuit_close(circ);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* find circuits that are waiting on me, if any, and get them to send the onion */
|
||||
@ -818,8 +751,9 @@ void circuit_n_conn_open(connection_t *or_conn) {
|
||||
if(!circ)
|
||||
return;
|
||||
|
||||
log(LOG_DEBUG,"circuit_n_conn_open(): Found circ, sending onion.");
|
||||
if(circuit_send_onion(or_conn, circ) < 0) {
|
||||
log(LOG_DEBUG,"circuit_n_conn_open(): Found circ, sending onion skin.");
|
||||
circ->n_conn = or_conn;
|
||||
if(circuit_send_next_onion_skin(circ) < 0) {
|
||||
log(LOG_DEBUG,"circuit_n_conn_open(): circuit marked for closing.");
|
||||
circuit_close(circ);
|
||||
return; /* FIXME will want to try the other circuits too? */
|
||||
@ -828,50 +762,182 @@ void circuit_n_conn_open(connection_t *or_conn) {
|
||||
}
|
||||
}
|
||||
|
||||
int circuit_send_onion(connection_t *n_conn, circuit_t *circ) {
|
||||
int circuit_send_next_onion_skin(circuit_t *circ) {
|
||||
cell_t cell;
|
||||
int tmpbuflen, dataleft;
|
||||
char *tmpbuf;
|
||||
crypt_path_t *hop;
|
||||
routerinfo_t *router;
|
||||
|
||||
circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, ACI_TYPE_BOTH);
|
||||
circ->n_conn = n_conn;
|
||||
log(LOG_DEBUG,"circuit_send_onion(): n_conn is %s:%u",n_conn->address,n_conn->port);
|
||||
assert(circ && circ->cpath);
|
||||
|
||||
/* deliver the onion as one or more create cells */
|
||||
cell.command = CELL_CREATE;
|
||||
cell.aci = circ->n_aci;
|
||||
if(circ->cpath->state == CPATH_STATE_CLOSED) {
|
||||
|
||||
tmpbuflen = circ->onionlen+4;
|
||||
tmpbuf = malloc(tmpbuflen);
|
||||
if(!tmpbuf)
|
||||
return -1;
|
||||
*(uint32_t*)tmpbuf = htonl(circ->onionlen);
|
||||
memcpy(tmpbuf+4, circ->onion, circ->onionlen);
|
||||
log(LOG_DEBUG,"circuit_send_next_onion_skin(): First skin; sending create cell.");
|
||||
circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, ACI_TYPE_BOTH);
|
||||
|
||||
dataleft = tmpbuflen;
|
||||
while(dataleft) {
|
||||
memset(&cell, 0, sizeof(cell_t));
|
||||
cell.command = CELL_CREATE;
|
||||
cell.aci = circ->n_aci;
|
||||
log(LOG_DEBUG,"circuit_send_onion(): Sending a create cell for the onion...");
|
||||
if(dataleft >= CELL_PAYLOAD_SIZE) {
|
||||
cell.length = CELL_PAYLOAD_SIZE;
|
||||
memcpy(cell.payload, tmpbuf + tmpbuflen - dataleft, CELL_PAYLOAD_SIZE);
|
||||
connection_write_cell_to_buf(&cell, n_conn);
|
||||
dataleft -= CELL_PAYLOAD_SIZE;
|
||||
} else { /* last cell */
|
||||
cell.length = dataleft;
|
||||
memcpy(cell.payload, tmpbuf + tmpbuflen - dataleft, dataleft);
|
||||
/* fill extra space with 0 bytes */
|
||||
memset(cell.payload + dataleft, 0, CELL_PAYLOAD_SIZE - dataleft);
|
||||
connection_write_cell_to_buf(&cell, n_conn);
|
||||
dataleft = 0;
|
||||
cell.length = 208;
|
||||
|
||||
if(onion_skin_create(circ->n_conn->pkey, &(circ->cpath->handshake_state), cell.payload) < 0) {
|
||||
log(LOG_INFO,"circuit_send_next_onion_skin(): onion_skin_create (first hop) failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(connection_write_cell_to_buf(&cell, circ->n_conn) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
|
||||
circ->state = CIRCUIT_STATE_BUILDING;
|
||||
log(LOG_DEBUG,"circuit_send_next_onion_skin(): first skin; finished sending create cell.");
|
||||
} else {
|
||||
assert(circ->cpath->state == CPATH_STATE_OPEN);
|
||||
assert(circ->state == CIRCUIT_STATE_BUILDING);
|
||||
log(LOG_DEBUG,"circuit_send_next_onion_skin(): starting to send subsequent skin.");
|
||||
for(hop=circ->cpath->next;
|
||||
hop != circ->cpath && hop->state == CPATH_STATE_OPEN;
|
||||
hop=hop->next) ;
|
||||
if(hop == circ->cpath) { /* done building the circuit. whew. */
|
||||
circ->state = CIRCUIT_STATE_OPEN;
|
||||
log(LOG_DEBUG,"circuit_send_next_onion_skin(): circuit built!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
router = router_get_by_addr_port(hop->addr,hop->port);
|
||||
if(!router) {
|
||||
log(LOG_INFO,"circuit_send_next_onion_skin(): couldn't lookup router %d:%d",hop->addr,hop->port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&cell, 0, sizeof(cell_t));
|
||||
cell.command = CELL_RELAY;
|
||||
cell.aci = circ->n_aci;
|
||||
SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_EXTEND);
|
||||
SET_CELL_STREAM_ID(cell, ZERO_STREAM);
|
||||
|
||||
cell.length = RELAY_HEADER_SIZE + 6 + 208;
|
||||
*(uint32_t*)(cell.payload+RELAY_HEADER_SIZE) = htonl(hop->addr);
|
||||
*(uint32_t*)(cell.payload+RELAY_HEADER_SIZE+4) = htons(hop->port);
|
||||
if(onion_skin_create(router->pkey, &(hop->handshake_state), cell.payload+RELAY_HEADER_SIZE+6) < 0) {
|
||||
log(LOG_INFO,"circuit_send_next_onion_skin(): onion_skin_create failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"circuit_send_next_onion_skin(): Sending extend relay cell.");
|
||||
/* send it to hop->prev, because it will transfer it to a create cell and then send to hop */
|
||||
if(circuit_deliver_relay_cell_from_edge(&cell, circ, EDGE_AP, hop->prev) < 0) {
|
||||
log(LOG_DEBUG,"circuit_send_next_onion_skin(): failed to deliver extend cell. Closing.");
|
||||
return -1;
|
||||
}
|
||||
hop->state = CPATH_STATE_AWAITING_KEYS;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* take the 'extend' cell, pull out addr/port plus the onion skin. Connect
|
||||
* to the next hop, and pass it the onion skin in a create cell.
|
||||
*/
|
||||
int circuit_extend(cell_t *cell, circuit_t *circ) {
|
||||
connection_t *n_conn;
|
||||
aci_t aci_type;
|
||||
struct sockaddr_in me; /* my router identity */
|
||||
cell_t newcell;
|
||||
|
||||
circ->n_addr = ntohl(*(uint32_t*)(cell->payload+RELAY_HEADER_SIZE));
|
||||
circ->n_port = ntohs(*(uint16_t*)(cell->payload+RELAY_HEADER_SIZE+4));
|
||||
|
||||
if(learn_my_address(&me) < 0)
|
||||
return -1;
|
||||
|
||||
n_conn = connection_twin_get_by_addr_port(circ->n_addr,circ->n_port);
|
||||
if(!n_conn || n_conn->type != CONN_TYPE_OR) {
|
||||
/* i've disabled making connections through OPs, but it's definitely
|
||||
* possible here. I'm not sure if it would be a bug or a feature. -RD
|
||||
*/
|
||||
/* note also that this will close circuits where the onion has the same
|
||||
* router twice in a row in the path. i think that's ok. -RD
|
||||
*/
|
||||
log(LOG_DEBUG,"circuit_extend(): Next router not connected. Closing.");
|
||||
/* XXX later we should fail more gracefully here, like with a 'truncated' */
|
||||
return -1;
|
||||
}
|
||||
|
||||
circ->n_addr = n_conn->addr; /* these are different if we found a twin instead */
|
||||
circ->n_port = n_conn->port;
|
||||
|
||||
circ->n_conn = n_conn;
|
||||
log(LOG_DEBUG,"circuit_extend(): n_conn is %s:%u",n_conn->address,n_conn->port);
|
||||
|
||||
aci_type = decide_aci_type(ntohl(me.sin_addr.s_addr), ntohs(me.sin_port),
|
||||
circ->n_addr, circ->n_port);
|
||||
|
||||
log(LOG_DEBUG,"circuit_extend(): aci_type = %u.",aci_type);
|
||||
circ->n_aci = get_unique_aci_by_addr_port(circ->n_addr, circ->n_port, aci_type);
|
||||
if(!circ->n_aci) {
|
||||
log(LOG_ERR,"circuit_extend(): failed to get unique aci.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"circuit_extend(): Chosen ACI %u.",circ->n_aci);
|
||||
|
||||
memset(&newcell, 0, sizeof(cell_t));
|
||||
newcell.command = CELL_CREATE;
|
||||
newcell.aci = circ->n_aci;
|
||||
newcell.length = 208;
|
||||
|
||||
memcpy(newcell.payload, cell->payload+RELAY_HEADER_SIZE+6, 208);
|
||||
|
||||
if(connection_write_cell_to_buf(&newcell, circ->n_conn) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int circuit_finish_handshake(circuit_t *circ, char *reply) {
|
||||
unsigned char iv[16];
|
||||
unsigned char keys[32];
|
||||
crypt_path_t *hop;
|
||||
|
||||
memset(iv, 0, 16);
|
||||
|
||||
assert(circ->cpath);
|
||||
if(circ->cpath->state == CPATH_STATE_AWAITING_KEYS)
|
||||
hop = circ->cpath;
|
||||
else {
|
||||
for(hop=circ->cpath->next;
|
||||
hop != circ->cpath && hop->state == CPATH_STATE_OPEN;
|
||||
hop=hop->next) ;
|
||||
if(hop == circ->cpath) { /* got an extended when we're all done? */
|
||||
log(LOG_INFO,"circuit_finish_handshake(): got extended when circ already built? Weird.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
free(tmpbuf);
|
||||
assert(hop->state == CPATH_STATE_AWAITING_KEYS);
|
||||
|
||||
circ->state = CIRCUIT_STATE_OPEN;
|
||||
/* FIXME should set circ->expire to something here */
|
||||
if(onion_skin_client_handshake(hop->handshake_state, reply, keys, 32) < 0) {
|
||||
log(LOG_ERR,"circuit_finish_handshake(): onion_skin_client_handshake failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto_dh_free(hop->handshake_state); /* don't need it anymore */
|
||||
hop->handshake_state = NULL;
|
||||
|
||||
log(LOG_DEBUG,"circuit_finish_handshake(): hop %d init cipher forward %d, backward %d.", hop, *(int*)keys, *(int*)(keys+16));
|
||||
if (!(hop->f_crypto =
|
||||
crypto_create_init_cipher(DEFAULT_CIPHER,keys,iv,1))) {
|
||||
log(LOG_ERR,"Cipher initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(hop->b_crypto =
|
||||
crypto_create_init_cipher(DEFAULT_CIPHER,keys+16,iv,0))) {
|
||||
log(LOG_ERR,"Cipher initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hop->state = CPATH_STATE_OPEN;
|
||||
log(LOG_DEBUG,"circuit_finish_handshake(): Completed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
136
src/or/command.c
136
src/or/command.c
@ -28,8 +28,8 @@ void command_time_process_cell(cell_t *cell, connection_t *conn,
|
||||
}
|
||||
|
||||
void command_process_cell(cell_t *cell, connection_t *conn) {
|
||||
static int num_create=0, num_relay=0, num_destroy=0, num_sendme=0;
|
||||
static int create_time=0, relay_time=0, destroy_time=0, sendme_time=0;
|
||||
static int num_create=0, num_created=0, num_relay=0, num_destroy=0, num_sendme=0;
|
||||
static int create_time=0, created_time=0, relay_time=0, destroy_time=0, sendme_time=0;
|
||||
static long current_second = 0; /* from previous calls to gettimeofday */
|
||||
struct timeval now;
|
||||
|
||||
@ -39,18 +39,20 @@ void command_process_cell(cell_t *cell, connection_t *conn) {
|
||||
/* print stats */
|
||||
log(LOG_INFO,"At end of second:");
|
||||
log(LOG_INFO,"Create: %d (%d ms)", num_create, create_time/1000);
|
||||
log(LOG_INFO,"Created: %d (%d ms)", num_created, created_time/1000);
|
||||
log(LOG_INFO,"Relay: %d (%d ms)", num_relay, relay_time/1000);
|
||||
log(LOG_INFO,"Destroy: %d (%d ms)", num_destroy, destroy_time/1000);
|
||||
log(LOG_INFO,"Sendme: %d (%d ms)", num_sendme, sendme_time/1000);
|
||||
|
||||
/* zero out stats */
|
||||
num_create = num_relay = num_destroy = num_sendme = 0;
|
||||
create_time = relay_time = destroy_time = sendme_time = 0;
|
||||
num_create = num_created = num_relay = num_destroy = num_sendme = 0;
|
||||
create_time = created_time = relay_time = destroy_time = sendme_time = 0;
|
||||
|
||||
/* remember which second it is, for next time */
|
||||
current_second = now.tv_sec;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"command_process_cell(): Examining cell type %d.", cell->command);
|
||||
switch(cell->command) {
|
||||
case CELL_PADDING:
|
||||
/* do nothing */
|
||||
@ -59,6 +61,10 @@ void command_process_cell(cell_t *cell, connection_t *conn) {
|
||||
command_time_process_cell(cell, conn, &num_create, &create_time,
|
||||
command_process_create_cell);
|
||||
break;
|
||||
case CELL_CREATED:
|
||||
command_time_process_cell(cell, conn, &num_created, &created_time,
|
||||
command_process_created_cell);
|
||||
break;
|
||||
case CELL_RELAY:
|
||||
command_time_process_cell(cell, conn, &num_relay, &relay_time,
|
||||
command_process_relay_cell);
|
||||
@ -82,61 +88,77 @@ void command_process_create_cell(cell_t *cell, connection_t *conn) {
|
||||
|
||||
circ = circuit_get_by_aci_conn(cell->aci, conn);
|
||||
|
||||
if(circ && circ->state != CIRCUIT_STATE_ONION_WAIT) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): received CREATE cell, not in onion_wait. Dropping.");
|
||||
if(circ) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): received CREATE cell for known circ. Dropping.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!circ) { /* if it's not there, create it */
|
||||
circ = circuit_new(cell->aci, conn);
|
||||
circ->state = CIRCUIT_STATE_ONION_WAIT;
|
||||
circ->onionlen = ntohl(*(int*)cell->payload);
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Onion length is %u.",circ->onionlen);
|
||||
if(circ->onionlen > 50000 || circ->onionlen < 1) { /* too big or too small */
|
||||
log(LOG_DEBUG,"That's ludicrous. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
circ->onion = malloc(circ->onionlen);
|
||||
if(!circ->onion) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Out of memory. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
if(circ->onionlen < cell->length-4) { /* protect from buffer overflow */
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Onion too small. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
memcpy((void *)circ->onion,(void *)(cell->payload+4),cell->length-4);
|
||||
circ->recvlen = cell->length-4;
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Primary create cell handled, have received %d of %d onion bytes.",
|
||||
circ->recvlen,circ->onionlen);
|
||||
|
||||
} else { /* pull over as much of the onion as we can */
|
||||
if(cell->length + circ->recvlen > circ->onionlen) { /* protect from buffer overflow */
|
||||
log(LOG_DEBUG,"command_process_create_cell(): payload too big for onion. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
memcpy((void *)(circ->onion+circ->recvlen),(void *)cell->payload,cell->length);
|
||||
circ->recvlen += cell->length;
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Secondary create cell handled, have received %d of %d onion bytes (aci %d)",
|
||||
circ->recvlen,circ->onionlen,circ->p_aci);
|
||||
}
|
||||
|
||||
if(circ->recvlen != circ->onionlen) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Onion not all here yet. Ok.");
|
||||
circ = circuit_new(cell->aci, conn);
|
||||
circ->state = CIRCUIT_STATE_ONIONSKIN_PENDING;
|
||||
if(cell->length != 208) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Bad cell length %d. Dropping.", cell->length);
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(circ->onionskin,cell->payload,cell->length);
|
||||
|
||||
/* add it to the pending onions queue, and then return */
|
||||
circ->state = CIRCUIT_STATE_ONION_PENDING;
|
||||
|
||||
if(onion_pending_add(circ) < 0) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Failed to queue onion. Closing.");
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Failed to queue onionskin. Closing.");
|
||||
circuit_close(circ);
|
||||
}
|
||||
log(LOG_DEBUG,"command_process_create_cell(): success: queued onionskin.");
|
||||
return;
|
||||
}
|
||||
|
||||
void command_process_created_cell(cell_t *cell, connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
cell_t newcell;
|
||||
|
||||
circ = circuit_get_by_aci_conn(cell->aci, conn);
|
||||
|
||||
if(!circ) {
|
||||
log(LOG_DEBUG,"command_process_created_cell(): received CREATED cell for unknown circ. Dropping.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(circ->n_aci != cell->aci) {
|
||||
log(LOG_DEBUG,"command_process_created_cell(): got created cell from OPward? Dropping.");
|
||||
return;
|
||||
}
|
||||
assert(cell->length == 192);
|
||||
|
||||
if(circ->cpath) { /* we're the OP. Handshake this. */
|
||||
log(LOG_DEBUG,"command_process_created_cell(): at OP. Finishing handshake.");
|
||||
if(circuit_finish_handshake(circ, cell->payload) < 0) {
|
||||
log(LOG_INFO,"command_process_created_cell(): circuit_finish_handshake failed.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
log(LOG_DEBUG,"command_process_created_cell(): Moving to next skin.");
|
||||
if(circuit_send_next_onion_skin(circ) < 0) {
|
||||
log(LOG_INFO,"command_process_created_cell(): circuit_send_next_onion_skin failed.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
} else { /* pack it into an extended relay cell, and send it. */
|
||||
memset(&newcell, 0, sizeof(cell_t));
|
||||
newcell.command = CELL_RELAY;
|
||||
newcell.aci = circ->p_aci;
|
||||
SET_CELL_RELAY_COMMAND(newcell, RELAY_COMMAND_EXTENDED);
|
||||
SET_CELL_STREAM_ID(newcell, ZERO_STREAM);
|
||||
|
||||
newcell.length = RELAY_HEADER_SIZE + cell->length;
|
||||
memcpy(newcell.payload+RELAY_HEADER_SIZE, cell->payload, 192);
|
||||
|
||||
log(LOG_DEBUG,"command_process_created_cell(): Sending extended relay cell.");
|
||||
if(circuit_deliver_relay_cell_from_edge(&newcell, circ, EDGE_EXIT, NULL) < 0) {
|
||||
log(LOG_DEBUG,"command_process_created_cell(): failed to deliver extended cell. Closing.");
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -150,6 +172,7 @@ void command_process_sendme_cell(cell_t *cell, connection_t *conn) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if(circ->state == CIRCUIT_STATE_ONION_WAIT) {
|
||||
log(LOG_DEBUG,"command_process_sendme_cell(): circuit in onion_wait. Dropping.");
|
||||
return;
|
||||
@ -158,6 +181,7 @@ void command_process_sendme_cell(cell_t *cell, connection_t *conn) {
|
||||
log(LOG_DEBUG,"command_process_sendme_cell(): circuit in or_wait. Dropping.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* at this point both circ->n_conn and circ->p_conn are guaranteed to be set */
|
||||
|
||||
@ -205,7 +229,7 @@ void command_process_relay_cell(cell_t *cell, connection_t *conn) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(circ->state == CIRCUIT_STATE_ONION_PENDING) {
|
||||
if(circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
|
||||
log(LOG_DEBUG,"command_process_relay_cell(): circuit in create_wait. Queueing relay cell.");
|
||||
onion_pending_relay_add(circ, cell);
|
||||
return;
|
||||
@ -213,22 +237,23 @@ void command_process_relay_cell(cell_t *cell, connection_t *conn) {
|
||||
|
||||
if(cell->aci == circ->p_aci) { /* it's an outgoing cell */
|
||||
if(--circ->p_receive_circwindow < 0) { /* is it less than 0 after decrement? */
|
||||
log(LOG_INFO,"connection_process_relay_cell(): Too many relay cells for out circuit (aci %d). Closing.", circ->p_aci);
|
||||
log(LOG_INFO,"command_process_relay_cell(): Too many relay cells for out circuit (aci %d). Closing.", circ->p_aci);
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
log(LOG_DEBUG,"connection_process_relay_cell(): p_receive_circwindow for aci %d is %d.",circ->p_aci,circ->p_receive_circwindow);
|
||||
log(LOG_DEBUG,"command_process_relay_cell(): p_receive_circwindow for aci %d is %d.",circ->p_aci,circ->p_receive_circwindow);
|
||||
}
|
||||
|
||||
if(cell->aci == circ->n_aci) { /* it's an ingoing cell */
|
||||
if(--circ->n_receive_circwindow < 0) { /* is it less than 0 after decrement? */
|
||||
log(LOG_INFO,"connection_process_relay_cell(): Too many relay cells for in circuit (aci %d). Closing.", circ->n_aci);
|
||||
log(LOG_INFO,"command_process_relay_cell(): Too many relay cells for in circuit (aci %d). Closing.", circ->n_aci);
|
||||
circuit_close(circ);
|
||||
return;
|
||||
}
|
||||
log(LOG_DEBUG,"connection_process_relay_cell(): n_receive_circwindow for aci %d is %d.",circ->n_aci,circ->n_receive_circwindow);
|
||||
log(LOG_DEBUG,"command_process_relay_cell(): n_receive_circwindow for aci %d is %d.",circ->n_aci,circ->n_receive_circwindow);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if(circ->state == CIRCUIT_STATE_ONION_WAIT) {
|
||||
log(LOG_WARNING,"command_process_relay_cell(): circuit in onion_wait. Dropping relay cell.");
|
||||
return;
|
||||
@ -237,6 +262,7 @@ void command_process_relay_cell(cell_t *cell, connection_t *conn) {
|
||||
log(LOG_WARNING,"command_process_relay_cell(): circuit in or_wait. Dropping relay cell.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* circ->p_conn and n_conn are only null if we're at an edge point with no connections yet */
|
||||
|
||||
if(cell->aci == circ->p_aci) { /* it's an outgoing cell */
|
||||
@ -267,7 +293,7 @@ void command_process_destroy_cell(cell_t *cell, connection_t *conn) {
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"command_process_destroy_cell(): Received for aci %d.",cell->aci);
|
||||
if(circ->state == CIRCUIT_STATE_ONION_PENDING) {
|
||||
if(circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
|
||||
onion_pending_remove(circ);
|
||||
}
|
||||
|
||||
|
@ -607,6 +607,8 @@ int connection_encrypt_cell(char *cellp, connection_t *conn) {
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
assert(conn);
|
||||
|
||||
if(crypto_cipher_encrypt(conn->f_crypto, cellp, CELL_NETWORK_SIZE, cryptcell)) {
|
||||
log(LOG_ERR,"Could not encrypt cell for connection %s:%u.",conn->address,conn->port);
|
||||
return -1;
|
||||
|
@ -23,7 +23,7 @@ int connection_edge_process_inbuf(connection_t *conn) {
|
||||
circ = circuit_get_by_conn(conn);
|
||||
if (!circ)
|
||||
return -1;
|
||||
|
||||
|
||||
memset(&cell, 0, sizeof(cell_t));
|
||||
cell.command = CELL_RELAY;
|
||||
cell.length = RELAY_HEADER_SIZE;
|
||||
@ -123,13 +123,12 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
|
||||
if(edge_type == EDGE_AP) {
|
||||
log(LOG_INFO,"connection_edge_process_relay_cell(): relay begin request unsupported. Dropping.");
|
||||
return 0;
|
||||
} else {
|
||||
if(conn) {
|
||||
log(LOG_INFO,"connection_edge_process_relay_cell(): begin cell for known stream. Dropping.");
|
||||
return 0;
|
||||
}
|
||||
return connection_exit_begin_conn(cell, circ);
|
||||
}
|
||||
if(conn) {
|
||||
log(LOG_INFO,"connection_edge_process_relay_cell(): begin cell for known stream. Dropping.");
|
||||
return 0;
|
||||
}
|
||||
return connection_exit_begin_conn(cell, circ);
|
||||
case RELAY_COMMAND_DATA:
|
||||
if(!conn) {
|
||||
log(LOG_DEBUG,"connection_edge_process_relay_cell(): relay cell dropped, unknown stream %d.",*(int*)conn->stream_id);
|
||||
@ -166,14 +165,6 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
|
||||
}
|
||||
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
|
||||
if(conn == circ->p_conn) {
|
||||
circ->p_conn = conn->next_stream;
|
||||
}
|
||||
for(prevconn = circ->p_conn; prevconn->next_stream != conn; prevconn = prevconn->next_stream) ;
|
||||
prevconn->next_stream = conn->next_stream;
|
||||
#endif
|
||||
#ifdef HALF_OPEN
|
||||
conn->done_sending = 1;
|
||||
shutdown(conn->s, 1); /* XXX check return; refactor NM */
|
||||
@ -182,6 +173,23 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, connection
|
||||
#endif
|
||||
conn->marked_for_close = 1;
|
||||
break;
|
||||
case RELAY_COMMAND_EXTEND:
|
||||
if(conn) {
|
||||
log(LOG_INFO,"connection_edge_process_relay_cell(): 'extend' for non-zero stream. Dropping.");
|
||||
return 0;
|
||||
}
|
||||
return circuit_extend(cell, circ);
|
||||
case RELAY_COMMAND_EXTENDED:
|
||||
if(edge_type == EDGE_EXIT) {
|
||||
log(LOG_INFO,"connection_edge_process_relay_cell(): 'extended' unsupported at exit. Dropping.");
|
||||
return 0;
|
||||
}
|
||||
log(LOG_DEBUG,"connection_edge_process_relay_cell(): Got an extended cell! Yay.");
|
||||
if(circuit_finish_handshake(circ, cell->payload+RELAY_HEADER_SIZE) < 0) {
|
||||
log(LOG_INFO,"connection_edge_process_relay_cell(): circuit_finish_handshake failed.");
|
||||
return -1;
|
||||
}
|
||||
return circuit_send_next_onion_skin(circ);
|
||||
case RELAY_COMMAND_CONNECTED:
|
||||
if(edge_type == EDGE_EXIT) {
|
||||
log(LOG_INFO,"connection_edge_process_relay_cell(): 'connected' unsupported at exit. Dropping.");
|
||||
|
@ -337,7 +337,6 @@ int prepare_for_poll(int *timeout) {
|
||||
for(i=0;i<nfds;i++) {
|
||||
tmpconn = connection_array[i];
|
||||
connection_increment_receiver_bucket(tmpconn);
|
||||
connection_array[i]->onions_handled_this_second = 0;
|
||||
|
||||
/* check connections to see whether we should send a keepalive, expire, or wait */
|
||||
if(!connection_speaks_cells(tmpconn))
|
||||
@ -683,7 +682,6 @@ int tor_main(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
init_tracked_tree(); /* initialize the replay detection tree */
|
||||
init_cache_tree(); /* initialize the dns resolve tree */
|
||||
|
||||
signal (SIGINT, catch); /* catch kills so we can exit cleanly */
|
||||
|
559
src/or/onion.c
559
src/or/onion.c
@ -6,11 +6,8 @@
|
||||
|
||||
extern or_options_t options; /* command-line and config-file options */
|
||||
|
||||
static int onion_process(circuit_t *circ);
|
||||
static int onion_deliver_to_conn(aci_t aci, unsigned char *onion, uint32_t onionlen, connection_t *conn);
|
||||
static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len);
|
||||
static int find_tracked_onion(unsigned char *onion, uint32_t onionlen,
|
||||
int expire);
|
||||
static int onionskin_process(circuit_t *circ);
|
||||
|
||||
int decide_aci_type(uint32_t local_addr, uint16_t local_port,
|
||||
uint32_t remote_addr, uint16_t remote_port) {
|
||||
@ -76,17 +73,19 @@ void onion_pending_process_one(void) {
|
||||
if(!ol_list)
|
||||
return; /* no onions pending, we're done */
|
||||
|
||||
assert(ol_list->circ && ol_list->circ->p_conn);
|
||||
assert(ol_list->circ);
|
||||
assert(ol_list->circ->p_conn);
|
||||
assert(ol_length > 0);
|
||||
circ = ol_list->circ;
|
||||
|
||||
if(onion_process(circ) < 0) {
|
||||
if(onionskin_process(circ) < 0) {
|
||||
log(LOG_DEBUG,"onion_pending_process_one(): Failed. Closing.");
|
||||
onion_pending_remove(circ);
|
||||
circuit_close(circ);
|
||||
} else {
|
||||
log(LOG_DEBUG,"onion_pending_process_one(): Succeeded. Delivering queued relay cells.");
|
||||
for(tmpd = ol_list->relay_cells; tmpd; tmpd=tmpd->next) {
|
||||
log(LOG_DEBUG,"onion_pending_process_one(): Delivering relay cell...");
|
||||
command_process_relay_cell(tmpd->cell, circ->p_conn);
|
||||
}
|
||||
onion_pending_remove(circ);
|
||||
@ -174,136 +173,48 @@ void onion_pending_relay_add(circuit_t *circ, cell_t *cell) {
|
||||
}
|
||||
}
|
||||
|
||||
/* helper function for onion_process */
|
||||
static int onion_deliver_to_conn(aci_t aci, unsigned char *onion, uint32_t onionlen, connection_t *conn) {
|
||||
char *buf;
|
||||
int buflen, dataleft;
|
||||
/* learn keys, initialize, then send a created cell back */
|
||||
static int onionskin_process(circuit_t *circ) {
|
||||
unsigned char iv[16];
|
||||
unsigned char keys[32];
|
||||
cell_t cell;
|
||||
|
||||
assert(aci && onion && onionlen);
|
||||
|
||||
buflen = onionlen+4;
|
||||
buf = malloc(buflen);
|
||||
if(!buf)
|
||||
return -1;
|
||||
|
||||
log(LOG_DEBUG,"onion_deliver_to_conn(): Setting onion length to %u.",onionlen);
|
||||
*(uint32_t*)buf = htonl(onionlen);
|
||||
memcpy((buf+4),onion,onionlen);
|
||||
|
||||
dataleft = buflen;
|
||||
while(dataleft > 0) {
|
||||
memset(&cell,0,sizeof(cell_t));
|
||||
cell.command = CELL_CREATE;
|
||||
cell.aci = aci;
|
||||
if(dataleft >= CELL_PAYLOAD_SIZE)
|
||||
cell.length = CELL_PAYLOAD_SIZE;
|
||||
else
|
||||
cell.length = dataleft;
|
||||
memcpy(cell.payload, buf+buflen-dataleft, cell.length);
|
||||
dataleft -= cell.length;
|
||||
|
||||
log(LOG_DEBUG,"onion_deliver_to_conn(): Delivering create cell, payload %d bytes.",cell.length);
|
||||
if(connection_write_cell_to_buf(&cell, conn) < 0) {
|
||||
log(LOG_DEBUG,"onion_deliver_to_conn(): Could not buffer new create cells. Closing.");
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int onion_process(circuit_t *circ) {
|
||||
connection_t *n_conn;
|
||||
int retval;
|
||||
aci_t aci_type;
|
||||
struct sockaddr_in me; /* my router identity */
|
||||
onion_layer_t layer;
|
||||
memset(iv, 0, 16);
|
||||
|
||||
if(learn_my_address(&me) < 0)
|
||||
return -1;
|
||||
memset(&cell, 0, sizeof(cell_t));
|
||||
cell.command = CELL_CREATED;
|
||||
cell.aci = circ->p_aci;
|
||||
cell.length = 192;
|
||||
|
||||
/* decrypt it in-place */
|
||||
if(decrypt_onion(circ->onion,circ->onionlen,getprivatekey(),&layer) < 0) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): decrypt_onion() failed, closing circuit.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Onion decrypted.");
|
||||
circ->state = CIRCUIT_STATE_OPEN;
|
||||
|
||||
/* check freshness */
|
||||
if (layer.expire < (uint32_t)time(NULL)) /* expired onion */ /*XXXX*/
|
||||
{
|
||||
log(LOG_NOTICE,"I have just received an expired onion. This could be a replay attack.");
|
||||
log(LOG_DEBUG,"onionskin_process(): Entering.");
|
||||
|
||||
if(onion_skin_server_handshake(circ->onionskin, getprivatekey(),
|
||||
cell.payload, keys, 32) < 0) {
|
||||
log(LOG_ERR,"onionskin_process(): onion_skin_server_handshake failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
aci_type = decide_aci_type(ntohl(me.sin_addr.s_addr), ntohs(me.sin_port),
|
||||
layer.addr, layer.port);
|
||||
|
||||
if(circuit_init(circ, aci_type, &layer) < 0) {
|
||||
log(LOG_ERR,"process_onion(): init_circuit() failed.");
|
||||
log(LOG_DEBUG,"onionskin_process: init cipher forward %d, backward %d.", *(int*)keys, *(int*)(keys+16));
|
||||
|
||||
if (!(circ->n_crypto =
|
||||
crypto_create_init_cipher(DEFAULT_CIPHER,keys,iv,0))) {
|
||||
log(LOG_ERR,"Cipher initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check for replay. at the same time, add it to the pile of tracked onions. */
|
||||
if(find_tracked_onion(circ->onion, circ->onionlen, layer.expire)) {
|
||||
log(LOG_NOTICE,"process_onion(): I have just received a replayed onion. This could be a replay attack.");
|
||||
if (!(circ->p_crypto =
|
||||
crypto_create_init_cipher(DEFAULT_CIPHER,keys+16,iv,1))) {
|
||||
log(LOG_ERR,"Cipher initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now we must send create cells to the next router */
|
||||
if(circ->n_addr && circ->n_port) {
|
||||
n_conn = connection_twin_get_by_addr_port(circ->n_addr,circ->n_port);
|
||||
if(!n_conn || n_conn->type != CONN_TYPE_OR) {
|
||||
/* i've disabled making connections through OPs, but it's definitely
|
||||
* possible here. I'm not sure if it would be a bug or a feature. -RD
|
||||
*/
|
||||
/* note also that this will close circuits where the onion has the same
|
||||
* router twice in a row in the path. i think that's ok. -RD
|
||||
*/
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Next router not connected. Closing.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
circ->n_addr = n_conn->addr; /* these are different if we found a twin instead */
|
||||
circ->n_port = n_conn->port;
|
||||
|
||||
circ->n_conn = n_conn;
|
||||
log(LOG_DEBUG,"command_process_create_cell(): n_conn is %s:%u",n_conn->address,n_conn->port);
|
||||
|
||||
/* send the CREATE cells on to the next hop */
|
||||
pad_onion(circ->onion, circ->onionlen, ONION_LAYER_SIZE);
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Padded the onion with random data.");
|
||||
|
||||
retval = onion_deliver_to_conn(circ->n_aci, circ->onion, circ->onionlen, n_conn);
|
||||
free(circ->onion);
|
||||
circ->onion = NULL;
|
||||
if (retval == -1) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Could not deliver the onion to next conn. Closing.");
|
||||
return -1;
|
||||
}
|
||||
} else { /* this is destined for an exit */
|
||||
log(LOG_DEBUG,"command_process_create_cell(): create cell reached exit. Circuit established.");
|
||||
#if 0
|
||||
log(LOG_DEBUG,"command_process_create_cell(): Creating new exit connection.");
|
||||
n_conn = connection_new(CONN_TYPE_EXIT);
|
||||
if(!n_conn) {
|
||||
log(LOG_DEBUG,"command_process_create_cell(): connection_new failed. Closing.");
|
||||
return -1;
|
||||
}
|
||||
n_conn->state = EXIT_CONN_STATE_CONNECTING_WAIT;
|
||||
n_conn->receiver_bucket = -1; /* edge connections don't do receiver buckets */
|
||||
n_conn->bandwidth = -1;
|
||||
n_conn->s = -1; /* not yet valid */
|
||||
if(connection_add(n_conn) < 0) { /* no space, forget it */
|
||||
log(LOG_DEBUG,"command_process_create_cell(): connection_add failed. Closing.");
|
||||
connection_free(n_conn);
|
||||
return -1;
|
||||
}
|
||||
circ->n_conn = n_conn;
|
||||
#endif
|
||||
if(connection_write_cell_to_buf(&cell, circ->p_conn) < 0) {
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"onionskin_process(): Finished sending 'created' cell.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -432,402 +343,82 @@ static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len) {
|
||||
return num;
|
||||
}
|
||||
|
||||
/* creates a new onion from route, stores it and its length into buf and len respectively */
|
||||
unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int *route, int routelen, int *len, crypt_path_t **cpath)
|
||||
{
|
||||
crypt_path_t *onion_generate_cpath(routerinfo_t **firsthop) {
|
||||
int routelen; /* length of the route */
|
||||
unsigned int *route; /* hops in the route as an array of indexes into rarray */
|
||||
crypt_path_t *cpath=NULL;
|
||||
routerinfo_t **rarray;
|
||||
int rarray_len;
|
||||
int i;
|
||||
char *layerp;
|
||||
crypt_path_t *hop;
|
||||
unsigned char *buf;
|
||||
routerinfo_t *router;
|
||||
unsigned char iv[16];
|
||||
struct in_addr netaddr;
|
||||
onion_layer_t layer;
|
||||
|
||||
assert(rarray && route && len && routelen && cpath);
|
||||
router_get_rarray(&rarray, &rarray_len);
|
||||
|
||||
*cpath = NULL;
|
||||
|
||||
/* calculate the size of the onion */
|
||||
*len = routelen * ONION_LAYER_SIZE + ONION_PADDING_SIZE;
|
||||
/* 28 bytes per layer + 100 bytes padding for the innermost layer */
|
||||
log(LOG_DEBUG,"create_onion() : Size of the onion is %u.",*len);
|
||||
|
||||
/* allocate memory for the onion */
|
||||
buf = malloc(*len);
|
||||
if(!buf) {
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
/* choose a route */
|
||||
route = new_route(options.CoinWeight, rarray, rarray_len, &routelen);
|
||||
if (!route) {
|
||||
log(LOG_ERR,"onion_generate_cpath(): Error choosing a route through the OR network.");
|
||||
return NULL;
|
||||
}
|
||||
log(LOG_DEBUG,"create_onion() : Allocated memory for the onion.");
|
||||
log(LOG_DEBUG,"onion_generate_cpath(): Chosen a route of length %u: ",routelen);
|
||||
|
||||
*firsthop = rarray[route[routelen-1]];
|
||||
assert(*firsthop); /* should always be defined */
|
||||
|
||||
for(i=0; i<routelen; i++) {
|
||||
netaddr.s_addr = htonl((rarray[route[i]])->addr);
|
||||
|
||||
log(LOG_DEBUG,"create_onion(): %u : %s:%u, %u/%u",routelen-i,
|
||||
log(LOG_DEBUG,"onion_generate_cpath(): %u : %s:%u, %u/%u",routelen-i,
|
||||
inet_ntoa(netaddr),
|
||||
(rarray[route[i]])->or_port,
|
||||
(rarray[route[i]])->pkey,
|
||||
crypto_pk_keysize((rarray[route[i]])->pkey));
|
||||
}
|
||||
|
||||
layerp = buf + *len - ONION_LAYER_SIZE - ONION_PADDING_SIZE; /* pointer to innermost layer */
|
||||
/* create the onion layer by layer, starting with the innermost */
|
||||
/* create the cpath layer by layer, starting at the last hop */
|
||||
for (i=0;i<routelen;i++) {
|
||||
router = rarray[route[i]];
|
||||
|
||||
layer.version = OR_VERSION;
|
||||
if (i) { /* not last hop */
|
||||
layer.port = rarray[route[i-1]]->or_port;
|
||||
layer.addr = rarray[route[i-1]]->addr;
|
||||
} else {
|
||||
layer.port = 0;
|
||||
layer.addr = 0;
|
||||
}
|
||||
|
||||
/* Expiration Time */
|
||||
layer.expire = (uint32_t)(time(NULL) + 86400); /* NOW + 1 day */
|
||||
|
||||
/* Key Seed Material */
|
||||
if(crypto_rand(ONION_KEYSEED_LEN, layer.keyseed)) { /* error */
|
||||
log(LOG_ERR,"Error generating random data.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
onion_pack(layerp, &layer);
|
||||
|
||||
// log(LOG_DEBUG,"create_onion() : Onion layer %u built : %u, %u, %u, %s, %u.",i+1,layer->zero,layer->backf,layer->forwf,inet_ntoa(*((struct in_addr *)&layer->addr)),layer->port);
|
||||
|
||||
/* build up the crypt_path */
|
||||
hop = (crypt_path_t *)malloc(sizeof(crypt_path_t));
|
||||
if(!hop) {
|
||||
log(LOG_ERR,"Error allocating memory.");
|
||||
goto error;
|
||||
log(LOG_ERR,"Error allocating crypt path hop memory.");
|
||||
circuit_free_cpath(cpath);
|
||||
free(route);
|
||||
return NULL;
|
||||
}
|
||||
memset(hop, 0, sizeof(crypt_path_t));
|
||||
|
||||
/* link hop into the cpath, at the front */
|
||||
hop->next = *cpath;
|
||||
hop->next = cpath;
|
||||
hop->prev = NULL;
|
||||
hop->state = CPATH_STATE_OPEN; /* change when we move to incremental paths */
|
||||
if(*cpath) {
|
||||
(*cpath)->prev = hop;
|
||||
hop->state = CPATH_STATE_CLOSED;
|
||||
if(cpath) {
|
||||
cpath->prev = hop;
|
||||
}
|
||||
*cpath = hop;
|
||||
cpath = hop;
|
||||
|
||||
log(LOG_DEBUG,"create_onion() : Building hop %u of crypt path.",i+1);
|
||||
|
||||
/* calculate keys */
|
||||
crypto_SHA_digest(layer.keyseed,16,hop->digest3);
|
||||
log(LOG_DEBUG,"create_onion() : First SHA pass performed.");
|
||||
crypto_SHA_digest(hop->digest3,20,hop->digest2);
|
||||
log(LOG_DEBUG,"create_onion() : Second SHA pass performed.");
|
||||
crypto_SHA_digest(hop->digest2,20,hop->digest3);
|
||||
log(LOG_DEBUG,"create_onion() : Third SHA pass performed.");
|
||||
log(LOG_DEBUG,"create_onion() : Keys generated.");
|
||||
/* set IV to zero */
|
||||
memset((void *)iv,0,16);
|
||||
|
||||
/* initialize cipher engines */
|
||||
if (! (hop->f_crypto =
|
||||
crypto_create_init_cipher(DEFAULT_CIPHER, hop->digest3, iv, 1))) {
|
||||
/* cipher initialization failed */
|
||||
log(LOG_ERR,"Could not create a crypto environment.");
|
||||
goto error;
|
||||
#if 0
|
||||
if (i) { /* not last hop. (last hop has 0's for these.) */
|
||||
hop->port = rarray[route[i-1]]->or_port;
|
||||
hop->addr = rarray[route[i-1]]->addr;
|
||||
}
|
||||
#endif
|
||||
hop->port = rarray[route[i]]->or_port;
|
||||
hop->addr = rarray[route[i]]->addr;
|
||||
|
||||
if (! (hop->b_crypto =
|
||||
crypto_create_init_cipher(DEFAULT_CIPHER, hop->digest2, iv, 0))) {
|
||||
/* cipher initialization failed */
|
||||
log(LOG_ERR,"Could not create a crypto environment.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"create_onion() : Built corresponding crypt path hop.");
|
||||
|
||||
/* padding if this is the innermost layer */
|
||||
if (!i) {
|
||||
if (crypto_pseudo_rand(ONION_PADDING_SIZE, layerp + ONION_LAYER_SIZE)) { /* error */
|
||||
log(LOG_ERR,"Error generating pseudo-random data.");
|
||||
goto error;
|
||||
}
|
||||
log(LOG_DEBUG,"create_onion() : This is the innermost layer. Adding 100 bytes of padding.");
|
||||
}
|
||||
|
||||
/* encrypt */
|
||||
|
||||
if(encrypt_onion(layerp,ONION_PADDING_SIZE+(i+1)*ONION_LAYER_SIZE,router->pkey,layer.keyseed) < 0) {
|
||||
log(LOG_ERR,"Error encrypting onion layer.");
|
||||
goto error;
|
||||
}
|
||||
log(LOG_DEBUG,"create_onion() : Encrypted layer.");
|
||||
|
||||
/* calculate pointer to next layer */
|
||||
layerp = buf + (routelen-i-2)*ONION_LAYER_SIZE;
|
||||
log(LOG_DEBUG,"onion_generate_cpath() : Building hop %u of crypt path.",i+1);
|
||||
}
|
||||
|
||||
/* now link cpath->prev to the end of cpath */
|
||||
for(hop=*cpath; hop->next; hop=hop->next) ;
|
||||
hop->next = *cpath;
|
||||
(*cpath)->prev = hop;
|
||||
for(hop=cpath; hop->next; hop=hop->next) ;
|
||||
hop->next = cpath;
|
||||
cpath->prev = hop;
|
||||
|
||||
return buf;
|
||||
|
||||
error:
|
||||
if(buf)
|
||||
free(buf);
|
||||
circuit_free_cpath(*cpath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* encrypts 128 bytes of the onion with the specified public key, the rest with
|
||||
* DES OFB with the key as defined in the outter layer */
|
||||
int encrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *pkey, char* keyseed) {
|
||||
unsigned char *tmpbuf = NULL; /* temporary buffer for crypto operations */
|
||||
unsigned char digest[20]; /* stores SHA1 output - 160 bits */
|
||||
unsigned char iv[8];
|
||||
|
||||
crypto_cipher_env_t *crypt_env = NULL; /* crypto environment */
|
||||
|
||||
assert(onion && pkey);
|
||||
assert(onionlen >= 128);
|
||||
|
||||
memset(iv,0,8);
|
||||
|
||||
// log(LOG_DEBUG,"Onion layer : %u, %u, %u, %s, %u.",onion->zero,onion->backf,onion->forwf,inet_ntoa(*((struct in_addr *)&onion->addr)),onion->port);
|
||||
/* allocate space for tmpbuf */
|
||||
tmpbuf = (unsigned char *)malloc(onionlen);
|
||||
if(!tmpbuf) {
|
||||
log(LOG_ERR,"Could not allocate memory.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"encrypt_onion() : allocated %u bytes of memory for the encrypted onion (at %u).",onionlen,tmpbuf);
|
||||
|
||||
/* get key1 = SHA1(KeySeed) */
|
||||
if (crypto_SHA_digest(keyseed,16,digest)) {
|
||||
log(LOG_ERR,"Error computing SHA1 digest.");
|
||||
goto error;
|
||||
}
|
||||
log(LOG_DEBUG,"encrypt_onion() : Computed DES key.");
|
||||
|
||||
log(LOG_DEBUG,"encrypt_onion() : Trying to RSA encrypt.");
|
||||
/* encrypt 128 bytes with RSA *pkey */
|
||||
if (crypto_pk_public_encrypt(pkey, onion, 128, tmpbuf, RSA_NO_PADDING) == -1) {
|
||||
log(LOG_ERR,"Error RSA-encrypting data :%s",crypto_perror());
|
||||
goto error;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"encrypt_onion() : RSA encrypted first 128 bytes of the onion.");
|
||||
|
||||
/* now encrypt the rest with 3DES OFB */
|
||||
crypt_env = crypto_create_init_cipher(CRYPTO_CIPHER_3DES, digest, iv, 1);
|
||||
if (!crypt_env) {
|
||||
log(LOG_ERR,"Error creating the crypto environment.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (crypto_cipher_encrypt(crypt_env,onion+128, onionlen-128, (unsigned char *)tmpbuf+128)) { /* error */
|
||||
log(LOG_ERR,"Error performing DES encryption:%s",crypto_perror());
|
||||
goto error;
|
||||
}
|
||||
log(LOG_DEBUG,"encrypt_onion() : 3DES OFB encrypted the rest of the onion.");
|
||||
|
||||
/* now copy tmpbuf to onion */
|
||||
memcpy(onion,tmpbuf,onionlen);
|
||||
log(LOG_DEBUG,"encrypt_onion() : Copied cipher to original onion buffer.");
|
||||
free(tmpbuf);
|
||||
crypto_free_cipher_env(crypt_env);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (tmpbuf)
|
||||
free(tmpbuf);
|
||||
if (crypt_env)
|
||||
crypto_free_cipher_env(crypt_env);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* decrypts the first 128 bytes using RSA and prkey, decrypts the rest with DES OFB with key1 */
|
||||
int decrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *prkey, onion_layer_t *layer) {
|
||||
void *tmpbuf = NULL; /* temporary buffer for crypto operations */
|
||||
unsigned char digest[20]; /* stores SHA1 output - 160 bits */
|
||||
unsigned char iv[8];
|
||||
|
||||
crypto_cipher_env_t *crypt_env =NULL; /* crypto environment */
|
||||
|
||||
assert(onion && prkey);
|
||||
|
||||
memset(iv,0,8);
|
||||
|
||||
/* allocate space for tmpbuf */
|
||||
tmpbuf = malloc(onionlen);
|
||||
if (!tmpbuf) {
|
||||
log(LOG_ERR,"Could not allocate memory.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"decrypt_onion() : Allocated memory for the temporary buffer.");
|
||||
|
||||
/* decrypt 128 bytes with RSA *prkey */
|
||||
if (crypto_pk_private_decrypt(prkey, onion, 128, tmpbuf, RSA_NO_PADDING) == -1)
|
||||
{
|
||||
log(LOG_ERR,"Error RSA-decrypting data :%s",crypto_perror());
|
||||
goto error;
|
||||
}
|
||||
log(LOG_DEBUG,"decrypt_onion() : RSA decryption complete.");
|
||||
|
||||
onion_unpack(layer, tmpbuf);
|
||||
|
||||
/* get key1 = SHA1(KeySeed) */
|
||||
if (crypto_SHA_digest(layer->keyseed,16,digest)) {
|
||||
log(LOG_ERR,"Error computing SHA1 digest.");
|
||||
goto error;
|
||||
}
|
||||
log(LOG_DEBUG,"decrypt_onion() : Computed DES key.");
|
||||
|
||||
/* now decrypt the rest with 3DES OFB */
|
||||
crypt_env = crypto_create_init_cipher(CRYPTO_CIPHER_3DES, digest, iv, 0);
|
||||
if (!crypt_env) {
|
||||
log(LOG_ERR,"Error creating crypto environment");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (crypto_cipher_decrypt(crypt_env,onion+128, onionlen-128,tmpbuf+128)) {
|
||||
log(LOG_ERR,"Error performing DES decryption:%s",crypto_perror());
|
||||
goto error;
|
||||
}
|
||||
|
||||
log(LOG_DEBUG,"decrypt_onion() : DES decryption complete.");
|
||||
|
||||
/* now copy tmpbuf to onion */
|
||||
memcpy(onion,tmpbuf,onionlen);
|
||||
free(tmpbuf);
|
||||
crypto_free_cipher_env(crypt_env);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (tmpbuf)
|
||||
free(tmpbuf);
|
||||
if (crypt_env)
|
||||
crypto_free_cipher_env(crypt_env);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* delete first n bytes of the onion and pads the end with n bytes of random data */
|
||||
void pad_onion(unsigned char *onion, uint32_t onionlen, int n)
|
||||
{
|
||||
assert(onion);
|
||||
|
||||
memmove(onion,onion+n,onionlen-n);
|
||||
crypto_pseudo_rand(n, onion+onionlen-n);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* red black tree using Niels' tree.h. I used
|
||||
http://www.openbsd.org/cgi-bin/cvsweb/src/regress/sys/sys/tree/rb/
|
||||
as my guide */
|
||||
|
||||
#include "tree.h"
|
||||
|
||||
struct tracked_onion {
|
||||
RB_ENTRY(tracked_onion) node;
|
||||
uint32_t expire;
|
||||
char digest[20]; /* SHA digest of the onion */
|
||||
struct tracked_onion *next;
|
||||
};
|
||||
|
||||
RB_HEAD(tracked_tree, tracked_onion) tracked_root;
|
||||
|
||||
int compare_tracked_onions(struct tracked_onion *a, struct tracked_onion *b) {
|
||||
return memcmp(a->digest, b->digest, 20);
|
||||
}
|
||||
|
||||
RB_PROTOTYPE(tracked_tree, tracked_onion, node, compare_tracked_onions)
|
||||
RB_GENERATE(tracked_tree, tracked_onion, node, compare_tracked_onions)
|
||||
|
||||
void init_tracked_tree(void) {
|
||||
RB_INIT(&tracked_root);
|
||||
}
|
||||
|
||||
/* see if this onion has been seen before. if so, return 1, else
|
||||
* return 0 and add the sha1 of this onion to the tree.
|
||||
*/
|
||||
static int find_tracked_onion(unsigned char *onion, uint32_t onionlen,
|
||||
int expire) {
|
||||
static struct tracked_onion *head_tracked_onions = NULL; /* linked list of tracked onions */
|
||||
static struct tracked_onion *tail_tracked_onions = NULL;
|
||||
|
||||
uint32_t now = time(NULL);
|
||||
struct tracked_onion *to;
|
||||
|
||||
/* first take this opportunity to see if there are any expired
|
||||
* onions in the tree. we know this is fast because the linked list
|
||||
* 'tracked_onions' is ordered by when they were seen.
|
||||
*/
|
||||
while(head_tracked_onions && (head_tracked_onions->expire < now)) {
|
||||
to = head_tracked_onions;
|
||||
log(LOG_DEBUG,"find_tracked_onion(): Forgetting old onion (expires %d)", to->expire);
|
||||
head_tracked_onions = to->next;
|
||||
if(!head_tracked_onions) /* if there are no more, */
|
||||
tail_tracked_onions = NULL; /* then make sure the list's tail knows that too */
|
||||
RB_REMOVE(tracked_tree, &tracked_root, to);
|
||||
free(to);
|
||||
}
|
||||
|
||||
to = malloc(sizeof(struct tracked_onion));
|
||||
|
||||
/* compute the SHA digest of the onion */
|
||||
crypto_SHA_digest(onion, onionlen, to->digest);
|
||||
|
||||
/* try adding it to the tree. if it's already there it will return it. */
|
||||
if(RB_INSERT(tracked_tree, &tracked_root, to)) {
|
||||
/* yes, it's already there: this is a replay. */
|
||||
free(to);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* this is a new onion. add it to the list. */
|
||||
|
||||
to->expire = expire; /* set the expiration date */
|
||||
to->next = NULL;
|
||||
|
||||
if (!head_tracked_onions) {
|
||||
head_tracked_onions = to;
|
||||
} else {
|
||||
tail_tracked_onions->next = to;
|
||||
}
|
||||
tail_tracked_onions = to;
|
||||
|
||||
log(LOG_DEBUG,"find_tracked_onion(): Remembered new onion (expires %d)", to->expire);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
onion_pack(char *dest, onion_layer_t *src)
|
||||
{
|
||||
assert((src->version & 0x80) == 0);
|
||||
|
||||
*(uint8_t*)(dest) = src->version;
|
||||
*(uint16_t*)(dest+1) = htons(src->port);
|
||||
*(uint32_t*)(dest+3) = htonl(src->addr);
|
||||
*(uint32_t*)(dest+7) = htonl(src->expire);
|
||||
memcpy(dest+11, src->keyseed, ONION_KEYSEED_LEN);
|
||||
log(LOG_DEBUG,"onion_pack(): version %d, port %d, addr %s, expire %u", src->version, src->port,
|
||||
inet_ntoa(*((struct in_addr *)(dest+3))), src->expire);
|
||||
}
|
||||
|
||||
void
|
||||
onion_unpack(onion_layer_t *dest, char *src)
|
||||
{
|
||||
dest->version = *(uint8_t*)src;
|
||||
dest->port = ntohs(*(uint16_t*)(src+1));
|
||||
dest->addr = ntohl(*(uint32_t*)(src+3));
|
||||
dest->expire = ntohl(*(uint32_t*)(src+7));
|
||||
memcpy(dest->keyseed, src+11, ONION_KEYSEED_LEN);
|
||||
|
||||
log(LOG_DEBUG,"onion_unpack(): version %d, port %d, addr %s, expire %u", dest->version, dest->port,
|
||||
inet_ntoa(*((struct in_addr *)(src+3))), dest->expire);
|
||||
free(route);
|
||||
return cpath;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
@ -843,7 +434,7 @@ onion_unpack(onion_layer_t *dest, char *src)
|
||||
* and the last 80 are encrypted with the symmetric key.
|
||||
*/
|
||||
int
|
||||
onion_skin_create(crypto_pk_env_t *router_key,
|
||||
onion_skin_create(crypto_pk_env_t *dest_router_key,
|
||||
crypto_dh_env_t **handshake_state_out,
|
||||
char *onion_skin_out) /* Must be 208 bytes long */
|
||||
{
|
||||
@ -861,7 +452,7 @@ onion_skin_create(crypto_pk_env_t *router_key,
|
||||
goto err;
|
||||
|
||||
dhbytes = crypto_dh_get_bytes(dh);
|
||||
pkbytes = crypto_pk_keysize(router_key);
|
||||
pkbytes = crypto_pk_keysize(dest_router_key);
|
||||
assert(dhbytes+16 == 208);
|
||||
if (!(pubkey = malloc(dhbytes+16)))
|
||||
goto err;
|
||||
@ -896,7 +487,7 @@ onion_skin_create(crypto_pk_env_t *router_key,
|
||||
if (!cipher)
|
||||
goto err;
|
||||
|
||||
if (crypto_pk_public_encrypt(router_key, pubkey, pkbytes,
|
||||
if (crypto_pk_public_encrypt(dest_router_key, pubkey, pkbytes,
|
||||
onion_skin_out, RSA_NO_PADDING)==-1)
|
||||
goto err;
|
||||
|
||||
|
76
src/or/or.h
76
src/or/or.h
@ -113,9 +113,9 @@
|
||||
#define DIR_CONN_STATE_COMMAND_WAIT 3
|
||||
#define DIR_CONN_STATE_WRITING 4
|
||||
|
||||
#define CIRCUIT_STATE_ONION_WAIT 0 /* receiving the onion */
|
||||
#define CIRCUIT_STATE_ONION_PENDING 1 /* waiting to process the onion */
|
||||
#define CIRCUIT_STATE_OR_WAIT 2 /* I'm at the beginning of the path, my firsthop is still connecting */
|
||||
#define CIRCUIT_STATE_BUILDING 0 /* I'm the OP, still haven't done all my handshakes */
|
||||
#define CIRCUIT_STATE_ONIONSKIN_PENDING 1 /* waiting to process the onion */
|
||||
#define CIRCUIT_STATE_OR_WAIT 2 /* I'm the OP, my firsthop is still connecting */
|
||||
#define CIRCUIT_STATE_OPEN 3 /* onion processed, ready to send data along the connection */
|
||||
//#define CIRCUIT_STATE_CLOSE_WAIT1 4 /* sent two "destroy" signals, waiting for acks */
|
||||
//#define CIRCUIT_STATE_CLOSE_WAIT2 5 /* received one ack, waiting for one more
|
||||
@ -127,23 +127,14 @@
|
||||
#define RELAY_COMMAND_END 3
|
||||
#define RELAY_COMMAND_CONNECTED 4
|
||||
#define RELAY_COMMAND_SENDME 5
|
||||
#define RELAY_COMMAND_EXTEND 6
|
||||
#define RELAY_COMMAND_EXTENDED 7
|
||||
|
||||
#define RELAY_HEADER_SIZE 8
|
||||
|
||||
#define RELAY_STATE_RESOLVING
|
||||
|
||||
/* available cipher functions */
|
||||
#if 0
|
||||
#define ONION_CIPHER_IDENTITY 0
|
||||
#define ONION_CIPHER_DES 1
|
||||
#define ONION_CIPHER_RC4 2
|
||||
#define ONION_CIPHER_3DES 3
|
||||
#endif
|
||||
|
||||
/* default cipher function */
|
||||
#if 0
|
||||
#define ONION_DEFAULT_CIPHER ONION_CIPHER_3DES
|
||||
#endif
|
||||
#define DEFAULT_CIPHER CRYPTO_CIPHER_3DES
|
||||
|
||||
#define CELL_DIRECTION_IN 1
|
||||
@ -160,9 +151,10 @@
|
||||
/* cell commands */
|
||||
#define CELL_PADDING 0
|
||||
#define CELL_CREATE 1
|
||||
#define CELL_RELAY 2
|
||||
#define CELL_DESTROY 3
|
||||
#define CELL_SENDME 4
|
||||
#define CELL_CREATED 2
|
||||
#define CELL_RELAY 3
|
||||
#define CELL_DESTROY 4
|
||||
#define CELL_SENDME 5
|
||||
|
||||
#define CELL_PAYLOAD_SIZE 248
|
||||
#define CELL_NETWORK_SIZE 256
|
||||
@ -246,8 +238,6 @@ struct connection_t {
|
||||
|
||||
long timestamp_created;
|
||||
|
||||
int onions_handled_this_second;
|
||||
|
||||
/* used by OR and OP: */
|
||||
|
||||
uint32_t bandwidth; /* connection bandwidth */
|
||||
@ -339,16 +329,19 @@ typedef struct {
|
||||
} routerinfo_t;
|
||||
|
||||
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 */
|
||||
|
||||
/* crypto environments */
|
||||
crypto_cipher_env_t *f_crypto;
|
||||
crypto_cipher_env_t *b_crypto;
|
||||
|
||||
crypto_dh_env_t *handshake_state;
|
||||
|
||||
uint32_t addr;
|
||||
uint16_t port;
|
||||
|
||||
char state;
|
||||
#define CPATH_STATE_CLOSED 0
|
||||
#define CPATH_STATE_AWAITING_KEY 1
|
||||
#define CPATH_STATE_AWAITING_KEYS 1
|
||||
#define CPATH_STATE_OPEN 2
|
||||
struct crypt_path_t *next;
|
||||
struct crypt_path_t *prev; /* doubly linked list */
|
||||
@ -382,15 +375,15 @@ typedef struct {
|
||||
|
||||
crypt_path_t *cpath;
|
||||
|
||||
uint32_t expire; /* expiration time for the corresponding onion */
|
||||
char onionskin[208]; /* for storage while onionskin pending */
|
||||
long timestamp_created;
|
||||
char dirty; /* whether this circuit has been used yet */
|
||||
|
||||
int state;
|
||||
|
||||
unsigned char *onion; /* stores the onion when state is CONN_STATE_OPEN_WAIT */
|
||||
uint32_t onionlen; /* total onion length */
|
||||
uint32_t recvlen; /* length of the onion so far */
|
||||
// unsigned char *onion; /* stores the onion when state is CONN_STATE_OPEN_WAIT */
|
||||
// uint32_t onionlen; /* total onion length */
|
||||
// uint32_t recvlen; /* length of the onion so far */
|
||||
|
||||
void *next;
|
||||
} circuit_t;
|
||||
@ -538,17 +531,18 @@ void circuit_dump_by_conn(connection_t *conn);
|
||||
|
||||
void circuit_expire_unused_circuits(void);
|
||||
void circuit_launch_new(int failure_status);
|
||||
int circuit_create_onion(void);
|
||||
int circuit_establish_circuit(unsigned int *route, int routelen, char *onion,
|
||||
int onionlen, crypt_path_t *cpath);
|
||||
int circuit_establish_circuit(void);
|
||||
void circuit_n_conn_open(connection_t *or_conn);
|
||||
int circuit_send_onion(connection_t *or_conn, circuit_t *circ);
|
||||
int circuit_send_next_onion_skin(circuit_t *circ);
|
||||
int circuit_extend(cell_t *cell, circuit_t *circ);
|
||||
int circuit_finish_handshake(circuit_t *circ, char *reply);
|
||||
|
||||
/********************************* command.c ***************************/
|
||||
|
||||
void command_process_cell(cell_t *cell, connection_t *conn);
|
||||
|
||||
void command_process_create_cell(cell_t *cell, connection_t *conn);
|
||||
void command_process_created_cell(cell_t *cell, connection_t *conn);
|
||||
void command_process_sendme_cell(cell_t *cell, connection_t *conn);
|
||||
void command_process_relay_cell(cell_t *cell, connection_t *conn);
|
||||
void command_process_destroy_cell(cell_t *cell, connection_t *conn);
|
||||
@ -775,23 +769,7 @@ int chooselen(double cw);
|
||||
*/
|
||||
unsigned int *new_route(double cw, routerinfo_t **rarray, int rarray_len, int *routelen);
|
||||
|
||||
/* creates a new onion from route, stores it and its length into bufp and lenp respectively */
|
||||
unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int *route, int routelen, int *len, crypt_path_t **cpath);
|
||||
|
||||
/* encrypts 128 bytes of the onion with the specified public key, the rest with
|
||||
* DES OFB with the key as defined in the outter layer */
|
||||
int encrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *pkey, char *keyseed);
|
||||
|
||||
/* decrypts the first 128 bytes using RSA and prkey, decrypts the rest with DES OFB with key1. Writes the first layer into 'layer' */
|
||||
int decrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *prkey, onion_layer_t *layer);
|
||||
|
||||
/* delete first n bytes of the onion and pads the end with n bytes of random data */
|
||||
void pad_onion(unsigned char *onion, uint32_t onionlen, int n);
|
||||
|
||||
void init_tracked_tree(void);
|
||||
|
||||
void onion_pack(char *dest, onion_layer_t *src);
|
||||
void onion_unpack(onion_layer_t *dest, char *src);
|
||||
crypt_path_t *onion_generate_cpath(routerinfo_t **firsthop);
|
||||
|
||||
int onion_skin_create(crypto_pk_env_t *router_key,
|
||||
crypto_dh_env_t **handshake_state_out,
|
||||
@ -814,10 +792,8 @@ int learn_my_address(struct sockaddr_in *me);
|
||||
void router_retry_connections(void);
|
||||
routerinfo_t *router_pick_directory_server(void);
|
||||
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port);
|
||||
unsigned int *router_new_route(int *routelen);
|
||||
unsigned char *router_create_onion(unsigned int *route, int routelen, int *len, crypt_path_t **cpath);
|
||||
void router_get_rarray(routerinfo_t ***prouter_array, int *prarray_len);
|
||||
int router_is_me(uint32_t addr, uint16_t port);
|
||||
routerinfo_t *router_get_first_in_route(unsigned int *route, int routelen);
|
||||
void router_forget_router(uint32_t addr, uint16_t port);
|
||||
int router_get_list_from_file(char *routerfile);
|
||||
int router_get_list_from_string(char *s);
|
||||
|
@ -98,18 +98,9 @@ routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
routerinfo_t *router_get_first_in_route(unsigned int *route, int routelen) {
|
||||
return router_array[route[routelen-1]];
|
||||
}
|
||||
|
||||
/* a wrapper around new_route. put all these in routers.c perhaps? */
|
||||
unsigned int *router_new_route(int *routelen) {
|
||||
return new_route(options.CoinWeight, router_array, rarray_len, routelen);
|
||||
}
|
||||
|
||||
/* a wrapper around create_onion */
|
||||
unsigned char *router_create_onion(unsigned int *route, int routelen, int *len, crypt_path_t **cpath) {
|
||||
return create_onion(router_array,rarray_len,route,routelen,len,cpath);
|
||||
void router_get_rarray(routerinfo_t ***prouter_array, int *prarray_len) {
|
||||
*prouter_array = router_array;
|
||||
*prarray_len = rarray_len;
|
||||
}
|
||||
|
||||
/* return 1 if addr and port corresponds to my addr and my or_listenport. else 0,
|
||||
@ -132,52 +123,6 @@ int router_is_me(uint32_t addr, uint16_t port)
|
||||
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
/* local host information */
|
||||
char localhostname[512];
|
||||
struct hostent *localhost;
|
||||
struct in_addr *a;
|
||||
char *tmp1;
|
||||
|
||||
char *addr = NULL;
|
||||
int i = 0;
|
||||
|
||||
/* obtain local host information */
|
||||
if (gethostname(localhostname,512) < 0) {
|
||||
log(LOG_ERR,"router_is_me(): Error obtaining local hostname.");
|
||||
return -1;
|
||||
}
|
||||
localhost = gethostbyname(localhostname);
|
||||
if (!localhost) {
|
||||
log(LOG_ERR,"router_is_me(): Error obtaining local host info.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check host addresses for a match with or_address above */
|
||||
addr = localhost->h_addr_list[i++]; /* set to the first local address */
|
||||
while(addr)
|
||||
{
|
||||
a = (struct in_addr *)addr;
|
||||
|
||||
tmp1 = strdup(inet_ntoa(*a)); /* can't call inet_ntoa twice in the same
|
||||
printf, since it overwrites its static
|
||||
memory each time */
|
||||
log(LOG_DEBUG,"router_is_me(): Comparing '%s' to '%s'.",tmp1,
|
||||
inet_ntoa( *((struct in_addr *)&or_address) ) );
|
||||
free(tmp1);
|
||||
if (!memcmp((void *)&or_address, (void *)addr, sizeof(uint32_t))) { /* addresses match */
|
||||
log(LOG_DEBUG,"router_is_me(): Addresses match. Comparing ports.");
|
||||
if (or_listenport == my_or_listenport) { /* ports also match */
|
||||
log(LOG_DEBUG,"router_is_me(): Ports match too.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
addr = localhost->h_addr_list[i++];
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* delete a list of routers from memory */
|
||||
|
Loading…
Reference in New Issue
Block a user