mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 13:13:44 +01:00
r12387@catbus: nickm | 2007-04-16 00:06:40 -0400
Refactor router/directory parsing backend: use a separate token table for everything that we parse, and enforce the correct count of each item. svn:r9965
This commit is contained in:
parent
108f1c255f
commit
cf02ab6d39
@ -53,6 +53,8 @@ Changes in version 0.2.0.1-alpha - 2007-??-??
|
|||||||
- Don't save non-general-purpose router descriptors to the disk cache,
|
- Don't save non-general-purpose router descriptors to the disk cache,
|
||||||
because we have no way of remembering what their purpose was when
|
because we have no way of remembering what their purpose was when
|
||||||
we restart.
|
we restart.
|
||||||
|
- Correctly enforce that elements of directory objects do not appear
|
||||||
|
more often than they are allowed to appear.
|
||||||
|
|
||||||
o Minor bugfixes (controller), reported by daejees:
|
o Minor bugfixes (controller), reported by daejees:
|
||||||
- Make 'getinfo fingerprint' return a 551 error if we're not a
|
- Make 'getinfo fingerprint' return a 551 error if we're not a
|
||||||
|
@ -22,7 +22,7 @@ const char routerparse_c_id[] =
|
|||||||
* not-a-token.
|
* not-a-token.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
K_ACCEPT,
|
K_ACCEPT = 0,
|
||||||
K_DIRECTORY_SIGNATURE,
|
K_DIRECTORY_SIGNATURE,
|
||||||
K_RECOMMENDED_SOFTWARE,
|
K_RECOMMENDED_SOFTWARE,
|
||||||
K_REJECT,
|
K_REJECT,
|
||||||
@ -77,7 +77,7 @@ typedef struct directory_token_t {
|
|||||||
int n_args; /**< Number of elements in args */
|
int n_args; /**< Number of elements in args */
|
||||||
char **args; /**< Array of arguments from keyword line. */
|
char **args; /**< Array of arguments from keyword line. */
|
||||||
char *object_type; /**< -----BEGIN [object_type]-----*/
|
char *object_type; /**< -----BEGIN [object_type]-----*/
|
||||||
size_t object_size; /**< Bytes in object_body */
|
size_t object_size; /**< Bytes in object_body */
|
||||||
char *object_body; /**< Contents of object, base64-decoded. */
|
char *object_body; /**< Contents of object, base64-decoded. */
|
||||||
crypto_pk_env_t *key; /**< For public keys only. */
|
crypto_pk_env_t *key; /**< For public keys only. */
|
||||||
const char *error; /**< For _ERR tokens only. */
|
const char *error; /**< For _ERR tokens only. */
|
||||||
@ -102,63 +102,105 @@ typedef enum {
|
|||||||
OBJ_OK, /**< Object is optional. */
|
OBJ_OK, /**< Object is optional. */
|
||||||
} obj_syntax;
|
} obj_syntax;
|
||||||
|
|
||||||
/** Rules for where a keyword can appear. */
|
/** DOCDOC */
|
||||||
typedef enum {
|
typedef struct token_rule_t {
|
||||||
DIR = 1, /**< Appears only in directory. */
|
const char *t; directory_keyword v; arg_syntax s; obj_syntax os;
|
||||||
RTR = 2, /**< Appears only in router descriptor or runningrouters. */
|
int min_cnt; int max_cnt;
|
||||||
NETSTATUS = 4, /**< v2 or later ("versioned") network status. */
|
} token_rule_t;
|
||||||
ANYSIGNED = 7, /**< Any "full" document (that is, not a router status.) */
|
|
||||||
RTRSTATUS = 8, /**< Router-status portion of a versioned network status. */
|
|
||||||
EXTRAINFO = 16, /**< DOCDOC */
|
|
||||||
ANY = 31, /**< Appears in any document type. */
|
|
||||||
} where_syntax;
|
|
||||||
|
|
||||||
/** Table mapping keywords to token value and to argument rules. */
|
/** DOCDOC */
|
||||||
static struct {
|
#define END_OF_TABLE { NULL, _NIL, NO_ARGS, NO_OBJ, 0, INT_MAX }
|
||||||
const char *t; directory_keyword v; arg_syntax s; obj_syntax os; int ws;
|
#define T(s,t,a,o) { s, t, a, o, 0, INT_MAX }
|
||||||
} token_table[] = {
|
#define T0N(s,t,a,o) { s, t, a, o, 0, INT_MAX }
|
||||||
{ "accept", K_ACCEPT, ARGS, NO_OBJ, RTR },
|
#define T1(s,t,a,o) { s, t, a, o, 1, 1 }
|
||||||
{ "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ,
|
#define T01(s,t,a,o) { s, t, a, o, 0, 1 }
|
||||||
DIR|NETSTATUS},
|
|
||||||
{ "r", K_R, ARGS, NO_OBJ, RTRSTATUS },
|
/** DOCDOC */
|
||||||
{ "s", K_S, ARGS, NO_OBJ, RTRSTATUS },
|
static token_rule_t routerdesc_token_table[] = {
|
||||||
{ "v", K_V, CONCAT_ARGS, NO_OBJ, RTRSTATUS },
|
T0N("accept", K_ACCEPT, ARGS, NO_OBJ ),
|
||||||
{ "reject", K_REJECT, ARGS, NO_OBJ, RTR },
|
T0N("reject", K_REJECT, ARGS, NO_OBJ ),
|
||||||
{ "router", K_ROUTER, ARGS, NO_OBJ, RTR },
|
T1( "router", K_ROUTER, ARGS, NO_OBJ ),
|
||||||
{ "recommended-software",K_RECOMMENDED_SOFTWARE,ARGS, NO_OBJ, DIR },
|
T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY ),
|
||||||
{ "signed-directory", K_SIGNED_DIRECTORY, NO_ARGS, NO_OBJ, DIR },
|
T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY ),
|
||||||
{ "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY,RTR },
|
T1( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
|
||||||
{ "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY,RTR },
|
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
|
||||||
{ "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ,RTR|EXTRAINFO },
|
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
|
||||||
{ "running-routers", K_RUNNING_ROUTERS, ARGS, NO_OBJ, DIR },
|
T01("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
|
||||||
{ "router-status", K_ROUTER_STATUS, ARGS, NO_OBJ, DIR },
|
T01("uptime", K_UPTIME, ARGS, NO_OBJ ),
|
||||||
{ "bandwidth", K_BANDWIDTH, ARGS, NO_OBJ, RTR },
|
T01("family", K_FAMILY, ARGS, NO_OBJ ),
|
||||||
{ "platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ, RTR },
|
T01("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
|
||||||
{ "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ, ANYSIGNED|EXTRAINFO },
|
T01("hibernating", K_HIBERNATING, ARGS, NO_OBJ ),
|
||||||
{ "opt", K_OPT, CONCAT_ARGS, OBJ_OK, ANY },
|
T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ),
|
||||||
{ "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ, ANYSIGNED },
|
T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
|
||||||
{ "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ, DIR },
|
T01("eventdns", K_EVENTDNS, ARGS, NO_OBJ ),
|
||||||
{ "uptime", K_UPTIME, ARGS, NO_OBJ, RTR },
|
T01("extra-info-digest", K_EXTRA_INFO_DIGEST, ARGS, NO_OBJ ),
|
||||||
{ "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, OBJ_OK,
|
T01("caches-extra-info", K_CACHES_EXTRA_INFO, NO_ARGS, NO_OBJ ),
|
||||||
DIR|NETSTATUS},
|
T1("bandwidth", K_BANDWIDTH, ARGS, NO_OBJ ),
|
||||||
{ "family", K_FAMILY, ARGS, NO_OBJ, RTR },
|
T01("platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ ),
|
||||||
{ "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ, ANYSIGNED },
|
|
||||||
{ "hibernating", K_HIBERNATING, ARGS, NO_OBJ, RTR },
|
END_OF_TABLE
|
||||||
{ "read-history", K_READ_HISTORY, ARGS, NO_OBJ, RTR|EXTRAINFO },
|
|
||||||
{ "write-history", K_WRITE_HISTORY, ARGS, NO_OBJ, RTR|EXTRAINFO },
|
|
||||||
{ "network-status-version", K_NETWORK_STATUS_VERSION,
|
|
||||||
ARGS, NO_OBJ, NETSTATUS },
|
|
||||||
{ "dir-source", K_DIR_SOURCE, ARGS, NO_OBJ, NETSTATUS },
|
|
||||||
{ "dir-options", K_DIR_OPTIONS, ARGS, NO_OBJ, NETSTATUS },
|
|
||||||
{ "client-versions", K_CLIENT_VERSIONS, ARGS, NO_OBJ, NETSTATUS },
|
|
||||||
{ "server-versions", K_SERVER_VERSIONS, ARGS, NO_OBJ, NETSTATUS },
|
|
||||||
{ "eventdns", K_EVENTDNS, ARGS, NO_OBJ, RTR },
|
|
||||||
{ "extra-info", K_EXTRA_INFO, ARGS, NO_OBJ, EXTRAINFO },
|
|
||||||
{ "extra-info-digest", K_EXTRA_INFO_DIGEST, ARGS, NO_OBJ, RTR },
|
|
||||||
{ "caches-extra-info", K_CACHES_EXTRA_INFO, NO_ARGS, NO_OBJ, RTR },
|
|
||||||
{ NULL, _NIL, NO_ARGS, NO_OBJ, ANY }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static token_rule_t extrainfo_token_table[] = {
|
||||||
|
T1( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
|
||||||
|
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
|
||||||
|
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
|
||||||
|
T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ),
|
||||||
|
T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
|
||||||
|
T1( "extra-info", K_EXTRA_INFO, ARGS, NO_OBJ ),
|
||||||
|
|
||||||
|
END_OF_TABLE
|
||||||
|
};
|
||||||
|
|
||||||
|
static token_rule_t rtrstatus_token_table[] = {
|
||||||
|
T1( "r", K_R, ARGS, NO_OBJ ),
|
||||||
|
T1( "s", K_S, ARGS, NO_OBJ ),
|
||||||
|
T01("v", K_V, CONCAT_ARGS, NO_OBJ ),
|
||||||
|
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
|
||||||
|
END_OF_TABLE
|
||||||
|
};
|
||||||
|
|
||||||
|
static token_rule_t netstatus_token_table[] = {
|
||||||
|
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
|
||||||
|
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
|
||||||
|
T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
|
||||||
|
T1( "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, OBJ_OK ),
|
||||||
|
T1( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
|
||||||
|
T1( "network-status-version", K_NETWORK_STATUS_VERSION,
|
||||||
|
ARGS, NO_OBJ ),
|
||||||
|
T1( "dir-source", K_DIR_SOURCE, ARGS, NO_OBJ ),
|
||||||
|
T01("dir-options", K_DIR_OPTIONS, ARGS, NO_OBJ ),
|
||||||
|
T01("client-versions", K_CLIENT_VERSIONS, ARGS, NO_OBJ ),
|
||||||
|
T01("server-versions", K_SERVER_VERSIONS, ARGS, NO_OBJ ),
|
||||||
|
|
||||||
|
END_OF_TABLE
|
||||||
|
};
|
||||||
|
|
||||||
|
static token_rule_t dir_footer_token_table[] = {
|
||||||
|
T1( "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ ),
|
||||||
|
END_OF_TABLE
|
||||||
|
};
|
||||||
|
|
||||||
|
static token_rule_t dir_token_table[] = {
|
||||||
|
/* don't enforce counts; this is obsolete. */
|
||||||
|
T( "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ ),
|
||||||
|
T( "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ ),
|
||||||
|
T( "recommended-software",K_RECOMMENDED_SOFTWARE,ARGS, NO_OBJ ),
|
||||||
|
T( "signed-directory", K_SIGNED_DIRECTORY, NO_ARGS, NO_OBJ ),
|
||||||
|
|
||||||
|
T( "running-routers", K_RUNNING_ROUTERS, ARGS, NO_OBJ ),
|
||||||
|
T( "router-status", K_ROUTER_STATUS, ARGS, NO_OBJ ),
|
||||||
|
T( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
|
||||||
|
T( "opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
|
||||||
|
T( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
|
||||||
|
T( "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, OBJ_OK ),
|
||||||
|
T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
|
||||||
|
|
||||||
|
END_OF_TABLE
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef T
|
||||||
|
|
||||||
/* static function prototypes */
|
/* static function prototypes */
|
||||||
static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
|
static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
|
||||||
static addr_policy_t *router_parse_addr_policy(directory_token_t *tok);
|
static addr_policy_t *router_parse_addr_policy(directory_token_t *tok);
|
||||||
@ -171,8 +213,10 @@ static smartlist_t *find_all_exitpolicy(smartlist_t *s);
|
|||||||
static directory_token_t *find_first_by_keyword(smartlist_t *s,
|
static directory_token_t *find_first_by_keyword(smartlist_t *s,
|
||||||
directory_keyword keyword);
|
directory_keyword keyword);
|
||||||
static int tokenize_string(const char *start, const char *end,
|
static int tokenize_string(const char *start, const char *end,
|
||||||
smartlist_t *out, where_syntax where);
|
smartlist_t *out,
|
||||||
static directory_token_t *get_next_token(const char **s, where_syntax where);
|
struct token_rule_t *table);
|
||||||
|
static directory_token_t *get_next_token(const char **s,
|
||||||
|
struct token_rule_t *table);
|
||||||
static int check_directory_signature(const char *digest,
|
static int check_directory_signature(const char *digest,
|
||||||
directory_token_t *tok,
|
directory_token_t *tok,
|
||||||
crypto_pk_env_t *pkey,
|
crypto_pk_env_t *pkey,
|
||||||
@ -402,7 +446,7 @@ router_parse_directory(const char *str)
|
|||||||
}
|
}
|
||||||
++cp;
|
++cp;
|
||||||
tokens = smartlist_create();
|
tokens = smartlist_create();
|
||||||
if (tokenize_string(cp,strchr(cp,'\0'),tokens,DIR)) {
|
if (tokenize_string(cp,strchr(cp,'\0'),tokens,dir_token_table)) {
|
||||||
log_warn(LD_DIR, "Error tokenizing directory signature"); goto err;
|
log_warn(LD_DIR, "Error tokenizing directory signature"); goto err;
|
||||||
}
|
}
|
||||||
if (smartlist_len(tokens) != 1) {
|
if (smartlist_len(tokens) != 1) {
|
||||||
@ -431,7 +475,7 @@ router_parse_directory(const char *str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tokens = smartlist_create();
|
tokens = smartlist_create();
|
||||||
if (tokenize_string(str,end,tokens,DIR)) {
|
if (tokenize_string(str,end,tokens,dir_token_table)) {
|
||||||
log_warn(LD_DIR, "Error tokenizing directory"); goto err;
|
log_warn(LD_DIR, "Error tokenizing directory"); goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,7 +525,7 @@ router_parse_runningrouters(const char *str)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
tokens = smartlist_create();
|
tokens = smartlist_create();
|
||||||
if (tokenize_string(str,str+strlen(str),tokens,DIR)) {
|
if (tokenize_string(str,str+strlen(str),tokens,dir_token_table)) {
|
||||||
log_warn(LD_DIR, "Error tokenizing running-routers"); goto err;
|
log_warn(LD_DIR, "Error tokenizing running-routers"); goto err;
|
||||||
}
|
}
|
||||||
tok = smartlist_get(tokens,0);
|
tok = smartlist_get(tokens,0);
|
||||||
@ -540,7 +584,7 @@ find_dir_signing_key(const char *str)
|
|||||||
return NULL;
|
return NULL;
|
||||||
++cp; /* Now cp points to the start of the token. */
|
++cp; /* Now cp points to the start of the token. */
|
||||||
|
|
||||||
tok = get_next_token(&cp, DIR);
|
tok = get_next_token(&cp, dir_token_table);
|
||||||
if (!tok) {
|
if (!tok) {
|
||||||
log_warn(LD_DIR, "Unparseable dir-signing-key token");
|
log_warn(LD_DIR, "Unparseable dir-signing-key token");
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -772,7 +816,7 @@ router_parse_entry_from_string(const char *s, const char *end,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
tokens = smartlist_create();
|
tokens = smartlist_create();
|
||||||
if (tokenize_string(s,end,tokens,RTR)) {
|
if (tokenize_string(s,end,tokens,routerdesc_token_table)) {
|
||||||
log_warn(LD_DIR, "Error tokeninzing router descriptor.");
|
log_warn(LD_DIR, "Error tokeninzing router descriptor.");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -1038,7 +1082,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
tokens = smartlist_create();
|
tokens = smartlist_create();
|
||||||
if (tokenize_string(s,end,tokens,EXTRAINFO)) {
|
if (tokenize_string(s,end,tokens,extrainfo_token_table)) {
|
||||||
log_warn(LD_DIR, "Error tokeninzing router descriptor.");
|
log_warn(LD_DIR, "Error tokeninzing router descriptor.");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -1162,7 +1206,7 @@ routerstatus_parse_entry_from_string(const char **s, smartlist_t *tokens)
|
|||||||
|
|
||||||
eos = find_start_of_next_routerstatus(*s);
|
eos = find_start_of_next_routerstatus(*s);
|
||||||
|
|
||||||
if (tokenize_string(*s, eos, tokens, RTRSTATUS)) {
|
if (tokenize_string(*s, eos, tokens, rtrstatus_token_table)) {
|
||||||
log_warn(LD_DIR, "Error tokenizing router status");
|
log_warn(LD_DIR, "Error tokenizing router status");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -1297,6 +1341,7 @@ networkstatus_parse_from_string(const char *s)
|
|||||||
{
|
{
|
||||||
const char *eos;
|
const char *eos;
|
||||||
smartlist_t *tokens = smartlist_create();
|
smartlist_t *tokens = smartlist_create();
|
||||||
|
smartlist_t *footer_tokens = smartlist_create();
|
||||||
networkstatus_t *ns = NULL;
|
networkstatus_t *ns = NULL;
|
||||||
char ns_digest[DIGEST_LEN];
|
char ns_digest[DIGEST_LEN];
|
||||||
char tmp_digest[DIGEST_LEN];
|
char tmp_digest[DIGEST_LEN];
|
||||||
@ -1310,7 +1355,7 @@ networkstatus_parse_from_string(const char *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
eos = find_start_of_next_routerstatus(s);
|
eos = find_start_of_next_routerstatus(s);
|
||||||
if (tokenize_string(s, eos, tokens, NETSTATUS)) {
|
if (tokenize_string(s, eos, tokens, netstatus_token_table)) {
|
||||||
log_warn(LD_DIR, "Error tokenizing network-status header.");
|
log_warn(LD_DIR, "Error tokenizing network-status header.");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -1433,15 +1478,15 @@ networkstatus_parse_from_string(const char *s)
|
|||||||
smartlist_uniq(ns->entries, _compare_routerstatus_entries,
|
smartlist_uniq(ns->entries, _compare_routerstatus_entries,
|
||||||
_free_duplicate_routerstatus_entry);
|
_free_duplicate_routerstatus_entry);
|
||||||
|
|
||||||
if (tokenize_string(s, NULL, tokens, NETSTATUS)) {
|
if (tokenize_string(s, NULL, footer_tokens, dir_footer_token_table)) {
|
||||||
log_warn(LD_DIR, "Error tokenizing network-status footer.");
|
log_warn(LD_DIR, "Error tokenizing network-status footer.");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (smartlist_len(tokens) < 1) {
|
if (smartlist_len(footer_tokens) < 1) {
|
||||||
log_warn(LD_DIR, "Too few items in network-status footer.");
|
log_warn(LD_DIR, "Too few items in network-status footer.");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
tok = smartlist_get(tokens, smartlist_len(tokens)-1);
|
tok = smartlist_get(footer_tokens, smartlist_len(footer_tokens)-1);
|
||||||
if (tok->tp != K_DIRECTORY_SIGNATURE) {
|
if (tok->tp != K_DIRECTORY_SIGNATURE) {
|
||||||
log_warn(LD_DIR,
|
log_warn(LD_DIR,
|
||||||
"Expected network-status footer to end with a signature.");
|
"Expected network-status footer to end with a signature.");
|
||||||
@ -1460,6 +1505,8 @@ networkstatus_parse_from_string(const char *s)
|
|||||||
done:
|
done:
|
||||||
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
|
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
|
||||||
smartlist_free(tokens);
|
smartlist_free(tokens);
|
||||||
|
SMARTLIST_FOREACH(footer_tokens, directory_token_t *, t, token_free(t));
|
||||||
|
smartlist_free(footer_tokens);
|
||||||
|
|
||||||
return ns;
|
return ns;
|
||||||
}
|
}
|
||||||
@ -1494,7 +1541,7 @@ router_parse_addr_policy_from_string(const char *s, int assume_action)
|
|||||||
tor_free(tmp);
|
tor_free(tmp);
|
||||||
cp = tmp = new_str;
|
cp = tmp = new_str;
|
||||||
}
|
}
|
||||||
tok = get_next_token(&cp, RTR);
|
tok = get_next_token(&cp, routerdesc_token_table);
|
||||||
if (tok->tp == _ERR) {
|
if (tok->tp == _ERR) {
|
||||||
log_warn(LD_DIR, "Error reading address policy: %s", tok->error);
|
log_warn(LD_DIR, "Error reading address policy: %s", tok->error);
|
||||||
goto err;
|
goto err;
|
||||||
@ -1668,11 +1715,10 @@ token_free(directory_token_t *tok)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Helper function: read the next token from *s, advance *s to the end
|
/** Helper function: read the next token from *s, advance *s to the end
|
||||||
* of the token, and return the parsed token. If 'where' is DIR
|
* of the token, and return the parsed token. DOCDOC table
|
||||||
* or RTR, reject all tokens of the wrong type.
|
|
||||||
*/
|
*/
|
||||||
static directory_token_t *
|
static directory_token_t *
|
||||||
get_next_token(const char **s, where_syntax where)
|
get_next_token(const char **s, struct token_rule_t *table)
|
||||||
{
|
{
|
||||||
const char *next, *obstart;
|
const char *next, *obstart;
|
||||||
int i, done, allocated, is_opt;
|
int i, done, allocated, is_opt;
|
||||||
@ -1710,23 +1756,12 @@ get_next_token(const char **s, where_syntax where)
|
|||||||
RET_ERR("opt without keyword");
|
RET_ERR("opt without keyword");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; token_table[i].t ; ++i) {
|
for (i = 0; table[i].t ; ++i) {
|
||||||
if (!strncmp(token_table[i].t, *s, next-*s)) {
|
if (!strncmp(table[i].t, *s, next-*s)) {
|
||||||
/* We've found the keyword. */
|
/* We've found the keyword. */
|
||||||
tok->tp = token_table[i].v;
|
tok->tp = table[i].v;
|
||||||
a_syn = token_table[i].s;
|
a_syn = table[i].s;
|
||||||
o_syn = token_table[i].os;
|
o_syn = table[i].os;
|
||||||
if (!(token_table[i].ws & where)) {
|
|
||||||
if (where == DIR) {
|
|
||||||
RET_ERR("Found an out-of-place token in a directory section");
|
|
||||||
} else if (where == RTR) {
|
|
||||||
RET_ERR("Found an out-of-place token in a router descriptor");
|
|
||||||
} else if (where == NETSTATUS) {
|
|
||||||
RET_ERR("Found an out-of-place token in a network-status header");
|
|
||||||
} else {
|
|
||||||
RET_ERR("Found an out-of-place token in a router status body");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (a_syn == ARGS) {
|
if (a_syn == ARGS) {
|
||||||
/* This keyword takes multiple arguments. */
|
/* This keyword takes multiple arguments. */
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -1846,28 +1881,45 @@ get_next_token(const char **s, where_syntax where)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Read all tokens from a string between <b>start</b> and <b>end</b>, and add
|
/** Read all tokens from a string between <b>start</b> and <b>end</b>, and add
|
||||||
* them to <b>out</b>. If <b>is_dir</b> is true, reject all non-directory
|
* them to <b>out</b>. DOCDOC table.
|
||||||
* tokens; else reject all non-routerdescriptor tokens.
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
tokenize_string(const char *start, const char *end, smartlist_t *out,
|
tokenize_string(const char *start, const char *end, smartlist_t *out,
|
||||||
where_syntax where)
|
token_rule_t *table)
|
||||||
{
|
{
|
||||||
const char **s;
|
const char **s;
|
||||||
directory_token_t *tok = NULL;
|
directory_token_t *tok = NULL;
|
||||||
|
int counts[_NIL];
|
||||||
|
int i;
|
||||||
|
|
||||||
s = &start;
|
s = &start;
|
||||||
if (!end)
|
if (!end)
|
||||||
end = start+strlen(start);
|
end = start+strlen(start);
|
||||||
|
memset(counts, 0, sizeof(counts));
|
||||||
|
for (i = 0; i < _NIL; ++i)
|
||||||
|
counts[i] = 0;
|
||||||
while (*s < end && (!tok || tok->tp != _EOF)) {
|
while (*s < end && (!tok || tok->tp != _EOF)) {
|
||||||
tok = get_next_token(s, where);
|
tok = get_next_token(s, table);
|
||||||
if (tok->tp == _ERR) {
|
if (tok->tp == _ERR) {
|
||||||
log_warn(LD_DIR, "parse error: %s", tok->error);
|
log_warn(LD_DIR, "parse error: %s", tok->error);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
++counts[tok->tp];
|
||||||
smartlist_add(out, tok);
|
smartlist_add(out, tok);
|
||||||
*s = eat_whitespace(*s);
|
*s = eat_whitespace(*s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
tor_assert(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (counts[table[i].v] > table[i].max_cnt) {
|
||||||
|
log_warn(LD_DIR, "Parse error: too many %s elements.", table[i].t);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user