summaryrefslogtreecommitdiff
path: root/src/or/routerparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/routerparse.c')
-rw-r--r--src/or/routerparse.c146
1 files changed, 125 insertions, 21 deletions
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 686ac48e40..cb2bc72d0c 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -6,7 +6,51 @@
/**
* \file routerparse.c
- * \brief Code to parse and validate router descriptors and directories.
+ * \brief Code to parse and validate router descriptors, consenus directories,
+ * and similar objects.
+ *
+ * The objects parsed by this module use a common text-based metaformat,
+ * documented in dir-spec.txt in torspec.git. This module is itself divided
+ * into two major kinds of function: code to handle the metaformat, and code
+ * to convert from particular instances of the metaformat into the
+ * objects that Tor uses.
+ *
+ * The generic parsing code works by calling a table-based tokenizer on the
+ * input string. Each token corresponds to a single line with a token, plus
+ * optional arguments on that line, plus an optional base-64 encoded object
+ * after that line. Each token has a definition in a table of token_rule_t
+ * entries that describes how many arguments it can take, whether it takes an
+ * object, how many times it may appear, whether it must appear first, and so
+ * on.
+ *
+ * The tokenizer function tokenize_string() converts its string input into a
+ * smartlist full of instances of directory_token_t, according to a provided
+ * table of token_rule_t.
+ *
+ * The generic parts of this module additionally include functions for
+ * finding the start and end of signed information inside a signed object, and
+ * computing the digest that will be signed.
+ *
+ * There are also functions for saving objects to disk that have caused
+ * parsing to fail.
+ *
+ * The specific parts of this module describe conversions between
+ * particular lists of directory_token_t and particular objects. The
+ * kinds of objects that can be parsed here are:
+ * <ul>
+ * <li>router descriptors (managed from routerlist.c)
+ * <li>extra-info documents (managed from routerlist.c)
+ * <li>microdescriptors (managed from microdesc.c)
+ * <li>vote and consensus networkstatus documents, and the routerstatus_t
+ * objects that they comprise (managed from networkstatus.c)
+ * <li>detached-signature objects used by authorities for gathering
+ * signatures on the networkstatus consensus (managed from dirvote.c)
+ * <li>authority key certificates (managed from routerlist.c)
+ * <li>hidden service descriptors (managed from rendcommon.c and rendcache.c)
+ * </ul>
+ *
+ * For no terribly good reason, the functions to <i>generate</i> signatures on
+ * the above directory objects are also in this module.
**/
#define ROUTERPARSE_PRIVATE
@@ -17,6 +61,7 @@
#include "dirserv.h"
#include "dirvote.h"
#include "policies.h"
+#include "protover.h"
#include "rendcommon.h"
#include "router.h"
#include "routerlist.h"
@@ -58,6 +103,7 @@ typedef enum {
K_RUNNING_ROUTERS,
K_ROUTER_STATUS,
K_PLATFORM,
+ K_PROTO,
K_OPT,
K_BANDWIDTH,
K_CONTACT,
@@ -74,6 +120,10 @@ typedef enum {
K_DIR_OPTIONS,
K_CLIENT_VERSIONS,
K_SERVER_VERSIONS,
+ K_RECOMMENDED_CLIENT_PROTOCOLS,
+ K_RECOMMENDED_RELAY_PROTOCOLS,
+ K_REQUIRED_CLIENT_PROTOCOLS,
+ K_REQUIRED_RELAY_PROTOCOLS,
K_OR_ADDRESS,
K_ID,
K_P,
@@ -252,12 +302,14 @@ typedef struct token_rule_t {
int is_annotation;
} token_rule_t;
-/*
+/**
+ * @name macros for defining token rules
+ *
* Helper macros to define token tables. 's' is a string, 't' is a
* directory_keyword, 'a' is a trio of argument multiplicities, and 'o' is an
* object syntax.
- *
*/
+/**@{*/
/** Appears to indicate the end of a table. */
#define END_OF_TABLE { NULL, NIL_, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
@@ -278,16 +330,17 @@ typedef struct token_rule_t {
/** An annotation that must appear no more than once */
#define A01(s,t,a,o) { s, t, a, o, 0, 1, 0, 1 }
-/* Argument multiplicity: any number of arguments. */
+/** Argument multiplicity: any number of arguments. */
#define ARGS 0,INT_MAX,0
-/* Argument multiplicity: no arguments. */
+/** Argument multiplicity: no arguments. */
#define NO_ARGS 0,0,0
-/* Argument multiplicity: concatenate all arguments. */
+/** Argument multiplicity: concatenate all arguments. */
#define CONCAT_ARGS 1,1,1
-/* Argument multiplicity: at least <b>n</b> arguments. */
+/** Argument multiplicity: at least <b>n</b> arguments. */
#define GE(n) n,INT_MAX,0
-/* Argument multiplicity: exactly <b>n</b> arguments. */
+/** Argument multiplicity: exactly <b>n</b> arguments. */
#define EQ(n) n,n,0
+/**@}*/
/** List of tokens recognized in router descriptors */
static token_rule_t routerdesc_token_table[] = {
@@ -306,6 +359,7 @@ static token_rule_t routerdesc_token_table[] = {
T01("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
T01("hibernating", K_HIBERNATING, GE(1), NO_OBJ ),
T01("platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ ),
+ T01("proto", K_PROTO, CONCAT_ARGS, NO_OBJ ),
T01("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ),
T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
@@ -382,6 +436,7 @@ static token_rule_t rtrstatus_token_table[] = {
T01("w", K_W, ARGS, NO_OBJ ),
T0N("m", K_M, CONCAT_ARGS, NO_OBJ ),
T0N("id", K_ID, GE(2), NO_OBJ ),
+ T01("pr", K_PROTO, CONCAT_ARGS, NO_OBJ ),
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
END_OF_TABLE
};
@@ -459,6 +514,14 @@ static token_rule_t networkstatus_token_table[] = {
T01("shared-rand-previous-value", K_PREVIOUS_SRV,EQ(2), NO_OBJ ),
T01("shared-rand-current-value", K_CURRENT_SRV, EQ(2), NO_OBJ ),
T0N("package", K_PACKAGE, CONCAT_ARGS, NO_OBJ ),
+ T01("recommended-client-protocols", K_RECOMMENDED_CLIENT_PROTOCOLS,
+ CONCAT_ARGS, NO_OBJ ),
+ T01("recommended-relay-protocols", K_RECOMMENDED_RELAY_PROTOCOLS,
+ CONCAT_ARGS, NO_OBJ ),
+ T01("required-client-protocols", K_REQUIRED_CLIENT_PROTOCOLS,
+ CONCAT_ARGS, NO_OBJ ),
+ T01("required-relay-protocols", K_REQUIRED_RELAY_PROTOCOLS,
+ CONCAT_ARGS, NO_OBJ ),
CERTIFICATE_MEMBERS
@@ -500,6 +563,15 @@ static token_rule_t networkstatus_consensus_token_table[] = {
T01("shared-rand-previous-value", K_PREVIOUS_SRV, EQ(2), NO_OBJ ),
T01("shared-rand-current-value", K_CURRENT_SRV, EQ(2), NO_OBJ ),
+ T01("recommended-client-protocols", K_RECOMMENDED_CLIENT_PROTOCOLS,
+ CONCAT_ARGS, NO_OBJ ),
+ T01("recommended-relay-protocols", K_RECOMMENDED_RELAY_PROTOCOLS,
+ CONCAT_ARGS, NO_OBJ ),
+ T01("required-client-protocols", K_REQUIRED_CLIENT_PROTOCOLS,
+ CONCAT_ARGS, NO_OBJ ),
+ T01("required-relay-protocols", K_REQUIRED_RELAY_PROTOCOLS,
+ CONCAT_ARGS, NO_OBJ ),
+
END_OF_TABLE
};
@@ -2090,6 +2162,10 @@ router_parse_entry_from_string(const char *s, const char *end,
router->platform = tor_strdup(tok->args[0]);
}
+ if ((tok = find_opt_by_keyword(tokens, K_PROTO))) {
+ router->protocol_list = tor_strdup(tok->args[0]);
+ }
+
if ((tok = find_opt_by_keyword(tokens, K_CONTACT))) {
router->contact_info = tor_strdup(tok->args[0]);
}
@@ -2142,7 +2218,7 @@ router_parse_entry_from_string(const char *s, const char *end,
escaped(tok->args[i]));
goto err;
}
- smartlist_add(router->declared_family, tor_strdup(tok->args[i]));
+ smartlist_add_strdup(router->declared_family, tok->args[i]);
}
}
@@ -2729,7 +2805,7 @@ routerstatus_parse_guardfraction(const char *guardfraction_str,
*
* Parse according to the syntax used by the consensus flavor <b>flav</b>.
**/
-static routerstatus_t *
+STATIC routerstatus_t *
routerstatus_parse_entry_from_string(memarea_t *area,
const char **s, smartlist_t *tokens,
networkstatus_t *vote,
@@ -2843,6 +2919,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
}
}
} else if (tok) {
+ /* This is a consensus, not a vote. */
int i;
for (i=0; i < tok->n_args; ++i) {
if (!strcmp(tok->args[i], "Exit"))
@@ -2873,14 +2950,28 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->is_v2_dir = 1;
}
}
+ /* These are implied true by having been included in a consensus made
+ * with a given method */
+ rs->is_flagged_running = 1; /* Starting with consensus method 4. */
+ if (consensus_method >= MIN_METHOD_FOR_EXCLUDING_INVALID_NODES)
+ rs->is_valid = 1;
+ }
+ int found_protocol_list = 0;
+ if ((tok = find_opt_by_keyword(tokens, K_PROTO))) {
+ found_protocol_list = 1;
+ rs->protocols_known = 1;
+ rs->supports_extend2_cells =
+ protocol_list_supports_protocol(tok->args[0], PRT_RELAY, 2);
}
if ((tok = find_opt_by_keyword(tokens, K_V))) {
tor_assert(tok->n_args == 1);
- rs->version_known = 1;
- if (strcmpstart(tok->args[0], "Tor ")) {
- } else {
- rs->version_supports_extend2_cells =
+ if (!strcmpstart(tok->args[0], "Tor ") && !found_protocol_list) {
+ /* We only do version checks like this in the case where
+ * the version is a "Tor" version, and where there is no
+ * list of protocol versions that we should be looking at instead. */
+ rs->supports_extend2_cells =
tor_version_as_new_as(tok->args[0], "0.2.4.8-alpha");
+ rs->protocols_known = 1;
}
if (vote_rs) {
vote_rs->version = tor_strdup(tok->args[0]);
@@ -2963,6 +3054,10 @@ routerstatus_parse_entry_from_string(memarea_t *area,
}
}
}
+ if (t->tp == K_PROTO) {
+ tor_assert(t->n_args == 1);
+ vote_rs->protocols = tor_strdup(t->args[0]);
+ }
} SMARTLIST_FOREACH_END(t);
} else if (flav == FLAV_MICRODESC) {
tok = find_opt_by_keyword(tokens, K_M);
@@ -3626,9 +3721,9 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHODS);
if (tok) {
for (i=0; i < tok->n_args; ++i)
- smartlist_add(ns->supported_methods, tor_strdup(tok->args[i]));
+ smartlist_add_strdup(ns->supported_methods, tok->args[i]);
} else {
- smartlist_add(ns->supported_methods, tor_strdup("1"));
+ smartlist_add_strdup(ns->supported_methods, "1");
}
} else {
tok = find_opt_by_keyword(tokens, K_CONSENSUS_METHOD);
@@ -3643,6 +3738,15 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
}
}
+ if ((tok = find_opt_by_keyword(tokens, K_RECOMMENDED_CLIENT_PROTOCOLS)))
+ ns->recommended_client_protocols = tor_strdup(tok->args[0]);
+ if ((tok = find_opt_by_keyword(tokens, K_RECOMMENDED_RELAY_PROTOCOLS)))
+ ns->recommended_relay_protocols = tor_strdup(tok->args[0]);
+ if ((tok = find_opt_by_keyword(tokens, K_REQUIRED_CLIENT_PROTOCOLS)))
+ ns->required_client_protocols = tor_strdup(tok->args[0]);
+ if ((tok = find_opt_by_keyword(tokens, K_REQUIRED_RELAY_PROTOCOLS)))
+ ns->required_relay_protocols = tor_strdup(tok->args[0]);
+
tok = find_by_keyword(tokens, K_VALID_AFTER);
if (parse_iso_time(tok->args[0], &ns->valid_after))
goto err;
@@ -3701,7 +3805,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
ns->package_lines = smartlist_new();
if (package_lst) {
SMARTLIST_FOREACH(package_lst, directory_token_t *, t,
- smartlist_add(ns->package_lines, tor_strdup(t->args[0])));
+ smartlist_add_strdup(ns->package_lines, t->args[0]));
}
smartlist_free(package_lst);
}
@@ -3710,7 +3814,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
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]));
+ smartlist_add_strdup(ns->known_flags, tok->args[i]);
if (i>0 && strcmp(tok->args[i-1], tok->args[i])>= 0) {
log_warn(LD_DIR, "%s >= %s", tok->args[i-1], tok->args[i]);
inorder = 0;
@@ -3762,7 +3866,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
}
tor_free(last_kwd);
last_kwd = tor_strndup(tok->args[i], eq_pos);
- smartlist_add(ns->net_params, tor_strdup(tok->args[i]));
+ smartlist_add_strdup(ns->net_params, tok->args[i]);
}
if (!inorder) {
log_warn(LD_DIR, "params not in order");
@@ -4005,7 +4109,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
log_warn(LD_DIR, "Bad element '%s' in params", escaped(tok->args[i]));
goto err;
}
- smartlist_add(ns->weight_params, tor_strdup(tok->args[i]));
+ smartlist_add_strdup(ns->weight_params, tok->args[i]);
}
}
@@ -5370,7 +5474,7 @@ microdescs_parse_from_string(const char *s, const char *eos,
escaped(tok->args[i]));
goto next;
}
- smartlist_add(md->family, tor_strdup(tok->args[i]));
+ smartlist_add_strdup(md->family, tok->args[i]);
}
}