2003-10-08 04:04:08 +02:00
|
|
|
/* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
|
Implemented link padding and receiver token buckets
Each socket reads at most 'bandwidth' bytes per second sustained, but
can handle bursts of up to 10*bandwidth bytes.
Cells are now sent out at evenly-spaced intervals, with padding sent
out otherwise. Set Linkpadding=0 in the rc file to send cells as soon
as they're available (and to never send padding cells).
Added license/copyrights statements at the top of most files.
router->min and router->max have been merged into a single 'bandwidth'
value. We should make the routerinfo_t reflect this (want to do that,
Mat?)
As the bandwidth increases, and we want to stop sleeping more and more
frequently to send a single cell, cpu usage goes up. At 128kB/s we're
pretty much calling poll with a timeout of 1ms or even 0ms. The current
code takes a timeout of 0-9ms and makes it 10ms. prepare_for_poll()
handles everything that should have happened in the past, so as long as
our buffers don't get too full in that 10ms, we're ok.
Speaking of too full, if you run three servers at 100kB/s with -l debug,
it spends too much time printing debugging messages to be able to keep
up with the cells. The outbuf ultimately fills up and it kills that
connection. If you run with -l err, it works fine up through 500kB/s and
probably beyond. Down the road we'll want to teach it to recognize when
an outbuf is getting full, and back off.
svn:r50
2002-07-16 03:12:15 +02:00
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
/* $Id$ */
|
2002-06-27 00:45:49 +02:00
|
|
|
|
|
|
|
#include "or.h"
|
|
|
|
|
2002-11-27 05:08:20 +01:00
|
|
|
extern or_options_t options; /* command-line and config-file options */
|
2002-09-04 08:29:28 +02:00
|
|
|
|
2003-04-08 08:44:38 +02:00
|
|
|
static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len);
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2003-11-11 04:01:48 +01:00
|
|
|
int decide_circ_id_type(char *local_nick, char *remote_nick) {
|
2003-10-01 03:49:53 +02:00
|
|
|
int result;
|
|
|
|
|
|
|
|
assert(remote_nick);
|
|
|
|
if(!local_nick)
|
2003-11-11 04:01:48 +01:00
|
|
|
return CIRC_ID_TYPE_LOWER;
|
2003-10-01 03:49:53 +02:00
|
|
|
result = strcmp(local_nick, remote_nick);
|
|
|
|
assert(result);
|
|
|
|
if(result < 0)
|
2003-11-11 04:01:48 +01:00
|
|
|
return CIRC_ID_TYPE_LOWER;
|
|
|
|
return CIRC_ID_TYPE_HIGHER;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
|
|
|
|
2003-09-16 22:57:09 +02:00
|
|
|
struct onion_queue_t {
|
|
|
|
circuit_t *circ;
|
|
|
|
struct onion_queue_t *next;
|
|
|
|
};
|
|
|
|
|
2002-11-27 05:08:20 +01:00
|
|
|
/* global (within this file) variables used by the next few functions */
|
|
|
|
static struct onion_queue_t *ol_list=NULL;
|
|
|
|
static struct onion_queue_t *ol_tail=NULL;
|
|
|
|
static int ol_length=0;
|
|
|
|
|
|
|
|
int onion_pending_add(circuit_t *circ) {
|
|
|
|
struct onion_queue_t *tmp;
|
|
|
|
|
2003-05-20 08:41:23 +02:00
|
|
|
tmp = tor_malloc(sizeof(struct onion_queue_t));
|
2002-11-27 05:08:20 +01:00
|
|
|
memset(tmp, 0, sizeof(struct onion_queue_t));
|
|
|
|
tmp->circ = circ;
|
|
|
|
|
|
|
|
if(!ol_tail) {
|
|
|
|
assert(!ol_list);
|
|
|
|
assert(!ol_length);
|
|
|
|
ol_list = tmp;
|
|
|
|
ol_tail = tmp;
|
|
|
|
ol_length++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(ol_list);
|
|
|
|
assert(!ol_tail->next);
|
|
|
|
|
|
|
|
if(ol_length >= options.MaxOnionsPending) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"Already have %d onions queued. Closing.", ol_length);
|
2002-11-27 05:08:20 +01:00
|
|
|
free(tmp);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ol_length++;
|
|
|
|
ol_tail->next = tmp;
|
|
|
|
ol_tail = tmp;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2003-08-21 01:05:22 +02:00
|
|
|
circuit_t *onion_next_task(void) {
|
2003-09-14 10:17:14 +02:00
|
|
|
circuit_t *circ;
|
2002-11-27 05:08:20 +01:00
|
|
|
|
|
|
|
if(!ol_list)
|
2003-08-21 01:05:22 +02:00
|
|
|
return NULL; /* no onions pending, we're done */
|
2002-11-27 05:08:20 +01:00
|
|
|
|
2003-05-06 01:24:46 +02:00
|
|
|
assert(ol_list->circ);
|
2003-05-20 08:41:23 +02:00
|
|
|
if(!ol_list->circ->p_conn) {
|
2003-08-21 01:05:22 +02:00
|
|
|
log_fn(LOG_INFO,"ol_list->circ->p_conn null, must have died?");
|
2003-05-20 08:41:23 +02:00
|
|
|
onion_pending_remove(ol_list->circ);
|
2003-08-21 01:05:22 +02:00
|
|
|
return onion_next_task(); /* recurse: how about the next one? */
|
2003-05-20 08:41:23 +02:00
|
|
|
}
|
|
|
|
|
2002-11-27 05:08:20 +01:00
|
|
|
assert(ol_length > 0);
|
2003-09-14 10:17:14 +02:00
|
|
|
circ = ol_list->circ;
|
|
|
|
onion_pending_remove(ol_list->circ);
|
|
|
|
return circ;
|
2002-11-27 05:08:20 +01:00
|
|
|
}
|
|
|
|
|
2002-12-03 23:18:23 +01:00
|
|
|
/* go through ol_list, find the onion_queue_t element which points to
|
|
|
|
* circ, remove and free that element. leave circ itself alone.
|
2002-11-27 05:08:20 +01:00
|
|
|
*/
|
|
|
|
void onion_pending_remove(circuit_t *circ) {
|
|
|
|
struct onion_queue_t *tmpo, *victim;
|
|
|
|
|
|
|
|
if(!ol_list)
|
|
|
|
return; /* nothing here. */
|
|
|
|
|
|
|
|
/* first check to see if it's the first entry */
|
|
|
|
tmpo = ol_list;
|
|
|
|
if(tmpo->circ == circ) {
|
|
|
|
/* it's the first one. remove it from the list. */
|
|
|
|
ol_list = tmpo->next;
|
|
|
|
if(!ol_list)
|
|
|
|
ol_tail = NULL;
|
|
|
|
ol_length--;
|
|
|
|
victim = tmpo;
|
|
|
|
} else { /* we need to hunt through the rest of the list */
|
|
|
|
for( ;tmpo->next && tmpo->next->circ != circ; tmpo=tmpo->next) ;
|
|
|
|
if(!tmpo->next) {
|
2003-11-11 04:01:48 +01:00
|
|
|
log_fn(LOG_DEBUG,"circ (p_circ_id %d) not in list, probably at cpuworker.",circ->p_circ_id);
|
2002-11-27 05:08:20 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* now we know tmpo->next->circ == circ */
|
|
|
|
victim = tmpo->next;
|
|
|
|
tmpo->next = victim->next;
|
|
|
|
if(ol_tail == victim)
|
|
|
|
ol_tail = tmpo;
|
|
|
|
ol_length--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now victim points to the element that needs to be removed */
|
|
|
|
|
|
|
|
free(victim);
|
|
|
|
}
|
|
|
|
|
2003-08-21 01:05:22 +02:00
|
|
|
/* given a response payload and keys, initialize, then send a created cell back */
|
2003-09-14 04:58:50 +02:00
|
|
|
int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *keys) {
|
2003-05-06 01:24:46 +02:00
|
|
|
unsigned char iv[16];
|
2002-11-27 05:08:20 +01:00
|
|
|
cell_t cell;
|
|
|
|
|
2003-05-06 01:24:46 +02:00
|
|
|
memset(iv, 0, 16);
|
2002-10-03 00:54:20 +02:00
|
|
|
|
2003-05-06 01:24:46 +02:00
|
|
|
memset(&cell, 0, sizeof(cell_t));
|
|
|
|
cell.command = CELL_CREATED;
|
2003-11-11 04:01:48 +01:00
|
|
|
cell.circ_id = circ->p_circ_id;
|
2003-05-06 07:54:42 +02:00
|
|
|
cell.length = DH_KEY_LEN;
|
2003-05-06 01:24:46 +02:00
|
|
|
|
|
|
|
circ->state = CIRCUIT_STATE_OPEN;
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2003-08-21 01:05:22 +02:00
|
|
|
log_fn(LOG_DEBUG,"Entering.");
|
2003-05-06 01:24:46 +02:00
|
|
|
|
2003-08-21 01:05:22 +02:00
|
|
|
memcpy(cell.payload, payload, DH_KEY_LEN);
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2003-08-21 01:05:22 +02:00
|
|
|
log_fn(LOG_DEBUG,"init cipher forward %d, backward %d.", *(int*)keys, *(int*)(keys+16));
|
2003-05-06 01:24:46 +02:00
|
|
|
|
|
|
|
if (!(circ->n_crypto =
|
2003-07-30 21:12:03 +02:00
|
|
|
crypto_create_init_cipher(CIRCUIT_CIPHER,keys,iv,0))) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"Cipher initialization failed (n).");
|
2002-06-27 00:45:49 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2003-05-06 01:24:46 +02:00
|
|
|
if (!(circ->p_crypto =
|
2003-07-30 21:12:03 +02:00
|
|
|
crypto_create_init_cipher(CIRCUIT_CIPHER,keys+16,iv,1))) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"Cipher initialization failed (p).");
|
2002-06-27 00:45:49 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2003-10-09 20:45:14 +02:00
|
|
|
connection_or_write_cell_to_buf(&cell, circ->p_conn);
|
2003-08-21 01:05:22 +02:00
|
|
|
log_fn(LOG_DEBUG,"Finished sending 'created' cell.");
|
2002-06-27 00:45:49 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Integrated onion proxy into or/
The 'or' process can now be told (by the global_role variable) what
roles this server should play -- connect to all ORs, listen for ORs,
listen for OPs, listen for APs, or any combination.
* everything in /src/op/ is now obsolete.
* connection_ap.c now handles all interactions with application proxies
* "port" is now or_port, op_port, ap_port. But routers are still always
referenced (say, in conn_get_by_addr_port()) by addr / or_port. We
should make routers.c actually read these new ports (currently I've
kludged it so op_port = or_port+10, ap_port=or_port+20)
* circuits currently know if they're at the beginning of the path because
circ->cpath is set. They use this instead for crypts (both ways),
if it's set.
* I still obey the "send a 0 back to the AP when you're ready" protocol,
but I think we should phase it out. I can simply not read from the AP
socket until I'm ready.
I need to do a lot of cleanup work here, but the code appears to work, so
now's a good time for a checkin.
svn:r22
2002-07-02 11:36:58 +02:00
|
|
|
/* uses a weighted coin with weight cw to choose a route length */
|
2003-09-16 07:41:49 +02:00
|
|
|
static int chooselen(double cw) {
|
Integrated onion proxy into or/
The 'or' process can now be told (by the global_role variable) what
roles this server should play -- connect to all ORs, listen for ORs,
listen for OPs, listen for APs, or any combination.
* everything in /src/op/ is now obsolete.
* connection_ap.c now handles all interactions with application proxies
* "port" is now or_port, op_port, ap_port. But routers are still always
referenced (say, in conn_get_by_addr_port()) by addr / or_port. We
should make routers.c actually read these new ports (currently I've
kludged it so op_port = or_port+10, ap_port=or_port+20)
* circuits currently know if they're at the beginning of the path because
circ->cpath is set. They use this instead for crypts (both ways),
if it's set.
* I still obey the "send a 0 back to the AP when you're ready" protocol,
but I think we should phase it out. I can simply not read from the AP
socket until I'm ready.
I need to do a lot of cleanup work here, but the code appears to work, so
now's a good time for a checkin.
svn:r22
2002-07-02 11:36:58 +02:00
|
|
|
int len = 2;
|
2003-04-17 19:10:41 +02:00
|
|
|
uint8_t coin;
|
Integrated onion proxy into or/
The 'or' process can now be told (by the global_role variable) what
roles this server should play -- connect to all ORs, listen for ORs,
listen for OPs, listen for APs, or any combination.
* everything in /src/op/ is now obsolete.
* connection_ap.c now handles all interactions with application proxies
* "port" is now or_port, op_port, ap_port. But routers are still always
referenced (say, in conn_get_by_addr_port()) by addr / or_port. We
should make routers.c actually read these new ports (currently I've
kludged it so op_port = or_port+10, ap_port=or_port+20)
* circuits currently know if they're at the beginning of the path because
circ->cpath is set. They use this instead for crypts (both ways),
if it's set.
* I still obey the "send a 0 back to the AP when you're ready" protocol,
but I think we should phase it out. I can simply not read from the AP
socket until I'm ready.
I need to do a lot of cleanup work here, but the code appears to work, so
now's a good time for a checkin.
svn:r22
2002-07-02 11:36:58 +02:00
|
|
|
|
|
|
|
if ((cw < 0) || (cw >= 1)) /* invalid parameter */
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while(1)
|
|
|
|
{
|
2003-04-17 19:10:41 +02:00
|
|
|
if (CRYPTO_PSEUDO_RAND_INT(coin))
|
Integrated onion proxy into or/
The 'or' process can now be told (by the global_role variable) what
roles this server should play -- connect to all ORs, listen for ORs,
listen for OPs, listen for APs, or any combination.
* everything in /src/op/ is now obsolete.
* connection_ap.c now handles all interactions with application proxies
* "port" is now or_port, op_port, ap_port. But routers are still always
referenced (say, in conn_get_by_addr_port()) by addr / or_port. We
should make routers.c actually read these new ports (currently I've
kludged it so op_port = or_port+10, ap_port=or_port+20)
* circuits currently know if they're at the beginning of the path because
circ->cpath is set. They use this instead for crypts (both ways),
if it's set.
* I still obey the "send a 0 back to the AP when you're ready" protocol,
but I think we should phase it out. I can simply not read from the AP
socket until I'm ready.
I need to do a lot of cleanup work here, but the code appears to work, so
now's a good time for a checkin.
svn:r22
2002-07-02 11:36:58 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (coin > cw*255) /* don't extend */
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
static int new_route_len(double cw, routerinfo_t **rarray, int rarray_len) {
|
2003-04-08 08:44:38 +02:00
|
|
|
int num_acceptable_routers;
|
2003-11-12 03:32:20 +01:00
|
|
|
int routelen;
|
2003-04-16 08:18:31 +02:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
assert((cw >= 0) && (cw < 1) && (rarray) ); /* valid parameters */
|
2002-07-22 06:38:36 +02:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
routelen = chooselen(cw);
|
|
|
|
if (routelen == -1) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"Choosing route length failed.");
|
2003-11-12 03:32:20 +01:00
|
|
|
return -1;
|
2002-08-23 05:35:44 +02:00
|
|
|
}
|
2003-11-12 03:32:20 +01:00
|
|
|
log_fn(LOG_DEBUG,"Chosen route length %d (%d routers available).",routelen, rarray_len);
|
2002-08-23 05:35:44 +02:00
|
|
|
|
2003-04-08 08:44:38 +02:00
|
|
|
num_acceptable_routers = count_acceptable_routers(rarray, rarray_len);
|
|
|
|
|
2003-04-16 08:18:31 +02:00
|
|
|
if(num_acceptable_routers < 2) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_INFO,"Not enough acceptable routers. Failing.");
|
2003-11-12 03:32:20 +01:00
|
|
|
return -1;
|
2003-04-16 08:18:31 +02:00
|
|
|
}
|
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
if(num_acceptable_routers < routelen) {
|
|
|
|
log_fn(LOG_INFO,"Not enough routers: cutting routelen from %d to %d.",routelen, num_acceptable_routers);
|
|
|
|
routelen = num_acceptable_routers;
|
2002-08-23 05:35:44 +02:00
|
|
|
}
|
2002-07-22 06:38:36 +02:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
if (routelen < 1) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"Didn't find any acceptable routers. Failing.");
|
2003-11-12 03:32:20 +01:00
|
|
|
return -1;
|
2002-08-23 05:35:44 +02:00
|
|
|
}
|
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
return routelen;
|
Integrated onion proxy into or/
The 'or' process can now be told (by the global_role variable) what
roles this server should play -- connect to all ORs, listen for ORs,
listen for OPs, listen for APs, or any combination.
* everything in /src/op/ is now obsolete.
* connection_ap.c now handles all interactions with application proxies
* "port" is now or_port, op_port, ap_port. But routers are still always
referenced (say, in conn_get_by_addr_port()) by addr / or_port. We
should make routers.c actually read these new ports (currently I've
kludged it so op_port = or_port+10, ap_port=or_port+20)
* circuits currently know if they're at the beginning of the path because
circ->cpath is set. They use this instead for crypts (both ways),
if it's set.
* I still obey the "send a 0 back to the AP when you're ready" protocol,
but I think we should phase it out. I can simply not read from the AP
socket until I'm ready.
I need to do a lot of cleanup work here, but the code appears to work, so
now's a good time for a checkin.
svn:r22
2002-07-02 11:36:58 +02:00
|
|
|
}
|
|
|
|
|
2003-11-12 03:55:38 +01:00
|
|
|
int onion_new_route_len(void) {
|
|
|
|
directory_t *dir;
|
|
|
|
|
|
|
|
router_get_directory(&dir);
|
|
|
|
return new_route_len(options.CoinWeight, dir->routers, dir->n_routers);
|
|
|
|
}
|
|
|
|
|
2003-04-08 08:44:38 +02:00
|
|
|
static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len) {
|
|
|
|
int i, j;
|
|
|
|
int num=0;
|
2003-04-16 08:18:31 +02:00
|
|
|
connection_t *conn;
|
2003-04-08 08:44:38 +02:00
|
|
|
|
|
|
|
for(i=0;i<rarray_len;i++) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_DEBUG,"Contemplating whether router %d is a new option...",i);
|
2003-05-28 04:03:25 +02:00
|
|
|
if(options.OnionRouter) {
|
2003-04-16 08:18:31 +02:00
|
|
|
conn = connection_exact_get_by_addr_port(rarray[i]->addr, rarray[i]->or_port);
|
|
|
|
if(!conn || conn->type != CONN_TYPE_OR || conn->state != OR_CONN_STATE_OPEN) {
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_DEBUG,"Nope, %d is not connected.",i);
|
2003-04-16 08:18:31 +02:00
|
|
|
goto next_i_loop;
|
|
|
|
}
|
2003-04-08 08:44:38 +02:00
|
|
|
}
|
|
|
|
for(j=0;j<i;j++) {
|
2003-09-25 07:17:11 +02:00
|
|
|
if(!crypto_pk_cmp_keys(rarray[i]->onion_pkey, rarray[j]->onion_pkey)) {
|
2003-04-08 08:44:38 +02:00
|
|
|
/* these guys are twins. so we've already counted him. */
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_DEBUG,"Nope, %d is a twin of %d.",i,j);
|
2003-04-08 08:44:38 +02:00
|
|
|
goto next_i_loop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
num++;
|
2003-09-26 12:03:50 +02:00
|
|
|
log_fn(LOG_DEBUG,"I like %d. num_acceptable_routers now %d.",i, num);
|
2003-04-08 08:44:38 +02:00
|
|
|
next_i_loop:
|
|
|
|
; /* our compiler may need an explicit statement after the label */
|
|
|
|
}
|
|
|
|
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
int onion_extend_cpath(crypt_path_t **head_ptr, int path_len, routerinfo_t **router_out)
|
|
|
|
{
|
|
|
|
int cur_len;
|
|
|
|
crypt_path_t *cpath, *hop;
|
|
|
|
routerinfo_t **rarray, *r;
|
|
|
|
unsigned int choice;
|
|
|
|
int rarray_len;
|
|
|
|
int i;
|
|
|
|
directory_t *dir;
|
2003-05-02 00:55:51 +02:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
assert(head_ptr);
|
|
|
|
if (router_out)
|
|
|
|
*router_out = NULL;
|
2002-11-23 07:49:01 +01:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
router_get_directory(&dir);
|
|
|
|
rarray = dir->routers;
|
|
|
|
rarray_len = dir->n_routers;
|
|
|
|
|
|
|
|
if (!*head_ptr) {
|
|
|
|
cur_len = 0;
|
|
|
|
} else {
|
|
|
|
cur_len = 1;
|
|
|
|
for (cpath = *head_ptr; cpath->next != *head_ptr; cpath = cpath->next) {
|
|
|
|
++cur_len;
|
|
|
|
}
|
2002-11-23 07:49:01 +01:00
|
|
|
}
|
2003-11-12 03:32:20 +01:00
|
|
|
if (cur_len >= path_len) { return 1; }
|
|
|
|
log_fn(LOG_DEBUG, "Path is %d long; we want %d", cur_len, path_len);
|
2003-05-02 00:55:51 +02:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
again:
|
|
|
|
if (CRYPTO_PSEUDO_RAND_INT(choice)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
choice %= rarray_len;
|
|
|
|
log_fn(LOG_DEBUG,"Contemplating router %s for hop %d",
|
|
|
|
rarray[choice]->nickname, cur_len);
|
|
|
|
for (i = 0, cpath = *head_ptr; i < cur_len; ++i, cpath=cpath->next) {
|
|
|
|
r = router_get_by_addr_port(cpath->addr, cpath->port);
|
|
|
|
if ((r && !crypto_pk_cmp_keys(r->onion_pkey, rarray[choice]->onion_pkey))
|
|
|
|
|| (cpath->addr == rarray[choice]->addr &&
|
|
|
|
cpath->port == rarray[choice]->or_port)
|
|
|
|
|| (options.OnionRouter &&
|
|
|
|
!(connection_twin_get_by_addr_port(rarray[choice]->addr,
|
|
|
|
rarray[choice]->or_port)))) {
|
|
|
|
log_fn(LOG_DEBUG, "Picked an already-selected router for hop %d; retrying.",
|
|
|
|
cur_len);
|
|
|
|
goto again;
|
2002-11-23 07:49:01 +01:00
|
|
|
}
|
2003-11-12 03:32:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Okay, so we haven't used 'choice' before. */
|
|
|
|
hop = (crypt_path_t *)tor_malloc(sizeof(crypt_path_t));
|
|
|
|
memset(hop, 0, sizeof(crypt_path_t));
|
|
|
|
|
|
|
|
/* link hop into the cpath, at the end. */
|
|
|
|
if (*head_ptr) {
|
|
|
|
hop->next = (*head_ptr);
|
|
|
|
hop->prev = (*head_ptr)->prev;
|
|
|
|
(*head_ptr)->prev->next = hop;
|
|
|
|
(*head_ptr)->prev = hop;
|
|
|
|
} else {
|
|
|
|
*head_ptr = hop;
|
|
|
|
hop->prev = hop->next = hop;
|
2002-11-23 07:49:01 +01:00
|
|
|
}
|
Integrated onion proxy into or/
The 'or' process can now be told (by the global_role variable) what
roles this server should play -- connect to all ORs, listen for ORs,
listen for OPs, listen for APs, or any combination.
* everything in /src/op/ is now obsolete.
* connection_ap.c now handles all interactions with application proxies
* "port" is now or_port, op_port, ap_port. But routers are still always
referenced (say, in conn_get_by_addr_port()) by addr / or_port. We
should make routers.c actually read these new ports (currently I've
kludged it so op_port = or_port+10, ap_port=or_port+20)
* circuits currently know if they're at the beginning of the path because
circ->cpath is set. They use this instead for crypts (both ways),
if it's set.
* I still obey the "send a 0 back to the AP when you're ready" protocol,
but I think we should phase it out. I can simply not read from the AP
socket until I'm ready.
I need to do a lot of cleanup work here, but the code appears to work, so
now's a good time for a checkin.
svn:r22
2002-07-02 11:36:58 +02:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
hop->state = CPATH_STATE_CLOSED;
|
|
|
|
|
|
|
|
hop->port = rarray[choice]->or_port;
|
|
|
|
hop->addr = rarray[choice]->addr;
|
|
|
|
|
|
|
|
hop->package_window = CIRCWINDOW_START;
|
|
|
|
hop->deliver_window = CIRCWINDOW_START;
|
2002-11-23 07:49:01 +01:00
|
|
|
|
2003-11-12 03:32:20 +01:00
|
|
|
log_fn(LOG_DEBUG, "Extended circuit path with %s for hop %d",
|
|
|
|
rarray[choice]->nickname, cur_len);
|
|
|
|
|
|
|
|
if (router_out)
|
|
|
|
*router_out = rarray[choice];
|
|
|
|
return 0;
|
2003-04-16 18:19:27 +02:00
|
|
|
}
|
|
|
|
|
2003-05-01 21:42:51 +02:00
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
|
2003-05-26 08:03:16 +02:00
|
|
|
/* Given a router's public key, generates a 144-byte encrypted DH pubkey,
|
2003-05-01 21:42:51 +02:00
|
|
|
* and stores it into onion_skin out. Stores the DH private key into
|
|
|
|
* handshake_state_out for later completion of the handshake.
|
|
|
|
*
|
|
|
|
* The encrypted pubkey is formed as follows:
|
|
|
|
* 16 bytes of symmetric key
|
2003-05-26 08:03:16 +02:00
|
|
|
* 128 bytes of g^x for DH.
|
2003-05-01 21:42:51 +02:00
|
|
|
* The first 128 bytes are RSA-encrypted with the server's public key,
|
2003-05-26 08:03:16 +02:00
|
|
|
* and the last 16 are encrypted with the symmetric key.
|
2003-05-01 21:42:51 +02:00
|
|
|
*/
|
|
|
|
int
|
2003-05-06 01:24:46 +02:00
|
|
|
onion_skin_create(crypto_pk_env_t *dest_router_key,
|
2003-05-01 21:42:51 +02:00
|
|
|
crypto_dh_env_t **handshake_state_out,
|
2003-05-06 07:54:42 +02:00
|
|
|
char *onion_skin_out) /* Must be DH_ONIONSKIN_LEN bytes long */
|
2003-05-01 21:42:51 +02:00
|
|
|
{
|
|
|
|
char iv[16];
|
|
|
|
char *pubkey = NULL;
|
|
|
|
crypto_dh_env_t *dh = NULL;
|
|
|
|
crypto_cipher_env_t *cipher = NULL;
|
|
|
|
int dhbytes, pkbytes;
|
|
|
|
|
|
|
|
*handshake_state_out = NULL;
|
2003-05-06 07:54:42 +02:00
|
|
|
memset(onion_skin_out, 0, DH_ONIONSKIN_LEN);
|
2003-05-05 06:27:00 +02:00
|
|
|
memset(iv, 0, 16);
|
2003-05-01 21:42:51 +02:00
|
|
|
|
|
|
|
if (!(dh = crypto_dh_new()))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
dhbytes = crypto_dh_get_bytes(dh);
|
2003-05-06 01:24:46 +02:00
|
|
|
pkbytes = crypto_pk_keysize(dest_router_key);
|
2003-05-06 07:54:42 +02:00
|
|
|
assert(dhbytes+16 == DH_ONIONSKIN_LEN);
|
2003-05-20 08:41:23 +02:00
|
|
|
pubkey = (char *)tor_malloc(dhbytes+16);
|
2003-05-01 21:42:51 +02:00
|
|
|
|
|
|
|
if (crypto_rand(16, pubkey))
|
|
|
|
goto err;
|
2003-05-05 06:27:00 +02:00
|
|
|
|
|
|
|
/* XXXX You can't just run around RSA-encrypting any bitstream: if it's
|
|
|
|
* greater than the RSA key, then OpenSSL will happily encrypt,
|
|
|
|
* and later decrypt to the wrong value. So we set the first bit
|
|
|
|
* of 'pubkey' to 0. This means that our symmetric key is really only
|
|
|
|
* 127 bits long, but since it shouldn't be necessary to encrypt
|
|
|
|
* DH public keys values in the first place, we should be fine.
|
|
|
|
*/
|
|
|
|
pubkey[0] &= 0x7f;
|
2003-05-01 21:42:51 +02:00
|
|
|
|
|
|
|
if (crypto_dh_get_public(dh, pubkey+16, dhbytes))
|
|
|
|
goto err;
|
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
|
|
|
#define PA(a,n) \
|
|
|
|
{ int _i; for (_i = 0; _i<n; ++_i) printf("%02x ",((int)(a)[_i])&0xFF); }
|
|
|
|
|
|
|
|
printf("Client: client g^x:");
|
|
|
|
PA(pubkey+16,3);
|
|
|
|
printf("...");
|
|
|
|
PA(pubkey+141,3);
|
|
|
|
puts("");
|
|
|
|
|
|
|
|
printf("Client: client symkey:");
|
|
|
|
PA(pubkey+0,16);
|
|
|
|
puts("");
|
2003-05-05 06:27:00 +02:00
|
|
|
#endif
|
|
|
|
|
2003-07-30 21:12:03 +02:00
|
|
|
cipher = crypto_create_init_cipher(ONION_CIPHER, pubkey, iv, 1);
|
2003-05-05 06:27:00 +02:00
|
|
|
|
|
|
|
if (!cipher)
|
|
|
|
goto err;
|
|
|
|
|
2003-05-06 01:24:46 +02:00
|
|
|
if (crypto_pk_public_encrypt(dest_router_key, pubkey, pkbytes,
|
2003-05-05 06:27:00 +02:00
|
|
|
onion_skin_out, RSA_NO_PADDING)==-1)
|
2003-05-01 21:42:51 +02:00
|
|
|
goto err;
|
|
|
|
|
2003-05-05 06:27:00 +02:00
|
|
|
if (crypto_cipher_encrypt(cipher, pubkey+pkbytes, dhbytes+16-pkbytes,
|
2003-05-01 21:42:51 +02:00
|
|
|
onion_skin_out+pkbytes))
|
|
|
|
goto err;
|
2003-11-12 03:32:20 +01:00
|
|
|
|
2003-05-01 21:42:51 +02:00
|
|
|
free(pubkey);
|
|
|
|
crypto_free_cipher_env(cipher);
|
|
|
|
*handshake_state_out = dh;
|
2003-05-05 06:27:00 +02:00
|
|
|
|
2003-05-01 21:42:51 +02:00
|
|
|
return 0;
|
|
|
|
err:
|
2003-10-21 11:48:17 +02:00
|
|
|
tor_free(pubkey);
|
2003-05-01 21:42:51 +02:00
|
|
|
if (dh) crypto_dh_free(dh);
|
|
|
|
if (cipher) crypto_free_cipher_env(cipher);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given an encrypted DH public key as generated by onion_skin_create,
|
2003-05-26 08:03:16 +02:00
|
|
|
* and the private key for this onion router, generate the 128-byte DH
|
2003-05-01 21:42:51 +02:00
|
|
|
* reply, and key_out_len bytes of key material, stored in key_out.
|
|
|
|
*/
|
|
|
|
int
|
2003-05-06 07:54:42 +02:00
|
|
|
onion_skin_server_handshake(char *onion_skin, /* DH_ONIONSKIN_LEN bytes long */
|
2003-05-01 21:42:51 +02:00
|
|
|
crypto_pk_env_t *private_key,
|
2003-05-06 07:54:42 +02:00
|
|
|
char *handshake_reply_out, /* DH_KEY_LEN bytes long */
|
2003-05-01 21:42:51 +02:00
|
|
|
char *key_out,
|
|
|
|
int key_out_len)
|
|
|
|
{
|
2003-05-06 07:54:42 +02:00
|
|
|
char buf[DH_ONIONSKIN_LEN];
|
2003-05-01 21:42:51 +02:00
|
|
|
char iv[16];
|
|
|
|
crypto_dh_env_t *dh = NULL;
|
|
|
|
crypto_cipher_env_t *cipher = NULL;
|
|
|
|
int pkbytes;
|
2003-06-14 03:30:53 +02:00
|
|
|
int len;
|
2003-05-01 21:42:51 +02:00
|
|
|
|
|
|
|
memset(iv, 0, 16);
|
|
|
|
pkbytes = crypto_pk_keysize(private_key);
|
|
|
|
|
|
|
|
if (crypto_pk_private_decrypt(private_key,
|
|
|
|
onion_skin, pkbytes,
|
2003-05-05 06:27:00 +02:00
|
|
|
buf, RSA_NO_PADDING) == -1)
|
2003-05-01 21:42:51 +02:00
|
|
|
goto err;
|
2003-05-05 06:27:00 +02:00
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
|
|
|
printf("Server: client symkey:");
|
|
|
|
PA(buf+0,16);
|
|
|
|
puts("");
|
2003-05-05 06:27:00 +02:00
|
|
|
#endif
|
2003-05-01 21:42:51 +02:00
|
|
|
|
2003-07-30 21:12:03 +02:00
|
|
|
cipher = crypto_create_init_cipher(ONION_CIPHER, buf, iv, 0);
|
2003-05-01 21:42:51 +02:00
|
|
|
|
2003-05-06 07:54:42 +02:00
|
|
|
if (crypto_cipher_decrypt(cipher, onion_skin+pkbytes, DH_ONIONSKIN_LEN-pkbytes,
|
2003-05-01 21:42:51 +02:00
|
|
|
buf+pkbytes))
|
|
|
|
goto err;
|
2003-05-05 06:27:00 +02:00
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
|
|
|
printf("Server: client g^x:");
|
|
|
|
PA(buf+16,3);
|
|
|
|
printf("...");
|
|
|
|
PA(buf+141,3);
|
|
|
|
puts("");
|
2003-05-05 06:27:00 +02:00
|
|
|
#endif
|
2003-05-01 21:42:51 +02:00
|
|
|
|
|
|
|
dh = crypto_dh_new();
|
2003-05-06 07:54:42 +02:00
|
|
|
if (crypto_dh_get_public(dh, handshake_reply_out, DH_KEY_LEN))
|
2003-05-01 21:42:51 +02:00
|
|
|
goto err;
|
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
|
|
|
printf("Server: server g^y:");
|
|
|
|
PA(handshake_reply_out+0,3);
|
|
|
|
printf("...");
|
|
|
|
PA(handshake_reply_out+125,3);
|
|
|
|
puts("");
|
|
|
|
#endif
|
|
|
|
|
2003-07-30 21:12:03 +02:00
|
|
|
len = crypto_dh_compute_secret(dh, buf+16, DH_KEY_LEN, key_out, key_out_len);
|
2003-06-14 03:30:53 +02:00
|
|
|
if (len < 0)
|
2003-05-01 21:42:51 +02:00
|
|
|
goto err;
|
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
2003-06-14 03:34:39 +02:00
|
|
|
printf("Server: key material:");
|
|
|
|
PA(buf, DH_KEY_LEN);
|
|
|
|
puts("");
|
2003-06-13 23:23:14 +02:00
|
|
|
printf("Server: keys out:");
|
|
|
|
PA(key_out, key_out_len);
|
|
|
|
puts("");
|
|
|
|
#endif
|
|
|
|
|
2003-05-01 21:42:51 +02:00
|
|
|
crypto_free_cipher_env(cipher);
|
|
|
|
crypto_dh_free(dh);
|
|
|
|
return 0;
|
|
|
|
err:
|
|
|
|
if (cipher) crypto_free_cipher_env(cipher);
|
|
|
|
if (dh) crypto_dh_free(dh);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finish the client side of the DH handshake.
|
2003-05-26 08:03:16 +02:00
|
|
|
* Given the 128 byte DH reply as generated by onion_skin_server_handshake
|
2003-05-01 21:42:51 +02:00
|
|
|
* and the handshake state generated by onion_skin_create, generate
|
|
|
|
* key_out_len bytes of shared key material and store them in key_out.
|
|
|
|
*
|
|
|
|
* After the invocation, call crypto_dh_free on handshake_state.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
onion_skin_client_handshake(crypto_dh_env_t *handshake_state,
|
2003-05-06 07:54:42 +02:00
|
|
|
char *handshake_reply,/* Must be DH_KEY_LEN bytes long*/
|
2003-05-01 21:42:51 +02:00
|
|
|
char *key_out,
|
|
|
|
int key_out_len)
|
|
|
|
{
|
2003-06-14 03:30:53 +02:00
|
|
|
int len;
|
2003-05-06 07:54:42 +02:00
|
|
|
assert(crypto_dh_get_bytes(handshake_state) == DH_KEY_LEN);
|
2003-05-01 21:42:51 +02:00
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
|
|
|
printf("Client: server g^y:");
|
|
|
|
PA(handshake_reply+0,3);
|
|
|
|
printf("...");
|
|
|
|
PA(handshake_reply+125,3);
|
|
|
|
puts("");
|
|
|
|
#endif
|
|
|
|
|
2003-06-14 03:30:53 +02:00
|
|
|
len = crypto_dh_compute_secret(handshake_state, handshake_reply, DH_KEY_LEN,
|
2003-07-30 21:12:03 +02:00
|
|
|
key_out, key_out_len);
|
2003-06-14 03:30:53 +02:00
|
|
|
if (len < 0)
|
2003-05-01 21:42:51 +02:00
|
|
|
return -1;
|
|
|
|
|
2003-06-13 23:23:14 +02:00
|
|
|
#ifdef DEBUG_ONION_SKINS
|
|
|
|
printf("Client: keys out:");
|
|
|
|
PA(key_out, key_out_len);
|
|
|
|
puts("");
|
|
|
|
#endif
|
|
|
|
|
2003-05-01 21:42:51 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-04-07 04:12:02 +02:00
|
|
|
/*
|
|
|
|
Local Variables:
|
|
|
|
mode:c
|
|
|
|
indent-tabs-mode:nil
|
|
|
|
c-basic-offset:2
|
|
|
|
End:
|
|
|
|
*/
|
2003-11-12 03:32:20 +01:00
|
|
|
|
|
|
|
|