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 */
6 const char routerparse_c_id
[] = "$Id$";
10 * \brief Code to parse and validate router descriptors and directories.
13 #define NEW_LOG_INTERFACE
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
26 K_DIRECTORY_SIGNATURE
,
27 K_RECOMMENDED_SOFTWARE
,
50 K_NETWORK_STATUS_VERSION
,
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
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. */
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. */
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. */
92 /** Rules for whether the keyword needs an object. */
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. */
100 /** Rules for where a keyword can appear. */
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. */
110 /** Table mapping keywords to token value and to argument rules. */
112 const char *t
; int v
; arg_syntax s
; obj_syntax os
; int ws
;
114 { "accept", K_ACCEPT
, ARGS
, NO_OBJ
, RTR
},
115 { "directory-signature", K_DIRECTORY_SIGNATURE
, ARGS
, NEED_OBJ
,
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
,
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
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
];
225 if (crypto_pk_private_sign(private_key
, signature
, digest
, DIGEST_LEN
) < 0) {
227 warn(LD_BUG
,"Couldn't sign digest.");
230 if (strlcat(buf
, "-----BEGIN SIGNATURE-----\n", buf_len
) >= buf_len
)
234 if (base64_encode(buf
+i
, buf_len
-i
, signature
, 128) < 0) {
235 warn(LD_BUG
,"couldn't base64-encode signature");
240 if (strlcat(buf
, "-----END SIGNATURE-----\n", buf_len
) >= buf_len
)
245 warn(LD_BUG
,"tried to exceed string length.");
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
258 * (versionlist is a comma-separated list of version strings,
259 * optionally prefixed with "Tor". Versions that can't be parsed are
263 tor_version_is_obsolete(const char *myversion
, const char *versionlist
)
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
;
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
);
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 "))
288 if (tor_version_parse(cp
, &other
)) {
289 /* Couldn't parse other; it can't be a match. */
291 same
= tor_version_same_series(&mine
, &other
);
293 found_any_in_series
= 1;
294 r
= tor_version_compare(&mine
, &other
);
296 ret
= VS_RECOMMENDED
;
301 found_newer_in_series
= 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
) {
313 } else if (found_older
&& !found_newer
) {
316 ret
= VS_UNRECOMMENDED
;
320 SMARTLIST_FOREACH(version_sl
, char *, version
, tor_free(version
));
321 smartlist_free(version_sl
);
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).
337 version_status_join(version_status_t a
, version_status_t b
)
341 else if (a
== VS_UNRECOMMENDED
|| b
== VS_UNRECOMMENDED
)
342 return VS_UNRECOMMENDED
;
343 else if (a
== VS_RECOMMENDED
)
345 else if (b
== VS_RECOMMENDED
)
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 */
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
];
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
373 if (router_get_dir_hash(str
, digest
)) {
374 warn(LD_DIR
, "Unable to compute digest of directory");
377 debug(LD_DIR
,"Received directory hashes to %s",hex_str(digest
,4));
379 /* Check signature first, before we try to tokenize. */
381 while (cp
&& (end
= strstr(cp
+1, "\ndirectory-signature")))
383 if (cp
== str
|| !cp
) {
384 warn(LD_DIR
, "No signature found on directory."); goto err
;
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)
402 SMARTLIST_FOREACH(tokens
, directory_token_t
*, tok
, token_free(tok
));
403 smartlist_free(tokens
);
406 /* Now try to parse the first part of the directory. */
407 if ((end
= strstr(str
,"\nrouter "))) {
409 } else if ((end
= strstr(str
, "\ndirectory-signature"))) {
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.");
424 tor_assert(tok
->n_args
== 1);
426 if (parse_iso_time(tok
->args
[0], &published_on
) < 0) {
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);
440 if (declared_key
) crypto_free_pk_env(declared_key
);
442 SMARTLIST_FOREACH(tokens
, directory_token_t
*, tok
, token_free(tok
));
443 smartlist_free(tokens
);
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,
452 router_parse_runningrouters(const char *str
)
454 char digest
[DIGEST_LEN
];
455 directory_token_t
*tok
;
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");
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",
474 tok
= smartlist_get(tokens
,0);
475 if (tok
->tp
!= K_NETWORK_STATUS
) {
476 warn(LD_DIR
, "Network-status starts with wrong token");
480 if (!(tok
= find_first_by_keyword(tokens
, K_PUBLISHED
))) {
481 warn(LD_DIR
, "Missing published time on directory.");
484 tor_assert(tok
->n_args
== 1);
485 if (parse_iso_time(tok
->args
[0], &published_on
) < 0) {
488 if (!(tok
= find_first_by_keyword(tokens
, K_DIRECTORY_SIGNATURE
))) {
489 warn(LD_DIR
, "Missing signature on running-routers");
492 declared_key
= find_dir_signing_key(str
);
493 if (check_directory_signature(digest
, tok
, NULL
, declared_key
, 1) < 0)
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);
503 if (declared_key
) crypto_free_pk_env(declared_key
);
505 SMARTLIST_FOREACH(tokens
, directory_token_t
*, tok
, token_free(tok
));
506 smartlist_free(tokens
);
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
)
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");
524 cp
= strstr(str
, "\ndir-signing-key");
527 ++cp
; /* Now cp points to the start of the token. */
529 tok
= get_next_token(&cp
, DIR);
531 warn(LD_DIR
, "Unparseable dir-signing-key token");
534 if (tok
->tp
!= K_DIR_SIGNING_KEY
) {
535 warn(LD_DIR
, "Dir-signing-key token did not parse as expected");
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]);
547 warn(LD_DIR
, "Unparseable dir-signing-key argument");
551 warn(LD_DIR
, "Dir-signing-key token contained no key");
559 /** Return true iff <b>key</b> is allowed to sign directories.
562 dir_signing_key_is_trusted(crypto_pk_env_t
*key
)
564 char digest
[DIGEST_LEN
];
566 if (crypto_pk_get_digest(key
, digest
) < 0) {
567 warn(LD_DIR
, "Error computing dir-signing-key digest");
570 if (!router_digest_is_trusted_dir(digest
)) {
571 warn(LD_DIR
, "Listed dir-signing-key is not trusted");
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.)
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
,
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");
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 */
613 warn(LD_DIR
, "Obsolete directory format (dir signing key not present) or signing key not trusted--rejecting.");
617 if (strcmp(tok
->object_type
, "SIGNATURE") || tok
->object_size
!= 128) {
618 warn(LD_DIR
, "Bad object type or length on directory signature");
624 if (crypto_pk_public_checksig(_pkey
, signed_digest
, tok
->object_body
, 128)
626 warn(LD_DIR
, "Error reading directory: invalid signature.");
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.");
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
;
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)
658 if ((end
= strstr(*s
+1, "\nrouter "))) {
661 } else if ((end
= strstr(*s
+1, "\ndirectory-signature"))) {
665 cp
= end
= *s
+strlen(*s
);
668 while (cp
> *s
&& (!*cp
|| TOR_ISSPACE(*cp
)))
670 /* cp now points to the last non-space character in this descriptor. */
672 while (cp
> *s
&& *cp
!= '\n')
674 /* cp now points to the first \n before the last non-blank line in this
677 if (strcmpstart(cp
, "\n-----END SIGNATURE-----\n")) {
678 info(LD_DIR
, "Ignoring truncated router descriptor.");
682 router
= router_parse_entry_from_string(*s
, end
);
686 warn(LD_DIR
, "Error reading router; skipping");
689 smartlist_add(dest
, router
);
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
700 router_parse_entry_from_string(const char *s
, const char *end
)
702 routerinfo_t
*router
= NULL
;
703 char signed_digest
[128];
705 smartlist_t
*tokens
= NULL
, *exit_policy_tokens
= NULL
;
706 directory_token_t
*tok
;
708 int ports_set
, bw_set
;
715 /* point 'end' to a point immediately after the final newline. */
716 while (end
> s
+2 && *(end
-1) == '\n' && *(end
-2) == '\n')
719 if (router_get_router_hash(s
, digest
) < 0) {
720 warn(LD_DIR
, "Couldn't compute router hash.");
723 tokens
= smartlist_create();
724 if (tokenize_string(s
,end
,tokens
,RTR
)) {
725 warn(LD_DIR
, "Error tokeninzing router descriptor.");
729 if (smartlist_len(tokens
) < 2) {
730 warn(LD_DIR
, "Impossibly short router descriptor.");
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.)",
739 tok
= smartlist_get(tokens
,0);
740 if (tok
->tp
!= K_ROUTER
) {
741 warn(LD_DIR
,"Entry does not start with \"router\"");
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");
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.");
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
);
770 warn(LD_DIR
,"Wrong # of arguments to \"router\" (%d)",tok
->n_args
);
774 tok
= find_first_by_keyword(tokens
, K_PORTS
);
775 if (tok
&& ports_set
) {
776 warn(LD_DIR
,"Redundant ports line");
779 if (tok
->n_args
!= 3) {
780 warn(LD_DIR
,"Wrong # of arguments to \"ports\"");
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
);
788 tok
= find_first_by_keyword(tokens
, K_BANDWIDTH
);
790 warn(LD_DIR
,"Redundant bandwidth line");
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
);
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
);
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.");
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.");
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)
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);
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);
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");
868 if ((tok
= find_first_by_keyword(tokens
, K_FAMILY
)) && tok
->n_args
) {
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
]);
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");
884 if (strcmp(tok
->object_type
, "SIGNATURE") || tok
->object_size
!= 128) {
885 warn(LD_DIR
, "Bad object type or length on router signature");
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
);
893 if (memcmp(digest
, signed_digest
, DIGEST_LEN
)) {
894 warn(LD_DIR
, "Mismatched signature");
899 warn(LD_DIR
,"No ports declared; failing.");
903 warn(LD_DIR
,"No bandwidth declared; failing.");
906 if (!router
->or_port
) {
907 warn(LD_DIR
,"or_port unreadable or 0. Failing.");
910 if (!router
->bandwidthrate
) {
911 warn(LD_DIR
,"bandwidthrate unreadable or 0. Failing.");
914 if (!router
->platform
) {
915 router
->platform
= tor_strdup("<unknown>");
921 routerinfo_free(router
);
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
);
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 ");
943 eos
= strstr(s
, "\ndirectory-signature");
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
)
958 routerstatus_t
*rs
= NULL
;
959 directory_token_t
*tok
;
960 char timebuf
[ISO_TIME_LEN
+1];
965 eos
= find_start_of_next_routerstatus(*s
);
967 if (tokenize_string(*s
, eos
, tokens
, RTRSTATUS
)) {
968 warn(LD_DIR
, "Error tokenizing router status");
971 if (smartlist_len(tokens
) < 1) {
972 warn(LD_DIR
, "Impossibly short router status");
975 if ((tok
= find_first_by_keyword(tokens
, _UNRECOGNIZED
))) {
976 warn(LD_DIR
, "Unrecognized keyword \"%s\" in router status; skipping.",
980 if (!(tok
= find_first_by_keyword(tokens
, K_R
))) {
981 warn(LD_DIR
, "Missing 'r' keywork in router status; skipping.");
984 if (tok
->n_args
< 8) {
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])) {
992 "Invalid nickname '%s' in router status; skipping.", tok
->args
[0]);
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]);
1002 if (digest_from_base64(rs
->descriptor_digest
, tok
->args
[2])) {
1003 warn(LD_DIR
, "Error decoding digest '%s'", tok
->args
[2]);
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]);
1014 if (tor_inet_aton(tok
->args
[5], &in
) == 0) {
1015 warn(LD_DIR
, "Error parsing address '%s'", tok
->args
[5]);
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
))) {
1025 for (i
=0; i
< tok
->n_args
; ++i
) {
1026 if (!strcmp(tok
->args
[i
], "Exit"))
1028 else if (!strcmp(tok
->args
[i
], "Stable"))
1030 else if (!strcmp(tok
->args
[i
], "Fast"))
1032 else if (!strcmp(tok
->args
[i
], "Running"))
1034 else if (!strcmp(tok
->args
[i
], "Named"))
1036 else if (!strcmp(tok
->args
[i
], "Valid"))
1044 routerstatus_free(rs
);
1047 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_free(t
));
1048 smartlist_clear(tokens
);
1054 /** Helper to sort a smartlist of pointers to routerstatus_t */
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
);
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
1074 networkstatus_parse_from_string(const char *s
)
1077 smartlist_t
*tokens
= smartlist_create();
1078 networkstatus_t
*ns
= NULL
;
1079 char ns_digest
[DIGEST_LEN
];
1080 char tmp_digest
[DIGEST_LEN
];
1082 directory_token_t
*tok
;
1085 if (router_get_networkstatus_v2_hash(s
, ns_digest
)) {
1086 warn(LD_DIR
, "Unable to compute digest of network-status");
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.");
1095 if ((tok
= find_first_by_keyword(tokens
, _UNRECOGNIZED
))) {
1096 warn(LD_DIR
, "Unrecognized keyword '%s'; can't parse network-status",
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");
1108 if (!(tok
= find_first_by_keyword(tokens
, K_DIR_SOURCE
))) {
1109 warn(LD_DIR
, "Couldn't find dir-source keyword");
1112 if (tok
->n_args
< 3) {
1113 warn(LD_DIR
, "Too few arguments to dir-source keyword");
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]);
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.");
1129 if (!(tok
= find_first_by_keyword(tokens
, K_FINGERPRINT
))) {
1130 warn(LD_DIR
, "Couldn't find fingerprint keyword");
1133 if (tok
->n_args
< 1) {
1134 warn(LD_DIR
, "Too few arguments to fingerprint");
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]);
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");
1152 ns
->signing_key
= tok
->key
;
1155 if (crypto_pk_get_digest(ns
->signing_key
, tmp_digest
)<0) {
1156 warn(LD_DIR
, "Couldn't compute signing key digest");
1159 if (memcmp(tmp_digest
, ns
->identity_digest
, DIGEST_LEN
)) {
1160 warn(LD_DIR
, "network-status fingerprint did not match dir-signing-key");
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
)) ||
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
)) ||
1183 warn(LD_DIR
, "Missing server-versions on versioning directory");
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.");
1194 tor_assert(tok
->n_args
== 1);
1195 if (parse_iso_time(tok
->args
[0], &ns
->published_on
) < 0) {
1199 ns
->entries
= smartlist_create();
1201 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_free(t
));
1202 smartlist_clear(tokens
);
1203 while (!strcmpstart(s
, "r ")) {
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.");
1226 if (smartlist_len(tokens
) < 1) {
1227 warn(LD_DIR
, "Too few items in network-status footer.");
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.");
1236 if (check_directory_signature(ns_digest
, tok
, NULL
, ns
->signing_key
, 0))
1242 networkstatus_free(ns
);
1245 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_free(t
));
1246 smartlist_free(tokens
);
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.
1256 router_parse_addr_policy_from_string(const char *s
, int assume_action
)
1258 directory_token_t
*tok
= NULL
;
1264 /* *s might not end with \n, so we need to extend it with one. */
1266 cp
= tmp
= tor_malloc(len
+2);
1267 for (idx
= 0; idx
< len
; ++idx
) {
1268 tmp
[idx
] = tolower(s
[idx
]);
1272 while (TOR_ISSPACE(*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
);
1281 tok
= get_next_token(&cp
, RTR
);
1282 if (tok
->tp
== _ERR
) {
1283 warn(LD_DIR
, "Error reading exit policy: %s", tok
->error
);
1286 if (tok
->tp
!= K_ACCEPT
&& tok
->tp
!= K_REJECT
) {
1287 warn(LD_DIR
, "Expected 'accept' or 'reject'.");
1291 /* Now that we've gotten an exit policy, add it to the router. */
1292 r
= router_parse_addr_policy(tok
);
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);
1312 for (tmpe
= router
->exit_policy
; tmpe
; tmpe
=tmpe
->next
)
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. */
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
);
1328 for (tmpe
= &router
->exit_policy
; *tmpe
; tmpe
=&((*tmpe
)->next
))
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;
1344 // char buf[INET_NTOA_BUF_LEN];
1346 tor_assert(tok
->tp
== K_REJECT
|| tok
->tp
== K_ACCEPT
);
1348 if (tok
->n_args
!= 1)
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);
1377 tor_assert(newe
->string
);
1378 warn(LD_DIR
,"Couldn't parse line '%s'. Dropping", newe
->string
);
1379 tor_free(newe
->string
);
1384 /** Log and exit if <b>t</b> is malformed */
1386 assert_addr_policy_ok(addr_policy_t
*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);
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
);
1410 * Low-level tokenizer for router descriptors and directories.
1413 /** Free all resources allocated for <b>tok</b> */
1415 token_free(directory_token_t
*tok
)
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
);
1428 crypto_free_pk_env(tok
->key
);
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
;
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));\
1450 goto done_tokenizing; } while (0)
1452 tok
= tor_malloc_zero(sizeof(directory_token_t
));
1455 *s
= eat_whitespace(*s
);
1460 next
= find_whitespace(*s
);
1462 tok
->error
= "Unexpected EOF"; return tok
;
1464 /* It's a keyword... but which one? */
1465 is_opt
= !strncmp("opt", *s
, next
-*s
);
1467 *s
= eat_whitespace(next
);
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
)) {
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");
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. */
1495 done
= (*next
== '\n');
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
);
1503 if (i
== allocated
) {
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);
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');
1516 RET_ERR("Unexpected EOF");
1517 tok
->args
= tor_malloc(sizeof(char*));
1518 tok
->args
[0] = tor_strndup(*s
,next
-*s
);
1520 *s
= eat_whitespace_no_nl(next
+1);
1522 /* The keyword takes no arguments. */
1523 tor_assert(a_syn
== NO_ARGS
);
1524 *s
= eat_whitespace_no_nl(next
);
1526 RET_ERR("Unexpected arguments");
1529 *s
= eat_whitespace_no_nl(*s
+1);
1534 if (tok
->tp
== _ERR
) {
1537 *s
= eat_whitespace_no_nl(next
);
1538 next
= strchr(*s
,'\n');
1540 RET_ERR("Unexpected EOF");
1541 tok
->args
= tor_malloc(sizeof(char*));
1542 tok
->args
[0] = tor_strndup(*s
,next
-*s
);
1544 *s
= eat_whitespace_no_nl(next
+1);
1547 tok
->tp
= _UNRECOGNIZED
;
1548 next
= strchr(*s
, '\n');
1550 RET_ERR("Unexpected EOF");
1552 tok
->args
= tor_malloc(sizeof(char*));
1553 tok
->args
[0] = tor_strndup(*s
,next
-*s
);
1559 *s
= eat_whitespace(*s
);
1560 if (strcmpstart(*s
, "-----BEGIN ")) {
1561 goto done_tokenizing
;
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);
1571 next
= strstr(*s
, "-----END ");
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.");
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
);
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");
1600 if (tok
->object_body
)
1601 RET_ERR("Unexpected object for keyword");
1603 RET_ERR("Unexpected public key for keyword");
1606 if (!tok
->object_body
)
1607 RET_ERR("Missing object for keyword");
1611 RET_ERR("Missing public key for keyword");
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.
1628 tokenize_string(const char *start
, const char *end
, smartlist_t
*out
,
1632 directory_token_t
*tok
= NULL
;
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
);
1642 smartlist_add(out
, tok
);
1643 *s
= eat_whitespace(*s
);
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
);
1659 /** Return a newly allocated smartlist of all accept or reject tokens in
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
));
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.
1680 router_get_hash_impl(const char *s
, char *digest
,
1681 const char *start_str
,
1682 const char *end_str
)
1685 start
= strstr(s
, start_str
);
1687 warn(LD_DIR
,"couldn't find \"%s\"",start_str
);
1690 if (start
!= s
&& *(start
-1) != '\n') {
1691 warn(LD_DIR
, "first occurrence of \"%s\" is not at the start of a line",
1695 end
= strstr(start
+strlen(start_str
), end_str
);
1697 warn(LD_DIR
,"couldn't find \"%s\"",end_str
);
1700 end
= strchr(end
+strlen(end_str
), '\n');
1702 warn(LD_DIR
,"couldn't find EOL");
1707 if (crypto_digest(digest
, start
, end
-start
)) {
1708 warn(LD_DIR
,"couldn't compute digest");
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
;
1726 if (tor_version_parse(cutoff
, &cutoff_version
)<0) {
1727 warn(LD_DIR
,"Bug: cutoff version '%s' unparseable.",cutoff
);
1730 if (strcmpstart(platform
,"Tor ")) /* nonstandard Tor; be safe and say yes */
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 */
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
;
1755 * "Tor " ? NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ -cvs ] ]
1760 memset(out
, 0, sizeof(tor_version_t
));
1762 if (!strcasecmpstart(s
, "Tor "))
1766 out
->major
= strtol(s
,&eos
,10);
1767 if (!eos
|| eos
==s
|| *eos
!= '.') return -1;
1771 out
->minor
= strtol(cp
,&eos
,10);
1772 if (!eos
|| eos
==cp
|| *eos
!= '.') return -1;
1776 out
->micro
= strtol(cp
,&eos
,10);
1777 if (!eos
|| eos
==cp
) return -1;
1779 out
->status
= VER_RELEASE
;
1780 out
->patchlevel
= 0;
1781 out
->cvs
= IS_NOT_CVS
;
1788 out
->status
= VER_RELEASE
;
1790 } else if (0==strncmp(cp
, "pre", 3)) {
1791 out
->status
= VER_PRE
;
1793 } else if (0==strncmp(cp
, "rc", 2)) {
1794 out
->status
= VER_RC
;
1800 /* Get patchlevel */
1801 out
->patchlevel
= strtol(cp
,&eos
,10);
1802 if (!eos
|| eos
==cp
) return -1;
1805 /* Get cvs status and status tag. */
1806 if (*cp
== '-' || *cp
== '.')
1808 strlcpy(out
->status_tag
, cp
, sizeof(out
->status_tag
));
1809 if (0==strcmp(cp
, "cvs")) {
1812 out
->cvs
= IS_NOT_CVS
;
1818 /** Compare two tor versions; Return <0 if a < b; 0 if a ==b, >0 if a >
1821 tor_version_compare(tor_version_t
*a
, tor_version_t
*b
)
1826 if ((i
= a
->major
- b
->major
))
1828 else if ((i
= a
->minor
- b
->minor
))
1830 else if ((i
= a
->micro
- b
->micro
))
1832 else if ((i
= a
->status
- b
->status
))
1834 else if ((i
= a
->patchlevel
- b
->patchlevel
))
1837 if (a
->major
> 0 || a
->minor
> 0) {
1838 return strcmp(a
->status_tag
, b
->status_tag
);
1840 return (a
->cvs
- b
->cvs
);
1844 /** Return true iff versions <b>a</b> and <b>b</b> belong to the same series.
1847 tor_version_same_series(tor_version_t
*a
, tor_version_t
*b
)
1851 return ((a
->major
== b
->major
) &&
1852 (a
->minor
== b
->minor
) &&
1853 (a
->micro
== b
->micro
));