diff options
Diffstat (limited to 'src/or/routerparse.c')
-rw-r--r-- | src/or/routerparse.c | 305 |
1 files changed, 192 insertions, 113 deletions
diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 2ff546bb1d..970353a43c 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2011, The Tor Project, Inc. */ + * Copyright (c) 2007-2012, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -64,13 +64,13 @@ typedef enum { K_DIR_OPTIONS, K_CLIENT_VERSIONS, K_SERVER_VERSIONS, + K_OR_ADDRESS, K_P, K_R, K_S, K_V, K_W, K_M, - K_EVENTDNS, K_EXTRA_INFO, K_EXTRA_INFO_DIGEST, K_CACHES_EXTRA_INFO, @@ -178,7 +178,7 @@ typedef struct directory_token_t { size_t object_size; /**< Bytes in object_body */ char *object_body; /**< Contents of object, base64-decoded. */ - crypto_pk_env_t *key; /**< For public keys only. Heap-allocated. */ + crypto_pk_t *key; /**< For public keys only. Heap-allocated. */ char *error; /**< For _ERR tokens only. */ } directory_token_t; @@ -263,7 +263,7 @@ typedef struct token_rule_t { /* Argument multiplicity: exactly <b>n</b> arguments. */ #define EQ(n) n,n,0 -/** List of tokens allowable in router descriptors */ +/** List of tokens recognized in router descriptors */ static token_rule_t routerdesc_token_table[] = { T0N("reject", K_REJECT, ARGS, NO_OBJ ), T0N("accept", K_ACCEPT, ARGS, NO_OBJ ), @@ -287,7 +287,7 @@ static token_rule_t routerdesc_token_table[] = { T01("family", K_FAMILY, ARGS, NO_OBJ ), T01("caches-extra-info", K_CACHES_EXTRA_INFO, NO_ARGS, NO_OBJ ), - T01("eventdns", K_EVENTDNS, ARGS, NO_OBJ ), + T0N("or-address", K_OR_ADDRESS, GE(1), NO_OBJ ), T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), T1( "bandwidth", K_BANDWIDTH, GE(3), NO_OBJ ), @@ -296,7 +296,7 @@ static token_rule_t routerdesc_token_table[] = { END_OF_TABLE }; -/** List of tokens allowable in extra-info documents. */ +/** List of tokens recognized in extra-info documents. */ static token_rule_t extrainfo_token_table[] = { T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ), T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), @@ -333,7 +333,7 @@ static token_rule_t extrainfo_token_table[] = { END_OF_TABLE }; -/** List of tokens allowable in the body part of v2 and v3 networkstatus +/** List of tokens recognized in the body part of v2 and v3 networkstatus * documents. */ static token_rule_t rtrstatus_token_table[] = { T01("p", K_P, CONCAT_ARGS, NO_OBJ ), @@ -346,7 +346,7 @@ static token_rule_t rtrstatus_token_table[] = { END_OF_TABLE }; -/** List of tokens allowable in the header part of v2 networkstatus documents. +/** List of tokens recognized in the header part of v2 networkstatus documents. */ static token_rule_t netstatus_token_table[] = { T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ), @@ -364,14 +364,14 @@ static token_rule_t netstatus_token_table[] = { END_OF_TABLE }; -/** List of tokens allowable in the footer of v1/v2 directory/networkstatus +/** List of tokens recognized in the footer of v1/v2 directory/networkstatus * footers. */ static token_rule_t dir_footer_token_table[] = { T1("directory-signature", K_DIRECTORY_SIGNATURE, EQ(1), NEED_OBJ ), END_OF_TABLE }; -/** List of tokens allowable in v1 directory headers/footers. */ +/** List of tokens recognized in v1 directory headers/footers. */ static token_rule_t dir_token_table[] = { /* don't enforce counts; this is obsolete. */ T( "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ ), @@ -403,14 +403,14 @@ static token_rule_t dir_token_table[] = { NO_ARGS, NEED_OBJ), \ T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ), -/** List of tokens allowable in V3 authority certificates. */ +/** List of tokens recognized in V3 authority certificates. */ static token_rule_t dir_key_certificate_table[] = { CERTIFICATE_MEMBERS T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ), END_OF_TABLE }; -/** List of tokens allowable in rendezvous service descriptors */ +/** List of tokens recognized in rendezvous service descriptors */ static token_rule_t desc_token_table[] = { T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR, EQ(1), NO_OBJ), @@ -424,7 +424,7 @@ static token_rule_t desc_token_table[] = { END_OF_TABLE }; -/** List of tokens allowed in the (encrypted) list of introduction points of +/** List of tokens recognized in the (encrypted) list of introduction points of * rendezvous service descriptors */ static token_rule_t ipo_token_table[] = { T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ), @@ -435,7 +435,7 @@ static token_rule_t ipo_token_table[] = { END_OF_TABLE }; -/** List of tokens allowed in the (possibly encrypted) list of introduction +/** List of tokens recognized in the (possibly encrypted) list of introduction * points of rendezvous service descriptors */ static token_rule_t client_keys_token_table[] = { T1_START("client-name", C_CLIENT_NAME, CONCAT_ARGS, NO_OBJ), @@ -444,7 +444,7 @@ static token_rule_t client_keys_token_table[] = { END_OF_TABLE }; -/** List of tokens allowed in V3 networkstatus votes. */ +/** List of tokens recognized in V3 networkstatus votes. */ static token_rule_t networkstatus_token_table[] = { T1_START("network-status-version", K_NETWORK_STATUS_VERSION, GE(1), NO_OBJ ), @@ -472,7 +472,7 @@ static token_rule_t networkstatus_token_table[] = { END_OF_TABLE }; -/** List of tokens allowed in V3 networkstatus consensuses. */ +/** List of tokens recognized in V3 networkstatus consensuses. */ static token_rule_t networkstatus_consensus_token_table[] = { T1_START("network-status-version", K_NETWORK_STATUS_VERSION, GE(1), NO_OBJ ), @@ -498,7 +498,7 @@ static token_rule_t networkstatus_consensus_token_table[] = { END_OF_TABLE }; -/** List of tokens allowable in the footer of v1/v2 directory/networkstatus +/** List of tokens recognized in the footer of v1/v2 directory/networkstatus * footers. */ static token_rule_t networkstatus_vote_footer_token_table[] = { T01("directory-footer", K_DIRECTORY_FOOTER, NO_ARGS, NO_OBJ ), @@ -507,7 +507,7 @@ static token_rule_t networkstatus_vote_footer_token_table[] = { END_OF_TABLE }; -/** List of tokens allowable in detached networkstatus signature documents. */ +/** List of tokens recognized in detached networkstatus signature documents. */ static token_rule_t networkstatus_detached_signature_token_table[] = { T1_START("consensus-digest", K_CONSENSUS_DIGEST, GE(1), NO_OBJ ), T("additional-digest", K_ADDITIONAL_DIGEST,GE(3), NO_OBJ ), @@ -519,6 +519,7 @@ static token_rule_t networkstatus_detached_signature_token_table[] = { END_OF_TABLE }; +/** List of tokens recognized in microdescriptors */ static token_rule_t microdesc_token_table[] = { T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024), T01("family", K_FAMILY, ARGS, NO_OBJ ), @@ -543,6 +544,7 @@ static int router_get_hashes_impl(const char *s, size_t s_len, const char *start_str, const char *end_str, char end_char); static void token_clear(directory_token_t *tok); +static smartlist_t *find_all_by_keyword(smartlist_t *s, directory_keyword k); static smartlist_t *find_all_exitpolicy(smartlist_t *s); static directory_token_t *_find_by_keyword(smartlist_t *s, directory_keyword keyword, @@ -568,10 +570,10 @@ static directory_token_t *get_next_token(memarea_t *area, static int check_signature_token(const char *digest, ssize_t digest_len, directory_token_t *tok, - crypto_pk_env_t *pkey, + crypto_pk_t *pkey, int flags, const char *doctype); -static crypto_pk_env_t *find_dir_signing_key(const char *str, const char *eos); +static crypto_pk_t *find_dir_signing_key(const char *str, const char *eos); #undef DEBUG_AREA_ALLOC @@ -681,12 +683,12 @@ router_get_networkstatus_v3_hash(const char *s, char *digest, ' ', alg); } -/** Set <b>digest</b> to the SHA-1 digest of the hash of the extrainfo - * string in <b>s</b>. Return 0 on success, -1 on failure. */ +/** Set <b>digest</b> to the SHA-1 digest of the hash of the <b>s_len</b>-byte + * extrainfo string at <b>s</b>. Return 0 on success, -1 on failure. */ int -router_get_extrainfo_hash(const char *s, char *digest) +router_get_extrainfo_hash(const char *s, size_t s_len, char *digest) { - return router_get_hash_impl(s, strlen(s), digest, "extra-info", + return router_get_hash_impl(s, s_len, digest, "extra-info", "\nrouter-signature",'\n', DIGEST_SHA1); } @@ -699,7 +701,7 @@ router_get_extrainfo_hash(const char *s, char *digest) */ int router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest, - size_t digest_len, crypto_pk_env_t *private_key) + size_t digest_len, crypto_pk_t *private_key) { char *signature; size_t i, keysize; @@ -765,7 +767,7 @@ tor_version_is_obsolete(const char *myversion, const char *versionlist) log_err(LD_BUG,"I couldn't parse my own version (%s)", myversion); tor_assert(0); } - version_sl = smartlist_create(); + version_sl = smartlist_new(); smartlist_split_string(version_sl, versionlist, ",", SPLIT_SKIP_SPACE, 0); if (!strlen(versionlist)) { /* no authorities cared or agreed */ @@ -773,7 +775,7 @@ tor_version_is_obsolete(const char *myversion, const char *versionlist) goto done; } - SMARTLIST_FOREACH(version_sl, const char *, cp, { + SMARTLIST_FOREACH_BEGIN(version_sl, const char *, cp) { if (!strcmpstart(cp, "Tor ")) cp += 4; @@ -795,7 +797,7 @@ tor_version_is_obsolete(const char *myversion, const char *versionlist) found_older = 1; } } - }); + } SMARTLIST_FOREACH_END(cp); /* We didn't find the listed version. Is it new or old? */ if (found_any_in_series && !found_newer_in_series && found_newer) { @@ -826,7 +828,7 @@ router_parse_directory(const char *str) int r; const char *end, *cp, *str_dup = str; smartlist_t *tokens = NULL; - crypto_pk_env_t *declared_key = NULL; + crypto_pk_t *declared_key = NULL; memarea_t *area = memarea_new(); /* XXXX This could be simplified a lot, but it will all go away @@ -847,7 +849,7 @@ router_parse_directory(const char *str) log_warn(LD_DIR, "No signature found on directory."); goto err; } ++cp; - tokens = smartlist_create(); + tokens = smartlist_new(); if (tokenize_string(area,cp,strchr(cp,'\0'),tokens,dir_token_table,0)) { log_warn(LD_DIR, "Error tokenizing directory signature"); goto err; } @@ -900,7 +902,7 @@ router_parse_directory(const char *str) dump_desc(str_dup, "v1 directory"); r = -1; done: - if (declared_key) crypto_free_pk_env(declared_key); + if (declared_key) crypto_pk_free(declared_key); if (tokens) { SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); @@ -922,7 +924,7 @@ router_parse_runningrouters(const char *str) directory_token_t *tok; time_t published_on; int r = -1; - crypto_pk_env_t *declared_key = NULL; + crypto_pk_t *declared_key = NULL; smartlist_t *tokens = NULL; const char *eos = str + strlen(str), *str_dup = str; memarea_t *area = NULL; @@ -932,7 +934,7 @@ router_parse_runningrouters(const char *str) goto err; } area = memarea_new(); - tokens = smartlist_create(); + tokens = smartlist_new(); if (tokenize_string(area,str,eos,tokens,dir_token_table,0)) { log_warn(LD_DIR, "Error tokenizing running-routers"); goto err; } @@ -966,7 +968,7 @@ router_parse_runningrouters(const char *str) r = 0; err: dump_desc(str_dup, "v1 running-routers"); - if (declared_key) crypto_free_pk_env(declared_key); + if (declared_key) crypto_pk_free(declared_key); if (tokens) { SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); @@ -981,12 +983,12 @@ router_parse_runningrouters(const char *str) /** Given a directory or running-routers string in <b>str</b>, try to * find the its dir-signing-key token (if any). If this token is * present, extract and return the key. Return NULL on failure. */ -static crypto_pk_env_t * +static crypto_pk_t * find_dir_signing_key(const char *str, const char *eos) { const char *cp; directory_token_t *tok; - crypto_pk_env_t *key = NULL; + crypto_pk_t *key = NULL; memarea_t *area = NULL; tor_assert(str); tor_assert(eos); @@ -1029,7 +1031,7 @@ find_dir_signing_key(const char *str, const char *eos) /** Return true iff <b>key</b> is allowed to sign directories. */ static int -dir_signing_key_is_trusted(crypto_pk_env_t *key) +dir_signing_key_is_trusted(crypto_pk_t *key) { char digest[DIGEST_LEN]; if (!key) return 0; @@ -1056,7 +1058,7 @@ static int check_signature_token(const char *digest, ssize_t digest_len, directory_token_t *tok, - crypto_pk_env_t *pkey, + crypto_pk_t *pkey, int flags, const char *doctype) { @@ -1261,7 +1263,7 @@ dump_distinct_digest_count(int severity) * s through end into the signed_descriptor_body of the resulting * routerinfo_t. * - * If <b>end</b> is NULL, <b>s</b> must be properly NULL-terminated. + * If <b>end</b> is NULL, <b>s</b> must be properly NUL-terminated. * * If <b>allow_annotations</b>, it's okay to encounter annotations in <b>s</b> * before the router; if it's false, reject the router if it's annotated. If @@ -1297,7 +1299,7 @@ router_parse_entry_from_string(const char *s, const char *end, --end; area = memarea_new(); - tokens = smartlist_create(); + tokens = smartlist_new(); if (prepend_annotations) { if (tokenize_string(area,prepend_annotations,NULL,tokens, routerdesc_token_table,TS_NOCHECK)) { @@ -1357,7 +1359,6 @@ router_parse_entry_from_string(const char *s, const char *end, tor_assert(tok->n_args >= 5); router = tor_malloc_zero(sizeof(routerinfo_t)); - router->country = -1; router->cache_info.routerlist_index = -1; router->cache_info.annotations_len = s-start_of_annotations + prepend_len; router->cache_info.signed_descriptor_len = end-s; @@ -1503,19 +1504,33 @@ router_parse_entry_from_string(const char *s, const char *end, router->contact_info = tor_strdup(tok->args[0]); } - if ((tok = find_opt_by_keyword(tokens, K_EVENTDNS))) { - router->has_old_dnsworkers = tok->n_args && !strcmp(tok->args[0], "0"); - } else if (router->platform) { - if (! tor_version_as_new_as(router->platform, "0.1.2.2-alpha")) - router->has_old_dnsworkers = 1; - } - if (find_opt_by_keyword(tokens, K_REJECT6) || find_opt_by_keyword(tokens, K_ACCEPT6)) { log_warn(LD_DIR, "Rejecting router with reject6/accept6 line: they crash " "older Tors."); goto err; } + { + smartlist_t *or_addresses = find_all_by_keyword(tokens, K_OR_ADDRESS); + if (or_addresses) { + SMARTLIST_FOREACH_BEGIN(or_addresses, directory_token_t *, t) { + tor_addr_t a; + maskbits_t bits; + uint16_t port_min, port_max; + /* XXXX Prop186 the full spec allows much more than this. */ + if (tor_addr_parse_mask_ports(t->args[0], &a, &bits, &port_min, + &port_max) == AF_INET6 && + bits == 128 && + port_min == port_max) { + /* Okay, this is one we can understand. */ + tor_addr_copy(&router->ipv6_addr, &a); + router->ipv6_orport = port_min; + break; + } + } SMARTLIST_FOREACH_END(t); + smartlist_free(or_addresses); + } + } exit_policy_tokens = find_all_exitpolicy(tokens); if (!smartlist_len(exit_policy_tokens)) { log_warn(LD_DIR, "No exit policy tokens in descriptor."); @@ -1532,7 +1547,7 @@ router_parse_entry_from_string(const char *s, const char *end, if ((tok = find_opt_by_keyword(tokens, K_FAMILY)) && tok->n_args) { int i; - router->declared_family = smartlist_create(); + router->declared_family = smartlist_new(); for (i=0;i<tok->n_args;++i) { if (!is_legal_nickname_or_hexdigest(tok->args[i])) { log_warn(LD_DIR, "Illegal nickname %s in family line", @@ -1574,8 +1589,6 @@ router_parse_entry_from_string(const char *s, const char *end, "router descriptor") < 0) goto err; - routerinfo_set_country(router); - if (!router->or_port) { log_warn(LD_DIR,"or_port unreadable or 0. Failing."); goto err; @@ -1618,7 +1631,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end, char digest[128]; smartlist_t *tokens = NULL; directory_token_t *tok; - crypto_pk_env_t *key = NULL; + crypto_pk_t *key = NULL; routerinfo_t *router = NULL; memarea_t *area = NULL; const char *s_dup = s; @@ -1631,11 +1644,11 @@ extrainfo_parse_entry_from_string(const char *s, const char *end, while (end > s+2 && *(end-1) == '\n' && *(end-2) == '\n') --end; - if (router_get_extrainfo_hash(s, digest) < 0) { + if (router_get_extrainfo_hash(s, end-s, digest) < 0) { log_warn(LD_DIR, "Couldn't compute router hash."); goto err; } - tokens = smartlist_create(); + tokens = smartlist_new(); area = memarea_new(); if (tokenize_string(area,s,end,tokens,extrainfo_token_table,0)) { log_warn(LD_DIR, "Error tokenizing extra-info document."); @@ -1768,7 +1781,7 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string) return NULL; } - tokens = smartlist_create(); + tokens = smartlist_new(); area = memarea_new(); if (tokenize_string(area,s, eos, tokens, dir_key_certificate_table, 0) < 0) { log_warn(LD_DIR, "Error tokenizing key certificate"); @@ -1823,9 +1836,9 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string) struct in_addr in; char *address = NULL; tor_assert(tok->n_args); - /* XXX023 use tor_addr_port_parse() below instead. -RD */ - if (parse_addr_port(LOG_WARN, tok->args[0], &address, NULL, - &cert->dir_port)<0 || + /* XXX024 use some tor_addr parse function below instead. -RD */ + if (tor_addr_port_split(LOG_WARN, tok->args[0], &address, + &cert->dir_port) < 0 || tor_inet_aton(address, &in) == 0) { log_warn(LD_DIR, "Couldn't parse dir-address in certificate"); tor_free(address); @@ -1975,6 +1988,7 @@ routerstatus_parse_entry_from_string(memarea_t *area, if (!consensus_method) flav = FLAV_NS; + tor_assert(flav == FLAV_NS || flav == FLAV_MICRODESC); eos = find_start_of_next_routerstatus(*s); @@ -1987,15 +2001,16 @@ routerstatus_parse_entry_from_string(memarea_t *area, goto err; } tok = find_by_keyword(tokens, K_R); - tor_assert(tok->n_args >= 7); + tor_assert(tok->n_args >= 7); /* guaranteed by GE(7) in K_R setup */ if (flav == FLAV_NS) { if (tok->n_args < 8) { log_warn(LD_DIR, "Too few arguments to r"); goto err; } - } else { - offset = -1; + } else if (flav == FLAV_MICRODESC) { + offset = -1; /* There is no identity digest */ } + if (vote_rs) { rs = &vote_rs->status; } else { @@ -2069,7 +2084,7 @@ routerstatus_parse_entry_from_string(memarea_t *area, else if (!strcmp(tok->args[i], "Fast")) rs->is_fast = 1; else if (!strcmp(tok->args[i], "Running")) - rs->is_running = 1; + rs->is_flagged_running = 1; else if (!strcmp(tok->args[i], "Named")) rs->is_named = 1; else if (!strcmp(tok->args[i], "Valid")) @@ -2100,6 +2115,8 @@ routerstatus_parse_entry_from_string(memarea_t *area, rs->version_supports_begindir = 1; rs->version_supports_extrainfo_upload = 1; rs->version_supports_conditional_consensus = 1; + rs->version_supports_microdesc_cache = 1; + rs->version_supports_optimistic_data = 1; } else { rs->version_supports_begindir = tor_version_as_new_as(tok->args[0], "0.2.0.1-alpha"); @@ -2109,6 +2126,10 @@ routerstatus_parse_entry_from_string(memarea_t *area, tor_version_as_new_as(tok->args[0], "0.2.0.8-alpha"); rs->version_supports_conditional_consensus = tor_version_as_new_as(tok->args[0], "0.2.1.1-alpha"); + rs->version_supports_microdesc_cache = + tor_version_supports_microdescriptors(tok->args[0]); + rs->version_supports_optimistic_data = + tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha"); } if (vote_rs) { vote_rs->version = tor_strdup(tok->args[0]); @@ -2171,6 +2192,16 @@ routerstatus_parse_entry_from_string(memarea_t *area, vote_rs->microdesc = line; } } SMARTLIST_FOREACH_END(t); + } else if (flav == FLAV_MICRODESC) { + tok = find_opt_by_keyword(tokens, K_M); + if (tok) { + tor_assert(tok->n_args); + if (digest256_from_base64(rs->descriptor_digest, tok->args[0])) { + log_warn(LD_DIR, "Error decoding microdescriptor digest %s", + escaped(tok->args[0])); + goto err; + } + } } if (!strcasecmp(rs->nickname, UNNAMED_ROUTER_NICKNAME)) @@ -2221,8 +2252,8 @@ networkstatus_v2_t * networkstatus_v2_parse_from_string(const char *s) { const char *eos, *s_dup = s; - smartlist_t *tokens = smartlist_create(); - smartlist_t *footer_tokens = smartlist_create(); + smartlist_t *tokens = smartlist_new(); + smartlist_t *footer_tokens = smartlist_new(); networkstatus_v2_t *ns = NULL; char ns_digest[DIGEST_LEN]; char tmp_digest[DIGEST_LEN]; @@ -2332,7 +2363,7 @@ networkstatus_v2_parse_from_string(const char *s) goto err; } - ns->entries = smartlist_create(); + ns->entries = smartlist_new(); s = eos; SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_clear(tokens); @@ -2779,7 +2810,7 @@ networkstatus_t * networkstatus_parse_vote_from_string(const char *s, const char **eos_out, networkstatus_type_t ns_type) { - smartlist_t *tokens = smartlist_create(); + smartlist_t *tokens = smartlist_new(); smartlist_t *rs_tokens = NULL, *footer_tokens = NULL; networkstatus_voter_info_t *voter = NULL; networkstatus_t *ns = NULL; @@ -2791,6 +2822,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, int i, inorder, n_signatures = 0; memarea_t *area = NULL, *rs_area = NULL; consensus_flavor_t flav = FLAV_NS; + char *last_kwd=NULL; tor_assert(s); @@ -2864,7 +2896,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, if (parse_iso_time(tok->args[0], &ns->published)) goto err; - ns->supported_methods = smartlist_create(); + ns->supported_methods = smartlist_new(); tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHODS); if (tok) { for (i=0; i < tok->n_args; ++i) @@ -2931,7 +2963,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, } tok = find_by_keyword(tokens, K_KNOWN_FLAGS); - ns->known_flags = smartlist_create(); + ns->known_flags = smartlist_new(); inorder = 1; for (i = 0; i < tok->n_args; ++i) { smartlist_add(ns->known_flags, tor_strdup(tok->args[i])); @@ -2947,15 +2979,18 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, tok = find_opt_by_keyword(tokens, K_PARAMS); if (tok) { + int any_dups = 0; inorder = 1; - ns->net_params = smartlist_create(); + ns->net_params = smartlist_new(); for (i = 0; i < tok->n_args; ++i) { int ok=0; char *eq = strchr(tok->args[i], '='); + size_t eq_pos; if (!eq) { log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i])); goto err; } + eq_pos = eq-tok->args[i]; tor_parse_long(eq+1, 10, INT32_MIN, INT32_MAX, &ok, NULL); if (!ok) { log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i])); @@ -2965,15 +3000,27 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]); inorder = 0; } + if (last_kwd && eq_pos == strlen(last_kwd) && + fast_memeq(last_kwd, tok->args[i], eq_pos)) { + log_warn(LD_DIR, "Duplicate value for %s parameter", + escaped(tok->args[i])); + any_dups = 1; + } + tor_free(last_kwd); + last_kwd = tor_strndup(tok->args[i], eq_pos); smartlist_add(ns->net_params, tor_strdup(tok->args[i])); } if (!inorder) { log_warn(LD_DIR, "params not in order"); goto err; } + if (any_dups) { + log_warn(LD_DIR, "Duplicate in parameters"); + goto err; + } } - ns->voters = smartlist_create(); + ns->voters = smartlist_new(); SMARTLIST_FOREACH_BEGIN(tokens, directory_token_t *, _tok) { tok = _tok; @@ -2983,7 +3030,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, if (voter) smartlist_add(ns->voters, voter); voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); - voter->sigs = smartlist_create(); + voter->sigs = smartlist_new(); if (ns->type != NS_TYPE_CONSENSUS) memcpy(voter->vote_digest, ns_digests.d[DIGEST_SHA1], DIGEST_LEN); @@ -3068,10 +3115,10 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, } /* Parse routerstatus lines. */ - rs_tokens = smartlist_create(); + rs_tokens = smartlist_new(); rs_area = memarea_new(); s = end_of_header; - ns->routerstatus_list = smartlist_create(); + ns->routerstatus_list = smartlist_new(); while (!strcmpstart(s, "r ")) { if (ns->type != NS_TYPE_CONSENSUS) { @@ -3111,7 +3158,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, } /* Parse footer; check signature. */ - footer_tokens = smartlist_create(); + footer_tokens = smartlist_new(); if ((end_of_footer = strstr(s, "\nnetwork-status-version "))) ++end_of_footer; else @@ -3144,7 +3191,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, tok = find_opt_by_keyword(footer_tokens, K_BW_WEIGHTS); if (tok) { - ns->weight_params = smartlist_create(); + ns->weight_params = smartlist_new(); for (i = 0; i < tok->n_args; ++i) { int ok=0; char *eq = strchr(tok->args[i], '='); @@ -3309,6 +3356,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, } if (rs_area) memarea_drop_all(rs_area); + tor_free(last_kwd); return ns; } @@ -3336,7 +3384,7 @@ detached_get_signatures(ns_detached_signatures_t *sigs, { smartlist_t *sl = strmap_get(sigs->signatures, flavor_name); if (!sl) { - sl = smartlist_create(); + sl = smartlist_new(); strmap_set(sigs->signatures, flavor_name, sl); } return sl; @@ -3353,7 +3401,7 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos) memarea_t *area = NULL; digests_t *digests; - smartlist_t *tokens = smartlist_create(); + smartlist_t *tokens = smartlist_new(); ns_detached_signatures_t *sigs = tor_malloc_zero(sizeof(ns_detached_signatures_t)); sigs->digests = strmap_new(); @@ -3502,10 +3550,10 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos) siglist = detached_get_signatures(sigs, flavor); is_duplicate = 0; - SMARTLIST_FOREACH(siglist, document_signature_t *, s, { - if (s->alg == alg && - tor_memeq(id_digest, s->identity_digest, DIGEST_LEN) && - tor_memeq(sk_digest, s->signing_key_digest, DIGEST_LEN)) { + SMARTLIST_FOREACH(siglist, document_signature_t *, dsig, { + if (dsig->alg == alg && + tor_memeq(id_digest, dsig->identity_digest, DIGEST_LEN) && + tor_memeq(sk_digest, dsig->signing_key_digest, DIGEST_LEN)) { is_duplicate = 1; } }); @@ -3608,7 +3656,7 @@ router_add_exit_policy(routerinfo_t *router, directory_token_t *tok) if (!newe) return -1; if (! router->exit_policy) - router->exit_policy = smartlist_create(); + router->exit_policy = smartlist_new(); if (((tok->tp == K_ACCEPT6 || tok->tp == K_REJECT6) && tor_addr_family(&newe->addr) == AF_INET) @@ -3716,7 +3764,7 @@ static void token_clear(directory_token_t *tok) { if (tok->key) - crypto_free_pk_env(tok->key); + crypto_pk_free(tok->key); } #define ALLOC_ZERO(sz) memarea_alloc_zero(area,sz) @@ -3962,11 +4010,11 @@ get_next_token(memarea_t *area, RET_ERR("Couldn't parse object: missing footer or object much too big."); if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */ - tok->key = crypto_new_pk_env(); + tok->key = crypto_pk_new(); if (crypto_pk_read_public_key_from_string(tok->key, obstart, eol-obstart)) RET_ERR("Couldn't parse public key."); } else if (!strcmp(tok->object_type, "RSA PRIVATE KEY")) { /* private key */ - tok->key = crypto_new_pk_env(); + tok->key = crypto_pk_new(); if (crypto_pk_read_private_key_from_string(tok->key, obstart, eol-obstart)) RET_ERR("Couldn't parse private key."); } else { /* If it's something else, try to base64-decode it */ @@ -4122,13 +4170,30 @@ _find_by_keyword(smartlist_t *s, directory_keyword keyword, return tok; } +/** If there are any directory_token_t entries in <b>s</b> whose keyword is + * <b>k</b>, return a newly allocated smartlist_t containing all such entries, + * in the same order in which they occur in <b>s</b>. Otherwise return + * NULL. */ +static smartlist_t * +find_all_by_keyword(smartlist_t *s, directory_keyword k) +{ + smartlist_t *out = NULL; + SMARTLIST_FOREACH(s, directory_token_t *, t, + if (t->tp == k) { + if (!out) + out = smartlist_new(); + smartlist_add(out, t); + }); + return out; +} + /** Return a newly allocated smartlist of all accept or reject tokens in * <b>s</b>. */ static smartlist_t * find_all_exitpolicy(smartlist_t *s) { - smartlist_t *out = smartlist_create(); + smartlist_t *out = smartlist_new(); SMARTLIST_FOREACH(s, directory_token_t *, t, if (t->tp == K_ACCEPT || t->tp == K_ACCEPT6 || t->tp == K_REJECT || t->tp == K_REJECT6) @@ -4136,6 +4201,13 @@ find_all_exitpolicy(smartlist_t *s) return out; } +/** Helper function for <b>router_get_hash_impl</b>: given <b>s</b>, + * <b>s_len</b>, <b>start_str</b>, <b>end_str</b>, and <b>end_c</b> with the + * same semantics as in that function, set *<b>start_out</b> (inclusive) and + * *<b>end_out</b> (exclusive) to the boundaries of the string to be hashed. + * + * Return 0 on success and -1 on failure. + */ static int router_get_hash_impl_helper(const char *s, size_t s_len, const char *start_str, @@ -4300,8 +4372,8 @@ microdescs_parse_from_string(const char *s, const char *eos, s = eat_whitespace_eos(s, eos); area = memarea_new(); - result = smartlist_create(); - tokens = smartlist_create(); + result = smartlist_new(); + tokens = smartlist_new(); while (s < eos) { start_of_next_microdesc = find_start_of_next_microdesc(s, eos); @@ -4346,7 +4418,7 @@ microdescs_parse_from_string(const char *s, const char *eos, if ((tok = find_opt_by_keyword(tokens, K_FAMILY))) { int i; - md->family = smartlist_create(); + md->family = smartlist_new(); for (i=0;i<tok->n_args;++i) { if (!is_legal_nickname_or_hexdigest(tok->args[i])) { log_warn(LD_DIR, "Illegal nickname %s in family line", @@ -4358,7 +4430,7 @@ microdescs_parse_from_string(const char *s, const char *eos, } if ((tok = find_opt_by_keyword(tokens, K_P))) { - md->exitsummary = tor_strdup(tok->args[0]); + md->exit_policy = parse_short_policy(tok->args[0]); } crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256); @@ -4381,6 +4453,14 @@ microdescs_parse_from_string(const char *s, const char *eos, return result; } +/** Return true iff this Tor version can answer directory questions + * about microdescriptors. */ +int +tor_version_supports_microdescriptors(const char *platform) +{ + return tor_version_as_new_as(platform, "0.2.3.1-alpha"); +} + /** Parse the Tor version of the platform string <b>platform</b>, * and compare it to the version in <b>cutoff</b>. Return 1 if * the router is at least as new as the cutoff, else return 0. @@ -4621,7 +4701,7 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, tor_malloc_zero(sizeof(rend_service_descriptor_t)); char desc_hash[DIGEST_LEN]; const char *eos; - smartlist_t *tokens = smartlist_create(); + smartlist_t *tokens = smartlist_new(); directory_token_t *tok; char secret_id_part[DIGEST_LEN]; int i, version, num_ok=1; @@ -4730,7 +4810,7 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, /* Parse protocol versions. */ tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS); tor_assert(tok->n_args == 1); - versions = smartlist_create(); + versions = smartlist_new(); smartlist_split_string(versions, tok->args[0], ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); for (i = 0; i < smartlist_len(versions); i++) { @@ -4813,8 +4893,8 @@ rend_decrypt_introduction_points(char **ipos_decrypted, session_key[CIPHER_KEY_LEN], *dec; int declen, client_blocks; size_t pos = 0, len, client_entries_len; - crypto_digest_env_t *digest; - crypto_cipher_env_t *cipher; + crypto_digest_t *digest; + crypto_cipher_t *cipher; client_blocks = (int) ipos_encrypted[1]; client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE * REND_BASIC_AUTH_CLIENT_ENTRY_LEN; @@ -4824,33 +4904,33 @@ rend_decrypt_introduction_points(char **ipos_decrypted, return -1; } memcpy(iv, ipos_encrypted + 2 + client_entries_len, CIPHER_IV_LEN); - digest = crypto_new_digest_env(); + digest = crypto_digest_new(); crypto_digest_add_bytes(digest, descriptor_cookie, REND_DESC_COOKIE_LEN); crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN); crypto_digest_get_digest(digest, client_id, REND_BASIC_AUTH_CLIENT_ID_LEN); - crypto_free_digest_env(digest); + crypto_digest_free(digest); for (pos = 2; pos < 2 + client_entries_len; pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN) { if (tor_memeq(ipos_encrypted + pos, client_id, REND_BASIC_AUTH_CLIENT_ID_LEN)) { /* Attempt to decrypt introduction points. */ - cipher = crypto_create_init_cipher(descriptor_cookie, 0); + cipher = crypto_cipher_new(descriptor_cookie); if (crypto_cipher_decrypt(cipher, session_key, ipos_encrypted + pos + REND_BASIC_AUTH_CLIENT_ID_LEN, CIPHER_KEY_LEN) < 0) { log_warn(LD_REND, "Could not decrypt session key for client."); - crypto_free_cipher_env(cipher); + crypto_cipher_free(cipher); return -1; } - crypto_free_cipher_env(cipher); - cipher = crypto_create_init_cipher(session_key, 0); + crypto_cipher_free(cipher); + len = ipos_encrypted_size - 2 - client_entries_len - CIPHER_IV_LEN; dec = tor_malloc(len); - declen = crypto_cipher_decrypt_with_iv(cipher, dec, len, + declen = crypto_cipher_decrypt_with_iv(session_key, dec, len, ipos_encrypted + 2 + client_entries_len, ipos_encrypted_size - 2 - client_entries_len); - crypto_free_cipher_env(cipher); + if (declen < 0) { log_warn(LD_REND, "Could not decrypt introduction point string."); tor_free(dec); @@ -4871,7 +4951,6 @@ rend_decrypt_introduction_points(char **ipos_decrypted, "check your authorization for this service!"); return -1; } else if (ipos_encrypted[0] == (int)REND_STEALTH_AUTH) { - crypto_cipher_env_t *cipher; char *dec; int declen; if (ipos_encrypted_size < CIPHER_IV_LEN + 2) { @@ -4880,13 +4959,13 @@ rend_decrypt_introduction_points(char **ipos_decrypted, return -1; } dec = tor_malloc_zero(ipos_encrypted_size - CIPHER_IV_LEN - 1); - cipher = crypto_create_init_cipher(descriptor_cookie, 0); - declen = crypto_cipher_decrypt_with_iv(cipher, dec, + + declen = crypto_cipher_decrypt_with_iv(descriptor_cookie, dec, ipos_encrypted_size - CIPHER_IV_LEN - 1, ipos_encrypted + 1, ipos_encrypted_size - 1); - crypto_free_cipher_env(cipher); + if (declen < 0) { log_warn(LD_REND, "Decrypting introduction points failed!"); tor_free(dec); @@ -4926,8 +5005,8 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed, /* Consider one intro point after the other. */ current_ipo = intro_points_encoded; end_of_intro_points = intro_points_encoded + intro_points_encoded_size; - tokens = smartlist_create(); - parsed->intro_nodes = smartlist_create(); + tokens = smartlist_new(); + parsed->intro_nodes = smartlist_new(); area = memarea_new(); while (!fast_memcmpstart(current_ipo, end_of_intro_points-current_ipo, @@ -4974,7 +5053,7 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed, info->identity_digest, DIGEST_LEN); /* Parse IP address. */ tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS); - if (tor_addr_from_str(&info->addr, tok->args[0])<0) { + if (tor_addr_parse(&info->addr, tok->args[0])<0) { log_warn(LD_REND, "Could not parse introduction point address."); rend_intro_point_free(intro); goto err; @@ -5048,7 +5127,7 @@ rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr) memarea_t *area = NULL; if (!ckstr || strlen(ckstr) == 0) return -1; - tokens = smartlist_create(); + tokens = smartlist_new(); /* Begin parsing with first entry, skipping comments or whitespace at the * beginning. */ area = memarea_new(); @@ -5120,9 +5199,9 @@ rend_parse_client_keys(strmap_t *parsed_clients, const char *ckstr) /* The size of descriptor_cookie_tmp needs to be REND_DESC_COOKIE_LEN+2, * because a base64 encoding of length 24 does not fit into 16 bytes in all * cases. */ - if ((base64_decode(descriptor_cookie_tmp, REND_DESC_COOKIE_LEN+2, - tok->args[0], REND_DESC_COOKIE_LEN_BASE64+2+1) - != REND_DESC_COOKIE_LEN)) { + if (base64_decode(descriptor_cookie_tmp, sizeof(descriptor_cookie_tmp), + tok->args[0], strlen(tok->args[0])) + != REND_DESC_COOKIE_LEN) { log_warn(LD_REND, "Descriptor cookie contains illegal characters: " "%s", escaped(tok->args[0])); goto err; |