tor  0.4.2.0-alpha-dev
microdesc_parse.c
Go to the documentation of this file.
1 /* Copyright (c) 2001 Matej Pfajfar.
2  * Copyright (c) 2001-2004, Roger Dingledine.
3  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4  * Copyright (c) 2007-2019, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
6 
12 #include "core/or/or.h"
13 
14 #include "app/config/config.h"
15 #include "core/or/policies.h"
22 #include "feature/relay/router.h"
26 #include "lib/memarea/memarea.h"
27 
28 #include "feature/nodelist/microdesc_st.h"
29 
32  T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024),
33  T01("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
34  T0N("id", K_ID, GE(2), NO_OBJ ),
35  T0N("a", K_A, GE(1), NO_OBJ ),
36  T01("family", K_FAMILY, CONCAT_ARGS, NO_OBJ ),
37  T01("p", K_P, CONCAT_ARGS, NO_OBJ ),
38  T01("p6", K_P6, CONCAT_ARGS, NO_OBJ ),
39  A01("@last-listed", A_LAST_LISTED, CONCAT_ARGS, NO_OBJ ),
41 };
42 
45 static const char *
46 find_start_of_next_microdesc(const char *s, const char *eos)
47 {
48  int started_with_annotations;
49  s = eat_whitespace_eos(s, eos);
50  if (!s)
51  return NULL;
52 
53 #define CHECK_LENGTH() STMT_BEGIN \
54  if (eos - s < 32) \
55  return NULL; \
56  STMT_END
57 
58 #define NEXT_LINE() STMT_BEGIN \
59  s = memchr(s, '\n', eos-s); \
60  if (!s || eos - s <= 1) \
61  return NULL; \
62  s++; \
63  STMT_END
64 
65  CHECK_LENGTH();
66 
67  started_with_annotations = (*s == '@');
68 
69  if (started_with_annotations) {
70  /* Start by advancing to the first non-annotation line. */
71  while (*s == '@')
72  NEXT_LINE();
73  }
74  CHECK_LENGTH();
75 
76  /* Now we should be pointed at an onion-key line. If we are, then skip
77  * it. */
78  if (!strcmpstart(s, "onion-key"))
79  NEXT_LINE();
80 
81  /* Okay, now we're pointed at the first line of the microdescriptor which is
82  not an annotation or onion-key. The next line that _is_ an annotation or
83  onion-key is the start of the next microdescriptor. */
84  while (eos - s > 32) {
85  if (*s == '@' || !strcmpstart(s, "onion-key"))
86  return s;
87  NEXT_LINE();
88  }
89  return NULL;
90 
91 #undef CHECK_LENGTH
92 #undef NEXT_LINE
93 }
94 
106 smartlist_t *
107 microdescs_parse_from_string(const char *s, const char *eos,
108  int allow_annotations,
109  saved_location_t where,
110  smartlist_t *invalid_digests_out)
111 {
112  smartlist_t *tokens;
113  smartlist_t *result;
114  microdesc_t *md = NULL;
115  memarea_t *area;
116  const char *start = s;
117  const char *start_of_next_microdesc;
118  int flags = allow_annotations ? TS_ANNOTATIONS_OK : 0;
119  const int copy_body = (where != SAVED_IN_CACHE);
120 
121  directory_token_t *tok;
122 
123  if (!eos)
124  eos = s + strlen(s);
125 
126  s = eat_whitespace_eos(s, eos);
127  area = memarea_new();
128  result = smartlist_new();
129  tokens = smartlist_new();
130 
131  while (s < eos) {
132  int okay = 0;
133 
134  start_of_next_microdesc = find_start_of_next_microdesc(s, eos);
135  if (!start_of_next_microdesc)
136  start_of_next_microdesc = eos;
137 
138  md = tor_malloc_zero(sizeof(microdesc_t));
139  {
140  const char *cp = tor_memstr(s, start_of_next_microdesc-s,
141  "onion-key");
142  const int no_onion_key = (cp == NULL);
143  if (no_onion_key) {
144  cp = s; /* So that we have *some* junk to put in the body */
145  }
146 
147  md->bodylen = start_of_next_microdesc - cp;
148  md->saved_location = where;
149  if (copy_body)
150  md->body = tor_memdup_nulterm(cp, md->bodylen);
151  else
152  md->body = (char*)cp;
153  md->off = cp - start;
154  crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
155  if (no_onion_key) {
156  log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Malformed or truncated descriptor");
157  goto next;
158  }
159  }
160 
161  if (tokenize_string(area, s, start_of_next_microdesc, tokens,
162  microdesc_token_table, flags)) {
163  const char *location;
164  switch (where) {
165  case SAVED_NOWHERE:
166  location = "download or generated string";
167  break;
168  case SAVED_IN_CACHE:
169  location = "cache";
170  break;
171  case SAVED_IN_JOURNAL:
172  location = "journal";
173  break;
174  default:
175  location = "unknown location";
176  break;
177  }
178  log_warn(LD_DIR, "Unparseable microdescriptor found in %s", location);
179  goto next;
180  }
181 
182  if ((tok = find_opt_by_keyword(tokens, A_LAST_LISTED))) {
183  if (parse_iso_time(tok->args[0], &md->last_listed)) {
184  log_warn(LD_DIR, "Bad last-listed time in microdescriptor");
185  goto next;
186  }
187  }
188 
189  tok = find_by_keyword(tokens, K_ONION_KEY);
190  if (!crypto_pk_public_exponent_ok(tok->key)) {
191  log_warn(LD_DIR,
192  "Relay's onion key had invalid exponent.");
193  goto next;
194  }
195  md->onion_pkey = tor_memdup(tok->object_body, tok->object_size);
196  md->onion_pkey_len = tok->object_size;
197  crypto_pk_free(tok->key);
198 
199  if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) {
201  tor_assert(tok->n_args >= 1);
202  if (curve25519_public_from_base64(&k, tok->args[0]) < 0) {
203  log_warn(LD_DIR, "Bogus ntor-onion-key in microdesc");
204  goto next;
205  }
207  tor_memdup(&k, sizeof(curve25519_public_key_t));
208  }
209 
210  smartlist_t *id_lines = find_all_by_keyword(tokens, K_ID);
211  if (id_lines) {
213  tor_assert(t->n_args >= 2);
214  if (!strcmp(t->args[0], "ed25519")) {
215  if (md->ed25519_identity_pkey) {
216  log_warn(LD_DIR, "Extra ed25519 key in microdesc");
217  smartlist_free(id_lines);
218  goto next;
219  }
221  if (ed25519_public_from_base64(&k, t->args[1])<0) {
222  log_warn(LD_DIR, "Bogus ed25519 key in microdesc");
223  smartlist_free(id_lines);
224  goto next;
225  }
226  md->ed25519_identity_pkey = tor_memdup(&k, sizeof(k));
227  }
228  } SMARTLIST_FOREACH_END(t);
229  smartlist_free(id_lines);
230  }
231 
232  {
233  smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
234  if (a_lines) {
235  find_single_ipv6_orport(a_lines, &md->ipv6_addr, &md->ipv6_orport);
236  smartlist_free(a_lines);
237  }
238  }
239 
240  if ((tok = find_opt_by_keyword(tokens, K_FAMILY))) {
241  md->family = nodefamily_parse(tok->args[0],
242  NULL,
243  NF_WARN_MALFORMED);
244  }
245 
246  if ((tok = find_opt_by_keyword(tokens, K_P))) {
247  md->exit_policy = parse_short_policy(tok->args[0]);
248  }
249  if ((tok = find_opt_by_keyword(tokens, K_P6))) {
251  }
252 
253  smartlist_add(result, md);
254  okay = 1;
255 
256  md = NULL;
257  next:
258  if (! okay && invalid_digests_out) {
259  smartlist_add(invalid_digests_out,
260  tor_memdup(md->digest, DIGEST256_LEN));
261  }
262  microdesc_free(md);
263  md = NULL;
264 
266  memarea_clear(area);
267  smartlist_clear(tokens);
268  s = start_of_next_microdesc;
269  }
270 
272  memarea_drop_all(area);
273  smartlist_free(tokens);
274 
275  return result;
276 }
struct crypto_pk_t * key
Definition: parsecommon.h:210
struct short_policy_t * exit_policy
Definition: microdesc_st.h:76
smartlist_t * find_all_by_keyword(const smartlist_t *s, directory_keyword k)
Definition: parsecommon.c:461
#define END_OF_TABLE
Definition: parsecommon.h:244
uint16_t ipv6_orport
Definition: microdesc_st.h:72
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
Header file for nodefamily.c.
#define T0N(s, t, a, o)
Definition: parsecommon.h:248
int curve25519_public_from_base64(curve25519_public_key_t *pkey, const char *input)
#define A01(s, t, a, o)
Definition: parsecommon.h:260
void smartlist_add(smartlist_t *sl, void *element)
Header file for config.c.
Header file for nickname.c.
Header file for microdesc.c.
int strcmpstart(const char *s1, const char *s2)
Definition: util_string.c:206
#define T1_START(s, t, a, o)
Definition: parsecommon.h:252
Header file for microdesc_parse.c.
size_t onion_pkey_len
Definition: microdesc_st.h:63
void memarea_clear(memarea_t *area)
Definition: memarea.c:178
memarea_t * memarea_new(void)
Definition: memarea.c:153
saved_location_t
Definition: or.h:746
int find_single_ipv6_orport(const smartlist_t *list, tor_addr_t *addr_out, uint16_t *port_out)
Definition: routerparse.c:336
size_t bodylen
Definition: microdesc_st.h:51
short_policy_t * parse_short_policy(const char *summary)
Definition: policies.c:2802
time_t last_listed
Definition: microdesc_st.h:29
#define DIGEST256_LEN
Definition: digest_sizes.h:23
Header file for policies.c.
#define NO_ARGS
Definition: parsecommon.h:265
tor_assert(buffer)
smartlist_t * microdescs_parse_from_string(const char *s, const char *eos, int allow_annotations, saved_location_t where, smartlist_t *invalid_digests_out)
Header for crypto_format.c.
#define GE(n)
Definition: parsecommon.h:269
Master header file for Tor-specific functionality.
Header for memarea.c.
Header for crypto_ed25519.c.
struct ed25519_public_key_t * ed25519_identity_pkey
Definition: microdesc_st.h:68
#define CONCAT_ARGS
Definition: parsecommon.h:267
char * body
Definition: microdesc_st.h:49
static const char * find_start_of_next_microdesc(const char *s, const char *eos)
directory_token_t * find_opt_by_keyword(const smartlist_t *s, directory_keyword keyword)
Definition: parsecommon.c:450
tor_addr_t ipv6_addr
Definition: microdesc_st.h:70
char * onion_pkey
Definition: microdesc_st.h:61
int crypto_pk_public_exponent_ok(const crypto_pk_t *env)
#define LD_DIR
Definition: log.h:85
Header file for parsecommon.c.
struct curve25519_public_key_t * onion_curve25519_pkey
Definition: microdesc_st.h:66
#define SMARTLIST_FOREACH(sl, type, var, cmd)
Header file for router.c.
struct short_policy_t * ipv6_exit_policy
Definition: microdesc_st.h:78
#define log_fn(severity, domain, args,...)
Definition: log.h:272
int ed25519_public_from_base64(ed25519_public_key_t *pkey, const char *input)
char digest[DIGEST256_LEN]
Definition: microdesc_st.h:53
void token_clear(directory_token_t *tok)
Definition: parsecommon.c:41
static token_rule_t microdesc_token_table[]
struct nodefamily_t * family
Definition: microdesc_st.h:74
int crypto_digest256(char *digest, const char *m, size_t len, digest_algorithm_t algorithm)
int parse_iso_time(const char *cp, time_t *t)
Definition: time_fmt.c:392
void smartlist_clear(smartlist_t *sl)
int tokenize_string(memarea_t *area, const char *start, const char *end, smartlist_t *out, const token_rule_t *table, int flags)
Definition: parsecommon.c:53
saved_location_bitfield_t saved_location
Definition: microdesc_st.h:31
#define T01(s, t, a, o)
Definition: parsecommon.h:258
Header for crypto_curve25519.c.
const char * eat_whitespace_eos(const char *s, const char *eos)
Definition: util_string.c:295
Header file for routerparse.c.