Add and document router-status line using new unified liveness/verifiedness format; continue to generate running-routers; continue to parse running-routers when no router-status line is found

svn:r2592
This commit is contained in:
Nick Mathewson
2004-10-27 00:48:51 +00:00
parent 26f3cb8652
commit b90b2bb848
5 changed files with 283 additions and 160 deletions
+83 -68
View File
@@ -20,7 +20,8 @@ extern or_options_t options; /**< command-line and config-file options */
static int the_directory_is_dirty = 1;
static int runningrouters_is_dirty = 1;
static int list_running_servers(char **nicknames_out);
static int list_server_status(char **running_routers_out,
char **router_status_out);
static void directory_remove_unrecognized(void);
static int dirserv_regenerate_directory(void);
@@ -456,71 +457,80 @@ dirserv_load_from_directory_string(const char *dir)
return 0;
}
/** Set *<b>nicknames_out</b> to a comma-separated list of all the ORs that we
* believe are currently running (because we have open connections to
* them). Return 0 on success; -1 on error.
/**
* Allocate and return a description of the status of the server <b>desc</b>,
* for use in a running-routers line (if <b>rr_format</b> is true), or in a
* router-status line (if <b>rr_format</b> is false. The server is listed
* as running iff <b>is_live</b> is true.
*/
static char *
list_single_server_status(descriptor_entry_t *desc, int is_live,
int rr_format)
{
char buf[MAX_NICKNAME_LEN+HEX_DIGEST_LEN+4]; /* !nickname=$hexdigest\0 */
char *cp;
tor_assert(desc);
tor_assert(desc->router);
cp = buf;
if (!is_live) {
*cp++ = '!';
}
if (desc->verified) {
strcpy(cp, desc->nickname);
cp += strlen(cp);
if (!rr_format)
*cp++ = '=';
}
if (!desc->verified || !rr_format) {
*cp++ = '$';
base16_encode(cp, HEX_DIGEST_LEN+1, desc->router->identity_digest,
DIGEST_LEN);
}
return tor_strdup(buf);
}
/** Allocate the contents of a running-routers line and a router-status line,
* and store them in *<b>running_routers_out</b> and *<b>router_status_out</b>
* respectively. Return 0 on success, -1 on failure.
*/
static int
list_running_servers(char **nicknames_out)
list_server_status(char **running_routers_out, char **router_status_out)
{
connection_t **connection_array;
int n_conns;
connection_t *conn;
char *cp;
int i;
size_t length;
smartlist_t *nicknames_up, *nicknames_down;
char *name;
const char *s;
/* List of entries in running-routers style: An optional !, then either
* a nickname or a dollar-prefixed hexdigest. */
smartlist_t *rr_entries;
/* List of entries in a router-status style: An optional !, then an optional
* equals-suffixed nickname, then a dollar-prefixed hexdigest. */
smartlist_t *rs_entries;
*nicknames_out = NULL;
nicknames_up = smartlist_create();
nicknames_down = smartlist_create();
smartlist_add(nicknames_up, tor_strdup(options.Nickname));
tor_assert(running_routers_out || router_status_out);
get_connection_array(&connection_array, &n_conns);
for (i = 0; i<n_conns; ++i) {
conn = connection_array[i];
if (conn->type != CONN_TYPE_OR || !conn->nickname)
continue; /* only list connections to ORs with certificates. */
s = dirserv_get_nickname_by_digest(conn->identity_digest);
if (s) {
name = tor_strdup(s);
} else {
name = tor_malloc(HEX_DIGEST_LEN+2);
*name = '$';
base16_encode(name+1, HEX_DIGEST_LEN+1, conn->identity_digest, DIGEST_LEN);
}
rr_entries = smartlist_create();
rs_entries = smartlist_create();
SMARTLIST_FOREACH(descriptor_list, descriptor_entry_t *, d,
{
int is_live;
tor_assert(d->router);
connection_t *conn = connection_get_by_identity_digest(
d->router->identity_digest, CONN_TYPE_OR);
is_live = (conn && conn->state == OR_CONN_STATE_OPEN);
smartlist_add(rr_entries, list_single_server_status(d, is_live, 1));
smartlist_add(rs_entries, list_single_server_status(d, is_live, 0));
});
if (running_routers_out)
*running_routers_out = smartlist_join_strings(rr_entries, " ", 0);
if (router_status_out)
*router_status_out = smartlist_join_strings(rs_entries, " ", 0);
SMARTLIST_FOREACH(rr_entries, char *, cp, tor_free(cp));
SMARTLIST_FOREACH(rs_entries, char *, cp, tor_free(cp));
smartlist_free(rr_entries);
smartlist_free(rs_entries);
if(conn->state == OR_CONN_STATE_OPEN)
smartlist_add(nicknames_up, name);
else
smartlist_add(nicknames_down, name);
}
length = smartlist_len(nicknames_up) +
2*smartlist_len(nicknames_down) + 1;
/* spaces + EOS + !'s + 1. */
SMARTLIST_FOREACH(nicknames_up, char *, c, length += strlen(c));
SMARTLIST_FOREACH(nicknames_down, char *, c, length += strlen(c));
*nicknames_out = tor_malloc_zero(length);
cp = *nicknames_out;
for (i = 0; i<smartlist_len(nicknames_up); ++i) {
if (i)
strcat(cp, " ");
strcat(cp, (char*)smartlist_get(nicknames_up,i)); /* can't overflow */
while (*cp)
++cp;
}
for (i = 0; i<smartlist_len(nicknames_down); ++i) {
strcat(cp, " !");
strcat(cp, (char*)smartlist_get(nicknames_down,i)); /* can't overflow */
while (*cp)
++cp;
}
SMARTLIST_FOREACH(nicknames_up, char *, victim, tor_free(victim));
SMARTLIST_FOREACH(nicknames_down, char *, victim, tor_free(victim));
smartlist_free(nicknames_up);
smartlist_free(nicknames_down);
return 0;
}
@@ -557,7 +567,8 @@ int
dirserv_dump_directory_to_string(char *s, size_t maxlen,
crypto_pk_env_t *private_key)
{
char *cp, *eos;
char *eos, *cp;
char *running_routers, *router_status;
char *identity_pkey; /* Identity key, DER64-encoded. */
char *recommended_versions;
char digest[20];
@@ -570,7 +581,7 @@ dirserv_dump_directory_to_string(char *s, size_t maxlen,
if (!descriptor_list)
descriptor_list = smartlist_create();
if (list_running_servers(&cp))
if (list_server_status(&running_routers, &router_status))
return -1;
/* ASN.1-encode the public key. This is a temporary measure; once
@@ -612,10 +623,13 @@ dirserv_dump_directory_to_string(char *s, size_t maxlen,
"published %s\n"
"recommended-software %s\n"
"running-routers %s\n"
"opt router-status %s\n"
"opt dir-signing-key %s\n\n",
published, recommended_versions, cp, identity_pkey);
published, recommended_versions, running_routers, router_status,
identity_pkey);
tor_free(cp);
tor_free(running_routers);
tor_free(router_status);
tor_free(identity_pkey);
i = strlen(s);
cp = s+i;
@@ -788,6 +802,7 @@ static size_t runningrouters_len=0;
static int generate_runningrouters(crypto_pk_env_t *private_key)
{
char *s, *cp;
char *router_status;
char digest[DIGEST_LEN];
char signature[PK_BYTES];
int i;
@@ -798,7 +813,7 @@ static int generate_runningrouters(crypto_pk_env_t *private_key)
len = 1024+(MAX_HEX_NICKNAME_LEN+2)*smartlist_len(descriptor_list);
s = tor_malloc_zero(len);
if (list_running_servers(&cp))
if (list_server_status(NULL, &router_status))
return -1;
/* ASN.1-encode the public key. This is a temporary measure; once
* everyone is running 0.0.9pre3 or later, we can shift to using a
@@ -822,12 +837,12 @@ static int generate_runningrouters(crypto_pk_env_t *private_key)
format_iso_time(published, published_on);
sprintf(s, "network-status\n"
"published %s\n"
"running-routers %s\n"
"router-status %s\n"
"opt dir-signing-key %s\n"
"directory-signature %s\n"
"-----BEGIN SIGNATURE-----\n",
published, cp, identity_pkey, options.Nickname);
tor_free(cp);
published, router_status, identity_pkey, options.Nickname);
tor_free(router_status);
tor_free(identity_pkey);
if (router_get_runningrouters_hash(s,digest)) {
log_fn(LOG_WARN,"couldn't compute digest");
+8 -1
View File
@@ -621,6 +621,7 @@ typedef struct running_routers_t {
time_t published_on; /**< When was the list marked as published? */
/** Which ORs are on the list? Entries may be prefixed with ! and $. */
smartlist_t *running_routers;
int is_running_routers_format; /**< Are we using the old entry format? */
} running_routers_t;
/** Holds accounting information for a single step in the layered encryption
@@ -1469,9 +1470,14 @@ int router_exit_policy_rejects_all(routerinfo_t *router);
void running_routers_free(running_routers_t *rr);
void routerlist_update_from_runningrouters(routerlist_t *list,
running_routers_t *rr);
int routers_update_status_from_entry(smartlist_t *routers,
time_t list_time,
const char *s,
int rr_format);
int router_update_status_from_smartlist(routerinfo_t *r,
time_t list_time,
smartlist_t *running_list);
smartlist_t *running_list,
int rr_format);
void add_trusted_dir_server(const char *addr, uint16_t port,const char *digest);
void clear_trusted_dir_servers(void);
@@ -1493,6 +1499,7 @@ int router_get_runningrouters_hash(const char *s, char *digest);
int router_parse_list_from_string(const char **s,
routerlist_t **dest,
smartlist_t *good_nickname_list,
int rr_format,
time_t published);
int router_parse_routerlist_from_directory(const char *s,
routerlist_t **dest,
+124 -61
View File
@@ -1018,8 +1018,8 @@ void running_routers_free(running_routers_t *rr)
void routerlist_update_from_runningrouters(routerlist_t *list,
running_routers_t *rr)
{
int n_routers, i;
routerinfo_t *router, *me = router_get_my_routerinfo();
routerinfo_t *me = router_get_my_routerinfo();
smartlist_t *all_routers;
if (!list)
return;
if (list->published_on >= rr->published_on)
@@ -1027,18 +1027,15 @@ void routerlist_update_from_runningrouters(routerlist_t *list,
if (list->running_routers_updated_on >= rr->published_on)
return;
if(me) { /* learn if the dirservers think I'm verified */
router_update_status_from_smartlist(me,
rr->published_on,
rr->running_routers);
}
n_routers = smartlist_len(list->routers);
for (i=0; i<n_routers; ++i) {
router = smartlist_get(list->routers, i);
router_update_status_from_smartlist(router,
rr->published_on,
rr->running_routers);
}
all_routers = smartlist_create();
if(me) /* learn if the dirservers think I'm verified */
smartlist_add(all_routers, me);
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,
cp, rr->is_running_routers_format));
smartlist_free(all_routers);
list->running_routers_updated_on = rr->published_on;
}
@@ -1046,6 +1043,14 @@ void routerlist_update_from_runningrouters(routerlist_t *list,
* 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.
* (running-routers format)
* <li> !<b>nickname</b> -- router is not-running and verified.
* (running-routers format)
* <li> <b>nickname</b>=$<b>hexdigest</b> -- router is running and
* verified. (router-status format)
* (router-status format)
* <li> !<b>nickname</b>=$<b>hexdigest</b> -- router is running and
* verified. (router-status format)
* <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.
@@ -1053,57 +1058,115 @@ void routerlist_update_from_runningrouters(routerlist_t *list,
*
* Return 1 if we found router in running_list, else return 0.
*/
int router_update_status_from_smartlist(routerinfo_t *router,
time_t list_time,
smartlist_t *running_list)
int routers_update_status_from_entry(smartlist_t *routers,
time_t list_time,
const char *s,
int rr_format)
{
int n_names, i, running, approved;
const char *name;
#if 1
char *cp;
size_t n;
n = 0;
for (i=0; i<smartlist_len(running_list); ++i) {
name = smartlist_get(running_list, i);
n += strlen(name) + 1;
}
cp = tor_malloc(n+2);
cp[0] = '\0';
for (i=0; i<smartlist_len(running_list); ++i) {
name = smartlist_get(running_list, i);
strlcat(cp, name, n);
strlcat(cp, " ", n);
}
log_fn(LOG_DEBUG, "Updating status of %s from list \"%s\"",
router->nickname, cp);
tor_free(cp);
#endif
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;
running = approved = 0;
n_names = smartlist_len(running_list);
for (i=0; i<n_names; ++i) {
name = smartlist_get(running_list, i);
if (*name != '!') {
if (router_nickname_matches(router, name)) {
if (router->status_set_at < list_time) {
router->status_set_at = list_time;
router->is_running = 1;
}
router->is_verified = (name[0] != '$');
return 1;
}
} else { /* *name == '!' */
name++;
if (router_nickname_matches(router, name)) {
if (router->status_set_at < list_time) {
router->status_set_at = list_time;
router->is_running = 0;
}
router->is_verified = (name[0] != '$');
return 1;
}
/* First, parse the entry. */
cp = s;
if (*cp == '!') {
is_running = 0;
++cp;
}
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)",
end-cp, s);
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;
}
/* '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)",
strlen(cp), s);
return -1;
}
strcpy(hexdigest, cp);
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;
}
}
/* Make sure that the entry was in the right format. */
if (rr_format) {
if (is_verified == hex_digest_set) {
log_fn(LOG_WARN, "Invalid syntax for running-routers member (%s)", s);
return -1;
}
} else {
if (!hex_digest_set) {
log_fn(LOG_WARN, "Invalid syntax for router-status member (%s)", s);
return -1;
}
}
/* 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);
if (nickname_matches && (digest_matches||rr_format))
r->is_verified = 1;
else if (digest_matches)
r->is_verified = 0;
if (digest_matches || (nickname_matches&&rr_format))
if (r->status_set_at < list_time) {
r->is_running = is_running;
r->status_set_at = time(NULL);
}
});
return 0;
}
int router_update_status_from_smartlist(routerinfo_t *router,
time_t list_time,
smartlist_t *running_list,
int rr_format)
{
smartlist_t *rl;
rl = smartlist_create();
smartlist_add(rl,router);
SMARTLIST_FOREACH(running_list, const char *, cp,
routers_update_status_from_entry(rl,list_time,cp,rr_format));
smartlist_free(rl);
return 0;
}
+42 -26
View File
@@ -32,6 +32,7 @@ typedef enum {
K_ROUTER_SIGNATURE,
K_PUBLISHED,
K_RUNNING_ROUTERS,
K_ROUTER_STATUS,
K_PLATFORM,
K_OPT,
K_BANDWIDTH,
@@ -106,6 +107,7 @@ static struct {
{ "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY,RTR_ONLY },
{ "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ,RTR_ONLY },
{ "running-routers", K_RUNNING_ROUTERS, ARGS, NO_OBJ, DIR_ONLY },
{ "router-status", K_ROUTER_STATUS, ARGS, NO_OBJ, DIR_ONLY },
{ "ports", K_PORTS, ARGS, NO_OBJ, RTR_ONLY },
{ "bandwidth", K_BANDWIDTH, ARGS, NO_OBJ, RTR_ONLY },
{ "platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ, RTR_ONLY },
@@ -393,9 +395,13 @@ router_parse_routerlist_from_directory(const char *str,
}
versions = tok->n_args ? tor_strdup(tok->args[0]) : tor_strdup("");
if (!(tok = find_first_by_keyword(tokens, K_RUNNING_ROUTERS))) {
log_fn(LOG_WARN, "Missing running-routers line from directory.");
goto err;
/* Prefer router-status, then running-routers. */
if (!(tok = find_first_by_keyword(tokens, K_ROUTER_STATUS))) {
if (!(tok = find_first_by_keyword(tokens, K_RUNNING_ROUTERS))) {
log_fn(LOG_WARN,
"Missing running-routers/router-status line from directory.");
goto err;
}
}
good_nickname_list = smartlist_create();
@@ -408,11 +414,28 @@ router_parse_routerlist_from_directory(const char *str,
* router. */
str = end;
if (router_parse_list_from_string(&str, &new_dir,
good_nickname_list, published_on)) {
good_nickname_list,
tok->tp==K_RUNNING_ROUTERS,
published_on)) {
log_fn(LOG_WARN, "Error reading routers from directory");
goto err;
}
/* Determine if my routerinfo is considered verified. */
{
static int have_warned_about_unverified_status = 0;
routerinfo_t *me = router_get_my_routerinfo();
if(me) {
if(router_update_status_from_smartlist(me, published_on,
good_nickname_list,
tok->tp==K_RUNNING_ROUTERS)==1 &&
me->is_verified == 0 && !have_warned_about_unverified_status) {
log_fn(LOG_WARN,"Dirserver %s lists your server as unverified. Please consider sending your identity fingerprint to the tor-ops.", dirnickname);
have_warned_about_unverified_status = 1;
}
}
}
new_dir->software_versions = versions; versions = NULL;
new_dir->published_on = published_on;
@@ -420,20 +443,6 @@ router_parse_routerlist_from_directory(const char *str,
smartlist_free(tokens);
tokens = NULL;
/* Determine if my routerinfo is considered verified. */
{
static int have_warned_about_unverified_status = 0;
routerinfo_t *me = router_get_my_routerinfo();
if(me) {
if(router_update_status_from_smartlist(me, published_on,
good_nickname_list)==1 &&
me->is_verified == 0 && !have_warned_about_unverified_status) {
log_fn(LOG_WARN,"Dirserver %s lists your server as unverified. Please consider sending your identity fingerprint to the tor-ops.", dirnickname);
have_warned_about_unverified_status = 1;
}
}
}
if (*dest)
routerlist_free(*dest);
*dest = new_dir;
@@ -497,14 +506,18 @@ router_parse_runningrouters(const char *str)
goto err;
}
if (!(tok = find_first_by_keyword(tokens, K_RUNNING_ROUTERS))) {
log_fn(LOG_WARN, "Missing running-routers line from directory.");
goto err;
if (!(tok = find_first_by_keyword(tokens, K_ROUTER_STATUS))) {
if (!(tok = find_first_by_keyword(tokens, K_RUNNING_ROUTERS))) {
log_fn(LOG_WARN,
"Missing running-routers/router-status line from directory.");
goto err;
}
}
new_list = tor_malloc_zero(sizeof(running_routers_t));
new_list->published_on = published_on;
new_list->running_routers = smartlist_create();
new_list->is_running_routers_format = (tok->tp == K_RUNNING_ROUTERS);
for (i=0;i<tok->n_args;++i) {
smartlist_add(new_list->running_routers, tok->args[i]);
}
@@ -661,7 +674,7 @@ static int check_directory_signature(const char *digest,
int
router_parse_list_from_string(const char **s, routerlist_t **dest,
smartlist_t *good_nickname_list,
time_t published_on)
int rr_format, time_t published_on)
{
routerinfo_t *router;
smartlist_t *routers;
@@ -692,10 +705,7 @@ router_parse_list_from_string(const char **s, routerlist_t **dest,
continue;
}
if (good_nickname_list) {
router_update_status_from_smartlist(router, published_on,
good_nickname_list);
} else {
if (!good_nickname_list) {
router->is_running = 1; /* start out assuming all dirservers are up */
router->is_verified = 1;
router->status_set_at = time(NULL);
@@ -704,6 +714,12 @@ router_parse_list_from_string(const char **s, routerlist_t **dest,
log_fn(LOG_DEBUG,"just added router #%d.",smartlist_len(routers));
}
if (good_nickname_list) {
SMARTLIST_FOREACH(good_nickname_list, const char *, cp,
routers_update_status_from_entry(routers, published_on,
cp, rr_format));
}
if (*dest)
routerlist_free(*dest);
*dest = tor_malloc_zero(sizeof(routerlist_t));