mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-23 14:40:51 +01:00
Remaining 008pre1 items done; deferred where more design is needed.
More docs and (way more!) testing needed. Done: - Authdirservers down directories from others. - Generate and use running-routers lists - Cache directories; store across reboots. - Refactor directory parsing a bit; note potential trouble spots. svn:r1985
This commit is contained in:
parent
e9b882554e
commit
76f769deb9
9 changed files with 340 additions and 58 deletions
19
doc/TODO
19
doc/TODO
|
@ -19,27 +19,30 @@ For scalability:
|
|||
For dtor:
|
||||
|
||||
NICK pre1:
|
||||
. make all ORs serve the directory too.
|
||||
o make all ORs serve the directory too.
|
||||
o "AuthoritativeDir 1" for dirservers
|
||||
o non-authorative servers with dirport publish opt dircacheport
|
||||
o make clients read that and use it.
|
||||
o make clients able to read a normal dirport from non-trusted OR too
|
||||
o make ORs parse-and-keep-and-serve the directory they pull down
|
||||
- authoritativedirservers should pull down directories from
|
||||
o authoritativedirservers should pull down directories from
|
||||
other authdirservers, to merge descriptors.
|
||||
- Have clients and dirservers preserve reputation info over
|
||||
D Have clients and dirservers preserve reputation info over
|
||||
reboots.
|
||||
- allow dirservers to serve running-router list separately.
|
||||
[Deferred until we know what reputation info we actually want to
|
||||
maintain. Our current algorithm Couldn't Possibly Work.]
|
||||
. allow dirservers to serve running-router list separately.
|
||||
o "get /running-routers" will fetch just this.
|
||||
- actually make the clients use this sometimes.
|
||||
- distinguish directory-is-dirty from runninglist-is-dirty
|
||||
o actually make the clients use this sometimes.
|
||||
o distinguish directory-is-dirty from runninglist-is-dirty
|
||||
- ORs keep this too, and serve it
|
||||
- tor remembers descriptor-lists across reboots.
|
||||
- Design: do we need running and non-running lists?
|
||||
o tor remembers descriptor-lists across reboots.
|
||||
. Packages define datadir as /var/lib/tor/. If no datadir is defined,
|
||||
then choose, make, and secure ~/.tor as datadir.
|
||||
o Adjust tor
|
||||
o Change torrc.sample
|
||||
- Change packages
|
||||
D Change packages (not till 0.0.8 packages!)
|
||||
- Look in ~/.torrc if no */etc/torrc is found?
|
||||
o Contact info, pgp fingerprint, comments in router desc.
|
||||
o Add a ContactInfo line to torrc, which gets published in
|
||||
|
|
|
@ -352,6 +352,8 @@ int connection_dir_process_inbuf(connection_t *conn) {
|
|||
}
|
||||
|
||||
if(conn->purpose == DIR_PURPOSE_FETCH_RUNNING_LIST) {
|
||||
running_routers_t *rrs;
|
||||
routerlist_t *rl;
|
||||
/* just update our list of running routers, if this list is new info */
|
||||
log_fn(LOG_INFO,"Received running-routers list (size %d):\n%s", body_len, body);
|
||||
if(status_code != 200) {
|
||||
|
@ -361,7 +363,15 @@ int connection_dir_process_inbuf(connection_t *conn) {
|
|||
connection_mark_for_close(conn);
|
||||
return -1;
|
||||
}
|
||||
/* XXX008 hand 'body' to something that parses a running-routers list. */
|
||||
if (!(rrs = router_parse_runningrouters(body))) {
|
||||
log_fn(LOG_WARN, "Can't parse runningrouters list");
|
||||
free(body); free(headers);
|
||||
connection_mark_for_close(conn);
|
||||
return -1;
|
||||
}
|
||||
router_get_routerlist(&rl);
|
||||
routerlist_update_from_runningrouters(rl,rrs);
|
||||
running_routers_free(rrs);
|
||||
}
|
||||
|
||||
if(conn->purpose == DIR_PURPOSE_UPLOAD_DIR) {
|
||||
|
|
|
@ -16,6 +16,7 @@ extern or_options_t options; /**< command-line and config-file options */
|
|||
|
||||
/** Do we need to regenerate the directory when someone asks for it? */
|
||||
static int the_directory_is_dirty = 1;
|
||||
static int runningrouters_is_dirty = 1;
|
||||
|
||||
static int list_running_servers(char **nicknames_out);
|
||||
static void directory_remove_unrecognized(void);
|
||||
|
@ -406,13 +407,14 @@ void
|
|||
directory_set_dirty()
|
||||
{
|
||||
the_directory_is_dirty = 1;
|
||||
runningrouters_is_dirty = 1;
|
||||
}
|
||||
|
||||
/** Load all descriptors from an earlier directory stored in the string
|
||||
/** Load all descriptors from a directory stored in the string
|
||||
* <b>dir</b>.
|
||||
*/
|
||||
int
|
||||
dirserv_init_from_directory_string(const char *dir)
|
||||
dirserv_load_from_directory_string(const char *dir)
|
||||
{
|
||||
const char *cp = dir;
|
||||
while(1) {
|
||||
|
@ -525,7 +527,9 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
|
|||
"signed-directory\n"
|
||||
"published %s\n"
|
||||
"recommended-software %s\n"
|
||||
"running-routers %s\n\n", published, options.RecommendedVersions, cp);
|
||||
"running-routers %s\n\n",
|
||||
published, options.RecommendedVersions, cp);
|
||||
|
||||
free(cp);
|
||||
i = strlen(s);
|
||||
cp = s+i;
|
||||
|
@ -563,7 +567,7 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
|
|||
log_fn(LOG_WARN,"couldn't base64-encode signature");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (strlcat(s, "-----END SIGNATURE-----\n", maxlen) >= maxlen)
|
||||
goto truncated;
|
||||
|
||||
|
@ -583,6 +587,7 @@ static int cached_directory_len = -1;
|
|||
void dirserv_set_cached_directory(const char *directory, time_t when)
|
||||
{
|
||||
time_t now;
|
||||
char filename[512];
|
||||
if (!options.AuthoritativeDir)
|
||||
return;
|
||||
now = time(NULL);
|
||||
|
@ -591,6 +596,11 @@ void dirserv_set_cached_directory(const char *directory, time_t when)
|
|||
tor_free(cached_directory);
|
||||
cached_directory = tor_strdup(directory);
|
||||
cached_directory_len = strlen(cached_directory);
|
||||
cached_directory_published = when;
|
||||
sprintf(filename,"%s/cached-directory", options.DataDirectory);
|
||||
if(write_str_to_file(filename,cached_directory) < 0) {
|
||||
log_fn(LOG_WARN, "Couldn't write cached directory to disk. Ignoring.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -644,12 +654,70 @@ size_t dirserv_get_directory(const char **directory)
|
|||
return the_directory_len;
|
||||
}
|
||||
|
||||
static char *runningrouters_string=NULL;
|
||||
static size_t runningrouters_len=0;
|
||||
|
||||
/** Replace the current running-routers list with a newly generated one. */
|
||||
static int generate_runningrouters(crypto_pk_env_t *private_key)
|
||||
{
|
||||
char *s, *cp;
|
||||
char digest[DIGEST_LEN];
|
||||
char signature[PK_BYTES];
|
||||
int i, len;
|
||||
char published[33];
|
||||
time_t published_on;
|
||||
|
||||
len = 1024+MAX_NICKNAME_LEN*smartlist_len(descriptor_list);
|
||||
s = tor_malloc_zero(len);
|
||||
if (list_running_servers(&cp))
|
||||
return -1;
|
||||
published_on = time(NULL);
|
||||
strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on));
|
||||
sprintf(s, "network-status\n"
|
||||
"published %s\n"
|
||||
"running-routers %s\n"
|
||||
"directory-signature %s\n"
|
||||
"-----BEGIN SIGNATURE-----\n",
|
||||
published, cp, options.Nickname);
|
||||
free(cp);
|
||||
if (router_get_runningrouters_hash(s,digest)) {
|
||||
log_fn(LOG_WARN,"couldn't compute digest");
|
||||
return -1;
|
||||
}
|
||||
if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) {
|
||||
log_fn(LOG_WARN,"couldn't sign digest");
|
||||
return -1;
|
||||
}
|
||||
|
||||
i = strlen(s);
|
||||
cp = s+i;
|
||||
if (base64_encode(cp, len-i, signature, 128) < 0) {
|
||||
log_fn(LOG_WARN,"couldn't base64-encode signature");
|
||||
return -1;
|
||||
}
|
||||
if (strlcat(s, "-----END SIGNATURE-----\n", len) >= len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tor_free(runningrouters_string);
|
||||
runningrouters_string = s;
|
||||
runningrouters_len = strlen(s);
|
||||
runningrouters_is_dirty = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Set *<b>rr</b> to the most recently generated encoded signed
|
||||
* running-routers list, generating a new one as necessary. */
|
||||
size_t dirserv_get_runningrouters(const char **rr)
|
||||
{
|
||||
/* XXX008 fill in this function */
|
||||
return 0;
|
||||
if (runningrouters_is_dirty) {
|
||||
if(generate_runningrouters(get_identity_key())) {
|
||||
log_fn(LOG_ERR, "Couldn't generate running-routers list?");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*rr = runningrouters_string;
|
||||
return runningrouters_len;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -451,9 +451,8 @@ static void run_scheduled_events(time_t now) {
|
|||
router_rebuild_descriptor();
|
||||
router_upload_dir_desc_to_dirservers();
|
||||
}
|
||||
if(!options.DirPort) {
|
||||
/* NOTE directory servers do not currently fetch directories.
|
||||
* Hope this doesn't bite us later. */
|
||||
if(!options.DirPort || !options.AuthoritativeDir) {
|
||||
/* XXXX should directories do this next part too? */
|
||||
routerlist_remove_old_routers(); /* purge obsolete entries */
|
||||
directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 0);
|
||||
} else {
|
||||
|
@ -461,6 +460,8 @@ static void run_scheduled_events(time_t now) {
|
|||
dirserv_remove_old_servers();
|
||||
/* dirservers try to reconnect too, in case connections have failed */
|
||||
router_retry_connections();
|
||||
/* fetch another directory, in case it knows something we don't */
|
||||
directory_get_from_dirserver(DIR_PURPOSE_FETCH_DIR, NULL, 0);
|
||||
}
|
||||
/* Force an upload of our descriptors every DirFetchPostPeriod seconds. */
|
||||
rend_services_upload(1);
|
||||
|
|
14
src/or/or.h
14
src/or/or.h
|
@ -595,10 +595,17 @@ typedef struct {
|
|||
* published?
|
||||
*/
|
||||
time_t published_on;
|
||||
time_t running_routers_updated_on;
|
||||
/** Which router is claimed to have signed it? */
|
||||
char *signing_router;
|
||||
} routerlist_t;
|
||||
|
||||
/* DOCDOC */
|
||||
typedef struct running_routers_t {
|
||||
time_t published_on;
|
||||
smartlist_t *running_routers;
|
||||
} running_routers_t;
|
||||
|
||||
/** Holds accounting information for a single step in the layered encryption
|
||||
* performed by a circuit. Used only at the client edge of a circuit. */
|
||||
struct crypt_path_t {
|
||||
|
@ -1130,7 +1137,7 @@ int dirserv_parse_fingerprint_file(const char *fname);
|
|||
int dirserv_router_fingerprint_is_known(const routerinfo_t *router);
|
||||
void dirserv_free_fingerprint_list();
|
||||
int dirserv_add_descriptor(const char **desc);
|
||||
int dirserv_init_from_directory_string(const char *dir);
|
||||
int dirserv_load_from_directory_string(const char *dir);
|
||||
void dirserv_free_descriptors();
|
||||
void dirserv_remove_old_servers(void);
|
||||
int dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
|
||||
|
@ -1352,11 +1359,15 @@ int router_compare_addr_to_exit_policy(uint32_t addr, uint16_t port,
|
|||
#define ADDR_POLICY_UNKNOWN 1
|
||||
int router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port);
|
||||
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);
|
||||
|
||||
/********************************* routerparse.c ************************/
|
||||
|
||||
int router_get_router_hash(const char *s, char *digest);
|
||||
int router_get_dir_hash(const char *s, char *digest);
|
||||
int router_get_runningrouters_hash(const char *s, char *digest);
|
||||
int router_parse_list_from_string(const char **s,
|
||||
routerlist_t **dest,
|
||||
int n_good_nicknames,
|
||||
|
@ -1364,6 +1375,7 @@ int router_parse_list_from_string(const char **s,
|
|||
int router_parse_routerlist_from_directory(const char *s,
|
||||
routerlist_t **dest,
|
||||
crypto_pk_env_t *pkey);
|
||||
running_routers_t *router_parse_runningrouters(const char *str);
|
||||
routerinfo_t *router_parse_entry_from_string(const char *s, const char *end);
|
||||
int router_add_exit_policy_from_string(routerinfo_t *router, const char *s);
|
||||
struct exit_policy_t *router_parse_exit_policy_from_string(const char *s);
|
||||
|
|
|
@ -248,6 +248,45 @@ void rep_hist_dump_stats(time_t now, int severity)
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void write_rep_history(const char *filename)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
char *tmpfile;
|
||||
int completed = 0;
|
||||
or_history_t *or_history;
|
||||
link_history_t *link_history;
|
||||
strmap_iter_t *lhist_it;
|
||||
strmap_iter_t *orhist_it;
|
||||
void *or_history_p, *link_history_p;
|
||||
const char *name1;
|
||||
|
||||
tmpfile = tor_malloc(strlen(filename)+5);
|
||||
strcpy(tmpfile, filename);
|
||||
strcat(tmpfile, "_tmp");
|
||||
|
||||
f = fopen(tmpfile, "w");
|
||||
if (!f) goto done;
|
||||
for (orhist_it = strmap_iter_init(history_map); !strmap_iter_done(orhist_it);
|
||||
orhist_it = strmap_iter_next(history_map,orhist_it)) {
|
||||
strmap_iter_get(orhist_it, &name1, &or_history_p);
|
||||
or_history = (or_history_t*) or_history_p;
|
||||
fprintf(f, "link %s connected:u%ld failed:%uld uptime:%uld",
|
||||
name1, or_history->since1,
|
||||
}
|
||||
|
||||
|
||||
done:
|
||||
if (f)
|
||||
fclose(f);
|
||||
if (completed)
|
||||
replace_file(filename, tmpfile);
|
||||
else
|
||||
unlink(tmpfile);
|
||||
tor_free(tmpfile);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
|
|
|
@ -284,12 +284,14 @@ int init_keys(void) {
|
|||
if(!cp) {
|
||||
log_fn(LOG_INFO,"Cached directory %s not present. Ok.",keydir);
|
||||
} else {
|
||||
if(dirserv_init_from_directory_string(cp) < 0) {
|
||||
if(options.AuthoritativeDir && dirserv_load_from_directory_string(cp) < 0){
|
||||
log_fn(LOG_ERR, "Cached directory %s is corrupt", keydir);
|
||||
free(cp);
|
||||
return -1;
|
||||
}
|
||||
free(cp);
|
||||
/* set time to 1 so it will be replaced on first download.
|
||||
*/
|
||||
dirserv_set_cached_directory(cp, 1);
|
||||
}
|
||||
/* success */
|
||||
return 0;
|
||||
|
|
|
@ -477,7 +477,11 @@ int router_load_routerlist_from_directory(const char *s,
|
|||
log_fn(LOG_WARN, "Error resolving routerlist");
|
||||
return -1;
|
||||
}
|
||||
/* Remember the directory, if we're nonauthoritative.*/
|
||||
dirserv_set_cached_directory(s, routerlist->published_on);
|
||||
/* Learn about the descriptors in the directory, if we're authoritative */
|
||||
if (options.AuthoritativeDir)
|
||||
dirserv_load_from_directory_string(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -621,6 +625,50 @@ int router_exit_policy_rejects_all(routerinfo_t *router) {
|
|||
== ADDR_POLICY_REJECTED;
|
||||
}
|
||||
|
||||
/* DODCDOC */
|
||||
void running_routers_free(running_routers_t *rr)
|
||||
{
|
||||
tor_assert(rr);
|
||||
if (rr->running_routers) {
|
||||
SMARTLIST_FOREACH(rr->running_routers, char *, s, tor_free(s));
|
||||
smartlist_free(rr->running_routers);
|
||||
}
|
||||
tor_free(rr);
|
||||
}
|
||||
|
||||
/* DOCDOC*/
|
||||
void routerlist_update_from_runningrouters(routerlist_t *list,
|
||||
running_routers_t *rr)
|
||||
{
|
||||
int n_routers, n_names, i, j, running;
|
||||
routerinfo_t *router;
|
||||
const char *name;
|
||||
if (!routerlist)
|
||||
return;
|
||||
if (routerlist->published_on >= rr->published_on)
|
||||
return;
|
||||
if (routerlist->running_routers_updated_on >= rr->published_on)
|
||||
return;
|
||||
|
||||
n_routers = smartlist_len(list->routers);
|
||||
n_names = smartlist_len(rr->running_routers);
|
||||
for (i=0; i<n_routers; ++i) {
|
||||
running = 0;
|
||||
router = smartlist_get(list->routers, i);
|
||||
for (j=0; j<n_names; ++j) {
|
||||
name = smartlist_get(rr->running_routers, j);
|
||||
if (!strcmp(name, router->nickname)) {
|
||||
running=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
router->is_running = 1; /* arma: is this correct? */
|
||||
}
|
||||
routerlist->running_routers_updated_on = rr->published_on;
|
||||
/* XXXX008 Should there also be a list of which are down, so that we
|
||||
* don't mark merely unknown routers as down? */
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode:c
|
||||
|
|
|
@ -41,6 +41,7 @@ typedef enum {
|
|||
K_PORTS,
|
||||
K_DIRCACHEPORT,
|
||||
K_CONTACT,
|
||||
K_NETWORK_STATUS,
|
||||
_UNRECOGNIZED,
|
||||
_ERR,
|
||||
_EOF,
|
||||
|
@ -88,7 +89,7 @@ typedef enum {
|
|||
typedef enum {
|
||||
ANY = 0, /**< Appears in router descriptor or in directory sections. */
|
||||
DIR_ONLY, /**< Appears only in directory. */
|
||||
RTR_ONLY, /**< Appears only in router descriptor. */
|
||||
RTR_ONLY, /**< Appears only in router descriptor or runningrouters */
|
||||
} where_syntax;
|
||||
|
||||
/** Table mapping keywords to token value and to argument rules. */
|
||||
|
@ -113,6 +114,7 @@ static struct {
|
|||
{ "opt", K_OPT, CONCAT_ARGS, OBJ_OK, ANY },
|
||||
{ "dircacheport", K_DIRCACHEPORT, ARGS, NO_OBJ, RTR_ONLY },
|
||||
{ "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ, ANY },
|
||||
{ "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ, DIR_ONLY },
|
||||
{ NULL, -1 }
|
||||
};
|
||||
|
||||
|
@ -128,6 +130,10 @@ static directory_token_t *find_first_by_keyword(smartlist_t *s,
|
|||
static int tokenize_string(const char *start, const char *end,
|
||||
smartlist_t *out, int is_dir);
|
||||
static directory_token_t *get_next_token(const char **s, where_syntax where);
|
||||
static int check_directory_signature(const char *digest,
|
||||
directory_token_t *tok,
|
||||
crypto_pk_env_t *pkey);
|
||||
|
||||
|
||||
/** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
|
||||
* <b>s</b>. Return 0 on success, nonzero on failure.
|
||||
|
@ -147,6 +153,13 @@ int router_get_router_hash(const char *s, char *digest)
|
|||
"router ","router-signature");
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
int router_get_runningrouters_hash(const char *s, char *digest)
|
||||
{
|
||||
return router_get_hash_impl(s,digest,
|
||||
"network-status ","directory-signature");
|
||||
}
|
||||
|
||||
/** Parse a date of the format "YYYY-MM-DD hh:mm:ss" and store the result into
|
||||
* *<b>t</b>.
|
||||
*/
|
||||
|
@ -273,13 +286,12 @@ router_parse_routerlist_from_directory(const char *str,
|
|||
crypto_pk_env_t *pkey)
|
||||
{
|
||||
directory_token_t *tok;
|
||||
char digest[20];
|
||||
char signed_digest[128];
|
||||
char digest[DIGEST_LEN];
|
||||
routerlist_t *new_dir = NULL;
|
||||
char *versions = NULL;
|
||||
time_t published_on;
|
||||
char *good_nickname_lst[1024];
|
||||
int n_good_nicknames = 0;
|
||||
char *good_nickname_lst[1024]; /* XXXX008 correct this limit. */
|
||||
time_t published_on;
|
||||
int i, r;
|
||||
const char *end;
|
||||
smartlist_t *tokens = NULL;
|
||||
|
@ -373,40 +385,9 @@ router_parse_routerlist_from_directory(const char *str,
|
|||
(tok->tp != K_DIRECTORY_SIGNATURE)) {
|
||||
log_fn(LOG_WARN,"Expected a single directory signature"); goto err;
|
||||
}
|
||||
if (tok->n_args == 1) {
|
||||
routerinfo_t *r = router_get_by_nickname(tok->args[0]);
|
||||
log_fn(LOG_DEBUG, "Got directory signed by %s", tok->args[0]);
|
||||
if (r && r->is_trusted_dir) {
|
||||
pkey = r->identity_pkey;
|
||||
} else if (!r && pkey) {
|
||||
/* pkey provided for debugging purposes. */
|
||||
} else if (!r) {
|
||||
log_fn(LOG_WARN, "Directory was signed by unrecognized server %s",
|
||||
tok->args[0]);
|
||||
goto err;
|
||||
} else if (r && !r->is_trusted_dir) {
|
||||
log_fn(LOG_WARN, "Directory was signed by non-trusted server %s",
|
||||
tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
|
||||
log_fn(LOG_WARN, "Bad object type or length on directory signature");
|
||||
if (check_directory_signature(digest, smartlist_get(tokens,0), pkey)<0) {
|
||||
goto err;
|
||||
}
|
||||
if (pkey) {
|
||||
if (crypto_pk_public_checksig(pkey, tok->object_body, 128, signed_digest)
|
||||
!= 20) {
|
||||
log_fn(LOG_WARN, "Error reading directory: invalid signature.");
|
||||
goto err;
|
||||
}
|
||||
log(LOG_DEBUG,"Signed directory hash starts %s", hex_str(signed_digest,4));
|
||||
|
||||
if (memcmp(digest, signed_digest, 20)) {
|
||||
log_fn(LOG_WARN, "Error reading directory: signature does not match.");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (*dest)
|
||||
routerlist_free(*dest);
|
||||
|
@ -430,6 +411,124 @@ router_parse_routerlist_from_directory(const char *str,
|
|||
return r;
|
||||
}
|
||||
|
||||
running_routers_t *
|
||||
router_parse_runningrouters(const char *str)
|
||||
{
|
||||
char digest[DIGEST_LEN];
|
||||
running_routers_t *new_list = NULL;
|
||||
directory_token_t *tok;
|
||||
time_t published_on;
|
||||
int i;
|
||||
|
||||
smartlist_t *tokens = NULL;
|
||||
|
||||
if (router_get_runningrouters_hash(str, digest)) {
|
||||
log_fn(LOG_WARN, "Unable to compute digest of directory");
|
||||
goto err;
|
||||
}
|
||||
tokens = smartlist_create();
|
||||
if (tokenize_string(str,str+strlen(str),tokens,1)) {
|
||||
log_fn(LOG_WARN, "Error tokenizing directory"); goto err;
|
||||
}
|
||||
if ((tok = find_first_by_keyword(tokens, _UNRECOGNIZED))) {
|
||||
log_fn(LOG_WARN, "Unrecognized keyword in \"%s\"; can't parse directory.",
|
||||
tok->args[0]);
|
||||
goto err;
|
||||
}
|
||||
tok = smartlist_get(tokens,0);
|
||||
if (tok->tp != K_NETWORK_STATUS) {
|
||||
log_fn(LOG_WARN, "Network-status starts with wrong token");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(tok = find_first_by_keyword(tokens, K_PUBLISHED))) {
|
||||
log_fn(LOG_WARN, "Missing published time on directory.");
|
||||
goto err;
|
||||
}
|
||||
tor_assert(tok->n_args == 1);
|
||||
if (parse_time(tok->args[0], &published_on) < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(tok = find_first_by_keyword(tokens, K_RUNNING_ROUTERS))) {
|
||||
log_fn(LOG_WARN, "Missing running-routers 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();
|
||||
for (i=0;i<tok->n_args;++i) {
|
||||
smartlist_add(new_list->running_routers, tok->args[i]);
|
||||
}
|
||||
|
||||
if (!(tok = find_first_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
|
||||
log_fn(LOG_WARN, "Missing signature on directory");
|
||||
goto err;
|
||||
}
|
||||
if (check_directory_signature(digest, tok, NULL)<0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
goto done;
|
||||
err:
|
||||
running_routers_free(new_list);
|
||||
new_list = NULL;
|
||||
done:
|
||||
if (tokens) {
|
||||
SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
|
||||
smartlist_free(tokens);
|
||||
}
|
||||
return new_list;
|
||||
}
|
||||
|
||||
static int check_directory_signature(const char *digest,
|
||||
directory_token_t *tok,
|
||||
crypto_pk_env_t *pkey)
|
||||
{
|
||||
char signed_digest[PK_BYTES];
|
||||
if (tok->n_args == 1) {
|
||||
routerinfo_t *r = router_get_by_nickname(tok->args[0]);
|
||||
log_fn(LOG_DEBUG, "Got directory signed by %s", tok->args[0]);
|
||||
if (r && r->is_trusted_dir) {
|
||||
pkey = r->identity_pkey;
|
||||
} else if (!r && pkey) {
|
||||
/* pkey provided for debugging purposes. */
|
||||
} else if (!r) {
|
||||
log_fn(LOG_WARN, "Directory was signed by unrecognized server %s",
|
||||
tok->args[0]);
|
||||
return -1;
|
||||
} else if (r && !r->is_trusted_dir) {
|
||||
log_fn(LOG_WARN, "Directory was signed by non-trusted server %s",
|
||||
tok->args[0]);
|
||||
return -1;
|
||||
}
|
||||
} else if (tok->n_args > 1) {
|
||||
log_fn(LOG_WARN, "Too many arguments to directory-signature");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
|
||||
log_fn(LOG_WARN, "Bad object type or length on directory signature");
|
||||
return -1;
|
||||
}
|
||||
if (pkey) {
|
||||
if (crypto_pk_public_checksig(pkey, tok->object_body, 128, signed_digest)
|
||||
!= 20) {
|
||||
log_fn(LOG_WARN, "Error reading directory: invalid signature.");
|
||||
return -1;
|
||||
}
|
||||
log(LOG_DEBUG,"Signed directory hash starts %s", hex_str(signed_digest,4));
|
||||
if (memcmp(digest, signed_digest, 20)) {
|
||||
log_fn(LOG_WARN, "Error reading directory: signature does not match.");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* XXXX008 freak out, unless testing. */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** Given a string *<b>s</b> containing a concatenated
|
||||
* sequence of router descriptors, parses them and stores the result
|
||||
* in *<b>dest</b>. If good_nickname_lst is provided, then routers whose
|
||||
|
|
Loading…
Add table
Reference in a new issue