Commit 8a94dd60 authored by Roger Dingledine's avatar Roger Dingledine
Browse files

cpath is now a doubly linked list, not an array


svn:r260
parent 1eeb3f65
......@@ -89,8 +89,7 @@ void circuit_free(circuit_t *circ) {
if(circ->onion)
free(circ->onion);
if(circ->cpath)
circuit_free_cpath(circ->cpath, circ->cpathlen);
circuit_free_cpath(circ->cpath);
while(circ->relay_queue) {
tmpd = circ->relay_queue;
circ->relay_queue = tmpd->next;
......@@ -101,13 +100,29 @@ void circuit_free(circuit_t *circ) {
free(circ);
}
void circuit_free_cpath(crypt_path_t **cpath, int cpathlen) {
int i;
void circuit_free_cpath(crypt_path_t *cpath) {
crypt_path_t *victim, *head=cpath;
for(i=0;i<cpathlen;i++)
free(cpath[i]);
if(!cpath)
return;
/* it's a doubly linked list, so we have to notice when we've
* gone through it once. */
while(cpath->next && cpath->next != head) {
victim = cpath;
cpath = victim->next;
circuit_free_cpath_node(victim);
}
circuit_free_cpath_node(cpath);
}
free(cpath);
void circuit_free_cpath_node(crypt_path_t *victim) {
if(victim->f_crypto)
crypto_free_cipher_env(victim->f_crypto);
if(victim->b_crypto)
crypto_free_cipher_env(victim->b_crypto);
free(victim);
}
/* return 0 if can't get a unique aci. */
......@@ -250,23 +265,18 @@ circuit_t *circuit_get_by_conn(connection_t *conn) {
return NULL;
}
circuit_t *circuit_get_newest_by_edge_type(char edge_type) {
circuit_t *circuit_get_newest_ap(void) {
circuit_t *circ, *bestcirc=NULL;
for(circ=global_circuitlist;circ;circ = circ->next) {
if(edge_type == EDGE_AP && (!circ->p_conn || circ->p_conn->type == CONN_TYPE_AP)) {
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_by_edge_type(): Choosing n_aci %d.", circ->n_aci);
log(LOG_DEBUG,"circuit_get_newest_ap(): Choosing n_aci %d.", circ->n_aci);
assert(circ->n_aci);
bestcirc = circ;
}
}
if(edge_type == EDGE_EXIT && (!circ->n_conn || circ->n_conn->type == CONN_TYPE_EXIT)) {
if(circ->state == CIRCUIT_STATE_OPEN && (!bestcirc ||
bestcirc->timestamp_created < circ->timestamp_created))
bestcirc = circ;
}
}
return bestcirc;
}
......@@ -346,7 +356,6 @@ int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ, int cell_direction
int circuit_crypt(circuit_t *circ, char *in, int inlen, char cell_direction) {
char *out;
int i;
crypt_path_t *thishop;
assert(circ && in);
......@@ -357,12 +366,10 @@ int circuit_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. */
for (i=circ->cpathlen-1; i >= 0; i--) /* moving from first to last hop
* Remember : cpath is in reverse order, i.e. last hop first
*/
{
thishop = circ->cpath[i];
thishop = circ->cpath;
/* Remember: cpath is in forward order, that is, first hop first. */
do {
assert(thishop);
/* decrypt */
if(crypto_cipher_decrypt(thishop->b_crypto, in, inlen, out)) {
log(LOG_ERR,"Error performing decryption:%s",crypto_perror());
......@@ -372,7 +379,8 @@ int circuit_crypt(circuit_t *circ, char *in, int inlen, char cell_direction) {
/* copy ciphertext back to buf */
memcpy(in,out,inlen);
}
thishop = thishop->next;
} while(thishop != circ->cpath);
} else { /* we're in the middle. Just one crypt. */
if(crypto_cipher_encrypt(circ->p_crypto,in, inlen, out)) {
log(LOG_ERR,"circuit_encrypt(): Encryption failed for ACI : %u (%s).",
......@@ -384,12 +392,10 @@ int circuit_crypt(circuit_t *circ, char *in, int inlen, char cell_direction) {
}
} 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. */
for (i=0; i < circ->cpathlen; i++) /* moving from last to first hop
* Remember : cpath is in reverse order, i.e. last hop first
*/
{
thishop = circ->cpath[i];
thishop = circ->cpath->prev;
/* moving from last to first hop */
do {
assert(thishop);
/* encrypt */
if(crypto_cipher_encrypt(thishop->f_crypto, in, inlen, (unsigned char *)out)) {
log(LOG_ERR,"Error performing encryption:%s",crypto_perror());
......@@ -399,7 +405,8 @@ int circuit_crypt(circuit_t *circ, char *in, int inlen, char cell_direction) {
/* 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).",
......@@ -524,7 +531,7 @@ void circuit_close(circuit_t *circ) {
assert(circ);
if(options.APPort) {
youngest = circuit_get_newest_by_edge_type(EDGE_AP);
youngest = circuit_get_newest_ap();
log(LOG_DEBUG,"circuit_close(): youngest %d, circ %d.",youngest,circ);
}
circuit_remove(circ);
......@@ -623,7 +630,7 @@ void circuit_expire_unused_circuits(void) {
circuit_t *circ, *tmpcirc;
circuit_t *youngest;
youngest = circuit_get_newest_by_edge_type(EDGE_AP);
youngest = circuit_get_newest_ap();
circ = global_circuitlist;
while(circ) {
......@@ -674,7 +681,7 @@ int circuit_create_onion(void) {
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 */
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);
......@@ -684,30 +691,21 @@ int circuit_create_onion(void) {
}
log(LOG_DEBUG,"circuit_create_onion(): Chosen a route of length %u : ",routelen);
/* allocate memory for the crypt path */
cpath = malloc(routelen * sizeof(crypt_path_t *));
if (!cpath) {
log(LOG_ERR,"circuit_create_onion(): Error allocating memory for cpath.");
free(route);
return -1;
}
/* create an onion and calculate crypto keys */
onion = router_create_onion(route,routelen,&onionlen,cpath);
onion = router_create_onion(route,routelen,&onionlen, &cpath);
if (!onion) {
log(LOG_ERR,"circuit_create_onion(): Error creating an onion.");
free(route);
free(cpath); /* it's got nothing in it, since !onion */
return -1;
}
log(LOG_DEBUG,"circuit_create_onion(): Created an onion of size %u bytes.",onionlen);
log(LOG_DEBUG,"circuit_create_onion(): Crypt path :");
// 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 onionlen, crypt_path_t *cpath) {
routerinfo_t *firsthop;
connection_t *n_conn;
circuit_t *circ;
......@@ -722,7 +720,6 @@ int circuit_establish_circuit(unsigned int *route, int routelen, char *onion,
circ->onion = onion;
circ->onionlen = onionlen;
circ->cpath = cpath;
circ->cpathlen = routelen;
log(LOG_DEBUG,"circuit_establish_circuit(): Looking for firsthop '%s:%u'",
firsthop->address,firsthop->or_port);
......
......@@ -94,7 +94,7 @@ int ap_handshake_process_socks(connection_t *conn) {
}
/* find the circuit that we should use, if there is one. */
circ = circuit_get_newest_by_edge_type(EDGE_AP);
circ = circuit_get_newest_ap();
if(!circ) {
log(LOG_INFO,"ap_handshake_process_socks(): No circuit ready. Closing.");
......
......@@ -325,7 +325,7 @@ int prepare_for_poll(int *timeout) {
if(options.APPort && time_to_new_circuit < now.tv_sec) {
circuit_expire_unused_circuits();
circuit_launch_new(-1); /* tell it to forget about previous failures */
circ = circuit_get_newest_by_edge_type(EDGE_AP);
circ = circuit_get_newest_ap();
if(!circ || circ->dirty) {
log(LOG_INFO,"prepare_for_poll(): Youngest circuit %s; launching replacement.", circ ? "dirty" : "missing");
circuit_launch_new(0); /* make an onion and lay the circuit */
......
......@@ -434,22 +434,24 @@ static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len) {
/* 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)
{
int i,j;
int i;
char *layerp;
crypt_path_t *hop = NULL;
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);
assert(rarray && route && len && routelen && cpath);
*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) {
......@@ -457,7 +459,7 @@ unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int
return NULL;
}
log(LOG_DEBUG,"create_onion() : Allocated memory for the onion.");
for(i=0; i<routelen; i++) {
netaddr.s_addr = htonl((rarray[route[i]])->addr);
......@@ -467,29 +469,20 @@ unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int
(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 */
for (i=0;i<routelen;i++) {
router = rarray[route[i]];
// log(LOG_DEBUG,"create_onion() : %u",router);
// log(LOG_DEBUG,"create_onion() : This router is %s:%u",inet_ntoa(*((struct in_addr *)&router->addr)),router->or_port);
// log(LOG_DEBUG,"create_onion() : Key pointer = %u.",router->pkey);
// log(LOG_DEBUG,"create_onion() : Key size = %u.",crypto_pk_keysize(router->pkey));
layer.version = OR_VERSION;
if (i) /* not last hop */
if (i) { /* not last hop */
layer.port = rarray[route[i-1]]->or_port;
else
layer.port = 0;
/* Dest Addr */
if (i) /* not last hop */
layer.addr = rarray[route[i-1]]->addr;
else
} else {
layer.port = 0;
layer.addr = 0;
}
/* Expiration Time */
layer.expire = (uint32_t)(time(NULL) + 86400); /* NOW + 1 day */
......@@ -503,47 +496,53 @@ unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int
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 */
if(cpath) {
cpath[i] = (crypt_path_t *)malloc(sizeof(crypt_path_t));
if(!cpath[i]) {
log(LOG_ERR,"Error allocating memory.");
goto error;
}
log(LOG_DEBUG,"create_onion() : Building hop %u of crypt path.",i+1);
hop = cpath[i];
/* 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;
}
hop = (crypt_path_t *)malloc(sizeof(crypt_path_t));
if(!hop) {
log(LOG_ERR,"Error allocating memory.");
goto error;
}
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.");
/* link hop into the cpath, at the front */
hop->next = *cpath;
hop->prev = NULL;
hop->state = CPATH_STATE_OPEN; /* change when we move to incremental paths */
if(*cpath) {
(*cpath)->prev = 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 (! (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 */
......@@ -552,7 +551,7 @@ unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int
}
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) {
......@@ -560,25 +559,22 @@ unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int
goto error;
}
log(LOG_DEBUG,"create_onion() : Encrypted layer.");
/* calculate pointer to next layer */
layerp = buf + (routelen-i-2)*ONION_LAYER_SIZE;
}
/* now link cpath->prev to the end of cpath */
for(hop=*cpath; hop->next; hop=hop->next) ;
hop->next = *cpath;
(*cpath)->prev = hop;
return buf;
error:
if (buf)
if(buf)
free(buf);
if (cpath) {
for (j=0;j<i;j++) {
if(cpath[i]->f_crypto)
crypto_free_cipher_env(cpath[i]->f_crypto);
if(cpath[i]->b_crypto)
crypto_free_cipher_env(cpath[i]->b_crypto);
free((void *)cpath[i]);
}
}
circuit_free_cpath(*cpath);
return NULL;
}
......
......@@ -342,7 +342,14 @@ typedef struct {
/* crypto environments */
crypto_cipher_env_t *f_crypto;
crypto_cipher_env_t *b_crypto;
char state;
#define CPATH_STATE_CLOSED 0
#define CPATH_STATE_AWAITING_KEY 1
#define CPATH_STATE_OPEN 2
void *next;
void *prev; /* doubly linked list */
} crypt_path_t;
struct relay_queue_t {
......@@ -355,7 +362,7 @@ typedef struct {
uint32_t n_addr;
uint16_t n_port;
connection_t *p_conn;
connection_t *n_conn;
connection_t *n_conn; /* convention: first conn is the OR conn, if there is one */
int n_receive_circwindow;
int p_receive_circwindow;
......@@ -364,11 +371,10 @@ typedef struct {
struct relay_queue_t *relay_queue; /* for queueing cells at the edges */
crypto_cipher_env_t *p_crypto; /* crypto environments */
crypto_cipher_env_t *p_crypto; /* used only for intermediate hops */
crypto_cipher_env_t *n_crypto;
crypt_path_t **cpath;
int cpathlen;
crypt_path_t *cpath;
uint32_t expire; /* expiration time for the corresponding onion */
long timestamp_created;
......@@ -497,7 +503,7 @@ aci_t get_unique_aci_by_addr_port(uint32_t addr, uint16_t port, int aci_type);
circuit_t *circuit_get_by_aci_conn(aci_t aci, connection_t *conn);
circuit_t *circuit_get_by_conn(connection_t *conn);
circuit_t *circuit_get_newest_by_edge_type(char edge_type);
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);
......@@ -510,7 +516,8 @@ int circuit_consider_sending_sendme(circuit_t *circ, int edge_type);
int circuit_init(circuit_t *circ, int aci_type, onion_layer_t *layer);
void circuit_free(circuit_t *circ);
void circuit_free_cpath(crypt_path_t **cpath, int cpathlen);
void circuit_free_cpath(crypt_path_t *cpath);
void circuit_free_cpath_node(crypt_path_t *victim);
void circuit_close(circuit_t *circ);
......@@ -523,7 +530,7 @@ 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 onionlen, crypt_path_t *cpath);
void circuit_n_conn_open(connection_t *or_conn);
int circuit_send_onion(connection_t *or_conn, circuit_t *circ);
......
......@@ -475,7 +475,7 @@ main(int c, char**v) {
test_buffers();
puts("========================== Crypto ==========================");
test_crypto_dh();
test_crypto(); /* this seg faults :( */ /* Still? -NM 2003/04/30 */
test_crypto();
puts("\n========================== Util ============================");
test_util();
puts("");
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment