2003-10-08 04:04:08 +02:00
|
|
|
/* Copyright 2001-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$ */
|
|
|
|
|
2003-09-30 20:47:29 +02:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
/* XXX this is required on rh7 to make strptime not complain. how bad
|
|
|
|
* is this for portability?
|
|
|
|
*/
|
|
|
|
|
2002-06-27 00:45:49 +02:00
|
|
|
#include "or.h"
|
|
|
|
|
2002-09-26 14:09:10 +02:00
|
|
|
/****************************************************************************/
|
|
|
|
|
2003-12-05 10:51:49 +01:00
|
|
|
static routerlist_t *routerlist = NULL; /* router array */
|
2002-09-26 14:09:10 +02:00
|
|
|
extern or_options_t options; /* command-line and config-file options */
|
|
|
|
|
|
|
|
/****************************************************************************/
|
2002-09-04 08:29:28 +02:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Enumeration of possible token types. The ones starting with K_ correspond
|
2004-01-11 00:40:38 +01:00
|
|
|
* to directory 'keywords'. _SIGNATURE and _PUBLIC_KEY are self-explanatory.
|
2003-12-09 05:29:52 +01:00
|
|
|
* _ERR is an error in the tokenizing process, _EOF is an end-of-file marker,
|
|
|
|
* and _NIL is used to encode not-a-token.
|
|
|
|
*/
|
|
|
|
typedef enum {
|
|
|
|
K_ACCEPT,
|
|
|
|
K_DIRECTORY_SIGNATURE,
|
|
|
|
K_RECOMMENDED_SOFTWARE,
|
|
|
|
K_REJECT,
|
|
|
|
K_ROUTER,
|
|
|
|
K_SIGNED_DIRECTORY,
|
|
|
|
K_SIGNING_KEY,
|
|
|
|
K_ONION_KEY,
|
2004-04-25 00:17:50 +02:00
|
|
|
K_LINK_KEY, /* XXXX obsolete */
|
2003-12-09 05:29:52 +01:00
|
|
|
K_ROUTER_SIGNATURE,
|
|
|
|
K_PUBLISHED,
|
|
|
|
K_RUNNING_ROUTERS,
|
|
|
|
K_PLATFORM,
|
2004-03-05 06:48:28 +01:00
|
|
|
K_OPT,
|
|
|
|
K_BANDWIDTH,
|
|
|
|
K_PORTS,
|
|
|
|
_UNRECOGNIZED,
|
2003-12-09 05:29:52 +01:00
|
|
|
_ERR,
|
|
|
|
_EOF,
|
|
|
|
_NIL
|
|
|
|
} directory_keyword;
|
|
|
|
|
|
|
|
typedef struct directory_token_t {
|
|
|
|
directory_keyword tp; /* Type of the token. */
|
2004-03-05 06:48:28 +01:00
|
|
|
int n_args;
|
|
|
|
char **args;
|
|
|
|
char *object_type;
|
|
|
|
int object_size;
|
|
|
|
char *object_body;
|
|
|
|
crypto_pk_env_t *key; /* For public keys only. */
|
|
|
|
char *error; /* For _ERR tokens only. */
|
2003-12-09 05:29:52 +01:00
|
|
|
} directory_token_t;
|
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
/* ********************************************************************** */
|
|
|
|
|
|
|
|
/* Every keyword takes either... */
|
|
|
|
typedef enum {
|
|
|
|
NO_ARGS, /* (1) no arguments, ever */
|
|
|
|
ARGS, /* (2) a list of arguments separated by spaces */
|
|
|
|
CONCAT_ARGS, /* or (3) the rest of the line, treated as a single argument. */
|
|
|
|
} arg_syntax;
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
NO_OBJ,
|
|
|
|
NEED_OBJ,
|
|
|
|
NEED_KEY,
|
|
|
|
OBJ_OK,
|
|
|
|
} obj_syntax;
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
ANY = 0,
|
|
|
|
DIR_ONLY,
|
|
|
|
RTR_ONLY,
|
|
|
|
} where_syntax;
|
|
|
|
|
|
|
|
/* Table mapping keywods to token value and to argument rules. */
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
char *t; int v; arg_syntax s; obj_syntax os; where_syntax ws;
|
|
|
|
} token_table[] = {
|
|
|
|
{ "accept", K_ACCEPT, ARGS, NO_OBJ, RTR_ONLY },
|
2004-04-25 00:17:50 +02:00
|
|
|
{ "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ, DIR_ONLY},
|
2004-03-05 06:48:28 +01:00
|
|
|
{ "reject", K_REJECT, ARGS, NO_OBJ, RTR_ONLY },
|
|
|
|
{ "router", K_ROUTER, ARGS, NO_OBJ, RTR_ONLY },
|
|
|
|
{ "recommended-software", K_RECOMMENDED_SOFTWARE, ARGS, NO_OBJ, DIR_ONLY },
|
|
|
|
{ "signed-directory", K_SIGNED_DIRECTORY, NO_ARGS, NO_OBJ, DIR_ONLY },
|
|
|
|
{ "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY, RTR_ONLY },
|
|
|
|
{ "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY, RTR_ONLY },
|
|
|
|
{ "link-key", K_LINK_KEY, NO_ARGS, NEED_KEY, RTR_ONLY },
|
|
|
|
{ "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ, RTR_ONLY },
|
|
|
|
{ "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ, ANY },
|
|
|
|
{ "running-routers", K_RUNNING_ROUTERS, ARGS, NO_OBJ, DIR_ONLY },
|
|
|
|
{ "platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ, RTR_ONLY },
|
|
|
|
{ "ports", K_PORTS, ARGS, NO_OBJ, RTR_ONLY },
|
|
|
|
{ "bandwidth", K_BANDWIDTH, ARGS, NO_OBJ, RTR_ONLY },
|
|
|
|
{ "opt", K_OPT, CONCAT_ARGS, OBJ_OK, ANY },
|
2004-04-07 21:46:27 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
{ NULL, -1 }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* ********************************************************************** */
|
2003-12-09 05:29:52 +01:00
|
|
|
|
2002-09-24 12:43:57 +02:00
|
|
|
/* static function prototypes */
|
2004-02-26 23:56:36 +01:00
|
|
|
static routerinfo_t *
|
|
|
|
router_pick_directory_server_impl(void);
|
2004-01-11 00:40:38 +01:00
|
|
|
static int
|
2003-12-09 00:45:37 +01:00
|
|
|
router_get_list_from_string_impl(const char **s, routerlist_t **dest,
|
2003-12-06 07:01:42 +01:00
|
|
|
int n_good_nicknames,
|
|
|
|
const char **good_nickname_lst);
|
2004-03-29 21:50:59 +02:00
|
|
|
int /* Exposed for unit tests */
|
2003-12-09 00:45:37 +01:00
|
|
|
router_get_routerlist_from_directory_impl(const char *s, routerlist_t **dest,
|
2003-12-06 07:01:42 +01:00
|
|
|
crypto_pk_env_t *pkey);
|
2004-01-11 00:40:38 +01:00
|
|
|
static int
|
|
|
|
router_add_exit_policy(routerinfo_t *router, directory_token_t *tok);
|
|
|
|
static int
|
|
|
|
router_resolve_routerlist(routerlist_t *dir);
|
2003-12-09 05:29:52 +01:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
static int router_get_hash_impl(const char *s, char *digest,
|
|
|
|
const char *start_str, const char *end_str);
|
|
|
|
static void token_free(directory_token_t *tok);
|
|
|
|
static smartlist_t *find_all_exitpolicy(smartlist_t *s);
|
2004-04-07 21:57:40 +02:00
|
|
|
static directory_token_t *find_first_by_keyword(smartlist_t *s,
|
2004-03-05 06:48:28 +01:00
|
|
|
directory_keyword keyword);
|
|
|
|
static int tokenize_string(const char *start, const char *end,
|
|
|
|
smartlist_t *out, int is_dir);
|
|
|
|
static directory_token_t *get_next_token(const char **s, where_syntax where);
|
2003-12-09 05:29:52 +01:00
|
|
|
|
|
|
|
/****************************************************************************/
|
2003-12-13 02:43:21 +01:00
|
|
|
|
2004-02-29 02:31:33 +01:00
|
|
|
extern int has_fetched_directory;
|
|
|
|
|
2004-02-26 23:56:36 +01:00
|
|
|
/* try to find a running dirserver. if there are no dirservers
|
|
|
|
* in our routerlist, reload the routerlist and try again. */
|
2002-09-26 14:09:10 +02:00
|
|
|
routerinfo_t *router_pick_directory_server(void) {
|
2004-02-26 23:56:36 +01:00
|
|
|
routerinfo_t *choice;
|
|
|
|
|
|
|
|
choice = router_pick_directory_server_impl();
|
|
|
|
if(!choice) {
|
|
|
|
log_fn(LOG_WARN,"No dirservers known. Reloading and trying again.");
|
2004-02-29 02:31:33 +01:00
|
|
|
has_fetched_directory=0; /* reset it */
|
2004-02-26 23:56:36 +01:00
|
|
|
if(options.RouterFile) {
|
|
|
|
if(router_set_routerlist_from_file(options.RouterFile) < 0)
|
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
if(config_assign_default_dirservers() < 0)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* give it another try */
|
|
|
|
choice = router_pick_directory_server_impl();
|
|
|
|
}
|
|
|
|
return choice;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* pick a random running router with a positive dir_port */
|
|
|
|
static routerinfo_t *router_pick_directory_server_impl(void) {
|
2003-12-13 02:43:21 +01:00
|
|
|
int i;
|
2003-11-10 09:06:55 +01:00
|
|
|
routerinfo_t *router, *dirserver=NULL;
|
2003-12-13 02:43:21 +01:00
|
|
|
smartlist_t *sl;
|
2003-12-03 11:39:27 +01:00
|
|
|
|
2003-12-05 10:51:49 +01:00
|
|
|
if(!routerlist)
|
2002-09-26 14:09:10 +02:00
|
|
|
return NULL;
|
|
|
|
|
2004-03-31 00:59:00 +02:00
|
|
|
sl = smartlist_create();
|
2004-04-07 21:46:27 +02:00
|
|
|
for(i=0;i< smartlist_len(routerlist->routers); i++) {
|
|
|
|
router = smartlist_get(routerlist->routers, i);
|
2003-09-30 23:27:16 +02:00
|
|
|
if(router->dir_port > 0 && router->is_running)
|
2003-12-13 02:43:21 +01:00
|
|
|
smartlist_add(sl, router);
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
|
|
|
|
2003-12-13 02:43:21 +01:00
|
|
|
router = smartlist_choose(sl);
|
|
|
|
smartlist_free(sl);
|
2003-11-10 09:06:55 +01:00
|
|
|
|
2003-12-13 02:43:21 +01:00
|
|
|
if(router)
|
|
|
|
return router;
|
|
|
|
log_fn(LOG_INFO,"No dirservers are reachable. Trying them all again.");
|
|
|
|
/* no running dir servers found? go through and mark them all as up,
|
|
|
|
* and we'll cycle through the list again. */
|
2004-04-07 21:46:27 +02:00
|
|
|
for(i=0; i < smartlist_len(routerlist->routers); i++) {
|
|
|
|
router = smartlist_get(routerlist->routers, i);
|
2003-12-13 02:43:21 +01:00
|
|
|
if(router->dir_port > 0) {
|
|
|
|
router->is_running = 1;
|
|
|
|
dirserver = router;
|
2003-12-03 11:39:27 +01:00
|
|
|
}
|
|
|
|
}
|
2003-12-13 09:06:03 +01:00
|
|
|
if(!dirserver)
|
|
|
|
log_fn(LOG_WARN,"No dirservers in directory! Returning NULL.");
|
2003-12-13 02:43:21 +01:00
|
|
|
return dirserver;
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
|
|
|
|
2004-04-03 00:23:15 +02:00
|
|
|
void add_nickname_list_to_smartlist(smartlist_t *sl, char *list) {
|
|
|
|
char *start,*end;
|
2004-04-05 02:47:48 +02:00
|
|
|
char nick[MAX_NICKNAME_LEN+1];
|
2004-04-03 00:23:15 +02:00
|
|
|
routerinfo_t *router;
|
|
|
|
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(sl);
|
|
|
|
tor_assert(list);
|
2004-04-03 01:38:26 +02:00
|
|
|
|
2004-04-03 00:23:15 +02:00
|
|
|
while(isspace((int)*list) || *list==',') list++;
|
|
|
|
|
|
|
|
start = list;
|
|
|
|
while(*start) {
|
|
|
|
end=start; while(*end && !isspace((int)*end) && *end != ',') end++;
|
|
|
|
memcpy(nick,start,end-start);
|
|
|
|
nick[end-start] = 0; /* null terminate it */
|
|
|
|
router = router_get_by_nickname(nick);
|
|
|
|
if (router) {
|
|
|
|
if (router->is_running)
|
|
|
|
smartlist_add(sl,router);
|
|
|
|
else
|
|
|
|
log_fn(LOG_INFO,"Nickname list includes '%s' which is known but down.",nick);
|
|
|
|
} else
|
|
|
|
log_fn(has_fetched_directory ? LOG_WARN : LOG_INFO,
|
|
|
|
"Nickname list includes '%s' which isn't a known router.",nick);
|
|
|
|
while(isspace((int)*end) || *end==',') end++;
|
|
|
|
start = end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-13 08:01:46 +01:00
|
|
|
void router_add_running_routers_to_smartlist(smartlist_t *sl) {
|
2003-12-13 02:43:21 +01:00
|
|
|
routerinfo_t *router;
|
2003-12-13 08:01:46 +01:00
|
|
|
int i;
|
2003-12-03 11:28:51 +01:00
|
|
|
|
2003-12-05 10:51:49 +01:00
|
|
|
if(!routerlist)
|
2003-12-13 08:01:46 +01:00
|
|
|
return;
|
2003-12-03 11:28:51 +01:00
|
|
|
|
2004-04-07 21:46:27 +02:00
|
|
|
for(i=0;i<smartlist_len(routerlist->routers);i++) {
|
|
|
|
router = smartlist_get(routerlist->routers, i);
|
2003-12-13 08:01:46 +01:00
|
|
|
if(router->is_running &&
|
|
|
|
(!options.ORPort ||
|
|
|
|
connection_twin_get_by_addr_port(router->addr, router->or_port) ))
|
|
|
|
smartlist_add(sl, router);
|
|
|
|
}
|
2003-12-03 11:28:51 +01:00
|
|
|
}
|
|
|
|
|
2004-04-03 00:30:39 +02:00
|
|
|
/* Pick a random node from preferred if possible, else from all of dir.
|
|
|
|
* Never pick a node in excluded.
|
|
|
|
* If excludedsmartlist is defined, never pick a node in it either.
|
|
|
|
*/
|
|
|
|
routerinfo_t *router_choose_random_node(routerlist_t *dir,
|
|
|
|
char *preferred, char *excluded,
|
|
|
|
smartlist_t *excludedsmartlist)
|
2004-04-03 00:23:15 +02:00
|
|
|
{
|
|
|
|
smartlist_t *sl, *excludednodes;
|
|
|
|
routerinfo_t *choice;
|
|
|
|
|
|
|
|
excludednodes = smartlist_create();
|
|
|
|
add_nickname_list_to_smartlist(excludednodes,excluded);
|
|
|
|
|
|
|
|
/* try the nodes in RendNodes first */
|
|
|
|
sl = smartlist_create();
|
|
|
|
add_nickname_list_to_smartlist(sl,preferred);
|
|
|
|
smartlist_subtract(sl,excludednodes);
|
2004-04-03 00:30:39 +02:00
|
|
|
if(excludedsmartlist)
|
|
|
|
smartlist_subtract(sl,excludedsmartlist);
|
2004-04-03 00:23:15 +02:00
|
|
|
choice = smartlist_choose(sl);
|
|
|
|
smartlist_free(sl);
|
|
|
|
if(!choice) {
|
|
|
|
sl = smartlist_create();
|
|
|
|
router_add_running_routers_to_smartlist(sl);
|
|
|
|
smartlist_subtract(sl,excludednodes);
|
2004-04-03 00:30:39 +02:00
|
|
|
if(excludedsmartlist)
|
|
|
|
smartlist_subtract(sl,excludedsmartlist);
|
2004-04-03 00:23:15 +02:00
|
|
|
choice = smartlist_choose(sl);
|
|
|
|
smartlist_free(sl);
|
|
|
|
}
|
|
|
|
smartlist_free(excludednodes);
|
|
|
|
if(!choice)
|
|
|
|
log_fn(LOG_WARN,"No available nodes when trying to choose node. Failing.");
|
|
|
|
return choice;
|
|
|
|
}
|
|
|
|
|
2002-09-26 14:09:10 +02:00
|
|
|
routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(routerlist);
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2004-04-07 21:46:27 +02:00
|
|
|
for(i=0;i<smartlist_len(routerlist->routers);i++) {
|
|
|
|
router = smartlist_get(routerlist->routers, i);
|
2002-09-26 14:09:10 +02:00
|
|
|
if ((router->addr == addr) && (router->or_port == port))
|
|
|
|
return router;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2003-09-30 23:27:16 +02:00
|
|
|
routerinfo_t *router_get_by_nickname(char *nickname)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(routerlist);
|
2003-09-25 07:17:11 +02:00
|
|
|
|
2004-04-07 21:46:27 +02:00
|
|
|
for(i=0;i<smartlist_len(routerlist->routers);i++) {
|
|
|
|
router = smartlist_get(routerlist->routers, i);
|
2004-04-07 00:23:12 +02:00
|
|
|
if (0 == strcasecmp(router->nickname, nickname))
|
2003-09-25 07:17:11 +02:00
|
|
|
return router;
|
|
|
|
}
|
2004-04-06 00:22:42 +02:00
|
|
|
|
2003-09-25 07:17:11 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2003-09-11 22:32:15 +02:00
|
|
|
|
2003-12-05 10:51:49 +01:00
|
|
|
/* a way to access routerlist outside this file */
|
|
|
|
void router_get_routerlist(routerlist_t **prouterlist) {
|
|
|
|
*prouterlist = routerlist;
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
|
|
|
|
2003-10-18 04:18:22 +02:00
|
|
|
/* delete a router 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-10-18 04:18:22 +02:00
|
|
|
struct exit_policy_t *e;
|
2003-12-05 10:51:49 +01:00
|
|
|
|
2003-05-09 04:00:33 +02:00
|
|
|
if (!router)
|
2002-06-27 00:45:49 +02:00
|
|
|
return;
|
|
|
|
|
2003-10-21 11:48:17 +02:00
|
|
|
tor_free(router->address);
|
|
|
|
tor_free(router->nickname);
|
2004-04-07 23:36:03 +02:00
|
|
|
tor_free(router->platform);
|
2003-09-25 07:17:11 +02:00
|
|
|
if (router->onion_pkey)
|
|
|
|
crypto_free_pk_env(router->onion_pkey);
|
|
|
|
if (router->identity_pkey)
|
|
|
|
crypto_free_pk_env(router->identity_pkey);
|
2003-10-18 04:18:22 +02:00
|
|
|
while (router->exit_policy) {
|
|
|
|
e = router->exit_policy;
|
|
|
|
router->exit_policy = e->next;
|
2003-10-21 11:48:17 +02:00
|
|
|
tor_free(e->string);
|
2003-05-09 04:00:33 +02:00
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
free(router);
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
|
|
|
|
2004-04-08 00:18:57 +02:00
|
|
|
routerinfo_t *routerinfo_copy(const routerinfo_t *router)
|
|
|
|
{
|
|
|
|
routerinfo_t *r;
|
|
|
|
struct exit_policy_t **e, *tmp;
|
|
|
|
|
|
|
|
r = tor_malloc(sizeof(routerinfo_t));
|
|
|
|
memcpy(r, router, sizeof(routerinfo_t));
|
|
|
|
|
|
|
|
r->address = tor_strdup(r->address);
|
|
|
|
r->nickname = tor_strdup(r->nickname);
|
|
|
|
r->platform = tor_strdup(r->platform);
|
|
|
|
if (r->onion_pkey)
|
|
|
|
r->onion_pkey = crypto_pk_dup_key(r->onion_pkey);
|
|
|
|
if (r->identity_pkey)
|
|
|
|
r->identity_pkey = crypto_pk_dup_key(r->identity_pkey);
|
|
|
|
e = &r->exit_policy;
|
|
|
|
while (*e) {
|
|
|
|
tmp = tor_malloc(sizeof(struct exit_policy_t));
|
|
|
|
memcpy(tmp,*e,sizeof(struct exit_policy_t));
|
|
|
|
*e = tmp;
|
|
|
|
(*e)->string = tor_strdup((*e)->string);
|
|
|
|
e = & ((*e)->next);
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2003-12-06 06:54:04 +01:00
|
|
|
static void routerlist_free(routerlist_t *rl)
|
2003-05-06 19:38:16 +02:00
|
|
|
{
|
2004-04-07 21:46:27 +02:00
|
|
|
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
|
|
|
|
routerinfo_free(r));
|
|
|
|
smartlist_free(rl->routers);
|
2003-12-05 10:51:49 +01:00
|
|
|
tor_free(rl->software_versions);
|
2004-04-07 21:46:27 +02:00
|
|
|
tor_free(rl);
|
2003-05-06 19:38:16 +02:00
|
|
|
}
|
|
|
|
|
2003-09-30 23:27:16 +02:00
|
|
|
void router_mark_as_down(char *nickname) {
|
|
|
|
routerinfo_t *router = router_get_by_nickname(nickname);
|
2002-09-26 15:17:14 +02:00
|
|
|
if(!router) /* we don't seem to know about him in the first place */
|
|
|
|
return;
|
2003-09-30 23:27:16 +02:00
|
|
|
log_fn(LOG_DEBUG,"Marking %s as down.",router->nickname);
|
|
|
|
router->is_running = 0;
|
2002-09-26 15:17:14 +02:00
|
|
|
}
|
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
|
2004-04-25 22:37:37 +02:00
|
|
|
#if 0
|
2004-04-25 21:04:11 +02:00
|
|
|
static void dump_onion_keys(int severity)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char buf[FINGERPRINT_LEN+1];
|
|
|
|
routerinfo_t *r;
|
|
|
|
|
|
|
|
log_fn(severity, "Parsed a directory. Here are the onion keys:");
|
|
|
|
for (i = 0; i < smartlist_len(routerlist->routers); i++) {
|
|
|
|
r = smartlist_get(routerlist->routers, i);
|
|
|
|
crypto_pk_get_fingerprint(r->onion_pkey, buf);
|
|
|
|
log_fn(severity, "%10s: %s", r->nickname, buf);
|
|
|
|
}
|
|
|
|
}
|
2004-04-25 22:37:37 +02:00
|
|
|
#endif
|
2004-04-25 21:04:11 +02:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Replace the current router list with the one stored in 'routerfile'. */
|
2003-12-05 10:51:49 +01:00
|
|
|
int router_set_routerlist_from_file(char *routerfile)
|
2002-06-27 00:45:49 +02:00
|
|
|
{
|
2002-09-24 12:43:57 +02:00
|
|
|
char *string;
|
2002-06-27 00:45:49 +02:00
|
|
|
|
2003-09-28 08:48:20 +02:00
|
|
|
string = read_file_to_str(routerfile);
|
|
|
|
if(!string) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"Failed to load routerfile %s.",routerfile);
|
2002-09-26 14:09:10 +02:00
|
|
|
return -1;
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
2003-12-03 09:06:55 +01:00
|
|
|
|
2003-12-05 10:51:49 +01:00
|
|
|
if(router_set_routerlist_from_string(string) < 0) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"The routerfile itself was corrupt.");
|
2002-09-26 14:09:10 +02:00
|
|
|
free(string);
|
|
|
|
return -1;
|
|
|
|
}
|
2004-04-25 21:04:11 +02:00
|
|
|
/* dump_onion_keys(LOG_NOTICE); */
|
2002-09-26 14:09:10 +02:00
|
|
|
|
|
|
|
free(string);
|
|
|
|
return 0;
|
2003-12-03 09:06:55 +01:00
|
|
|
}
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Helper function: read routerinfo elements from s, and throw out the
|
|
|
|
* ones that don't parse and resolve. Replace the current
|
|
|
|
* routerlist. */
|
2004-02-26 22:25:51 +01:00
|
|
|
int router_set_routerlist_from_string(const char *s)
|
2003-12-09 05:29:52 +01:00
|
|
|
{
|
|
|
|
if (router_get_list_from_string_impl(&s, &routerlist, -1, NULL)) {
|
|
|
|
log(LOG_WARN, "Error parsing router file");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (router_resolve_routerlist(routerlist)) {
|
|
|
|
log(LOG_WARN, "Error resolving routerlist");
|
|
|
|
return -1;
|
|
|
|
}
|
2004-04-25 21:04:11 +02:00
|
|
|
/* dump_onion_keys(LOG_NOTICE); */
|
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2003-12-09 00:45:37 +01:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Set 'digest' to the SHA-1 digest of the hash of the directory in 's'.
|
|
|
|
* Return 0 on success, nonzero on failure.
|
|
|
|
*/
|
|
|
|
int router_get_dir_hash(const char *s, char *digest)
|
|
|
|
{
|
|
|
|
return router_get_hash_impl(s,digest,
|
|
|
|
"signed-directory","directory-signature");
|
|
|
|
}
|
|
|
|
/* Set 'digest' to the SHA-1 digest of the hash of the first router in 's'.
|
|
|
|
* Return 0 on success, nonzero on failure.
|
|
|
|
*/
|
|
|
|
int router_get_router_hash(const char *s, char *digest)
|
|
|
|
{
|
|
|
|
return router_get_hash_impl(s,digest,
|
|
|
|
"router ","router-signature");
|
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2004-03-28 06:54:36 +02:00
|
|
|
/* return 1 if myversion is in versionlist. Else return 0.
|
2004-01-11 00:40:38 +01:00
|
|
|
* (versionlist contains a comma-separated list of versions.) */
|
2004-03-28 06:54:36 +02:00
|
|
|
int is_recommended_version(const char *myversion,
|
|
|
|
const char *versionlist) {
|
2003-12-09 05:29:52 +01:00
|
|
|
int len_myversion = strlen(myversion);
|
|
|
|
char *comma;
|
|
|
|
const char *end = versionlist + strlen(versionlist);
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
log_fn(LOG_DEBUG,"checking '%s' in '%s'.", myversion, versionlist);
|
2003-12-17 22:09:31 +01:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
for(;;) {
|
|
|
|
comma = strchr(versionlist, ',');
|
|
|
|
if( ((comma ? comma : end) - versionlist == len_myversion) &&
|
|
|
|
!strncmp(versionlist, myversion, len_myversion))
|
|
|
|
/* only do strncmp if the length matches */
|
2004-03-28 06:54:36 +02:00
|
|
|
return 1; /* success, it's there */
|
2003-12-09 05:29:52 +01:00
|
|
|
if(!comma)
|
2004-03-28 06:54:36 +02:00
|
|
|
return 0; /* nope */
|
2003-12-09 05:29:52 +01:00
|
|
|
versionlist = comma+1;
|
|
|
|
}
|
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Replace the current routerlist with the routers stored in the directory
|
2004-01-11 00:40:38 +01:00
|
|
|
* 's'. If pkey is provided, make sure that 's' is signed with pkey. */
|
2003-12-09 05:29:52 +01:00
|
|
|
int router_set_routerlist_from_directory(const char *s, crypto_pk_env_t *pkey)
|
2003-08-28 06:21:57 +02:00
|
|
|
{
|
2003-12-09 05:29:52 +01:00
|
|
|
if (router_get_routerlist_from_directory_impl(s, &routerlist, pkey)) {
|
|
|
|
log_fn(LOG_WARN, "Couldn't parse directory.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (router_resolve_routerlist(routerlist)) {
|
|
|
|
log_fn(LOG_WARN, "Error resolving routerlist");
|
|
|
|
return -1;
|
|
|
|
}
|
2004-03-30 02:02:52 +02:00
|
|
|
if (!is_recommended_version(VERSION, routerlist->software_versions)) {
|
2003-12-09 05:29:52 +01:00
|
|
|
log(options.IgnoreVersion ? LOG_WARN : LOG_ERR,
|
2003-12-19 20:55:02 +01:00
|
|
|
"You are running Tor version %s, which will not work with this network.\n"
|
|
|
|
"Please use %s%s.",
|
|
|
|
VERSION, strchr(routerlist->software_versions,',') ? "one of " : "",
|
|
|
|
routerlist->software_versions);
|
2003-12-09 05:29:52 +01:00
|
|
|
if(options.IgnoreVersion) {
|
|
|
|
log(LOG_WARN, "IgnoreVersion is set. If it breaks, we told you so.");
|
|
|
|
} else {
|
|
|
|
fflush(0);
|
|
|
|
exit(0);
|
2003-08-28 06:21:57 +02:00
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
}
|
2004-04-25 21:04:11 +02:00
|
|
|
/* dump_onion_keys(LOG_NOTICE); */
|
2003-12-09 05:29:52 +01:00
|
|
|
return 0;
|
2003-08-28 06:21:57 +02:00
|
|
|
}
|
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Helper function: resolve the hostname for 'router' */
|
2003-05-07 20:30:46 +02:00
|
|
|
static int
|
2003-12-09 05:29:52 +01:00
|
|
|
router_resolve(routerinfo_t *router)
|
|
|
|
{
|
|
|
|
struct hostent *rent;
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2004-04-28 21:35:12 +02:00
|
|
|
if (tor_lookup_hostname(router->address, &router->addr)) {
|
2004-03-04 02:53:56 +01:00
|
|
|
log_fn(LOG_WARN,"Could not get address for router %s (%s).",
|
|
|
|
router->address, router->nickname);
|
2003-12-17 22:09:31 +01:00
|
|
|
return -1;
|
2003-12-09 05:29:52 +01:00
|
|
|
}
|
|
|
|
router->addr = ntohl(router->addr); /* get it back into host order */
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2003-12-03 09:06:55 +01:00
|
|
|
|
2004-04-07 21:46:27 +02:00
|
|
|
/* Helper function: resolve every router in rl, and ensure that our own
|
|
|
|
* routerinfo is at the front.
|
|
|
|
*/
|
2003-12-09 05:29:52 +01:00
|
|
|
static int
|
|
|
|
router_resolve_routerlist(routerlist_t *rl)
|
|
|
|
{
|
2004-04-07 21:46:27 +02:00
|
|
|
int i, remove;
|
|
|
|
routerinfo_t *r;
|
2003-12-09 05:29:52 +01:00
|
|
|
if (!rl)
|
|
|
|
rl = routerlist;
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2004-04-07 21:46:27 +02:00
|
|
|
i = 0;
|
|
|
|
if ((r = router_get_my_routerinfo())) {
|
2004-04-08 00:18:57 +02:00
|
|
|
smartlist_insert(rl->routers, 0, routerinfo_copy(r));
|
2004-04-07 21:46:27 +02:00
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( ; i < smartlist_len(rl->routers); ++i) {
|
2003-12-09 05:29:52 +01:00
|
|
|
remove = 0;
|
2004-04-07 21:46:27 +02:00
|
|
|
r = smartlist_get(rl->routers,i);
|
|
|
|
if (router_is_me(r)) {
|
2003-12-09 05:29:52 +01:00
|
|
|
remove = 1;
|
2004-04-07 21:46:27 +02:00
|
|
|
} else if (router_resolve(r)) {
|
|
|
|
log_fn(LOG_WARN, "Couldn't resolve router %s; not using", r->address);
|
2003-12-09 05:29:52 +01:00
|
|
|
remove = 1;
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
if (remove) {
|
2004-04-07 21:46:27 +02:00
|
|
|
routerinfo_free(r);
|
|
|
|
smartlist_del_keeporder(rl->routers, i--);
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
return 0;
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Addr is 0 for "IP unknown".
|
|
|
|
*
|
|
|
|
* Returns -1 for 'rejected', 0 for accepted, 1 for 'maybe' (since IP is
|
|
|
|
* unknown.
|
|
|
|
*/
|
|
|
|
int router_compare_addr_to_exit_policy(uint32_t addr, uint16_t port,
|
|
|
|
struct exit_policy_t *policy)
|
2003-05-07 20:30:46 +02:00
|
|
|
{
|
2003-12-09 05:29:52 +01:00
|
|
|
int maybe_reject = 0;
|
2004-02-17 08:56:33 +01:00
|
|
|
int maybe_accept = 0;
|
2003-12-09 05:29:52 +01:00
|
|
|
int match = 0;
|
2004-02-17 09:52:03 +01:00
|
|
|
int maybe = 0;
|
2003-12-09 05:29:52 +01:00
|
|
|
struct in_addr in;
|
|
|
|
struct exit_policy_t *tmpe;
|
2003-12-05 10:51:49 +01:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
for(tmpe=policy; tmpe; tmpe=tmpe->next) {
|
2004-03-27 01:13:27 +01:00
|
|
|
// log_fn(LOG_DEBUG,"Considering exit policy %s", tmpe->string);
|
2004-02-17 09:52:03 +01:00
|
|
|
maybe = 0;
|
2003-12-09 05:29:52 +01:00
|
|
|
if (!addr) {
|
|
|
|
/* Address is unknown. */
|
2004-02-17 09:52:03 +01:00
|
|
|
if (port >= tmpe->prt_min && port <= tmpe->prt_max) {
|
|
|
|
/* The port definitely matches. */
|
|
|
|
if (tmpe->msk == 0) {
|
|
|
|
match = 1;
|
2004-02-17 08:56:33 +01:00
|
|
|
} else {
|
2004-02-17 09:52:03 +01:00
|
|
|
maybe = 1;
|
2004-02-17 09:10:07 +01:00
|
|
|
}
|
2004-02-17 09:52:03 +01:00
|
|
|
} else if (!port) {
|
|
|
|
/* The port maybe matches. */
|
|
|
|
maybe = 1;
|
2003-12-09 05:29:52 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Address is known */
|
2004-02-17 09:52:57 +01:00
|
|
|
if ((addr & tmpe->msk) == (tmpe->addr & tmpe->msk)) {
|
|
|
|
if (port >= tmpe->prt_min && port <= tmpe->prt_max) {
|
|
|
|
/* Exact match for the policy */
|
|
|
|
match = 1;
|
|
|
|
} else if (!port) {
|
|
|
|
maybe = 1;
|
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
}
|
|
|
|
}
|
2004-02-17 09:52:03 +01:00
|
|
|
if (maybe) {
|
|
|
|
if (tmpe->policy_type == EXIT_POLICY_REJECT)
|
|
|
|
maybe_reject = 1;
|
|
|
|
else
|
|
|
|
maybe_accept = 1;
|
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
if (match) {
|
|
|
|
in.s_addr = htonl(addr);
|
2004-03-27 01:13:27 +01:00
|
|
|
log_fn(LOG_DEBUG,"Address %s:%d matches exit policy '%s'",
|
2003-12-09 05:29:52 +01:00
|
|
|
inet_ntoa(in), port, tmpe->string);
|
2004-02-17 08:56:33 +01:00
|
|
|
if(tmpe->policy_type == EXIT_POLICY_ACCEPT) {
|
|
|
|
/* If we already hit a clause that might trigger a 'reject', than we
|
|
|
|
* can't be sure of this certain 'accept'.*/
|
|
|
|
return maybe_reject ? ADDR_POLICY_UNKNOWN : ADDR_POLICY_ACCEPTED;
|
|
|
|
} else {
|
|
|
|
return maybe_accept ? ADDR_POLICY_UNKNOWN : ADDR_POLICY_REJECTED;
|
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
}
|
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
|
|
|
}
|
2004-02-17 08:56:33 +01:00
|
|
|
/* accept all by default. */
|
|
|
|
return maybe_reject ? ADDR_POLICY_UNKNOWN : ADDR_POLICY_ACCEPTED;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* return 1 if all running routers will reject addr:port, return 0 if
|
|
|
|
any might accept it. */
|
|
|
|
int router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port) {
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
2003-08-23 12:09:25 +02:00
|
|
|
|
2004-04-07 21:46:27 +02:00
|
|
|
for (i=0;i<smartlist_len(routerlist->routers);i++) {
|
|
|
|
router = smartlist_get(routerlist->routers, i);
|
2004-02-17 08:56:33 +01:00
|
|
|
if (router->is_running && router_compare_addr_to_exit_policy(
|
|
|
|
addr, port, router->exit_policy) != ADDR_POLICY_REJECTED)
|
2003-12-09 05:29:52 +01:00
|
|
|
return 0; /* this one could be ok. good enough. */
|
2003-08-23 12:09:25 +02:00
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
return 1; /* all will reject. */
|
2003-08-23 12:09:25 +02:00
|
|
|
}
|
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
int router_exit_policy_rejects_all(routerinfo_t *router) {
|
2004-04-07 21:57:40 +02:00
|
|
|
return router_compare_addr_to_exit_policy(0, 0, router->exit_policy)
|
2004-02-17 08:56:33 +01:00
|
|
|
== ADDR_POLICY_REJECTED;
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
|
|
|
|
2004-03-09 23:17:35 +01:00
|
|
|
static int parse_time(const char *cp, time_t *t)
|
2004-03-09 23:01:17 +01:00
|
|
|
{
|
|
|
|
struct tm st_tm;
|
2004-03-09 23:09:13 +01:00
|
|
|
#ifdef HAVE_STRPTIME
|
2004-03-09 23:01:17 +01:00
|
|
|
if (!strptime(cp, "%Y-%m-%d %H:%M:%S", &st_tm)) {
|
2004-03-09 23:17:35 +01:00
|
|
|
log_fn(LOG_WARN, "Published time was unparseable"); return -1;
|
2004-03-09 23:01:17 +01:00
|
|
|
}
|
2004-04-07 21:57:40 +02:00
|
|
|
#else
|
2004-03-09 23:01:17 +01:00
|
|
|
unsigned int year=0, month=0, day=0, hour=100, minute=100, second=100;
|
2004-04-07 21:57:40 +02:00
|
|
|
if (sscanf(cp, "%u-%u-%u %u:%u:%u", &year, &month,
|
2004-03-11 07:22:53 +01:00
|
|
|
&day, &hour, &minute, &second) < 6) {
|
|
|
|
log_fn(LOG_WARN, "Published time was unparseable"); return -1;
|
2004-03-09 23:01:17 +01:00
|
|
|
}
|
2004-03-09 23:17:35 +01:00
|
|
|
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
|
2004-03-11 07:22:53 +01:00
|
|
|
hour > 23 || minute > 59 || second > 61) {
|
|
|
|
log_fn(LOG_WARN, "Published time was nonsensical"); return -1;
|
2004-03-09 23:01:17 +01:00
|
|
|
}
|
|
|
|
st_tm.tm_year = year;
|
2004-03-11 07:19:08 +01:00
|
|
|
st_tm.tm_mon = month-1;
|
2004-03-09 23:01:17 +01:00
|
|
|
st_tm.tm_mday = day;
|
|
|
|
st_tm.tm_hour = hour;
|
|
|
|
st_tm.tm_min = minute;
|
|
|
|
st_tm.tm_sec = second;
|
|
|
|
#endif
|
2004-03-09 23:17:35 +01:00
|
|
|
*t = tor_timegm(&st_tm);
|
|
|
|
return 0;
|
2004-03-09 23:01:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Helper function: parse a directory from 's' and, when done, store the
|
|
|
|
* resulting routerlist in *dest, freeing the old value if necessary.
|
|
|
|
* If pkey is provided, we check the directory signature with pkey.
|
|
|
|
*/
|
2004-03-29 21:50:59 +02:00
|
|
|
int /* Should be static; exposed for unit tests */
|
2004-04-07 21:57:40 +02:00
|
|
|
router_get_routerlist_from_directory_impl(const char *str,
|
2004-03-05 06:48:28 +01:00
|
|
|
routerlist_t **dest,
|
2003-12-06 06:54:04 +01:00
|
|
|
crypto_pk_env_t *pkey)
|
2003-05-07 20:30:46 +02:00
|
|
|
{
|
2004-03-05 06:48:28 +01:00
|
|
|
directory_token_t *tok;
|
2003-05-07 20:30:46 +02:00
|
|
|
char digest[20];
|
|
|
|
char signed_digest[128];
|
2003-12-05 10:51:49 +01:00
|
|
|
routerlist_t *new_dir = NULL;
|
2003-12-09 00:45:37 +01:00
|
|
|
char *versions = NULL;
|
2003-09-27 23:30:10 +02:00
|
|
|
time_t published_on;
|
2003-12-09 00:45:37 +01:00
|
|
|
char *good_nickname_lst[1024];
|
|
|
|
int n_good_nicknames = 0;
|
2004-03-05 06:48:28 +01:00
|
|
|
int i, r;
|
|
|
|
const char *end;
|
|
|
|
smartlist_t *tokens = NULL;
|
2003-12-17 22:09:31 +01:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
if (router_get_dir_hash(str, digest)) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN, "Unable to compute digest of directory");
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
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
|
|
|
}
|
2004-04-06 22:16:12 +02:00
|
|
|
log(LOG_DEBUG,"Received directory hashes to %s",hex_str(digest,4));
|
2003-09-30 22:05:45 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
if ((end = strstr(str,"\nrouter "))) {
|
|
|
|
++end;
|
|
|
|
} else if ((end = strstr(str, "\ndirectory-signature"))) {
|
|
|
|
++end;
|
|
|
|
} else {
|
|
|
|
end = str + strlen(str);
|
|
|
|
}
|
2004-03-30 22:05:52 +02:00
|
|
|
|
2004-03-31 00:59:00 +02:00
|
|
|
tokens = smartlist_create();
|
2004-03-05 06:48:28 +01:00
|
|
|
if (tokenize_string(str,end,tokens,1)) {
|
|
|
|
log_fn(LOG_WARN, "Error tokenizing directory"); goto err;
|
|
|
|
}
|
2004-04-03 02:58:54 +02:00
|
|
|
if (smartlist_len(tokens) < 1) {
|
2004-03-05 06:48:28 +01:00
|
|
|
log_fn(LOG_WARN, "Impossibly short directory header"); goto err;
|
|
|
|
}
|
|
|
|
if ((tok = find_first_by_keyword(tokens, _UNRECOGNIZED))) {
|
|
|
|
log_fn(LOG_WARN, "Unrecognized keyword in \"%s\"; can't parse directory.",
|
|
|
|
tok->args[0]);
|
|
|
|
goto err;
|
|
|
|
}
|
2004-03-30 22:05:52 +02:00
|
|
|
|
2004-04-03 02:58:54 +02:00
|
|
|
tok = smartlist_get(tokens,0);
|
2004-03-05 06:48:28 +01:00
|
|
|
if (tok->tp != K_SIGNED_DIRECTORY) {
|
2004-04-07 21:57:40 +02:00
|
|
|
log_fn(LOG_WARN, "Directory doesn't start with signed-directory.");
|
2004-03-05 06:48:28 +01:00
|
|
|
goto err;
|
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
if (!(tok = find_first_by_keyword(tokens, K_PUBLISHED))) {
|
|
|
|
log_fn(LOG_WARN, "Missing published time on directory.");
|
|
|
|
goto err;
|
|
|
|
}
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(tok->n_args == 1);
|
2004-04-07 21:57:40 +02:00
|
|
|
|
2004-03-09 23:17:35 +01:00
|
|
|
if (parse_time(tok->args[0], &published_on) < 0) {
|
2004-03-09 23:01:17 +01:00
|
|
|
goto err;
|
2003-09-27 23:30:10 +02:00
|
|
|
}
|
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
if (!(tok = find_first_by_keyword(tokens, K_RECOMMENDED_SOFTWARE))) {
|
|
|
|
log_fn(LOG_WARN, "Missing recommended-software line from directory.");
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
2003-05-09 04:25:37 +02:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
if (tok->n_args != 1) {
|
|
|
|
log_fn(LOG_WARN, "Invalid recommended-software line"); goto err;
|
|
|
|
}
|
|
|
|
versions = tor_strdup(tok->args[0]);
|
2004-04-07 21:57:40 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
if (!(tok = find_first_by_keyword(tokens, K_RUNNING_ROUTERS))) {
|
|
|
|
log_fn(LOG_WARN, "Missing running-routers line from directory.");
|
2004-04-07 21:57:40 +02:00
|
|
|
goto err;
|
2004-03-05 06:48:28 +01:00
|
|
|
}
|
2003-12-09 00:45:37 +01:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
n_good_nicknames = tok->n_args;
|
|
|
|
memcpy(good_nickname_lst, tok->args, n_good_nicknames*sizeof(char *));
|
|
|
|
tok->n_args = 0; /* Don't free the strings in good_nickname_lst yet. */
|
2003-09-27 23:30:10 +02:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Read the router list from s, advancing s up past the end of the last
|
|
|
|
* router. */
|
2004-03-05 06:48:28 +01:00
|
|
|
str = end;
|
|
|
|
if (router_get_list_from_string_impl(&str, &new_dir,
|
2003-12-17 22:09:31 +01:00
|
|
|
n_good_nicknames,
|
2003-12-09 00:45:37 +01:00
|
|
|
(const char**)good_nickname_lst)) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN, "Error reading routers from directory");
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
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
|
|
|
}
|
2004-01-30 21:33:04 +01:00
|
|
|
for (i = 0; i < n_good_nicknames; ++i) {
|
|
|
|
tor_free(good_nickname_lst[i]); /* now free them */
|
|
|
|
}
|
2003-12-09 00:45:37 +01:00
|
|
|
new_dir->software_versions = versions; versions = NULL;
|
2003-09-27 23:30:10 +02:00
|
|
|
new_dir->published_on = published_on;
|
2004-04-03 02:58:54 +02:00
|
|
|
|
|
|
|
SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
|
2004-03-05 06:48:28 +01:00
|
|
|
smartlist_free(tokens);
|
2004-04-03 02:58:54 +02:00
|
|
|
|
2004-03-31 00:59:00 +02:00
|
|
|
tokens = smartlist_create();
|
2004-03-05 06:48:28 +01:00
|
|
|
if (tokenize_string(str,str+strlen(str),tokens,1)<0) {
|
|
|
|
log_fn(LOG_WARN, "Error tokenizing signature"); goto err;
|
|
|
|
}
|
2003-09-25 07:17:11 +02:00
|
|
|
|
2004-04-03 02:58:54 +02:00
|
|
|
if (smartlist_len(tokens) != 1 ||
|
|
|
|
((directory_token_t*)smartlist_get(tokens,0))->tp != K_DIRECTORY_SIGNATURE){
|
2004-03-05 06:48:28 +01:00
|
|
|
log_fn(LOG_WARN,"Expected a single directory signature"); goto err;
|
|
|
|
}
|
2004-04-03 02:58:54 +02:00
|
|
|
tok = smartlist_get(tokens,0);
|
2004-03-05 06:48:28 +01:00
|
|
|
if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
|
2004-04-07 21:57:40 +02:00
|
|
|
log_fn(LOG_WARN, "Bad object type or length on directory signature");
|
2004-03-05 06:48:28 +01:00
|
|
|
goto err;
|
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
if (pkey) {
|
2004-03-05 06:48:28 +01:00
|
|
|
if (crypto_pk_public_checksig(pkey, tok->object_body, 128, signed_digest)
|
2003-05-07 20:30:46 +02:00
|
|
|
!= 20) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN, "Error reading directory: invalid signature.");
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
2004-04-06 22:16:12 +02:00
|
|
|
log(LOG_DEBUG,"Signed directory hash starts %s", hex_str(signed_digest,4));
|
|
|
|
|
2003-05-07 20:30:46 +02:00
|
|
|
if (memcmp(digest, signed_digest, 20)) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN, "Error reading directory: signature does not match.");
|
2003-09-25 07:17:11 +02:00
|
|
|
goto err;
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-17 22:09:31 +01:00
|
|
|
if (*dest)
|
2003-12-05 10:51:49 +01:00
|
|
|
routerlist_free(*dest);
|
2003-05-07 20:39:44 +02:00
|
|
|
*dest = new_dir;
|
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
r = 0;
|
|
|
|
goto done;
|
2003-09-25 07:17:11 +02:00
|
|
|
err:
|
2004-03-05 06:48:28 +01:00
|
|
|
r = -1;
|
2003-09-25 07:17:11 +02:00
|
|
|
if (new_dir)
|
2003-12-05 10:51:49 +01:00
|
|
|
routerlist_free(new_dir);
|
2003-12-09 05:29:52 +01:00
|
|
|
tor_free(versions);
|
|
|
|
for (i = 0; i < n_good_nicknames; ++i) {
|
|
|
|
tor_free(good_nickname_lst[i]);
|
2003-12-09 00:45:37 +01:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
done:
|
|
|
|
if (tokens) {
|
2004-04-03 02:58:54 +02:00
|
|
|
SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
|
2004-03-05 06:48:28 +01:00
|
|
|
smartlist_free(tokens);
|
|
|
|
}
|
|
|
|
return r;
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Helper function: Given a string *s containing a concatenated
|
|
|
|
* sequence of router descriptors, parses them and stores the result
|
|
|
|
* in *dest. If good_nickname_lst is provided, then routers whose
|
|
|
|
* nicknames are not listed are marked as nonrunning. Advances *s to
|
|
|
|
* a point immediately following the last router entry. Returns 0 on
|
|
|
|
* success and -1 on failure.
|
|
|
|
*/
|
2003-12-06 06:54:04 +01:00
|
|
|
static int
|
2003-12-09 00:45:37 +01:00
|
|
|
router_get_list_from_string_impl(const char **s, routerlist_t **dest,
|
2003-12-06 06:54:04 +01:00
|
|
|
int n_good_nicknames,
|
|
|
|
const char **good_nickname_lst)
|
2003-05-06 19:38:16 +02:00
|
|
|
{
|
2002-09-26 14:09:10 +02:00
|
|
|
routerinfo_t *router;
|
2004-04-07 21:46:27 +02:00
|
|
|
smartlist_t *routers;
|
2003-05-09 04:00:33 +02:00
|
|
|
int rarray_len = 0;
|
2003-09-30 10:18:10 +02:00
|
|
|
int i;
|
2004-03-05 06:48:28 +01:00
|
|
|
const char *end;
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(s && *s);
|
2002-09-26 14:09:10 +02:00
|
|
|
|
2004-04-07 21:46:27 +02:00
|
|
|
routers = smartlist_create();
|
2003-05-09 04:00:33 +02:00
|
|
|
|
2003-09-25 07:17:11 +02:00
|
|
|
while (1) {
|
|
|
|
*s = eat_whitespace(*s);
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Don't start parsing the rest of *s unless it contains a router. */
|
2003-09-25 07:17:11 +02:00
|
|
|
if (strncmp(*s, "router ", 7)!=0)
|
|
|
|
break;
|
2004-03-05 06:48:28 +01:00
|
|
|
if ((end = strstr(*s+1, "\nrouter "))) {
|
|
|
|
end++;
|
|
|
|
} else if ((end = strstr(*s+1, "\ndirectory-signature"))) {
|
|
|
|
end++;
|
|
|
|
} else {
|
|
|
|
end = *s+strlen(*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
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
|
|
|
|
router = router_get_entry_from_string(*s, end);
|
|
|
|
*s = end;
|
|
|
|
if (!router) {
|
|
|
|
log_fn(LOG_WARN, "Error reading router; skipping");
|
2003-05-09 04:00:33 +02:00
|
|
|
continue;
|
2003-12-17 22:09:31 +01:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
|
2003-09-27 23:30:10 +02:00
|
|
|
if (n_good_nicknames>=0) {
|
|
|
|
router->is_running = 0;
|
|
|
|
for (i = 0; i < n_good_nicknames; ++i) {
|
|
|
|
if (0==strcasecmp(good_nickname_lst[i], router->nickname)) {
|
|
|
|
router->is_running = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2003-09-30 23:27:16 +02:00
|
|
|
} else {
|
|
|
|
router->is_running = 1; /* start out assuming all dirservers are up */
|
2003-09-27 23:30:10 +02:00
|
|
|
}
|
2004-04-07 21:46:27 +02:00
|
|
|
smartlist_add(routers, router);
|
2003-09-30 10:18:10 +02:00
|
|
|
log_fn(LOG_DEBUG,"just added router #%d.",rarray_len);
|
2002-06-27 00:45:49 +02:00
|
|
|
}
|
2003-12-03 09:06:55 +01:00
|
|
|
|
|
|
|
if (*dest)
|
2003-12-05 10:51:49 +01:00
|
|
|
routerlist_free(*dest);
|
2004-04-07 21:46:27 +02:00
|
|
|
*dest = tor_malloc(sizeof(routerlist_t));
|
|
|
|
(*dest)->routers = routers;
|
2003-09-13 23:53:38 +02:00
|
|
|
(*dest)->software_versions = NULL;
|
2004-04-25 21:04:11 +02:00
|
|
|
|
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-05-06 19:38:16 +02:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Helper function: reads a single router entry from *s, and advances
|
2003-12-13 00:03:25 +01:00
|
|
|
* *s so it points to just after the router it just read.
|
2003-12-09 05:29:52 +01:00
|
|
|
* mallocs a new router and returns it if all goes well, else returns
|
|
|
|
* NULL.
|
2004-04-07 21:46:27 +02:00
|
|
|
*
|
2004-03-05 06:48:28 +01:00
|
|
|
* DOCDOC
|
2002-09-24 12:43:57 +02:00
|
|
|
*/
|
2004-03-05 06:48:28 +01:00
|
|
|
routerinfo_t *router_get_entry_from_string(const char *s,
|
|
|
|
const char *end) {
|
2003-05-07 20:30:46 +02:00
|
|
|
routerinfo_t *router = NULL;
|
2003-09-25 07:17:11 +02:00
|
|
|
char signed_digest[128];
|
|
|
|
char digest[128];
|
2004-03-05 06:48:28 +01:00
|
|
|
smartlist_t *tokens = NULL, *exit_policy_tokens = NULL;
|
|
|
|
directory_token_t *tok;
|
2004-04-03 02:58:54 +02:00
|
|
|
int t;
|
2004-03-05 06:48:28 +01:00
|
|
|
int ports_set, bw_set;
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
if (!end) {
|
|
|
|
end = s + strlen(s);
|
|
|
|
}
|
2003-05-07 20:30:46 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
if (router_get_router_hash(s, digest) < 0) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN, "Couldn't compute router hash.");
|
2003-09-25 07:17:11 +02:00
|
|
|
return NULL;
|
2003-10-02 00:31:13 +02:00
|
|
|
}
|
2004-03-31 00:59:00 +02:00
|
|
|
tokens = smartlist_create();
|
2004-03-05 06:48:28 +01:00
|
|
|
if (tokenize_string(s,end,tokens,0)) {
|
|
|
|
log_fn(LOG_WARN, "Error tokeninzing router descriptor."); goto err;
|
|
|
|
}
|
2003-09-25 07:17:11 +02:00
|
|
|
|
2004-04-03 02:58:54 +02:00
|
|
|
if (smartlist_len(tokens) < 2) {
|
2004-03-05 06:48:28 +01:00
|
|
|
log_fn(LOG_WARN, "Impossibly short router descriptor.");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if ((tok = find_first_by_keyword(tokens, _UNRECOGNIZED))) {
|
|
|
|
log_fn(LOG_WARN, "Unrecognized keyword in \"%s\"; skipping descriptor.",
|
|
|
|
tok->args[0]);
|
|
|
|
goto err;
|
|
|
|
}
|
2003-09-25 07:17:11 +02:00
|
|
|
|
2004-04-03 02:58:54 +02:00
|
|
|
tok = smartlist_get(tokens,0);
|
2003-05-07 20:30:46 +02:00
|
|
|
if (tok->tp != K_ROUTER) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"Entry does not start with \"router\"");
|
2003-12-09 00:45:37 +01:00
|
|
|
goto err;
|
2003-05-06 19:38:16 +02:00
|
|
|
}
|
2003-05-20 08:41:23 +02:00
|
|
|
|
2003-11-18 09:20:19 +01:00
|
|
|
router = tor_malloc_zero(sizeof(routerinfo_t));
|
2004-04-25 00:17:50 +02:00
|
|
|
router->onion_pkey = router->identity_pkey = NULL;
|
2004-03-05 06:48:28 +01:00
|
|
|
ports_set = bw_set = 0;
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2004-04-25 00:17:50 +02:00
|
|
|
if (tok->n_args == 2 || tok->n_args == 5 || tok->n_args == 6) {
|
2004-03-05 06:48:28 +01:00
|
|
|
router->nickname = tor_strdup(tok->args[0]);
|
|
|
|
if (strlen(router->nickname) > MAX_NICKNAME_LEN) {
|
|
|
|
log_fn(LOG_WARN,"Router nickname too long.");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (strspn(router->nickname, LEGAL_NICKNAME_CHARACTERS) !=
|
|
|
|
strlen(router->nickname)) {
|
|
|
|
log_fn(LOG_WARN, "Router nickname contains illegal characters.");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
router->address = tor_strdup(tok->args[1]);
|
|
|
|
router->addr = 0;
|
2004-04-05 02:47:48 +02:00
|
|
|
|
2004-04-25 00:17:50 +02:00
|
|
|
if (tok->n_args >= 5) {
|
2004-03-05 06:48:28 +01:00
|
|
|
router->or_port = atoi(tok->args[2]);
|
|
|
|
router->socks_port = atoi(tok->args[3]);
|
|
|
|
router->dir_port = atoi(tok->args[4]);
|
2004-04-25 00:17:50 +02:00
|
|
|
ports_set = 1;
|
|
|
|
/* XXXX Remove this after everyone has moved to 0.0.6 */
|
|
|
|
if (tok->n_args == 6) {
|
|
|
|
router->bandwidthrate = atoi(tok->args[5]);
|
|
|
|
router->bandwidthburst = router->bandwidthrate * 10;
|
|
|
|
bw_set = 1;
|
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
}
|
|
|
|
} else {
|
2004-04-25 00:17:50 +02:00
|
|
|
log_fn(LOG_WARN,"Wrong # of arguments to \"router\" (%d)",tok->n_args);
|
2003-05-07 20:30:46 +02:00
|
|
|
goto err;
|
2004-04-07 21:57:40 +02:00
|
|
|
}
|
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
tok = find_first_by_keyword(tokens, K_PORTS);
|
|
|
|
if (tok && ports_set) {
|
2004-03-08 00:50:15 +01:00
|
|
|
log_fn(LOG_WARN,"Redundant ports line");
|
2003-09-27 23:30:10 +02:00
|
|
|
goto err;
|
2004-03-05 06:48:28 +01:00
|
|
|
} else if (tok) {
|
|
|
|
if (tok->n_args != 3) {
|
|
|
|
log_fn(LOG_WARN,"Wrong # of arguments to \"ports\"");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
router->or_port = atoi(tok->args[0]);
|
|
|
|
router->socks_port = atoi(tok->args[1]);
|
|
|
|
router->dir_port = atoi(tok->args[2]);
|
|
|
|
ports_set = 1;
|
2003-10-02 00:31:13 +02:00
|
|
|
}
|
2004-04-07 21:57:40 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
tok = find_first_by_keyword(tokens, K_BANDWIDTH);
|
|
|
|
if (tok && bw_set) {
|
2004-03-09 15:53:00 +01:00
|
|
|
log_fn(LOG_WARN,"Redundant bandwidth line");
|
2003-09-27 23:30:10 +02:00
|
|
|
goto err;
|
2004-03-05 06:48:28 +01:00
|
|
|
} else if (tok) {
|
2004-04-25 00:17:50 +02:00
|
|
|
if (tok->n_args < 2) {
|
2004-03-05 06:48:28 +01:00
|
|
|
log_fn(LOG_WARN,"Not enough arguments to \"bandwidth\"");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
router->bandwidthrate = atoi(tok->args[0]);
|
2004-04-25 00:17:50 +02:00
|
|
|
router->bandwidthburst = atoi(tok->args[1]);
|
2004-03-05 06:48:28 +01:00
|
|
|
bw_set = 1;
|
2003-10-02 00:31:13 +02:00
|
|
|
}
|
2003-12-17 22:09:31 +01:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
if (!(tok = find_first_by_keyword(tokens, K_PUBLISHED))) {
|
|
|
|
log_fn(LOG_WARN, "Missing published time"); goto err;
|
|
|
|
}
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(tok->n_args == 1);
|
2004-03-09 23:17:35 +01:00
|
|
|
if (parse_time(tok->args[0], &router->published_on) < 0)
|
2004-03-11 07:22:53 +01:00
|
|
|
goto err;
|
2004-03-05 06:48:28 +01:00
|
|
|
|
|
|
|
if (!(tok = find_first_by_keyword(tokens, K_ONION_KEY))) {
|
|
|
|
log_fn(LOG_WARN, "Missing onion key"); goto err;
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
/* XXX Check key length */
|
|
|
|
router->onion_pkey = tok->key;
|
|
|
|
tok->key = NULL; /* Prevent free */
|
2003-12-17 22:09:31 +01:00
|
|
|
|
2004-04-25 00:17:50 +02:00
|
|
|
if ((tok = find_first_by_keyword(tokens, K_LINK_KEY))) {
|
2004-04-25 00:50:09 +02:00
|
|
|
log_fn(LOG_INFO, "Skipping obsolete link-key");
|
2004-03-05 06:48:28 +01:00
|
|
|
}
|
2003-12-17 22:09:31 +01:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
if (!(tok = find_first_by_keyword(tokens, K_SIGNING_KEY))) {
|
|
|
|
log_fn(LOG_WARN, "Missing onion key"); goto err;
|
|
|
|
}
|
|
|
|
/* XXX Check key length */
|
|
|
|
router->identity_pkey = tok->key;
|
|
|
|
tok->key = NULL; /* Prevent free */
|
|
|
|
|
2004-04-07 23:36:03 +02:00
|
|
|
if ((tok = find_first_by_keyword(tokens, K_PLATFORM))) {
|
|
|
|
router->platform = tor_strdup(tok->args[0]);
|
|
|
|
}
|
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
exit_policy_tokens = find_all_exitpolicy(tokens);
|
2004-04-03 02:58:54 +02:00
|
|
|
SMARTLIST_FOREACH(exit_policy_tokens, directory_token_t *, t,
|
|
|
|
if (router_add_exit_policy(router,t)<0) {
|
|
|
|
log_fn(LOG_WARN,"Error in exit policy"); goto err;}
|
|
|
|
);
|
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
if (!(tok = find_first_by_keyword(tokens, K_ROUTER_SIGNATURE))) {
|
|
|
|
log_fn(LOG_WARN, "Missing router signature"); goto err;
|
|
|
|
}
|
|
|
|
if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
|
2004-04-03 02:58:54 +02:00
|
|
|
log_fn(LOG_WARN, "Bad object type or length on router signature");
|
2004-03-05 06:48:28 +01:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if ((t=crypto_pk_public_checksig(router->identity_pkey, tok->object_body,
|
|
|
|
128, signed_digest)) != 20) {
|
|
|
|
log_fn(LOG_WARN, "Invalid signature %d",t); goto err;
|
|
|
|
}
|
|
|
|
if (memcmp(digest, signed_digest, 20)) {
|
|
|
|
log_fn(LOG_WARN, "Mismatched signature"); goto err;
|
|
|
|
}
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
if (!ports_set) {
|
|
|
|
log_fn(LOG_WARN,"No ports declared; failing."); goto err;
|
|
|
|
}
|
|
|
|
if (!bw_set) {
|
|
|
|
log_fn(LOG_WARN,"No bandwidth declared; failing."); goto err;
|
|
|
|
}
|
|
|
|
if(!router->or_port) {
|
|
|
|
log_fn(LOG_WARN,"or_port unreadable or 0. Failing.");
|
|
|
|
goto err;
|
|
|
|
}
|
2004-01-11 00:40:38 +01:00
|
|
|
if (!router->bandwidthrate) {
|
|
|
|
log_fn(LOG_WARN,"bandwidthrate unreadable or 0. Failing.");
|
|
|
|
goto err;
|
|
|
|
}
|
2004-04-07 23:36:03 +02:00
|
|
|
if (!router->platform) {
|
|
|
|
router->platform = tor_strdup("<unknown>");
|
|
|
|
}
|
2004-01-11 00:40:38 +01:00
|
|
|
|
2004-01-11 08:41:01 +01:00
|
|
|
log_fn(LOG_DEBUG,"or_port %d, socks_port %d, dir_port %d, bandwidthrate %u, bandwidthburst %u.",
|
2003-12-17 22:09:31 +01:00
|
|
|
router->or_port, router->socks_port, router->dir_port,
|
2004-01-11 08:41:01 +01:00
|
|
|
(unsigned) router->bandwidthrate, (unsigned) router->bandwidthburst);
|
2002-09-24 12:43:57 +02:00
|
|
|
|
2003-09-26 20:27:35 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
goto done;
|
|
|
|
return router;
|
2004-04-07 21:57:40 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
err:
|
|
|
|
routerinfo_free(router);
|
|
|
|
router = NULL;
|
|
|
|
done:
|
|
|
|
if (tokens) {
|
2004-04-03 02:58:54 +02:00
|
|
|
SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
|
2004-03-05 06:48:28 +01:00
|
|
|
smartlist_free(tokens);
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
if (exit_policy_tokens) {
|
|
|
|
smartlist_free(exit_policy_tokens);
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
2003-04-07 06:38:19 +02:00
|
|
|
return router;
|
2002-09-24 12:43:57 +02:00
|
|
|
}
|
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Parse the exit policy in the string 's' and add it to 'router'.
|
|
|
|
*/
|
2003-12-06 06:54:04 +01:00
|
|
|
int
|
2003-12-09 00:45:37 +01:00
|
|
|
router_add_exit_policy_from_string(routerinfo_t *router, const char *s)
|
2003-10-08 00:09:09 +02:00
|
|
|
{
|
2004-03-05 06:48:28 +01:00
|
|
|
directory_token_t *tok = NULL;
|
2003-12-09 00:45:37 +01:00
|
|
|
const char *cp;
|
|
|
|
char *tmp;
|
2003-10-08 00:09:09 +02:00
|
|
|
int r;
|
2003-10-08 01:02:37 +02:00
|
|
|
int len, idx;
|
2003-10-08 00:09:09 +02:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* *s might not end with \n, so we need to extend it with one. */
|
2003-10-08 00:15:47 +02:00
|
|
|
len = strlen(s);
|
2003-12-09 00:45:37 +01:00
|
|
|
cp = tmp = tor_malloc(len+2);
|
2003-10-08 01:02:37 +02:00
|
|
|
for (idx = 0; idx < len; ++idx) {
|
|
|
|
tmp[idx] = tolower(s[idx]);
|
|
|
|
}
|
2003-10-08 00:15:47 +02:00
|
|
|
tmp[len]='\n';
|
|
|
|
tmp[len+1]='\0';
|
2004-03-05 06:48:28 +01:00
|
|
|
tok = get_next_token(&cp, RTR_ONLY);
|
|
|
|
if (tok->tp == _ERR) {
|
|
|
|
log_fn(LOG_WARN, "Error reading exit policy: %s", tok->error);
|
2004-01-30 22:16:51 +01:00
|
|
|
goto err;
|
2003-10-08 00:09:09 +02:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
if (tok->tp != K_ACCEPT && tok->tp != K_REJECT) {
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN, "Expected 'accept' or 'reject'.");
|
2004-01-30 22:16:51 +01:00
|
|
|
goto err;
|
2003-10-08 00:09:09 +02:00
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
|
|
|
|
/* Now that we've gotten an exit policy, add it to the router. */
|
2004-03-05 06:48:28 +01:00
|
|
|
r = router_add_exit_policy(router, tok);
|
2004-01-30 22:16:51 +01:00
|
|
|
goto done;
|
|
|
|
err:
|
|
|
|
r = -1;
|
|
|
|
done:
|
2003-10-08 00:09:09 +02:00
|
|
|
free(tmp);
|
2004-03-05 06:48:28 +01:00
|
|
|
token_free(tok);
|
2003-10-08 00:09:09 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Given a K_ACCEPT or K_REJECT token and a router, create a new exit_policy_t
|
|
|
|
* corresponding to the token, and add it to 'router' */
|
2004-04-07 21:57:40 +02:00
|
|
|
static int
|
2004-03-05 06:48:28 +01:00
|
|
|
router_add_exit_policy(routerinfo_t *router, directory_token_t *tok) {
|
2003-12-09 05:29:52 +01:00
|
|
|
|
2003-04-07 06:38:19 +02:00
|
|
|
struct exit_policy_t *tmpe, *newe;
|
2003-11-14 21:45:47 +01:00
|
|
|
struct in_addr in;
|
|
|
|
char *arg, *address, *mask, *port, *endptr;
|
|
|
|
int bits;
|
2003-04-07 06:38:19 +02:00
|
|
|
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(tok->tp == K_REJECT || tok->tp == K_ACCEPT);
|
2003-12-09 05:29:52 +01:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
if (tok->n_args != 1)
|
2003-05-07 20:30:46 +02:00
|
|
|
return -1;
|
2004-03-05 06:48:28 +01:00
|
|
|
arg = tok->args[0];
|
2003-04-07 06:38:19 +02:00
|
|
|
|
2003-11-18 09:20:19 +01:00
|
|
|
newe = tor_malloc_zero(sizeof(struct exit_policy_t));
|
|
|
|
|
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
|
|
|
strcpy(newe->string, "accept ");
|
|
|
|
newe->policy_type = EXIT_POLICY_ACCEPT;
|
2003-04-07 06:38:19 +02:00
|
|
|
}
|
2004-03-14 23:47:11 +01:00
|
|
|
strcat(newe->string, arg); /* can't overflow */
|
2003-11-14 21:45:47 +01:00
|
|
|
|
|
|
|
address = arg;
|
|
|
|
mask = strchr(arg,'/');
|
|
|
|
port = strchr(mask?mask:arg,':');
|
2003-12-17 22:09:31 +01:00
|
|
|
/* Break 'arg' into separate strings. 'arg' was already strdup'd by
|
2003-12-14 01:04:29 +01:00
|
|
|
* _router_get_next_token, so it's safe to modify.
|
|
|
|
*/
|
2003-11-14 21:45:47 +01:00
|
|
|
if (mask)
|
|
|
|
*mask++ = 0;
|
2003-12-14 01:04:29 +01:00
|
|
|
if (port)
|
|
|
|
*port++ = 0;
|
2003-11-14 21:45:47 +01:00
|
|
|
|
|
|
|
if (strcmp(address, "*") == 0) {
|
|
|
|
newe->addr = 0;
|
2004-03-09 23:01:17 +01:00
|
|
|
} else if (tor_inet_aton(address, &in) != 0) {
|
2003-11-17 08:37:45 +01:00
|
|
|
newe->addr = ntohl(in.s_addr);
|
2003-11-14 21:45:47 +01:00
|
|
|
} else {
|
|
|
|
log_fn(LOG_WARN, "Malformed IP %s in exit policy; rejecting.",
|
|
|
|
address);
|
|
|
|
goto policy_read_failed;
|
|
|
|
}
|
|
|
|
if (!mask) {
|
|
|
|
if (strcmp(address, "*") == 0)
|
|
|
|
newe->msk = 0;
|
|
|
|
else
|
|
|
|
newe->msk = 0xFFFFFFFFu;
|
|
|
|
} else {
|
|
|
|
endptr = NULL;
|
|
|
|
bits = (int) strtol(mask, &endptr, 10);
|
|
|
|
if (!*endptr) {
|
|
|
|
/* strtol handled the whole mask. */
|
|
|
|
newe->msk = ~((1<<(32-bits))-1);
|
2004-03-09 23:01:17 +01:00
|
|
|
} else if (tor_inet_aton(mask, &in) != 0) {
|
2003-11-17 08:37:45 +01:00
|
|
|
newe->msk = ntohl(in.s_addr);
|
2003-11-14 21:45:47 +01:00
|
|
|
} else {
|
|
|
|
log_fn(LOG_WARN, "Malformed mask %s on exit policy; rejecting.",
|
|
|
|
mask);
|
|
|
|
goto policy_read_failed;
|
|
|
|
}
|
|
|
|
}
|
2003-12-14 01:04:29 +01:00
|
|
|
if (!port || strcmp(port, "*") == 0) {
|
2004-02-17 07:39:20 +01:00
|
|
|
newe->prt_min = 0;
|
2003-12-13 03:44:02 +01:00
|
|
|
newe->prt_max = 65535;
|
2003-12-05 10:51:49 +01:00
|
|
|
} else {
|
2003-11-14 21:45:47 +01:00
|
|
|
endptr = NULL;
|
2004-03-09 23:01:17 +01:00
|
|
|
newe->prt_min = (uint16_t) strtol(port, &endptr, 10);
|
2003-12-13 03:44:02 +01:00
|
|
|
if (*endptr == '-') {
|
|
|
|
port = endptr+1;
|
|
|
|
endptr = NULL;
|
2004-03-09 23:01:17 +01:00
|
|
|
newe->prt_max = (uint16_t) strtol(port, &endptr, 10);
|
2003-12-13 03:44:02 +01:00
|
|
|
if (*endptr) {
|
|
|
|
log_fn(LOG_WARN, "Malformed port %s on exit policy; rejecting.",
|
|
|
|
port);
|
|
|
|
}
|
|
|
|
} else if (*endptr) {
|
2003-11-14 21:45:47 +01:00
|
|
|
log_fn(LOG_WARN, "Malformed port %s on exit policy; rejecting.",
|
|
|
|
port);
|
|
|
|
goto policy_read_failed;
|
2003-12-13 03:44:02 +01:00
|
|
|
} else {
|
|
|
|
newe->prt_max = newe->prt_min;
|
2003-11-14 21:45:47 +01:00
|
|
|
}
|
|
|
|
}
|
2003-04-07 06:38:19 +02:00
|
|
|
|
2003-11-17 08:37:45 +01:00
|
|
|
in.s_addr = htonl(newe->addr);
|
2003-11-14 21:45:47 +01:00
|
|
|
address = tor_strdup(inet_ntoa(in));
|
2003-11-17 08:37:45 +01:00
|
|
|
in.s_addr = htonl(newe->msk);
|
2003-12-13 03:44:02 +01:00
|
|
|
log_fn(LOG_DEBUG,"%s %s/%s:%d-%d",
|
2003-11-14 21:45:47 +01:00
|
|
|
newe->policy_type == EXIT_POLICY_REJECT ? "reject" : "accept",
|
2003-12-13 03:44:02 +01:00
|
|
|
address, inet_ntoa(in), newe->prt_min, newe->prt_max);
|
2003-11-14 21:45:47 +01:00
|
|
|
tor_free(address);
|
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:
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(newe->string);
|
2003-10-10 03:48:32 +02:00
|
|
|
log_fn(LOG_WARN,"Couldn't parse line '%s'. Dropping", newe->string);
|
2003-10-21 11:48:17 +02:00
|
|
|
tor_free(newe->string);
|
2003-04-07 06:38:19 +02:00
|
|
|
free(newe);
|
2003-05-07 20:30:46 +02:00
|
|
|
return -1;
|
2003-04-07 06:38:19 +02:00
|
|
|
}
|
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* ------------------------------------------------------------ */
|
|
|
|
/* Tokenizer for router descriptors and directories. */
|
|
|
|
|
|
|
|
|
|
|
|
/* Free any malloced resources allocated for a token. Does not free
|
|
|
|
* the token itself.
|
2003-11-16 06:33:45 +01:00
|
|
|
*/
|
2003-12-09 05:29:52 +01:00
|
|
|
static void
|
2004-03-05 06:48:28 +01:00
|
|
|
token_free(directory_token_t *tok)
|
2003-11-16 06:33:45 +01:00
|
|
|
{
|
2003-12-09 05:29:52 +01:00
|
|
|
int i;
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(tok);
|
2004-03-05 06:48:28 +01:00
|
|
|
if (tok->args) {
|
|
|
|
for (i = 0; i < tok->n_args; ++i) {
|
|
|
|
tor_free(tok->args[i]);
|
2003-12-09 05:29:52 +01:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
tor_free(tok->args);
|
|
|
|
}
|
|
|
|
tor_free(tok->object_type);
|
|
|
|
tor_free(tok->object_body);
|
|
|
|
if (tok->key)
|
|
|
|
crypto_free_pk_env(tok->key);
|
|
|
|
tor_free(tok);
|
2003-11-16 06:33:45 +01:00
|
|
|
}
|
2003-11-14 21:45:47 +01:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
/* Helper function: read the next token from *s, and stores it into a new
|
|
|
|
* directory token *tok.
|
2003-04-08 08:44:38 +02:00
|
|
|
*/
|
2004-03-05 06:48:28 +01:00
|
|
|
static directory_token_t *
|
|
|
|
get_next_token(const char **s, where_syntax where) {
|
|
|
|
const char *next, *obstart;
|
|
|
|
int i, done, allocated;
|
|
|
|
directory_token_t *tok;
|
|
|
|
arg_syntax a_syn;
|
|
|
|
obj_syntax o_syn = NO_OBJ;
|
|
|
|
|
|
|
|
#define RET_ERR(msg) \
|
|
|
|
do { if (tok) token_free(tok); \
|
|
|
|
tok = tor_malloc_zero(sizeof(directory_token_t));\
|
|
|
|
tok->tp = _ERR; \
|
|
|
|
tok->error = msg; \
|
|
|
|
goto done_tokenizing; } while (0)
|
2004-04-07 21:57:40 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
tok = tor_malloc_zero(sizeof(directory_token_t));
|
2003-12-09 05:29:52 +01:00
|
|
|
tok->tp = _ERR;
|
|
|
|
|
|
|
|
*s = eat_whitespace(*s);
|
|
|
|
if (!**s) {
|
|
|
|
tok->tp = _EOF;
|
2004-03-05 06:48:28 +01:00
|
|
|
return tok;
|
2004-04-07 21:57:40 +02:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
next = find_whitespace(*s);
|
|
|
|
if (!next) {
|
|
|
|
tok->error = "Unexpected EOF"; return tok;
|
|
|
|
}
|
|
|
|
/* It's a keyword... but which one? */
|
|
|
|
for (i = 0 ; token_table[i].t ; ++i) {
|
|
|
|
if (!strncmp(token_table[i].t, *s, next-*s)) {
|
|
|
|
/* We've found the keyword. */
|
|
|
|
tok->tp = token_table[i].v;
|
|
|
|
a_syn = token_table[i].s;
|
|
|
|
o_syn = token_table[i].os;
|
|
|
|
if (token_table[i].ws != ANY && token_table[i].ws != where) {
|
|
|
|
if (where == DIR_ONLY) {
|
|
|
|
RET_ERR("Found a router-only token in a directory section");
|
|
|
|
} else {
|
|
|
|
RET_ERR("Found a directory-only token in a router descriptor");
|
|
|
|
}
|
2003-11-14 21:45:47 +01:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
if (a_syn == ARGS) {
|
|
|
|
/* This keyword takes multiple arguments. */
|
|
|
|
i = 0;
|
|
|
|
done = (*next == '\n');
|
|
|
|
allocated = 32;
|
2004-04-07 21:46:27 +02:00
|
|
|
tok->args = tor_malloc(sizeof(char*)*32);
|
2004-03-05 06:48:28 +01:00
|
|
|
*s = eat_whitespace_no_nl(next);
|
|
|
|
while (**s != '\n' && !done) {
|
|
|
|
next = find_whitespace(*s);
|
|
|
|
if (*next == '\n')
|
|
|
|
done = 1;
|
|
|
|
if (i == allocated) {
|
|
|
|
allocated *= 2;
|
2004-04-07 21:46:27 +02:00
|
|
|
tok->args = tor_realloc(tok->args,sizeof(char*)*allocated);
|
2003-12-09 05:29:52 +01:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
tok->args[i++] = tor_strndup(*s,next-*s);
|
2003-12-09 05:29:52 +01:00
|
|
|
*s = eat_whitespace_no_nl(next+1);
|
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
tok->n_args = i;
|
|
|
|
} else if (a_syn == CONCAT_ARGS) {
|
|
|
|
/* The keyword takes the line as a single argument */
|
|
|
|
*s = eat_whitespace_no_nl(next);
|
|
|
|
next = strchr(*s, '\n');
|
|
|
|
if (!next)
|
|
|
|
RET_ERR("Unexpected EOF");
|
2004-04-07 21:46:27 +02:00
|
|
|
tok->args = tor_malloc(sizeof(char*));
|
2004-03-05 06:48:28 +01:00
|
|
|
tok->args[0] = tor_strndup(*s,next-*s);
|
|
|
|
tok->n_args = 1;
|
|
|
|
*s = eat_whitespace_no_nl(next+1);
|
|
|
|
} else {
|
|
|
|
/* The keyword takes no arguments. */
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(a_syn == NO_ARGS);
|
2004-03-05 06:48:28 +01:00
|
|
|
*s = eat_whitespace_no_nl(next);
|
|
|
|
if (**s != '\n') {
|
|
|
|
RET_ERR("Unexpected arguments");
|
|
|
|
}
|
|
|
|
tok->n_args = 0;
|
|
|
|
*s = eat_whitespace_no_nl(*s+1);
|
2003-12-09 05:29:52 +01:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (tok->tp == _ERR) {
|
|
|
|
tok->tp = _UNRECOGNIZED;
|
|
|
|
next = strchr(*s, '\n');
|
|
|
|
if (!next) {
|
|
|
|
RET_ERR("Unexpected EOF");
|
2004-04-07 21:46:27 +02:00
|
|
|
}
|
|
|
|
tok->args = tor_malloc(sizeof(char*));
|
2004-03-05 06:48:28 +01:00
|
|
|
tok->args[0] = tor_strndup(*s,next-*s);
|
|
|
|
tok->n_args = 1;
|
|
|
|
*s = next+1;
|
|
|
|
o_syn = OBJ_OK;
|
|
|
|
}
|
|
|
|
*s = eat_whitespace(*s);
|
|
|
|
if (strncmp(*s, "-----BEGIN ", 11)) {
|
|
|
|
goto done_tokenizing;
|
|
|
|
}
|
|
|
|
obstart = *s;
|
|
|
|
*s += 11; /* length of "-----BEGIN ". */
|
|
|
|
next = strchr(*s, '\n');
|
|
|
|
if (next-*s < 6 || strncmp(next-5, "-----\n", 6)) {
|
|
|
|
RET_ERR("Malformed object: bad begin line");
|
|
|
|
}
|
|
|
|
tok->object_type = tor_strndup(*s, next-*s-5);
|
|
|
|
*s = next+1;
|
|
|
|
next = strstr(*s, "-----END ");
|
|
|
|
if (!next) {
|
|
|
|
RET_ERR("Malformed object: missing end line");
|
|
|
|
}
|
|
|
|
if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) {
|
|
|
|
if (strncmp(next, "-----END RSA PUBLIC KEY-----\n", 29))
|
|
|
|
RET_ERR("Malformed object: mismatched end line");
|
|
|
|
next = strchr(next,'\n')+1;
|
2004-04-03 04:40:30 +02:00
|
|
|
tok->key = crypto_new_pk_env();
|
2004-03-05 06:48:28 +01:00
|
|
|
if (crypto_pk_read_public_key_from_string(tok->key, obstart, next-obstart))
|
|
|
|
RET_ERR("Couldn't parse public key.");
|
|
|
|
*s = next;
|
|
|
|
} else {
|
|
|
|
tok->object_body = tor_malloc(next-*s); /* really, this is too much RAM. */
|
|
|
|
i = base64_decode(tok->object_body, 256, *s, next-*s);
|
|
|
|
if (i<0) {
|
|
|
|
RET_ERR("Malformed object: bad base64-encoded data");
|
2003-04-08 08:44:38 +02:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
tok->object_size = i;
|
|
|
|
*s = next + 9; /* length of "-----END ". */
|
|
|
|
i = strlen(tok->object_type);
|
|
|
|
if (strncmp(*s, tok->object_type, i) || strncmp(*s+i, "-----\n", 6)) {
|
|
|
|
RET_ERR("Malformed object: mismatched end tag");
|
|
|
|
}
|
|
|
|
*s += i+6;
|
2003-04-08 08:44:38 +02:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
switch(o_syn)
|
|
|
|
{
|
|
|
|
case NO_OBJ:
|
|
|
|
if (tok->object_body)
|
|
|
|
RET_ERR("Unexpected object for keyword");
|
|
|
|
if (tok->key)
|
|
|
|
RET_ERR("Unexpected public key for keyword");
|
|
|
|
break;
|
|
|
|
case NEED_OBJ:
|
|
|
|
if (!tok->object_body)
|
|
|
|
RET_ERR("Missing object for keyword");
|
|
|
|
break;
|
|
|
|
case NEED_KEY:
|
|
|
|
if (!tok->key)
|
|
|
|
RET_ERR("Missing publid key for keyword");
|
|
|
|
break;
|
|
|
|
case OBJ_OK:
|
|
|
|
break;
|
|
|
|
}
|
2004-04-07 21:57:40 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
done_tokenizing:
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
for (i = 0; token_table[i].t ; ++i) {
|
|
|
|
if (token_table[i].v == tok->tp) {
|
|
|
|
fputs(token_table[i].t, stdout);
|
|
|
|
break;
|
|
|
|
i = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i) {
|
|
|
|
if (tok->tp == _UNRECOGNIZED) fputs("UNRECOGNIZED", stdout);
|
|
|
|
if (tok->tp == _ERR) fputs("ERR",stdout);
|
|
|
|
if (tok->tp == _EOF) fputs("EOF",stdout);
|
|
|
|
if (tok->tp == _NIL) fputs("_NIL",stdout);
|
|
|
|
}
|
|
|
|
for(i = 0; i < tok->n_args; ++i) {
|
|
|
|
fprintf(stdout," \"%s\"", tok->args[i]);
|
|
|
|
}
|
|
|
|
if (tok->error) { fprintf(stdout," *%s*", tok->error); }
|
|
|
|
fputs("\n",stdout);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
return tok;
|
|
|
|
#undef RET_ERR
|
2003-11-14 21:45:47 +01:00
|
|
|
}
|
|
|
|
|
2004-04-07 21:57:40 +02:00
|
|
|
static int
|
|
|
|
tokenize_string(const char *start, const char *end, smartlist_t *out,
|
2004-03-05 06:48:28 +01:00
|
|
|
int is_dir)
|
|
|
|
{
|
|
|
|
const char **s;
|
|
|
|
directory_token_t *tok = NULL;
|
|
|
|
where_syntax where = is_dir ? DIR_ONLY : RTR_ONLY;
|
|
|
|
s = &start;
|
|
|
|
while (*s < end && (!tok || tok->tp != _EOF)) {
|
|
|
|
tok = get_next_token(s, where);
|
|
|
|
if (tok->tp == _ERR) {
|
|
|
|
log_fn(LOG_WARN, "parse error: %s", tok->error);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
smartlist_add(out, tok);
|
|
|
|
*s = eat_whitespace(*s);
|
|
|
|
}
|
2004-04-07 21:57:40 +02:00
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static directory_token_t *
|
|
|
|
find_first_by_keyword(smartlist_t *s, directory_keyword keyword)
|
|
|
|
{
|
2004-04-03 02:58:54 +02:00
|
|
|
SMARTLIST_FOREACH(s, directory_token_t *, t, if (t->tp == keyword) return t);
|
2004-03-05 06:48:28 +01:00
|
|
|
return NULL;
|
2003-12-09 05:29:52 +01:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
|
|
|
|
static smartlist_t *
|
|
|
|
find_all_exitpolicy(smartlist_t *s)
|
|
|
|
{
|
2004-03-31 00:59:00 +02:00
|
|
|
smartlist_t *out = smartlist_create();
|
2004-04-03 02:58:54 +02:00
|
|
|
SMARTLIST_FOREACH(s, directory_token_t *, t,
|
|
|
|
if (t->tp == K_ACCEPT || t->tp == K_REJECT)
|
|
|
|
smartlist_add(out,t));
|
2004-03-05 06:48:28 +01:00
|
|
|
return out;
|
2003-12-03 09:06:55 +01:00
|
|
|
}
|
2004-03-05 06:48:28 +01:00
|
|
|
|
2003-12-03 09:06:55 +01:00
|
|
|
|
2003-12-09 05:29:52 +01:00
|
|
|
/* Compute the SHA digest of the substring of s taken from the first
|
|
|
|
* occurrence of start_str through the first newline after the first
|
|
|
|
* subsequent occurrence of end_str; store the 20-byte result in 'digest';
|
|
|
|
* return 0 on success.
|
|
|
|
*
|
|
|
|
* If no such substring exists, return -1.
|
|
|
|
*/
|
2003-12-17 22:09:31 +01:00
|
|
|
static int router_get_hash_impl(const char *s, char *digest,
|
2003-12-09 05:29:52 +01:00
|
|
|
const char *start_str,
|
|
|
|
const char *end_str)
|
|
|
|
{
|
|
|
|
char *start, *end;
|
|
|
|
start = strstr(s, start_str);
|
|
|
|
if (!start) {
|
|
|
|
log_fn(LOG_WARN,"couldn't find \"%s\"",start_str);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
end = strstr(start+strlen(start_str), end_str);
|
|
|
|
if (!end) {
|
|
|
|
log_fn(LOG_WARN,"couldn't find \"%s\"",end_str);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
end = strchr(end, '\n');
|
|
|
|
if (!end) {
|
|
|
|
log_fn(LOG_WARN,"couldn't find EOL");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
++end;
|
|
|
|
|
2004-04-03 04:40:30 +02:00
|
|
|
if (crypto_digest(start, end-start, digest)) {
|
2003-12-09 05:29:52 +01:00
|
|
|
log_fn(LOG_WARN,"couldn't compute digest");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2003-04-08 08:44:38 +02:00
|
|
|
}
|
|
|
|
|
2003-04-07 04:12:02 +02:00
|
|
|
/*
|
|
|
|
Local Variables:
|
|
|
|
mode:c
|
|
|
|
indent-tabs-mode:nil
|
|
|
|
c-basic-offset:2
|
|
|
|
End:
|
|
|
|
*/
|