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$ */
|
|
|
|
|
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-10 19:30:51 +02:00
|
|
|
* \brief Code 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
|
|
|
|
2004-03-05 06:48:28 +01:00
|
|
|
/* ********************************************************************** */
|
2003-12-09 05:29:52 +01:00
|
|
|
|
2002-09-24 12:43:57 +02:00
|
|
|
/* static function prototypes */
|
2004-05-10 19:30:51 +02:00
|
|
|
static routerinfo_t *router_pick_directory_server_impl(void);
|
|
|
|
static int router_resolve_routerlist(routerlist_t *dir);
|
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-05-17 22:31:01 +02:00
|
|
|
routerlist_clear_trusted_directories();
|
2004-02-26 23:56:36 +01:00
|
|
|
if(options.RouterFile) {
|
2004-05-17 22:31:01 +02:00
|
|
|
if(router_load_routerlist_from_file(options.RouterFile, 1) < 0)
|
2004-02-26 23:56:36 +01:00
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
if(config_assign_default_dirservers() < 0)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* give it another try */
|
|
|
|
choice = router_pick_directory_server_impl();
|
|
|
|
}
|
|
|
|
return choice;
|
|
|
|
}
|
|
|
|
|
2004-06-16 23:08:29 +02:00
|
|
|
/** Pick a random running router that's a trusted dirserver 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);
|
2004-06-16 23:08:29 +02:00
|
|
|
if(router->is_running && router->is_trusted_dir) {
|
|
|
|
tor_assert(router->dir_port > 0);
|
2003-12-13 02:43:21 +01:00
|
|
|
smartlist_add(sl, router);
|
2004-06-16 23:08:29 +02:00
|
|
|
}
|
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);
|
2004-06-16 23:08:29 +02:00
|
|
|
if(router->is_trusted_dir) {
|
|
|
|
tor_assert(router->dir_port > 0);
|
2003-12-13 02:43:21 +01:00
|
|
|
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
|
2004-07-05 00:48:11 +02:00
|
|
|
log_fn(LOG_WARN,"Nickname list includes '%s' which is known but down.",nick);
|
2004-04-03 00:23:15 +02:00
|
|
|
} 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 ||
|
2004-07-02 01:13:04 +02:00
|
|
|
connection_get_by_identity_digest(router->identity_digest,
|
|
|
|
CONN_TYPE_OR)))
|
2003-12-13 08:01:46 +01:00
|
|
|
smartlist_add(sl, router);
|
|
|
|
}
|
2003-12-03 11:28:51 +01:00
|
|
|
}
|
|
|
|
|
2004-05-20 21:12:28 +02:00
|
|
|
/** Return a random running router from the routerlist. If any node
|
2004-05-10 06:34:48 +02:00
|
|
|
* 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
|
|
|
*/
|
2004-05-20 21:12:28 +02:00
|
|
|
routerinfo_t *router_choose_random_node(char *preferred, char *excluded,
|
2004-04-03 00:30:39 +02:00
|
|
|
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-07-03 01:40:03 +02:00
|
|
|
/* DOCDOC */
|
|
|
|
static INLINE int router_hex_digest_matches(routerinfo_t *router,
|
|
|
|
const char *hexdigest)
|
|
|
|
{
|
|
|
|
char digest[DIGEST_LEN];
|
|
|
|
tor_assert(hexdigest);
|
|
|
|
if (hexdigest[0] == '$')
|
|
|
|
++hexdigest;
|
|
|
|
|
|
|
|
if (base16_decode(digest, DIGEST_LEN, hexdigest, HEX_DIGEST_LEN)<0)
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return (!memcmp(digest, router->identity_digest, DIGEST_LEN));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* DOCDOC */
|
|
|
|
int router_nickname_matches(routerinfo_t *router, const char *nickname)
|
|
|
|
{
|
|
|
|
if (nickname[0]!='$' && !strcasecmp(router->nickname, nickname))
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return router_hex_digest_matches(router, nickname);
|
|
|
|
}
|
|
|
|
|
2004-07-01 03:16:59 +02:00
|
|
|
/** Return the router in our routerlist whose (case-insensitive)
|
|
|
|
* nickname or (case-sensitive) hexadecimal key digest is
|
|
|
|
* <b>nickname</b>. Return NULL if no such router is known.
|
2004-05-04 20:17:45 +02:00
|
|
|
*/
|
2004-07-01 03:16:59 +02:00
|
|
|
routerinfo_t *router_get_by_nickname(const char *nickname)
|
2003-09-25 07:17:11 +02:00
|
|
|
{
|
2004-07-04 06:52:43 +02:00
|
|
|
int i, maybedigest;
|
2003-09-25 07:17:11 +02:00
|
|
|
routerinfo_t *router;
|
2004-07-01 03:16:59 +02:00
|
|
|
char digest[DIGEST_LEN];
|
2003-09-25 07:17:11 +02:00
|
|
|
|
2004-05-12 21:49:48 +02:00
|
|
|
tor_assert(nickname);
|
2004-06-02 22:00:57 +02:00
|
|
|
if (!routerlist)
|
|
|
|
return NULL;
|
2004-07-03 01:40:03 +02:00
|
|
|
if (nickname[0] == '$')
|
|
|
|
return router_get_by_hexdigest(nickname);
|
|
|
|
|
2004-07-01 03:16:59 +02:00
|
|
|
maybedigest = (strlen(nickname) == HEX_DIGEST_LEN) &&
|
|
|
|
(base16_decode(digest,DIGEST_LEN,nickname,HEX_DIGEST_LEN) == 0);
|
|
|
|
|
|
|
|
for(i=0;i<smartlist_len(routerlist->routers);i++) {
|
|
|
|
router = smartlist_get(routerlist->routers, i);
|
|
|
|
if (0 == strcasecmp(router->nickname, nickname) ||
|
|
|
|
(maybedigest && 0 == memcmp(digest, router->identity_digest,
|
|
|
|
DIGEST_LEN)))
|
|
|
|
return router;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return the router in our routerlist whose hexadecimal key digest
|
|
|
|
* is <b>hexdigest</b>. Return NULL if no such router is known. */
|
|
|
|
routerinfo_t *router_get_by_hexdigest(const char *hexdigest) {
|
|
|
|
char digest[DIGEST_LEN];
|
|
|
|
|
|
|
|
tor_assert(hexdigest);
|
|
|
|
if (!routerlist)
|
|
|
|
return NULL;
|
2004-07-03 01:40:03 +02:00
|
|
|
if (hexdigest[0]=='$')
|
|
|
|
++hexdigest;
|
2004-07-01 03:16:59 +02:00
|
|
|
if (strlen(hexdigest) != HEX_DIGEST_LEN ||
|
|
|
|
base16_decode(digest,DIGEST_LEN,hexdigest,HEX_DIGEST_LEN) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return router_get_by_digest(digest);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Return the router in our routerlist whose 20-byte key digest
|
|
|
|
* is <b>hexdigest</b>. Return NULL if no such router is known. */
|
|
|
|
routerinfo_t *router_get_by_digest(const char *digest) {
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
|
|
|
tor_assert(digest);
|
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-07-01 03:16:59 +02:00
|
|
|
if (0 == memcmp(router->identity_digest, digest, DIGEST_LEN))
|
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-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);
|
2004-05-20 04:42:50 +02:00
|
|
|
exit_policy_free(router->exit_policy);
|
2003-05-09 04:00:33 +02:00
|
|
|
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> */
|
2004-05-10 19:30:51 +02:00
|
|
|
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. */
|
2004-07-03 01:40:03 +02:00
|
|
|
void router_mark_as_down(const char *digest) {
|
2004-05-12 21:49:48 +02:00
|
|
|
routerinfo_t *router;
|
2004-07-03 01:40:03 +02:00
|
|
|
tor_assert(digest);
|
|
|
|
router = router_get_by_digest(digest);
|
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-17 22:31:01 +02:00
|
|
|
/** Add <b>router</b> to the routerlist, if we don't already have it. Replace
|
|
|
|
* older entries (if any) with the same name. Note: Callers should not hold
|
|
|
|
* their pointers to <b>router</b> after invoking this function; <b>router</b>
|
|
|
|
* will either be inserted into the routerlist or freed. Returns 0 if the
|
|
|
|
* router was added; -1 if it was not.
|
|
|
|
*/
|
|
|
|
int router_add_to_routerlist(routerinfo_t *router) {
|
|
|
|
int i;
|
|
|
|
routerinfo_t *r;
|
|
|
|
/* If we have a router with this name, and the identity key is the same,
|
|
|
|
* choose the newer one. If the identity key has changed, drop the router.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < smartlist_len(routerlist->routers); ++i) {
|
|
|
|
r = smartlist_get(routerlist->routers, i);
|
2004-07-03 01:40:03 +02:00
|
|
|
/* XXXX008 should just compare digests instead. */
|
2004-05-17 22:31:01 +02:00
|
|
|
if (!strcasecmp(router->nickname, r->nickname)) {
|
|
|
|
if (!crypto_pk_cmp_keys(router->identity_pkey, r->identity_pkey)) {
|
|
|
|
if (router->published_on > r->published_on) {
|
|
|
|
log_fn(LOG_DEBUG, "Replacing entry for router '%s'",
|
|
|
|
router->nickname);
|
|
|
|
/* Remember whether we trust this router as a dirserver. */
|
|
|
|
if (r->is_trusted_dir)
|
|
|
|
router->is_trusted_dir = 1;
|
2004-05-18 18:54:04 +02:00
|
|
|
/* If the address hasn't changed; no need to re-resolve. */
|
2004-05-17 22:31:01 +02:00
|
|
|
if (!strcasecmp(r->address, router->address))
|
|
|
|
router->addr = r->addr;
|
|
|
|
routerinfo_free(r);
|
|
|
|
smartlist_set(routerlist->routers, i, router);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
log_fn(LOG_DEBUG, "Skipping old entry for router '%s'",
|
|
|
|
router->nickname);
|
|
|
|
/* If we now trust 'router', then we trust the one in the routerlist
|
|
|
|
* too. */
|
|
|
|
if (router->is_trusted_dir)
|
|
|
|
r->is_trusted_dir = 1;
|
|
|
|
/* Update the is_running status to whatever we were told. */
|
|
|
|
r->is_running = router->is_running;
|
|
|
|
routerinfo_free(router);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
2004-07-03 01:40:03 +02:00
|
|
|
/* XXXX008 It's okay to have two keys for a nickname as soon as
|
|
|
|
* all the 007 clients are dead. */
|
2004-05-17 22:31:01 +02:00
|
|
|
log_fn(LOG_WARN, "Identity key mismatch for router '%s'",
|
|
|
|
router->nickname);
|
|
|
|
routerinfo_free(router);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* We haven't seen a router with this name before. Add it to the end of
|
|
|
|
* the list. */
|
|
|
|
smartlist_add(routerlist->routers, router);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-05-20 07:10:30 +02:00
|
|
|
/** Remove any routers from the routerlist that are more than ROUTER_MAX_AGE
|
|
|
|
* seconds old.
|
|
|
|
*
|
|
|
|
* (This function is just like dirserv_remove_old_servers. One day we should
|
|
|
|
* merge them.)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
routerlist_remove_old_routers(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
time_t cutoff;
|
|
|
|
routerinfo_t *router;
|
|
|
|
if (!routerlist)
|
|
|
|
return;
|
|
|
|
|
|
|
|
cutoff = time(NULL) - ROUTER_MAX_AGE;
|
|
|
|
for (i = 0; i < smartlist_len(routerlist->routers); ++i) {
|
|
|
|
router = smartlist_get(routerlist->routers, i);
|
2004-05-20 08:42:38 +02:00
|
|
|
if (router->published_on < cutoff &&
|
|
|
|
!router->dir_port) {
|
|
|
|
/* Too old. Remove it. But never remove dirservers! */
|
2004-05-20 07:10:30 +02:00
|
|
|
log_fn(LOG_INFO,"Forgetting obsolete routerinfo for node %s.", router->nickname);
|
|
|
|
routerinfo_free(router);
|
|
|
|
smartlist_del(routerlist->routers, i--);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-17 22:31:01 +02:00
|
|
|
/** Update the current router list with the one stored in
|
|
|
|
* <b>routerfile</b>. If <b>trusted</b> is true, then we'll use
|
|
|
|
* directory servers from the file. */
|
|
|
|
int router_load_routerlist_from_file(char *routerfile, int trusted)
|
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
|
|
|
|
2004-05-17 22:31:01 +02:00
|
|
|
if(router_load_routerlist_from_string(string, trusted) < 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-17 22:31:01 +02:00
|
|
|
/** Mark all directories in the routerlist as nontrusted. */
|
|
|
|
void routerlist_clear_trusted_directories(void)
|
|
|
|
{
|
|
|
|
if (!routerlist) return;
|
|
|
|
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, r,
|
|
|
|
r->is_trusted_dir = 0);
|
|
|
|
}
|
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/** Helper function: read routerinfo elements from s, and throw out the
|
2004-05-17 22:31:01 +02:00
|
|
|
* ones that don't parse and resolve. Add all remaining elements to the
|
|
|
|
* routerlist. If <b>trusted</b> is true, then we'll use
|
|
|
|
* directory servers from the string
|
|
|
|
*/
|
|
|
|
int router_load_routerlist_from_string(const char *s, int trusted)
|
2003-12-09 05:29:52 +01:00
|
|
|
{
|
2004-05-17 22:31:01 +02:00
|
|
|
routerlist_t *new_list=NULL;
|
|
|
|
|
|
|
|
if (router_parse_list_from_string(&s, &new_list, -1, NULL)) {
|
2003-12-09 05:29:52 +01:00
|
|
|
log(LOG_WARN, "Error parsing router file");
|
|
|
|
return -1;
|
|
|
|
}
|
2004-05-17 22:31:01 +02:00
|
|
|
if (trusted) {
|
|
|
|
SMARTLIST_FOREACH(new_list->routers, routerinfo_t *, r,
|
|
|
|
if (r->dir_port) r->is_trusted_dir = 1);
|
|
|
|
}
|
2004-05-17 22:41:40 +02:00
|
|
|
if (routerlist) {
|
|
|
|
SMARTLIST_FOREACH(new_list->routers, routerinfo_t *, r,
|
|
|
|
router_add_to_routerlist(r));
|
|
|
|
smartlist_clear(new_list->routers);
|
|
|
|
routerlist_free(new_list);
|
|
|
|
} else {
|
|
|
|
routerlist = new_list;
|
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
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-20 07:10:30 +02:00
|
|
|
/** Add to the current routerlist each router stored in the
|
2004-06-02 22:00:57 +02:00
|
|
|
* signed directory <b>s</b>. If pkey is provided, check the signature against
|
|
|
|
* pkey; else check against the pkey of the signing directory server. */
|
|
|
|
int router_load_routerlist_from_directory(const char *s,
|
|
|
|
crypto_pk_env_t *pkey)
|
2003-08-28 06:21:57 +02:00
|
|
|
{
|
2004-05-17 22:31:01 +02:00
|
|
|
routerlist_t *new_list = NULL;
|
2004-06-01 20:19:01 +02:00
|
|
|
check_software_version_against_directory(s, options.IgnoreVersion);
|
2004-05-17 22:31:01 +02:00
|
|
|
if (router_parse_routerlist_from_directory(s, &new_list, pkey)) {
|
2003-12-09 05:29:52 +01:00
|
|
|
log_fn(LOG_WARN, "Couldn't parse directory.");
|
|
|
|
return -1;
|
|
|
|
}
|
2004-05-17 22:41:40 +02:00
|
|
|
if (routerlist) {
|
|
|
|
SMARTLIST_FOREACH(new_list->routers, routerinfo_t *, r,
|
|
|
|
router_add_to_routerlist(r));
|
|
|
|
smartlist_clear(new_list->routers);
|
|
|
|
routerlist->published_on = new_list->published_on;
|
|
|
|
tor_free(routerlist->software_versions);
|
|
|
|
routerlist->software_versions = new_list->software_versions;
|
|
|
|
new_list->software_versions = NULL;
|
|
|
|
routerlist_free(new_list);
|
|
|
|
} else {
|
|
|
|
routerlist = new_list;
|
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
if (router_resolve_routerlist(routerlist)) {
|
|
|
|
log_fn(LOG_WARN, "Error resolving routerlist");
|
|
|
|
return -1;
|
|
|
|
}
|
2004-06-30 23:48:02 +02:00
|
|
|
if (options.AuthoritativeDir) {
|
|
|
|
/* Learn about the descriptors in the directory. */
|
2004-06-25 02:29:31 +02:00
|
|
|
dirserv_load_from_directory_string(s);
|
2004-06-30 23:48:02 +02:00
|
|
|
} else {
|
|
|
|
/* Remember the directory. */
|
|
|
|
dirserv_set_cached_directory(s, routerlist->published_on);
|
|
|
|
}
|
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-07-04 06:52:43 +02:00
|
|
|
if (tor_lookup_hostname(router->address, &router->addr) != 0
|
|
|
|
|| !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-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-05-17 22:31:01 +02:00
|
|
|
} else if (r->addr) {
|
|
|
|
/* already resolved. */
|
2004-05-17 22:41:40 +02:00
|
|
|
} else if (router_resolve(r)) {
|
2004-04-07 21:46:27 +02:00
|
|
|
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-06-25 02:29:31 +02:00
|
|
|
/* DODCDOC */
|
|
|
|
void running_routers_free(running_routers_t *rr)
|
|
|
|
{
|
|
|
|
tor_assert(rr);
|
|
|
|
if (rr->running_routers) {
|
|
|
|
SMARTLIST_FOREACH(rr->running_routers, char *, s, tor_free(s));
|
|
|
|
smartlist_free(rr->running_routers);
|
|
|
|
}
|
|
|
|
tor_free(rr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* DOCDOC*/
|
|
|
|
void routerlist_update_from_runningrouters(routerlist_t *list,
|
|
|
|
running_routers_t *rr)
|
|
|
|
{
|
|
|
|
int n_routers, n_names, i, j, running;
|
|
|
|
routerinfo_t *router;
|
|
|
|
const char *name;
|
2004-06-30 18:48:36 +02:00
|
|
|
if (!list)
|
2004-06-25 02:29:31 +02:00
|
|
|
return;
|
2004-06-30 18:48:36 +02:00
|
|
|
if (list->published_on >= rr->published_on)
|
2004-06-25 02:29:31 +02:00
|
|
|
return;
|
2004-06-30 18:48:36 +02:00
|
|
|
if (list->running_routers_updated_on >= rr->published_on)
|
2004-06-25 02:29:31 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
n_routers = smartlist_len(list->routers);
|
|
|
|
n_names = smartlist_len(rr->running_routers);
|
|
|
|
for (i=0; i<n_routers; ++i) {
|
|
|
|
running = 0;
|
|
|
|
router = smartlist_get(list->routers, i);
|
|
|
|
for (j=0; j<n_names; ++j) {
|
|
|
|
name = smartlist_get(rr->running_routers, j);
|
2004-07-03 01:40:03 +02:00
|
|
|
if (*name != '!') {
|
|
|
|
if (router_nickname_matches(router, name)) {
|
|
|
|
router->is_running = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else { /* *name == '!' */
|
|
|
|
if (router_nickname_matches(router, name)) {
|
|
|
|
router->is_running = 0;
|
|
|
|
break;
|
|
|
|
}
|
2004-06-25 02:29:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-06-30 18:48:36 +02:00
|
|
|
list->running_routers_updated_on = rr->published_on;
|
2004-06-25 02:29:31 +02:00
|
|
|
}
|
|
|
|
|
2003-04-07 04:12:02 +02:00
|
|
|
/*
|
|
|
|
Local Variables:
|
|
|
|
mode:c
|
|
|
|
indent-tabs-mode:nil
|
|
|
|
c-basic-offset:2
|
|
|
|
End:
|
|
|
|
*/
|