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 
95 static inline int
96 policy_is_reject_star_or_null(struct short_policy_t *policy)
97 {
98  return !policy || short_policy_is_reject_star(policy);
99 }
100 
112 smartlist_t *
113 microdescs_parse_from_string(const char *s, const char *eos,
114  int allow_annotations,
115  saved_location_t where,
116  smartlist_t *invalid_digests_out)
117 {
118  smartlist_t *tokens;
119  smartlist_t *result;
120  microdesc_t *md = NULL;
121  memarea_t *area;
122  const char *start = s;
123  const char *start_of_next_microdesc;
124  int flags = allow_annotations ? TS_ANNOTATIONS_OK : 0;
125  const int copy_body = (where != SAVED_IN_CACHE);
126 
127  directory_token_t *tok;
128 
129  if (!eos)
130  eos = s + strlen(s);
131 
132  s = eat_whitespace_eos(s, eos);
133  area = memarea_new();
134  result = smartlist_new();
135  tokens = smartlist_new();
136 
137  while (s < eos) {
138  int okay = 0;
139 
140  start_of_next_microdesc = find_start_of_next_microdesc(s, eos);
141  if (!start_of_next_microdesc)
142  start_of_next_microdesc = eos;
143 
144  md = tor_malloc_zero(sizeof(microdesc_t));
145  {
146  const char *cp = tor_memstr(s, start_of_next_microdesc-s,
147  "onion-key");
148  const int no_onion_key = (cp == NULL);
149  if (no_onion_key) {
150  cp = s; /* So that we have *some* junk to put in the body */
151  }
152 
153  md->bodylen = start_of_next_microdesc - cp;
154  md->saved_location = where;
155  if (copy_body)
156  md->body = tor_memdup_nulterm(cp, md->bodylen);
157  else
158  md->body = (char*)cp;
159  md->off = cp - start;
160  crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
161  if (no_onion_key) {
162  log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Malformed or truncated descriptor");
163  goto next;
164  }
165  }
166 
167  if (tokenize_string(area, s, start_of_next_microdesc, tokens,
168  microdesc_token_table, flags)) {
169  const char *location;
170  switch (where) {
171  case SAVED_NOWHERE:
172  location = "download or generated string";
173  break;
174  case SAVED_IN_CACHE:
175  location = "cache";
176  break;
177  case SAVED_IN_JOURNAL:
178  location = "journal";
179  break;
180  default:
181  location = "unknown location";
182  break;
183  }
184  log_warn(LD_DIR, "Unparseable microdescriptor found in %s", location);
185  goto next;
186  }
187 
188  if ((tok = find_opt_by_keyword(tokens, A_LAST_LISTED))) {
189  if (parse_iso_time(tok->args[0], &md->last_listed)) {
190  log_warn(LD_DIR, "Bad last-listed time in microdescriptor");
191  goto next;
192  }
193  }
194 
195  tok = find_by_keyword(tokens, K_ONION_KEY);
196  if (!crypto_pk_public_exponent_ok(tok->key)) {
197  log_warn(LD_DIR,
198  "Relay's onion key had invalid exponent.");
199  goto next;
200  }
201  md->onion_pkey = tor_memdup(tok->object_body, tok->object_size);
202  md->onion_pkey_len = tok->object_size;
203  crypto_pk_free(tok->key);
204 
205  if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) {
207  tor_assert(tok->n_args >= 1);
208  if (curve25519_public_from_base64(&k, tok->args[0]) < 0) {
209  log_warn(LD_DIR, "Bogus ntor-onion-key in microdesc");
210  goto next;
211  }
213  tor_memdup(&k, sizeof(curve25519_public_key_t));
214  }
215 
216  smartlist_t *id_lines = find_all_by_keyword(tokens, K_ID);
217  if (id_lines) {
219  tor_assert(t->n_args >= 2);
220  if (!strcmp(t->args[0], "ed25519")) {
221  if (md->ed25519_identity_pkey) {
222  log_warn(LD_DIR, "Extra ed25519 key in microdesc");
223  smartlist_free(id_lines);
224  goto next;
225  }
227  if (ed25519_public_from_base64(&k, t->args[1])<0) {
228  log_warn(LD_DIR, "Bogus ed25519 key in microdesc");
229  smartlist_free(id_lines);
230  goto next;
231  }
232  md->ed25519_identity_pkey = tor_memdup(&k, sizeof(k));
233  }
234  } SMARTLIST_FOREACH_END(t);
235  smartlist_free(id_lines);
236  }
237 
238  {
239  smartlist_t *a_lines = find_all_by_keyword(tokens, K_A);
240  if (a_lines) {
241  find_single_ipv6_orport(a_lines, &md->ipv6_addr, &md->ipv6_orport);
242  smartlist_free(a_lines);
243  }
244  }
245 
246  if ((tok = find_opt_by_keyword(tokens, K_FAMILY))) {
247  md->family = nodefamily_parse(tok->args[0],
248  NULL,
249  NF_WARN_MALFORMED);
250  }
251 
252  if ((tok = find_opt_by_keyword(tokens, K_P))) {
253  md->exit_policy = parse_short_policy(tok->args[0]);
254  }
255  if ((tok = find_opt_by_keyword(tokens, K_P6))) {
257  }
258 
259  if (policy_is_reject_star_or_null(md->exit_policy) &&
260  policy_is_reject_star_or_null(md->ipv6_exit_policy)) {
261  md->policy_is_reject_star = 1;
262  }
263 
264  smartlist_add(result, md);
265  okay = 1;
266 
267  md = NULL;
268  next:
269  if (! okay && invalid_digests_out) {
270  smartlist_add(invalid_digests_out,
271  tor_memdup(md->digest, DIGEST256_LEN));
272  }
273  microdesc_free(md);
274  md = NULL;
275 
277  memarea_clear(area);
278  smartlist_clear(tokens);
279  s = start_of_next_microdesc;
280  }
281 
283  memarea_drop_all(area);
284  smartlist_free(tokens);
285 
286  return result;
287 }
struct crypto_pk_t * key
Definition: parsecommon.h:210
struct short_policy_t * exit_policy
Definition: microdesc_st.h:78
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:74
#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 short_policy_is_reject_star(const short_policy_t *policy)
Definition: policies.c:2987
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:65
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:53
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:70
#define CONCAT_ARGS
Definition: parsecommon.h:267
char * body
Definition: microdesc_st.h:51
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:72
char * onion_pkey
Definition: microdesc_st.h:63
int crypto_pk_public_exponent_ok(const crypto_pk_t *env)
#define LD_DIR
Definition: log.h:86
Header file for parsecommon.c.
struct curve25519_public_key_t * onion_curve25519_pkey
Definition: microdesc_st.h:68
#define SMARTLIST_FOREACH(sl, type, var, cmd)
Header file for router.c.
struct short_policy_t * ipv6_exit_policy
Definition: microdesc_st.h:80
#define log_fn(severity, domain, args,...)
Definition: log.h:274
int ed25519_public_from_base64(ed25519_public_key_t *pkey, const char *input)
char digest[DIGEST256_LEN]
Definition: microdesc_st.h:55
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:76
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.
unsigned int policy_is_reject_star
Definition: microdesc_st.h:37