Commit 0068415b authored by Nick Mathewson's avatar Nick Mathewson 🎨
Browse files

Add an implementation of trusted_dir_server logic to switch towards simply...

Add an implementation of trusted_dir_server logic to switch towards simply remembering an addr/port/keyid for each trusted dir server


svn:r2443
parent 43ef5a3e
......@@ -34,6 +34,7 @@ static int config_get_lines(FILE *f, struct config_line_t **result);
static void config_free_lines(struct config_line_t *front);
static int config_compare(struct config_line_t *c, const char *key, config_type_t type, void *arg);
static int config_assign(or_options_t *options, struct config_line_t *list);
static int parse_dir_server_line(const char *line);
/** Helper: Read a list of configuration options from the command line. */
static struct config_line_t *config_get_commandlines(int argc, char **argv) {
......@@ -205,6 +206,7 @@ static int config_assign(or_options_t *options, struct config_line_t *list) {
config_compare(list, "DirPort", CONFIG_TYPE_INT, &options->DirPort) ||
config_compare(list, "DirBindAddress", CONFIG_TYPE_LINELIST, &options->DirBindAddress) ||
config_compare(list, "DirFetchPostPeriod",CONFIG_TYPE_INT, &options->DirFetchPostPeriod) ||
config_compare(list, "DirServer", CONFIG_TYPE_LINELIST, &options->DirServers) ||
config_compare(list, "ExitNodes", CONFIG_TYPE_STRING, &options->ExitNodes) ||
config_compare(list, "EntryNodes", CONFIG_TYPE_STRING, &options->EntryNodes) ||
......@@ -387,6 +389,11 @@ int config_assign_default_dirservers(void) {
log_fn(LOG_WARN,"Bug: the default dirservers internal string is corrupt.");
return -1;
}
#if 0
parse_dir_server_line("18.244.0.188:9031 XXXX");
parse_dir_server_line("18.244.0.188:9032 XXXX");
parse_dir_server_line("62.116.124.106:9030 XXXX");
#endif
return 0;
}
......@@ -535,6 +542,7 @@ static void free_options(or_options_t *options) {
config_free_lines(options->DirBindAddress);
config_free_lines(options->ExitPolicy);
config_free_lines(options->SocksPolicy);
config_free_lines(options->DirServers);
if (options->FirewallPorts) {
SMARTLIST_FOREACH(options->FirewallPorts, char *, cp, tor_free(cp));
smartlist_free(options->FirewallPorts);
......@@ -573,6 +581,7 @@ static void init_options(or_options_t *options) {
options->NumCpus = 1;
options->RendConfigLines = NULL;
options->FirewallPorts = NULL;
options->DirServers = NULL;
}
static char *get_default_conf_file(void)
......@@ -856,6 +865,11 @@ int getconfig(int argc, char **argv, or_options_t *options) {
result = -1;
}
for (cl = options->DirServers; cl; cl = cl->next) {
if (parse_dir_server_line(cl->value)<0)
return -1;
}
/* XXX look at the various nicknamelists and make sure they're
* valid and don't have hostnames that are too long.
*/
......@@ -1025,6 +1039,49 @@ void exit_policy_free(struct exit_policy_t *p) {
}
}
static int parse_dir_server_line(const char *line)
{
smartlist_t *items = NULL;
int r;
char *addrport, *address=NULL;
uint16_t port;
char digest[DIGEST_LEN];
items = smartlist_create();
smartlist_split_string(items, line, " ",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
if (smartlist_len(items) < 2) {
log_fn(LOG_WARN, "Too few arguments to DirServer line."); goto err;
}
addrport = smartlist_get(items, 0);
if (parse_addr_port(addrport, &address, NULL, &port)<0) {
log_fn(LOG_WARN, "Error parsing DirServer address '%s'", addrport);goto err;
}
if (!port) {
log_fn(LOG_WARN, "Missing port in DirServe address '%s'",addrport);goto err;
}
tor_strstrip(smartlist_get(items, 1), " ");
if (strlen(smartlist_get(items, 1)) != HEX_DIGEST_LEN) {
log_fn(LOG_WARN, "Key digest for DirServer is wrong length."); goto err;
}
if (base16_decode(digest, DIGEST_LEN,
smartlist_get(items,1), HEX_DIGEST_LEN)<0) {
log_fn(LOG_WARN, "Unable to decode DirServer key digest."); goto err;
}
add_trusted_dir_server(address, port, digest);
r = 0;
goto done;
err:
r = -1;
done:
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
smartlist_free(items);
if (address) tor_free(address);
return r;
}
const char *get_data_directory(or_options_t *options) {
const char *d;
if (options->DataDirectory)
......
......@@ -27,10 +27,21 @@
*/
static void
directory_initiate_command(routerinfo_t *router, uint8_t purpose,
directory_initiate_command_router(routerinfo_t *router, uint8_t purpose,
const char *payload, int payload_len);
static void
directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv,
uint8_t purpose, const char *payload, int payload_len);
static void
directory_initiate_command(const char *address, uint32_t addr, uint16_t port,
const char *platform,
const char *digest, uint8_t purpose,
const char *payload, int payload_len);
static void
directory_send_command(connection_t *conn, routerinfo_t *router, int purpose,
directory_send_command(connection_t *conn, const char *platform,
uint16_t dir_port, int purpose,
const char *payload, int payload_len);
static int directory_handle_command(connection_t *conn);
......@@ -75,7 +86,7 @@ directory_post_to_dirservers(uint8_t purpose, const char *payload,
/* Note: this posts our descriptor to ourselves, if we're an
* authdirserver. But I think that's ok. */
if(router->is_trusted_dir)
directory_initiate_command(router, purpose, payload, payload_len);
directory_initiate_command_router(router, purpose, payload, payload_len);
}
}
......@@ -88,29 +99,37 @@ void
directory_get_from_dirserver(uint8_t purpose, const char *payload,
int payload_len)
{
routerinfo_t *ds;
routerinfo_t *r = NULL;
trusted_dir_server_t *ds = NULL;
if (purpose == DIR_PURPOSE_FETCH_DIR) {
if (advertised_server_mode()) {
/* only ask authdirservers, and don't ask myself */
ds = router_pick_directory_server(1, 1);
r = router_pick_directory_server(1, 1);
/* XXXX NM Enable this once we actually set keys for dirservers.
* ds = router_pick_trusteddirserver(1);
*/
} else {
/* anybody with a non-zero dirport will do */
ds = router_pick_directory_server(0, 1);
r = router_pick_directory_server(0, 1);
}
} else { // (purpose == DIR_PURPOSE_FETCH_RENDDESC)
/* only ask authdirservers, any of them will do */
ds = router_pick_directory_server(1, 0);
r = router_pick_directory_server(1, 0);
/* XXXX NM Enable this once we actually set keys for dirservers.
* ds = router_pick_trusteddirserver(0);
*/
}
if (!ds) { /* no viable dirserver found */
if (r)
directory_initiate_command_router(r, purpose, payload, payload_len);
else if (ds)
directory_initiate_command_trusted_dir(ds, purpose, payload, payload_len);
else
log_fn(LOG_WARN,"No running dirservers known. Not trying. (purpose %d)", purpose);
return;
}
directory_initiate_command(ds, purpose, payload, payload_len);
}
/** Launch a new connection to the directory server <b>router</b> to upload or
* download a service or rendezvous descriptor. <b>purpose</b> determines what
* kind of directory connection we're launching, and must be one of
......@@ -121,13 +140,31 @@ directory_get_from_dirserver(uint8_t purpose, const char *payload,
* and <b>payload_len</b> are the service ID we want to fetch.
*/
static void
directory_initiate_command(routerinfo_t *router, uint8_t purpose,
directory_initiate_command_router(routerinfo_t *router, uint8_t purpose,
const char *payload, int payload_len)
{
directory_initiate_command(router->address, router->addr, router->dir_port,
router->platform, router->identity_digest,
purpose, payload, payload_len);
}
static void
directory_initiate_command_trusted_dir(trusted_dir_server_t *dirserv,
uint8_t purpose, const char *payload, int payload_len)
{
directory_initiate_command(dirserv->address, dirserv->addr, dirserv->dir_port,
NULL, dirserv->digest, purpose, payload, payload_len);
}
static void
directory_initiate_command(const char *address, uint32_t addr,
uint16_t dir_port, const char *platform,
const char *digest, uint8_t purpose,
const char *payload, int payload_len)
{
connection_t *conn;
tor_assert(router);
tor_assert(router->dir_port);
tor_assert(address && addr && dir_port && digest);
switch (purpose) {
case DIR_PURPOSE_FETCH_DIR:
......@@ -154,14 +191,15 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose,
conn->addr = options.HttpProxyAddr;
conn->port = options.HttpProxyPort;
} else {
conn->addr = router->addr;
conn->port = router->dir_port;
conn->addr = addr;
conn->port = dir_port;
}
conn->address = tor_strdup(router->address);
conn->nickname = tor_strdup(router->nickname);
tor_assert(router->identity_pkey);
conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey);
crypto_pk_get_digest(conn->identity_pkey, conn->identity_digest);
conn->address = tor_strdup(address);
/* conn->nickname = tor_strdup(router->nickname); */
/* tor_assert(router->identity_pkey); */
/* conn->identity_pkey = crypto_pk_dup_key(router->identity_pkey); */
/* crypto_pk_get_digest(conn->identity_pkey, conn->identity_digest); */
memcpy(conn->identity_digest, digest, DIGEST_LEN);
conn->purpose = purpose;
......@@ -185,7 +223,8 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose,
/* fall through */
case 0:
/* queue the command on the outbuf */
directory_send_command(conn, router, purpose, payload, payload_len);
directory_send_command(conn, platform, dir_port,
purpose, payload, payload_len);
connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
/* writable indicates finish, readable indicates broken link,
......@@ -206,7 +245,8 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose,
conn->state = DIR_CONN_STATE_CLIENT_SENDING;
connection_add(conn);
/* queue the command on the outbuf */
directory_send_command(conn, router, purpose, payload, payload_len);
directory_send_command(conn, platform, dir_port,
purpose, payload, payload_len);
connection_watch_events(conn, POLLIN | POLLOUT | POLLERR);
}
}
......@@ -216,7 +256,8 @@ directory_initiate_command(routerinfo_t *router, uint8_t purpose,
* directory_initiate_command.
*/
static void
directory_send_command(connection_t *conn, routerinfo_t *router, int purpose,
directory_send_command(connection_t *conn, const char *platform,
uint16_t dir_port, int purpose,
const char *payload, int payload_len) {
char tmp[8192];
char proxystring[128];
......@@ -226,14 +267,15 @@ directory_send_command(connection_t *conn, routerinfo_t *router, int purpose,
char *httpcommand = NULL;
tor_assert(conn && conn->type == CONN_TYPE_DIR);
tor_assert(router);
tor_assert(dir_port && conn);
use_newer = tor_version_as_new_as(router->platform, "0.0.9pre1");
/* If we don't know the platform, assume it's up-to-date. */
use_newer = platform ? tor_version_as_new_as(platform, "0.0.9pre1"):1;
if(router->dir_port == 80) {
strlcpy(hoststring, router->address, sizeof(hoststring));
if(dir_port == 80) {
strlcpy(hoststring, conn->address, sizeof(hoststring));
} else {
sprintf(hoststring, "%s:%d", router->address, router->dir_port);
sprintf(hoststring, "%s:%d", conn->address, dir_port);
}
if(options.HttpProxy) {
sprintf(proxystring, "http://%s", hoststring);
......@@ -245,7 +287,7 @@ directory_send_command(connection_t *conn, routerinfo_t *router, int purpose,
case DIR_PURPOSE_FETCH_DIR:
tor_assert(payload == NULL);
log_fn(LOG_DEBUG, "Asking for %scompressed directory from server running %s",
use_newer?"":"un", router->platform);
use_newer?"":"un", platform?platform:"<unknown version>");
httpcommand = "GET";
strlcpy(url, use_newer ? "/tor/dir.z" : "/", sizeof(url));
break;
......
......@@ -900,6 +900,9 @@ typedef struct {
uint32_t HttpProxyAddr; /**< Parsed IPv4 addr for http proxy, if any */
uint16_t HttpProxyPort; /**< Parsed port for http proxy, if any */
struct config_line_t *DirServers; /**< List of configuration lines
* for directory servers. */
} or_options_t;
/* XXX are these good enough defaults? */
......@@ -1397,8 +1400,17 @@ int is_legal_nickname_or_hexdigest(const char *s);
/********************************* routerlist.c ***************************/
typedef struct trusted_dir_server_t {
char *address;
uint32_t addr;
uint16_t dir_port;
char digest[DIGEST_LEN];
int is_running;
} trusted_dir_server_t;
int router_reload_router_list(void);
routerinfo_t *router_pick_directory_server(int requireauth, int requireothers);
trusted_dir_server_t *router_pick_trusteddirserver(int requireothers);
int all_directory_servers_down(void);
struct smartlist_t;
void routerlist_add_friends(struct smartlist_t *sl, routerinfo_t *router);
......@@ -1440,6 +1452,7 @@ void routerlist_update_from_runningrouters(routerlist_t *list,
int router_update_status_from_smartlist(routerinfo_t *r,
time_t list_time,
smartlist_t *running_list);
void add_trusted_dir_server(const char *addr, uint16_t port,const char *digest);
/********************************* routerparse.c ************************/
......
......@@ -18,17 +18,19 @@ extern or_options_t options; /**< command-line and config-file options */
/* ********************************************************************** */
static smartlist_t *trusted_dir_servers = NULL;
/* static function prototypes */
static routerinfo_t *
router_pick_directory_server_impl(int requireauth, int requireothers, int fascistfirewall);
static void mark_all_authdirservers_up(void);
static trusted_dir_server_t *
router_pick_trusteddirserver_impl(int requireother, int fascistfirewall);
static void mark_all_trusteddirservers_up(void);
static int router_resolve_routerlist(routerlist_t *dir);
static void clear_trusted_dir_servers(void);
/****************************************************************************/
/** List of digests of keys for servers that are trusted directories. */
static smartlist_t *trusted_dir_digests = NULL;
/****
* Functions to manage and access our list of known routers. (Note:
* dirservers maintain a separate, independent list of known router
......@@ -92,7 +94,7 @@ routerinfo_t *router_pick_directory_server(int requireauth, int requireothers) {
log_fn(LOG_INFO,"No dirservers are reachable. Trying them all again.");
/* mark all authdirservers as up again */
mark_all_authdirservers_up();
mark_all_trusteddirservers_up();
/* try again */
choice = router_pick_directory_server_impl(requireauth, requireothers, 0);
if(choice)
......@@ -110,6 +112,34 @@ routerinfo_t *router_pick_directory_server(int requireauth, int requireothers) {
return choice;
}
trusted_dir_server_t *router_pick_trusteddirserver(int requireothers) {
trusted_dir_server_t *choice;
choice = router_pick_trusteddirserver_impl(requireothers,
options.FascistFirewall);
if(choice)
return choice;
log_fn(LOG_INFO,"No trusted dirservers are reachable. Trying them all again.");
/* mark all authdirservers as up again */
mark_all_trusteddirservers_up();
/* try again */
choice = router_pick_trusteddirserver_impl(requireothers, 0);
if(choice)
return choice;
log_fn(LOG_WARN,"Still no dirservers %s. Reloading and trying again.",
options.FascistFirewall ? "reachable" : "known");
has_fetched_directory=0; /* reset it */
routerlist_clear_trusted_directories();
if(router_reload_router_list()) {
return NULL;
}
/* give it one last try */
choice = router_pick_trusteddirserver_impl(requireothers, 0);
return choice;
}
/** Pick a random running router from our routerlist. If requireauth,
* it has to be a trusted server. If requireothers, it cannot be us.
*/
......@@ -147,21 +177,48 @@ router_pick_directory_server_impl(int requireauth, int requireothers, int fascis
return router;
}
/** Go through and mark the auth dirservers as up */
static void mark_all_authdirservers_up(void) {
int i;
routerinfo_t *router;
static trusted_dir_server_t *
router_pick_trusteddirserver_impl(int requireother, int fascistfirewall)
{
smartlist_t *sl;
routerinfo_t *me;
char buf[16];
trusted_dir_server_t *ds;
sl = smartlist_create();
me = router_get_my_routerinfo();
if(!routerlist)
return;
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) {
sprintf(buf,"%d",d->dir_port);
if (!smartlist_string_isin(options.FirewallPorts, buf))
continue;
}
smartlist_add(sl, d);
});
for(i=0; i < smartlist_len(routerlist->routers); i++) {
router = smartlist_get(routerlist->routers, i);
if(router->is_trusted_dir) {
tor_assert(router->dir_port > 0);
router->is_running = 1;
router->status_set_at = time(NULL);
}
ds = smartlist_choose(sl);
smartlist_free(sl);
return ds;
}
/** Go through and mark the auth dirservers as up */
static void mark_all_trusteddirservers_up(void) {
if(routerlist) {
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, router,
if(router->is_trusted_dir) {
tor_assert(router->dir_port > 0);
router->is_running = 1;
router->status_set_at = time(NULL);
});
}
if (trusted_dir_servers) {
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, dir,
dir->is_running = 1);
}
}
......@@ -180,6 +237,12 @@ int all_directory_servers_down(void) {
return 0;
}
}
/* XXXX NM look at trusted_dir_servers instead.
if (!trusted_dir_servers)
return 1;
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, dir,
if (dir->is_running) return 0);
*/
return 1;
}
......@@ -477,14 +540,13 @@ routerinfo_t *router_get_by_nickname(const char *nickname)
return NULL;
}
/* XXX008 currently this trusted_dir_digests stuff is not used. */
/** Return true iff <b>digest</b> is the digest of the identity key of
* a trusted directory. */
int router_digest_is_trusted_dir(const char *digest) {
if (!trusted_dir_digests)
if (!trusted_dir_servers)
return 0;
SMARTLIST_FOREACH(trusted_dir_digests, char *, cp,
if (!memcmp(digest, cp, DIGEST_LEN)) return 1);
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, ent,
if (!memcmp(digest, ent->digest, DIGEST_LEN)) return 1);
return 0;
}
......@@ -586,6 +648,11 @@ void routerlist_free(routerlist_t *rl)
void router_mark_as_down(const char *digest) {
routerinfo_t *router;
tor_assert(digest);
SMARTLIST_FOREACH(trusted_dir_servers, trusted_dir_server_t *, d,
if (!memcmp(d->digest, digest, DIGEST_LEN))
d->is_running = 0);
router = router_get_by_digest(digest);
if(!router) /* we don't seem to know about him in the first place */
return;
......@@ -619,7 +686,9 @@ int router_add_to_routerlist(routerinfo_t *router) {
log_fn(LOG_DEBUG, "Replacing entry for router '%s/%s' [%s]",
router->nickname, r->nickname, hex_str(id_digest,DIGEST_LEN));
/* Remember whether we trust this router as a dirserver. */
if (r->is_trusted_dir)
/*XXXXNM first test is redundant; second should move elsewhere */
if (r->is_trusted_dir ||
router_digest_is_trusted_dir(router->identity_digest))
router->is_trusted_dir = 1;
/* If the address hasn't changed; no need to re-resolve. */
if (!strcasecmp(r->address, router->address))
......@@ -735,10 +804,7 @@ void routerlist_clear_trusted_directories(void)
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, r,
r->is_trusted_dir = 0);
}
if (trusted_dir_digests) {
SMARTLIST_FOREACH(trusted_dir_digests, char *, cp, tor_free(cp));
smartlist_clear(trusted_dir_digests);
}
clear_trusted_dir_servers();
}
/** Helper function: read routerinfo elements from s, and throw out the
......@@ -760,17 +826,12 @@ int router_load_routerlist_from_string(const char *s, int trusted)
}
if (trusted) {
int i;
if (!trusted_dir_digests)
trusted_dir_digests = smartlist_create();
for (i=0;i<smartlist_len(new_list->routers);++i) {
routerinfo_t *r = smartlist_get(new_list->routers, i);
if (r->dir_port) {
char *b;
log_fn(LOG_DEBUG,"Trusting router %s.", r->nickname);
r->is_trusted_dir = 1;
b = tor_malloc(DIGEST_LEN);
memcpy(b, r->identity_digest, DIGEST_LEN);
smartlist_add(trusted_dir_digests, b);
add_trusted_dir_server(r->address, r->dir_port, r->identity_digest);
}
}
}
......@@ -1079,6 +1140,38 @@ int router_update_status_from_smartlist(routerinfo_t *router,
return 0;
}
void add_trusted_dir_server(const char *addr, uint16_t port, const char *digest)
{
trusted_dir_server_t *ent;
uint32_t a;
if (!trusted_dir_servers)
trusted_dir_servers = smartlist_create();
if (tor_lookup_hostname(addr, &a)) {
log_fn(LOG_WARN, "Unable to lookup address for directory server at %s",
addr);
return;
}
ent = tor_malloc(sizeof(trusted_dir_server_t));
ent->address = tor_strdup(addr);
ent->addr = a;
ent->dir_port = port;
ent->is_running = 1;
memcpy(ent->digest, digest, DIGEST_LEN);
}
static void clear_trusted_dir_servers(void)
{
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();
}
}
/*
Local Variables:
mode:c
......
......@@ -577,17 +577,12 @@ static crypto_pk_env_t *find_dir_signing_key(const char *str)
static int dir_signing_key_is_trusted(crypto_pk_env_t *key)
{
char digest[DIGEST_LEN];
routerinfo_t *r;
if (!key) return 0;
if (crypto_pk_get_digest(key, digest) < 0) {
log_fn(LOG_WARN, "Error computing dir-signing-key digest");
return 0;
}
if (!(r = router_get_by_digest(digest))) {
log_fn(LOG_WARN, "No router known with given dir-signing-key digest");
return 0;
}
if (! r->is_trusted_dir) {
if(!router_digest_is_trusted_dir(digest)) {
log_fn(LOG_WARN, "Listed dir-signing-key is not trusted");
return 0;
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment