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.
15 /****************************************************************************/
17 /** Enumeration of possible token types. The ones starting with K_
18 * correspond to directory 'keywords'. _UNRECOGNIZED is for an
19 * unrecognized keyword; _ERR is an error in the tokenizing process,
20 * _EOF is an end-of-file marker, and _NIL is used to encode
25 K_DIRECTORY_SIGNATURE
,
26 K_RECOMMENDED_SOFTWARE
,
49 K_NETWORK_STATUS_VERSION
,
62 /** Structure to hold a single directory token.
64 * We parse a directory by breaking it into "tokens", each consisting
65 * of a keyword, a line full of arguments, and a binary object. The
66 * arguments and object are both optional, depending on the keyword
69 typedef struct directory_token_t
{
70 directory_keyword tp
; /**< Type of the token. */
71 int n_args
; /**< Number of elements in args */
72 char **args
; /**< Array of arguments from keyword line. */
73 char *object_type
; /**< -----BEGIN [object_type]-----*/
74 size_t object_size
; /**< Bytes in object_body */
75 char *object_body
; /**< Contents of object, base64-decoded. */
76 crypto_pk_env_t
*key
; /**< For public keys only. */
77 const char *error
; /**< For _ERR tokens only. */
80 /* ********************************************************************** */
82 /** We use a table of rules to decide how to parse each token type. */
84 /** Rules for how many arguments a keyword can take. */
86 NO_ARGS
, /**< No arguments, ever. */
87 ARGS
, /**< A list of arguments separated by spaces. */
88 CONCAT_ARGS
, /**< The rest of the line, treated as a single argument. */
91 /** Rules for whether the keyword needs an object. */
93 NO_OBJ
, /**< No object, ever. */
94 NEED_OBJ
, /**< Object is required. */
95 NEED_KEY
, /**< Object is required, and must be a public key. */
96 OBJ_OK
, /**< Object is optional. */
99 /** Rules for where a keyword can appear. */
101 DIR = 1, /**< Appears only in directory. */
102 RTR
= 2, /**< Appears only in router descriptor or runningrouters. */
103 NETSTATUS
= 4, /**< v2 or later ("versioned") network status. */
104 ANYSIGNED
= 7, /**< Any "full" document (that is, not a router status.) */
105 RTRSTATUS
= 8, /**< Router-status portion of a versioned network status. */
106 ANY
= 15, /**< Appears in any document type. */
109 /** Table mapping keywords to token value and to argument rules. */
111 const char *t
; int v
; arg_syntax s
; obj_syntax os
; int ws
;
113 { "accept", K_ACCEPT
, ARGS
, NO_OBJ
, RTR
},
114 { "directory-signature", K_DIRECTORY_SIGNATURE
, ARGS
, NEED_OBJ
,
116 { "r", K_R
, ARGS
, NO_OBJ
, RTRSTATUS
},
117 { "s", K_S
, ARGS
, NO_OBJ
, RTRSTATUS
},
118 { "reject", K_REJECT
, ARGS
, NO_OBJ
, RTR
},
119 { "router", K_ROUTER
, ARGS
, NO_OBJ
, RTR
},
120 { "recommended-software",K_RECOMMENDED_SOFTWARE
,ARGS
, NO_OBJ
, DIR },
121 { "signed-directory", K_SIGNED_DIRECTORY
, NO_ARGS
, NO_OBJ
, DIR },
122 { "signing-key", K_SIGNING_KEY
, NO_ARGS
, NEED_KEY
,RTR
},
123 { "onion-key", K_ONION_KEY
, NO_ARGS
, NEED_KEY
,RTR
},
124 { "router-signature", K_ROUTER_SIGNATURE
, NO_ARGS
, NEED_OBJ
,RTR
},
125 { "running-routers", K_RUNNING_ROUTERS
, ARGS
, NO_OBJ
, DIR },
126 { "router-status", K_ROUTER_STATUS
, ARGS
, NO_OBJ
, DIR },
127 { "ports", K_PORTS
, ARGS
, NO_OBJ
, RTR
},
128 { "bandwidth", K_BANDWIDTH
, ARGS
, NO_OBJ
, RTR
},
129 { "platform", K_PLATFORM
, CONCAT_ARGS
, NO_OBJ
, RTR
},
130 { "published", K_PUBLISHED
, CONCAT_ARGS
, NO_OBJ
, ANYSIGNED
},
131 { "opt", K_OPT
, CONCAT_ARGS
, OBJ_OK
, ANY
},
132 { "contact", K_CONTACT
, CONCAT_ARGS
, NO_OBJ
, ANYSIGNED
},
133 { "network-status", K_NETWORK_STATUS
, NO_ARGS
, NO_OBJ
, DIR },
134 { "uptime", K_UPTIME
, ARGS
, NO_OBJ
, RTR
},
135 { "dir-signing-key", K_DIR_SIGNING_KEY
, ARGS
, OBJ_OK
,
137 { "family", K_FAMILY
, ARGS
, NO_OBJ
, RTR
},
138 { "fingerprint", K_FINGERPRINT
, ARGS
, NO_OBJ
, ANYSIGNED
},
139 { "hibernating", K_HIBERNATING
, ARGS
, NO_OBJ
, RTR
},
140 { "read-history", K_READ_HISTORY
, ARGS
, NO_OBJ
, RTR
},
141 { "write-history", K_WRITE_HISTORY
, ARGS
, NO_OBJ
, RTR
},
142 { "network-status-version", K_NETWORK_STATUS_VERSION
,
143 ARGS
, NO_OBJ
, NETSTATUS
},
144 { "dir-source", K_DIR_SOURCE
, ARGS
, NO_OBJ
, NETSTATUS
},
145 { "dir-options", K_DIR_OPTIONS
, ARGS
, NO_OBJ
, NETSTATUS
},
146 { "client-versions", K_CLIENT_VERSIONS
, ARGS
, NO_OBJ
, NETSTATUS
},
147 { "server-versions", K_SERVER_VERSIONS
, ARGS
, NO_OBJ
, NETSTATUS
},
148 { NULL
, -1, NO_ARGS
, NO_OBJ
, ANY
}
151 /* static function prototypes */
152 static int router_add_exit_policy(routerinfo_t
*router
,directory_token_t
*tok
);
153 static addr_policy_t
*router_parse_addr_policy(directory_token_t
*tok
);
154 static int router_get_hash_impl(const char *s
, char *digest
,
155 const char *start_str
, const char *end_str
);
156 static void token_free(directory_token_t
*tok
);
157 static smartlist_t
*find_all_exitpolicy(smartlist_t
*s
);
158 static directory_token_t
*find_first_by_keyword(smartlist_t
*s
,
159 directory_keyword keyword
);
160 static int tokenize_string(const char *start
, const char *end
,
161 smartlist_t
*out
, where_syntax where
);
162 static directory_token_t
*get_next_token(const char **s
, where_syntax where
);
163 static int check_directory_signature(const char *digest
,
164 directory_token_t
*tok
,
165 crypto_pk_env_t
*pkey
,
166 crypto_pk_env_t
*declared_key
,
167 int check_authority
);
168 static crypto_pk_env_t
*find_dir_signing_key(const char *str
);
169 static int tor_version_same_series(tor_version_t
*a
, tor_version_t
*b
);
171 /** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
172 * <b>s</b>. Return 0 on success, -1 on failure.
175 router_get_dir_hash(const char *s
, char *digest
)
177 return router_get_hash_impl(s
,digest
,
178 "signed-directory","\ndirectory-signature");
181 /** Set <b>digest</b> to the SHA-1 digest of the hash of the first router in
182 * <b>s</b>. Return 0 on success, -1 on failure.
185 router_get_router_hash(const char *s
, char *digest
)
187 return router_get_hash_impl(s
,digest
,
188 "router ","\nrouter-signature");
191 /** Set <b>digest</b> to the SHA-1 digest of the hash of the running-routers
192 * string in <b>s</b>. Return 0 on success, -1 on failure.
195 router_get_runningrouters_hash(const char *s
, char *digest
)
197 return router_get_hash_impl(s
,digest
,
198 "network-status","\ndirectory-signature");
201 /** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
202 * string in <b>s</b>. Return 0 on success, -1 on failure. */
204 router_get_networkstatus_v2_hash(const char *s
, char *digest
)
206 return router_get_hash_impl(s
,digest
,
207 "network-status-version","\ndirectory-signature");
210 /** Helper: used to generate signatures for routers, directories and
211 * network-status objects. Given a digest in <b>digest</b> and a secret
212 * <b>private_key</b>, generate an PKCS1-padded signature, BASE64-encode it,
213 * surround it with -----BEGIN/END----- pairs, and write it to the
214 * <b>buf_len</b>-byte buffer at <b>buf</b>. Return 0 on success, -1 on
218 router_append_dirobj_signature(char *buf
, size_t buf_len
, const char *digest
,
219 crypto_pk_env_t
*private_key
)
221 char signature
[PK_BYTES
];
224 if (crypto_pk_private_sign(private_key
, signature
, digest
, DIGEST_LEN
) < 0) {
226 log_fn(LOG_WARN
,"Couldn't sign digest.");
229 if (strlcat(buf
, "-----BEGIN SIGNATURE-----\n", buf_len
) >= buf_len
)
233 if (base64_encode(buf
+i
, buf_len
-i
, signature
, 128) < 0) {
234 log_fn(LOG_WARN
,"couldn't base64-encode signature");
239 if (strlcat(buf
, "-----END SIGNATURE-----\n", buf_len
) >= buf_len
)
244 log_fn(LOG_WARN
,"tried to exceed string length.");
248 /** Return VS_RECOMMENDED if <b>myversion</b> is contained in
249 * <b>versionlist</b>. Else, return VS_OLD if every member of
250 * <b>versionlist</b> is newer than <b>myversion</b>. Else, return
251 * VS_NEW_IN_SERIES if there is at least one member of <b>versionlist</b> in
252 * the same series (major.minor.micro) as <b>myversion</b>, but no such member
253 * is newer than <b>myversion.</b>. Else, return VS_NEW if every memeber of
254 * <b>versionlist</b> is older than <b>myversion</b>. Else, return
257 * (versionlist is a comma-separated list of version strings,
258 * optionally prefixed with "Tor". Versions that can't be parsed are
262 tor_version_is_obsolete(const char *myversion
, const char *versionlist
)
265 tor_version_t mine
, other
;
266 int found_newer
= 0, found_older
= 0, found_newer_in_series
= 0,
267 found_any_in_series
= 0, r
, same
;
268 version_status_t ret
= VS_UNRECOMMENDED
;
269 smartlist_t
*version_sl
;
273 log_fn(LOG_DEBUG
,"Checking whether version '%s' is in '%s'",
274 myversion
, versionlist
);
276 if (tor_version_parse(myversion
, &mine
)) {
277 log_fn(LOG_ERR
, "I couldn't parse my own version (%s)", myversion
);
280 version_sl
= smartlist_create();
281 smartlist_split_string(version_sl
, versionlist
, ",", SPLIT_SKIP_SPACE
, 0);
283 SMARTLIST_FOREACH(version_sl
, const char *, cp
, {
284 if (!strcmpstart(cp
, "Tor "))
287 if (tor_version_parse(cp
, &other
)) {
288 /* Couldn't parse other; it can't be a match. */
290 same
= tor_version_same_series(&mine
, &other
);
292 found_any_in_series
= 1;
293 r
= tor_version_compare(&mine
, &other
);
295 ret
= VS_RECOMMENDED
;
300 found_newer_in_series
= 1;
307 /* We didn't find the listed version. Is it new or old? */
308 if (found_any_in_series
&& !found_newer_in_series
) {
309 ret
= VS_NEW_IN_SERIES
;
310 } else if (found_newer
&& !found_older
) {
312 } else if (found_older
&& !found_newer
) {
315 ret
= VS_UNRECOMMENDED
;
319 SMARTLIST_FOREACH(version_sl
, char *, version
, tor_free(version
));
320 smartlist_free(version_sl
);
324 /** Return the combined status of the current version, given that we know of
325 * one set of networkstatuses that give us status <b>a</b>, and another that
326 * gives us status <b>b</b>.
328 * For example, if one authority thinks that we're NEW, and another thinks
329 * we're OLD, we're simply UNRECOMMENDED.
331 * This function does not handle calculating whether we're RECOMMENDED; that
332 * follows a simple majority rule. This function simply calculates *why*
333 * we're not recommended (if we're not).
336 version_status_join(version_status_t a
, version_status_t b
)
340 else if (a
== VS_UNRECOMMENDED
|| b
== VS_UNRECOMMENDED
)
341 return VS_UNRECOMMENDED
;
342 else if (a
== VS_RECOMMENDED
)
344 else if (b
== VS_RECOMMENDED
)
346 /* Okay. Neither is 'recommended' or 'unrecommended', and they differ. */
347 else if (a
== VS_OLD
|| b
== VS_OLD
)
348 return VS_UNRECOMMENDED
;
349 /* One is VS_NEW, the other is VS_NEW_IN_SERIES */
351 return VS_NEW_IN_SERIES
;
354 /** Read a signed directory from <b>str</b>. If it's well-formed, return 0.
355 * Otherwise, return -1. If we're a directory cache, cache it.
358 router_parse_directory(const char *str
)
360 directory_token_t
*tok
;
361 char digest
[DIGEST_LEN
];
364 const char *end
, *cp
;
365 smartlist_t
*tokens
= NULL
;
366 crypto_pk_env_t
*declared_key
= NULL
;
368 /* XXXX This could be simplified a lot, but it will all go away
369 * once pre-0.1.1.8 is obsolete, and for now it's better not to
372 if (router_get_dir_hash(str
, digest
)) {
373 log_fn(LOG_WARN
, "Unable to compute digest of directory");
376 log_fn(LOG_DEBUG
,"Received directory hashes to %s",hex_str(digest
,4));
378 /* Check signature first, before we try to tokenize. */
380 while (cp
&& (end
= strstr(cp
+1, "\ndirectory-signature")))
382 if (cp
== str
|| !cp
) {
383 log_fn(LOG_WARN
, "No signature found on directory."); goto err
;
386 tokens
= smartlist_create();
387 if (tokenize_string(cp
,strchr(cp
,'\0'),tokens
,DIR)) {
388 log_fn(LOG_WARN
, "Error tokenizing directory signature"); goto err
;
390 if (smartlist_len(tokens
) != 1) {
391 log_fn(LOG_WARN
, "Unexpected number of tokens in signature"); goto err
;
393 tok
=smartlist_get(tokens
,0);
394 if (tok
->tp
!= K_DIRECTORY_SIGNATURE
) {
395 log_fn(LOG_WARN
,"Expected a single directory signature"); goto err
;
397 declared_key
= find_dir_signing_key(str
);
398 if (check_directory_signature(digest
, tok
, NULL
, declared_key
, 1)<0)
401 SMARTLIST_FOREACH(tokens
, directory_token_t
*, tok
, token_free(tok
));
402 smartlist_free(tokens
);
405 /* Now try to parse the first part of the directory. */
406 if ((end
= strstr(str
,"\nrouter "))) {
408 } else if ((end
= strstr(str
, "\ndirectory-signature"))) {
411 end
= str
+ strlen(str
);
414 tokens
= smartlist_create();
415 if (tokenize_string(str
,end
,tokens
,DIR)) {
416 log_fn(LOG_WARN
, "Error tokenizing directory"); goto err
;
419 if (!(tok
= find_first_by_keyword(tokens
, K_PUBLISHED
))) {
420 log_fn(LOG_WARN
, "Missing published time on directory.");
423 tor_assert(tok
->n_args
== 1);
425 if (parse_iso_time(tok
->args
[0], &published_on
) < 0) {
429 /* Now that we know the signature is okay, and we have a
430 * publication time, cache the directory. */
431 if (get_options()->DirPort
&& !get_options()->V1AuthoritativeDir
)
432 dirserv_set_cached_directory(str
, published_on
, 0);
439 if (declared_key
) crypto_free_pk_env(declared_key
);
441 SMARTLIST_FOREACH(tokens
, directory_token_t
*, tok
, token_free(tok
));
442 smartlist_free(tokens
);
447 /** Read a signed router status statement from <b>str</b>. If it's
448 * well-formed, return 0. Otherwise, return -1. If we're a directory cache,
451 router_parse_runningrouters(const char *str
)
453 char digest
[DIGEST_LEN
];
454 directory_token_t
*tok
;
457 crypto_pk_env_t
*declared_key
= NULL
;
458 smartlist_t
*tokens
= NULL
;
460 if (router_get_runningrouters_hash(str
, digest
)) {
461 log_fn(LOG_WARN
, "Unable to compute digest of directory");
464 tokens
= smartlist_create();
465 if (tokenize_string(str
,str
+strlen(str
),tokens
,DIR)) {
466 log_fn(LOG_WARN
, "Error tokenizing directory"); goto err
;
468 if ((tok
= find_first_by_keyword(tokens
, _UNRECOGNIZED
))) {
469 log_fn(LOG_WARN
, "Unrecognized keyword '%s'; can't parse running-routers",
473 tok
= smartlist_get(tokens
,0);
474 if (tok
->tp
!= K_NETWORK_STATUS
) {
475 log_fn(LOG_WARN
, "Network-status starts with wrong token");
479 if (!(tok
= find_first_by_keyword(tokens
, K_PUBLISHED
))) {
480 log_fn(LOG_WARN
, "Missing published time on directory.");
483 tor_assert(tok
->n_args
== 1);
484 if (parse_iso_time(tok
->args
[0], &published_on
) < 0) {
487 if (!(tok
= find_first_by_keyword(tokens
, K_DIRECTORY_SIGNATURE
))) {
488 log_fn(LOG_WARN
, "Missing signature on running-routers");
491 declared_key
= find_dir_signing_key(str
);
492 if (check_directory_signature(digest
, tok
, NULL
, declared_key
, 1) < 0)
495 /* Now that we know the signature is okay, and we have a
496 * publication time, cache the list. */
497 if (get_options()->DirPort
&& !get_options()->V1AuthoritativeDir
)
498 dirserv_set_cached_directory(str
, published_on
, 1);
502 if (declared_key
) crypto_free_pk_env(declared_key
);
504 SMARTLIST_FOREACH(tokens
, directory_token_t
*, tok
, token_free(tok
));
505 smartlist_free(tokens
);
510 /** Given a directory or running-routers string in <b>str</b>, try to
511 * find the its dir-signing-key token (if any). If this token is
512 * present, extract and return the key. Return NULL on failure. */
513 static crypto_pk_env_t
*
514 find_dir_signing_key(const char *str
)
517 directory_token_t
*tok
;
518 crypto_pk_env_t
*key
= NULL
;
520 /* Is there a dir-signing-key in the directory? */
521 cp
= strstr(str
, "\nopt dir-signing-key");
523 cp
= strstr(str
, "\ndir-signing-key");
526 ++cp
; /* Now cp points to the start of the token. */
528 tok
= get_next_token(&cp
, DIR);
530 log_fn(LOG_WARN
, "Unparseable dir-signing-key token");
533 if (tok
->tp
!= K_DIR_SIGNING_KEY
) {
534 log_fn(LOG_WARN
, "Dir-signing-key token did not parse as expected");
540 tok
->key
= NULL
; /* steal reference. */
541 } else if (tok
->n_args
>= 1) {
542 /** XXXX Once all the directories are running 0.1.0.6-rc or later, we
543 * can remove this logic. */
544 key
= crypto_pk_DER64_decode_public_key(tok
->args
[0]);
546 log_fn(LOG_WARN
, "Unparseable dir-signing-key argument");
550 log_fn(LOG_WARN
, "Dir-signing-key token contained no key");
558 /** Return true iff <b>key</b> is allowed to sign directories.
561 dir_signing_key_is_trusted(crypto_pk_env_t
*key
)
563 char digest
[DIGEST_LEN
];
565 if (crypto_pk_get_digest(key
, digest
) < 0) {
566 log_fn(LOG_WARN
, "Error computing dir-signing-key digest");
569 if (!router_digest_is_trusted_dir(digest
)) {
570 log_fn(LOG_WARN
, "Listed dir-signing-key is not trusted");
576 /** Check whether the K_DIRECTORY_SIGNATURE token in <b>tok</b> has a
577 * good signature for <b>digest</b>.
579 * If <b>declared_key</b> is set, the directory has declared what key
580 * was used to sign it, so we will use that key only if it is an
581 * authoritative directory signing key or if check_authority is 0.
583 * Otherwise, if pkey is provided, try to use it.
585 * (New callers should always use <b>declared_key</b> when possible;
586 * <b>pkey</b> is only for debugging.)
589 check_directory_signature(const char *digest
,
590 directory_token_t
*tok
,
591 crypto_pk_env_t
*pkey
,
592 crypto_pk_env_t
*declared_key
,
595 char signed_digest
[PK_BYTES
];
596 crypto_pk_env_t
*_pkey
= NULL
;
598 if (tok
->n_args
!= 1) {
599 log_fn(LOG_WARN
, "Too many or too few arguments to directory-signature");
604 if (!check_authority
|| dir_signing_key_is_trusted(declared_key
))
605 _pkey
= declared_key
;
607 if (!_pkey
&& pkey
) {
608 /* pkey provided for debugging purposes */
612 log_fn(LOG_WARN
, "Obsolete directory format (dir signing key not present) or signing key not trusted--rejecting.");
616 if (strcmp(tok
->object_type
, "SIGNATURE") || tok
->object_size
!= 128) {
617 log_fn(LOG_WARN
, "Bad object type or length on directory signature");
623 if (crypto_pk_public_checksig(_pkey
, signed_digest
, tok
->object_body
, 128)
625 log_fn(LOG_WARN
, "Error reading directory: invalid signature.");
628 log_fn(LOG_DEBUG
,"Signed directory hash starts %s", hex_str(signed_digest
,4));
629 if (memcmp(digest
, signed_digest
, DIGEST_LEN
)) {
630 log_fn(LOG_WARN
, "Error reading directory: signature does not match.");
636 /** Given a string *<b>s</b> containing a concatenated sequence of router
637 * descriptors, parses them and stores the result in <b>dest</b>. All routers
638 * are marked running and verified. Advances *s to a point immediately
639 * following the last router entry. Ignore any trailing router entries that
640 * are not complete. Returns 0 on success and -1 on failure.
643 router_parse_list_from_string(const char **s
, smartlist_t
*dest
)
645 routerinfo_t
*router
;
646 const char *end
, *cp
;
653 *s
= eat_whitespace(*s
);
654 /* Don't start parsing the rest of *s unless it contains a router. */
655 if (strcmpstart(*s
, "router ")!=0)
657 if ((end
= strstr(*s
+1, "\nrouter "))) {
660 } else if ((end
= strstr(*s
+1, "\ndirectory-signature"))) {
664 cp
= end
= *s
+strlen(*s
);
667 while (cp
> *s
&& (!*cp
|| TOR_ISSPACE(*cp
)))
669 /* cp now points to the last non-space character in this descriptor. */
671 while (cp
> *s
&& *cp
!= '\n')
673 /* cp now points to the first \n before the last non-bank line in this
676 if (strcmpstart(cp
, "\n-----END SIGNATURE-----\n")) {
677 log_fn(LOG_INFO
, "Ignoring truncated router descriptor.");
681 router
= router_parse_entry_from_string(*s
, end
);
685 log_fn(LOG_WARN
, "Error reading router; skipping");
688 smartlist_add(dest
, router
);
694 /** Helper function: reads a single router entry from *<b>s</b> ...
695 * *<b>end</b>. Mallocs a new router and returns it if all goes well, else
699 router_parse_entry_from_string(const char *s
, const char *end
)
701 routerinfo_t
*router
= NULL
;
702 char signed_digest
[128];
704 smartlist_t
*tokens
= NULL
, *exit_policy_tokens
= NULL
;
705 directory_token_t
*tok
;
707 int ports_set
, bw_set
;
714 /* point 'end' to a point immediately after the final newline. */
715 while (end
> s
+2 && *(end
-1) == '\n' && *(end
-2) == '\n')
718 if (router_get_router_hash(s
, digest
) < 0) {
719 log_fn(LOG_WARN
, "Couldn't compute router hash.");
722 tokens
= smartlist_create();
723 if (tokenize_string(s
,end
,tokens
,RTR
)) {
724 log_fn(LOG_WARN
, "Error tokeninzing router descriptor.");
728 if (smartlist_len(tokens
) < 2) {
729 log_fn(LOG_WARN
, "Impossibly short router descriptor.");
732 if ((tok
= find_first_by_keyword(tokens
, _UNRECOGNIZED
))) {
733 log_fn(LOG_INFO
, "Unrecognized critical keyword '%s'; skipping descriptor. (It may be from another version of Tor.)",
738 tok
= smartlist_get(tokens
,0);
739 if (tok
->tp
!= K_ROUTER
) {
740 log_fn(LOG_WARN
,"Entry does not start with \"router\"");
744 router
= tor_malloc_zero(sizeof(routerinfo_t
));
745 router
->signed_descriptor
= tor_strndup(s
, end
-s
);
746 router
->signed_descriptor_len
= end
-s
;
747 memcpy(router
->signed_descriptor_digest
, digest
, DIGEST_LEN
);
748 ports_set
= bw_set
= 0;
750 if (tok
->n_args
== 2 || tok
->n_args
== 5 || tok
->n_args
== 6) {
751 router
->nickname
= tor_strdup(tok
->args
[0]);
752 if (!is_legal_nickname(router
->nickname
)) {
753 log_fn(LOG_WARN
,"Router nickname is invalid");
756 router
->address
= tor_strdup(tok
->args
[1]);
757 if (!tor_inet_aton(router
->address
, &in
)) {
758 log_fn(LOG_WARN
,"Router address is not an IP.");
761 router
->addr
= ntohl(in
.s_addr
);
763 if (tok
->n_args
>= 5) {
764 router
->or_port
= (uint16_t) tor_parse_long(tok
->args
[2],10,0,65535,NULL
,NULL
);
765 router
->dir_port
= (uint16_t) tor_parse_long(tok
->args
[4],10,0,65535,NULL
,NULL
);
769 log_fn(LOG_WARN
,"Wrong # of arguments to \"router\" (%d)",tok
->n_args
);
773 tok
= find_first_by_keyword(tokens
, K_PORTS
);
774 if (tok
&& ports_set
) {
775 log_fn(LOG_WARN
,"Redundant ports line");
778 if (tok
->n_args
!= 3) {
779 log_fn(LOG_WARN
,"Wrong # of arguments to \"ports\"");
782 router
->or_port
= (uint16_t) tor_parse_long(tok
->args
[0],10,0,65535,NULL
,NULL
);
783 router
->dir_port
= (uint16_t) tor_parse_long(tok
->args
[2],10,0,65535,NULL
,NULL
);
787 tok
= find_first_by_keyword(tokens
, K_BANDWIDTH
);
789 log_fn(LOG_WARN
,"Redundant bandwidth line");
792 if (tok
->n_args
< 3) {
793 /* XXXX Once 0.0.7 is *really* dead, restore this warning to its old form*/
794 log_fn(LOG_WARN
,"Not enough arguments to \"bandwidth\": must be an obsolete server. Rejecting one server (nickname '%s').", router
->nickname
);
797 router
->bandwidthrate
= tor_parse_long(tok
->args
[0],10,0,INT_MAX
,NULL
,NULL
);
798 router
->bandwidthburst
= tor_parse_long(tok
->args
[1],10,0,INT_MAX
,NULL
,NULL
);
799 router
->bandwidthcapacity
= tor_parse_long(tok
->args
[2],10,0,INT_MAX
,NULL
,NULL
);
803 if ((tok
= find_first_by_keyword(tokens
, K_UPTIME
))) {
804 if (tok
->n_args
!= 1) {
805 log_fn(LOG_WARN
, "Unrecognized number of args on K_UPTIME; skipping.");
807 router
->uptime
= tor_parse_long(tok
->args
[0],10,0,LONG_MAX
,NULL
,NULL
);
811 if ((tok
= find_first_by_keyword(tokens
, K_HIBERNATING
))) {
812 if (tok
->n_args
< 1) {
813 log_fn(LOG_WARN
, "Too few args on 'hibernating' keyword. Skipping.");
815 router
->is_hibernating
816 = (tor_parse_long(tok
->args
[0],10,0,LONG_MAX
,NULL
,NULL
) != 0);
820 if (!(tok
= find_first_by_keyword(tokens
, K_PUBLISHED
))) {
821 log_fn(LOG_WARN
, "Missing published time"); goto err
;
823 tor_assert(tok
->n_args
== 1);
824 if (parse_iso_time(tok
->args
[0], &router
->published_on
) < 0)
827 if (!(tok
= find_first_by_keyword(tokens
, K_ONION_KEY
))) {
828 log_fn(LOG_WARN
, "Missing onion key"); goto err
;
830 if (crypto_pk_keysize(tok
->key
) != PK_BYTES
) {
831 log_fn(LOG_WARN
, "Wrong size on onion key: %d bits!",
832 (int)crypto_pk_keysize(tok
->key
)*8);
835 router
->onion_pkey
= tok
->key
;
836 tok
->key
= NULL
; /* Prevent free */
838 if (!(tok
= find_first_by_keyword(tokens
, K_SIGNING_KEY
))) {
839 log_fn(LOG_WARN
, "Missing identity key"); goto err
;
841 if (crypto_pk_keysize(tok
->key
) != PK_BYTES
) {
842 log_fn(LOG_WARN
, "Wrong size on identity key: %d bits!",
843 (int)crypto_pk_keysize(tok
->key
)*8);
846 router
->identity_pkey
= tok
->key
;
847 tok
->key
= NULL
; /* Prevent free */
848 if (crypto_pk_get_digest(router
->identity_pkey
,router
->identity_digest
)) {
849 log_fn(LOG_WARN
, "Couldn't calculate key digest"); goto err
;
852 if ((tok
= find_first_by_keyword(tokens
, K_PLATFORM
))) {
853 router
->platform
= tor_strdup(tok
->args
[0]);
856 if ((tok
= find_first_by_keyword(tokens
, K_CONTACT
))) {
857 router
->contact_info
= tor_strdup(tok
->args
[0]);
860 exit_policy_tokens
= find_all_exitpolicy(tokens
);
861 SMARTLIST_FOREACH(exit_policy_tokens
, directory_token_t
*, t
,
862 if (router_add_exit_policy(router
,t
)<0) {
863 log_fn(LOG_WARN
,"Error in exit policy");
867 if ((tok
= find_first_by_keyword(tokens
, K_FAMILY
)) && tok
->n_args
) {
869 router
->declared_family
= smartlist_create();
870 for (i
=0;i
<tok
->n_args
;++i
) {
871 if (!is_legal_nickname_or_hexdigest(tok
->args
[i
])) {
872 log_fn(LOG_WARN
, "Illegal nickname '%s' in family line", tok
->args
[i
]);
875 smartlist_add(router
->declared_family
, tor_strdup(tok
->args
[i
]));
879 if (!(tok
= find_first_by_keyword(tokens
, K_ROUTER_SIGNATURE
))) {
880 log_fn(LOG_WARN
, "Missing router signature");
883 if (strcmp(tok
->object_type
, "SIGNATURE") || tok
->object_size
!= 128) {
884 log_fn(LOG_WARN
, "Bad object type or length on router signature");
887 if ((t
=crypto_pk_public_checksig(router
->identity_pkey
, signed_digest
,
888 tok
->object_body
, 128)) != 20) {
889 log_fn(LOG_WARN
, "Invalid signature %d",t
);
892 if (memcmp(digest
, signed_digest
, DIGEST_LEN
)) {
893 log_fn(LOG_WARN
, "Mismatched signature");
898 log_fn(LOG_WARN
,"No ports declared; failing.");
902 log_fn(LOG_WARN
,"No bandwidth declared; failing.");
905 if (!router
->or_port
) {
906 log_fn(LOG_WARN
,"or_port unreadable or 0. Failing.");
909 if (!router
->bandwidthrate
) {
910 log_fn(LOG_WARN
,"bandwidthrate unreadable or 0. Failing.");
913 if (!router
->platform
) {
914 router
->platform
= tor_strdup("<unknown>");
920 routerinfo_free(router
);
924 SMARTLIST_FOREACH(tokens
, directory_token_t
*, tok
, token_free(tok
));
925 smartlist_free(tokens
);
927 if (exit_policy_tokens
) {
928 smartlist_free(exit_policy_tokens
);
933 /** Helper: given a string <b>s</b>, return the start of the next router-status
934 * object (starting with "r " at the start of a line). If none is found,
935 * return the start of the next directory signature. If none is found, return
936 * the end of the string. */
937 static INLINE
const char *
938 find_start_of_next_routerstatus(const char *s
)
940 const char *eos
= strstr(s
, "\nr ");
942 eos
= strstr(s
, "\ndirectory-signature");
946 return s
+ strlen(s
);
949 /** Given a string at *<b>s</b>, containing a routerstatus object, and an
950 * empty smartlist at <b>tokens</b>, parse and return the first router status
951 * object in the string, and advance *<b>s</b> to just after the end of the
952 * router status. Return NULL and advance *<b>s</b> on error. */
953 static routerstatus_t
*
954 routerstatus_parse_entry_from_string(const char **s
, smartlist_t
*tokens
)
957 routerstatus_t
*rs
= NULL
;
958 directory_token_t
*tok
;
959 char timebuf
[ISO_TIME_LEN
+1];
964 eos
= find_start_of_next_routerstatus(*s
);
966 if (tokenize_string(*s
, eos
, tokens
, RTRSTATUS
)) {
967 log_fn(LOG_WARN
, "Error tokenizing router status");
970 if (smartlist_len(tokens
) < 1) {
971 log_fn(LOG_WARN
, "Impossibly short router status");
974 if ((tok
= find_first_by_keyword(tokens
, _UNRECOGNIZED
))) {
975 log_fn(LOG_WARN
, "Unrecognized keyword \"%s\" in router status; skipping.",
979 if (!(tok
= find_first_by_keyword(tokens
, K_R
))) {
980 log_fn(LOG_WARN
, "Missing 'r' keywork in router status; skipping.");
983 if (tok
->n_args
< 8) {
985 "Too few arguments to 'r' keywork in router status; skipping.");
987 rs
= tor_malloc_zero(sizeof(routerstatus_t
));
989 if (!is_legal_nickname(tok
->args
[0])) {
991 "Invalid nickname '%s' in router status; skipping.", tok
->args
[0]);
994 strlcpy(rs
->nickname
, tok
->args
[0], sizeof(rs
->nickname
));
996 if (digest_from_base64(rs
->identity_digest
, tok
->args
[1])) {
997 log_fn(LOG_WARN
, "Error decoding digest '%s'", tok
->args
[1]);
1001 if (digest_from_base64(rs
->descriptor_digest
, tok
->args
[2])) {
1002 log_fn(LOG_WARN
, "Error decoding digest '%s'", tok
->args
[2]);
1006 if (tor_snprintf(timebuf
, sizeof(timebuf
), "%s %s",
1007 tok
->args
[3], tok
->args
[4]) < 0 ||
1008 parse_iso_time(timebuf
, &rs
->published_on
)<0) {
1009 log_fn(LOG_WARN
, "Error parsing time '%s %s'", tok
->args
[3], tok
->args
[4]);
1013 if (tor_inet_aton(tok
->args
[5], &in
) == 0) {
1014 log_fn(LOG_WARN
, "Error parsing address '%s'", tok
->args
[5]);
1017 rs
->addr
= ntohl(in
.s_addr
);
1019 rs
->or_port
=(uint16_t) tor_parse_long(tok
->args
[6],10,0,65535,NULL
,NULL
);
1020 rs
->dir_port
= (uint16_t) tor_parse_long(tok
->args
[7],10,0,65535,NULL
,NULL
);
1022 if ((tok
= find_first_by_keyword(tokens
, K_S
))) {
1024 for (i
=0; i
< tok
->n_args
; ++i
) {
1025 if (!strcmp(tok
->args
[i
], "Exit"))
1027 else if (!strcmp(tok
->args
[i
], "Stable"))
1029 else if (!strcmp(tok
->args
[i
], "Fast"))
1031 else if (!strcmp(tok
->args
[i
], "Running"))
1033 else if (!strcmp(tok
->args
[i
], "Named"))
1035 else if (!strcmp(tok
->args
[i
], "Valid"))
1043 routerstatus_free(rs
);
1046 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_free(t
));
1047 smartlist_clear(tokens
);
1053 /** Helper to sort a smartlist of pointers to routerstatus_t */
1055 _compare_routerstatus_entries(const void **_a
, const void **_b
)
1057 const routerstatus_t
*a
= *_a
, *b
= *_b
;
1058 return memcmp(a
->identity_digest
, b
->identity_digest
, DIGEST_LEN
);
1062 sort_routerstatus_entries(smartlist_t
*sl
)
1064 smartlist_sort(sl
, _compare_routerstatus_entries
);
1067 /** Given a versioned (v2 or later) network-status object in <b>s</b>, try to
1068 * parse it and return the result. Return NULL on failure. Check the
1069 * signature of the network status, but do not (yet) check the signing key for
1073 networkstatus_parse_from_string(const char *s
)
1076 smartlist_t
*tokens
= smartlist_create();
1077 networkstatus_t
*ns
= NULL
;
1078 char ns_digest
[DIGEST_LEN
];
1079 char tmp_digest
[DIGEST_LEN
];
1081 directory_token_t
*tok
;
1084 if (router_get_networkstatus_v2_hash(s
, ns_digest
)) {
1085 log_fn(LOG_WARN
, "Unable to compute digest of network-status");
1089 eos
= find_start_of_next_routerstatus(s
);
1090 if (tokenize_string(s
, eos
, tokens
, NETSTATUS
)) {
1091 log_fn(LOG_WARN
, "Error tokenizing network-status header.");
1094 if ((tok
= find_first_by_keyword(tokens
, _UNRECOGNIZED
))) {
1095 log_fn(LOG_WARN
, "Unrecognized keyword '%s'; can't parse network-status",
1099 ns
= tor_malloc_zero(sizeof(networkstatus_t
));
1100 memcpy(ns
->networkstatus_digest
, ns_digest
, DIGEST_LEN
);
1102 if (!(tok
= find_first_by_keyword(tokens
, K_NETWORK_STATUS_VERSION
))) {
1103 log_fn(LOG_WARN
, "Couldn't find network-status-version keyword");
1107 if (!(tok
= find_first_by_keyword(tokens
, K_DIR_SOURCE
))) {
1108 log_fn(LOG_WARN
, "Couldn't find dir-source keyword");
1111 if (tok
->n_args
< 3) {
1112 log_fn(LOG_WARN
, "Too few arguments to dir-source keyword");
1115 ns
->source_address
= tok
->args
[0]; tok
->args
[0] = NULL
;
1116 if (tor_inet_aton(tok
->args
[1], &in
) == 0) {
1117 log_fn(LOG_WARN
, "Error parsing address '%s'", tok
->args
[1]);
1120 ns
->source_addr
= ntohl(in
.s_addr
);
1121 ns
->source_dirport
=
1122 (uint16_t) tor_parse_long(tok
->args
[2],10,0,65535,NULL
,NULL
);
1123 if (ns
->source_dirport
== 0) {
1124 log_fn(LOG_WARN
, "Directory source without dirport; skipping.");
1128 if (!(tok
= find_first_by_keyword(tokens
, K_FINGERPRINT
))) {
1129 log_fn(LOG_WARN
, "Couldn't find fingerprint keyword");
1132 if (tok
->n_args
< 1) {
1133 log_fn(LOG_WARN
, "Too few arguments to fingerprint");
1136 if (base16_decode(ns
->identity_digest
, DIGEST_LEN
, tok
->args
[0],
1137 strlen(tok
->args
[0]))) {
1138 log_fn(LOG_WARN
, "Couldn't decode fingerprint '%s'", tok
->args
[0]);
1142 if ((tok
= find_first_by_keyword(tokens
, K_CONTACT
)) && tok
->n_args
) {
1143 ns
->contact
= tok
->args
[0];
1144 tok
->args
[0] = NULL
;
1147 if (!(tok
= find_first_by_keyword(tokens
, K_DIR_SIGNING_KEY
)) || !tok
->key
) {
1148 log_fn(LOG_WARN
, "Missing dir-signing-key");
1151 ns
->signing_key
= tok
->key
;
1154 if (crypto_pk_get_digest(ns
->signing_key
, tmp_digest
)<0) {
1155 log_fn(LOG_WARN
, "Couldn't compute signing key digest");
1158 if (memcmp(tmp_digest
, ns
->identity_digest
, DIGEST_LEN
)) {
1159 log_fn(LOG_WARN
, "network-status fingerprint did not match dir-signing-key");
1163 if ((tok
= find_first_by_keyword(tokens
, K_DIR_OPTIONS
))) {
1164 for (i
=0; i
< tok
->n_args
; ++i
) {
1165 if (!strcmp(tok
->args
[i
], "Names"))
1166 ns
->binds_names
= 1;
1167 if (!strcmp(tok
->args
[i
], "Versions"))
1168 ns
->recommends_versions
= 1;
1172 if (ns
->recommends_versions
) {
1173 if (!(tok
= find_first_by_keyword(tokens
, K_CLIENT_VERSIONS
)) ||
1175 log_fn(LOG_WARN
, "Missing client-versions");
1177 ns
->client_versions
= tok
->args
[0];
1178 tok
->args
[0] = NULL
;
1180 if (!(tok
= find_first_by_keyword(tokens
, K_SERVER_VERSIONS
)) ||
1182 log_fn(LOG_WARN
, "Missing server-versions on versioning directory");
1185 ns
->server_versions
= tok
->args
[0];
1186 tok
->args
[0] = NULL
;
1189 if (!(tok
= find_first_by_keyword(tokens
, K_PUBLISHED
))) {
1190 log_fn(LOG_WARN
, "Missing published time on directory.");
1193 tor_assert(tok
->n_args
== 1);
1194 if (parse_iso_time(tok
->args
[0], &ns
->published_on
) < 0) {
1198 ns
->entries
= smartlist_create();
1200 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_free(t
));
1201 smartlist_clear(tokens
);
1202 while (!strcmpstart(s
, "r ")) {
1204 if ((rs
= routerstatus_parse_entry_from_string(&s
, tokens
)))
1205 smartlist_add(ns
->entries
, rs
);
1207 smartlist_sort(ns
->entries
, _compare_routerstatus_entries
);
1209 /* Kill duplicate entries. */
1210 for (i
=0; i
< smartlist_len(ns
->entries
)-1; ++i
) {
1211 routerstatus_t
*rs1
= smartlist_get(ns
->entries
, i
);
1212 routerstatus_t
*rs2
= smartlist_get(ns
->entries
, i
+1);
1213 if (!memcmp(rs1
->identity_digest
,
1214 rs2
->identity_digest
, DIGEST_LEN
)) {
1215 log_fn(LOG_WARN
, "Network-status has two entries for the same router. Dropping one.");
1216 smartlist_del_keeporder(ns
->entries
, i
--);
1217 routerstatus_free(rs1
);
1221 if (tokenize_string(s
, NULL
, tokens
, NETSTATUS
)) {
1222 log_fn(LOG_WARN
, "Error tokenizing network-status footer.");
1225 if (smartlist_len(tokens
) < 1) {
1226 log_fn(LOG_WARN
, "Too few items in network-status footer.");
1229 tok
= smartlist_get(tokens
, smartlist_len(tokens
)-1);
1230 if (tok
->tp
!= K_DIRECTORY_SIGNATURE
) {
1231 log_fn(LOG_WARN
, "Expected network-status footer to end with a signature.");
1235 if (check_directory_signature(ns_digest
, tok
, NULL
, ns
->signing_key
, 0))
1241 networkstatus_free(ns
);
1244 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_free(t
));
1245 smartlist_free(tokens
);
1250 /** Parse the exit policy in the string <b>s</b> and return it. If
1251 * assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or
1252 * ADDR_POLICY_REJECT) for items that specify no action.
1255 router_parse_addr_policy_from_string(const char *s
, int assume_action
)
1257 directory_token_t
*tok
= NULL
;
1263 /* *s might not end with \n, so we need to extend it with one. */
1265 cp
= tmp
= tor_malloc(len
+2);
1266 for (idx
= 0; idx
< len
; ++idx
) {
1267 tmp
[idx
] = tolower(s
[idx
]);
1271 while (TOR_ISSPACE(*cp
))
1273 if ((*cp
== '*' || TOR_ISDIGIT(*cp
)) && assume_action
>= 0) {
1274 char *new_str
= tor_malloc(len
+10);
1275 tor_snprintf(new_str
, len
+10, "%s %s\n",
1276 assume_action
== ADDR_POLICY_ACCEPT
?"accept":"reject", cp
);
1280 tok
= get_next_token(&cp
, RTR
);
1281 if (tok
->tp
== _ERR
) {
1282 log_fn(LOG_WARN
, "Error reading exit policy: %s", tok
->error
);
1285 if (tok
->tp
!= K_ACCEPT
&& tok
->tp
!= K_REJECT
) {
1286 log_fn(LOG_WARN
, "Expected 'accept' or 'reject'.");
1290 /* Now that we've gotten an exit policy, add it to the router. */
1291 r
= router_parse_addr_policy(tok
);
1301 /** Given an exit policicy stored in <b>s</b>, parse it and add it to the end
1302 * of the exit policy of <b>router</b>. Return 0 on success, -1 on failure.
1305 router_add_exit_policy_from_string(routerinfo_t
*router
, const char *s
)
1307 addr_policy_t
*newe
, *tmpe
;
1308 newe
= router_parse_addr_policy_from_string(s
, -1);
1311 for (tmpe
= router
->exit_policy
; tmpe
; tmpe
=tmpe
->next
)
1318 /** Add an exit policy stored in the token <b>tok</b> to the router info in
1319 * <b>router</b>. Return 0 on success, -1 on failure. */
1321 router_add_exit_policy(routerinfo_t
*router
, directory_token_t
*tok
)
1323 addr_policy_t
*newe
, **tmpe
;
1324 newe
= router_parse_addr_policy(tok
);
1327 for (tmpe
= &router
->exit_policy
; *tmpe
; tmpe
=&((*tmpe
)->next
))
1334 /** Given a K_ACCEPT or K_REJECT token and a router, create and return
1335 * a new exit_policy_t corresponding to the token. */
1336 static addr_policy_t
*
1337 router_parse_addr_policy(directory_token_t
*tok
)
1339 addr_policy_t
*newe
;
1340 // struct in_addr in;
1343 // char buf[INET_NTOA_BUF_LEN];
1345 tor_assert(tok
->tp
== K_REJECT
|| tok
->tp
== K_ACCEPT
);
1347 if (tok
->n_args
!= 1)
1351 newe
= tor_malloc_zero(sizeof(addr_policy_t
));
1353 newe
->string
= tor_malloc(8+strlen(arg
));
1354 /* XXX eventually, use the code from router.c:727 to generate this */
1355 tor_snprintf(newe
->string
, 8+strlen(arg
), "%s %s",
1356 (tok
->tp
== K_REJECT
) ? "reject" : "accept", arg
);
1357 newe
->policy_type
= (tok
->tp
== K_REJECT
) ? ADDR_POLICY_REJECT
1358 : ADDR_POLICY_ACCEPT
;
1360 if (parse_addr_and_port_range(arg
, &newe
->addr
, &newe
->msk
,
1361 &newe
->prt_min
, &newe
->prt_max
))
1362 goto policy_read_failed
;
1364 // in.s_addr = htonl(newe->addr);
1365 // tor_inet_ntoa(&in, buf, sizeof(buf));
1366 // address = tor_strdup(buf);
1367 // in.s_addr = htonl(newe->msk);
1368 // log_fn(LOG_DEBUG,"%s %s/%s:%d-%d",
1369 // newe->policy_type == ADDR_POLICY_REJECT ? "reject" : "accept",
1370 // address, inet_ntoa(in), newe->prt_min, newe->prt_max);
1371 // tor_free(address);
1376 tor_assert(newe
->string
);
1377 log_fn(LOG_WARN
,"Couldn't parse line '%s'. Dropping", newe
->string
);
1378 tor_free(newe
->string
);
1383 /** Log and exit if <b>t</b> is malformed */
1385 assert_addr_policy_ok(addr_policy_t
*t
)
1389 tor_assert(t
->policy_type
== ADDR_POLICY_REJECT
||
1390 t
->policy_type
== ADDR_POLICY_ACCEPT
);
1391 tor_assert(t
->prt_min
<= t
->prt_max
);
1392 t2
= router_parse_addr_policy_from_string(t
->string
, -1);
1394 tor_assert(t2
->policy_type
== t
->policy_type
);
1395 tor_assert(t2
->addr
== t
->addr
);
1396 tor_assert(t2
->msk
== t
->msk
);
1397 tor_assert(t2
->prt_min
== t
->prt_min
);
1398 tor_assert(t2
->prt_max
== t
->prt_max
);
1399 tor_assert(!strcmp(t2
->string
, t
->string
));
1400 tor_assert(t2
->next
== NULL
);
1401 addr_policy_free(t2
);
1409 * Low-level tokenizer for router descriptors and directories.
1412 /** Free all resources allocated for <b>tok</b> */
1414 token_free(directory_token_t
*tok
)
1419 for (i
= 0; i
< tok
->n_args
; ++i
) {
1420 tor_free(tok
->args
[i
]);
1422 tor_free(tok
->args
);
1424 tor_free(tok
->object_type
);
1425 tor_free(tok
->object_body
);
1427 crypto_free_pk_env(tok
->key
);
1431 /** Helper function: read the next token from *s, advance *s to the end
1432 * of the token, and return the parsed token. If 'where' is DIR
1433 * or RTR, reject all tokens of the wrong type.
1435 static directory_token_t
*
1436 get_next_token(const char **s
, where_syntax where
)
1438 const char *next
, *obstart
;
1439 int i
, done
, allocated
, is_opt
;
1440 directory_token_t
*tok
;
1442 obj_syntax o_syn
= NO_OBJ
;
1444 #define RET_ERR(msg) \
1445 do { if (tok) token_free(tok); \
1446 tok = tor_malloc_zero(sizeof(directory_token_t));\
1449 goto done_tokenizing; } while (0)
1451 tok
= tor_malloc_zero(sizeof(directory_token_t
));
1454 *s
= eat_whitespace(*s
);
1459 next
= find_whitespace(*s
);
1461 tok
->error
= "Unexpected EOF"; return tok
;
1463 /* It's a keyword... but which one? */
1464 is_opt
= !strncmp("opt", *s
, next
-*s
);
1466 *s
= eat_whitespace(next
);
1469 next
= find_whitespace(*s
);
1470 if (!**s
|| !next
) {
1471 RET_ERR("opt without keyword");
1474 for (i
= 0; token_table
[i
].t
; ++i
) {
1475 if (!strncmp(token_table
[i
].t
, *s
, next
-*s
)) {
1476 /* We've found the keyword. */
1477 tok
->tp
= token_table
[i
].v
;
1478 a_syn
= token_table
[i
].s
;
1479 o_syn
= token_table
[i
].os
;
1480 if (!(token_table
[i
].ws
& where
)) {
1482 RET_ERR("Found an out-of-place token in a directory section");
1483 } else if (where
== RTR
) {
1484 RET_ERR("Found an out-of-place token in a router descriptor");
1485 } else if (where
== NETSTATUS
) {
1486 RET_ERR("Found an out-of-place token in a network-status header");
1488 RET_ERR("Found an out-of-place token in a router status body");
1491 if (a_syn
== ARGS
) {
1492 /* This keyword takes multiple arguments. */
1494 done
= (*next
== '\n');
1496 tok
->args
= tor_malloc(sizeof(char*)*32);
1497 *s
= eat_whitespace_no_nl(next
);
1498 while (**s
!= '\n' && !done
) {
1499 next
= find_whitespace(*s
);
1502 if (i
== allocated
) {
1504 tok
->args
= tor_realloc(tok
->args
,sizeof(char*)*allocated
);
1506 tok
->args
[i
++] = tor_strndup(*s
,next
-*s
);
1507 *s
= eat_whitespace_no_nl(next
+1);
1510 } else if (a_syn
== CONCAT_ARGS
) {
1511 /* The keyword takes the line as a single argument */
1512 *s
= eat_whitespace_no_nl(next
);
1513 next
= strchr(*s
, '\n');
1515 RET_ERR("Unexpected EOF");
1516 tok
->args
= tor_malloc(sizeof(char*));
1517 tok
->args
[0] = tor_strndup(*s
,next
-*s
);
1519 *s
= eat_whitespace_no_nl(next
+1);
1521 /* The keyword takes no arguments. */
1522 tor_assert(a_syn
== NO_ARGS
);
1523 *s
= eat_whitespace_no_nl(next
);
1525 RET_ERR("Unexpected arguments");
1528 *s
= eat_whitespace_no_nl(*s
+1);
1533 if (tok
->tp
== _ERR
) {
1536 *s
= eat_whitespace_no_nl(next
);
1537 next
= strchr(*s
,'\n');
1539 RET_ERR("Unexpected EOF");
1540 tok
->args
= tor_malloc(sizeof(char*));
1541 tok
->args
[0] = tor_strndup(*s
,next
-*s
);
1543 *s
= eat_whitespace_no_nl(next
+1);
1546 tok
->tp
= _UNRECOGNIZED
;
1547 next
= strchr(*s
, '\n');
1549 RET_ERR("Unexpected EOF");
1551 tok
->args
= tor_malloc(sizeof(char*));
1552 tok
->args
[0] = tor_strndup(*s
,next
-*s
);
1558 *s
= eat_whitespace(*s
);
1559 if (strcmpstart(*s
, "-----BEGIN ")) {
1560 goto done_tokenizing
;
1563 *s
+= 11; /* length of "-----BEGIN ". */
1564 next
= strchr(*s
, '\n');
1565 if (next
-*s
< 6 || strcmpstart(next
-5, "-----\n")) {
1566 RET_ERR("Malformed object: bad begin line");
1568 tok
->object_type
= tor_strndup(*s
, next
-*s
-5);
1570 next
= strstr(*s
, "-----END ");
1572 RET_ERR("Malformed object: missing end line");
1574 if (!strcmp(tok
->object_type
, "RSA PUBLIC KEY")) {
1575 if (strcmpstart(next
, "-----END RSA PUBLIC KEY-----\n"))
1576 RET_ERR("Malformed object: mismatched end line");
1577 next
= strchr(next
,'\n')+1;
1578 tok
->key
= crypto_new_pk_env();
1579 if (crypto_pk_read_public_key_from_string(tok
->key
, obstart
, next
-obstart
))
1580 RET_ERR("Couldn't parse public key.");
1583 tok
->object_body
= tor_malloc(next
-*s
); /* really, this is too much RAM. */
1584 i
= base64_decode(tok
->object_body
, 256, *s
, next
-*s
);
1586 RET_ERR("Malformed object: bad base64-encoded data");
1588 tok
->object_size
= i
;
1589 *s
= next
+ 9; /* length of "-----END ". */
1590 i
= strlen(tok
->object_type
);
1591 if (strncmp(*s
, tok
->object_type
, i
) || strcmpstart(*s
+i
, "-----\n")) {
1592 RET_ERR("Malformed object: mismatched end tag");
1599 if (tok
->object_body
)
1600 RET_ERR("Unexpected object for keyword");
1602 RET_ERR("Unexpected public key for keyword");
1605 if (!tok
->object_body
)
1606 RET_ERR("Missing object for keyword");
1610 RET_ERR("Missing public key for keyword");
1622 /** Read all tokens from a string between <b>start</b> and <b>end</b>, and add
1623 * them to <b>out</b>. If <b>is_dir</b> is true, reject all non-directory
1624 * tokens; else reject all non-routerdescriptor tokens.
1627 tokenize_string(const char *start
, const char *end
, smartlist_t
*out
,
1631 directory_token_t
*tok
= NULL
;
1634 end
= start
+strlen(start
);
1635 while (*s
< end
&& (!tok
|| tok
->tp
!= _EOF
)) {
1636 tok
= get_next_token(s
, where
);
1637 if (tok
->tp
== _ERR
) {
1638 log_fn(LOG_WARN
, "parse error: %s", tok
->error
);
1641 smartlist_add(out
, tok
);
1642 *s
= eat_whitespace(*s
);
1648 /** Find the first token in <b>s</b> whose keyword is <b>keyword</b>; return
1649 * NULL if no such keyword is found.
1651 static directory_token_t
*
1652 find_first_by_keyword(smartlist_t
*s
, directory_keyword keyword
)
1654 SMARTLIST_FOREACH(s
, directory_token_t
*, t
, if (t
->tp
== keyword
) return t
);
1658 /** Return a newly allocated smartlist of all accept or reject tokens in
1661 static smartlist_t
*
1662 find_all_exitpolicy(smartlist_t
*s
)
1664 smartlist_t
*out
= smartlist_create();
1665 SMARTLIST_FOREACH(s
, directory_token_t
*, t
,
1666 if (t
->tp
== K_ACCEPT
|| t
->tp
== K_REJECT
)
1667 smartlist_add(out
,t
));
1671 /** Compute the SHA digest of the substring of <b>s</b> taken from the first
1672 * occurrence of <b>start_str</b> through the first newline after the first
1673 * subsequent occurrence of <b>end_str</b>; store the 20-byte result in
1674 * <b>digest</b>; return 0 on success.
1676 * If no such substring exists, return -1.
1679 router_get_hash_impl(const char *s
, char *digest
,
1680 const char *start_str
,
1681 const char *end_str
)
1684 start
= strstr(s
, start_str
);
1686 log_fn(LOG_WARN
,"couldn't find \"%s\"",start_str
);
1689 if (start
!= s
&& *(start
-1) != '\n') {
1690 log_fn(LOG_WARN
, "first occurrence of \"%s\" is not at the start of a line",
1694 end
= strstr(start
+strlen(start_str
), end_str
);
1696 log_fn(LOG_WARN
,"couldn't find \"%s\"",end_str
);
1699 end
= strchr(end
+strlen(end_str
), '\n');
1701 log_fn(LOG_WARN
,"couldn't find EOL");
1706 if (crypto_digest(digest
, start
, end
-start
)) {
1707 log_fn(LOG_WARN
,"couldn't compute digest");
1714 /** Parse the Tor version of the platform string <b>platform</b>,
1715 * and compare it to the version in <b>cutoff</b>. Return 1 if
1716 * the router is at least as new as the cutoff, else return 0.
1719 tor_version_as_new_as(const char *platform
, const char *cutoff
)
1721 tor_version_t cutoff_version
, router_version
;
1725 if (tor_version_parse(cutoff
, &cutoff_version
)<0) {
1726 log_fn(LOG_WARN
,"Bug: cutoff version '%s' unparseable.",cutoff
);
1729 if (strcmpstart(platform
,"Tor ")) /* nonstandard Tor; be safe and say yes */
1732 start
= (char *)eat_whitespace(platform
+3);
1733 if (!*start
) return 0;
1734 s
= (char *)find_whitespace(start
); /* also finds '\0', which is fine */
1735 if ((size_t)(s
-start
+1) >= sizeof(tmp
)) /* too big, no */
1737 strlcpy(tmp
, start
, s
-start
+1);
1739 if (tor_version_parse(tmp
, &router_version
)<0) {
1740 log_fn(LOG_INFO
,"Router version '%s' unparseable.",tmp
);
1741 return 1; /* be safe and say yes */
1744 return tor_version_compare(&router_version
, &cutoff_version
) >= 0;
1747 /** Parse a tor version from <b>s</b>, and store the result in <b>out</b>.
1748 * Return 0 on success, -1 on failure. */
1750 tor_version_parse(const char *s
, tor_version_t
*out
)
1752 char *eos
=NULL
, *cp
=NULL
;
1754 * "Tor " ? NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ -cvs ] ]
1759 memset(out
, 0, sizeof(tor_version_t
));
1761 if (!strcasecmpstart(s
, "Tor "))
1765 out
->major
= strtol(s
,&eos
,10);
1766 if (!eos
|| eos
==s
|| *eos
!= '.') return -1;
1770 out
->minor
= strtol(cp
,&eos
,10);
1771 if (!eos
|| eos
==cp
|| *eos
!= '.') return -1;
1775 out
->micro
= strtol(cp
,&eos
,10);
1776 if (!eos
|| eos
==cp
) return -1;
1778 out
->status
= VER_RELEASE
;
1779 out
->patchlevel
= 0;
1780 out
->cvs
= IS_NOT_CVS
;
1787 out
->status
= VER_RELEASE
;
1789 } else if (0==strncmp(cp
, "pre", 3)) {
1790 out
->status
= VER_PRE
;
1792 } else if (0==strncmp(cp
, "rc", 2)) {
1793 out
->status
= VER_RC
;
1799 /* Get patchlevel */
1800 out
->patchlevel
= strtol(cp
,&eos
,10);
1801 if (!eos
|| eos
==cp
) return -1;
1804 /* Get cvs status and status tag. */
1805 if (*cp
== '-' || *cp
== '.')
1807 strlcpy(out
->status_tag
, cp
, sizeof(out
->status_tag
));
1808 if (0==strcmp(cp
, "cvs")) {
1811 out
->cvs
= IS_NOT_CVS
;
1817 /** Compare two tor versions; Return <0 if a < b; 0 if a ==b, >0 if a >
1820 tor_version_compare(tor_version_t
*a
, tor_version_t
*b
)
1825 if ((i
= a
->major
- b
->major
))
1827 else if ((i
= a
->minor
- b
->minor
))
1829 else if ((i
= a
->micro
- b
->micro
))
1831 else if ((i
= a
->status
- b
->status
))
1833 else if ((i
= a
->patchlevel
- b
->patchlevel
))
1836 if (a
->major
> 0 || a
->minor
> 0) {
1837 return strcmp(a
->status_tag
, b
->status_tag
);
1839 return (a
->cvs
- b
->cvs
);
1843 /** Return true iff versions <b>a</b> and <b>b</b> belong to the same series.
1846 tor_version_same_series(tor_version_t
*a
, tor_version_t
*b
)
1850 return ((a
->major
== b
->major
) &&
1851 (a
->minor
== b
->minor
) &&
1852 (a
->micro
== b
->micro
));