2004-11-07 02:33:06 +01:00
|
|
|
/* Copyright 2001 Matej Pfajfar.
|
|
|
|
* Copyright 2001-2004 Roger Dingledine.
|
2005-04-01 22:15:56 +02:00
|
|
|
* Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
|
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$ */
|
2004-11-29 23:25:31 +01:00
|
|
|
const char routerlist_c_id[] = "$Id$";
|
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
|
|
|
|
2004-05-09 18:47:25 +02:00
|
|
|
/**
|
|
|
|
* \file routerlist.c
|
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
|
|
|
|
2005-06-11 07:31:17 +02:00
|
|
|
#include "or.h"
|
|
|
|
|
2002-09-26 14:09:10 +02:00
|
|
|
/****************************************************************************/
|
|
|
|
|
2004-10-12 17:55:20 +02:00
|
|
|
static smartlist_t *trusted_dir_servers = NULL;
|
|
|
|
|
2002-09-24 12:43:57 +02:00
|
|
|
/* static function prototypes */
|
2004-07-20 08:44:16 +02:00
|
|
|
static routerinfo_t *
|
2005-06-21 01:04:13 +02:00
|
|
|
router_pick_directory_server_impl(int requireother, int fascistfirewall,
|
2004-11-29 22:01:34 +01:00
|
|
|
int for_runningrouters);
|
2004-10-12 17:55:20 +02:00
|
|
|
static trusted_dir_server_t *
|
|
|
|
router_pick_trusteddirserver_impl(int requireother, int fascistfirewall);
|
|
|
|
static void mark_all_trusteddirservers_up(void);
|
2005-06-21 01:04:13 +02:00
|
|
|
static int router_nickname_is_in_list(routerinfo_t *router, const char *list);
|
|
|
|
static int router_nickname_matches(routerinfo_t *router, const char *nickname);
|
2005-08-16 04:52:27 +02:00
|
|
|
static void router_normalize_routerlist(routerlist_t *rl);
|
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.)
|
2005-06-21 01:04:13 +02:00
|
|
|
****/
|
2004-05-04 20:17:45 +02:00
|
|
|
|
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-09-08 08:52:33 +02:00
|
|
|
/**
|
2005-06-21 01:04:13 +02:00
|
|
|
* Reload the most recent cached directory (if present).
|
2004-09-08 08:52:33 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
router_reload_router_list(void)
|
2004-09-08 08:52:33 +02:00
|
|
|
{
|
|
|
|
char filename[512];
|
2004-10-28 20:37:52 +02:00
|
|
|
int is_recent;
|
2004-11-14 14:35:39 +01:00
|
|
|
struct stat st;
|
2004-11-09 08:05:53 +01:00
|
|
|
char *s;
|
|
|
|
tor_assert(get_options()->DataDirectory);
|
|
|
|
|
|
|
|
tor_snprintf(filename,sizeof(filename),"%s/cached-directory",
|
|
|
|
get_options()->DataDirectory);
|
|
|
|
s = read_file_to_str(filename,0);
|
|
|
|
if (s) {
|
2004-11-15 10:22:01 +01:00
|
|
|
stat(filename, &st); /* if s is true, stat probably worked */
|
2004-11-09 08:05:53 +01:00
|
|
|
log_fn(LOG_INFO, "Loading cached directory from %s", filename);
|
|
|
|
is_recent = st.st_mtime > time(NULL) - 60*15;
|
2005-01-06 21:11:52 +01:00
|
|
|
if (router_load_routerlist_from_directory(s, NULL, is_recent, 1) < 0) {
|
2004-11-25 05:20:10 +01:00
|
|
|
log_fn(LOG_WARN, "Cached directory at '%s' was unparseable; ignoring.", filename);
|
2004-10-28 20:37:52 +02:00
|
|
|
}
|
2004-11-28 10:05:49 +01:00
|
|
|
if (routerlist &&
|
2005-01-13 21:22:38 +01:00
|
|
|
((routerlist->published_on > time(NULL) - MIN_ONION_KEY_LIFETIME/2)
|
2004-11-28 12:39:53 +01:00
|
|
|
|| is_recent)) {
|
2005-02-27 10:47:01 +01:00
|
|
|
directory_has_arrived(st.st_mtime, NULL); /* do things we've been waiting to do */
|
2004-09-08 08:52:33 +02:00
|
|
|
}
|
2004-11-09 08:05:53 +01:00
|
|
|
tor_free(s);
|
2004-09-08 08:52:33 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-10-15 21:04:38 +02:00
|
|
|
/* Set *<b>outp</b> to a smartlist containing a list of
|
|
|
|
* trusted_dir_server_t * for all known trusted dirservers. Callers
|
|
|
|
* must not modify the list or its contents.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
router_get_trusted_dir_servers(smartlist_t **outp)
|
2004-10-15 21:04:38 +02:00
|
|
|
{
|
|
|
|
if (!trusted_dir_servers)
|
|
|
|
trusted_dir_servers = smartlist_create();
|
|
|
|
|
|
|
|
*outp = trusted_dir_servers;
|
|
|
|
}
|
|
|
|
|
2004-07-20 08:44:16 +02:00
|
|
|
/** Try to find a running dirserver. If there are no running dirservers
|
2005-06-21 01:04:13 +02:00
|
|
|
* in our routerlist and <b>retry_if_no_servers</b> is non-zero,
|
|
|
|
* set all the authoritative ones as running again, and pick one;
|
|
|
|
* if there are then no dirservers at all in our routerlist,
|
|
|
|
* reload the routerlist and try one last time. If for_runningrouters is
|
2004-11-29 22:01:34 +01:00
|
|
|
* true, then only pick a dirserver that can answer runningrouters queries
|
|
|
|
* (that is, a trusted dirserver, or one running 0.0.9rc5-cvs or later).
|
2005-06-21 01:04:13 +02:00
|
|
|
* Other args are as in router_pick_directory_server_impl().
|
2004-11-29 22:01:34 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
routerinfo_t *
|
2005-06-21 01:04:13 +02:00
|
|
|
router_pick_directory_server(int requireother,
|
2005-06-11 20:52:12 +02:00
|
|
|
int fascistfirewall,
|
|
|
|
int for_runningrouters,
|
|
|
|
int retry_if_no_servers)
|
|
|
|
{
|
2004-02-26 23:56:36 +01:00
|
|
|
routerinfo_t *choice;
|
|
|
|
|
2004-10-14 03:44:32 +02:00
|
|
|
if (!routerlist)
|
2004-10-14 04:29:03 +02:00
|
|
|
return NULL;
|
2004-10-14 03:44:32 +02:00
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
choice = router_pick_directory_server_impl(requireother, fascistfirewall,
|
2004-11-29 22:01:34 +01:00
|
|
|
for_runningrouters);
|
2005-01-03 21:51:24 +01:00
|
|
|
if (choice || !retry_if_no_servers)
|
2004-07-20 08:44:16 +02:00
|
|
|
return choice;
|
|
|
|
|
2004-10-14 03:44:32 +02:00
|
|
|
log_fn(LOG_INFO,"No reachable router entries for dirservers. Trying them all again.");
|
2004-08-18 23:13:58 +02:00
|
|
|
/* mark all authdirservers as up again */
|
2004-10-12 17:55:20 +02:00
|
|
|
mark_all_trusteddirservers_up();
|
2004-07-20 08:44:16 +02:00
|
|
|
/* try again */
|
2005-06-21 01:04:13 +02:00
|
|
|
choice = router_pick_directory_server_impl(requireother, fascistfirewall,
|
2004-11-29 22:01:34 +01:00
|
|
|
for_runningrouters);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (choice)
|
2004-07-20 08:44:16 +02:00
|
|
|
return choice;
|
|
|
|
|
2004-10-14 03:44:32 +02:00
|
|
|
log_fn(LOG_INFO,"Still no %s router entries. Reloading and trying again.",
|
2005-08-08 23:58:48 +02:00
|
|
|
firewall_is_fascist() ? "reachable" : "known");
|
2004-07-20 08:44:16 +02:00
|
|
|
has_fetched_directory=0; /* reset it */
|
2004-11-28 10:05:49 +01:00
|
|
|
if (router_reload_router_list()) {
|
2004-09-08 08:52:33 +02:00
|
|
|
return NULL;
|
2004-02-26 23:56:36 +01:00
|
|
|
}
|
2004-07-20 08:44:16 +02:00
|
|
|
/* give it one last try */
|
2005-06-21 01:04:13 +02:00
|
|
|
choice = router_pick_directory_server_impl(requireother, 0,
|
2004-11-29 22:01:34 +01:00
|
|
|
for_runningrouters);
|
2004-02-26 23:56:36 +01:00
|
|
|
return choice;
|
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** Try to find a running trusted dirserver. If there are no running
|
|
|
|
* trusted dirservers and <b>retry_if_no_servers</b> is non-zero,
|
|
|
|
* set them all as running again, and try again.
|
|
|
|
* Other args are as in router_pick_trusteddirserver_impl().
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
trusted_dir_server_t *
|
2005-06-21 01:04:13 +02:00
|
|
|
router_pick_trusteddirserver(int requireother,
|
2005-06-11 20:52:12 +02:00
|
|
|
int fascistfirewall,
|
|
|
|
int retry_if_no_servers)
|
|
|
|
{
|
2004-10-12 17:55:20 +02:00
|
|
|
trusted_dir_server_t *choice;
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
choice = router_pick_trusteddirserver_impl(requireother, fascistfirewall);
|
2005-01-03 21:51:24 +01:00
|
|
|
if (choice || !retry_if_no_servers)
|
2004-10-12 17:55:20 +02:00
|
|
|
return choice;
|
|
|
|
|
|
|
|
log_fn(LOG_INFO,"No trusted dirservers are reachable. Trying them all again.");
|
|
|
|
mark_all_trusteddirservers_up();
|
2005-06-21 01:04:13 +02:00
|
|
|
return router_pick_trusteddirserver_impl(requireother, fascistfirewall);
|
2004-10-12 17:55:20 +02:00
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** Pick a random running verified directory server/mirror from our
|
|
|
|
* routerlist.
|
|
|
|
* If <b>fascistfirewall</b> and we're not using a proxy,
|
|
|
|
* make sure the port we pick is allowed by options-\>firewallports.
|
|
|
|
* If <b>requireother</b>, it cannot be us.
|
|
|
|
* If <b>for_runningrouters</b>, make sure we pick a dirserver that
|
|
|
|
* can answer queries for running-routers (this option will become obsolete
|
|
|
|
* once 0.0.9-rc5 is dead).
|
2004-07-20 08:44:16 +02:00
|
|
|
*/
|
|
|
|
static routerinfo_t *
|
2005-06-21 01:04:13 +02:00
|
|
|
router_pick_directory_server_impl(int requireother, int fascistfirewall,
|
2004-11-29 22:01:34 +01:00
|
|
|
int for_runningrouters)
|
2004-07-20 08:44:16 +02:00
|
|
|
{
|
2003-12-13 02:43:21 +01:00
|
|
|
int i;
|
2004-07-12 22:39:40 +02:00
|
|
|
routerinfo_t *router;
|
2003-12-13 02:43:21 +01:00
|
|
|
smartlist_t *sl;
|
2003-12-03 11:39:27 +01:00
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!routerlist)
|
2002-09-26 14:09:10 +02:00
|
|
|
return NULL;
|
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (get_options()->HttpProxy)
|
2004-10-15 06:57:36 +02:00
|
|
|
fascistfirewall = 0;
|
|
|
|
|
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();
|
2005-04-01 10:42:26 +02:00
|
|
|
for (i=0;i < smartlist_len(routerlist->routers); i++) {
|
2004-04-07 21:46:27 +02:00
|
|
|
router = smartlist_get(routerlist->routers, i);
|
2005-02-10 08:00:23 +01:00
|
|
|
if (!router->is_running || !router->dir_port || !router->is_verified)
|
2004-07-20 08:44:16 +02:00
|
|
|
continue;
|
2005-06-21 01:04:13 +02:00
|
|
|
if (requireother && router_is_me(router))
|
2004-07-20 08:44:16 +02:00
|
|
|
continue;
|
2004-11-28 10:05:49 +01:00
|
|
|
if (fascistfirewall) {
|
2005-08-08 23:58:48 +02:00
|
|
|
if (!fascist_firewall_allows_address(router->addr, router->dir_port))
|
2004-08-16 22:47:00 +02:00
|
|
|
continue;
|
|
|
|
}
|
2004-11-29 22:01:34 +01:00
|
|
|
/* before 0.0.9rc5-cvs, only trusted dirservers served status info. */
|
|
|
|
if (for_runningrouters &&
|
|
|
|
!(tor_version_as_new_as(router->platform,"0.0.9rc5-cvs") ||
|
|
|
|
router_digest_is_trusted_dir(router->identity_digest)))
|
|
|
|
continue;
|
2004-07-20 08:44:16 +02: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);
|
2004-07-20 08:44:16 +02:00
|
|
|
return router;
|
|
|
|
}
|
2003-11-10 09:06:55 +01:00
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** Choose randomly from among the trusted dirservers that are up.
|
|
|
|
* If <b>fascistfirewall</b> and we're not using a proxy,
|
|
|
|
* make sure the port we pick is allowed by options-\>firewallports.
|
|
|
|
* If <b>requireother</b>, it cannot be us.
|
|
|
|
*/
|
2004-10-12 17:55:20 +02:00
|
|
|
static trusted_dir_server_t *
|
|
|
|
router_pick_trusteddirserver_impl(int requireother, int fascistfirewall)
|
|
|
|
{
|
|
|
|
smartlist_t *sl;
|
|
|
|
routerinfo_t *me;
|
|
|
|
trusted_dir_server_t *ds;
|
|
|
|
sl = smartlist_create();
|
|
|
|
me = router_get_my_routerinfo();
|
2004-07-20 08:44:16 +02:00
|
|
|
|
2004-10-14 04:29:03 +02:00
|
|
|
if (!trusted_dir_servers)
|
|
|
|
return NULL;
|
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (get_options()->HttpProxy)
|
2004-10-15 06:57:36 +02:00
|
|
|
fascistfirewall = 0;
|
|
|
|
|
2004-10-12 17:55:20 +02:00
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
|
|
|
|
{
|
|
|
|
if (!d->is_running) continue;
|
|
|
|
if (requireother && me &&
|
|
|
|
!memcmp(me->identity_digest, d->digest, DIGEST_LEN))
|
|
|
|
continue;
|
|
|
|
if (fascistfirewall) {
|
2005-08-08 23:58:48 +02:00
|
|
|
if (!fascist_firewall_allows_address(d->addr, d->dir_port))
|
2004-10-12 17:55:20 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
smartlist_add(sl, d);
|
|
|
|
});
|
2004-05-04 20:17:45 +02:00
|
|
|
|
2004-10-12 17:55:20 +02:00
|
|
|
ds = smartlist_choose(sl);
|
|
|
|
smartlist_free(sl);
|
|
|
|
return ds;
|
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** Go through and mark the authoritative dirservers as up. */
|
2005-06-11 20:52:12 +02:00
|
|
|
static void
|
|
|
|
mark_all_trusteddirservers_up(void)
|
|
|
|
{
|
2004-11-28 10:05:49 +01:00
|
|
|
if (routerlist) {
|
2004-10-12 17:55:20 +02:00
|
|
|
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
|
2005-07-15 20:56:59 +02:00
|
|
|
if (router_digest_is_trusted_dir(router->identity_digest) &&
|
|
|
|
router->dir_port > 0) {
|
2004-10-19 20:19:59 +02:00
|
|
|
router->is_running = 1;
|
|
|
|
router->status_set_at = time(NULL);
|
|
|
|
});
|
2004-10-12 17:55:20 +02:00
|
|
|
}
|
|
|
|
if (trusted_dir_servers) {
|
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, dir,
|
|
|
|
dir->is_running = 1);
|
2003-12-03 11:39:27 +01:00
|
|
|
}
|
2004-07-12 22:39:40 +02:00
|
|
|
}
|
|
|
|
|
2005-05-17 19:01:36 +02:00
|
|
|
/** Return 0 if \\exists an authoritative dirserver that's currently
|
2004-07-12 22:39:40 +02:00
|
|
|
* thought to be running, else return 1.
|
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
all_trusted_directory_servers_down(void)
|
|
|
|
{
|
2004-10-12 17:55:20 +02:00
|
|
|
if (!trusted_dir_servers)
|
|
|
|
return 1;
|
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, dir,
|
|
|
|
if (dir->is_running) return 0);
|
2004-07-12 22:39:40 +02:00
|
|
|
return 1;
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
|
|
|
|
2004-10-15 03:58:11 +02:00
|
|
|
/** Add all the family of <b>router</b> to the smartlist <b>sl</b>.
|
2005-06-21 01:04:13 +02:00
|
|
|
* This is used to make sure we don't pick siblings in a single path.
|
2004-09-10 23:40:29 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
routerlist_add_family(smartlist_t *sl, routerinfo_t *router)
|
|
|
|
{
|
2004-10-15 03:58:11 +02:00
|
|
|
routerinfo_t *r;
|
2005-07-22 23:12:10 +02:00
|
|
|
config_line_t *cl;
|
2004-09-10 23:40:29 +02:00
|
|
|
|
2004-10-15 03:58:11 +02:00
|
|
|
if (!router->declared_family)
|
|
|
|
return;
|
2004-10-15 22:52:09 +02:00
|
|
|
|
2004-10-15 05:55:53 +02:00
|
|
|
/* Add every r such that router declares familyness with r, and r
|
|
|
|
* declares familyhood with router. */
|
2004-10-15 03:58:11 +02:00
|
|
|
SMARTLIST_FOREACH(router->declared_family, const char *, n,
|
|
|
|
{
|
|
|
|
if (!(r = router_get_by_nickname(n)))
|
|
|
|
continue;
|
|
|
|
if (!r->declared_family)
|
|
|
|
continue;
|
|
|
|
SMARTLIST_FOREACH(r->declared_family, const char *, n2,
|
|
|
|
{
|
|
|
|
if (router_nickname_matches(router, n2))
|
|
|
|
smartlist_add(sl, r);
|
|
|
|
});
|
|
|
|
});
|
2004-10-15 22:52:09 +02:00
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/* If the user declared any families locally, honor those too. */
|
2004-11-06 06:18:11 +01:00
|
|
|
for (cl = get_options()->NodeFamilies; cl; cl = cl->next) {
|
2004-10-15 22:52:09 +02:00
|
|
|
if (router_nickname_is_in_list(router, cl->value)) {
|
|
|
|
add_nickname_list_to_smartlist(sl, cl->value, 0);
|
|
|
|
}
|
|
|
|
}
|
2004-09-10 23:40:29 +02:00
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** List of strings for nicknames we've already warned about and that are
|
|
|
|
* still unknown / unavailable. */
|
2005-04-03 07:53:34 +02:00
|
|
|
static smartlist_t *warned_nicknames = NULL;
|
|
|
|
|
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
|
|
|
*/
|
2004-08-18 13:20:15 +02:00
|
|
|
void
|
|
|
|
add_nickname_list_to_smartlist(smartlist_t *sl, const char *list, int warn_if_down)
|
|
|
|
{
|
2004-04-03 00:23:15 +02:00
|
|
|
routerinfo_t *router;
|
2004-09-02 20:39:59 +02:00
|
|
|
smartlist_t *nickname_list;
|
2004-04-03 00:23:15 +02:00
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!list)
|
2004-11-03 11:08:44 +01:00
|
|
|
return; /* nothing to do */
|
2004-04-25 22:37:37 +02:00
|
|
|
tor_assert(sl);
|
2004-04-03 01:38:26 +02:00
|
|
|
|
2004-09-02 20:39:59 +02:00
|
|
|
nickname_list = smartlist_create();
|
2005-04-03 07:53:34 +02:00
|
|
|
if (!warned_nicknames)
|
|
|
|
warned_nicknames = smartlist_create();
|
2004-04-03 00:23:15 +02:00
|
|
|
|
2004-09-02 20:39:59 +02:00
|
|
|
smartlist_split_string(nickname_list, list, ",",
|
|
|
|
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
|
|
|
|
|
|
|
SMARTLIST_FOREACH(nickname_list, const char *, nick, {
|
2005-04-03 07:53:34 +02:00
|
|
|
int warned;
|
2005-01-03 18:53:20 +01:00
|
|
|
if (!is_legal_nickname_or_hexdigest(nick)) {
|
|
|
|
log_fn(LOG_WARN,"Nickname %s is misformed; skipping", nick);
|
2004-07-22 23:36:03 +02:00
|
|
|
continue;
|
|
|
|
}
|
2004-04-03 00:23:15 +02:00
|
|
|
router = router_get_by_nickname(nick);
|
2005-04-03 07:53:34 +02:00
|
|
|
warned = smartlist_string_isin(warned_nicknames, nick);
|
2004-04-03 00:23:15 +02:00
|
|
|
if (router) {
|
2005-04-03 07:53:34 +02:00
|
|
|
if (router->is_running) {
|
2004-04-03 00:23:15 +02:00
|
|
|
smartlist_add(sl,router);
|
2005-04-03 07:53:34 +02:00
|
|
|
if (warned)
|
|
|
|
smartlist_string_remove(warned_nicknames, nick);
|
|
|
|
} else {
|
|
|
|
if (!warned) {
|
|
|
|
log_fn(warn_if_down ? LOG_WARN : LOG_DEBUG,
|
|
|
|
"Nickname list includes '%s' which is known but down.",nick);
|
|
|
|
smartlist_add(warned_nicknames, tor_strdup(nick));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!warned) {
|
|
|
|
log_fn(has_fetched_directory ? LOG_WARN : LOG_INFO,
|
|
|
|
"Nickname list includes '%s' which isn't a known router.",nick);
|
|
|
|
smartlist_add(warned_nicknames, tor_strdup(nick));
|
|
|
|
}
|
|
|
|
}
|
2004-09-02 20:39:59 +02:00
|
|
|
});
|
|
|
|
SMARTLIST_FOREACH(nickname_list, char *, nick, tor_free(nick));
|
|
|
|
smartlist_free(nickname_list);
|
2004-04-03 00:23:15 +02:00
|
|
|
}
|
|
|
|
|
2004-10-15 22:52:09 +02:00
|
|
|
/** Return 1 iff any member of the comma-separated list <b>list</b> is an
|
|
|
|
* acceptable nickname or hexdigest for <b>router</b>. Else return 0.
|
|
|
|
*/
|
2005-06-21 01:04:13 +02:00
|
|
|
static int
|
2004-10-15 22:52:09 +02:00
|
|
|
router_nickname_is_in_list(routerinfo_t *router, const char *list)
|
|
|
|
{
|
|
|
|
smartlist_t *nickname_list;
|
|
|
|
int v = 0;
|
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!list)
|
2004-11-03 11:08:44 +01:00
|
|
|
return 0; /* definitely not */
|
2004-10-15 22:52:09 +02:00
|
|
|
tor_assert(router);
|
|
|
|
|
|
|
|
nickname_list = smartlist_create();
|
|
|
|
smartlist_split_string(nickname_list, list, ",",
|
|
|
|
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
|
2004-10-16 10:39:56 +02:00
|
|
|
SMARTLIST_FOREACH(nickname_list, const char *, cp,
|
2004-10-15 22:52:09 +02:00
|
|
|
if (router_nickname_matches(router, cp)) {v=1;break;});
|
2004-10-16 10:39:56 +02:00
|
|
|
SMARTLIST_FOREACH(nickname_list, char *, cp, tor_free(cp));
|
|
|
|
smartlist_free(nickname_list);
|
2004-10-15 22:52:09 +02:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
*/
|
2004-08-17 08:27:32 +02:00
|
|
|
static void
|
2004-08-20 23:34:36 +02:00
|
|
|
router_add_running_routers_to_smartlist(smartlist_t *sl, int allow_unverified,
|
2005-01-12 05:58:23 +01:00
|
|
|
int need_uptime, int need_capacity)
|
2004-08-17 08:27:32 +02:00
|
|
|
{
|
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
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!routerlist)
|
2003-12-13 08:01:46 +01:00
|
|
|
return;
|
2003-12-03 11:28:51 +01:00
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
for (i=0;i<smartlist_len(routerlist->routers);i++) {
|
2004-04-07 21:46:27 +02:00
|
|
|
router = smartlist_get(routerlist->routers, i);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (router->is_running &&
|
2004-11-28 12:39:53 +01:00
|
|
|
(router->is_verified ||
|
|
|
|
(allow_unverified &&
|
2005-01-12 05:58:23 +01:00
|
|
|
!router_is_unreliable(router, need_uptime, need_capacity)))) {
|
2004-08-20 23:34:36 +02:00
|
|
|
/* If it's running, and either it's verified or we're ok picking
|
|
|
|
* unverified routers and this one is suitable.
|
|
|
|
*/
|
2004-08-18 11:07:11 +02:00
|
|
|
smartlist_add(sl, router);
|
2004-08-08 12:32:36 +02:00
|
|
|
}
|
2003-12-13 08:01:46 +01:00
|
|
|
}
|
2003-12-03 11:28:51 +01:00
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** Look through the routerlist until we find a router that has my key.
|
|
|
|
Return it. */
|
2004-08-18 12:32:50 +02:00
|
|
|
routerinfo_t *
|
2005-06-11 20:52:12 +02:00
|
|
|
routerlist_find_my_routerinfo(void)
|
|
|
|
{
|
2004-08-18 12:32:50 +02:00
|
|
|
routerinfo_t *router;
|
|
|
|
int i;
|
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!routerlist)
|
2004-08-18 12:32:50 +02:00
|
|
|
return NULL;
|
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
for (i=0;i<smartlist_len(routerlist->routers);i++) {
|
2004-08-18 12:32:50 +02:00
|
|
|
router = smartlist_get(routerlist->routers, i);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (router_is_me(router))
|
2004-08-18 12:32:50 +02:00
|
|
|
return router;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-08-15 05:25:40 +02:00
|
|
|
/** Find a router that's up, that has this IP address, and
|
|
|
|
* that allows exit to this address:port, or return NULL if there
|
|
|
|
* isn't a good one.
|
|
|
|
*/
|
|
|
|
routerinfo_t *
|
|
|
|
router_find_exact_exit_enclave(const char *address, uint16_t port) {
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
uint32_t addr;
|
|
|
|
struct in_addr in;
|
|
|
|
|
|
|
|
if (!tor_inet_aton(address, &in))
|
|
|
|
return NULL; /* it's not an IP already */
|
|
|
|
addr = ntohl(in.s_addr);
|
|
|
|
|
|
|
|
for (i=0;i < smartlist_len(routerlist->routers); i++) {
|
|
|
|
router = smartlist_get(routerlist->routers, i);
|
|
|
|
log_fn(LOG_DEBUG,"Considering %s: %d, %u==%u, %d.",
|
|
|
|
router->nickname,
|
|
|
|
router->is_running,
|
|
|
|
router->addr, addr,
|
|
|
|
router_compare_addr_to_addr_policy(addr, port, router->exit_policy));
|
|
|
|
if (router->is_running &&
|
|
|
|
router->addr == addr &&
|
|
|
|
router_compare_addr_to_addr_policy(addr, port, router->exit_policy) ==
|
|
|
|
ADDR_POLICY_ACCEPTED)
|
|
|
|
return router;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** Return 1 if <b>router</b> is not suitable for these parameters, else 0.
|
|
|
|
* If <b>need_uptime</b> is non-zero, we require a minimum uptime.
|
|
|
|
* If <b>need_capacity</b> is non-zero, we require a minimum advertised
|
|
|
|
* bandwidth.
|
|
|
|
*/
|
2004-08-20 23:34:36 +02:00
|
|
|
int
|
2005-01-12 05:58:23 +01:00
|
|
|
router_is_unreliable(routerinfo_t *router, int need_uptime, int need_capacity)
|
2004-08-20 23:34:36 +02:00
|
|
|
{
|
2004-11-28 10:05:49 +01:00
|
|
|
if (need_uptime && router->uptime < ROUTER_REQUIRED_MIN_UPTIME)
|
2004-08-20 23:34:36 +02:00
|
|
|
return 1;
|
2005-01-12 05:58:23 +01:00
|
|
|
if (need_capacity && router->bandwidthcapacity < ROUTER_REQUIRED_MIN_BANDWIDTH)
|
2004-08-20 23:34:36 +02:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2004-08-15 10:15:12 +02:00
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** Remove from routerlist <b>sl</b> all routers who have a low uptime. */
|
2004-08-15 10:15:12 +02:00
|
|
|
static void
|
|
|
|
routerlist_sl_remove_unreliable_routers(smartlist_t *sl)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
|
|
|
for (i = 0; i < smartlist_len(sl); ++i) {
|
|
|
|
router = smartlist_get(sl, i);
|
2005-01-12 05:58:23 +01:00
|
|
|
if (router_is_unreliable(router, 1, 0)) {
|
2005-08-12 02:34:50 +02:00
|
|
|
// log(LOG_DEBUG, "Router '%s' has insufficient uptime; deleting.",
|
|
|
|
// router->nickname);
|
2004-08-15 10:15:12 +02:00
|
|
|
smartlist_del(sl, i--);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
#define MAX_BELIEVABLE_BANDWIDTH 2000000 /* 2 MB/sec */
|
|
|
|
|
|
|
|
/** Choose a random element of router list <b>sl</b>, weighted by
|
|
|
|
* the advertised bandwidth of each router.
|
|
|
|
*/
|
2004-08-18 08:10:12 +02:00
|
|
|
routerinfo_t *
|
2004-08-15 10:15:12 +02:00
|
|
|
routerlist_sl_choose_by_bandwidth(smartlist_t *sl)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
smartlist_t *bandwidths;
|
|
|
|
uint32_t this_bw, tmp, total_bw=0, rand_bw;
|
|
|
|
uint32_t *p;
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/* First count the total bandwidth weight, and make a smartlist
|
|
|
|
* of each value. */
|
2004-08-15 10:15:12 +02:00
|
|
|
bandwidths = smartlist_create();
|
|
|
|
for (i = 0; i < smartlist_len(sl); ++i) {
|
|
|
|
router = smartlist_get(sl, i);
|
2004-10-17 23:51:20 +02:00
|
|
|
this_bw = (router->bandwidthcapacity < router->bandwidthrate) ?
|
|
|
|
router->bandwidthcapacity : router->bandwidthrate;
|
2005-06-21 01:04:13 +02:00
|
|
|
/* if they claim something huge, don't believe it */
|
|
|
|
if (this_bw > MAX_BELIEVABLE_BANDWIDTH)
|
|
|
|
this_bw = MAX_BELIEVABLE_BANDWIDTH;
|
2004-08-15 10:15:12 +02:00
|
|
|
p = tor_malloc(sizeof(uint32_t));
|
|
|
|
*p = this_bw;
|
|
|
|
smartlist_add(bandwidths, p);
|
|
|
|
total_bw += this_bw;
|
|
|
|
}
|
2004-12-07 09:51:10 +01:00
|
|
|
if (!total_bw) {
|
|
|
|
SMARTLIST_FOREACH(bandwidths, uint32_t*, p, tor_free(p));
|
|
|
|
smartlist_free(bandwidths);
|
2004-11-20 13:41:05 +01:00
|
|
|
return smartlist_choose(sl);
|
2004-12-07 09:51:10 +01:00
|
|
|
}
|
2005-06-21 01:04:13 +02:00
|
|
|
/* Second, choose a random value from the bandwidth weights. */
|
2004-08-15 10:15:12 +02:00
|
|
|
rand_bw = crypto_pseudo_rand_int(total_bw);
|
2005-06-21 01:04:13 +02:00
|
|
|
/* Last, count through sl until we get to the element we picked */
|
2004-08-15 10:15:12 +02:00
|
|
|
tmp = 0;
|
2004-11-28 10:05:49 +01:00
|
|
|
for (i=0; ; i++) {
|
2004-08-15 10:15:12 +02:00
|
|
|
tor_assert(i < smartlist_len(sl));
|
|
|
|
p = smartlist_get(bandwidths, i);
|
|
|
|
tmp += *p;
|
2004-11-28 10:05:49 +01:00
|
|
|
if (tmp >= rand_bw)
|
2004-08-15 10:15:12 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
SMARTLIST_FOREACH(bandwidths, uint32_t*, p, tor_free(p));
|
|
|
|
smartlist_free(bandwidths);
|
2005-06-21 01:04:13 +02:00
|
|
|
return (routerinfo_t *)smartlist_get(sl, i);
|
2004-08-15 10:15:12 +02:00
|
|
|
}
|
|
|
|
|
2004-05-20 21:12:28 +02:00
|
|
|
/** Return a random running router from the routerlist. If any node
|
2004-08-15 22:14:44 +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. If <b>strict</b> is true, never pick any node besides
|
|
|
|
* those in <b>preferred</b>.
|
2005-06-21 01:04:13 +02:00
|
|
|
* If <b>need_uptime</b> is non-zero, don't return a router with less
|
|
|
|
* than a minimum uptime.
|
|
|
|
* If <b>need_capacity</b> is non-zero, weight your choice by the
|
|
|
|
* advertised capacity of each router.
|
2004-04-03 00:30:39 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
routerinfo_t *
|
|
|
|
router_choose_random_node(const char *preferred,
|
|
|
|
const char *excluded,
|
|
|
|
smartlist_t *excludedsmartlist,
|
|
|
|
int need_uptime, int need_capacity,
|
|
|
|
int allow_unverified, int strict)
|
2004-04-03 00:23:15 +02:00
|
|
|
{
|
|
|
|
smartlist_t *sl, *excludednodes;
|
|
|
|
routerinfo_t *choice;
|
|
|
|
|
|
|
|
excludednodes = smartlist_create();
|
2004-08-18 13:20:15 +02:00
|
|
|
add_nickname_list_to_smartlist(excludednodes,excluded,0);
|
2004-04-03 00:23:15 +02:00
|
|
|
|
2005-04-06 08:17:35 +02:00
|
|
|
/* Try the preferred nodes first. Ignore need_uptime and need_capacity,
|
|
|
|
* since the user explicitly asked for these nodes. */
|
2004-04-03 00:23:15 +02:00
|
|
|
sl = smartlist_create();
|
2004-08-18 13:20:15 +02:00
|
|
|
add_nickname_list_to_smartlist(sl,preferred,1);
|
2004-04-03 00:23:15 +02:00
|
|
|
smartlist_subtract(sl,excludednodes);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (excludedsmartlist)
|
2004-04-03 00:30:39 +02:00
|
|
|
smartlist_subtract(sl,excludedsmartlist);
|
2005-04-06 08:17:35 +02:00
|
|
|
choice = smartlist_choose(sl);
|
2004-04-03 00:23:15 +02:00
|
|
|
smartlist_free(sl);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!choice && !strict) {
|
2005-04-06 08:17:35 +02:00
|
|
|
/* Then give up on our preferred choices: any node
|
|
|
|
* will do that has the required attributes. */
|
2004-04-03 00:23:15 +02:00
|
|
|
sl = smartlist_create();
|
2004-08-20 23:34:36 +02:00
|
|
|
router_add_running_routers_to_smartlist(sl, allow_unverified,
|
2005-01-12 05:58:23 +01:00
|
|
|
need_uptime, need_capacity);
|
2004-04-03 00:23:15 +02:00
|
|
|
smartlist_subtract(sl,excludednodes);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (excludedsmartlist)
|
2004-04-03 00:30:39 +02:00
|
|
|
smartlist_subtract(sl,excludedsmartlist);
|
2005-01-12 05:58:23 +01:00
|
|
|
if (need_uptime)
|
2004-08-15 10:15:12 +02:00
|
|
|
routerlist_sl_remove_unreliable_routers(sl);
|
2005-01-12 05:58:23 +01:00
|
|
|
if (need_capacity)
|
2004-08-15 10:15:12 +02:00
|
|
|
choice = routerlist_sl_choose_by_bandwidth(sl);
|
2004-08-18 09:53:43 +02:00
|
|
|
else
|
|
|
|
choice = smartlist_choose(sl);
|
2004-04-03 00:23:15 +02:00
|
|
|
smartlist_free(sl);
|
|
|
|
}
|
|
|
|
smartlist_free(excludednodes);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!choice)
|
2004-04-03 00:23:15 +02:00
|
|
|
log_fn(LOG_WARN,"No available nodes when trying to choose node. Failing.");
|
|
|
|
return choice;
|
|
|
|
}
|
|
|
|
|
2004-07-17 00:23:18 +02:00
|
|
|
/** Return true iff the digest of <b>router</b>'s identity key,
|
|
|
|
* encoded in hexadecimal, matches <b>hexdigest</b> (which is
|
|
|
|
* optionally prefixed with a single dollar sign). Return false if
|
|
|
|
* <b>hexdigest</b> is malformed, or it doesn't match. */
|
2005-06-11 20:52:12 +02:00
|
|
|
static INLINE int
|
|
|
|
router_hex_digest_matches(routerinfo_t *router, const char *hexdigest)
|
2004-07-03 01:40:03 +02:00
|
|
|
{
|
|
|
|
char digest[DIGEST_LEN];
|
|
|
|
tor_assert(hexdigest);
|
|
|
|
if (hexdigest[0] == '$')
|
|
|
|
++hexdigest;
|
|
|
|
|
2004-07-17 00:23:18 +02:00
|
|
|
if (strlen(hexdigest) != HEX_DIGEST_LEN ||
|
|
|
|
base16_decode(digest, DIGEST_LEN, hexdigest, HEX_DIGEST_LEN)<0)
|
2004-07-03 01:40:03 +02:00
|
|
|
return 0;
|
2005-06-21 01:04:13 +02:00
|
|
|
return (!memcmp(digest, router->identity_digest, DIGEST_LEN));
|
2004-07-03 01:40:03 +02:00
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** Return true if <b>router</b>'s nickname matches <b>nickname</b>
|
2004-07-17 00:23:18 +02:00
|
|
|
* (case-insensitive), or if <b>router's</b> identity key digest
|
|
|
|
* matches a hexadecimal value stored in <b>nickname</b>. Return
|
2005-06-21 01:04:13 +02:00
|
|
|
* false otherwise. */
|
|
|
|
static int
|
2005-06-11 20:52:12 +02:00
|
|
|
router_nickname_matches(routerinfo_t *router, const char *nickname)
|
2004-07-03 01:40:03 +02:00
|
|
|
{
|
|
|
|
if (nickname[0]!='$' && !strcasecmp(router->nickname, nickname))
|
|
|
|
return 1;
|
2005-06-21 01:04:13 +02:00
|
|
|
return router_hex_digest_matches(router, nickname);
|
2004-07-03 01:40:03 +02:00
|
|
|
}
|
|
|
|
|
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
|
|
|
*/
|
2005-06-11 20:52:12 +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);
|
2005-02-27 08:23:42 +01:00
|
|
|
if (server_mode(get_options()) &&
|
|
|
|
!strcasecmp(nickname, get_options()->Nickname))
|
|
|
|
return router_get_my_routerinfo();
|
2004-07-03 01:40:03 +02:00
|
|
|
|
2004-07-01 03:16:59 +02:00
|
|
|
maybedigest = (strlen(nickname) == HEX_DIGEST_LEN) &&
|
|
|
|
(base16_decode(digest,DIGEST_LEN,nickname,HEX_DIGEST_LEN) == 0);
|
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
for (i=0;i<smartlist_len(routerlist->routers);i++) {
|
2004-07-01 03:16:59 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2004-07-20 22:09:59 +02:00
|
|
|
/** Return true iff <b>digest</b> is the digest of the identity key of
|
|
|
|
* a trusted directory. */
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
router_digest_is_trusted_dir(const char *digest)
|
|
|
|
{
|
2004-10-12 17:55:20 +02:00
|
|
|
if (!trusted_dir_servers)
|
2004-07-20 22:09:59 +02:00
|
|
|
return 0;
|
2004-10-12 17:55:20 +02:00
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent,
|
|
|
|
if (!memcmp(digest, ent->digest, DIGEST_LEN)) return 1);
|
2004-07-20 22:09:59 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-07-01 03:16:59 +02:00
|
|
|
/** Return the router in our routerlist whose hexadecimal key digest
|
|
|
|
* is <b>hexdigest</b>. Return NULL if no such router is known. */
|
2005-06-11 20:52:12 +02:00
|
|
|
routerinfo_t *
|
|
|
|
router_get_by_hexdigest(const char *hexdigest)
|
|
|
|
{
|
2004-07-01 03:16:59 +02:00
|
|
|
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
|
2005-03-22 01:42:38 +01:00
|
|
|
* is <b>digest</b>. Return NULL if no such router is known. */
|
2005-06-11 20:52:12 +02:00
|
|
|
routerinfo_t *
|
|
|
|
router_get_by_digest(const char *digest)
|
|
|
|
{
|
2004-07-01 03:16:59 +02:00
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
|
|
|
|
|
|
|
tor_assert(digest);
|
2005-06-21 01:04:13 +02:00
|
|
|
|
2005-02-27 10:47:01 +01:00
|
|
|
if (!routerlist) return NULL;
|
2003-09-25 07:17:11 +02:00
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
for (i=0;i<smartlist_len(routerlist->routers);i++) {
|
2004-04-07 21:46:27 +02:00
|
|
|
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. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
router_get_routerlist(routerlist_t **prouterlist)
|
|
|
|
{
|
2003-12-05 10:51:49 +01:00
|
|
|
*prouterlist = routerlist;
|
2002-09-26 14:09:10 +02:00
|
|
|
}
|
|
|
|
|
2004-10-28 20:37:52 +02:00
|
|
|
/** Return the publication time on the current routerlist, or 0 if we have no
|
|
|
|
* routerlist. */
|
2005-06-11 20:52:12 +02:00
|
|
|
time_t
|
|
|
|
routerlist_get_published_time(void)
|
|
|
|
{
|
2004-10-28 20:37:52 +02:00
|
|
|
return routerlist ? routerlist->published_on : 0;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Free all storage held by <b>router</b>. */
|
2005-06-11 20:52:12 +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;
|
|
|
|
|
2005-02-25 21:46:13 +01:00
|
|
|
tor_free(router->signed_descriptor);
|
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);
|
2005-05-06 10:53:23 +02:00
|
|
|
tor_free(router->contact_info);
|
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-10-15 03:58:11 +02:00
|
|
|
if (router->declared_family) {
|
|
|
|
SMARTLIST_FOREACH(router->declared_family, char *, s, tor_free(s));
|
|
|
|
smartlist_free(router->declared_family);
|
|
|
|
}
|
2004-11-12 20:39:13 +01:00
|
|
|
addr_policy_free(router->exit_policy);
|
2004-09-29 08:52:36 +02:00
|
|
|
tor_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> */
|
2005-06-11 20:52:12 +02:00
|
|
|
routerinfo_t *
|
|
|
|
routerinfo_copy(const routerinfo_t *router)
|
2004-04-08 00:18:57 +02:00
|
|
|
{
|
|
|
|
routerinfo_t *r;
|
2004-12-04 02:14:36 +01:00
|
|
|
addr_policy_t **e, *tmp;
|
2004-04-08 00:18:57 +02:00
|
|
|
|
|
|
|
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);
|
2005-02-28 04:37:27 +01:00
|
|
|
if (r->signed_descriptor)
|
|
|
|
r->signed_descriptor = tor_strdup(r->signed_descriptor);
|
2004-04-08 00:18:57 +02:00
|
|
|
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) {
|
2004-12-04 02:14:36 +01:00
|
|
|
tmp = tor_malloc(sizeof(addr_policy_t));
|
|
|
|
memcpy(tmp,*e,sizeof(addr_policy_t));
|
2004-04-08 00:18:57 +02:00
|
|
|
*e = tmp;
|
|
|
|
(*e)->string = tor_strdup((*e)->string);
|
|
|
|
e = & ((*e)->next);
|
|
|
|
}
|
2004-10-15 03:58:11 +02:00
|
|
|
if (r->declared_family) {
|
|
|
|
r->declared_family = smartlist_create();
|
|
|
|
SMARTLIST_FOREACH(router->declared_family, const char *, s,
|
|
|
|
smartlist_add(r->declared_family, tor_strdup(s)));
|
|
|
|
}
|
2004-04-08 00:18:57 +02:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2004-05-10 06:34:48 +02:00
|
|
|
/** Free all storage held by a routerlist <b>rl</b> */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
routerlist_free(routerlist_t *rl)
|
2003-05-06 19:38:16 +02:00
|
|
|
{
|
2005-02-25 00:01:26 +01:00
|
|
|
tor_assert(rl);
|
2004-04-07 21:46:27 +02:00
|
|
|
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
|
|
|
|
routerinfo_free(r));
|
|
|
|
smartlist_free(rl->routers);
|
2005-02-25 21:46:13 +01:00
|
|
|
running_routers_free(rl->running_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
|
|
|
}
|
|
|
|
|
2005-06-11 20:52:12 +02:00
|
|
|
/** Free all entries in the current router list. */
|
|
|
|
void
|
|
|
|
routerlist_free_current(void)
|
2005-02-11 00:18:39 +01:00
|
|
|
{
|
2005-02-25 00:01:26 +01:00
|
|
|
if (routerlist)
|
|
|
|
routerlist_free(routerlist);
|
2005-02-11 00:18:39 +01:00
|
|
|
routerlist = NULL;
|
2005-04-03 07:53:34 +02:00
|
|
|
if (warned_nicknames) {
|
|
|
|
SMARTLIST_FOREACH(warned_nicknames, char *, cp, tor_free(cp));
|
|
|
|
smartlist_free(warned_nicknames);
|
|
|
|
warned_nicknames = NULL;
|
|
|
|
}
|
2005-02-11 00:18:39 +01:00
|
|
|
}
|
|
|
|
|
2005-06-11 20:52:12 +02:00
|
|
|
/** Free all entries in the list of trusted directory servers. */
|
|
|
|
void
|
|
|
|
free_trusted_dir_servers(void)
|
2005-02-11 00:18:39 +01:00
|
|
|
{
|
|
|
|
if (trusted_dir_servers) {
|
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ds,
|
|
|
|
{ tor_free(ds->address); tor_free(ds); });
|
|
|
|
smartlist_free(trusted_dir_servers);
|
|
|
|
trusted_dir_servers = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-12 20:19:55 +02:00
|
|
|
/** Mark the router with ID <b>digest</b> as non-running in our routerlist. */
|
2005-06-11 20:52:12 +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);
|
2004-10-12 17:55:20 +02:00
|
|
|
|
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
|
|
|
|
if (!memcmp(d->digest, digest, DIGEST_LEN))
|
|
|
|
d->is_running = 0);
|
|
|
|
|
2004-07-03 01:40:03 +02:00
|
|
|
router = router_get_by_digest(digest);
|
2004-11-28 10:05:49 +01:00
|
|
|
if (!router) /* we don't seem to know about him in the first place */
|
2002-09-26 15:17:14 +02:00
|
|
|
return;
|
2004-11-25 05:20:10 +01:00
|
|
|
log_fn(LOG_DEBUG,"Marking router '%s' as down.",router->nickname);
|
2004-09-21 18:44:20 +02:00
|
|
|
if (router_is_me(router))
|
2004-09-21 19:14:47 +02:00
|
|
|
log_fn(LOG_WARN, "We just marked ourself as down. Are your external addresses reachable?");
|
2003-09-30 23:27:16 +02:00
|
|
|
router->is_running = 0;
|
2004-07-17 01:05:40 +02:00
|
|
|
router->status_set_at = time(NULL);
|
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
|
2005-05-14 07:01:41 +02:00
|
|
|
* their pointers to <b>router</b> if this function fails; <b>router</b>
|
2004-05-17 22:31:01 +02:00
|
|
|
* will either be inserted into the routerlist or freed. Returns 0 if the
|
2005-08-26 23:46:24 +02:00
|
|
|
* router was added; less than 0 if it was not.
|
2005-04-03 00:02:13 +02:00
|
|
|
*
|
2005-08-26 23:46:24 +02:00
|
|
|
* If we're returning an error and <b>msg</b> is not NULL, then assign to
|
2005-06-21 01:04:13 +02:00
|
|
|
* *<b>msg</b> a static string describing the reason for refusing the
|
|
|
|
* routerinfo.
|
2005-08-26 23:46:24 +02:00
|
|
|
*
|
|
|
|
* If the return value is less than -1, there was a problem with the
|
|
|
|
* routerinfo. If the return value is equal to -1, then the routerinfo was
|
|
|
|
* fine, but out-of-date.
|
2004-05-17 22:31:01 +02:00
|
|
|
*/
|
2005-08-26 22:59:04 +02:00
|
|
|
int
|
2005-06-11 20:52:12 +02:00
|
|
|
router_add_to_routerlist(routerinfo_t *router, const char **msg)
|
|
|
|
{
|
2004-05-17 22:31:01 +02:00
|
|
|
int i;
|
2004-08-07 05:38:07 +02:00
|
|
|
char id_digest[DIGEST_LEN];
|
2005-08-26 22:59:04 +02:00
|
|
|
int authdir = get_options()->AuthoritativeDir;
|
|
|
|
int authdir_verified = 0;
|
2004-08-07 05:38:07 +02:00
|
|
|
|
2005-08-26 23:12:34 +02:00
|
|
|
if (!routerlist) {
|
|
|
|
routerlist = tor_malloc_zero(sizeof(routerlist_t));
|
|
|
|
routerlist->routers = smartlist_create();
|
|
|
|
}
|
|
|
|
|
2004-08-07 05:38:07 +02:00
|
|
|
crypto_pk_get_digest(router->identity_pkey, id_digest);
|
|
|
|
|
2005-08-26 22:59:04 +02:00
|
|
|
if (authdir) {
|
|
|
|
if (dirserv_wants_to_reject_router(router, &authdir_verified, msg))
|
2005-08-26 23:46:24 +02:00
|
|
|
return -2;
|
2005-08-26 22:59:04 +02:00
|
|
|
router->is_verified = authdir_verified;
|
|
|
|
if (tor_version_as_new_as(router->platform,"0.1.0.2-rc"))
|
|
|
|
router->is_verified = 1;
|
|
|
|
}
|
|
|
|
|
2004-05-17 22:31:01 +02:00
|
|
|
/* 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) {
|
2005-08-26 22:59:04 +02:00
|
|
|
routerinfo_t *old_router = smartlist_get(routerlist->routers, i);
|
|
|
|
if (!crypto_pk_cmp_keys(router->identity_pkey,old_router->identity_pkey)) {
|
|
|
|
if (router->published_on <= old_router->published_on) {
|
2005-04-03 00:02:13 +02:00
|
|
|
log_fn(LOG_DEBUG, "Skipping not-new descriptor for router '%s'",
|
2004-05-17 22:31:01 +02:00
|
|
|
router->nickname);
|
2005-08-26 23:12:53 +02:00
|
|
|
if (!authdir) {
|
2005-08-26 22:59:04 +02:00
|
|
|
/* Update the is_running status to whatever we were told. */
|
|
|
|
old_router->is_running = router->is_running;
|
2005-08-26 23:12:53 +02:00
|
|
|
}
|
2004-05-17 22:31:01 +02:00
|
|
|
routerinfo_free(router);
|
2005-04-03 00:02:13 +02:00
|
|
|
if (msg) *msg = "Router descriptor was not new.";
|
2004-05-17 22:31:01 +02:00
|
|
|
return -1;
|
2005-08-26 22:59:04 +02:00
|
|
|
} else {
|
|
|
|
log_fn(LOG_DEBUG, "Replacing entry for router '%s/%s' [%s]",
|
|
|
|
router->nickname, old_router->nickname,
|
|
|
|
hex_str(id_digest,DIGEST_LEN));
|
|
|
|
if (router->addr == old_router->addr &&
|
|
|
|
router->or_port == old_router->or_port) {
|
|
|
|
/* these carry over when the address and orport are unchanged.*/
|
|
|
|
router->last_reachable = old_router->last_reachable;
|
|
|
|
router->testing_since = old_router->testing_since;
|
|
|
|
}
|
|
|
|
if (msg)
|
|
|
|
*msg = authdir_verified ? "Verified server updated":
|
|
|
|
"Unverified server updated. (Have you sent us your key finerprint?)";
|
|
|
|
routerinfo_free(old_router);
|
|
|
|
smartlist_set(routerlist->routers, i, router);
|
|
|
|
directory_set_dirty();
|
|
|
|
return 0;
|
2004-05-17 22:31:01 +02:00
|
|
|
}
|
2005-08-26 22:59:04 +02:00
|
|
|
} else if (!strcasecmp(router->nickname, old_router->nickname)) {
|
2004-08-17 08:06:05 +02:00
|
|
|
/* nicknames match, keys don't. */
|
|
|
|
if (router->is_verified) {
|
|
|
|
/* The new verified router replaces the old one; remove the
|
2004-08-17 10:00:23 +02:00
|
|
|
* old one. And carry on to the end of the list, in case
|
2004-12-01 04:48:14 +01:00
|
|
|
* there are more old unverified routers with this nickname
|
2004-08-17 08:06:05 +02:00
|
|
|
*/
|
2004-08-17 10:00:23 +02:00
|
|
|
/* mark-for-close connections using the old key, so we can
|
|
|
|
* make new ones with the new key.
|
|
|
|
*/
|
|
|
|
connection_t *conn;
|
2005-08-26 22:59:04 +02:00
|
|
|
while ((conn = connection_get_by_identity_digest(
|
|
|
|
old_router->identity_digest, CONN_TYPE_OR))) {
|
|
|
|
log_fn(LOG_INFO,"Closing conn to obsolete router '%s'",
|
|
|
|
old_router->nickname);
|
2004-08-17 10:00:23 +02:00
|
|
|
connection_mark_for_close(conn);
|
|
|
|
}
|
2005-08-26 22:59:04 +02:00
|
|
|
routerinfo_free(old_router);
|
2004-08-17 08:06:05 +02:00
|
|
|
smartlist_del_keeporder(routerlist->routers, i--);
|
2005-08-26 22:59:04 +02:00
|
|
|
} else if (old_router->is_verified) {
|
2004-08-17 08:06:05 +02:00
|
|
|
/* Can't replace a verified router with an unverified one. */
|
|
|
|
log_fn(LOG_DEBUG, "Skipping unverified entry for verified router '%s'",
|
|
|
|
router->nickname);
|
|
|
|
routerinfo_free(router);
|
2005-07-15 21:40:38 +02:00
|
|
|
if (msg) *msg = "Already have verified router with same nickname and different key.";
|
2005-08-26 23:46:24 +02:00
|
|
|
return -2;
|
2004-08-17 08:06:05 +02:00
|
|
|
}
|
2004-05-17 22:31:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* We haven't seen a router with this name before. Add it to the end of
|
|
|
|
* the list. */
|
|
|
|
smartlist_add(routerlist->routers, router);
|
2005-08-26 22:59:04 +02:00
|
|
|
directory_set_dirty();
|
2004-05-17 22:31:01 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-08-07 00:15:25 +02:00
|
|
|
/** Remove any routers from the routerlist that are more than <b>age</b>
|
2004-05-20 07:10:30 +02:00
|
|
|
* seconds old.
|
|
|
|
*/
|
|
|
|
void
|
2004-08-07 00:15:25 +02:00
|
|
|
routerlist_remove_old_routers(int age)
|
2004-05-20 07:10:30 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
time_t cutoff;
|
|
|
|
routerinfo_t *router;
|
|
|
|
if (!routerlist)
|
|
|
|
return;
|
|
|
|
|
2004-08-07 00:15:25 +02:00
|
|
|
cutoff = time(NULL) - age;
|
2004-05-20 07:10:30 +02:00
|
|
|
for (i = 0; i < smartlist_len(routerlist->routers); ++i) {
|
|
|
|
router = smartlist_get(routerlist->routers, i);
|
2004-10-19 20:19:59 +02:00
|
|
|
if (router->published_on <= cutoff) {
|
|
|
|
/* Too old. Remove it. */
|
2004-11-25 05:20:10 +01:00
|
|
|
log_fn(LOG_INFO,"Forgetting obsolete routerinfo for router '%s'", router->nickname);
|
2004-05-20 07:10:30 +02:00
|
|
|
routerinfo_free(router);
|
|
|
|
smartlist_del(routerlist->routers, i--);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-26 22:59:04 +02:00
|
|
|
/**
|
2005-06-21 01:04:13 +02:00
|
|
|
* Code to parse a single router descriptor and insert it into the
|
|
|
|
* routerlist. Return -1 if the descriptor was ill-formed; 0 if the
|
2005-04-03 00:02:13 +02:00
|
|
|
* descriptor was well-formed but could not be added; and 1 if the
|
|
|
|
* descriptor was added.
|
2005-06-21 01:04:13 +02:00
|
|
|
*
|
|
|
|
* If we don't add it and <b>msg</b> is not NULL, then assign to
|
|
|
|
* *<b>msg</b> a static string describing the reason for refusing the
|
|
|
|
* descriptor.
|
2005-08-26 22:59:04 +02:00
|
|
|
*
|
|
|
|
* This is used only by the controller.
|
2004-05-10 06:34:48 +02:00
|
|
|
*/
|
2005-02-25 21:46:13 +01:00
|
|
|
int
|
2005-04-03 00:02:13 +02:00
|
|
|
router_load_single_router(const char *s, const char **msg)
|
2005-02-25 21:46:13 +01:00
|
|
|
{
|
|
|
|
routerinfo_t *ri;
|
2005-05-18 05:52:07 +02:00
|
|
|
tor_assert(msg);
|
2005-07-15 21:40:38 +02:00
|
|
|
*msg = NULL;
|
2005-02-25 21:46:13 +01:00
|
|
|
|
|
|
|
if (!(ri = router_parse_entry_from_string(s, NULL))) {
|
|
|
|
log_fn(LOG_WARN, "Error parsing router descriptor; dropping.");
|
2005-07-15 21:40:38 +02:00
|
|
|
*msg = "Couldn't parse router descriptor.";
|
2005-02-25 21:46:13 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2005-05-14 07:01:41 +02:00
|
|
|
if (router_is_me(ri)) {
|
|
|
|
log_fn(LOG_WARN, "Router's identity key matches mine; dropping.");
|
2005-05-18 05:52:07 +02:00
|
|
|
*msg = "Router's identity key matches mine.";
|
2005-05-14 07:01:41 +02:00
|
|
|
routerinfo_free(ri);
|
|
|
|
return 0;
|
|
|
|
}
|
2005-02-25 21:46:13 +01:00
|
|
|
if (routerlist && routerlist->running_routers) {
|
|
|
|
running_routers_t *rr = routerlist->running_routers;
|
|
|
|
router_update_status_from_smartlist(ri,
|
|
|
|
rr->published_on,
|
2005-05-02 23:22:31 +02:00
|
|
|
rr->running_routers);
|
2005-02-25 21:46:13 +01:00
|
|
|
}
|
2005-04-03 00:02:13 +02:00
|
|
|
if (router_add_to_routerlist(ri, msg)<0) {
|
2005-07-15 21:40:38 +02:00
|
|
|
log_fn(LOG_WARN, "Couldn't add router to list: %s Dropping.",
|
|
|
|
*msg?*msg:"(No message).");
|
2005-06-21 01:04:13 +02:00
|
|
|
/* we've already assigned to *msg now, and ri is already freed */
|
2005-04-03 00:02:13 +02:00
|
|
|
return 0;
|
2005-03-02 23:29:58 +01:00
|
|
|
} else {
|
|
|
|
smartlist_t *changed = smartlist_create();
|
|
|
|
smartlist_add(changed, ri);
|
|
|
|
control_event_descriptors_changed(changed);
|
|
|
|
smartlist_free(changed);
|
2005-02-25 21:46:13 +01:00
|
|
|
}
|
2005-05-11 00:33:45 +02:00
|
|
|
|
2005-02-25 21:46:13 +01:00
|
|
|
log_fn(LOG_DEBUG, "Added router to list");
|
2005-04-03 00:02:13 +02:00
|
|
|
return 1;
|
2005-02-25 21:46:13 +01:00
|
|
|
}
|
2004-04-25 21:04:11 +02:00
|
|
|
|
2004-05-20 07:10:30 +02:00
|
|
|
/** Add to the current routerlist each router stored in the
|
2005-06-21 01:04:13 +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.
|
2005-01-06 21:11:52 +01:00
|
|
|
*
|
2005-01-29 12:48:37 +01:00
|
|
|
* If <b>dir_is_recent</b> is non-zero, then examine the
|
|
|
|
* Recommended-versions line and take appropriate action.
|
|
|
|
*
|
|
|
|
* If <b>dir_is_cached</b> is non-zero, then we're reading it
|
|
|
|
* from the cache so don't bother to re-write it to the cache.
|
2005-01-06 21:11:52 +01:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
router_load_routerlist_from_directory(const char *s,
|
|
|
|
crypto_pk_env_t *pkey,
|
|
|
|
int dir_is_recent,
|
|
|
|
int dir_is_cached)
|
2003-08-28 06:21:57 +02:00
|
|
|
{
|
2004-05-17 22:31:01 +02:00
|
|
|
routerlist_t *new_list = NULL;
|
2004-10-03 04:37:52 +02:00
|
|
|
if (router_parse_routerlist_from_directory(s, &new_list, pkey,
|
2005-01-06 21:11:52 +01:00
|
|
|
dir_is_recent,
|
|
|
|
!dir_is_cached)) {
|
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) {
|
2005-06-21 01:04:13 +02:00
|
|
|
/* Merge the new_list into routerlist, then free new_list. Also
|
|
|
|
* keep a list of changed descriptors to inform controllers. */
|
2005-03-02 23:29:58 +01:00
|
|
|
smartlist_t *changed = smartlist_create();
|
2004-05-17 22:41:40 +02:00
|
|
|
SMARTLIST_FOREACH(new_list->routers, routerinfo_t *, r,
|
2005-03-02 23:29:58 +01:00
|
|
|
{
|
2005-08-27 01:04:12 +02:00
|
|
|
char *msg;
|
|
|
|
if (router_add_to_routerlist(r,&msg)==0)
|
2005-03-02 23:29:58 +01:00
|
|
|
smartlist_add(changed, r);
|
|
|
|
});
|
2004-05-17 22:41:40 +02:00
|
|
|
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);
|
2005-03-02 23:29:58 +01:00
|
|
|
control_event_descriptors_changed(changed);
|
|
|
|
smartlist_free(changed);
|
2004-05-17 22:41:40 +02:00
|
|
|
} else {
|
|
|
|
routerlist = new_list;
|
2005-03-02 23:29:58 +01:00
|
|
|
control_event_descriptors_changed(routerlist->routers);
|
2004-05-17 22:41:40 +02:00
|
|
|
}
|
2005-08-16 04:52:27 +02:00
|
|
|
router_normalize_routerlist(routerlist);
|
2005-08-26 23:28:16 +02:00
|
|
|
#if 0
|
2004-11-06 06:18:11 +01:00
|
|
|
if (get_options()->AuthoritativeDir) {
|
2004-06-30 23:48:02 +02:00
|
|
|
/* Learn about the descriptors in the directory. */
|
2004-06-25 02:29:31 +02:00
|
|
|
dirserv_load_from_directory_string(s);
|
2005-06-21 01:04:13 +02:00
|
|
|
//XXXRD
|
2004-06-30 23:48:02 +02:00
|
|
|
}
|
2005-08-26 23:28:16 +02:00
|
|
|
#endif
|
2003-12-09 05:29:52 +01:00
|
|
|
return 0;
|
2003-08-28 06:21:57 +02:00
|
|
|
}
|
|
|
|
|
2005-08-16 04:52:27 +02:00
|
|
|
/** Ensure that our own routerinfo is at the front, and remove duplicates
|
|
|
|
* of our routerinfo.
|
2004-04-07 21:46:27 +02:00
|
|
|
*/
|
2005-08-16 04:52:27 +02:00
|
|
|
static void
|
|
|
|
router_normalize_routerlist(routerlist_t *rl)
|
2003-12-09 05:29:52 +01:00
|
|
|
{
|
2005-08-16 04:52:27 +02:00
|
|
|
int i=0;
|
2004-04-07 21:46:27 +02:00
|
|
|
routerinfo_t *r;
|
|
|
|
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) {
|
|
|
|
r = smartlist_get(rl->routers,i);
|
|
|
|
if (router_is_me(r)) {
|
|
|
|
routerinfo_free(r);
|
|
|
|
smartlist_del_keeporder(rl->routers, i--);
|
2003-05-07 20:30:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-19 07:57:16 +01:00
|
|
|
/** Decide whether a given addr:port is definitely accepted,
|
|
|
|
* definitely rejected, probably accepted, or probably rejected by a
|
|
|
|
* given policy. If <b>addr</b> is 0, we don't know the IP of the
|
|
|
|
* target address. If <b>port</b> is 0, we don't know the port of the
|
|
|
|
* target address.
|
2003-12-09 05:29:52 +01:00
|
|
|
*
|
2005-03-19 07:57:16 +01:00
|
|
|
* For now, the algorithm is pretty simple: we look for definite and
|
|
|
|
* uncertain matches. The first definite match is what we guess; if
|
2005-07-01 03:59:37 +02:00
|
|
|
* it was preceded by no uncertain matches of the opposite policy,
|
2005-03-19 07:57:16 +01:00
|
|
|
* then the guess is definite; otherwise it is probable. (If we
|
|
|
|
* have a known addr and port, all matches are definite; if we have an
|
|
|
|
* unknown addr/port, any address/port ranges other than "all" are
|
|
|
|
* uncertain.)
|
|
|
|
*
|
|
|
|
* We could do better by assuming that some ranges never match typical
|
|
|
|
* addresses (127.0.0.1, and so on). But we'll try this for now.
|
2003-12-09 05:29:52 +01:00
|
|
|
*/
|
2005-03-19 07:57:16 +01:00
|
|
|
addr_policy_result_t
|
|
|
|
router_compare_addr_to_addr_policy(uint32_t addr, uint16_t port,
|
|
|
|
addr_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;
|
2004-12-04 02:14:36 +01:00
|
|
|
addr_policy_t *tmpe;
|
2003-12-05 10:51:49 +01:00
|
|
|
|
2004-11-28 10:05:49 +01:00
|
|
|
for (tmpe=policy; tmpe; tmpe=tmpe->next) {
|
2004-02-17 09:52:03 +01:00
|
|
|
maybe = 0;
|
2003-12-09 05:29:52 +01:00
|
|
|
if (!addr) {
|
|
|
|
/* Address is unknown. */
|
2004-12-05 08:10:08 +01:00
|
|
|
if ((port >= tmpe->prt_min && port <= tmpe->prt_max) ||
|
|
|
|
(!port && tmpe->prt_min<=1 && tmpe->prt_max>=65535)) {
|
2004-02-17 09:52:03 +01:00
|
|
|
/* 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) {
|
2004-11-12 20:39:13 +01:00
|
|
|
if (tmpe->policy_type == ADDR_POLICY_REJECT)
|
2004-02-17 09:52:03 +01:00
|
|
|
maybe_reject = 1;
|
|
|
|
else
|
|
|
|
maybe_accept = 1;
|
|
|
|
}
|
2003-12-09 05:29:52 +01:00
|
|
|
if (match) {
|
2004-11-28 10:05:49 +01:00
|
|
|
if (tmpe->policy_type == ADDR_POLICY_ACCEPT) {
|
2004-02-17 08:56:33 +01:00
|
|
|
/* If we already hit a clause that might trigger a 'reject', than we
|
|
|
|
* can't be sure of this certain 'accept'.*/
|
2005-03-19 07:57:16 +01:00
|
|
|
return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED : ADDR_POLICY_ACCEPTED;
|
2004-02-17 08:56:33 +01:00
|
|
|
} else {
|
2005-03-19 07:57:16 +01:00
|
|
|
return maybe_accept ? ADDR_POLICY_PROBABLY_REJECTED : ADDR_POLICY_REJECTED;
|
2004-02-17 08:56:33 +01:00
|
|
|
}
|
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. */
|
2005-03-19 07:57:16 +01:00
|
|
|
return maybe_reject ? ADDR_POLICY_PROBABLY_ACCEPTED : ADDR_POLICY_ACCEPTED;
|
2003-09-25 07:17:11 +02:00
|
|
|
}
|
|
|
|
|
2005-01-12 05:58:23 +01:00
|
|
|
/** Return 1 if all running sufficiently-stable routers will reject
|
|
|
|
* addr:port, return 0 if any might accept it. */
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port,
|
|
|
|
int need_uptime)
|
|
|
|
{
|
2003-12-09 05:29:52 +01:00
|
|
|
int i;
|
|
|
|
routerinfo_t *router;
|
2005-03-19 07:57:16 +01:00
|
|
|
addr_policy_result_t r;
|
2004-10-14 05:44:45 +02:00
|
|
|
if (!routerlist) return 1;
|
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);
|
2005-01-12 05:58:23 +01:00
|
|
|
if (router->is_running &&
|
2005-03-19 07:57:16 +01:00
|
|
|
!router_is_unreliable(router, need_uptime, 0)) {
|
|
|
|
r = router_compare_addr_to_addr_policy(addr, port, router->exit_policy);
|
|
|
|
if (r != ADDR_POLICY_REJECTED && r != ADDR_POLICY_PROBABLY_REJECTED)
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2005-01-20 19:39:48 +01:00
|
|
|
/**
|
|
|
|
* If <b>policy</b> implicitly allows connections to any port in the
|
|
|
|
* IP set <b>addr</b>/<b>mask</b>, then set *<b>policy_out</b> to the
|
|
|
|
* part of the policy that allows it, and return 1. Else return 0.
|
|
|
|
*
|
|
|
|
* A policy allows an IP:Port combination <em>implicitly</em> if
|
|
|
|
* it is included in a *: pattern, or in a fallback pattern.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
policy_includes_addr_mask_implicitly(addr_policy_t *policy,
|
|
|
|
uint32_t addr, uint32_t mask,
|
|
|
|
addr_policy_t **policy_out)
|
|
|
|
{
|
|
|
|
uint32_t addr2;
|
|
|
|
tor_assert(policy_out);
|
|
|
|
addr &= mask;
|
|
|
|
addr2 = addr | ~mask;
|
|
|
|
for (; policy; policy=policy->next) {
|
|
|
|
/* Does this policy cover all of the address range we're looking at? */
|
|
|
|
/* Boolean logic time: range X is contained in range Y if, for
|
|
|
|
* each bit B, all possible values of B in X are values of B in Y.
|
|
|
|
* In "addr", we have every fixed bit set to its value, and every
|
|
|
|
* free bit set to 0. In "addr2", we have every fixed bit set to
|
|
|
|
* its value, and every free bit set to 1. So if addr and addr2 are
|
|
|
|
* both in the policy, the range is covered by the policy.
|
|
|
|
*/
|
2005-05-14 02:13:17 +02:00
|
|
|
uint32_t p_addr = policy->addr & policy->msk;
|
|
|
|
if (p_addr == (addr & policy->msk) &&
|
|
|
|
p_addr == (addr2 & policy->msk) &&
|
2005-01-20 19:39:48 +01:00
|
|
|
(policy->prt_min <= 1 && policy->prt_max == 65535)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* Does this policy cover some of the address range we're looking at? */
|
|
|
|
/* Boolean logic time: range X and range Y intersect if there is
|
|
|
|
* some z such that z & Xmask == Xaddr and z & Ymask == Yaddr.
|
|
|
|
* This is FALSE iff there is some bit b where Xmask == yMask == 1
|
|
|
|
* and Xaddr != Yaddr. So if X intersects with Y iff at every
|
|
|
|
* place where Xmask&Ymask==1, Xaddr == Yaddr, or equivalently,
|
|
|
|
* Xaddr&Xmask&Ymask == Yaddr&Xmask&Ymask.
|
|
|
|
*/
|
|
|
|
if ((policy->addr & policy->msk & mask) == (addr & policy->msk) &&
|
|
|
|
policy->policy_type == ADDR_POLICY_ACCEPT) {
|
|
|
|
*policy_out = policy;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*policy_out = NULL;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** If <b>policy</b> implicitly allows connections to any port on
|
|
|
|
* 127.*, 192.168.*, etc, then warn (if <b>warn</b> is set) and return
|
|
|
|
* true. Else return false.
|
|
|
|
**/
|
|
|
|
int
|
|
|
|
exit_policy_implicitly_allows_local_networks(addr_policy_t *policy,
|
|
|
|
int warn)
|
|
|
|
{
|
|
|
|
addr_policy_t *p;
|
|
|
|
int r=0,i;
|
|
|
|
static struct {
|
|
|
|
uint32_t addr; uint32_t mask; const char *network;
|
|
|
|
} private_networks[] = {
|
2005-06-29 21:15:23 +02:00
|
|
|
{ 0x7f000000, 0xff000000, "localhost (127.0.0.0/8)" },
|
|
|
|
{ 0x0a000000, 0xff000000, "addresses in private network 10.0.0.0/8" },
|
|
|
|
{ 0xa9fe0000, 0xffff0000, "addresses in private network 169.254.0.0/16" },
|
|
|
|
{ 0xac100000, 0xfff00000, "addresses in private network 172.16.0.0/12" },
|
|
|
|
{ 0xc0a80000, 0xffff0000, "addresses in private network 192.168.0.0/16" },
|
2005-01-20 19:39:48 +01:00
|
|
|
{ 0,0,NULL},
|
|
|
|
};
|
|
|
|
for (i=0; private_networks[i].addr; ++i) {
|
|
|
|
p = NULL;
|
2005-05-14 02:13:17 +02:00
|
|
|
/* log_fn(LOG_INFO,"Checking network %s", private_networks[i].network); */
|
|
|
|
if (policy_includes_addr_mask_implicitly(
|
2005-01-20 19:39:48 +01:00
|
|
|
policy, private_networks[i].addr, private_networks[i].mask, &p)) {
|
2005-05-14 02:13:17 +02:00
|
|
|
if (warn)
|
|
|
|
log_fn(LOG_WARN, "Exit policy %s implicitly accepts %s",
|
|
|
|
p?p->string:"(default)",
|
|
|
|
private_networks[i].network);
|
|
|
|
r = 1;
|
|
|
|
}
|
2005-01-20 19:39:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
router_exit_policy_rejects_all(routerinfo_t *router)
|
|
|
|
{
|
2004-12-05 08:10:08 +01:00
|
|
|
return router_compare_addr_to_addr_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-08-04 03:25:21 +02:00
|
|
|
/** Release all space held in <b>rr</b>. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
running_routers_free(running_routers_t *rr)
|
2004-06-25 02:29:31 +02:00
|
|
|
{
|
2005-02-25 21:46:13 +01:00
|
|
|
if (!rr)
|
|
|
|
return;
|
2004-06-25 02:29:31 +02:00
|
|
|
if (rr->running_routers) {
|
|
|
|
SMARTLIST_FOREACH(rr->running_routers, char *, s, tor_free(s));
|
|
|
|
smartlist_free(rr->running_routers);
|
|
|
|
}
|
|
|
|
tor_free(rr);
|
|
|
|
}
|
|
|
|
|
2004-08-04 03:25:21 +02:00
|
|
|
/** Update the running/not-running status of every router in <b>list</b>, based
|
2004-07-17 00:23:18 +02:00
|
|
|
* on the contents of <b>rr</b>. */
|
2005-06-21 01:04:13 +02:00
|
|
|
static void
|
2005-06-11 20:52:12 +02:00
|
|
|
routerlist_update_from_runningrouters(routerlist_t *list,
|
|
|
|
running_routers_t *rr)
|
2004-06-25 02:29:31 +02:00
|
|
|
{
|
2004-10-27 02:48:51 +02:00
|
|
|
routerinfo_t *me = router_get_my_routerinfo();
|
|
|
|
smartlist_t *all_routers;
|
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;
|
|
|
|
|
2004-10-27 02:48:51 +02:00
|
|
|
all_routers = smartlist_create();
|
2004-11-28 10:05:49 +01:00
|
|
|
if (me) /* learn if the dirservers think I'm verified */
|
2004-10-27 02:48:51 +02:00
|
|
|
smartlist_add(all_routers, me);
|
2004-11-09 21:04:00 +01:00
|
|
|
|
2004-10-27 02:48:51 +02:00
|
|
|
smartlist_add_all(all_routers,list->routers);
|
|
|
|
SMARTLIST_FOREACH(rr->running_routers, const char *, cp,
|
|
|
|
routers_update_status_from_entry(all_routers, rr->published_on,
|
2005-05-02 23:22:31 +02:00
|
|
|
cp));
|
2004-10-27 02:48:51 +02:00
|
|
|
smartlist_free(all_routers);
|
2004-07-17 01:05:40 +02:00
|
|
|
list->running_routers_updated_on = rr->published_on;
|
|
|
|
}
|
|
|
|
|
2005-06-21 01:04:13 +02:00
|
|
|
/** We've just got a running routers list in <b>rr</b>; update the
|
|
|
|
* status of the routers in <b>list</b>, and cache <b>rr</b> */
|
|
|
|
void
|
|
|
|
routerlist_set_runningrouters(routerlist_t *list, running_routers_t *rr)
|
|
|
|
{
|
|
|
|
routerlist_update_from_runningrouters(list,rr);
|
|
|
|
if (list->running_routers != rr) {
|
|
|
|
running_routers_free(list->running_routers);
|
|
|
|
list->running_routers = rr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-17 01:05:40 +02:00
|
|
|
/** Update the is_running and is_verified fields of the router <b>router</b>,
|
|
|
|
* based in its status in the list of strings stored in <b>running_list</b>.
|
|
|
|
* All entries in <b>running_list</b> follow one of these formats:
|
|
|
|
* <ol><li> <b>nickname</b> -- router is running and verified.
|
2004-10-27 02:48:51 +02:00
|
|
|
* (running-routers format)
|
|
|
|
* <li> !<b>nickname</b> -- router is not-running and verified.
|
|
|
|
* (running-routers format)
|
2004-11-09 21:04:00 +01:00
|
|
|
* <li> <b>nickname</b>=$<b>hexdigest</b> -- router is running and
|
2004-10-27 02:48:51 +02:00
|
|
|
* verified. (router-status format)
|
|
|
|
* (router-status format)
|
2004-11-09 21:04:00 +01:00
|
|
|
* <li> !<b>nickname</b>=$<b>hexdigest</b> -- router is running and
|
2004-10-27 02:48:51 +02:00
|
|
|
* verified. (router-status format)
|
2004-07-17 01:05:40 +02:00
|
|
|
* <li> !<b>nickname</b> -- router is not-running and verified.
|
|
|
|
* <li> $<b>hexdigest</b> -- router is running and unverified.
|
|
|
|
* <li> !$<b>hexdigest</b> -- router is not-running and unverified.
|
|
|
|
* </ol>
|
2004-08-07 11:01:56 +02:00
|
|
|
*
|
|
|
|
* Return 1 if we found router in running_list, else return 0.
|
2004-07-17 01:05:40 +02:00
|
|
|
*/
|
2005-06-11 20:52:12 +02:00
|
|
|
int
|
|
|
|
routers_update_status_from_entry(smartlist_t *routers,
|
|
|
|
time_t list_time,
|
|
|
|
const char *s)
|
2004-07-17 01:05:40 +02:00
|
|
|
{
|
2005-08-26 22:59:04 +02:00
|
|
|
int authdir = get_options()->AuthoritativeDir;
|
2004-10-27 02:48:51 +02:00
|
|
|
int is_running = 1;
|
|
|
|
int is_verified = 0;
|
|
|
|
int hex_digest_set = 0;
|
|
|
|
char nickname[MAX_NICKNAME_LEN+1];
|
|
|
|
char hexdigest[HEX_DIGEST_LEN+1];
|
|
|
|
char digest[DIGEST_LEN];
|
|
|
|
const char *cp, *end;
|
|
|
|
|
|
|
|
/* First, parse the entry. */
|
|
|
|
cp = s;
|
|
|
|
if (*cp == '!') {
|
|
|
|
is_running = 0;
|
|
|
|
++cp;
|
2004-07-22 23:20:23 +02:00
|
|
|
}
|
2004-10-27 02:48:51 +02:00
|
|
|
|
|
|
|
if (*cp != '$') {
|
|
|
|
/* It starts with a non-dollar character; that's a nickname. The nickname
|
|
|
|
* entry will either extend to a NUL (old running-routers format) or to an
|
|
|
|
* equals sign (new router-status format). */
|
|
|
|
is_verified = 1;
|
|
|
|
end = strchr(cp, '=');
|
|
|
|
if (!end)
|
|
|
|
end = strchr(cp,'\0');
|
|
|
|
tor_assert(end);
|
|
|
|
/* 'end' now points on character beyond the end of the nickname */
|
|
|
|
if (end == cp || end-cp > MAX_NICKNAME_LEN) {
|
|
|
|
log_fn(LOG_WARN, "Bad nickname length (%d) in router status entry (%s)",
|
2004-11-09 12:36:38 +01:00
|
|
|
(int)(end-cp), s);
|
2004-10-27 02:48:51 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memcpy(nickname, cp, end-cp);
|
|
|
|
nickname[end-cp]='\0';
|
|
|
|
if (!is_legal_nickname(nickname)) {
|
|
|
|
log_fn(LOG_WARN, "Bad nickname (%s) in router status entry (%s)",
|
|
|
|
nickname, s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
cp = end;
|
|
|
|
if (*cp == '=')
|
|
|
|
++cp;
|
2004-07-22 23:20:23 +02:00
|
|
|
}
|
2004-10-27 02:48:51 +02:00
|
|
|
/* 'end' now points to the start of a hex digest, or EOS. */
|
|
|
|
|
|
|
|
/* Parse the hexdigest portion of the status. */
|
|
|
|
if (*cp == '$') {
|
|
|
|
hex_digest_set = 1;
|
|
|
|
++cp;
|
|
|
|
if (strlen(cp) != HEX_DIGEST_LEN) {
|
|
|
|
log_fn(LOG_WARN, "Bad length (%d) on digest in router status entry (%s)",
|
2004-10-27 23:14:11 +02:00
|
|
|
(int)strlen(cp), s);
|
2004-10-27 02:48:51 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2004-10-27 08:48:16 +02:00
|
|
|
strlcpy(hexdigest, cp, sizeof(hexdigest));
|
2004-10-27 02:48:51 +02:00
|
|
|
if (base16_decode(digest, DIGEST_LEN, hexdigest, HEX_DIGEST_LEN)<0) {
|
|
|
|
log_fn(LOG_WARN, "Invalid digest in router status entry (%s)", s);
|
|
|
|
return -1;
|
2004-06-25 02:29:31 +02:00
|
|
|
}
|
|
|
|
}
|
2004-10-27 02:48:51 +02:00
|
|
|
|
|
|
|
/* Make sure that the entry was in the right format. */
|
2005-05-02 23:22:31 +02:00
|
|
|
if (!hex_digest_set) {
|
|
|
|
log_fn(LOG_WARN, "Invalid syntax for router-status member (%s)", s);
|
|
|
|
return -1;
|
2004-10-27 02:48:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Okay, we're done parsing. For all routers that match, update their status.
|
|
|
|
*/
|
|
|
|
SMARTLIST_FOREACH(routers, routerinfo_t *, r,
|
|
|
|
{
|
|
|
|
int nickname_matches = is_verified && !strcasecmp(r->nickname, nickname);
|
|
|
|
int digest_matches = !memcmp(digest, r->identity_digest, DIGEST_LEN);
|
2005-08-26 22:59:04 +02:00
|
|
|
if (!authdir) {
|
|
|
|
/* If we're not an authoritative directory, update verified status.
|
|
|
|
*/
|
|
|
|
if (nickname_matches && digest_matches)
|
|
|
|
r->is_verified = 1;
|
|
|
|
else if (digest_matches)
|
|
|
|
r->is_verified = 0;
|
|
|
|
}
|
2005-05-02 23:22:31 +02:00
|
|
|
if (digest_matches)
|
2004-10-27 02:48:51 +02:00
|
|
|
if (r->status_set_at < list_time) {
|
2005-08-26 22:59:04 +02:00
|
|
|
if (!authdir || is_running)
|
|
|
|
/* If we're an authoritative directory, only believe that servers
|
|
|
|
* are down when we hear it ourselves. Otherwise, believe
|
|
|
|
* what we're told.
|
|
|
|
*/
|
|
|
|
r->is_running = is_running;
|
2004-10-27 02:48:51 +02:00
|
|
|
r->status_set_at = time(NULL);
|
|
|
|
}
|
|
|
|
});
|
2004-11-03 19:33:07 +01:00
|
|
|
|
2004-10-27 02:48:51 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-11-09 18:14:15 +01:00
|
|
|
/** As router_update_status_from_entry, but consider all entries in
|
|
|
|
* running_list. */
|
|
|
|
int
|
|
|
|
router_update_status_from_smartlist(routerinfo_t *router,
|
|
|
|
time_t list_time,
|
2005-05-02 23:22:31 +02:00
|
|
|
smartlist_t *running_list)
|
2004-10-27 02:48:51 +02:00
|
|
|
{
|
|
|
|
smartlist_t *rl;
|
|
|
|
rl = smartlist_create();
|
|
|
|
smartlist_add(rl,router);
|
|
|
|
SMARTLIST_FOREACH(running_list, const char *, cp,
|
2005-05-02 23:22:31 +02:00
|
|
|
routers_update_status_from_entry(rl,list_time,cp));
|
2004-10-27 02:48:51 +02:00
|
|
|
smartlist_free(rl);
|
2004-08-07 11:01:56 +02:00
|
|
|
return 0;
|
2004-06-25 02:29:31 +02:00
|
|
|
}
|
|
|
|
|
2004-11-09 18:14:15 +01:00
|
|
|
/** Add to the list of authorized directory servers one at
|
2005-08-26 21:31:51 +02:00
|
|
|
* <b>address</b>:<b>port</b>, with identity key <b>digest</b>. If
|
|
|
|
* <b>address</b> is NULL, add ourself. */
|
2004-11-09 18:14:15 +01:00
|
|
|
void
|
|
|
|
add_trusted_dir_server(const char *address, uint16_t port, const char *digest)
|
2004-10-12 17:55:20 +02:00
|
|
|
{
|
|
|
|
trusted_dir_server_t *ent;
|
|
|
|
uint32_t a;
|
2005-08-26 21:31:51 +02:00
|
|
|
char *hostname = NULL;
|
2004-10-12 17:55:20 +02:00
|
|
|
if (!trusted_dir_servers)
|
|
|
|
trusted_dir_servers = smartlist_create();
|
|
|
|
|
2005-08-26 21:31:51 +02:00
|
|
|
if (!address) { /* The address is us; we should guess. */
|
|
|
|
if (resolve_my_address(get_options(), &a, &hostname) < 0) {
|
2005-08-26 09:41:19 +02:00
|
|
|
log_fn(LOG_WARN, "Couldn't find a suitable address. Returning.");
|
|
|
|
return;
|
|
|
|
}
|
2005-08-26 21:25:36 +02:00
|
|
|
} else {
|
|
|
|
if (tor_lookup_hostname(address, &a)) {
|
|
|
|
log_fn(LOG_WARN, "Unable to lookup address for directory server at %s",
|
|
|
|
address);
|
|
|
|
return;
|
|
|
|
}
|
2005-08-26 21:31:51 +02:00
|
|
|
hostname = tor_strdup(address);
|
2005-08-26 21:25:36 +02:00
|
|
|
a = ntohl(a);
|
2004-10-12 17:55:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ent = tor_malloc(sizeof(trusted_dir_server_t));
|
2005-08-26 21:31:51 +02:00
|
|
|
ent->address = hostname;
|
2005-08-26 09:41:19 +02:00
|
|
|
ent->addr = a;
|
2004-10-12 17:55:20 +02:00
|
|
|
ent->dir_port = port;
|
|
|
|
ent->is_running = 1;
|
|
|
|
memcpy(ent->digest, digest, DIGEST_LEN);
|
2004-10-13 20:28:39 +02:00
|
|
|
smartlist_add(trusted_dir_servers, ent);
|
2004-10-12 17:55:20 +02:00
|
|
|
}
|
|
|
|
|
2005-03-17 13:38:37 +01:00
|
|
|
/** Remove all members from the list of trusted dir servers. */
|
2005-06-11 20:52:12 +02:00
|
|
|
void
|
|
|
|
clear_trusted_dir_servers(void)
|
2004-10-12 17:55:20 +02:00
|
|
|
{
|
|
|
|
if (trusted_dir_servers) {
|
|
|
|
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent,
|
|
|
|
{ tor_free(ent->address); tor_free(ent); });
|
|
|
|
smartlist_clear(trusted_dir_servers);
|
|
|
|
} else {
|
|
|
|
trusted_dir_servers = smartlist_create();
|
|
|
|
}
|
|
|
|
}
|
2005-06-09 21:03:31 +02:00
|
|
|
|