diff options
author | Nick Mathewson <nickm@torproject.org> | 2004-06-25 00:29:31 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2004-06-25 00:29:31 +0000 |
commit | 76f769deb9dab9e68cb2dd49c6a5a852f2ca2cd7 (patch) | |
tree | 8b833310f12954d9ebf61d267c61f87c7481afbf /src/or/routerparse.c | |
parent | e9b882554e44641011e3ee5be26e7cc200f3dd71 (diff) | |
download | tor-76f769deb9dab9e68cb2dd49c6a5a852f2ca2cd7.tar.gz tor-76f769deb9dab9e68cb2dd49c6a5a852f2ca2cd7.zip |
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
Diffstat (limited to 'src/or/routerparse.c')
-rw-r--r-- | src/or/routerparse.c | 163 |
1 files changed, 131 insertions, 32 deletions
diff --git a/src/or/routerparse.c b/src/or/routerparse.c index efd8f3731b..60daf0e33f 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.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,6 +385,108 @@ 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 (check_directory_signature(digest, smartlist_get(tokens,0), pkey)<0) { + goto err; + } + + if (*dest) + routerlist_free(*dest); + *dest = new_dir; + + r = 0; + goto done; + err: + r = -1; + if (new_dir) + routerlist_free(new_dir); + tor_free(versions); + for (i = 0; i < n_good_nicknames; ++i) { + tor_free(good_nickname_lst[i]); + } + done: + if (tokens) { + SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok)); + smartlist_free(tokens); + } + 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]); @@ -383,53 +497,38 @@ router_parse_routerlist_from_directory(const char *str, } else if (!r) { log_fn(LOG_WARN, "Directory was signed by unrecognized server %s", tok->args[0]); - goto err; + return -1; } else if (r && !r->is_trusted_dir) { log_fn(LOG_WARN, "Directory was signed by non-trusted server %s", tok->args[0]); - goto err; + 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"); - goto err; + 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."); - goto err; + 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."); - goto err; + return -1; } + } else { + /* XXXX008 freak out, unless testing. */ } - - if (*dest) - routerlist_free(*dest); - *dest = new_dir; - - r = 0; - goto done; - err: - r = -1; - if (new_dir) - routerlist_free(new_dir); - tor_free(versions); - for (i = 0; i < n_good_nicknames; ++i) { - tor_free(good_nickname_lst[i]); - } - done: - if (tokens) { - SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok)); - smartlist_free(tokens); - } - return r; + 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 |