diff options
Diffstat (limited to 'src/or/routerparse.c')
-rw-r--r-- | src/or/routerparse.c | 151 |
1 files changed, 96 insertions, 55 deletions
diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 299d07d376..a333780752 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -11,7 +11,7 @@ #include "or.h" #include "config.h" -#include "circuitbuild.h" +#include "circuitstats.h" #include "dirserv.h" #include "dirvote.h" #include "policies.h" @@ -29,8 +29,8 @@ /****************************************************************************/ /** Enumeration of possible token types. The ones starting with K_ correspond - * to directory 'keywords'. _ERR is an error in the tokenizing process, _EOF - * is an end-of-file marker, and _NIL is used to encode not-a-token. + * to directory 'keywords'. ERR_ is an error in the tokenizing process, EOF_ + * is an end-of-file marker, and NIL_ is used to encode not-a-token. */ typedef enum { K_ACCEPT = 0, @@ -67,6 +67,7 @@ typedef enum { K_OR_ADDRESS, K_P, K_R, + K_A, K_S, K_V, K_W, @@ -130,7 +131,7 @@ typedef enum { A_PURPOSE, A_LAST_LISTED, - _A_UNKNOWN, + A_UNKNOWN_, R_RENDEZVOUS_SERVICE_DESCRIPTOR, R_VERSION, @@ -151,13 +152,13 @@ typedef enum { C_DESCRIPTOR_COOKIE, C_CLIENT_KEY, - _ERR, - _EOF, - _NIL + ERR_, + EOF_, + NIL_ } directory_keyword; #define MIN_ANNOTATION A_PURPOSE -#define MAX_ANNOTATION _A_UNKNOWN +#define MAX_ANNOTATION A_UNKNOWN_ /** Structure to hold a single directory token. * @@ -180,7 +181,7 @@ typedef struct directory_token_t { crypto_pk_t *key; /**< For public keys only. Heap-allocated. */ - char *error; /**< For _ERR tokens only. */ + char *error; /**< For ERR_ tokens only. */ } directory_token_t; /* ********************************************************************** */ @@ -234,7 +235,7 @@ typedef struct token_rule_t { */ /** Appears to indicate the end of a table. */ -#define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 } +#define END_OF_TABLE { NULL, NIL_, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 } /** An item with no restrictions: used for obsolete document types */ #define T(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 } /** An item with no restrictions on multiplicity or location. */ @@ -338,6 +339,7 @@ static token_rule_t extrainfo_token_table[] = { static token_rule_t rtrstatus_token_table[] = { T01("p", K_P, CONCAT_ARGS, NO_OBJ ), T1( "r", K_R, GE(7), NO_OBJ ), + T0N("a", K_A, GE(1), NO_OBJ ), T1( "s", K_S, ARGS, NO_OBJ ), T01("v", K_V, CONCAT_ARGS, NO_OBJ ), T01("w", K_W, ARGS, NO_OBJ ), @@ -522,6 +524,7 @@ static token_rule_t networkstatus_detached_signature_token_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), + T0N("a", K_A, GE(1), NO_OBJ ), T01("family", K_FAMILY, ARGS, NO_OBJ ), T01("p", K_P, CONCAT_ARGS, NO_OBJ ), A01("@last-listed", A_LAST_LISTED, CONCAT_ARGS, NO_OBJ ), @@ -546,10 +549,10 @@ static int router_get_hashes_impl(const char *s, size_t s_len, 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, +static directory_token_t *find_by_keyword_(smartlist_t *s, directory_keyword keyword, const char *keyword_str); -#define find_by_keyword(s, keyword) _find_by_keyword((s), (keyword), #keyword) +#define find_by_keyword(s, keyword) find_by_keyword_((s), (keyword), #keyword) static directory_token_t *find_opt_by_keyword(smartlist_t *s, directory_keyword keyword); @@ -1257,6 +1260,42 @@ dump_distinct_digest_count(int severity) #endif } +/** Try to find an IPv6 OR port in <b>list</b> of directory_token_t's + * with at least one argument (use GE(1) in setup). If found, store + * address and port number to <b>addr_out</b> and + * <b>port_out</b>. Return number of OR ports found. */ +static int +find_single_ipv6_orport(const smartlist_t *list, + tor_addr_t *addr_out, + uint16_t *port_out) +{ + int ret = 0; + tor_assert(list != NULL); + tor_assert(addr_out != NULL); + tor_assert(port_out != NULL); + + SMARTLIST_FOREACH_BEGIN(list, directory_token_t *, t) { + tor_addr_t a; + maskbits_t bits; + uint16_t port_min, port_max; + tor_assert(t->n_args >= 1); + /* 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. Use it and ignore + any potential more addresses in list. */ + tor_addr_copy(addr_out, &a); + *port_out = port_min; + ret = 1; + break; + } + } SMARTLIST_FOREACH_END(t); + + return ret; +} + /** Helper function: reads a single router entry from *<b>s</b> ... * *<b>end</b>. Mallocs a new router and returns it if all goes well, else * returns NULL. If <b>cache_copy</b> is true, duplicate the contents of @@ -1513,21 +1552,8 @@ router_parse_entry_from_string(const char *s, const char *end, { 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); + find_single_ipv6_orport(or_addresses, &router->ipv6_addr, + &router->ipv6_orport); smartlist_free(or_addresses); } } @@ -2060,6 +2086,14 @@ routerstatus_parse_entry_from_string(memarea_t *area, rs->dir_port = (uint16_t) tor_parse_long(tok->args[7+offset], 10,0,65535,NULL,NULL); + { + smartlist_t *a_lines = find_all_by_keyword(tokens, K_A); + if (a_lines) { + find_single_ipv6_orport(a_lines, &rs->ipv6_addr, &rs->ipv6_orport); + smartlist_free(a_lines); + } + } + tok = find_opt_by_keyword(tokens, K_S); if (tok && vote) { int i; @@ -2067,7 +2101,7 @@ routerstatus_parse_entry_from_string(memarea_t *area, for (i=0; i < tok->n_args; ++i) { int p = smartlist_string_pos(vote->known_flags, tok->args[i]); if (p >= 0) { - vote_rs->flags |= (1<<p); + vote_rs->flags |= (U64_LITERAL(1)<<p); } else { log_warn(LD_DIR, "Flags line had a flag %s not listed in known_flags.", escaped(tok->args[i])); @@ -2112,20 +2146,9 @@ routerstatus_parse_entry_from_string(memarea_t *area, tor_assert(tok->n_args == 1); rs->version_known = 1; if (strcmpstart(tok->args[0], "Tor ")) { - 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"); - rs->version_supports_extrainfo_upload = - tor_version_as_new_as(tok->args[0], "0.2.0.0-alpha-dev (r10070)"); - rs->version_supports_v3_dir = - 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 = @@ -2240,7 +2263,7 @@ compare_routerstatus_entries(const void **_a, const void **_b) /** Helper: used in call to _smartlist_uniq to clear out duplicate entries. */ static void -_free_duplicate_routerstatus_entry(void *e) +free_duplicate_routerstatus_entry_(void *e) { log_warn(LD_DIR, "Network-status has two entries for the same router. " @@ -2381,7 +2404,7 @@ networkstatus_v2_parse_from_string(const char *s) } smartlist_sort(ns->entries, compare_routerstatus_entries); smartlist_uniq(ns->entries, compare_routerstatus_entries, - _free_duplicate_routerstatus_entry); + free_duplicate_routerstatus_entry_); if (tokenize_string(area,s, NULL, footer_tokens, dir_footer_token_table,0)) { log_warn(LD_DIR, "Error tokenizing network-status footer."); @@ -2981,6 +3004,16 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, log_warn(LD_DIR, "known-flags not in order"); goto err; } + if (ns->type != NS_TYPE_CONSENSUS && + smartlist_len(ns->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) { + /* If we allowed more than 64 flags in votes, then parsing them would make + * us invoke undefined behavior whenever we used 1<<flagnum to do a + * bit-shift. This is only for votes and opinions: consensus users don't + * care about flags they don't recognize, and so don't build a bitfield + * for them. */ + log_warn(LD_DIR, "Too many known-flags in consensus vote or opinion"); + goto err; + } tok = find_opt_by_keyword(tokens, K_PARAMS); if (tok) { @@ -3628,7 +3661,7 @@ router_parse_addr_policy_item_from_string(const char *s, int assume_action) eos = cp + strlen(cp); area = memarea_new(); tok = get_next_token(area, &cp, eos, routerdesc_token_table); - if (tok->tp == _ERR) { + if (tok->tp == ERR_) { log_warn(LD_DIR, "Error reading address policy: %s", tok->error); goto err; } @@ -3781,14 +3814,14 @@ token_clear(directory_token_t *tok) STMT_BEGIN \ if (tok) token_clear(tok); \ tok = ALLOC_ZERO(sizeof(directory_token_t)); \ - tok->tp = _ERR; \ + tok->tp = ERR_; \ tok->error = STRDUP(msg); \ goto done_tokenizing; \ STMT_END /** Helper: make sure that the token <b>tok</b> with keyword <b>kwd</b> obeys * the object syntax of <b>o_syn</b>. Allocate all storage in <b>area</b>. - * Return <b>tok</b> on success, or a new _ERR token if the token didn't + * Return <b>tok</b> on success, or a new ERR_ token if the token didn't * conform to the syntax we wanted. **/ static INLINE directory_token_t * @@ -3907,7 +3940,7 @@ get_next_token(memarea_t *area, tor_assert(area); tok = ALLOC_ZERO(sizeof(directory_token_t)); - tok->tp = _ERR; + tok->tp = ERR_; /* Set *s to first token, eol to end-of-line, next to after first token */ *s = eat_whitespace_eos(*s, eos); /* eat multi-line whitespace */ @@ -3964,10 +3997,10 @@ get_next_token(memarea_t *area, } } - if (tok->tp == _ERR) { + if (tok->tp == ERR_) { /* No keyword matched; call it an "K_opt" or "A_unrecognized" */ if (**s == '@') - tok->tp = _A_UNKNOWN; + tok->tp = A_UNKNOWN_; else tok->tp = K_OPT; tok->args = ALLOC(sizeof(char*)); @@ -4057,7 +4090,7 @@ tokenize_string(memarea_t *area, { const char **s; directory_token_t *tok = NULL; - int counts[_NIL]; + int counts[NIL_]; int i; int first_nonannotation; int prev_len = smartlist_len(out); @@ -4066,14 +4099,14 @@ tokenize_string(memarea_t *area, s = &start; if (!end) end = start+strlen(start); - for (i = 0; i < _NIL; ++i) + for (i = 0; i < NIL_; ++i) counts[i] = 0; SMARTLIST_FOREACH(out, const directory_token_t *, t, ++counts[t->tp]); - while (*s < end && (!tok || tok->tp != _EOF)) { + while (*s < end && (!tok || tok->tp != EOF_)) { tok = get_next_token(area, s, end, table); - if (tok->tp == _ERR) { + if (tok->tp == ERR_) { log_warn(LD_DIR, "parse error: %s", tok->error); token_clear(tok); return -1; @@ -4163,7 +4196,7 @@ find_opt_by_keyword(smartlist_t *s, directory_keyword keyword) * with an assert if no such keyword is found. */ static directory_token_t * -_find_by_keyword(smartlist_t *s, directory_keyword keyword, +find_by_keyword_(smartlist_t *s, directory_keyword keyword, const char *keyword_as_string) { directory_token_t *tok = find_opt_by_keyword(s, keyword); @@ -4421,6 +4454,14 @@ microdescs_parse_from_string(const char *s, const char *eos, md->onion_pkey = tok->key; tok->key = NULL; + { + smartlist_t *a_lines = find_all_by_keyword(tokens, K_A); + if (a_lines) { + find_single_ipv6_orport(a_lines, &md->ipv6_addr, &md->ipv6_orport); + smartlist_free(a_lines); + } + } + if ((tok = find_opt_by_keyword(tokens, K_FAMILY))) { int i; md->family = smartlist_new(); @@ -4654,7 +4695,7 @@ tor_version_same_series(tor_version_t *a, tor_version_t *b) * if _a precedes _b, 1 if _b precedes _a, and 0 if they are equivalent. * Used to sort a list of versions. */ static int -_compare_tor_version_str_ptr(const void **_a, const void **_b) +compare_tor_version_str_ptr_(const void **_a, const void **_b) { const char *a = *_a, *b = *_b; int ca, cb; @@ -4678,10 +4719,10 @@ _compare_tor_version_str_ptr(const void **_a, const void **_b) void sort_version_list(smartlist_t *versions, int remove_duplicates) { - smartlist_sort(versions, _compare_tor_version_str_ptr); + smartlist_sort(versions, compare_tor_version_str_ptr_); if (remove_duplicates) - smartlist_uniq(versions, _compare_tor_version_str_ptr, _tor_free); + smartlist_uniq(versions, compare_tor_version_str_ptr_, tor_free_); } /** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>, |