Efficiency hack: call tor_fix_source_file late, not early. Add "BUG" domain. Domains...
[tor.git] / src / or / routerparse.c
blobfe4ec89f12fb5d3974daea81c690f91258fdc313
1 /* Copyright 2001 Matej Pfajfar.
2 * Copyright 2001-2004 Roger Dingledine.
3 * Copyright 2004-2005 Roger Dingledine, Nick Mathewson. */
4 /* See LICENSE for licensing information */
5 /* $Id$ */
6 const char routerparse_c_id[] = "$Id$";
8 /**
9 * \file routerparse.c
10 * \brief Code to parse and validate router descriptors and directories.
11 **/
13 #define NEW_LOG_INTERFACE
14 #include "or.h"
16 /****************************************************************************/
18 /** Enumeration of possible token types. The ones starting with K_
19 * correspond to directory 'keywords'. _UNRECOGNIZED is for an
20 * unrecognized keyword; _ERR is an error in the tokenizing process,
21 * _EOF is an end-of-file marker, and _NIL is used to encode
22 * not-a-token.
24 typedef enum {
25 K_ACCEPT,
26 K_DIRECTORY_SIGNATURE,
27 K_RECOMMENDED_SOFTWARE,
28 K_REJECT,
29 K_ROUTER,
30 K_SIGNED_DIRECTORY,
31 K_SIGNING_KEY,
32 K_ONION_KEY,
33 K_ROUTER_SIGNATURE,
34 K_PUBLISHED,
35 K_RUNNING_ROUTERS,
36 K_ROUTER_STATUS,
37 K_PLATFORM,
38 K_OPT,
39 K_BANDWIDTH,
40 K_PORTS,
41 K_CONTACT,
42 K_NETWORK_STATUS,
43 K_UPTIME,
44 K_DIR_SIGNING_KEY,
45 K_FAMILY,
46 K_FINGERPRINT,
47 K_HIBERNATING,
48 K_READ_HISTORY,
49 K_WRITE_HISTORY,
50 K_NETWORK_STATUS_VERSION,
51 K_DIR_SOURCE,
52 K_DIR_OPTIONS,
53 K_CLIENT_VERSIONS,
54 K_SERVER_VERSIONS,
55 K_R,
56 K_S,
57 _UNRECOGNIZED,
58 _ERR,
59 _EOF,
60 _NIL
61 } directory_keyword;
63 /** Structure to hold a single directory token.
65 * We parse a directory by breaking it into "tokens", each consisting
66 * of a keyword, a line full of arguments, and a binary object. The
67 * arguments and object are both optional, depending on the keyword
68 * type.
70 typedef struct directory_token_t {
71 directory_keyword tp; /**< Type of the token. */
72 int n_args; /**< Number of elements in args */
73 char **args; /**< Array of arguments from keyword line. */
74 char *object_type; /**< -----BEGIN [object_type]-----*/
75 size_t object_size; /**< Bytes in object_body */
76 char *object_body; /**< Contents of object, base64-decoded. */
77 crypto_pk_env_t *key; /**< For public keys only. */
78 const char *error; /**< For _ERR tokens only. */
79 } directory_token_t;
81 /* ********************************************************************** */
83 /** We use a table of rules to decide how to parse each token type. */
85 /** Rules for how many arguments a keyword can take. */
86 typedef enum {
87 NO_ARGS, /**< No arguments, ever. */
88 ARGS, /**< A list of arguments separated by spaces. */
89 CONCAT_ARGS, /**< The rest of the line, treated as a single argument. */
90 } arg_syntax;
92 /** Rules for whether the keyword needs an object. */
93 typedef enum {
94 NO_OBJ, /**< No object, ever. */
95 NEED_OBJ, /**< Object is required. */
96 NEED_KEY, /**< Object is required, and must be a public key. */
97 OBJ_OK, /**< Object is optional. */
98 } obj_syntax;
100 /** Rules for where a keyword can appear. */
101 typedef enum {
102 DIR = 1, /**< Appears only in directory. */
103 RTR = 2, /**< Appears only in router descriptor or runningrouters. */
104 NETSTATUS = 4, /**< v2 or later ("versioned") network status. */
105 ANYSIGNED = 7, /**< Any "full" document (that is, not a router status.) */
106 RTRSTATUS = 8, /**< Router-status portion of a versioned network status. */
107 ANY = 15, /**< Appears in any document type. */
108 } where_syntax;
110 /** Table mapping keywords to token value and to argument rules. */
111 static struct {
112 const char *t; int v; arg_syntax s; obj_syntax os; int ws;
113 } token_table[] = {
114 { "accept", K_ACCEPT, ARGS, NO_OBJ, RTR },
115 { "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ,
116 DIR|NETSTATUS},
117 { "r", K_R, ARGS, NO_OBJ, RTRSTATUS },
118 { "s", K_S, ARGS, NO_OBJ, RTRSTATUS },
119 { "reject", K_REJECT, ARGS, NO_OBJ, RTR },
120 { "router", K_ROUTER, ARGS, NO_OBJ, RTR },
121 { "recommended-software",K_RECOMMENDED_SOFTWARE,ARGS, NO_OBJ, DIR },
122 { "signed-directory", K_SIGNED_DIRECTORY, NO_ARGS, NO_OBJ, DIR },
123 { "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY,RTR },
124 { "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY,RTR },
125 { "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ,RTR },
126 { "running-routers", K_RUNNING_ROUTERS, ARGS, NO_OBJ, DIR },
127 { "router-status", K_ROUTER_STATUS, ARGS, NO_OBJ, DIR },
128 { "ports", K_PORTS, ARGS, NO_OBJ, RTR },
129 { "bandwidth", K_BANDWIDTH, ARGS, NO_OBJ, RTR },
130 { "platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ, RTR },
131 { "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ, ANYSIGNED },
132 { "opt", K_OPT, CONCAT_ARGS, OBJ_OK, ANY },
133 { "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ, ANYSIGNED },
134 { "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ, DIR },
135 { "uptime", K_UPTIME, ARGS, NO_OBJ, RTR },
136 { "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, OBJ_OK,
137 DIR|NETSTATUS},
138 { "family", K_FAMILY, ARGS, NO_OBJ, RTR },
139 { "fingerprint", K_FINGERPRINT, ARGS, NO_OBJ, ANYSIGNED },
140 { "hibernating", K_HIBERNATING, ARGS, NO_OBJ, RTR },
141 { "read-history", K_READ_HISTORY, ARGS, NO_OBJ, RTR },
142 { "write-history", K_WRITE_HISTORY, ARGS, NO_OBJ, RTR },
143 { "network-status-version", K_NETWORK_STATUS_VERSION,
144 ARGS, NO_OBJ, NETSTATUS },
145 { "dir-source", K_DIR_SOURCE, ARGS, NO_OBJ, NETSTATUS },
146 { "dir-options", K_DIR_OPTIONS, ARGS, NO_OBJ, NETSTATUS },
147 { "client-versions", K_CLIENT_VERSIONS, ARGS, NO_OBJ, NETSTATUS },
148 { "server-versions", K_SERVER_VERSIONS, ARGS, NO_OBJ, NETSTATUS },
149 { NULL, -1, NO_ARGS, NO_OBJ, ANY }
152 /* static function prototypes */
153 static int router_add_exit_policy(routerinfo_t *router,directory_token_t *tok);
154 static addr_policy_t *router_parse_addr_policy(directory_token_t *tok);
155 static int router_get_hash_impl(const char *s, char *digest,
156 const char *start_str, const char *end_str);
157 static void token_free(directory_token_t *tok);
158 static smartlist_t *find_all_exitpolicy(smartlist_t *s);
159 static directory_token_t *find_first_by_keyword(smartlist_t *s,
160 directory_keyword keyword);
161 static int tokenize_string(const char *start, const char *end,
162 smartlist_t *out, where_syntax where);
163 static directory_token_t *get_next_token(const char **s, where_syntax where);
164 static int check_directory_signature(const char *digest,
165 directory_token_t *tok,
166 crypto_pk_env_t *pkey,
167 crypto_pk_env_t *declared_key,
168 int check_authority);
169 static crypto_pk_env_t *find_dir_signing_key(const char *str);
170 static int tor_version_same_series(tor_version_t *a, tor_version_t *b);
172 /** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
173 * <b>s</b>. Return 0 on success, -1 on failure.
176 router_get_dir_hash(const char *s, char *digest)
178 return router_get_hash_impl(s,digest,
179 "signed-directory","\ndirectory-signature");
182 /** Set <b>digest</b> to the SHA-1 digest of the hash of the first router in
183 * <b>s</b>. Return 0 on success, -1 on failure.
186 router_get_router_hash(const char *s, char *digest)
188 return router_get_hash_impl(s,digest,
189 "router ","\nrouter-signature");
192 /** Set <b>digest</b> to the SHA-1 digest of the hash of the running-routers
193 * string in <b>s</b>. Return 0 on success, -1 on failure.
196 router_get_runningrouters_hash(const char *s, char *digest)
198 return router_get_hash_impl(s,digest,
199 "network-status","\ndirectory-signature");
202 /** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
203 * string in <b>s</b>. Return 0 on success, -1 on failure. */
205 router_get_networkstatus_v2_hash(const char *s, char *digest)
207 return router_get_hash_impl(s,digest,
208 "network-status-version","\ndirectory-signature");
211 /** Helper: used to generate signatures for routers, directories and
212 * network-status objects. Given a digest in <b>digest</b> and a secret
213 * <b>private_key</b>, generate an PKCS1-padded signature, BASE64-encode it,
214 * surround it with -----BEGIN/END----- pairs, and write it to the
215 * <b>buf_len</b>-byte buffer at <b>buf</b>. Return 0 on success, -1 on
216 * failure.
219 router_append_dirobj_signature(char *buf, size_t buf_len, const char *digest,
220 crypto_pk_env_t *private_key)
222 char signature[PK_BYTES];
223 int i;
225 if (crypto_pk_private_sign(private_key, signature, digest, DIGEST_LEN) < 0) {
227 warn(LD_BUG,"Couldn't sign digest.");
228 return -1;
230 if (strlcat(buf, "-----BEGIN SIGNATURE-----\n", buf_len) >= buf_len)
231 goto truncated;
233 i = strlen(buf);
234 if (base64_encode(buf+i, buf_len-i, signature, 128) < 0) {
235 warn(LD_BUG,"couldn't base64-encode signature");
236 tor_free(buf);
237 return -1;
240 if (strlcat(buf, "-----END SIGNATURE-----\n", buf_len) >= buf_len)
241 goto truncated;
243 return 0;
244 truncated:
245 warn(LD_BUG,"tried to exceed string length.");
246 return -1;
249 /** Return VS_RECOMMENDED if <b>myversion</b> is contained in
250 * <b>versionlist</b>. Else, return VS_OLD if every member of
251 * <b>versionlist</b> is newer than <b>myversion</b>. Else, return
252 * VS_NEW_IN_SERIES if there is at least one member of <b>versionlist</b> in
253 * the same series (major.minor.micro) as <b>myversion</b>, but no such member
254 * is newer than <b>myversion.</b>. Else, return VS_NEW if every memeber of
255 * <b>versionlist</b> is older than <b>myversion</b>. Else, return
256 * VS_UNRECOMMENDED.
258 * (versionlist is a comma-separated list of version strings,
259 * optionally prefixed with "Tor". Versions that can't be parsed are
260 * ignored.)
262 version_status_t
263 tor_version_is_obsolete(const char *myversion, const char *versionlist)
265 const char *vl;
266 tor_version_t mine, other;
267 int found_newer = 0, found_older = 0, found_newer_in_series = 0,
268 found_any_in_series = 0, r, same;
269 version_status_t ret = VS_UNRECOMMENDED;
270 smartlist_t *version_sl;
272 vl = versionlist;
274 debug(LD_CONFIG,"Checking whether version '%s' is in '%s'",
275 myversion, versionlist);
277 if (tor_version_parse(myversion, &mine)) {
278 err(LD_BUG,"I couldn't parse my own version (%s)", myversion);
279 tor_assert(0);
281 version_sl = smartlist_create();
282 smartlist_split_string(version_sl, versionlist, ",", SPLIT_SKIP_SPACE, 0);
284 SMARTLIST_FOREACH(version_sl, const char *, cp, {
285 if (!strcmpstart(cp, "Tor "))
286 cp += 4;
288 if (tor_version_parse(cp, &other)) {
289 /* Couldn't parse other; it can't be a match. */
290 } else {
291 same = tor_version_same_series(&mine, &other);
292 if (same)
293 found_any_in_series = 1;
294 r = tor_version_compare(&mine, &other);
295 if (r==0) {
296 ret = VS_RECOMMENDED;
297 goto done;
298 } else if (r<0) {
299 found_newer = 1;
300 if (same)
301 found_newer_in_series = 1;
302 } else if (r>0) {
303 found_older = 1;
308 /* We didn't find the listed version. Is it new or old? */
309 if (found_any_in_series && !found_newer_in_series) {
310 ret = VS_NEW_IN_SERIES;
311 } else if (found_newer && !found_older) {
312 ret = VS_OLD;
313 } else if (found_older && !found_newer) {
314 ret = VS_NEW;
315 } else {
316 ret = VS_UNRECOMMENDED;
319 done:
320 SMARTLIST_FOREACH(version_sl, char *, version, tor_free(version));
321 smartlist_free(version_sl);
322 return ret;
325 /** Return the combined status of the current version, given that we know of
326 * one set of networkstatuses that give us status <b>a</b>, and another that
327 * gives us status <b>b</b>.
329 * For example, if one authority thinks that we're NEW, and another thinks
330 * we're OLD, we're simply UNRECOMMENDED.
332 * This function does not handle calculating whether we're RECOMMENDED; that
333 * follows a simple majority rule. This function simply calculates *why*
334 * we're not recommended (if we're not).
336 version_status_t
337 version_status_join(version_status_t a, version_status_t b)
339 if (a == b)
340 return a;
341 else if (a == VS_UNRECOMMENDED || b == VS_UNRECOMMENDED)
342 return VS_UNRECOMMENDED;
343 else if (a == VS_RECOMMENDED)
344 return b;
345 else if (b == VS_RECOMMENDED)
346 return a;
347 /* Okay. Neither is 'recommended' or 'unrecommended', and they differ. */
348 else if (a == VS_OLD || b == VS_OLD)
349 return VS_UNRECOMMENDED;
350 /* One is VS_NEW, the other is VS_NEW_IN_SERIES */
351 else
352 return VS_NEW_IN_SERIES;
355 /** Read a signed directory from <b>str</b>. If it's well-formed, return 0.
356 * Otherwise, return -1. If we're a directory cache, cache it.
359 router_parse_directory(const char *str)
361 directory_token_t *tok;
362 char digest[DIGEST_LEN];
363 time_t published_on;
364 int r;
365 const char *end, *cp;
366 smartlist_t *tokens = NULL;
367 crypto_pk_env_t *declared_key = NULL;
369 /* XXXX This could be simplified a lot, but it will all go away
370 * once pre-0.1.1.8 is obsolete, and for now it's better not to
371 * tuoch it. */
373 if (router_get_dir_hash(str, digest)) {
374 warn(LD_DIR, "Unable to compute digest of directory");
375 goto err;
377 debug(LD_DIR,"Received directory hashes to %s",hex_str(digest,4));
379 /* Check signature first, before we try to tokenize. */
380 cp = str;
381 while (cp && (end = strstr(cp+1, "\ndirectory-signature")))
382 cp = end;
383 if (cp == str || !cp) {
384 warn(LD_DIR, "No signature found on directory."); goto err;
386 ++cp;
387 tokens = smartlist_create();
388 if (tokenize_string(cp,strchr(cp,'\0'),tokens,DIR)) {
389 warn(LD_DIR, "Error tokenizing directory signature"); goto err;
391 if (smartlist_len(tokens) != 1) {
392 warn(LD_DIR, "Unexpected number of tokens in signature"); goto err;
394 tok=smartlist_get(tokens,0);
395 if (tok->tp != K_DIRECTORY_SIGNATURE) {
396 warn(LD_DIR,"Expected a single directory signature"); goto err;
398 declared_key = find_dir_signing_key(str);
399 if (check_directory_signature(digest, tok, NULL, declared_key, 1)<0)
400 goto err;
402 SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
403 smartlist_free(tokens);
404 tokens = NULL;
406 /* Now try to parse the first part of the directory. */
407 if ((end = strstr(str,"\nrouter "))) {
408 ++end;
409 } else if ((end = strstr(str, "\ndirectory-signature"))) {
410 ++end;
411 } else {
412 end = str + strlen(str);
415 tokens = smartlist_create();
416 if (tokenize_string(str,end,tokens,DIR)) {
417 warn(LD_DIR, "Error tokenizing directory"); goto err;
420 if (!(tok = find_first_by_keyword(tokens, K_PUBLISHED))) {
421 warn(LD_DIR, "Missing published time on directory.");
422 goto err;
424 tor_assert(tok->n_args == 1);
426 if (parse_iso_time(tok->args[0], &published_on) < 0) {
427 goto err;
430 /* Now that we know the signature is okay, and we have a
431 * publication time, cache the directory. */
432 if (get_options()->DirPort && !get_options()->V1AuthoritativeDir)
433 dirserv_set_cached_directory(str, published_on, 0);
435 r = 0;
436 goto done;
437 err:
438 r = -1;
439 done:
440 if (declared_key) crypto_free_pk_env(declared_key);
441 if (tokens) {
442 SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
443 smartlist_free(tokens);
445 return r;
448 /** Read a signed router status statement from <b>str</b>. If it's
449 * well-formed, return 0. Otherwise, return -1. If we're a directory cache,
450 * cache it.*/
452 router_parse_runningrouters(const char *str)
454 char digest[DIGEST_LEN];
455 directory_token_t *tok;
456 time_t published_on;
457 int r = -1;
458 crypto_pk_env_t *declared_key = NULL;
459 smartlist_t *tokens = NULL;
461 if (router_get_runningrouters_hash(str, digest)) {
462 warn(LD_DIR, "Unable to compute digest of directory");
463 goto err;
465 tokens = smartlist_create();
466 if (tokenize_string(str,str+strlen(str),tokens,DIR)) {
467 warn(LD_DIR, "Error tokenizing directory"); goto err;
469 if ((tok = find_first_by_keyword(tokens, _UNRECOGNIZED))) {
470 warn(LD_DIR, "Unrecognized keyword '%s'; can't parse running-routers",
471 tok->args[0]);
472 goto err;
474 tok = smartlist_get(tokens,0);
475 if (tok->tp != K_NETWORK_STATUS) {
476 warn(LD_DIR, "Network-status starts with wrong token");
477 goto err;
480 if (!(tok = find_first_by_keyword(tokens, K_PUBLISHED))) {
481 warn(LD_DIR, "Missing published time on directory.");
482 goto err;
484 tor_assert(tok->n_args == 1);
485 if (parse_iso_time(tok->args[0], &published_on) < 0) {
486 goto err;
488 if (!(tok = find_first_by_keyword(tokens, K_DIRECTORY_SIGNATURE))) {
489 warn(LD_DIR, "Missing signature on running-routers");
490 goto err;
492 declared_key = find_dir_signing_key(str);
493 if (check_directory_signature(digest, tok, NULL, declared_key, 1) < 0)
494 goto err;
496 /* Now that we know the signature is okay, and we have a
497 * publication time, cache the list. */
498 if (get_options()->DirPort && !get_options()->V1AuthoritativeDir)
499 dirserv_set_cached_directory(str, published_on, 1);
501 r = 0;
502 err:
503 if (declared_key) crypto_free_pk_env(declared_key);
504 if (tokens) {
505 SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
506 smartlist_free(tokens);
508 return r;
511 /** Given a directory or running-routers string in <b>str</b>, try to
512 * find the its dir-signing-key token (if any). If this token is
513 * present, extract and return the key. Return NULL on failure. */
514 static crypto_pk_env_t *
515 find_dir_signing_key(const char *str)
517 const char *cp;
518 directory_token_t *tok;
519 crypto_pk_env_t *key = NULL;
521 /* Is there a dir-signing-key in the directory? */
522 cp = strstr(str, "\nopt dir-signing-key");
523 if (!cp)
524 cp = strstr(str, "\ndir-signing-key");
525 if (!cp)
526 return NULL;
527 ++cp; /* Now cp points to the start of the token. */
529 tok = get_next_token(&cp, DIR);
530 if (!tok) {
531 warn(LD_DIR, "Unparseable dir-signing-key token");
532 return NULL;
534 if (tok->tp != K_DIR_SIGNING_KEY) {
535 warn(LD_DIR, "Dir-signing-key token did not parse as expected");
536 return NULL;
539 if (tok->key) {
540 key = tok->key;
541 tok->key = NULL; /* steal reference. */
542 } else if (tok->n_args >= 1) {
543 /** XXXX Once all the directories are running 0.1.0.6-rc or later, we
544 * can remove this logic. */
545 key = crypto_pk_DER64_decode_public_key(tok->args[0]);
546 if (!key) {
547 warn(LD_DIR, "Unparseable dir-signing-key argument");
548 return NULL;
550 } else {
551 warn(LD_DIR, "Dir-signing-key token contained no key");
552 return NULL;
555 token_free(tok);
556 return key;
559 /** Return true iff <b>key</b> is allowed to sign directories.
561 static int
562 dir_signing_key_is_trusted(crypto_pk_env_t *key)
564 char digest[DIGEST_LEN];
565 if (!key) return 0;
566 if (crypto_pk_get_digest(key, digest) < 0) {
567 warn(LD_DIR, "Error computing dir-signing-key digest");
568 return 0;
570 if (!router_digest_is_trusted_dir(digest)) {
571 warn(LD_DIR, "Listed dir-signing-key is not trusted");
572 return 0;
574 return 1;
577 /** Check whether the K_DIRECTORY_SIGNATURE token in <b>tok</b> has a
578 * good signature for <b>digest</b>.
580 * If <b>declared_key</b> is set, the directory has declared what key
581 * was used to sign it, so we will use that key only if it is an
582 * authoritative directory signing key or if check_authority is 0.
584 * Otherwise, if pkey is provided, try to use it.
586 * (New callers should always use <b>declared_key</b> when possible;
587 * <b>pkey</b> is only for debugging.)
589 static int
590 check_directory_signature(const char *digest,
591 directory_token_t *tok,
592 crypto_pk_env_t *pkey,
593 crypto_pk_env_t *declared_key,
594 int check_authority)
596 char signed_digest[PK_BYTES];
597 crypto_pk_env_t *_pkey = NULL;
599 if (tok->n_args != 1) {
600 warn(LD_DIR, "Too many or too few arguments to directory-signature");
601 return -1;
604 if (declared_key) {
605 if (!check_authority || dir_signing_key_is_trusted(declared_key))
606 _pkey = declared_key;
608 if (!_pkey && pkey) {
609 /* pkey provided for debugging purposes */
610 _pkey = pkey;
612 if (!_pkey) {
613 warn(LD_DIR, "Obsolete directory format (dir signing key not present) or signing key not trusted--rejecting.");
614 return -1;
617 if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
618 warn(LD_DIR, "Bad object type or length on directory signature");
619 return -1;
622 tor_assert(_pkey);
624 if (crypto_pk_public_checksig(_pkey, signed_digest, tok->object_body, 128)
625 != 20) {
626 warn(LD_DIR, "Error reading directory: invalid signature.");
627 return -1;
629 debug(LD_DIR,"Signed directory hash starts %s", hex_str(signed_digest,4));
630 if (memcmp(digest, signed_digest, DIGEST_LEN)) {
631 warn(LD_DIR, "Error reading directory: signature does not match.");
632 return -1;
634 return 0;
637 /** Given a string *<b>s</b> containing a concatenated sequence of router
638 * descriptors, parses them and stores the result in <b>dest</b>. All routers
639 * are marked running and verified. Advances *s to a point immediately
640 * following the last router entry. Ignore any trailing router entries that
641 * are not complete. Returns 0 on success and -1 on failure.
644 router_parse_list_from_string(const char **s, smartlist_t *dest)
646 routerinfo_t *router;
647 const char *end, *cp;
649 tor_assert(s);
650 tor_assert(*s);
651 tor_assert(dest);
653 while (1) {
654 *s = eat_whitespace(*s);
655 /* Don't start parsing the rest of *s unless it contains a router. */
656 if (strcmpstart(*s, "router ")!=0)
657 break;
658 if ((end = strstr(*s+1, "\nrouter "))) {
659 cp = end;
660 end++;
661 } else if ((end = strstr(*s+1, "\ndirectory-signature"))) {
662 cp = end;
663 end++;
664 } else {
665 cp = end = *s+strlen(*s);
668 while (cp > *s && (!*cp || TOR_ISSPACE(*cp)))
669 --cp;
670 /* cp now points to the last non-space character in this descriptor. */
672 while (cp > *s && *cp != '\n')
673 --cp;
674 /* cp now points to the first \n before the last non-blank line in this
675 * descriptor */
677 if (strcmpstart(cp, "\n-----END SIGNATURE-----\n")) {
678 info(LD_DIR, "Ignoring truncated router descriptor.");
679 continue;
682 router = router_parse_entry_from_string(*s, end);
684 *s = end;
685 if (!router) {
686 warn(LD_DIR, "Error reading router; skipping");
687 continue;
689 smartlist_add(dest, router);
692 return 0;
695 /** Helper function: reads a single router entry from *<b>s</b> ...
696 * *<b>end</b>. Mallocs a new router and returns it if all goes well, else
697 * returns NULL.
699 routerinfo_t *
700 router_parse_entry_from_string(const char *s, const char *end)
702 routerinfo_t *router = NULL;
703 char signed_digest[128];
704 char digest[128];
705 smartlist_t *tokens = NULL, *exit_policy_tokens = NULL;
706 directory_token_t *tok;
707 int t;
708 int ports_set, bw_set;
709 struct in_addr in;
711 if (!end) {
712 end = s + strlen(s);
715 /* point 'end' to a point immediately after the final newline. */
716 while (end > s+2 && *(end-1) == '\n' && *(end-2) == '\n')
717 --end;
719 if (router_get_router_hash(s, digest) < 0) {
720 warn(LD_DIR, "Couldn't compute router hash.");
721 return NULL;
723 tokens = smartlist_create();
724 if (tokenize_string(s,end,tokens,RTR)) {
725 warn(LD_DIR, "Error tokeninzing router descriptor.");
726 goto err;
729 if (smartlist_len(tokens) < 2) {
730 warn(LD_DIR, "Impossibly short router descriptor.");
731 goto err;
733 if ((tok = find_first_by_keyword(tokens, _UNRECOGNIZED))) {
734 warn(LD_DIR, "Unrecognized critical keyword '%s'; skipping descriptor. (It may be from another version of Tor.)",
735 tok->args[0]);
736 goto err;
739 tok = smartlist_get(tokens,0);
740 if (tok->tp != K_ROUTER) {
741 warn(LD_DIR,"Entry does not start with \"router\"");
742 goto err;
745 router = tor_malloc_zero(sizeof(routerinfo_t));
746 router->signed_descriptor = tor_strndup(s, end-s);
747 router->signed_descriptor_len = end-s;
748 memcpy(router->signed_descriptor_digest, digest, DIGEST_LEN);
749 ports_set = bw_set = 0;
751 if (tok->n_args == 2 || tok->n_args == 5 || tok->n_args == 6) {
752 router->nickname = tor_strdup(tok->args[0]);
753 if (!is_legal_nickname(router->nickname)) {
754 warn(LD_DIR,"Router nickname is invalid");
755 goto err;
757 router->address = tor_strdup(tok->args[1]);
758 if (!tor_inet_aton(router->address, &in)) {
759 warn(LD_DIR,"Router address is not an IP.");
760 goto err;
762 router->addr = ntohl(in.s_addr);
764 if (tok->n_args >= 5) {
765 router->or_port = (uint16_t) tor_parse_long(tok->args[2],10,0,65535,NULL,NULL);
766 router->dir_port = (uint16_t) tor_parse_long(tok->args[4],10,0,65535,NULL,NULL);
767 ports_set = 1;
769 } else {
770 warn(LD_DIR,"Wrong # of arguments to \"router\" (%d)",tok->n_args);
771 goto err;
774 tok = find_first_by_keyword(tokens, K_PORTS);
775 if (tok && ports_set) {
776 warn(LD_DIR,"Redundant ports line");
777 goto err;
778 } else if (tok) {
779 if (tok->n_args != 3) {
780 warn(LD_DIR,"Wrong # of arguments to \"ports\"");
781 goto err;
783 router->or_port = (uint16_t) tor_parse_long(tok->args[0],10,0,65535,NULL,NULL);
784 router->dir_port = (uint16_t) tor_parse_long(tok->args[2],10,0,65535,NULL,NULL);
785 ports_set = 1;
788 tok = find_first_by_keyword(tokens, K_BANDWIDTH);
789 if (tok && bw_set) {
790 warn(LD_DIR,"Redundant bandwidth line");
791 goto err;
792 } else if (tok) {
793 if (tok->n_args < 3) {
794 /* XXXX Once 0.0.7 is *really* dead, restore this warning to its old form*/
795 warn(LD_DIR,"Not enough arguments to \"bandwidth\": must be an obsolete server. Rejecting one server (nickname '%s').", router->nickname);
796 goto err;
798 router->bandwidthrate = tor_parse_long(tok->args[0],10,0,INT_MAX,NULL,NULL);
799 router->bandwidthburst = tor_parse_long(tok->args[1],10,0,INT_MAX,NULL,NULL);
800 router->bandwidthcapacity = tor_parse_long(tok->args[2],10,0,INT_MAX,NULL,NULL);
801 bw_set = 1;
804 if ((tok = find_first_by_keyword(tokens, K_UPTIME))) {
805 if (tok->n_args != 1) {
806 warn(LD_DIR, "Unrecognized number of args on K_UPTIME; skipping.");
807 } else {
808 router->uptime = tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL);
812 if ((tok = find_first_by_keyword(tokens, K_HIBERNATING))) {
813 if (tok->n_args < 1) {
814 warn(LD_DIR, "Too few args on 'hibernating' keyword. Skipping.");
815 } else {
816 router->is_hibernating
817 = (tor_parse_long(tok->args[0],10,0,LONG_MAX,NULL,NULL) != 0);
821 if (!(tok = find_first_by_keyword(tokens, K_PUBLISHED))) {
822 warn(LD_DIR, "Missing published time"); goto err;
824 tor_assert(tok->n_args == 1);
825 if (parse_iso_time(tok->args[0], &router->published_on) < 0)
826 goto err;
828 if (!(tok = find_first_by_keyword(tokens, K_ONION_KEY))) {
829 warn(LD_DIR, "Missing onion key"); goto err;
831 if (crypto_pk_keysize(tok->key) != PK_BYTES) {
832 warn(LD_DIR, "Wrong size on onion key: %d bits!",
833 (int)crypto_pk_keysize(tok->key)*8);
834 goto err;
836 router->onion_pkey = tok->key;
837 tok->key = NULL; /* Prevent free */
839 if (!(tok = find_first_by_keyword(tokens, K_SIGNING_KEY))) {
840 warn(LD_DIR, "Missing identity key"); goto err;
842 if (crypto_pk_keysize(tok->key) != PK_BYTES) {
843 warn(LD_DIR, "Wrong size on identity key: %d bits!",
844 (int)crypto_pk_keysize(tok->key)*8);
845 goto err;
847 router->identity_pkey = tok->key;
848 tok->key = NULL; /* Prevent free */
849 if (crypto_pk_get_digest(router->identity_pkey,router->identity_digest)) {
850 warn(LD_DIR, "Couldn't calculate key digest"); goto err;
853 if ((tok = find_first_by_keyword(tokens, K_PLATFORM))) {
854 router->platform = tor_strdup(tok->args[0]);
857 if ((tok = find_first_by_keyword(tokens, K_CONTACT))) {
858 router->contact_info = tor_strdup(tok->args[0]);
861 exit_policy_tokens = find_all_exitpolicy(tokens);
862 SMARTLIST_FOREACH(exit_policy_tokens, directory_token_t *, t,
863 if (router_add_exit_policy(router,t)<0) {
864 warn(LD_DIR,"Error in exit policy");
865 goto err;
868 if ((tok = find_first_by_keyword(tokens, K_FAMILY)) && tok->n_args) {
869 int i;
870 router->declared_family = smartlist_create();
871 for (i=0;i<tok->n_args;++i) {
872 if (!is_legal_nickname_or_hexdigest(tok->args[i])) {
873 warn(LD_DIR, "Illegal nickname '%s' in family line", tok->args[i]);
874 goto err;
876 smartlist_add(router->declared_family, tor_strdup(tok->args[i]));
880 if (!(tok = find_first_by_keyword(tokens, K_ROUTER_SIGNATURE))) {
881 warn(LD_DIR, "Missing router signature");
882 goto err;
884 if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
885 warn(LD_DIR, "Bad object type or length on router signature");
886 goto err;
888 if ((t=crypto_pk_public_checksig(router->identity_pkey, signed_digest,
889 tok->object_body, 128)) != 20) {
890 warn(LD_DIR, "Invalid signature %d",t);
891 goto err;
893 if (memcmp(digest, signed_digest, DIGEST_LEN)) {
894 warn(LD_DIR, "Mismatched signature");
895 goto err;
898 if (!ports_set) {
899 warn(LD_DIR,"No ports declared; failing.");
900 goto err;
902 if (!bw_set) {
903 warn(LD_DIR,"No bandwidth declared; failing.");
904 goto err;
906 if (!router->or_port) {
907 warn(LD_DIR,"or_port unreadable or 0. Failing.");
908 goto err;
910 if (!router->bandwidthrate) {
911 warn(LD_DIR,"bandwidthrate unreadable or 0. Failing.");
912 goto err;
914 if (!router->platform) {
915 router->platform = tor_strdup("<unknown>");
918 goto done;
920 err:
921 routerinfo_free(router);
922 router = NULL;
923 done:
924 if (tokens) {
925 SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
926 smartlist_free(tokens);
928 if (exit_policy_tokens) {
929 smartlist_free(exit_policy_tokens);
931 return router;
934 /** Helper: given a string <b>s</b>, return the start of the next router-status
935 * object (starting with "r " at the start of a line). If none is found,
936 * return the start of the next directory signature. If none is found, return
937 * the end of the string. */
938 static INLINE const char *
939 find_start_of_next_routerstatus(const char *s)
941 const char *eos = strstr(s, "\nr ");
942 if (!eos)
943 eos = strstr(s, "\ndirectory-signature");
944 if (eos)
945 return eos+1;
946 else
947 return s + strlen(s);
950 /** Given a string at *<b>s</b>, containing a routerstatus object, and an
951 * empty smartlist at <b>tokens</b>, parse and return the first router status
952 * object in the string, and advance *<b>s</b> to just after the end of the
953 * router status. Return NULL and advance *<b>s</b> on error. */
954 static routerstatus_t *
955 routerstatus_parse_entry_from_string(const char **s, smartlist_t *tokens)
957 const char *eos;
958 routerstatus_t *rs = NULL;
959 directory_token_t *tok;
960 char timebuf[ISO_TIME_LEN+1];
961 struct in_addr in;
963 tor_assert(tokens);
965 eos = find_start_of_next_routerstatus(*s);
967 if (tokenize_string(*s, eos, tokens, RTRSTATUS)) {
968 warn(LD_DIR, "Error tokenizing router status");
969 goto err;
971 if (smartlist_len(tokens) < 1) {
972 warn(LD_DIR, "Impossibly short router status");
973 goto err;
975 if ((tok = find_first_by_keyword(tokens, _UNRECOGNIZED))) {
976 warn(LD_DIR, "Unrecognized keyword \"%s\" in router status; skipping.",
977 tok->args[0]);
978 goto err;
980 if (!(tok = find_first_by_keyword(tokens, K_R))) {
981 warn(LD_DIR, "Missing 'r' keywork in router status; skipping.");
982 goto err;
984 if (tok->n_args < 8) {
985 warn(LD_DIR,
986 "Too few arguments to 'r' keywork in router status; skipping.");
988 rs = tor_malloc_zero(sizeof(routerstatus_t));
990 if (!is_legal_nickname(tok->args[0])) {
991 warn(LD_DIR,
992 "Invalid nickname '%s' in router status; skipping.", tok->args[0]);
993 goto err;
995 strlcpy(rs->nickname, tok->args[0], sizeof(rs->nickname));
997 if (digest_from_base64(rs->identity_digest, tok->args[1])) {
998 warn(LD_DIR, "Error decoding digest '%s'", tok->args[1]);
999 goto err;
1002 if (digest_from_base64(rs->descriptor_digest, tok->args[2])) {
1003 warn(LD_DIR, "Error decoding digest '%s'", tok->args[2]);
1004 goto err;
1007 if (tor_snprintf(timebuf, sizeof(timebuf), "%s %s",
1008 tok->args[3], tok->args[4]) < 0 ||
1009 parse_iso_time(timebuf, &rs->published_on)<0) {
1010 warn(LD_DIR, "Error parsing time '%s %s'", tok->args[3], tok->args[4]);
1011 goto err;
1014 if (tor_inet_aton(tok->args[5], &in) == 0) {
1015 warn(LD_DIR, "Error parsing address '%s'", tok->args[5]);
1016 goto err;
1018 rs->addr = ntohl(in.s_addr);
1020 rs->or_port =(uint16_t) tor_parse_long(tok->args[6],10,0,65535,NULL,NULL);
1021 rs->dir_port = (uint16_t) tor_parse_long(tok->args[7],10,0,65535,NULL,NULL);
1023 if ((tok = find_first_by_keyword(tokens, K_S))) {
1024 int i;
1025 for (i=0; i < tok->n_args; ++i) {
1026 if (!strcmp(tok->args[i], "Exit"))
1027 rs->is_exit = 1;
1028 else if (!strcmp(tok->args[i], "Stable"))
1029 rs->is_stable = 1;
1030 else if (!strcmp(tok->args[i], "Fast"))
1031 rs->is_fast = 1;
1032 else if (!strcmp(tok->args[i], "Running"))
1033 rs->is_running = 1;
1034 else if (!strcmp(tok->args[i], "Named"))
1035 rs->is_named = 1;
1036 else if (!strcmp(tok->args[i], "Valid"))
1037 rs->is_valid = 1;
1041 goto done;
1042 err:
1043 if (rs)
1044 routerstatus_free(rs);
1045 rs = NULL;
1046 done:
1047 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
1048 smartlist_clear(tokens);
1049 *s = eos;
1051 return rs;
1054 /** Helper to sort a smartlist of pointers to routerstatus_t */
1055 static int
1056 _compare_routerstatus_entries(const void **_a, const void **_b)
1058 const routerstatus_t *a = *_a, *b = *_b;
1059 return memcmp(a->identity_digest, b->identity_digest, DIGEST_LEN);
1062 void
1063 sort_routerstatus_entries(smartlist_t *sl)
1065 smartlist_sort(sl, _compare_routerstatus_entries);
1068 /** Given a versioned (v2 or later) network-status object in <b>s</b>, try to
1069 * parse it and return the result. Return NULL on failure. Check the
1070 * signature of the network status, but do not (yet) check the signing key for
1071 * authority.
1073 networkstatus_t *
1074 networkstatus_parse_from_string(const char *s)
1076 const char *eos;
1077 smartlist_t *tokens = smartlist_create();
1078 networkstatus_t *ns = NULL;
1079 char ns_digest[DIGEST_LEN];
1080 char tmp_digest[DIGEST_LEN];
1081 struct in_addr in;
1082 directory_token_t *tok;
1083 int i;
1085 if (router_get_networkstatus_v2_hash(s, ns_digest)) {
1086 warn(LD_DIR, "Unable to compute digest of network-status");
1087 goto err;
1090 eos = find_start_of_next_routerstatus(s);
1091 if (tokenize_string(s, eos, tokens, NETSTATUS)) {
1092 warn(LD_DIR, "Error tokenizing network-status header.");
1093 goto err;
1095 if ((tok = find_first_by_keyword(tokens, _UNRECOGNIZED))) {
1096 warn(LD_DIR, "Unrecognized keyword '%s'; can't parse network-status",
1097 tok->args[0]);
1098 goto err;
1100 ns = tor_malloc_zero(sizeof(networkstatus_t));
1101 memcpy(ns->networkstatus_digest, ns_digest, DIGEST_LEN);
1103 if (!(tok = find_first_by_keyword(tokens, K_NETWORK_STATUS_VERSION))) {
1104 warn(LD_DIR, "Couldn't find network-status-version keyword");
1105 goto err;
1108 if (!(tok = find_first_by_keyword(tokens, K_DIR_SOURCE))) {
1109 warn(LD_DIR, "Couldn't find dir-source keyword");
1110 goto err;
1112 if (tok->n_args < 3) {
1113 warn(LD_DIR, "Too few arguments to dir-source keyword");
1114 goto err;
1116 ns->source_address = tok->args[0]; tok->args[0] = NULL;
1117 if (tor_inet_aton(tok->args[1], &in) == 0) {
1118 warn(LD_DIR, "Error parsing address '%s'", tok->args[1]);
1119 goto err;
1121 ns->source_addr = ntohl(in.s_addr);
1122 ns->source_dirport =
1123 (uint16_t) tor_parse_long(tok->args[2],10,0,65535,NULL,NULL);
1124 if (ns->source_dirport == 0) {
1125 warn(LD_DIR, "Directory source without dirport; skipping.");
1126 goto err;
1129 if (!(tok = find_first_by_keyword(tokens, K_FINGERPRINT))) {
1130 warn(LD_DIR, "Couldn't find fingerprint keyword");
1131 goto err;
1133 if (tok->n_args < 1) {
1134 warn(LD_DIR, "Too few arguments to fingerprint");
1135 goto err;
1137 if (base16_decode(ns->identity_digest, DIGEST_LEN, tok->args[0],
1138 strlen(tok->args[0]))) {
1139 warn(LD_DIR, "Couldn't decode fingerprint '%s'", tok->args[0]);
1140 goto err;
1143 if ((tok = find_first_by_keyword(tokens, K_CONTACT)) && tok->n_args) {
1144 ns->contact = tok->args[0];
1145 tok->args[0] = NULL;
1148 if (!(tok = find_first_by_keyword(tokens, K_DIR_SIGNING_KEY)) || !tok->key) {
1149 warn(LD_DIR, "Missing dir-signing-key");
1150 goto err;
1152 ns->signing_key = tok->key;
1153 tok->key = NULL;
1155 if (crypto_pk_get_digest(ns->signing_key, tmp_digest)<0) {
1156 warn(LD_DIR, "Couldn't compute signing key digest");
1157 goto err;
1159 if (memcmp(tmp_digest, ns->identity_digest, DIGEST_LEN)) {
1160 warn(LD_DIR, "network-status fingerprint did not match dir-signing-key");
1161 goto err;
1164 if ((tok = find_first_by_keyword(tokens, K_DIR_OPTIONS))) {
1165 for (i=0; i < tok->n_args; ++i) {
1166 if (!strcmp(tok->args[i], "Names"))
1167 ns->binds_names = 1;
1168 if (!strcmp(tok->args[i], "Versions"))
1169 ns->recommends_versions = 1;
1173 if (ns->recommends_versions) {
1174 if (!(tok = find_first_by_keyword(tokens, K_CLIENT_VERSIONS)) ||
1175 tok->n_args<1) {
1176 warn(LD_DIR, "Missing client-versions");
1178 ns->client_versions = tok->args[0];
1179 tok->args[0] = NULL;
1181 if (!(tok = find_first_by_keyword(tokens, K_SERVER_VERSIONS)) ||
1182 tok->n_args<1) {
1183 warn(LD_DIR, "Missing server-versions on versioning directory");
1184 goto err;
1186 ns->server_versions = tok->args[0];
1187 tok->args[0] = NULL;
1190 if (!(tok = find_first_by_keyword(tokens, K_PUBLISHED))) {
1191 warn(LD_DIR, "Missing published time on directory.");
1192 goto err;
1194 tor_assert(tok->n_args == 1);
1195 if (parse_iso_time(tok->args[0], &ns->published_on) < 0) {
1196 goto err;
1199 ns->entries = smartlist_create();
1200 s = eos;
1201 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
1202 smartlist_clear(tokens);
1203 while (!strcmpstart(s, "r ")) {
1204 routerstatus_t *rs;
1205 if ((rs = routerstatus_parse_entry_from_string(&s, tokens)))
1206 smartlist_add(ns->entries, rs);
1208 smartlist_sort(ns->entries, _compare_routerstatus_entries);
1210 /* Kill duplicate entries. */
1211 for (i=0; i < smartlist_len(ns->entries)-1; ++i) {
1212 routerstatus_t *rs1 = smartlist_get(ns->entries, i);
1213 routerstatus_t *rs2 = smartlist_get(ns->entries, i+1);
1214 if (!memcmp(rs1->identity_digest,
1215 rs2->identity_digest, DIGEST_LEN)) {
1216 warn(LD_DIR, "Network-status has two entries for the same router. Dropping one.");
1217 smartlist_del_keeporder(ns->entries, i--);
1218 routerstatus_free(rs1);
1222 if (tokenize_string(s, NULL, tokens, NETSTATUS)) {
1223 warn(LD_DIR, "Error tokenizing network-status footer.");
1224 goto err;
1226 if (smartlist_len(tokens) < 1) {
1227 warn(LD_DIR, "Too few items in network-status footer.");
1228 goto err;
1230 tok = smartlist_get(tokens, smartlist_len(tokens)-1);
1231 if (tok->tp != K_DIRECTORY_SIGNATURE) {
1232 warn(LD_DIR, "Expected network-status footer to end with a signature.");
1233 goto err;
1236 if (check_directory_signature(ns_digest, tok, NULL, ns->signing_key, 0))
1237 goto err;
1239 goto done;
1240 err:
1241 if (ns)
1242 networkstatus_free(ns);
1243 ns = NULL;
1244 done:
1245 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_free(t));
1246 smartlist_free(tokens);
1248 return ns;
1251 /** Parse the exit policy in the string <b>s</b> and return it. If
1252 * assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or
1253 * ADDR_POLICY_REJECT) for items that specify no action.
1255 addr_policy_t *
1256 router_parse_addr_policy_from_string(const char *s, int assume_action)
1258 directory_token_t *tok = NULL;
1259 const char *cp;
1260 char *tmp;
1261 addr_policy_t *r;
1262 size_t len, idx;
1264 /* *s might not end with \n, so we need to extend it with one. */
1265 len = strlen(s);
1266 cp = tmp = tor_malloc(len+2);
1267 for (idx = 0; idx < len; ++idx) {
1268 tmp[idx] = tolower(s[idx]);
1270 tmp[len]='\n';
1271 tmp[len+1]='\0';
1272 while (TOR_ISSPACE(*cp))
1273 ++cp;
1274 if ((*cp == '*' || TOR_ISDIGIT(*cp)) && assume_action >= 0) {
1275 char *new_str = tor_malloc(len+10);
1276 tor_snprintf(new_str, len+10, "%s %s\n",
1277 assume_action == ADDR_POLICY_ACCEPT?"accept":"reject", cp);
1278 tor_free(tmp);
1279 cp = tmp = new_str;
1281 tok = get_next_token(&cp, RTR);
1282 if (tok->tp == _ERR) {
1283 warn(LD_DIR, "Error reading exit policy: %s", tok->error);
1284 goto err;
1286 if (tok->tp != K_ACCEPT && tok->tp != K_REJECT) {
1287 warn(LD_DIR, "Expected 'accept' or 'reject'.");
1288 goto err;
1291 /* Now that we've gotten an exit policy, add it to the router. */
1292 r = router_parse_addr_policy(tok);
1293 goto done;
1294 err:
1295 r = NULL;
1296 done:
1297 tor_free(tmp);
1298 token_free(tok);
1299 return r;
1302 /** Given an exit policicy stored in <b>s</b>, parse it and add it to the end
1303 * of the exit policy of <b>router</b>. Return 0 on success, -1 on failure.
1306 router_add_exit_policy_from_string(routerinfo_t *router, const char *s)
1308 addr_policy_t *newe, *tmpe;
1309 newe = router_parse_addr_policy_from_string(s, -1);
1310 if (!newe)
1311 return -1;
1312 for (tmpe = router->exit_policy; tmpe; tmpe=tmpe->next)
1314 tmpe->next = newe;
1316 return 0;
1319 /** Add an exit policy stored in the token <b>tok</b> to the router info in
1320 * <b>router</b>. Return 0 on success, -1 on failure. */
1321 static int
1322 router_add_exit_policy(routerinfo_t *router, directory_token_t *tok)
1324 addr_policy_t *newe, **tmpe;
1325 newe = router_parse_addr_policy(tok);
1326 if (!newe)
1327 return -1;
1328 for (tmpe = &router->exit_policy; *tmpe; tmpe=&((*tmpe)->next))
1330 *tmpe = newe;
1332 return 0;
1335 /** Given a K_ACCEPT or K_REJECT token and a router, create and return
1336 * a new exit_policy_t corresponding to the token. */
1337 static addr_policy_t *
1338 router_parse_addr_policy(directory_token_t *tok)
1340 addr_policy_t *newe;
1341 // struct in_addr in;
1342 char *arg;
1343 // char *address;
1344 // char buf[INET_NTOA_BUF_LEN];
1346 tor_assert(tok->tp == K_REJECT || tok->tp == K_ACCEPT);
1348 if (tok->n_args != 1)
1349 return NULL;
1350 arg = tok->args[0];
1352 newe = tor_malloc_zero(sizeof(addr_policy_t));
1354 newe->string = tor_malloc(8+strlen(arg));
1355 /* XXX eventually, use the code from router.c:727 to generate this */
1356 tor_snprintf(newe->string, 8+strlen(arg), "%s %s",
1357 (tok->tp == K_REJECT) ? "reject" : "accept", arg);
1358 newe->policy_type = (tok->tp == K_REJECT) ? ADDR_POLICY_REJECT
1359 : ADDR_POLICY_ACCEPT;
1361 if (parse_addr_and_port_range(arg, &newe->addr, &newe->msk,
1362 &newe->prt_min, &newe->prt_max))
1363 goto policy_read_failed;
1365 // in.s_addr = htonl(newe->addr);
1366 // tor_inet_ntoa(&in, buf, sizeof(buf));
1367 // address = tor_strdup(buf);
1368 // in.s_addr = htonl(newe->msk);
1369 // log_fn(LOG_DEBUG,"%s %s/%s:%d-%d",
1370 // newe->policy_type == ADDR_POLICY_REJECT ? "reject" : "accept",
1371 // address, inet_ntoa(in), newe->prt_min, newe->prt_max);
1372 // tor_free(address);
1374 return newe;
1376 policy_read_failed:
1377 tor_assert(newe->string);
1378 warn(LD_DIR,"Couldn't parse line '%s'. Dropping", newe->string);
1379 tor_free(newe->string);
1380 tor_free(newe);
1381 return NULL;
1384 /** Log and exit if <b>t</b> is malformed */
1385 void
1386 assert_addr_policy_ok(addr_policy_t *t)
1388 addr_policy_t *t2;
1389 while (t) {
1390 tor_assert(t->policy_type == ADDR_POLICY_REJECT ||
1391 t->policy_type == ADDR_POLICY_ACCEPT);
1392 tor_assert(t->prt_min <= t->prt_max);
1393 t2 = router_parse_addr_policy_from_string(t->string, -1);
1394 tor_assert(t2);
1395 tor_assert(t2->policy_type == t->policy_type);
1396 tor_assert(t2->addr == t->addr);
1397 tor_assert(t2->msk == t->msk);
1398 tor_assert(t2->prt_min == t->prt_min);
1399 tor_assert(t2->prt_max == t->prt_max);
1400 tor_assert(!strcmp(t2->string, t->string));
1401 tor_assert(t2->next == NULL);
1402 addr_policy_free(t2);
1404 t = t->next;
1410 * Low-level tokenizer for router descriptors and directories.
1413 /** Free all resources allocated for <b>tok</b> */
1414 static void
1415 token_free(directory_token_t *tok)
1417 int i;
1418 tor_assert(tok);
1419 if (tok->args) {
1420 for (i = 0; i < tok->n_args; ++i) {
1421 tor_free(tok->args[i]);
1423 tor_free(tok->args);
1425 tor_free(tok->object_type);
1426 tor_free(tok->object_body);
1427 if (tok->key)
1428 crypto_free_pk_env(tok->key);
1429 tor_free(tok);
1432 /** Helper function: read the next token from *s, advance *s to the end
1433 * of the token, and return the parsed token. If 'where' is DIR
1434 * or RTR, reject all tokens of the wrong type.
1436 static directory_token_t *
1437 get_next_token(const char **s, where_syntax where)
1439 const char *next, *obstart;
1440 int i, done, allocated, is_opt;
1441 directory_token_t *tok;
1442 arg_syntax a_syn;
1443 obj_syntax o_syn = NO_OBJ;
1445 #define RET_ERR(msg) \
1446 do { if (tok) token_free(tok); \
1447 tok = tor_malloc_zero(sizeof(directory_token_t));\
1448 tok->tp = _ERR; \
1449 tok->error = msg; \
1450 goto done_tokenizing; } while (0)
1452 tok = tor_malloc_zero(sizeof(directory_token_t));
1453 tok->tp = _ERR;
1455 *s = eat_whitespace(*s);
1456 if (!**s) {
1457 tok->tp = _EOF;
1458 return tok;
1460 next = find_whitespace(*s);
1461 if (!next) {
1462 tok->error = "Unexpected EOF"; return tok;
1464 /* It's a keyword... but which one? */
1465 is_opt = !strncmp("opt", *s, next-*s);
1466 if (is_opt) {
1467 *s = eat_whitespace(next);
1468 next = NULL;
1469 if (**s)
1470 next = find_whitespace(*s);
1471 if (!**s || !next) {
1472 RET_ERR("opt without keyword");
1475 for (i = 0; token_table[i].t ; ++i) {
1476 if (!strncmp(token_table[i].t, *s, next-*s)) {
1477 /* We've found the keyword. */
1478 tok->tp = token_table[i].v;
1479 a_syn = token_table[i].s;
1480 o_syn = token_table[i].os;
1481 if (!(token_table[i].ws & where)) {
1482 if (where == DIR) {
1483 RET_ERR("Found an out-of-place token in a directory section");
1484 } else if (where == RTR) {
1485 RET_ERR("Found an out-of-place token in a router descriptor");
1486 } else if (where == NETSTATUS) {
1487 RET_ERR("Found an out-of-place token in a network-status header");
1488 } else {
1489 RET_ERR("Found an out-of-place token in a router status body");
1492 if (a_syn == ARGS) {
1493 /* This keyword takes multiple arguments. */
1494 i = 0;
1495 done = (*next == '\n');
1496 allocated = 32;
1497 tok->args = tor_malloc(sizeof(char*)*32);
1498 *s = eat_whitespace_no_nl(next);
1499 while (**s != '\n' && !done) {
1500 next = find_whitespace(*s);
1501 if (*next == '\n')
1502 done = 1;
1503 if (i == allocated) {
1504 allocated *= 2;
1505 tok->args = tor_realloc(tok->args,sizeof(char*)*allocated);
1507 tok->args[i++] = tor_strndup(*s,next-*s);
1508 *s = eat_whitespace_no_nl(next+1);
1510 tok->n_args = i;
1511 } else if (a_syn == CONCAT_ARGS) {
1512 /* The keyword takes the line as a single argument */
1513 *s = eat_whitespace_no_nl(next);
1514 next = strchr(*s, '\n');
1515 if (!next)
1516 RET_ERR("Unexpected EOF");
1517 tok->args = tor_malloc(sizeof(char*));
1518 tok->args[0] = tor_strndup(*s,next-*s);
1519 tok->n_args = 1;
1520 *s = eat_whitespace_no_nl(next+1);
1521 } else {
1522 /* The keyword takes no arguments. */
1523 tor_assert(a_syn == NO_ARGS);
1524 *s = eat_whitespace_no_nl(next);
1525 if (**s != '\n') {
1526 RET_ERR("Unexpected arguments");
1528 tok->n_args = 0;
1529 *s = eat_whitespace_no_nl(*s+1);
1531 break;
1534 if (tok->tp == _ERR) {
1535 if (is_opt) {
1536 tok->tp = K_OPT;
1537 *s = eat_whitespace_no_nl(next);
1538 next = strchr(*s,'\n');
1539 if (!next)
1540 RET_ERR("Unexpected EOF");
1541 tok->args = tor_malloc(sizeof(char*));
1542 tok->args[0] = tor_strndup(*s,next-*s);
1543 tok->n_args = 1;
1544 *s = eat_whitespace_no_nl(next+1);
1545 o_syn = OBJ_OK;
1546 } else {
1547 tok->tp = _UNRECOGNIZED;
1548 next = strchr(*s, '\n');
1549 if (!next) {
1550 RET_ERR("Unexpected EOF");
1552 tok->args = tor_malloc(sizeof(char*));
1553 tok->args[0] = tor_strndup(*s,next-*s);
1554 tok->n_args = 1;
1555 *s = next+1;
1556 o_syn = OBJ_OK;
1559 *s = eat_whitespace(*s);
1560 if (strcmpstart(*s, "-----BEGIN ")) {
1561 goto done_tokenizing;
1563 obstart = *s;
1564 *s += 11; /* length of "-----BEGIN ". */
1565 next = strchr(*s, '\n');
1566 if (next-*s < 6 || strcmpstart(next-5, "-----\n")) {
1567 RET_ERR("Malformed object: bad begin line");
1569 tok->object_type = tor_strndup(*s, next-*s-5);
1570 *s = next+1;
1571 next = strstr(*s, "-----END ");
1572 if (!next) {
1573 RET_ERR("Malformed object: missing end line");
1575 if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) {
1576 if (strcmpstart(next, "-----END RSA PUBLIC KEY-----\n"))
1577 RET_ERR("Malformed object: mismatched end line");
1578 next = strchr(next,'\n')+1;
1579 tok->key = crypto_new_pk_env();
1580 if (crypto_pk_read_public_key_from_string(tok->key, obstart, next-obstart))
1581 RET_ERR("Couldn't parse public key.");
1582 *s = next;
1583 } else {
1584 tok->object_body = tor_malloc(next-*s); /* really, this is too much RAM. */
1585 i = base64_decode(tok->object_body, 256, *s, next-*s);
1586 if (i<0) {
1587 RET_ERR("Malformed object: bad base64-encoded data");
1589 tok->object_size = i;
1590 *s = next + 9; /* length of "-----END ". */
1591 i = strlen(tok->object_type);
1592 if (strncmp(*s, tok->object_type, i) || strcmpstart(*s+i, "-----\n")) {
1593 RET_ERR("Malformed object: mismatched end tag");
1595 *s += i+6;
1597 switch (o_syn)
1599 case NO_OBJ:
1600 if (tok->object_body)
1601 RET_ERR("Unexpected object for keyword");
1602 if (tok->key)
1603 RET_ERR("Unexpected public key for keyword");
1604 break;
1605 case NEED_OBJ:
1606 if (!tok->object_body)
1607 RET_ERR("Missing object for keyword");
1608 break;
1609 case NEED_KEY:
1610 if (!tok->key)
1611 RET_ERR("Missing public key for keyword");
1612 break;
1613 case OBJ_OK:
1614 break;
1617 done_tokenizing:
1619 return tok;
1620 #undef RET_ERR
1623 /** Read all tokens from a string between <b>start</b> and <b>end</b>, and add
1624 * them to <b>out</b>. If <b>is_dir</b> is true, reject all non-directory
1625 * tokens; else reject all non-routerdescriptor tokens.
1627 static int
1628 tokenize_string(const char *start, const char *end, smartlist_t *out,
1629 where_syntax where)
1631 const char **s;
1632 directory_token_t *tok = NULL;
1633 s = &start;
1634 if (!end)
1635 end = start+strlen(start);
1636 while (*s < end && (!tok || tok->tp != _EOF)) {
1637 tok = get_next_token(s, where);
1638 if (tok->tp == _ERR) {
1639 warn(LD_DIR, "parse error: %s", tok->error);
1640 return -1;
1642 smartlist_add(out, tok);
1643 *s = eat_whitespace(*s);
1646 return 0;
1649 /** Find the first token in <b>s</b> whose keyword is <b>keyword</b>; return
1650 * NULL if no such keyword is found.
1652 static directory_token_t *
1653 find_first_by_keyword(smartlist_t *s, directory_keyword keyword)
1655 SMARTLIST_FOREACH(s, directory_token_t *, t, if (t->tp == keyword) return t);
1656 return NULL;
1659 /** Return a newly allocated smartlist of all accept or reject tokens in
1660 * <b>s</b>.
1662 static smartlist_t *
1663 find_all_exitpolicy(smartlist_t *s)
1665 smartlist_t *out = smartlist_create();
1666 SMARTLIST_FOREACH(s, directory_token_t *, t,
1667 if (t->tp == K_ACCEPT || t->tp == K_REJECT)
1668 smartlist_add(out,t));
1669 return out;
1672 /** Compute the SHA digest of the substring of <b>s</b> taken from the first
1673 * occurrence of <b>start_str</b> through the first newline after the first
1674 * subsequent occurrence of <b>end_str</b>; store the 20-byte result in
1675 * <b>digest</b>; return 0 on success.
1677 * If no such substring exists, return -1.
1679 static int
1680 router_get_hash_impl(const char *s, char *digest,
1681 const char *start_str,
1682 const char *end_str)
1684 char *start, *end;
1685 start = strstr(s, start_str);
1686 if (!start) {
1687 warn(LD_DIR,"couldn't find \"%s\"",start_str);
1688 return -1;
1690 if (start != s && *(start-1) != '\n') {
1691 warn(LD_DIR, "first occurrence of \"%s\" is not at the start of a line",
1692 start_str);
1693 return -1;
1695 end = strstr(start+strlen(start_str), end_str);
1696 if (!end) {
1697 warn(LD_DIR,"couldn't find \"%s\"",end_str);
1698 return -1;
1700 end = strchr(end+strlen(end_str), '\n');
1701 if (!end) {
1702 warn(LD_DIR,"couldn't find EOL");
1703 return -1;
1705 ++end;
1707 if (crypto_digest(digest, start, end-start)) {
1708 warn(LD_DIR,"couldn't compute digest");
1709 return -1;
1712 return 0;
1715 /** Parse the Tor version of the platform string <b>platform</b>,
1716 * and compare it to the version in <b>cutoff</b>. Return 1 if
1717 * the router is at least as new as the cutoff, else return 0.
1720 tor_version_as_new_as(const char *platform, const char *cutoff)
1722 tor_version_t cutoff_version, router_version;
1723 char *s, *start;
1724 char tmp[128];
1726 if (tor_version_parse(cutoff, &cutoff_version)<0) {
1727 warn(LD_DIR,"Bug: cutoff version '%s' unparseable.",cutoff);
1728 return 0;
1730 if (strcmpstart(platform,"Tor ")) /* nonstandard Tor; be safe and say yes */
1731 return 1;
1733 start = (char *)eat_whitespace(platform+3);
1734 if (!*start) return 0;
1735 s = (char *)find_whitespace(start); /* also finds '\0', which is fine */
1736 if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */
1737 return 0;
1738 strlcpy(tmp, start, s-start+1);
1740 if (tor_version_parse(tmp, &router_version)<0) {
1741 info(LD_DIR,"Router version '%s' unparseable.",tmp);
1742 return 1; /* be safe and say yes */
1745 return tor_version_compare(&router_version, &cutoff_version) >= 0;
1748 /** Parse a tor version from <b>s</b>, and store the result in <b>out</b>.
1749 * Return 0 on success, -1 on failure. */
1751 tor_version_parse(const char *s, tor_version_t *out)
1753 char *eos=NULL, *cp=NULL;
1754 /* Format is:
1755 * "Tor " ? NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ -cvs ] ]
1757 tor_assert(s);
1758 tor_assert(out);
1760 memset(out, 0, sizeof(tor_version_t));
1762 if (!strcasecmpstart(s, "Tor "))
1763 cp += 4;
1765 /* Get major. */
1766 out->major = strtol(s,&eos,10);
1767 if (!eos || eos==s || *eos != '.') return -1;
1768 cp = eos+1;
1770 /* Get minor */
1771 out->minor = strtol(cp,&eos,10);
1772 if (!eos || eos==cp || *eos != '.') return -1;
1773 cp = eos+1;
1775 /* Get micro */
1776 out->micro = strtol(cp,&eos,10);
1777 if (!eos || eos==cp) return -1;
1778 if (!*eos) {
1779 out->status = VER_RELEASE;
1780 out->patchlevel = 0;
1781 out->cvs = IS_NOT_CVS;
1782 return 0;
1784 cp = eos;
1786 /* Get status */
1787 if (*cp == '.') {
1788 out->status = VER_RELEASE;
1789 ++cp;
1790 } else if (0==strncmp(cp, "pre", 3)) {
1791 out->status = VER_PRE;
1792 cp += 3;
1793 } else if (0==strncmp(cp, "rc", 2)) {
1794 out->status = VER_RC;
1795 cp += 2;
1796 } else {
1797 return -1;
1800 /* Get patchlevel */
1801 out->patchlevel = strtol(cp,&eos,10);
1802 if (!eos || eos==cp) return -1;
1803 cp = eos;
1805 /* Get cvs status and status tag. */
1806 if (*cp == '-' || *cp == '.')
1807 ++cp;
1808 strlcpy(out->status_tag, cp, sizeof(out->status_tag));
1809 if (0==strcmp(cp, "cvs")) {
1810 out->cvs = IS_CVS;
1811 } else {
1812 out->cvs = IS_NOT_CVS;
1815 return 0;
1818 /** Compare two tor versions; Return <0 if a < b; 0 if a ==b, >0 if a >
1819 * b. */
1821 tor_version_compare(tor_version_t *a, tor_version_t *b)
1823 int i;
1824 tor_assert(a);
1825 tor_assert(b);
1826 if ((i = a->major - b->major))
1827 return i;
1828 else if ((i = a->minor - b->minor))
1829 return i;
1830 else if ((i = a->micro - b->micro))
1831 return i;
1832 else if ((i = a->status - b->status))
1833 return i;
1834 else if ((i = a->patchlevel - b->patchlevel))
1835 return i;
1837 if (a->major > 0 || a->minor > 0) {
1838 return strcmp(a->status_tag, b->status_tag);
1839 } else {
1840 return (a->cvs - b->cvs);
1844 /** Return true iff versions <b>a</b> and <b>b</b> belong to the same series.
1846 static int
1847 tor_version_same_series(tor_version_t *a, tor_version_t *b)
1849 tor_assert(a);
1850 tor_assert(b);
1851 return ((a->major == b->major) &&
1852 (a->minor == b->minor) &&
1853 (a->micro == b->micro));