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"
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/**
|
|
|
|
* \file routerlist.c
|
2004-05-10 06:34:48 +02:00
|
|
|
*
|
2004-05-09 18:47:25 +02:00
|
|
|
* \brief Code to parse descriptors and directories, and to
|
2004-05-05 02:30:43 +02:00
|
|
|
* maintain and access the global list of routerinfos for known
|
|
|
|
* servers.
|
2004-05-09 18:47:25 +02:00
|
|
|
**/
|
2004-05-05 02:30:43 +02:00
|
|
|
|
2002-09-26 14:09:10 +02:00
|
|
|
/****************************************************************************/
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
extern or_options_t options; /**< command-line and config-file options */
|
2002-09-26 14:09:10 +02:00
|
|
|
|
|
|
|
/****************************************************************************/
|
2002-09-04 08:29:28 +02:00
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Enumeration of possible token types. The ones starting with K_
|
2004-05-04 20:17:45 +02:00
|
|
|
* correspond to directory 'keywords'. _UNRECOGNIZED is for an
|
|
|
|
* unrecognized keyword; _ERR is an error in the tokenizing process,
|
|
|
|
* _EOF is an end-of-file marker, and _NIL is used to encode
|
|
|
|
* not-a-token.
|
2003-12-09 05:29:52 +01:00
|
|
|
*/
|
|
|
|
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;
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Structure to hold a single directory token.
|
|
|
|
*
|
|
|
|
* We parse a directory by breaking it into "tokens", each consisting
|
|
|
|
* of a keyword, a line full of arguments, and a binary object. The
|
|
|
|
* arguments and object are both optional, depending on the keyword
|
|
|
|
* type.
|
2004-05-04 20:17:45 +02:00
|
|
|
*/
|
2003-12-09 05:29:52 +01:00
|
|
|
typedef struct directory_token_t {
|
2004-05-09 18:47:25 +02:00
|
|
|
directory_keyword tp; /**< Type of the token. */
|
|
|
|
int n_args; /**< Number of elements in args */
|
|
|
|
char **args; /**< Array of arguments from keyword line. */
|
|
|
|
char *object_type; /**< -----BEGIN [object_type]-----*/
|
|
|
|
int object_size; /**< Bytes in object_body */
|
|
|
|
char *object_body; /**< Contents of object, base64-decoded. */
|
|
|
|
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
|
|
|
/* ********************************************************************** */
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** We use a table of rules to decide how to parse each token type. */
|
2004-05-04 20:17:45 +02:00
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Rules for how many arguments a keyword can take. */
|
2004-03-05 06:48:28 +01:00
|
|
|
typedef enum {
|
2004-05-09 18:47:25 +02:00
|
|
|
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. */
|
2004-03-05 06:48:28 +01:00
|
|
|
} arg_syntax;
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Rules for whether the keyword needs an object. */
|
2004-03-05 06:48:28 +01:00
|
|
|
typedef enum {
|
2004-05-09 18:47:25 +02:00
|
|
|
NO_OBJ, /**< (1) no object, ever */
|
|
|
|
NEED_OBJ, /**< (2) object is required */
|
|
|
|
NEED_KEY, /**< (3) object is required, and must be a public key. */
|
|
|
|
OBJ_OK, /**< or (4) object is optional. */
|
2004-03-05 06:48:28 +01:00
|
|
|
} obj_syntax;
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Rules for where a keyword can appear. */
|
2004-03-05 06:48:28 +01:00
|
|
|
typedef enum {
|
2004-05-09 18:47:25 +02:00
|
|
|
ANY = 0, /**< Appears in router descriptor or in directory sections. */
|
|
|
|
DIR_ONLY, /**< Appears only in directory. */
|
|
|
|
RTR_ONLY, /**< Appears only in router descriptor. */
|
2004-03-05 06:48:28 +01:00
|
|
|
} where_syntax;
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Table mapping keywords to token value and to argument rules. */
|
2004-03-05 06:48:28 +01:00
|
|
|
static struct {
|
|
|
|
char *t; int v; arg_syntax s; obj_syntax os; where_syntax ws;
|
|
|
|
} token_table[] = {
|
2004-05-04 20:17:45 +02:00
|
|
|
{ "accept", K_ACCEPT, ARGS, NO_OBJ, RTR_ONLY },
|
|
|
|
{ "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ,DIR_ONLY},
|
|
|
|
{ "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 },
|
|
|
|
{ "running-routers", K_RUNNING_ROUTERS, ARGS, NO_OBJ, DIR_ONLY },
|
|
|
|
{ "ports", K_PORTS, ARGS, NO_OBJ, RTR_ONLY },
|
|
|
|
{ "bandwidth", K_BANDWIDTH, ARGS, NO_OBJ, RTR_ONLY },
|
|
|
|
{ "platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ, RTR_ONLY },
|
|
|
|
{ "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ, ANY },
|
|
|
|
{ "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-05-04 20:17:45 +02:00
|
|
|
/****
|
|
|
|
* Functions to manage and access our list of known routers. (Note:
|
|
|
|
* dirservers maintain a separate, independent list of known router
|
|
|
|
* descriptors.)
|
|
|
|
*****/
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Global list of all of the routers that we, as an OR or OP, know about. */
|
2004-05-04 20:17:45 +02:00
|
|
|
static routerlist_t *routerlist = NULL;
|
2004-02-29 02:31:33 +01:00
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
extern int has_fetched_directory; /**< from main.c */
|
2004-05-04 20:17:45 +02:00
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Try to find a running dirserver. If there are no running dirservers
|
2004-02-26 23:56:36 +01:00
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Pick a random running router with a positive dir_port from our
|
2004-05-04 20:17:45 +02:00
|
|
|
* routerlist. */
|
2004-02-26 23:56:36 +01:00
|
|
|
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-05-04 20:17:45 +02:00
|
|
|
/* Find all the running dirservers we know about. */
|
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.");
|
2004-05-04 20:17:45 +02:00
|
|
|
|
|
|
|
/* No running dir servers found? go through and mark them all as up,
|
2004-05-06 13:08:04 +02:00
|
|
|
* so we 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-05-09 18:47:25 +02:00
|
|
|
/** Given a comma-and-whitespace separated list of nicknames, see which
|
2004-05-10 06:34:48 +02:00
|
|
|
* nicknames in <b>list</b> name routers in our routerlist that are
|
|
|
|
* currently running. Add the routerinfos for those routers to <b>sl</b>.
|
2004-05-04 20:17:45 +02:00
|
|
|
*/
|
|
|
|
void add_nickname_list_to_smartlist(smartlist_t *sl, const char *list) {
|
2004-05-05 04:50:38 +02:00
|
|
|
const 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Add every router from our routerlist that is currently running to
|
|
|
|
* <b>sl</b>.
|
2004-05-04 20:17:45 +02:00
|
|
|
*/
|
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-05-10 06:34:48 +02:00
|
|
|
/** Pick a random running router from a routerlist <b>dir</b>. If any node
|
|
|
|
* named in <b>preferred</b> is available, pick one of those. Never pick a
|
|
|
|
* node named in <b>excluded</b>, or whose routerinfo is in
|
|
|
|
* <b>excludedsmartlist</b>, even if they are the only nodes available.
|
2004-04-03 00:30:39 +02:00
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Return the router in our routerlist whose address is <b>addr</b> and
|
|
|
|
* whose OR port is <b>port</b>. Return NULL if no such router is known.
|
2004-05-04 20:17:45 +02:00
|
|
|
*/
|
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;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Return the router in our routerlist whose nickname is <b>nickname</b>
|
2004-05-04 20:17:45 +02:00
|
|
|
* (case insensitive). Return NULL if no such router is known.
|
|
|
|
*/
|
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
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Set *<b>prouterlist</b> to the current list of all known routers. */
|
2003-12-05 10:51:49 +01:00
|
|
|
void router_get_routerlist(routerlist_t **prouterlist) {
|
|
|
|
*prouterlist = routerlist;
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Free all storage held by <b>router</b>. */
|
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-05-10 06:34:48 +02:00
|
|
|
/** Allocate a fresh copy of <b>router</b> */
|
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;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Free all storage held by a routerlist <b>rl</b> */
|
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
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Mark the router named <b>nickname</b> as non-running in our routerlist. */
|
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
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/*
|
2004-05-04 20:17:45 +02:00
|
|
|
* Code to parse router descriptors and directories.
|
2004-05-10 06:34:48 +02:00
|
|
|
*/
|
2004-04-25 21:04:11 +02:00
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Replace the current router list with the one stored in
|
|
|
|
* <b>routerfile</b>. */
|
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
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Helper function: read routerinfo elements from s, and throw out the
|
2003-12-09 05:29:52 +01:00
|
|
|
* 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
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
|
|
|
|
* <b>s</b>. Return 0 on success, nonzero on failure.
|
2003-12-09 05:29:52 +01:00
|
|
|
*/
|
|
|
|
int router_get_dir_hash(const char *s, char *digest)
|
|
|
|
{
|
|
|
|
return router_get_hash_impl(s,digest,
|
|
|
|
"signed-directory","directory-signature");
|
|
|
|
}
|
2004-05-09 18:47:25 +02:00
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Set <b>digest</b> to the SHA-1 digest of the hash of the first router in
|
|
|
|
* <b>s</b>. Return 0 on success, nonzero on failure.
|
2003-12-09 05:29:52 +01:00
|
|
|
*/
|
|
|
|
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-05-09 18:47:25 +02:00
|
|
|
/** Return 1 if myversion is in versionlist. Else return 0.
|
2004-05-04 20:17:45 +02:00
|
|
|
* (versionlist is 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
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Replace the current routerlist with the routers stored in the
|
2004-05-10 06:34:48 +02:00
|
|
|
* signed directory <b>s</b>. If pkey is provided, make sure that <b>s</b> is
|
2004-05-04 20:17:45 +02:00
|
|
|
* 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
|
|
|
}
|
|
|
|
return 0;
|
2003-08-28 06:21:57 +02:00
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Helper function: resolve the hostname for <b>router</b>. */
|
2003-05-07 20:30:46 +02:00
|
|
|
static int
|
2003-12-09 05:29:52 +01:00
|
|
|
router_resolve(routerinfo_t *router)
|
|
|
|
{
|
2004-04-28 22:11:37 +02:00
|
|
|
if (tor_lookup_hostname(router->address, &router->addr) != 0) {
|
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-05-09 18:47:25 +02:00
|
|
|
/** Helper function: resolve every router in rl, and ensure that our own
|
2004-04-07 21:46:27 +02:00
|
|
|
* 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
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Decide whether a given addr:port is definitely accepted, definitely
|
2004-05-10 06:34:48 +02:00
|
|
|
* rejected, or neither by a given exit policy. If <b>addr</b> is 0, we
|
2004-05-04 20:17:45 +02:00
|
|
|
* don't know the IP of the target address.
|
2003-12-09 05:29:52 +01:00
|
|
|
*
|
2004-05-10 06:34:48 +02:00
|
|
|
* Returns -1 for "rejected", 0 for "accepted", 1 for "maybe" (since IP is
|
2004-05-06 13:08:04 +02:00
|
|
|
* unknown).
|
2003-12-09 05:29:52 +01:00
|
|
|
*/
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Return 1 if all running routers will reject addr:port, return 0 if
|
2004-05-04 20:17:45 +02:00
|
|
|
* any might accept it. */
|
2003-12-09 05:29:52 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Return true iff <b>router</b> does not permit exit streams.
|
2004-05-04 20:17:45 +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-05-10 06:34:48 +02:00
|
|
|
/** Parse a date of the format "YYYY-MM-DD hh:mm:ss" and store the result into
|
|
|
|
* *<b>t</b>.
|
2004-05-04 20:17:45 +02:00
|
|
|
*/
|
2004-05-06 13:08:04 +02:00
|
|
|
/* XXX this should go in util.c, yes? -RD */
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Helper function: parse a directory from <b>s</b> and, when done, store the
|
|
|
|
* resulting routerlist in *<b>dest</b>, freeing the old value if necessary.
|
|
|
|
* If <b>pkey</b> is provided, we check the directory signature with pkey.
|
2003-12-09 05:29:52 +01:00
|
|
|
*/
|
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
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Helper function: Given a string *<b>s</b> containing a concatenated
|
2003-12-09 05:29:52 +01:00
|
|
|
* sequence of router descriptors, parses them and stores the result
|
2004-05-10 06:34:48 +02:00
|
|
|
* in *<b>dest</b>. If good_nickname_lst is provided, then routers whose
|
2003-12-09 05:29:52 +01:00
|
|
|
* 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
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Helper function: reads a single router entry from *<b>s</b> ...
|
|
|
|
* *<b>end</b>. Mallocs a new router and returns it if all goes well, else
|
|
|
|
* returns NULL.
|
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
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Parse the exit policy in the string <b>s</b> and add it to <b>router</b>.
|
2003-12-09 05:29:52 +01:00
|
|
|
*/
|
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;
|
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Given a K_ACCEPT or K_REJECT token and a router, create a new exit_policy_t
|
2004-05-10 06:34:48 +02:00
|
|
|
* corresponding to the token, and add it to <b>router</b> */
|
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
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/*
|
2004-05-04 20:17:45 +02:00
|
|
|
* Low-level tokenizer for router descriptors and directories.
|
2004-05-10 06:34:48 +02:00
|
|
|
*/
|
2003-12-09 05:29:52 +01:00
|
|
|
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Free all resources allocated for <b>tok</b> */
|
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-05-09 18:47:25 +02:00
|
|
|
/** Helper function: read the next token from *s, advance *s to the end
|
2004-05-04 20:17:45 +02:00
|
|
|
* of the token, and return the parsed token. If 'where' is DIR_ONLY
|
|
|
|
* or RTR_ONLY, reject all tokens of the wrong type.
|
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-05-10 06:34:48 +02:00
|
|
|
/** Read all tokens from a string between <b>start</b> and <b>end</b>, and add
|
|
|
|
* them to <b>out</b>. If <b>is_dir</b> is true, reject all non-directory
|
2004-05-04 20:17:45 +02:00
|
|
|
* tokens; else reject all non-routerdescriptor tokens.
|
|
|
|
*/
|
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;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Find the first token in <b>s</b> whose keyword is <b>keyword</b>; return
|
|
|
|
* NULL if no such keyword is found.
|
2004-05-04 20:17:45 +02:00
|
|
|
*/
|
2004-03-05 06:48:28 +01:00
|
|
|
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
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Return a newly allocated smartlist of all accept or reject tokens in
|
|
|
|
* <b>s</b>.
|
2004-05-04 20:17:45 +02: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
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Compute the SHA digest of the substring of <b>s</b> taken from the first
|
|
|
|
* occurrence of <b>start_str</b> through the first newline after the first
|
|
|
|
* subsequent occurrence of <b>end_str</b>; store the 20-byte result in
|
|
|
|
* <b>digest</b>; return 0 on success.
|
2003-12-09 05:29:52 +01:00
|
|
|
*
|
|
|
|
* 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:
|
|
|
|
*/
|