diff options
Diffstat (limited to 'src/or/routerparse.c')
-rw-r--r-- | src/or/routerparse.c | 132 |
1 files changed, 96 insertions, 36 deletions
diff --git a/src/or/routerparse.c b/src/or/routerparse.c index ef87caee7f..34111a76bc 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -1,4 +1,4 @@ -/* oCpyright (c) 2001 Matej Pfajfar. +/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2007, Roger Dingledine, Nick Mathewson. */ /* See LICENSE for licensing information */ @@ -15,11 +15,9 @@ const char routerparse_c_id[] = /****************************************************************************/ -/** Enumeration of possible token types. The ones starting with K_ - * correspond to directory 'keywords'. _UNRECOGNIZED is for an - * unrecognized keyword; _ERR is an error in the tokenizing process, - * _EOF is an end-of-file marker, and _NIL is used to encode - * not-a-token. +/** 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. */ typedef enum { K_ACCEPT = 0, @@ -77,12 +75,18 @@ typedef enum { K_CONSENSUS_DIGEST, K_CONSENSUS_METHODS, + A_PURPOSE, + _A_UNKNOWN, + _UNRECOGNIZED, _ERR, _EOF, _NIL } directory_keyword; +#define MIN_ANNOTATION A_PURPOSE +#define MAX_ANNOTATION _A_UNKNOWN + /** Structure to hold a single directory token. * * We parse a directory by breaking it into "tokens", each consisting @@ -139,6 +143,8 @@ typedef struct token_rule_t { /** One or more of AT_START/AT_END to limit where the item may appear in a * document. */ int pos; + /** DOCDOC */ + int is_annotation; } token_rule_t; /* @@ -149,21 +155,23 @@ 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 } +#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 } +#define T(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 } /** An item with no restrictions on multiplicity or location. */ -#define T0N(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0 } +#define T0N(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 } /** An item that must appear exactly once */ -#define T1(s,t,a,o) { s, t, a, o, 1, 1, 0 } +#define T1(s,t,a,o) { s, t, a, o, 1, 1, 0, 0 } /** An item that must appear exactly once, at the start of the document */ -#define T1_START(s,t,a,o) { s, t, a, o, 1, 1, AT_START } +#define T1_START(s,t,a,o) { s, t, a, o, 1, 1, AT_START, 0 } /** An item that must appear exactly once, at the end of the document */ -#define T1_END(s,t,a,o) { s, t, a, o, 1, 1, AT_END } +#define T1_END(s,t,a,o) { s, t, a, o, 1, 1, AT_END, 0 } /** An item that must appear one or more times */ -#define T1N(s,t,a,o) { s, t, a, o, 1, INT_MAX, 0 } +#define T1N(s,t,a,o) { s, t, a, o, 1, INT_MAX, 0, 0 } /** An item that must appear no more than once */ -#define T01(s,t,a,o) { s, t, a, o, 0, 1, 0 } +#define T01(s,t,a,o) { s, t, a, o, 0, 1, 0, 0 } +/** An annotation that must appear no more than once */ +#define A01(s,t,a,o) { s, t, a, o, 0, 1, 0, 0 } /* Argument multiplicity: any number of arguments. */ #define ARGS 0,INT_MAX,0 @@ -200,6 +208,7 @@ static token_rule_t routerdesc_token_table[] = { T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ), T1( "bandwidth", K_BANDWIDTH, GE(3), NO_OBJ ), + A01("@purpose", A_PURPOSE, GE(1), NO_OBJ ), END_OF_TABLE }; @@ -365,7 +374,8 @@ static directory_token_t *find_first_by_keyword(smartlist_t *s, directory_keyword keyword); static int tokenize_string(const char *start, const char *end, smartlist_t *out, - token_rule_t *table); + token_rule_t *table, + int allow_annotations); static directory_token_t *get_next_token(const char **s, const char *eos, token_rule_t *table); @@ -614,7 +624,7 @@ router_parse_directory(const char *str) } ++cp; tokens = smartlist_create(); - if (tokenize_string(cp,strchr(cp,'\0'),tokens,dir_token_table)) { + if (tokenize_string(cp,strchr(cp,'\0'),tokens,dir_token_table,0)) { log_warn(LD_DIR, "Error tokenizing directory signature"); goto err; } if (smartlist_len(tokens) != 1) { @@ -643,7 +653,7 @@ router_parse_directory(const char *str) } tokens = smartlist_create(); - if (tokenize_string(str,end,tokens,dir_token_table)) { + if (tokenize_string(str,end,tokens,dir_token_table,0)) { log_warn(LD_DIR, "Error tokenizing directory"); goto err; } @@ -692,7 +702,7 @@ router_parse_runningrouters(const char *str) goto err; } tokens = smartlist_create(); - if (tokenize_string(str,eos,tokens,dir_token_table)) { + if (tokenize_string(str,eos,tokens,dir_token_table,0)) { log_warn(LD_DIR, "Error tokenizing running-routers"); goto err; } tok = smartlist_get(tokens,0); @@ -858,7 +868,8 @@ int router_parse_list_from_string(const char **s, const char *eos, smartlist_t *dest, saved_location_t saved_location, - int want_extrainfo) + int want_extrainfo, + int allow_annotations) { routerinfo_t *router; extrainfo_t *extrainfo; @@ -923,7 +934,8 @@ router_parse_list_from_string(const char **s, const char *eos, } } else if (!have_extrainfo && !want_extrainfo) { router = router_parse_entry_from_string(*s, end, - saved_location != SAVED_IN_CACHE); + saved_location != SAVED_IN_CACHE, + allow_annotations); if (router) { signed_desc = &router->cache_info; elt = router; @@ -977,13 +989,14 @@ dump_distinct_digest_count(int severity) */ routerinfo_t * router_parse_entry_from_string(const char *s, const char *end, - int cache_copy) + int cache_copy, int allow_annotations) { routerinfo_t *router = NULL; char digest[128]; smartlist_t *tokens = NULL, *exit_policy_tokens = NULL; directory_token_t *tok; struct in_addr in; + const char *start_of_annotations, *cp; if (!end) { end = s + strlen(s); @@ -993,12 +1006,23 @@ router_parse_entry_from_string(const char *s, const char *end, while (end > s+2 && *(end-1) == '\n' && *(end-2) == '\n') --end; + start_of_annotations = s; + cp = tor_memstr(s, end-s, "\nrouter "); + if (!cp) { + if (end-s < 7 || strcmpstart(s, "router ")) { + log_warn(LD_DIR, "No router keyword found."); + goto err; + } + } else { + s = cp+1; + } + if (router_get_router_hash(s, digest) < 0) { log_warn(LD_DIR, "Couldn't compute router hash."); return NULL; } tokens = smartlist_create(); - if (tokenize_string(s,end,tokens,routerdesc_token_table)) { + if (tokenize_string(s,end,tokens,routerdesc_token_table,allow_annotations)) { log_warn(LD_DIR, "Error tokenizing router descriptor."); goto err; } @@ -1019,6 +1043,7 @@ router_parse_entry_from_string(const char *s, const char *end, router->routerlist_index = -1; if (cache_copy) router->cache_info.signed_descriptor_body = tor_strndup(s, end-s); + router->cache_info.signed_descriptor_len = s-start_of_annotations; router->cache_info.signed_descriptor_len = end-s; memcpy(router->cache_info.signed_descriptor_digest, digest, DIGEST_LEN); @@ -1218,13 +1243,13 @@ extrainfo_parse_entry_from_string(const char *s, const char *end, return NULL; } tokens = smartlist_create(); - if (tokenize_string(s,end,tokens,extrainfo_token_table)) { - log_warn(LD_DIR, "Error tokenizing router descriptor."); + if (tokenize_string(s,end,tokens,extrainfo_token_table,0)) { + log_warn(LD_DIR, "Error tokenizing extra-info document."); goto err; } if (smartlist_len(tokens) < 2) { - log_warn(LD_DIR, "Impossibly short router descriptor."); + log_warn(LD_DIR, "Impossibly short extra-info document."); goto err; } @@ -1328,7 +1353,7 @@ authority_cert_parse_from_string(const char *s, const char **end_of_string) len = eos - s; tokens = smartlist_create(); - if (tokenize_string(s, eos, tokens, dir_key_certificate_table) < 0) { + if (tokenize_string(s, eos, tokens, dir_key_certificate_table,0) < 0) { log_warn(LD_DIR, "Error tokenizing key certificate"); goto err; } @@ -1468,7 +1493,7 @@ routerstatus_parse_entry_from_string(const char **s, smartlist_t *tokens, eos = find_start_of_next_routerstatus(*s); - if (tokenize_string(*s, eos, tokens, rtrstatus_token_table)) { + if (tokenize_string(*s, eos, tokens, rtrstatus_token_table,0)) { log_warn(LD_DIR, "Error tokenizing router status"); goto err; } @@ -1640,7 +1665,7 @@ networkstatus_parse_from_string(const char *s) } eos = find_start_of_next_routerstatus(s); - if (tokenize_string(s, eos, tokens, netstatus_token_table)) { + if (tokenize_string(s, eos, tokens, netstatus_token_table,0)) { log_warn(LD_DIR, "Error tokenizing network-status header."); goto err; } @@ -1752,7 +1777,7 @@ networkstatus_parse_from_string(const char *s) smartlist_uniq(ns->entries, _compare_routerstatus_entries, _free_duplicate_routerstatus_entry); - if (tokenize_string(s, NULL, footer_tokens, dir_footer_token_table)) { + if (tokenize_string(s, NULL, footer_tokens, dir_footer_token_table,0)) { log_warn(LD_DIR, "Error tokenizing network-status footer."); goto err; } @@ -1812,7 +1837,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, end_of_header = find_start_of_next_routerstatus(s); if (tokenize_string(s, end_of_header, tokens, is_vote ? networkstatus_vote_token_table : - networkstatus_consensus_token_table)) { + networkstatus_consensus_token_table, 0)) { log_warn(LD_DIR, "Error tokenizing network-status vote header."); goto err; } @@ -2032,7 +2057,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out, else end_of_footer = s + strlen(s); if (tokenize_string(s, end_of_footer, footer_tokens, - networkstatus_vote_footer_token_table)) { + networkstatus_vote_footer_token_table, 0)) { log_warn(LD_DIR, "Error tokenizing network-status vote footer."); goto err; } @@ -2143,7 +2168,7 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos) eos = s + strlen(s); if (tokenize_string(s, eos, tokens, - networkstatus_detached_signature_token_table)) { + networkstatus_detached_signature_token_table, 0)) { log_warn(LD_DIR, "Error tokenizing detached networkstatus signatures"); goto err; } @@ -2569,8 +2594,12 @@ get_next_token(const char **s, const char *eos, token_rule_t *table) } } - if (tok->tp == _ERR) { /* No keyword matched; call it an "opt". */ - tok->tp = K_OPT; + if (tok->tp == _ERR) { + /* No keyword matched; call it an "K_opt" or "A_unrecognized" */ + if (**s == '@') + tok->tp = _A_UNKNOWN; + else + tok->tp = K_OPT; tok->args = tor_malloc(sizeof(char*)); tok->args[0] = tor_strndup(*s, eol-*s); tok->n_args = 1; @@ -2637,12 +2666,13 @@ get_next_token(const char **s, const char *eos, token_rule_t *table) */ static int tokenize_string(const char *start, const char *end, smartlist_t *out, - token_rule_t *table) + token_rule_t *table, int allow_annotations) { const char **s; directory_token_t *tok = NULL; int counts[_NIL]; int i; + int first_nonannotation; s = &start; if (!end) @@ -2661,6 +2691,36 @@ tokenize_string(const char *start, const char *end, smartlist_t *out, *s = eat_whitespace_eos(*s, end); } + if (allow_annotations) { + first_nonannotation = -1; + for (i = 0; i < smartlist_len(out); ++i) { + tok = smartlist_get(out, i); + if (tok->tp < MIN_ANNOTATION || tok->tp > MAX_ANNOTATION) { + first_nonannotation = i; + break; + } + } + if (first_nonannotation < 0) { + log_warn(LD_DIR, "parse error: item contains only annotations"); + return -1; + } + for (i=first_nonannotation; i < smartlist_len(out); ++i) { + tok = smartlist_get(out, i); + if (tok->tp >= MIN_ANNOTATION && tok->tp <= MAX_ANNOTATION) { + log_warn(LD_DIR, "parse error: Annotations mixed with keywords"); + return -1; + } + } + } else { + for (i=0; i < smartlist_len(out); ++i) { + tok = smartlist_get(out, i); + if (tok->tp >= MIN_ANNOTATION && tok->tp <= MAX_ANNOTATION) { + log_warn(LD_DIR, "parse error: no annotations allowed."); + return -1; + } + } + first_nonannotation = 0; + } for (i = 0; table[i].t; ++i) { if (counts[table[i].v] < table[i].min_cnt) { log_warn(LD_DIR, "Parse error: missing %s element.", table[i].t); @@ -2672,7 +2732,7 @@ tokenize_string(const char *start, const char *end, smartlist_t *out, } if (table[i].pos & AT_START) { if (smartlist_len(out) < 1 || - (tok = smartlist_get(out, 0))->tp != table[i].v) { + (tok = smartlist_get(out, first_nonannotation))->tp != table[i].v) { log_warn(LD_DIR, "Parse error: first item is not %s.", table[i].t); return -1; } |