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
|
|
|
/* Copyright 2001,2002 Roger Dingledine, Matej Pfajfar. */
|
|
|
|
/* See LICENSE for licensing information */
|
|
|
|
/* $Id$ */
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
#define OR_PUBLICKEY_BEGIN_TAG "-----BEGIN RSA PUBLIC KEY-----\n"
|
2002-09-24 12:43:57 +02:00
|
|
|
#define OR_PUBLICKEY_END_TAG "-----END RSA PUBLIC KEY-----\n"
|
2003-05-07 20:30:46 +02:00
|
|
|
#define OR_SIGNATURE_BEGIN_TAG "-----BEGIN SIGNATURE-----\n"
|
|
|
|
#define OR_SIGNATURE_END_TAG "-----END SIGNATURE-----\n"
|
2002-06-27 00:45:49 +02:00
|
|
|
|
|
|
|
#include "or.h"
|
|
|
|
|
2002-09-26 14:09:10 +02:00
|
|
|
/****************************************************************************/
|
|
|
|
|
|
|
|
/* router array */
|
2003-05-06 19:38:16 +02:00
|
|
|
static directory_t *directory = NULL;
|
2002-09-26 14:09:10 +02:00
|
|
|
|
|
|
|
extern or_options_t options; /* command-line and config-file options */
|
2002-09-26 15:17:14 +02:00
|
|
|
extern routerinfo_t *my_routerinfo; /* from main.c */
|
2002-09-26 14:09:10 +02:00
|
|
|
|
|
|
|
/****************************************************************************/
|
2002-09-04 08:29:28 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
struct directory_token;
|
|
|
|
typedef struct directory_token directory_token_t;
|
|
|
|
|
2002-09-24 12:43:57 +02:00
|
|
|
/* static function prototypes */
|
2003-05-07 04:13:23 +02:00
|
|
|
void routerlist_free(routerinfo_t *list);
|
2002-09-24 12:43:57 +02:00
|
|
|
static char *eat_whitespace(char *s);
|
2003-05-07 20:30:46 +02:00
|
|
|
static char *eat_whitespace_no_nl(char *s);
|
2002-09-24 12:43:57 +02:00
|
|
|
static char *find_whitespace(char *s);
|
2003-04-07 06:38:19 +02:00
|
|
|
static void router_free_exit_policy(routerinfo_t *router);
|
2003-05-07 20:30:46 +02:00
|
|
|
static routerinfo_t *router_get_entry_from_string_tok(char**s,
|
|
|
|
directory_token_t *tok);
|
|
|
|
static int router_get_list_from_string_tok(char **s, directory_t **dest,
|
|
|
|
directory_token_t *tok);
|
|
|
|
static int router_add_exit_policy(routerinfo_t *router,
|
|
|
|
directory_token_t *tok);
|
2003-09-16 07:41:49 +02:00
|
|
|
static int
|
|
|
|
router_resolve_directory(directory_t *dir);
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2002-09-26 14:09:10 +02:00
|
|
|
/****************************************************************************/
|
|
|
|
|
2002-10-03 00:54:20 +02:00
|
|
|
int learn_my_address(struct sockaddr_in *me) {
|
|
|
|
/* local host information */
|
|
|
|
char localhostname[512];
|
|
|
|
struct hostent *localhost;
|
|
|
|
|
|
|
|
/* obtain local host information */
|
|
|
|
if(gethostname(localhostname,512) < 0) {
|
2003-06-14 03:28:25 +02:00
|
|
|
log_fn(LOG_ERR,"Error obtaining local hostname");
|
2002-10-03 00:54:20 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2003-06-17 23:15:25 +02:00
|
|
|
log_fn(LOG_DEBUG,"localhostname is '%s'.",localhostname);
|
2002-10-03 00:54:20 +02:00
|
|
|
localhost = gethostbyname(localhostname);
|
|
|
|
if (!localhost) {
|
2003-05-09 04:25:37 +02:00
|
|
|
log_fn(LOG_ERR,"Error obtaining local host info.");
|
2002-10-03 00:54:20 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2003-04-07 06:38:19 +02:00
|
|
|
memset(me,0,sizeof(struct sockaddr_in));
|
2002-10-03 00:54:20 +02:00
|
|
|
me->sin_family = AF_INET;
|
|
|
|
memcpy((void *)&me->sin_addr,(void *)localhost->h_addr,sizeof(struct in_addr));
|
2003-08-12 10:18:13 +02:00
|
|
|
me->sin_port = htons((uint16_t) options.ORPort);
|
2003-06-17 23:15:25 +02:00
|
|
|
log_fn(LOG_DEBUG,"chose address as '%s'.",inet_ntoa(me->sin_addr));
|
2003-07-30 21:12:03 +02:00
|
|
|
if (!strncmp("127.",inet_ntoa(me->sin_addr), 4) &&
|
|
|
|
strcasecmp(localhostname, "localhost")) {
|
|
|
|
/* We're a loopback IP but we're not called localhost. Uh oh! */
|
|
|
|
log_fn(LOG_WARNING, "Got a loopback address: /etc/hosts may be wrong");
|
|
|
|
}
|
2002-10-03 00:54:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void router_retry_connections(void) {
|
2002-09-26 14:09:10 +02:00
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
for (i=0;i<directory->n_routers;i++) {
|
|
|
|
router = directory->routers[i];
|
2002-09-26 14:09:10 +02:00
|
|
|
if(!connection_exact_get_by_addr_port(router->addr,router->or_port)) { /* not in the list */
|
2003-06-17 23:15:25 +02:00
|
|
|
log_fn(LOG_DEBUG,"connecting to OR %s:%u.",router->address,router->or_port);
|
2003-05-28 04:03:25 +02:00
|
|
|
connection_or_connect(router);
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
routerinfo_t *router_pick_directory_server(void) {
|
|
|
|
/* currently, pick the first router with a positive dir_port */
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
if(!directory)
|
2002-09-26 14:09:10 +02:00
|
|
|
return NULL;
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
for(i=0;i<directory->n_routers;i++) {
|
|
|
|
router = directory->routers[i];
|
2002-09-26 14:09:10 +02:00
|
|
|
if(router->dir_port > 0)
|
|
|
|
return router;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
assert(directory);
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
for(i=0;i<directory->n_routers;i++) {
|
|
|
|
router = directory->routers[i];
|
2002-09-26 14:09:10 +02:00
|
|
|
if ((router->addr == addr) && (router->or_port == port))
|
|
|
|
return router;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2003-09-11 22:32:15 +02:00
|
|
|
routerinfo_t *router_get_by_pk(crypto_pk_env_t *pk)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
|
|
|
assert(directory);
|
|
|
|
|
|
|
|
for(i=0;i<directory->n_routers;i++) {
|
|
|
|
router = directory->routers[i];
|
|
|
|
/* XXX Should this really be a separate link key? */
|
|
|
|
if (0 == crypto_pk_cmp_keys(router->pkey, pk))
|
|
|
|
return router;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
void router_get_directory(directory_t **pdirectory) {
|
|
|
|
*pdirectory = directory;
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
|
|
|
|
2002-10-03 00:54:20 +02:00
|
|
|
/* return 1 if addr and port corresponds to my addr and my or_listenport. else 0,
|
|
|
|
* or -1 for failure.
|
|
|
|
*/
|
|
|
|
int router_is_me(uint32_t addr, uint16_t port)
|
2002-07-10 14:35:59 +02:00
|
|
|
{
|
2003-05-09 03:24:44 +02:00
|
|
|
/* XXXX Should this check the key too? */
|
2002-10-03 00:54:20 +02:00
|
|
|
struct sockaddr_in me; /* my router identity */
|
|
|
|
|
2003-05-28 04:03:25 +02:00
|
|
|
if(!options.OnionRouter) {
|
2002-10-03 00:54:20 +02:00
|
|
|
/* we're not an OR. This obviously isn't us. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(learn_my_address(&me) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if(ntohl(me.sin_addr.s_addr) == addr && ntohs(me.sin_port) == port)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2002-07-10 14:35:59 +02:00
|
|
|
}
|
|
|
|
|
2002-06-27 00:45:49 +02:00
|
|
|
/* delete a list of routers from memory */
|
2003-05-09 04:00:33 +02:00
|
|
|
void routerinfo_free(routerinfo_t *router)
|
2002-06-27 00:45:49 +02:00
|
|
|
{
|
2003-05-06 19:38:16 +02:00
|
|
|
struct exit_policy_t *e = NULL, *etmp = NULL;
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2003-05-09 04:00:33 +02:00
|
|
|
if (!router)
|
2002-06-27 00:45:49 +02:00
|
|
|
return;
|
|
|
|
|
2003-05-09 04:00:33 +02:00
|
|
|
if (router->address)
|
|
|
|
free(router->address);
|
|
|
|
if (router->pkey)
|
|
|
|
crypto_free_pk_env(router->pkey);
|
2003-08-28 06:21:57 +02:00
|
|
|
if (router->signing_pkey)
|
|
|
|
crypto_free_pk_env(router->signing_pkey);
|
2003-05-09 04:00:33 +02:00
|
|
|
e = router->exit_policy;
|
|
|
|
while (e) {
|
|
|
|
etmp = e->next;
|
|
|
|
if (e->string) free(e->string);
|
|
|
|
if (e->address) free(e->address);
|
|
|
|
if (e->port) free(e->port);
|
|
|
|
free(e);
|
|
|
|
e = etmp;
|
|
|
|
}
|
|
|
|
free(router);
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
void directory_free(directory_t *directory)
|
|
|
|
{
|
2003-05-09 04:00:33 +02:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < directory->n_routers; ++i)
|
|
|
|
routerinfo_free(directory->routers[i]);
|
|
|
|
free(directory->routers);
|
2003-09-13 23:53:38 +02:00
|
|
|
if(directory->software_versions)
|
|
|
|
free(directory->software_versions);
|
2003-05-06 19:38:16 +02:00
|
|
|
free(directory);
|
|
|
|
}
|
|
|
|
|
2002-09-26 15:17:14 +02:00
|
|
|
void router_forget_router(uint32_t addr, uint16_t port) {
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
|
|
|
router = router_get_by_addr_port(addr,port);
|
|
|
|
if(!router) /* we don't seem to know about him in the first place */
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* now walk down router_array until we get to router */
|
2003-05-06 19:38:16 +02:00
|
|
|
for(i=0;i<directory->n_routers;i++)
|
|
|
|
if(directory->routers[i] == router)
|
2002-09-26 15:17:14 +02:00
|
|
|
break;
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
assert(i != directory->n_routers); /* if so then router_get_by_addr_port should have returned null */
|
2002-09-26 15:17:14 +02:00
|
|
|
|
2002-09-26 15:19:13 +02:00
|
|
|
// free(router); /* don't actually free; we'll free it when we free the whole thing */
|
|
|
|
|
2002-09-26 15:17:14 +02:00
|
|
|
// log(LOG_DEBUG,"router_forget_router(): Forgot about router %d:%d",addr,port);
|
2003-05-06 19:38:16 +02:00
|
|
|
for(; i<directory->n_routers-1;i++)
|
|
|
|
directory->routers[i] = directory->routers[i+1];
|
2003-08-29 23:50:53 +02:00
|
|
|
/* XXX bug, we're not decrementing n_routers here? needs more attention. -RD */
|
2002-09-26 15:17:14 +02:00
|
|
|
}
|
|
|
|
|
2002-06-27 00:45:49 +02:00
|
|
|
/* load the router list */
|
2002-10-03 00:54:20 +02:00
|
|
|
int router_get_list_from_file(char *routerfile)
|
2002-06-27 00:45:49 +02:00
|
|
|
{
|
2002-09-24 12:43:57 +02:00
|
|
|
int fd; /* router file */
|
|
|
|
struct stat statbuf;
|
|
|
|
char *string;
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2002-09-26 14:09:10 +02:00
|
|
|
assert(routerfile);
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2002-07-22 06:08:37 +02:00
|
|
|
if (strcspn(routerfile,CONFIG_LEGAL_FILENAME_CHARACTERS) != 0) {
|
2003-06-17 23:15:25 +02:00
|
|
|
log_fn(LOG_ERR,"Filename %s contains illegal characters.",routerfile);
|
2002-09-26 14:09:10 +02:00
|
|
|
return -1;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
|
|
|
|
2002-09-24 12:43:57 +02:00
|
|
|
if(stat(routerfile, &statbuf) < 0) {
|
2003-06-17 23:15:25 +02:00
|
|
|
log_fn(LOG_ERR,"Could not stat %s.",routerfile);
|
2002-09-26 14:09:10 +02:00
|
|
|
return -1;
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
|
|
|
|
2002-06-27 00:45:49 +02:00
|
|
|
/* open the router list */
|
2002-09-24 12:43:57 +02:00
|
|
|
fd = open(routerfile,O_RDONLY,0);
|
|
|
|
if (fd<0) {
|
2003-06-17 23:15:25 +02:00
|
|
|
log_fn(LOG_ERR,"Could not open %s.",routerfile);
|
2002-09-26 14:09:10 +02:00
|
|
|
return -1;
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
|
|
|
|
2003-05-20 08:41:23 +02:00
|
|
|
string = tor_malloc(statbuf.st_size+1);
|
2002-09-24 12:43:57 +02:00
|
|
|
|
|
|
|
if(read(fd,string,statbuf.st_size) != statbuf.st_size) {
|
2003-06-18 00:18:26 +02:00
|
|
|
log_fn(LOG_ERR,"Couldn't read all %ld bytes of file '%s'.",
|
|
|
|
(long)statbuf.st_size,routerfile);
|
2002-09-26 14:09:10 +02:00
|
|
|
free(string);
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
2002-09-24 12:43:57 +02:00
|
|
|
close(fd);
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2002-09-24 12:43:57 +02:00
|
|
|
string[statbuf.st_size] = 0; /* null terminate it */
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2002-10-03 00:54:20 +02:00
|
|
|
if(router_get_list_from_string(string) < 0) {
|
2003-06-14 03:28:25 +02:00
|
|
|
log_fn(LOG_ERR,"The routerfile itself was corrupt.");
|
2002-09-26 14:09:10 +02:00
|
|
|
free(string);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(string);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
K_ACCEPT,
|
|
|
|
K_DIRECTORY_SIGNATURE,
|
2003-05-09 04:25:37 +02:00
|
|
|
K_RECOMMENDED_SOFTWARE,
|
2003-05-07 20:30:46 +02:00
|
|
|
K_REJECT,
|
|
|
|
K_ROUTER,
|
|
|
|
K_SIGNED_DIRECTORY,
|
|
|
|
K_SIGNING_KEY,
|
|
|
|
_SIGNATURE,
|
|
|
|
_PUBLIC_KEY,
|
|
|
|
_ERR,
|
|
|
|
_EOF
|
|
|
|
} directory_keyword;
|
|
|
|
|
|
|
|
struct token_table_ent { char *t; int v; };
|
|
|
|
|
|
|
|
static struct token_table_ent token_table[] = {
|
|
|
|
{ "accept", K_ACCEPT },
|
|
|
|
{ "directory-signature", K_DIRECTORY_SIGNATURE },
|
|
|
|
{ "reject", K_REJECT },
|
|
|
|
{ "router", K_ROUTER },
|
2003-05-09 04:25:37 +02:00
|
|
|
{ "recommended-software", K_RECOMMENDED_SOFTWARE },
|
2003-05-07 20:30:46 +02:00
|
|
|
{ "signed-directory", K_SIGNED_DIRECTORY },
|
|
|
|
{ "signing-key", K_SIGNING_KEY },
|
|
|
|
{ NULL, -1 }
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MAX_ARGS 8
|
|
|
|
struct directory_token {
|
|
|
|
directory_keyword tp;
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
char *args[MAX_ARGS+1];
|
|
|
|
int n_args;
|
|
|
|
} cmd;
|
|
|
|
char *signature;
|
|
|
|
char *error;
|
|
|
|
crypto_pk_env_t *public_key;
|
|
|
|
} val;
|
|
|
|
};
|
|
|
|
|
2003-08-28 06:21:57 +02:00
|
|
|
/* Free any malloced resources allocated for a token. Don't call this if
|
|
|
|
you inherit the reference to those resources.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
router_release_token(directory_token_t *tok)
|
|
|
|
{
|
|
|
|
switch (tok->tp)
|
|
|
|
{
|
|
|
|
case _SIGNATURE:
|
|
|
|
free(tok->val.signature);
|
|
|
|
break;
|
|
|
|
case _PUBLIC_KEY:
|
|
|
|
crypto_free_pk_env(tok->val.public_key);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
static int
|
|
|
|
_router_get_next_token(char **s, directory_token_t *tok) {
|
|
|
|
char *next;
|
|
|
|
crypto_pk_env_t *pkey = NULL;
|
|
|
|
char *signature = NULL;
|
|
|
|
int i, done;
|
|
|
|
|
|
|
|
tok->tp = _ERR;
|
|
|
|
tok->val.error = "";
|
|
|
|
|
|
|
|
*s = eat_whitespace(*s);
|
|
|
|
if (!**s) {
|
|
|
|
tok->tp = _EOF;
|
|
|
|
return 0;
|
|
|
|
} else if (**s == '-') {
|
|
|
|
next = strchr(*s, '\n');
|
|
|
|
if (! next) { tok->val.error = "No newline at EOF"; return -1; }
|
|
|
|
++next;
|
|
|
|
if (! strncmp(*s, OR_PUBLICKEY_BEGIN_TAG, next-*s)) {
|
|
|
|
next = strstr(*s, OR_PUBLICKEY_END_TAG);
|
|
|
|
if (!next) { tok->val.error = "No public key end tag found"; return -1; }
|
|
|
|
next = strchr(next, '\n'); /* Part of OR_PUBLICKEY_END_TAG; can't fail.*/
|
|
|
|
++next;
|
|
|
|
if (!(pkey = crypto_new_pk_env(CRYPTO_PK_RSA)))
|
|
|
|
return -1;
|
|
|
|
if (crypto_pk_read_public_key_from_string(pkey, *s, next-*s)) {
|
|
|
|
crypto_free_pk_env(pkey);
|
|
|
|
tok->val.error = "Couldn't parse public key.";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
tok->tp = _PUBLIC_KEY;
|
|
|
|
tok->val.public_key = pkey;
|
|
|
|
*s = next;
|
|
|
|
return 0;
|
|
|
|
} else if (! strncmp(*s, OR_SIGNATURE_BEGIN_TAG, next-*s)) {
|
|
|
|
/* Advance past newline; can't fail. */
|
|
|
|
*s = strchr(*s, '\n');
|
|
|
|
++*s;
|
|
|
|
/* Find end of base64'd data */
|
|
|
|
next = strstr(*s, OR_SIGNATURE_END_TAG);
|
|
|
|
if (!next) { tok->val.error = "No signature end tag found"; return -1; }
|
|
|
|
|
2003-05-20 08:41:23 +02:00
|
|
|
signature = tor_malloc(256);
|
2003-05-07 20:30:46 +02:00
|
|
|
i = base64_decode(signature, 256, *s, next-*s);
|
|
|
|
if (i<0) {
|
|
|
|
free(signature);
|
|
|
|
tok->val.error = "Error decoding signature."; return -1;
|
|
|
|
} else if (i != 128) {
|
|
|
|
free(signature);
|
|
|
|
tok->val.error = "Bad length on decoded signature."; return -1;
|
|
|
|
}
|
|
|
|
tok->tp = _SIGNATURE;
|
|
|
|
tok->val.signature = signature;
|
|
|
|
|
|
|
|
next = strchr(next, '\n'); /* Part of OR_SIGNATURE_END_TAG; can't fail.*/
|
|
|
|
*s = next+1;
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
tok->val.error = "Unrecognized begin line"; return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
next = find_whitespace(*s);
|
|
|
|
if (!next) {
|
|
|
|
tok->val.error = "Unexpected EOF"; return -1;
|
|
|
|
}
|
|
|
|
for (i = 0 ; token_table[i].t ; ++i) {
|
|
|
|
if (!strncmp(token_table[i].t, *s, next-*s)) {
|
|
|
|
tok->tp = token_table[i].v;
|
|
|
|
i = 0;
|
|
|
|
done = (*next == '\n');
|
|
|
|
*s = eat_whitespace_no_nl(next);
|
|
|
|
while (**s != '\n' && i <= MAX_ARGS && !done) {
|
|
|
|
next = find_whitespace(*s);
|
|
|
|
if (*next == '\n')
|
|
|
|
done = 1;
|
|
|
|
*next = 0;
|
|
|
|
tok->val.cmd.args[i++] = *s;
|
|
|
|
*s = eat_whitespace_no_nl(next+1);
|
|
|
|
};
|
|
|
|
tok->val.cmd.n_args = i;
|
|
|
|
if (i > MAX_ARGS) {
|
|
|
|
tok->tp = _ERR;
|
|
|
|
tok->val.error = "Too many arguments"; return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tok->val.error = "Unrecognized command"; return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-09 04:20:16 +02:00
|
|
|
#ifdef DEBUG_ROUTER_TOKENS
|
2003-05-07 20:30:46 +02:00
|
|
|
static void
|
|
|
|
router_dump_token(directory_token_t *tok) {
|
|
|
|
int i;
|
|
|
|
switch(tok->tp)
|
|
|
|
{
|
|
|
|
case _SIGNATURE:
|
|
|
|
puts("(signature)");
|
|
|
|
return;
|
|
|
|
case _PUBLIC_KEY:
|
|
|
|
puts("(public key)");
|
|
|
|
return;
|
|
|
|
case _ERR:
|
|
|
|
printf("(Error: %s\n)", tok->val.error);
|
|
|
|
return;
|
|
|
|
case _EOF:
|
|
|
|
puts("EOF");
|
|
|
|
return;
|
|
|
|
case K_ACCEPT: printf("Accept"); break;
|
|
|
|
case K_DIRECTORY_SIGNATURE: printf("Directory-Signature"); break;
|
|
|
|
case K_REJECT: printf("Reject"); break;
|
2003-05-09 04:25:37 +02:00
|
|
|
case K_RECOMMENDED_SOFTWARE: printf("Server-Software"); break;
|
2003-05-07 20:30:46 +02:00
|
|
|
case K_ROUTER: printf("Router"); break;
|
|
|
|
case K_SIGNED_DIRECTORY: printf("Signed-Directory"); break;
|
|
|
|
case K_SIGNING_KEY: printf("Signing-Key"); break;
|
|
|
|
default:
|
|
|
|
printf("?????? %d\n", tok->tp); return;
|
|
|
|
}
|
|
|
|
for (i = 0; i < tok->val.cmd.n_args; ++i) {
|
|
|
|
printf(" \"%s\"", tok->val.cmd.args[i]);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
router_get_next_token(char **s, directory_token_t *tok) {
|
|
|
|
int i;
|
|
|
|
i = _router_get_next_token(s, tok);
|
|
|
|
router_dump_token(tok);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define router_get_next_token _router_get_next_token
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* return the first char of s that is not whitespace and not a comment */
|
|
|
|
static char *eat_whitespace(char *s) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
while(isspace(*s) || *s == '#') {
|
|
|
|
while(isspace(*s))
|
|
|
|
s++;
|
|
|
|
if(*s == '#') { /* read to a \n or \0 */
|
|
|
|
while(*s && *s != '\n')
|
|
|
|
s++;
|
|
|
|
if(!*s)
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *eat_whitespace_no_nl(char *s) {
|
|
|
|
while(*s == ' ' || *s == '\t')
|
|
|
|
++s;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return the first char of s that is whitespace or '#' or '\0 */
|
|
|
|
static char *find_whitespace(char *s) {
|
|
|
|
assert(s);
|
|
|
|
|
|
|
|
while(*s && !isspace(*s) && *s != '#')
|
|
|
|
s++;
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2003-05-06 19:38:16 +02:00
|
|
|
int router_get_list_from_string(char *s)
|
|
|
|
{
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (router_get_list_from_string_impl(s, &directory)) {
|
|
|
|
log(LOG_ERR, "Error parsing router file");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (router_resolve_directory(directory)) {
|
|
|
|
log(LOG_ERR, "Error resolving directory");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
2003-05-06 19:38:16 +02:00
|
|
|
}
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
int router_get_list_from_string_impl(char *s, directory_t **dest) {
|
|
|
|
directory_token_t tok;
|
|
|
|
if (router_get_next_token(&s, &tok)) {
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
log(LOG_ERR, "Error reading routers: %s", tok.val.error);
|
2003-05-07 20:39:44 +02:00
|
|
|
return -1;
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
|
|
|
return router_get_list_from_string_tok(&s, dest, &tok);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int router_get_dir_hash(char *s, char *digest)
|
|
|
|
{
|
|
|
|
char *start, *end;
|
|
|
|
start = strstr(s, "signed-directory");
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (!start) {
|
|
|
|
log(LOG_ERR,"router_get_dir_hash(): couldn't find \"signed-directory\"");
|
|
|
|
return -1;
|
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
end = strstr(start, "directory-signature");
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (!end) {
|
|
|
|
log(LOG_ERR,"router_get_dir_hash(): couldn't find \"directory-signature\"");
|
|
|
|
return -1;
|
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
end = strchr(end, '\n');
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (!end) {
|
|
|
|
log(LOG_ERR,"router_get_dir_hash(): couldn't find EOL");
|
|
|
|
return -1;
|
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
++end;
|
|
|
|
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (crypto_SHA_digest(start, end-start, digest)) {
|
|
|
|
log(LOG_ERR,"router_get_dir_hash(): couldn't compute digest");
|
2003-05-07 20:30:46 +02:00
|
|
|
return -1;
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-08-23 12:09:25 +02:00
|
|
|
/* return 0 if myversion is in start. Else return -1. */
|
|
|
|
int compare_recommended_versions(char *myversion, char *start) {
|
|
|
|
int len_myversion = strlen(myversion);
|
|
|
|
char *comma;
|
|
|
|
char *end = start + strlen(start);
|
|
|
|
|
|
|
|
log_fn(LOG_DEBUG,"checking '%s' in '%s'.", myversion, start);
|
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
comma = strchr(start, ',');
|
|
|
|
if( ((comma ? comma : end) - start == len_myversion) &&
|
|
|
|
!strncmp(start, myversion, len_myversion)) /* only do strncmp if the length matches */
|
|
|
|
return 0; /* success, it's there */
|
|
|
|
if(!comma)
|
|
|
|
return -1; /* nope */
|
|
|
|
start = comma+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
int router_get_dir_from_string(char *s, crypto_pk_env_t *pkey)
|
|
|
|
{
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (router_get_dir_from_string_impl(s, &directory, pkey)) {
|
2003-05-09 04:20:16 +02:00
|
|
|
log(LOG_ERR, "router_get_dir_from_string: Couldn't parse directory.");
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (router_resolve_directory(directory)) {
|
|
|
|
log(LOG_ERR, "Error resolving directory");
|
|
|
|
return -1;
|
|
|
|
}
|
2003-08-23 12:09:25 +02:00
|
|
|
if (compare_recommended_versions(VERSION, directory->software_versions) < 0) {
|
|
|
|
log(LOG_ERR, "You are running tor version %s, which is no longer supported.\nPlease upgrade to one of %s.", VERSION, RECOMMENDED_SOFTWARE_VERSIONS);
|
|
|
|
if(options.IgnoreVersion) {
|
|
|
|
log(LOG_WARNING, "IgnoreVersion is set. If it breaks, we told you so.");
|
|
|
|
} else {
|
|
|
|
log(LOG_ERR,"Set IgnoreVersion config variable if you want to survive this error.");
|
|
|
|
fflush(0);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
return 0;
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int router_get_dir_from_string_impl(char *s, directory_t **dest,
|
|
|
|
crypto_pk_env_t *pkey)
|
|
|
|
{
|
|
|
|
directory_token_t tok;
|
|
|
|
char digest[20];
|
|
|
|
char signed_digest[128];
|
2003-05-07 20:39:44 +02:00
|
|
|
directory_t *new_dir = NULL;
|
2003-05-09 04:25:37 +02:00
|
|
|
char *versions;
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
#define NEXT_TOK() \
|
|
|
|
do { \
|
|
|
|
if (router_get_next_token(&s, &tok)) { \
|
|
|
|
log(LOG_ERR, "Error reading directory: %s", tok.val.error); \
|
|
|
|
return -1; \
|
|
|
|
} } while (0)
|
|
|
|
#define TOK_IS(type,name) \
|
|
|
|
do { \
|
|
|
|
if (tok.tp != type) { \
|
2003-08-28 06:21:57 +02:00
|
|
|
router_release_token(&tok); \
|
2003-05-07 20:30:46 +02:00
|
|
|
log(LOG_ERR, "Error reading directory: expected %s", name); \
|
|
|
|
return -1; \
|
|
|
|
} } while(0)
|
|
|
|
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (router_get_dir_hash(s, digest)) {
|
|
|
|
log(LOG_ERR, "Unable to compute digest of directory");
|
2003-05-07 20:30:46 +02:00
|
|
|
return -1;
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
NEXT_TOK();
|
|
|
|
TOK_IS(K_SIGNED_DIRECTORY, "signed-directory");
|
|
|
|
|
|
|
|
NEXT_TOK();
|
2003-05-09 04:25:37 +02:00
|
|
|
TOK_IS(K_RECOMMENDED_SOFTWARE, "recommended-software");
|
|
|
|
if (tok.val.cmd.n_args != 1) {
|
|
|
|
log(LOG_ERR, "Invalid recommded-software line");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
versions = strdup(tok.val.cmd.args[0]);
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
NEXT_TOK();
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (router_get_list_from_string_tok(&s, &new_dir, &tok)) {
|
|
|
|
log(LOG_ERR, "Error reading routers from directory");
|
2003-05-07 20:30:46 +02:00
|
|
|
return -1;
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
}
|
2003-05-09 04:25:37 +02:00
|
|
|
new_dir->software_versions = versions;
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
TOK_IS(K_DIRECTORY_SIGNATURE, "directory-signature");
|
|
|
|
NEXT_TOK();
|
|
|
|
TOK_IS(_SIGNATURE, "signature");
|
|
|
|
if (pkey) {
|
|
|
|
if (crypto_pk_public_checksig(pkey, tok.val.signature, 128, signed_digest)
|
|
|
|
!= 20) {
|
|
|
|
log(LOG_ERR, "Error reading directory: invalid signature.");
|
|
|
|
free(tok.val.signature);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (memcmp(digest, signed_digest, 20)) {
|
|
|
|
log(LOG_ERR, "Error reading directory: signature does not match.");
|
|
|
|
free(tok.val.signature);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(tok.val.signature);
|
|
|
|
|
|
|
|
NEXT_TOK();
|
|
|
|
TOK_IS(_EOF, "end of directory");
|
|
|
|
|
2003-05-07 20:39:44 +02:00
|
|
|
if (*dest)
|
|
|
|
directory_free(*dest);
|
|
|
|
*dest = new_dir;
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
return 0;
|
|
|
|
#undef NEXT_TOK
|
|
|
|
#undef TOK_IS
|
|
|
|
}
|
|
|
|
|
|
|
|
static int router_get_list_from_string_tok(char **s, directory_t **dest,
|
|
|
|
directory_token_t *tok)
|
2003-05-06 19:38:16 +02:00
|
|
|
{
|
2002-09-26 14:09:10 +02:00
|
|
|
routerinfo_t *router;
|
2003-05-09 04:00:33 +02:00
|
|
|
routerinfo_t **rarray;
|
|
|
|
int rarray_len = 0;
|
2002-09-26 14:09:10 +02:00
|
|
|
|
|
|
|
assert(s);
|
|
|
|
|
2003-05-20 08:41:23 +02:00
|
|
|
rarray = (routerinfo_t **)tor_malloc((sizeof(routerinfo_t *))*MAX_ROUTERS_IN_DIR);
|
2003-05-09 04:00:33 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
while (tok->tp == K_ROUTER) {
|
|
|
|
router = router_get_entry_from_string_tok(s, tok);
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
if (!router) {
|
|
|
|
log(LOG_ERR, "Error reading router");
|
|
|
|
return -1;
|
|
|
|
}
|
2003-05-09 04:00:33 +02:00
|
|
|
if (rarray_len >= MAX_ROUTERS_IN_DIR) {
|
|
|
|
log(LOG_ERR, "router_get_list_from_string_tok(): too many routers");
|
|
|
|
routerinfo_free(router);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
rarray[rarray_len++] = router;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2003-05-09 04:00:33 +02:00
|
|
|
if (*dest)
|
|
|
|
directory_free(*dest);
|
2003-05-20 08:41:23 +02:00
|
|
|
*dest = (directory_t *)tor_malloc(sizeof(directory_t));
|
2003-05-09 04:00:33 +02:00
|
|
|
(*dest)->routers = rarray;
|
|
|
|
(*dest)->n_routers = rarray_len;
|
2003-09-13 23:53:38 +02:00
|
|
|
(*dest)->software_versions = NULL;
|
2003-05-09 04:00:33 +02:00
|
|
|
return 0;
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
2003-05-07 20:39:44 +02:00
|
|
|
|
2003-09-16 07:41:49 +02:00
|
|
|
static int
|
2003-05-06 19:38:16 +02:00
|
|
|
router_resolve(routerinfo_t *router)
|
|
|
|
{
|
|
|
|
struct hostent *rent;
|
|
|
|
|
|
|
|
rent = (struct hostent *)gethostbyname(router->address);
|
|
|
|
if (!rent) {
|
|
|
|
log(LOG_ERR,"router_resolve(): Could not get address for router %s.",router->address);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
assert(rent->h_length == 4);
|
|
|
|
memcpy(&router->addr, rent->h_addr,rent->h_length);
|
|
|
|
router->addr = ntohl(router->addr); /* get it back into host order */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-09-16 07:41:49 +02:00
|
|
|
static int
|
2003-05-08 14:32:30 +02:00
|
|
|
router_resolve_directory(directory_t *dir)
|
|
|
|
{
|
2003-05-09 03:24:44 +02:00
|
|
|
int i, max, remove;
|
2003-05-08 14:32:30 +02:00
|
|
|
if (!dir)
|
|
|
|
dir = directory;
|
|
|
|
|
|
|
|
max = dir->n_routers;
|
|
|
|
for (i = 0; i < max; ++i) {
|
2003-05-09 03:24:44 +02:00
|
|
|
remove = 0;
|
2003-05-08 14:32:30 +02:00
|
|
|
if (router_resolve(dir->routers[i])) {
|
2003-05-09 04:20:16 +02:00
|
|
|
log(LOG_INFO, "Couldn't resolve router %s; removing",
|
Get directories working.
Or at least, directories get generated, signed, download, and checked, with
nobody seeming to crash.
In config/*, added 'signing-key' blocks to dirservers and routers.or, so
that everyone will know about the directories' signing keys.
In or/directory.c, refrained from using a dirserver's signing key when
no such key is known; added more debugging output.
In or/main.c, added debugging output and fixed a few logic errors.
In or/routers.c, added debugging output and prevented a segfault on
routers_resolve_directory. The interleaving of arrays and lists on
routerinfo_t is still messy, but at least it seems to work again.
svn:r278
2003-05-08 23:35:11 +02:00
|
|
|
dir->routers[i]->address);
|
2003-05-09 03:24:44 +02:00
|
|
|
remove = 1;
|
2003-05-09 04:00:33 +02:00
|
|
|
routerinfo_free(dir->routers[i]);
|
2003-05-09 03:24:44 +02:00
|
|
|
} else if (router_is_me(dir->routers[i]->addr, dir->routers[i]->or_port)) {
|
|
|
|
my_routerinfo = dir->routers[i];
|
|
|
|
remove = 1;
|
|
|
|
}
|
|
|
|
if (remove) {
|
2003-05-08 14:32:30 +02:00
|
|
|
dir->routers[i] = dir->routers[--max];
|
|
|
|
--dir->n_routers;
|
2003-05-09 03:24:44 +02:00
|
|
|
--i;
|
2003-05-08 14:32:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
routerinfo_t *router_get_entry_from_string(char **s) {
|
|
|
|
directory_token_t tok;
|
|
|
|
routerinfo_t *router;
|
|
|
|
if (router_get_next_token(s, &tok)) return NULL;
|
|
|
|
router = router_get_entry_from_string_tok(s, &tok);
|
2003-08-28 06:21:57 +02:00
|
|
|
if (tok.tp != _EOF) {
|
|
|
|
router_release_token(&tok);
|
2003-05-07 20:30:46 +02:00
|
|
|
return NULL;
|
2003-08-28 06:21:57 +02:00
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
return router;
|
|
|
|
}
|
|
|
|
|
2002-09-24 12:43:57 +02:00
|
|
|
/* reads a single router entry from s.
|
|
|
|
* updates s so it points to after the router it just read.
|
|
|
|
* mallocs a new router, returns it if all goes well, else returns NULL.
|
|
|
|
*/
|
2003-05-07 20:30:46 +02:00
|
|
|
static routerinfo_t *router_get_entry_from_string_tok(char**s, directory_token_t *tok) {
|
|
|
|
routerinfo_t *router = NULL;
|
2003-05-06 19:38:16 +02:00
|
|
|
|
2003-05-09 04:00:33 +02:00
|
|
|
#define NEXT_TOKEN() \
|
|
|
|
do { if (router_get_next_token(s, tok)) { \
|
|
|
|
log(LOG_ERR, "Error reading directory: %s", tok->val.error); \
|
|
|
|
goto err; \
|
|
|
|
} } while(0)
|
2003-05-07 20:30:46 +02:00
|
|
|
|
|
|
|
#define ARGS tok->val.cmd.args
|
|
|
|
|
|
|
|
if (tok->tp != K_ROUTER) {
|
2003-08-28 06:21:57 +02:00
|
|
|
router_release_token(tok);
|
2003-05-06 19:38:16 +02:00
|
|
|
log(LOG_ERR,"router_get_entry_from_string(): Entry does not start with \"router\"");
|
|
|
|
return NULL;
|
|
|
|
}
|
2003-05-20 08:41:23 +02:00
|
|
|
|
|
|
|
router = tor_malloc(sizeof(routerinfo_t));
|
2002-09-24 12:43:57 +02:00
|
|
|
memset(router,0,sizeof(routerinfo_t)); /* zero it out first */
|
2003-05-09 04:00:33 +02:00
|
|
|
/* C doesn't guarantee that NULL is represented by 0 bytes. You'll
|
|
|
|
thank me for this someday. */
|
|
|
|
router->pkey = router->signing_pkey = NULL;
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-08-28 00:42:10 +02:00
|
|
|
if (tok->val.cmd.n_args != 5) {
|
2003-05-07 20:30:46 +02:00
|
|
|
log(LOG_ERR,"router_get_entry_from_string(): Wrong # of arguments to \"router\"");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* read router.address */
|
|
|
|
if (!(router->address = strdup(ARGS[0])))
|
|
|
|
goto err;
|
2003-05-06 19:38:16 +02:00
|
|
|
router->addr = 0;
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
/* Read router->or_port */
|
|
|
|
router->or_port = atoi(ARGS[1]);
|
2002-09-24 12:43:57 +02:00
|
|
|
if(!router->or_port) {
|
2003-05-07 20:30:46 +02:00
|
|
|
log(LOG_ERR,"router_get_entry_from_string(): or_port unreadable or 0. Failing.");
|
|
|
|
goto err;
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
/* Router->ap_port */
|
2003-08-28 00:42:10 +02:00
|
|
|
router->ap_port = atoi(ARGS[2]);
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
/* Router->dir_port */
|
2003-08-28 00:42:10 +02:00
|
|
|
router->dir_port = atoi(ARGS[3]);
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
/* Router->bandwidth */
|
2003-08-28 00:42:10 +02:00
|
|
|
router->bandwidth = atoi(ARGS[4]);
|
2003-05-07 20:30:46 +02:00
|
|
|
if (!router->bandwidth) {
|
|
|
|
log(LOG_ERR,"router_get_entry_from_string(): bandwidth unreadable or 0. Failing.");
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2003-08-28 00:42:10 +02:00
|
|
|
log(LOG_DEBUG,"or_port %d, ap_port %d, dir_port %d, bandwidth %d.",
|
|
|
|
router->or_port, router->ap_port, router->dir_port, router->bandwidth);
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
NEXT_TOKEN();
|
2003-08-28 06:21:57 +02:00
|
|
|
if (tok->tp != _PUBLIC_KEY) {
|
2003-05-07 20:30:46 +02:00
|
|
|
log(LOG_ERR,"router_get_entry_from_string(): Missing public key");
|
|
|
|
goto err;
|
|
|
|
} /* Check key length */
|
|
|
|
router->pkey = tok->val.public_key;
|
|
|
|
|
|
|
|
NEXT_TOKEN();
|
|
|
|
if (tok->tp == K_SIGNING_KEY) {
|
|
|
|
NEXT_TOKEN();
|
|
|
|
if (tok->tp != _PUBLIC_KEY) {
|
|
|
|
log(LOG_ERR,"router_get_entry_from_string(): Missing signing key");
|
|
|
|
goto err;
|
2003-05-07 04:13:23 +02:00
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
router->signing_pkey = tok->val.public_key;
|
|
|
|
NEXT_TOKEN();
|
|
|
|
}
|
2003-05-07 04:13:23 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
while (tok->tp == K_ACCEPT || tok->tp == K_REJECT) {
|
|
|
|
router_add_exit_policy(router, tok);
|
|
|
|
NEXT_TOKEN();
|
2003-04-07 06:38:19 +02:00
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2003-04-07 06:38:19 +02:00
|
|
|
return router;
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
err:
|
2003-08-28 06:21:57 +02:00
|
|
|
router_release_token(tok);
|
2002-09-24 12:43:57 +02:00
|
|
|
if(router->address)
|
|
|
|
free(router->address);
|
|
|
|
if(router->pkey)
|
|
|
|
crypto_free_pk_env(router->pkey);
|
2003-08-28 06:21:57 +02:00
|
|
|
if(router->signing_pkey)
|
|
|
|
crypto_free_pk_env(router->signing_pkey);
|
2003-04-07 06:38:19 +02:00
|
|
|
router_free_exit_policy(router);
|
2002-09-24 12:43:57 +02:00
|
|
|
free(router);
|
|
|
|
return NULL;
|
2003-05-07 20:30:46 +02:00
|
|
|
#undef ARGS
|
|
|
|
#undef NEXT_TOKEN
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
|
|
|
|
2003-04-07 06:38:19 +02:00
|
|
|
static void router_free_exit_policy(routerinfo_t *router) {
|
|
|
|
struct exit_policy_t *tmpe;
|
|
|
|
|
|
|
|
while(router->exit_policy) {
|
|
|
|
tmpe = router->exit_policy;
|
|
|
|
router->exit_policy = tmpe->next;
|
|
|
|
free(tmpe->string);
|
|
|
|
free(tmpe->address);
|
|
|
|
free(tmpe->port);
|
|
|
|
free(tmpe);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-09-24 12:43:57 +02:00
|
|
|
#if 0
|
|
|
|
void test_write_pkey(crypto_pk_env_t *pkey) {
|
|
|
|
char *string;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
log(LOG_DEBUG,"Trying test write.");
|
|
|
|
if(crypto_pk_write_public_key_to_string(pkey,&string,&len)<0) {
|
|
|
|
log(LOG_DEBUG,"router_get_entry_from_string(): write pkey to string failed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
log(LOG_DEBUG,"I did it: len %d, string '%s'.",len,string);
|
|
|
|
free(string);
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
2002-09-24 12:43:57 +02:00
|
|
|
#endif
|
2002-07-22 06:08:37 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
static int router_add_exit_policy(routerinfo_t *router,
|
|
|
|
directory_token_t *tok) {
|
2003-04-07 06:38:19 +02:00
|
|
|
struct exit_policy_t *tmpe, *newe;
|
2003-05-07 20:30:46 +02:00
|
|
|
char *arg, *colon;
|
2003-04-07 06:38:19 +02:00
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
if (tok->val.cmd.n_args != 1)
|
|
|
|
return -1;
|
|
|
|
arg = tok->val.cmd.args[0];
|
2003-04-07 06:38:19 +02:00
|
|
|
|
2003-05-20 08:41:23 +02:00
|
|
|
newe = tor_malloc(sizeof(struct exit_policy_t));
|
2003-04-07 06:38:19 +02:00
|
|
|
memset(newe,0,sizeof(struct exit_policy_t));
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2003-05-20 08:41:23 +02:00
|
|
|
newe->string = tor_malloc(8+strlen(arg));
|
2003-05-07 20:30:46 +02:00
|
|
|
if (tok->tp == K_REJECT) {
|
|
|
|
strcpy(newe->string, "reject ");
|
2003-04-07 06:38:19 +02:00
|
|
|
newe->policy_type = EXIT_POLICY_REJECT;
|
|
|
|
} else {
|
2003-05-07 20:30:46 +02:00
|
|
|
assert(tok->tp == K_ACCEPT);
|
|
|
|
strcpy(newe->string, "accept ");
|
|
|
|
newe->policy_type = EXIT_POLICY_ACCEPT;
|
2003-04-07 06:38:19 +02:00
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
strcat(newe->string, arg);
|
|
|
|
|
|
|
|
colon = strchr(arg,':');
|
|
|
|
if(!colon)
|
2003-04-07 06:38:19 +02:00
|
|
|
goto policy_read_failed;
|
2003-05-07 20:30:46 +02:00
|
|
|
*colon = 0;
|
|
|
|
newe->address = strdup(arg);
|
|
|
|
newe->port = strdup(colon+1);
|
2003-04-07 06:38:19 +02:00
|
|
|
|
2003-08-14 05:52:51 +02:00
|
|
|
log(LOG_DEBUG,"router_add_exit_policy(): %s %s:%s",
|
|
|
|
newe->policy_type == EXIT_POLICY_REJECT ? "reject" : "accept",
|
|
|
|
newe->address, newe->port);
|
2003-04-07 06:38:19 +02:00
|
|
|
|
|
|
|
/* now link newe onto the end of exit_policy */
|
|
|
|
|
|
|
|
if(!router->exit_policy) {
|
|
|
|
router->exit_policy = newe;
|
2003-05-07 20:30:46 +02:00
|
|
|
return 0;
|
2003-04-07 06:38:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for(tmpe=router->exit_policy; tmpe->next; tmpe=tmpe->next) ;
|
|
|
|
tmpe->next = newe;
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
return 0;
|
2003-04-07 06:38:19 +02:00
|
|
|
|
|
|
|
policy_read_failed:
|
|
|
|
assert(newe->string);
|
|
|
|
log(LOG_INFO,"router_add_exit_policy(): Couldn't parse line '%s'. Dropping", newe->string);
|
|
|
|
if(newe->string)
|
|
|
|
free(newe->string);
|
|
|
|
if(newe->address)
|
|
|
|
free(newe->address);
|
|
|
|
if(newe->port)
|
|
|
|
free(newe->port);
|
|
|
|
free(newe);
|
2003-05-07 20:30:46 +02:00
|
|
|
return -1;
|
2003-04-07 06:38:19 +02:00
|
|
|
}
|
|
|
|
|
2003-04-08 08:44:38 +02:00
|
|
|
/* Return 0 if my exit policy says to allow connection to conn.
|
|
|
|
* Else return -1.
|
|
|
|
*/
|
|
|
|
int router_compare_to_exit_policy(connection_t *conn) {
|
|
|
|
struct exit_policy_t *tmpe;
|
|
|
|
|
|
|
|
if(!my_routerinfo) {
|
|
|
|
log(LOG_WARNING, "router_compare_to_exit_policy(): my_routerinfo undefined! Rejected.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(tmpe=my_routerinfo->exit_policy; tmpe; tmpe=tmpe->next) {
|
|
|
|
assert(tmpe->address);
|
|
|
|
assert(tmpe->port);
|
|
|
|
|
|
|
|
/* Totally ignore the address field of the exit policy, for now. */
|
|
|
|
|
|
|
|
if(!strcmp(tmpe->port,"*") || atoi(tmpe->port) == conn->port) {
|
|
|
|
log(LOG_INFO,"router_compare_to_exit_policy(): Port '%s' matches '%d'. %s.",
|
|
|
|
tmpe->port, conn->port,
|
|
|
|
tmpe->policy_type == EXIT_POLICY_ACCEPT ? "Accepting" : "Rejecting");
|
|
|
|
if(tmpe->policy_type == EXIT_POLICY_ACCEPT)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0; /* accept all by default. */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2003-04-07 04:12:02 +02:00
|
|
|
/*
|
|
|
|
Local Variables:
|
|
|
|
mode:c
|
|
|
|
indent-tabs-mode:nil
|
|
|
|
c-basic-offset:2
|
|
|
|
End:
|
|
|
|
*/
|
2003-04-07 06:38:19 +02:00
|
|
|
|