1 /* Copyright (c) 2001 Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2011, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
9 * \brief Code to parse and validate router descriptors and directories.
14 #include "circuitbuild.h"
18 #include "rendcommon.h"
20 #include "routerlist.h"
22 #include "microdesc.h"
23 #include "networkstatus.h"
25 #include "routerparse.h"
29 /****************************************************************************/
31 /** Enumeration of possible token types. The ones starting with K_ correspond
32 * to directory 'keywords'. _ERR is an error in the tokenizing process, _EOF
33 * is an end-of-file marker, and _NIL is used to encode not-a-token.
38 K_DIRECTORY_SIGNATURE
,
39 K_RECOMMENDED_SOFTWARE
,
62 K_NETWORK_STATUS_VERSION
,
78 K_ALLOW_SINGLE_HOP_EXITS
,
105 K_DIR_KEY_CERTIFICATE_VERSION
,
109 K_DIR_KEY_CERTIFICATION
,
125 K_ADDITIONAL_SIGNATURE
,
135 R_RENDEZVOUS_SERVICE_DESCRIPTOR
,
141 R_INTRODUCTION_POINTS
,
159 #define MIN_ANNOTATION A_PURPOSE
160 #define MAX_ANNOTATION _A_UNKNOWN
162 /** Structure to hold a single directory token.
164 * We parse a directory by breaking it into "tokens", each consisting
165 * of a keyword, a line full of arguments, and a binary object. The
166 * arguments and object are both optional, depending on the keyword
169 * This structure is only allocated in memareas; do not allocate it on
170 * the heap, or token_clear() won't work.
172 typedef struct directory_token_t
{
173 directory_keyword tp
; /**< Type of the token. */
174 int n_args
:30; /**< Number of elements in args */
175 char **args
; /**< Array of arguments from keyword line. */
177 char *object_type
; /**< -----BEGIN [object_type]-----*/
178 size_t object_size
; /**< Bytes in object_body */
179 char *object_body
; /**< Contents of object, base64-decoded. */
181 crypto_pk_env_t
*key
; /**< For public keys only. Heap-allocated. */
183 char *error
; /**< For _ERR tokens only. */
186 /* ********************************************************************** */
188 /** We use a table of rules to decide how to parse each token type. */
190 /** Rules for whether the keyword needs an object. */
192 NO_OBJ
, /**< No object, ever. */
193 NEED_OBJ
, /**< Object is required. */
194 NEED_SKEY_1024
,/**< Object is required, and must be a 1024 bit private key */
195 NEED_KEY_1024
, /**< Object is required, and must be a 1024 bit public key */
196 NEED_KEY
, /**< Object is required, and must be a public key. */
197 OBJ_OK
, /**< Object is optional. */
203 /** Determines the parsing rules for a single token type. */
204 typedef struct token_rule_t
{
205 /** The string value of the keyword identifying the type of item. */
207 /** The corresponding directory_keyword enum. */
209 /** Minimum number of arguments for this item */
211 /** Maximum number of arguments for this item */
213 /** If true, we concatenate all arguments for this item into a single
216 /** Requirements on object syntax for this item. */
218 /** Lowest number of times this item may appear in a document. */
220 /** Highest number of times this item may appear in a document. */
222 /** One or more of AT_START/AT_END to limit where the item may appear in a
225 /** True iff this token is an annotation. */
230 * Helper macros to define token tables. 's' is a string, 't' is a
231 * directory_keyword, 'a' is a trio of argument multiplicities, and 'o' is an
236 /** Appears to indicate the end of a table. */
237 #define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
238 /** An item with no restrictions: used for obsolete document types */
239 #define T(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 }
240 /** An item with no restrictions on multiplicity or location. */
241 #define T0N(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 }
242 /** An item that must appear exactly once */
243 #define T1(s,t,a,o) { s, t, a, o, 1, 1, 0, 0 }
244 /** An item that must appear exactly once, at the start of the document */
245 #define T1_START(s,t,a,o) { s, t, a, o, 1, 1, AT_START, 0 }
246 /** An item that must appear exactly once, at the end of the document */
247 #define T1_END(s,t,a,o) { s, t, a, o, 1, 1, AT_END, 0 }
248 /** An item that must appear one or more times */
249 #define T1N(s,t,a,o) { s, t, a, o, 1, INT_MAX, 0, 0 }
250 /** An item that must appear no more than once */
251 #define T01(s,t,a,o) { s, t, a, o, 0, 1, 0, 0 }
252 /** An annotation that must appear no more than once */
253 #define A01(s,t,a,o) { s, t, a, o, 0, 1, 0, 1 }
255 /* Argument multiplicity: any number of arguments. */
256 #define ARGS 0,INT_MAX,0
257 /* Argument multiplicity: no arguments. */
258 #define NO_ARGS 0,0,0
259 /* Argument multiplicity: concatenate all arguments. */
260 #define CONCAT_ARGS 1,1,1
261 /* Argument multiplicity: at least <b>n</b> arguments. */
262 #define GE(n) n,INT_MAX,0
263 /* Argument multiplicity: exactly <b>n</b> arguments. */
266 /** List of tokens allowable in router descriptors */
267 static token_rule_t routerdesc_token_table
[] = {
268 T0N("reject", K_REJECT
, ARGS
, NO_OBJ
),
269 T0N("accept", K_ACCEPT
, ARGS
, NO_OBJ
),
270 T0N("reject6", K_REJECT6
, ARGS
, NO_OBJ
),
271 T0N("accept6", K_ACCEPT6
, ARGS
, NO_OBJ
),
272 T1_START( "router", K_ROUTER
, GE(5), NO_OBJ
),
273 T1( "signing-key", K_SIGNING_KEY
, NO_ARGS
, NEED_KEY_1024
),
274 T1( "onion-key", K_ONION_KEY
, NO_ARGS
, NEED_KEY_1024
),
275 T1_END( "router-signature", K_ROUTER_SIGNATURE
, NO_ARGS
, NEED_OBJ
),
276 T1( "published", K_PUBLISHED
, CONCAT_ARGS
, NO_OBJ
),
277 T01("uptime", K_UPTIME
, GE(1), NO_OBJ
),
278 T01("fingerprint", K_FINGERPRINT
, CONCAT_ARGS
, NO_OBJ
),
279 T01("hibernating", K_HIBERNATING
, GE(1), NO_OBJ
),
280 T01("platform", K_PLATFORM
, CONCAT_ARGS
, NO_OBJ
),
281 T01("contact", K_CONTACT
, CONCAT_ARGS
, NO_OBJ
),
282 T01("read-history", K_READ_HISTORY
, ARGS
, NO_OBJ
),
283 T01("write-history", K_WRITE_HISTORY
, ARGS
, NO_OBJ
),
284 T01("extra-info-digest", K_EXTRA_INFO_DIGEST
, GE(1), NO_OBJ
),
285 T01("hidden-service-dir", K_HIDDEN_SERVICE_DIR
, NO_ARGS
, NO_OBJ
),
286 T01("allow-single-hop-exits",K_ALLOW_SINGLE_HOP_EXITS
, NO_ARGS
, NO_OBJ
),
288 T01("family", K_FAMILY
, ARGS
, NO_OBJ
),
289 T01("caches-extra-info", K_CACHES_EXTRA_INFO
, NO_ARGS
, NO_OBJ
),
290 T01("eventdns", K_EVENTDNS
, ARGS
, NO_OBJ
),
292 T0N("opt", K_OPT
, CONCAT_ARGS
, OBJ_OK
),
293 T1( "bandwidth", K_BANDWIDTH
, GE(3), NO_OBJ
),
294 A01("@purpose", A_PURPOSE
, GE(1), NO_OBJ
),
299 /** List of tokens allowable in extra-info documents. */
300 static token_rule_t extrainfo_token_table
[] = {
301 T1_END( "router-signature", K_ROUTER_SIGNATURE
, NO_ARGS
, NEED_OBJ
),
302 T1( "published", K_PUBLISHED
, CONCAT_ARGS
, NO_OBJ
),
303 T0N("opt", K_OPT
, CONCAT_ARGS
, OBJ_OK
),
304 T01("read-history", K_READ_HISTORY
, ARGS
, NO_OBJ
),
305 T01("write-history", K_WRITE_HISTORY
, ARGS
, NO_OBJ
),
306 T01("dirreq-stats-end", K_DIRREQ_END
, ARGS
, NO_OBJ
),
307 T01("dirreq-v2-ips", K_DIRREQ_V2_IPS
, ARGS
, NO_OBJ
),
308 T01("dirreq-v3-ips", K_DIRREQ_V3_IPS
, ARGS
, NO_OBJ
),
309 T01("dirreq-v2-reqs", K_DIRREQ_V2_REQS
, ARGS
, NO_OBJ
),
310 T01("dirreq-v3-reqs", K_DIRREQ_V3_REQS
, ARGS
, NO_OBJ
),
311 T01("dirreq-v2-share", K_DIRREQ_V2_SHARE
, ARGS
, NO_OBJ
),
312 T01("dirreq-v3-share", K_DIRREQ_V3_SHARE
, ARGS
, NO_OBJ
),
313 T01("dirreq-v2-resp", K_DIRREQ_V2_RESP
, ARGS
, NO_OBJ
),
314 T01("dirreq-v3-resp", K_DIRREQ_V3_RESP
, ARGS
, NO_OBJ
),
315 T01("dirreq-v2-direct-dl", K_DIRREQ_V2_DIR
, ARGS
, NO_OBJ
),
316 T01("dirreq-v3-direct-dl", K_DIRREQ_V3_DIR
, ARGS
, NO_OBJ
),
317 T01("dirreq-v2-tunneled-dl", K_DIRREQ_V2_TUN
, ARGS
, NO_OBJ
),
318 T01("dirreq-v3-tunneled-dl", K_DIRREQ_V3_TUN
, ARGS
, NO_OBJ
),
319 T01("entry-stats-end", K_ENTRY_END
, ARGS
, NO_OBJ
),
320 T01("entry-ips", K_ENTRY_IPS
, ARGS
, NO_OBJ
),
321 T01("cell-stats-end", K_CELL_END
, ARGS
, NO_OBJ
),
322 T01("cell-processed-cells", K_CELL_PROCESSED
, ARGS
, NO_OBJ
),
323 T01("cell-queued-cells", K_CELL_QUEUED
, ARGS
, NO_OBJ
),
324 T01("cell-time-in-queue", K_CELL_TIME
, ARGS
, NO_OBJ
),
325 T01("cell-circuits-per-decile", K_CELL_CIRCS
, ARGS
, NO_OBJ
),
326 T01("exit-stats-end", K_EXIT_END
, ARGS
, NO_OBJ
),
327 T01("exit-kibibytes-written", K_EXIT_WRITTEN
, ARGS
, NO_OBJ
),
328 T01("exit-kibibytes-read", K_EXIT_READ
, ARGS
, NO_OBJ
),
329 T01("exit-streams-opened", K_EXIT_OPENED
, ARGS
, NO_OBJ
),
331 T1_START( "extra-info", K_EXTRA_INFO
, GE(2), NO_OBJ
),
336 /** List of tokens allowable in the body part of v2 and v3 networkstatus
338 static token_rule_t rtrstatus_token_table
[] = {
339 T01("p", K_P
, CONCAT_ARGS
, NO_OBJ
),
340 T1( "r", K_R
, GE(7), NO_OBJ
),
341 T1( "s", K_S
, ARGS
, NO_OBJ
),
342 T01("v", K_V
, CONCAT_ARGS
, NO_OBJ
),
343 T01("w", K_W
, ARGS
, NO_OBJ
),
344 T0N("m", K_M
, CONCAT_ARGS
, NO_OBJ
),
345 T0N("opt", K_OPT
, CONCAT_ARGS
, OBJ_OK
),
349 /** List of tokens allowable in the header part of v2 networkstatus documents.
351 static token_rule_t netstatus_token_table
[] = {
352 T1( "published", K_PUBLISHED
, CONCAT_ARGS
, NO_OBJ
),
353 T0N("opt", K_OPT
, CONCAT_ARGS
, OBJ_OK
),
354 T1( "contact", K_CONTACT
, CONCAT_ARGS
, NO_OBJ
),
355 T1( "dir-signing-key", K_DIR_SIGNING_KEY
, NO_ARGS
, NEED_KEY_1024
),
356 T1( "fingerprint", K_FINGERPRINT
, CONCAT_ARGS
, NO_OBJ
),
357 T1_START("network-status-version", K_NETWORK_STATUS_VERSION
,
359 T1( "dir-source", K_DIR_SOURCE
, GE(3), NO_OBJ
),
360 T01("dir-options", K_DIR_OPTIONS
, ARGS
, NO_OBJ
),
361 T01("client-versions", K_CLIENT_VERSIONS
, CONCAT_ARGS
, NO_OBJ
),
362 T01("server-versions", K_SERVER_VERSIONS
, CONCAT_ARGS
, NO_OBJ
),
367 /** List of tokens allowable in the footer of v1/v2 directory/networkstatus
369 static token_rule_t dir_footer_token_table
[] = {
370 T1("directory-signature", K_DIRECTORY_SIGNATURE
, EQ(1), NEED_OBJ
),
374 /** List of tokens allowable in v1 directory headers/footers. */
375 static token_rule_t dir_token_table
[] = {
376 /* don't enforce counts; this is obsolete. */
377 T( "network-status", K_NETWORK_STATUS
, NO_ARGS
, NO_OBJ
),
378 T( "directory-signature", K_DIRECTORY_SIGNATURE
, ARGS
, NEED_OBJ
),
379 T( "recommended-software",K_RECOMMENDED_SOFTWARE
,CONCAT_ARGS
, NO_OBJ
),
380 T( "signed-directory", K_SIGNED_DIRECTORY
, NO_ARGS
, NO_OBJ
),
382 T( "running-routers", K_RUNNING_ROUTERS
, ARGS
, NO_OBJ
),
383 T( "router-status", K_ROUTER_STATUS
, ARGS
, NO_OBJ
),
384 T( "published", K_PUBLISHED
, CONCAT_ARGS
, NO_OBJ
),
385 T( "opt", K_OPT
, CONCAT_ARGS
, OBJ_OK
),
386 T( "contact", K_CONTACT
, CONCAT_ARGS
, NO_OBJ
),
387 T( "dir-signing-key", K_DIR_SIGNING_KEY
, ARGS
, OBJ_OK
),
388 T( "fingerprint", K_FINGERPRINT
, CONCAT_ARGS
, NO_OBJ
),
393 /** List of tokens common to V3 authority certificates and V3 consensuses. */
394 #define CERTIFICATE_MEMBERS \
395 T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, \
397 T1("dir-identity-key", K_DIR_IDENTITY_KEY, NO_ARGS, NEED_KEY ),\
398 T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ), \
399 T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ), \
400 T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),\
401 T01("dir-key-crosscert", K_DIR_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),\
402 T1("dir-key-certification", K_DIR_KEY_CERTIFICATION, \
403 NO_ARGS, NEED_OBJ), \
404 T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ),
406 /** List of tokens allowable in V3 authority certificates. */
407 static token_rule_t dir_key_certificate_table
[] = {
409 T1("fingerprint", K_FINGERPRINT
, CONCAT_ARGS
, NO_OBJ
),
413 /** List of tokens allowable in rendezvous service descriptors */
414 static token_rule_t desc_token_table
[] = {
415 T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR
,
417 T1("version", R_VERSION
, EQ(1), NO_OBJ
),
418 T1("permanent-key", R_PERMANENT_KEY
, NO_ARGS
, NEED_KEY_1024
),
419 T1("secret-id-part", R_SECRET_ID_PART
, EQ(1), NO_OBJ
),
420 T1("publication-time", R_PUBLICATION_TIME
, CONCAT_ARGS
, NO_OBJ
),
421 T1("protocol-versions", R_PROTOCOL_VERSIONS
, EQ(1), NO_OBJ
),
422 T01("introduction-points", R_INTRODUCTION_POINTS
, NO_ARGS
, NEED_OBJ
),
423 T1_END("signature", R_SIGNATURE
, NO_ARGS
, NEED_OBJ
),
427 /** List of tokens allowed in the (encrypted) list of introduction points of
428 * rendezvous service descriptors */
429 static token_rule_t ipo_token_table
[] = {
430 T1_START("introduction-point", R_IPO_IDENTIFIER
, EQ(1), NO_OBJ
),
431 T1("ip-address", R_IPO_IP_ADDRESS
, EQ(1), NO_OBJ
),
432 T1("onion-port", R_IPO_ONION_PORT
, EQ(1), NO_OBJ
),
433 T1("onion-key", R_IPO_ONION_KEY
, NO_ARGS
, NEED_KEY_1024
),
434 T1("service-key", R_IPO_SERVICE_KEY
, NO_ARGS
, NEED_KEY_1024
),
438 /** List of tokens allowed in the (possibly encrypted) list of introduction
439 * points of rendezvous service descriptors */
440 static token_rule_t client_keys_token_table
[] = {
441 T1_START("client-name", C_CLIENT_NAME
, CONCAT_ARGS
, NO_OBJ
),
442 T1("descriptor-cookie", C_DESCRIPTOR_COOKIE
, EQ(1), NO_OBJ
),
443 T01("client-key", C_CLIENT_KEY
, NO_ARGS
, NEED_SKEY_1024
),
447 /** List of tokens allowed in V3 networkstatus votes. */
448 static token_rule_t networkstatus_token_table
[] = {
449 T1_START("network-status-version", K_NETWORK_STATUS_VERSION
,
451 T1("vote-status", K_VOTE_STATUS
, GE(1), NO_OBJ
),
452 T1("published", K_PUBLISHED
, CONCAT_ARGS
, NO_OBJ
),
453 T1("valid-after", K_VALID_AFTER
, CONCAT_ARGS
, NO_OBJ
),
454 T1("fresh-until", K_FRESH_UNTIL
, CONCAT_ARGS
, NO_OBJ
),
455 T1("valid-until", K_VALID_UNTIL
, CONCAT_ARGS
, NO_OBJ
),
456 T1("voting-delay", K_VOTING_DELAY
, GE(2), NO_OBJ
),
457 T1("known-flags", K_KNOWN_FLAGS
, ARGS
, NO_OBJ
),
458 T01("params", K_PARAMS
, ARGS
, NO_OBJ
),
459 T( "fingerprint", K_FINGERPRINT
, CONCAT_ARGS
, NO_OBJ
),
463 T0N("opt", K_OPT
, CONCAT_ARGS
, OBJ_OK
),
464 T1( "contact", K_CONTACT
, CONCAT_ARGS
, NO_OBJ
),
465 T1( "dir-source", K_DIR_SOURCE
, GE(6), NO_OBJ
),
466 T01("legacy-dir-key", K_LEGACY_DIR_KEY
, GE(1), NO_OBJ
),
467 T1( "known-flags", K_KNOWN_FLAGS
, CONCAT_ARGS
, NO_OBJ
),
468 T01("client-versions", K_CLIENT_VERSIONS
, CONCAT_ARGS
, NO_OBJ
),
469 T01("server-versions", K_SERVER_VERSIONS
, CONCAT_ARGS
, NO_OBJ
),
470 T1( "consensus-methods", K_CONSENSUS_METHODS
, GE(1), NO_OBJ
),
475 /** List of tokens allowed in V3 networkstatus consensuses. */
476 static token_rule_t networkstatus_consensus_token_table
[] = {
477 T1_START("network-status-version", K_NETWORK_STATUS_VERSION
,
479 T1("vote-status", K_VOTE_STATUS
, GE(1), NO_OBJ
),
480 T1("valid-after", K_VALID_AFTER
, CONCAT_ARGS
, NO_OBJ
),
481 T1("fresh-until", K_FRESH_UNTIL
, CONCAT_ARGS
, NO_OBJ
),
482 T1("valid-until", K_VALID_UNTIL
, CONCAT_ARGS
, NO_OBJ
),
483 T1("voting-delay", K_VOTING_DELAY
, GE(2), NO_OBJ
),
485 T0N("opt", K_OPT
, CONCAT_ARGS
, OBJ_OK
),
487 T1N("dir-source", K_DIR_SOURCE
, GE(6), NO_OBJ
),
488 T1N("contact", K_CONTACT
, CONCAT_ARGS
, NO_OBJ
),
489 T1N("vote-digest", K_VOTE_DIGEST
, GE(1), NO_OBJ
),
491 T1( "known-flags", K_KNOWN_FLAGS
, CONCAT_ARGS
, NO_OBJ
),
493 T01("client-versions", K_CLIENT_VERSIONS
, CONCAT_ARGS
, NO_OBJ
),
494 T01("server-versions", K_SERVER_VERSIONS
, CONCAT_ARGS
, NO_OBJ
),
495 T01("consensus-method", K_CONSENSUS_METHOD
, EQ(1), NO_OBJ
),
496 T01("params", K_PARAMS
, ARGS
, NO_OBJ
),
501 /** List of tokens allowable in the footer of v1/v2 directory/networkstatus
503 static token_rule_t networkstatus_vote_footer_token_table
[] = {
504 T01("directory-footer", K_DIRECTORY_FOOTER
, NO_ARGS
, NO_OBJ
),
505 T01("bandwidth-weights", K_BW_WEIGHTS
, ARGS
, NO_OBJ
),
506 T( "directory-signature", K_DIRECTORY_SIGNATURE
, GE(2), NEED_OBJ
),
510 /** List of tokens allowable in detached networkstatus signature documents. */
511 static token_rule_t networkstatus_detached_signature_token_table
[] = {
512 T1_START("consensus-digest", K_CONSENSUS_DIGEST
, GE(1), NO_OBJ
),
513 T("additional-digest", K_ADDITIONAL_DIGEST
,GE(3), NO_OBJ
),
514 T1("valid-after", K_VALID_AFTER
, CONCAT_ARGS
, NO_OBJ
),
515 T1("fresh-until", K_FRESH_UNTIL
, CONCAT_ARGS
, NO_OBJ
),
516 T1("valid-until", K_VALID_UNTIL
, CONCAT_ARGS
, NO_OBJ
),
517 T("additional-signature", K_ADDITIONAL_SIGNATURE
, GE(4), NEED_OBJ
),
518 T1N("directory-signature", K_DIRECTORY_SIGNATURE
, GE(2), NEED_OBJ
),
522 static token_rule_t microdesc_token_table
[] = {
523 T1_START("onion-key", K_ONION_KEY
, NO_ARGS
, NEED_KEY_1024
),
524 T01("family", K_FAMILY
, ARGS
, NO_OBJ
),
525 T01("p", K_P
, CONCAT_ARGS
, NO_OBJ
),
526 A01("@last-listed", A_LAST_LISTED
, CONCAT_ARGS
, NO_OBJ
),
532 /* static function prototypes */
533 static int router_add_exit_policy(routerinfo_t
*router
,directory_token_t
*tok
);
534 static addr_policy_t
*router_parse_addr_policy(directory_token_t
*tok
);
535 static addr_policy_t
*router_parse_addr_policy_private(directory_token_t
*tok
);
537 static int router_get_hash_impl(const char *s
, size_t s_len
, char *digest
,
538 const char *start_str
, const char *end_str
,
540 digest_algorithm_t alg
);
541 static int router_get_hashes_impl(const char *s
, size_t s_len
,
543 const char *start_str
, const char *end_str
,
545 static void token_clear(directory_token_t
*tok
);
546 static smartlist_t
*find_all_exitpolicy(smartlist_t
*s
);
547 static directory_token_t
*_find_by_keyword(smartlist_t
*s
,
548 directory_keyword keyword
,
549 const char *keyword_str
);
550 #define find_by_keyword(s, keyword) _find_by_keyword((s), (keyword), #keyword)
551 static directory_token_t
*find_opt_by_keyword(smartlist_t
*s
,
552 directory_keyword keyword
);
554 #define TS_ANNOTATIONS_OK 1
556 #define TS_NO_NEW_ANNOTATIONS 4
557 static int tokenize_string(memarea_t
*area
,
558 const char *start
, const char *end
,
562 static directory_token_t
*get_next_token(memarea_t
*area
,
565 token_rule_t
*table
);
566 #define CST_CHECK_AUTHORITY (1<<0)
567 #define CST_NO_CHECK_OBJTYPE (1<<1)
568 static int check_signature_token(const char *digest
,
570 directory_token_t
*tok
,
571 crypto_pk_env_t
*pkey
,
573 const char *doctype
);
574 static crypto_pk_env_t
*find_dir_signing_key(const char *str
, const char *eos
);
575 static int tor_version_same_series(tor_version_t
*a
, tor_version_t
*b
);
577 #undef DEBUG_AREA_ALLOC
579 #ifdef DEBUG_AREA_ALLOC
580 #define DUMP_AREA(a,name) STMT_BEGIN \
581 size_t alloc=0, used=0; \
582 memarea_get_stats((a),&alloc,&used); \
583 log_debug(LD_MM, "Area for %s has %lu allocated; using %lu.", \
584 name, (unsigned long)alloc, (unsigned long)used); \
587 #define DUMP_AREA(a,name) STMT_NIL
590 /** Last time we dumped a descriptor to disk. */
591 static time_t last_desc_dumped
= 0;
593 /** For debugging purposes, dump unparseable descriptor *<b>desc</b> of
594 * type *<b>type</b> to file $DATADIR/unparseable-desc. Do not write more
595 * than one descriptor to disk per minute. If there is already such a
596 * file in the data directory, overwrite it. */
598 dump_desc(const char *desc
, const char *type
)
600 time_t now
= time(NULL
);
603 if (!last_desc_dumped
|| last_desc_dumped
+ 60 < now
) {
604 char *debugfile
= get_datadir_fname("unparseable-desc");
605 size_t filelen
= 50 + strlen(type
) + strlen(desc
);
606 char *content
= tor_malloc_zero(filelen
);
607 tor_snprintf(content
, filelen
, "Unable to parse descriptor of type "
608 "%s:\n%s", type
, desc
);
609 write_str_to_file(debugfile
, content
, 0);
610 log_info(LD_DIR
, "Unable to parse descriptor of type %s. See file "
611 "unparseable-desc in data directory for details.", type
);
614 last_desc_dumped
= now
;
618 /** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
619 * <b>s</b>. Return 0 on success, -1 on failure.
622 router_get_dir_hash(const char *s
, char *digest
)
624 return router_get_hash_impl(s
, strlen(s
), digest
,
625 "signed-directory","\ndirectory-signature",'\n',
629 /** Set <b>digest</b> to the SHA-1 digest of the hash of the first router in
630 * <b>s</b>. Return 0 on success, -1 on failure.
633 router_get_router_hash(const char *s
, size_t s_len
, char *digest
)
635 return router_get_hash_impl(s
, s_len
, digest
,
636 "router ","\nrouter-signature", '\n',
640 /** Set <b>digest</b> to the SHA-1 digest of the hash of the running-routers
641 * string in <b>s</b>. Return 0 on success, -1 on failure.
644 router_get_runningrouters_hash(const char *s
, char *digest
)
646 return router_get_hash_impl(s
, strlen(s
), digest
,
647 "network-status","\ndirectory-signature", '\n',
651 /** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
652 * string in <b>s</b>. Return 0 on success, -1 on failure. */
654 router_get_networkstatus_v2_hash(const char *s
, char *digest
)
656 return router_get_hash_impl(s
, strlen(s
), digest
,
657 "network-status-version","\ndirectory-signature",
662 /** Set <b>digests</b> to all the digests of the consensus document in
665 router_get_networkstatus_v3_hashes(const char *s
, digests_t
*digests
)
667 return router_get_hashes_impl(s
,strlen(s
),digests
,
668 "network-status-version",
669 "\ndirectory-signature",
673 /** Set <b>digest</b> to the SHA-1 digest of the hash of the network-status
674 * string in <b>s</b>. Return 0 on success, -1 on failure. */
676 router_get_networkstatus_v3_hash(const char *s
, char *digest
,
677 digest_algorithm_t alg
)
679 return router_get_hash_impl(s
, strlen(s
), digest
,
680 "network-status-version",
681 "\ndirectory-signature",
685 /** Set <b>digest</b> to the SHA-1 digest of the hash of the extrainfo
686 * string in <b>s</b>. Return 0 on success, -1 on failure. */
688 router_get_extrainfo_hash(const char *s
, char *digest
)
690 return router_get_hash_impl(s
, strlen(s
), digest
, "extra-info",
691 "\nrouter-signature",'\n', DIGEST_SHA1
);
694 /** Helper: used to generate signatures for routers, directories and
695 * network-status objects. Given a digest in <b>digest</b> and a secret
696 * <b>private_key</b>, generate an PKCS1-padded signature, BASE64-encode it,
697 * surround it with -----BEGIN/END----- pairs, and write it to the
698 * <b>buf_len</b>-byte buffer at <b>buf</b>. Return 0 on success, -1 on
702 router_append_dirobj_signature(char *buf
, size_t buf_len
, const char *digest
,
703 size_t digest_len
, crypto_pk_env_t
*private_key
)
709 keysize
= crypto_pk_keysize(private_key
);
710 signature
= tor_malloc(keysize
);
711 siglen
= crypto_pk_private_sign(private_key
, signature
, keysize
,
714 log_warn(LD_BUG
,"Couldn't sign digest.");
717 if (strlcat(buf
, "-----BEGIN SIGNATURE-----\n", buf_len
) >= buf_len
)
721 if (base64_encode(buf
+i
, buf_len
-i
, signature
, siglen
) < 0) {
722 log_warn(LD_BUG
,"couldn't base64-encode signature");
726 if (strlcat(buf
, "-----END SIGNATURE-----\n", buf_len
) >= buf_len
)
733 log_warn(LD_BUG
,"tried to exceed string length.");
739 /** Return VS_RECOMMENDED if <b>myversion</b> is contained in
740 * <b>versionlist</b>. Else, return VS_EMPTY if versionlist has no
741 * entries. Else, return VS_OLD if every member of
742 * <b>versionlist</b> is newer than <b>myversion</b>. Else, return
743 * VS_NEW_IN_SERIES if there is at least one member of <b>versionlist</b> in
744 * the same series (major.minor.micro) as <b>myversion</b>, but no such member
745 * is newer than <b>myversion.</b>. Else, return VS_NEW if every member of
746 * <b>versionlist</b> is older than <b>myversion</b>. Else, return
749 * (versionlist is a comma-separated list of version strings,
750 * optionally prefixed with "Tor". Versions that can't be parsed are
754 tor_version_is_obsolete(const char *myversion
, const char *versionlist
)
756 tor_version_t mine
, other
;
757 int found_newer
= 0, found_older
= 0, found_newer_in_series
= 0,
758 found_any_in_series
= 0, r
, same
;
759 version_status_t ret
= VS_UNRECOMMENDED
;
760 smartlist_t
*version_sl
;
762 log_debug(LD_CONFIG
,"Checking whether version '%s' is in '%s'",
763 myversion
, versionlist
);
765 if (tor_version_parse(myversion
, &mine
)) {
766 log_err(LD_BUG
,"I couldn't parse my own version (%s)", myversion
);
769 version_sl
= smartlist_create();
770 smartlist_split_string(version_sl
, versionlist
, ",", SPLIT_SKIP_SPACE
, 0);
772 if (!strlen(versionlist
)) { /* no authorities cared or agreed */
777 SMARTLIST_FOREACH(version_sl
, const char *, cp
, {
778 if (!strcmpstart(cp
, "Tor "))
781 if (tor_version_parse(cp
, &other
)) {
782 /* Couldn't parse other; it can't be a match. */
784 same
= tor_version_same_series(&mine
, &other
);
786 found_any_in_series
= 1;
787 r
= tor_version_compare(&mine
, &other
);
789 ret
= VS_RECOMMENDED
;
794 found_newer_in_series
= 1;
801 /* We didn't find the listed version. Is it new or old? */
802 if (found_any_in_series
&& !found_newer_in_series
&& found_newer
) {
803 ret
= VS_NEW_IN_SERIES
;
804 } else if (found_newer
&& !found_older
) {
806 } else if (found_older
&& !found_newer
) {
809 ret
= VS_UNRECOMMENDED
;
813 SMARTLIST_FOREACH(version_sl
, char *, version
, tor_free(version
));
814 smartlist_free(version_sl
);
818 /** Read a signed directory from <b>str</b>. If it's well-formed, return 0.
819 * Otherwise, return -1. If we're a directory cache, cache it.
822 router_parse_directory(const char *str
)
824 directory_token_t
*tok
;
825 char digest
[DIGEST_LEN
];
828 const char *end
, *cp
, *str_dup
= str
;
829 smartlist_t
*tokens
= NULL
;
830 crypto_pk_env_t
*declared_key
= NULL
;
831 memarea_t
*area
= memarea_new();
833 /* XXXX This could be simplified a lot, but it will all go away
834 * once pre-0.1.1.8 is obsolete, and for now it's better not to
837 if (router_get_dir_hash(str
, digest
)) {
838 log_warn(LD_DIR
, "Unable to compute digest of directory");
841 log_debug(LD_DIR
,"Received directory hashes to %s",hex_str(digest
,4));
843 /* Check signature first, before we try to tokenize. */
845 while (cp
&& (end
= strstr(cp
+1, "\ndirectory-signature")))
847 if (cp
== str
|| !cp
) {
848 log_warn(LD_DIR
, "No signature found on directory."); goto err
;
851 tokens
= smartlist_create();
852 if (tokenize_string(area
,cp
,strchr(cp
,'\0'),tokens
,dir_token_table
,0)) {
853 log_warn(LD_DIR
, "Error tokenizing directory signature"); goto err
;
855 if (smartlist_len(tokens
) != 1) {
856 log_warn(LD_DIR
, "Unexpected number of tokens in signature"); goto err
;
858 tok
=smartlist_get(tokens
,0);
859 if (tok
->tp
!= K_DIRECTORY_SIGNATURE
) {
860 log_warn(LD_DIR
,"Expected a single directory signature"); goto err
;
862 declared_key
= find_dir_signing_key(str
, str
+strlen(str
));
863 note_crypto_pk_op(VERIFY_DIR
);
864 if (check_signature_token(digest
, DIGEST_LEN
, tok
, declared_key
,
865 CST_CHECK_AUTHORITY
, "directory")<0)
868 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
869 smartlist_clear(tokens
);
872 /* Now try to parse the first part of the directory. */
873 if ((end
= strstr(str
,"\nrouter "))) {
875 } else if ((end
= strstr(str
, "\ndirectory-signature"))) {
878 end
= str
+ strlen(str
);
881 if (tokenize_string(area
,str
,end
,tokens
,dir_token_table
,0)) {
882 log_warn(LD_DIR
, "Error tokenizing directory"); goto err
;
885 tok
= find_by_keyword(tokens
, K_PUBLISHED
);
886 tor_assert(tok
->n_args
== 1);
888 if (parse_iso_time(tok
->args
[0], &published_on
) < 0) {
892 /* Now that we know the signature is okay, and we have a
893 * publication time, cache the directory. */
894 if (directory_caches_v1_dir_info(get_options()) &&
895 !authdir_mode_v1(get_options()))
896 dirserv_set_cached_directory(str
, published_on
, 0);
901 dump_desc(str_dup
, "v1 directory");
904 if (declared_key
) crypto_free_pk_env(declared_key
);
906 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
907 smartlist_free(tokens
);
910 DUMP_AREA(area
, "v1 directory");
911 memarea_drop_all(area
);
916 /** Read a signed router status statement from <b>str</b>. If it's
917 * well-formed, return 0. Otherwise, return -1. If we're a directory cache,
920 router_parse_runningrouters(const char *str
)
922 char digest
[DIGEST_LEN
];
923 directory_token_t
*tok
;
926 crypto_pk_env_t
*declared_key
= NULL
;
927 smartlist_t
*tokens
= NULL
;
928 const char *eos
= str
+ strlen(str
), *str_dup
= str
;
929 memarea_t
*area
= NULL
;
931 if (router_get_runningrouters_hash(str
, digest
)) {
932 log_warn(LD_DIR
, "Unable to compute digest of running-routers");
935 area
= memarea_new();
936 tokens
= smartlist_create();
937 if (tokenize_string(area
,str
,eos
,tokens
,dir_token_table
,0)) {
938 log_warn(LD_DIR
, "Error tokenizing running-routers"); goto err
;
940 tok
= smartlist_get(tokens
,0);
941 if (tok
->tp
!= K_NETWORK_STATUS
) {
942 log_warn(LD_DIR
, "Network-status starts with wrong token");
946 tok
= find_by_keyword(tokens
, K_PUBLISHED
);
947 tor_assert(tok
->n_args
== 1);
948 if (parse_iso_time(tok
->args
[0], &published_on
) < 0) {
951 if (!(tok
= find_opt_by_keyword(tokens
, K_DIRECTORY_SIGNATURE
))) {
952 log_warn(LD_DIR
, "Missing signature on running-routers");
955 declared_key
= find_dir_signing_key(str
, eos
);
956 note_crypto_pk_op(VERIFY_DIR
);
957 if (check_signature_token(digest
, DIGEST_LEN
, tok
, declared_key
,
958 CST_CHECK_AUTHORITY
, "running-routers")
962 /* Now that we know the signature is okay, and we have a
963 * publication time, cache the list. */
964 if (get_options()->DirPort
&& !authdir_mode_v1(get_options()))
965 dirserv_set_cached_directory(str
, published_on
, 1);
969 dump_desc(str_dup
, "v1 running-routers");
970 if (declared_key
) crypto_free_pk_env(declared_key
);
972 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
973 smartlist_free(tokens
);
976 DUMP_AREA(area
, "v1 running-routers");
977 memarea_drop_all(area
);
982 /** Given a directory or running-routers string in <b>str</b>, try to
983 * find the its dir-signing-key token (if any). If this token is
984 * present, extract and return the key. Return NULL on failure. */
985 static crypto_pk_env_t
*
986 find_dir_signing_key(const char *str
, const char *eos
)
989 directory_token_t
*tok
;
990 crypto_pk_env_t
*key
= NULL
;
991 memarea_t
*area
= NULL
;
995 /* Is there a dir-signing-key in the directory? */
996 cp
= tor_memstr(str
, eos
-str
, "\nopt dir-signing-key");
998 cp
= tor_memstr(str
, eos
-str
, "\ndir-signing-key");
1001 ++cp
; /* Now cp points to the start of the token. */
1003 area
= memarea_new();
1004 tok
= get_next_token(area
, &cp
, eos
, dir_token_table
);
1006 log_warn(LD_DIR
, "Unparseable dir-signing-key token");
1009 if (tok
->tp
!= K_DIR_SIGNING_KEY
) {
1010 log_warn(LD_DIR
, "Dir-signing-key token did not parse as expected");
1016 tok
->key
= NULL
; /* steal reference. */
1018 log_warn(LD_DIR
, "Dir-signing-key token contained no key");
1022 if (tok
) token_clear(tok
);
1024 DUMP_AREA(area
, "dir-signing-key token");
1025 memarea_drop_all(area
);
1030 /** Return true iff <b>key</b> is allowed to sign directories.
1033 dir_signing_key_is_trusted(crypto_pk_env_t
*key
)
1035 char digest
[DIGEST_LEN
];
1037 if (crypto_pk_get_digest(key
, digest
) < 0) {
1038 log_warn(LD_DIR
, "Error computing dir-signing-key digest");
1041 if (!router_digest_is_trusted_dir(digest
)) {
1042 log_warn(LD_DIR
, "Listed dir-signing-key is not trusted");
1048 /** Check whether the object body of the token in <b>tok</b> has a good
1049 * signature for <b>digest</b> using key <b>pkey</b>. If
1050 * <b>CST_CHECK_AUTHORITY</b> is set, make sure that <b>pkey</b> is the key of
1051 * a directory authority. If <b>CST_NO_CHECK_OBJTYPE</b> is set, do not check
1052 * the object type of the signature object. Use <b>doctype</b> as the type of
1053 * the document when generating log messages. Return 0 on success, negative
1057 check_signature_token(const char *digest
,
1059 directory_token_t
*tok
,
1060 crypto_pk_env_t
*pkey
,
1062 const char *doctype
)
1064 char *signed_digest
;
1066 const int check_authority
= (flags
& CST_CHECK_AUTHORITY
);
1067 const int check_objtype
= ! (flags
& CST_NO_CHECK_OBJTYPE
);
1072 tor_assert(doctype
);
1074 if (check_authority
&& !dir_signing_key_is_trusted(pkey
)) {
1075 log_warn(LD_DIR
, "Key on %s did not come from an authority; rejecting",
1080 if (check_objtype
) {
1081 if (strcmp(tok
->object_type
, "SIGNATURE")) {
1082 log_warn(LD_DIR
, "Bad object type on %s signature", doctype
);
1087 keysize
= crypto_pk_keysize(pkey
);
1088 signed_digest
= tor_malloc(keysize
);
1089 if (crypto_pk_public_checksig(pkey
, signed_digest
, keysize
,
1090 tok
->object_body
, tok
->object_size
)
1092 log_warn(LD_DIR
, "Error reading %s: invalid signature.", doctype
);
1093 tor_free(signed_digest
);
1096 // log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
1097 // hex_str(signed_digest,4));
1098 if (memcmp(digest
, signed_digest
, digest_len
)) {
1099 log_warn(LD_DIR
, "Error reading %s: signature does not match.", doctype
);
1100 tor_free(signed_digest
);
1103 tor_free(signed_digest
);
1107 /** Helper: move *<b>s_ptr</b> ahead to the next router, the next extra-info,
1108 * or to the first of the annotations proceeding the next router or
1109 * extra-info---whichever comes first. Set <b>is_extrainfo_out</b> to true if
1110 * we found an extrainfo, or false if found a router. Do not scan beyond
1111 * <b>eos</b>. Return -1 if we found nothing; 0 if we found something. */
1113 find_start_of_next_router_or_extrainfo(const char **s_ptr
,
1115 int *is_extrainfo_out
)
1117 const char *annotations
= NULL
;
1118 const char *s
= *s_ptr
;
1120 s
= eat_whitespace_eos(s
, eos
);
1122 while (s
< eos
-32) { /* 32 gives enough room for a the first keyword. */
1123 /* We're at the start of a line. */
1124 tor_assert(*s
!= '\n');
1126 if (*s
== '@' && !annotations
) {
1128 } else if (*s
== 'r' && !strcmpstart(s
, "router ")) {
1129 *s_ptr
= annotations
? annotations
: s
;
1130 *is_extrainfo_out
= 0;
1132 } else if (*s
== 'e' && !strcmpstart(s
, "extra-info ")) {
1133 *s_ptr
= annotations
? annotations
: s
;
1134 *is_extrainfo_out
= 1;
1138 if (!(s
= memchr(s
+1, '\n', eos
-(s
+1))))
1140 s
= eat_whitespace_eos(s
, eos
);
1145 /** Given a string *<b>s</b> containing a concatenated sequence of router
1146 * descriptors (or extra-info documents if <b>is_extrainfo</b> is set), parses
1147 * them and stores the result in <b>dest</b>. All routers are marked running
1148 * and valid. Advances *s to a point immediately following the last router
1149 * entry. Ignore any trailing router entries that are not complete.
1151 * If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each
1152 * descriptor in the signed_descriptor_body field of each routerinfo_t. If it
1153 * isn't SAVED_NOWHERE, remember the offset of each descriptor.
1155 * Returns 0 on success and -1 on failure.
1158 router_parse_list_from_string(const char **s
, const char *eos
,
1160 saved_location_t saved_location
,
1162 int allow_annotations
,
1163 const char *prepend_annotations
)
1165 routerinfo_t
*router
;
1166 extrainfo_t
*extrainfo
;
1167 signed_descriptor_t
*signed_desc
;
1169 const char *end
, *start
;
1178 eos
= *s
+ strlen(*s
);
1180 tor_assert(eos
>= *s
);
1183 if (find_start_of_next_router_or_extrainfo(s
, eos
, &have_extrainfo
) < 0)
1186 end
= tor_memstr(*s
, eos
-*s
, "\nrouter-signature");
1188 end
= tor_memstr(end
, eos
-end
, "\n-----END SIGNATURE-----\n");
1190 end
+= strlen("\n-----END SIGNATURE-----\n");
1197 if (have_extrainfo
&& want_extrainfo
) {
1198 routerlist_t
*rl
= router_get_routerlist();
1199 extrainfo
= extrainfo_parse_entry_from_string(*s
, end
,
1200 saved_location
!= SAVED_IN_CACHE
,
1203 signed_desc
= &extrainfo
->cache_info
;
1206 } else if (!have_extrainfo
&& !want_extrainfo
) {
1207 router
= router_parse_entry_from_string(*s
, end
,
1208 saved_location
!= SAVED_IN_CACHE
,
1210 prepend_annotations
);
1212 log_debug(LD_DIR
, "Read router '%s', purpose '%s'",
1213 router
->nickname
, router_purpose_to_string(router
->purpose
));
1214 signed_desc
= &router
->cache_info
;
1222 if (saved_location
!= SAVED_NOWHERE
) {
1223 signed_desc
->saved_location
= saved_location
;
1224 signed_desc
->saved_offset
= *s
- start
;
1227 smartlist_add(dest
, elt
);
1233 /* For debugging: define to count every descriptor digest we've seen so we
1234 * know if we need to try harder to avoid duplicate verifies. */
1235 #undef COUNT_DISTINCT_DIGESTS
1237 #ifdef COUNT_DISTINCT_DIGESTS
1238 static digestmap_t
*verified_digests
= NULL
;
1241 /** Log the total count of the number of distinct router digests we've ever
1242 * verified. When compared to the number of times we've verified routerdesc
1243 * signatures <i>in toto</i>, this will tell us if we're doing too much
1244 * multiple-verification. */
1246 dump_distinct_digest_count(int severity
)
1248 #ifdef COUNT_DISTINCT_DIGESTS
1249 if (!verified_digests
)
1250 verified_digests
= digestmap_new();
1251 log(severity
, LD_GENERAL
, "%d *distinct* router digests verified",
1252 digestmap_size(verified_digests
));
1254 (void)severity
; /* suppress "unused parameter" warning */
1258 /** Helper function: reads a single router entry from *<b>s</b> ...
1259 * *<b>end</b>. Mallocs a new router and returns it if all goes well, else
1260 * returns NULL. If <b>cache_copy</b> is true, duplicate the contents of
1261 * s through end into the signed_descriptor_body of the resulting
1264 * If <b>end</b> is NULL, <b>s</b> must be properly NULL-terminated.
1266 * If <b>allow_annotations</b>, it's okay to encounter annotations in <b>s</b>
1267 * before the router; if it's false, reject the router if it's annotated. If
1268 * <b>prepend_annotations</b> is set, it should contain some annotations:
1269 * append them to the front of the router before parsing it, and keep them
1270 * around when caching the router.
1272 * Only one of allow_annotations and prepend_annotations may be set.
1275 router_parse_entry_from_string(const char *s
, const char *end
,
1276 int cache_copy
, int allow_annotations
,
1277 const char *prepend_annotations
)
1279 routerinfo_t
*router
= NULL
;
1281 smartlist_t
*tokens
= NULL
, *exit_policy_tokens
= NULL
;
1282 directory_token_t
*tok
;
1284 const char *start_of_annotations
, *cp
, *s_dup
= s
;
1285 size_t prepend_len
= prepend_annotations
? strlen(prepend_annotations
) : 0;
1287 memarea_t
*area
= NULL
;
1289 tor_assert(!allow_annotations
|| !prepend_annotations
);
1292 end
= s
+ strlen(s
);
1295 /* point 'end' to a point immediately after the final newline. */
1296 while (end
> s
+2 && *(end
-1) == '\n' && *(end
-2) == '\n')
1299 area
= memarea_new();
1300 tokens
= smartlist_create();
1301 if (prepend_annotations
) {
1302 if (tokenize_string(area
,prepend_annotations
,NULL
,tokens
,
1303 routerdesc_token_table
,TS_NOCHECK
)) {
1304 log_warn(LD_DIR
, "Error tokenizing router descriptor (annotations).");
1309 start_of_annotations
= s
;
1310 cp
= tor_memstr(s
, end
-s
, "\nrouter ");
1312 if (end
-s
< 7 || strcmpstart(s
, "router ")) {
1313 log_warn(LD_DIR
, "No router keyword found.");
1320 if (start_of_annotations
!= s
) { /* We have annotations */
1321 if (allow_annotations
) {
1322 if (tokenize_string(area
,start_of_annotations
,s
,tokens
,
1323 routerdesc_token_table
,TS_NOCHECK
)) {
1324 log_warn(LD_DIR
, "Error tokenizing router descriptor (annotations).");
1328 log_warn(LD_DIR
, "Found unexpected annotations on router descriptor not "
1329 "loaded from disk. Dropping it.");
1334 if (router_get_router_hash(s
, end
- s
, digest
) < 0) {
1335 log_warn(LD_DIR
, "Couldn't compute router hash.");
1340 if (allow_annotations
)
1341 flags
|= TS_ANNOTATIONS_OK
;
1342 if (prepend_annotations
)
1343 flags
|= TS_ANNOTATIONS_OK
|TS_NO_NEW_ANNOTATIONS
;
1345 if (tokenize_string(area
,s
,end
,tokens
,routerdesc_token_table
, flags
)) {
1346 log_warn(LD_DIR
, "Error tokenizing router descriptor.");
1351 if (smartlist_len(tokens
) < 2) {
1352 log_warn(LD_DIR
, "Impossibly short router descriptor.");
1356 tok
= find_by_keyword(tokens
, K_ROUTER
);
1357 tor_assert(tok
->n_args
>= 5);
1359 router
= tor_malloc_zero(sizeof(routerinfo_t
));
1360 router
->country
= -1;
1361 router
->cache_info
.routerlist_index
= -1;
1362 router
->cache_info
.annotations_len
= s
-start_of_annotations
+ prepend_len
;
1363 router
->cache_info
.signed_descriptor_len
= end
-s
;
1365 size_t len
= router
->cache_info
.signed_descriptor_len
+
1366 router
->cache_info
.annotations_len
;
1368 router
->cache_info
.signed_descriptor_body
= tor_malloc(len
+1);
1369 if (prepend_annotations
) {
1370 memcpy(cp
, prepend_annotations
, prepend_len
);
1373 /* This assertion will always succeed.
1374 * len == signed_desc_len + annotations_len
1375 * == end-s + s-start_of_annotations + prepend_len
1376 * == end-start_of_annotations + prepend_len
1377 * We already wrote prepend_len bytes into the buffer; now we're
1378 * writing end-start_of_annotations -NM. */
1379 tor_assert(cp
+(end
-start_of_annotations
) ==
1380 router
->cache_info
.signed_descriptor_body
+len
);
1381 memcpy(cp
, start_of_annotations
, end
-start_of_annotations
);
1382 router
->cache_info
.signed_descriptor_body
[len
] = '\0';
1383 tor_assert(strlen(router
->cache_info
.signed_descriptor_body
) == len
);
1385 memcpy(router
->cache_info
.signed_descriptor_digest
, digest
, DIGEST_LEN
);
1387 router
->nickname
= tor_strdup(tok
->args
[0]);
1388 if (!is_legal_nickname(router
->nickname
)) {
1389 log_warn(LD_DIR
,"Router nickname is invalid");
1392 router
->address
= tor_strdup(tok
->args
[1]);
1393 if (!tor_inet_aton(router
->address
, &in
)) {
1394 log_warn(LD_DIR
,"Router address is not an IP address.");
1397 router
->addr
= ntohl(in
.s_addr
);
1400 (uint16_t) tor_parse_long(tok
->args
[2],10,0,65535,&ok
,NULL
);
1402 log_warn(LD_DIR
,"Invalid OR port %s", escaped(tok
->args
[2]));
1406 (uint16_t) tor_parse_long(tok
->args
[4],10,0,65535,&ok
,NULL
);
1408 log_warn(LD_DIR
,"Invalid dir port %s", escaped(tok
->args
[4]));
1412 tok
= find_by_keyword(tokens
, K_BANDWIDTH
);
1413 tor_assert(tok
->n_args
>= 3);
1414 router
->bandwidthrate
= (int)
1415 tor_parse_long(tok
->args
[0],10,1,INT_MAX
,&ok
,NULL
);
1418 log_warn(LD_DIR
, "bandwidthrate %s unreadable or 0. Failing.",
1419 escaped(tok
->args
[0]));
1422 router
->bandwidthburst
=
1423 (int) tor_parse_long(tok
->args
[1],10,0,INT_MAX
,&ok
,NULL
);
1425 log_warn(LD_DIR
, "Invalid bandwidthburst %s", escaped(tok
->args
[1]));
1428 router
->bandwidthcapacity
= (int)
1429 tor_parse_long(tok
->args
[2],10,0,INT_MAX
,&ok
,NULL
);
1431 log_warn(LD_DIR
, "Invalid bandwidthcapacity %s", escaped(tok
->args
[1]));
1435 if ((tok
= find_opt_by_keyword(tokens
, A_PURPOSE
))) {
1436 tor_assert(tok
->n_args
);
1437 router
->purpose
= router_purpose_from_string(tok
->args
[0]);
1439 router
->purpose
= ROUTER_PURPOSE_GENERAL
;
1441 router
->cache_info
.send_unencrypted
=
1442 (router
->purpose
== ROUTER_PURPOSE_GENERAL
) ? 1 : 0;
1444 if ((tok
= find_opt_by_keyword(tokens
, K_UPTIME
))) {
1445 tor_assert(tok
->n_args
>= 1);
1446 router
->uptime
= tor_parse_long(tok
->args
[0],10,0,LONG_MAX
,&ok
,NULL
);
1448 log_warn(LD_DIR
, "Invalid uptime %s", escaped(tok
->args
[0]));
1453 if ((tok
= find_opt_by_keyword(tokens
, K_HIBERNATING
))) {
1454 tor_assert(tok
->n_args
>= 1);
1455 router
->is_hibernating
1456 = (tor_parse_long(tok
->args
[0],10,0,LONG_MAX
,NULL
,NULL
) != 0);
1459 tok
= find_by_keyword(tokens
, K_PUBLISHED
);
1460 tor_assert(tok
->n_args
== 1);
1461 if (parse_iso_time(tok
->args
[0], &router
->cache_info
.published_on
) < 0)
1464 tok
= find_by_keyword(tokens
, K_ONION_KEY
);
1465 router
->onion_pkey
= tok
->key
;
1466 tok
->key
= NULL
; /* Prevent free */
1468 tok
= find_by_keyword(tokens
, K_SIGNING_KEY
);
1469 router
->identity_pkey
= tok
->key
;
1470 tok
->key
= NULL
; /* Prevent free */
1471 if (crypto_pk_get_digest(router
->identity_pkey
,
1472 router
->cache_info
.identity_digest
)) {
1473 log_warn(LD_DIR
, "Couldn't calculate key digest"); goto err
;
1476 if ((tok
= find_opt_by_keyword(tokens
, K_FINGERPRINT
))) {
1477 /* If there's a fingerprint line, it must match the identity digest. */
1479 tor_assert(tok
->n_args
== 1);
1480 tor_strstrip(tok
->args
[0], " ");
1481 if (base16_decode(d
, DIGEST_LEN
, tok
->args
[0], strlen(tok
->args
[0]))) {
1482 log_warn(LD_DIR
, "Couldn't decode router fingerprint %s",
1483 escaped(tok
->args
[0]));
1486 if (memcmp(d
,router
->cache_info
.identity_digest
, DIGEST_LEN
)!=0) {
1487 log_warn(LD_DIR
, "Fingerprint '%s' does not match identity digest.",
1493 if ((tok
= find_opt_by_keyword(tokens
, K_PLATFORM
))) {
1494 router
->platform
= tor_strdup(tok
->args
[0]);
1497 if ((tok
= find_opt_by_keyword(tokens
, K_CONTACT
))) {
1498 router
->contact_info
= tor_strdup(tok
->args
[0]);
1501 if ((tok
= find_opt_by_keyword(tokens
, K_EVENTDNS
))) {
1502 router
->has_old_dnsworkers
= tok
->n_args
&& !strcmp(tok
->args
[0], "0");
1503 } else if (router
->platform
) {
1504 if (! tor_version_as_new_as(router
->platform
, "0.1.2.2-alpha"))
1505 router
->has_old_dnsworkers
= 1;
1508 if (find_opt_by_keyword(tokens
, K_REJECT6
) ||
1509 find_opt_by_keyword(tokens
, K_ACCEPT6
)) {
1510 log_warn(LD_DIR
, "Rejecting router with reject6/accept6 line: they crash "
1514 exit_policy_tokens
= find_all_exitpolicy(tokens
);
1515 if (!smartlist_len(exit_policy_tokens
)) {
1516 log_warn(LD_DIR
, "No exit policy tokens in descriptor.");
1519 SMARTLIST_FOREACH(exit_policy_tokens
, directory_token_t
*, t
,
1520 if (router_add_exit_policy(router
,t
)<0) {
1521 log_warn(LD_DIR
,"Error in exit policy");
1524 policy_expand_private(&router
->exit_policy
);
1525 if (policy_is_reject_star(router
->exit_policy
))
1526 router
->policy_is_reject_star
= 1;
1528 if ((tok
= find_opt_by_keyword(tokens
, K_FAMILY
)) && tok
->n_args
) {
1530 router
->declared_family
= smartlist_create();
1531 for (i
=0;i
<tok
->n_args
;++i
) {
1532 if (!is_legal_nickname_or_hexdigest(tok
->args
[i
])) {
1533 log_warn(LD_DIR
, "Illegal nickname %s in family line",
1534 escaped(tok
->args
[i
]));
1537 smartlist_add(router
->declared_family
, tor_strdup(tok
->args
[i
]));
1541 if ((tok
= find_opt_by_keyword(tokens
, K_CACHES_EXTRA_INFO
)))
1542 router
->caches_extra_info
= 1;
1544 if ((tok
= find_opt_by_keyword(tokens
, K_ALLOW_SINGLE_HOP_EXITS
)))
1545 router
->allow_single_hop_exits
= 1;
1547 if ((tok
= find_opt_by_keyword(tokens
, K_EXTRA_INFO_DIGEST
))) {
1548 tor_assert(tok
->n_args
>= 1);
1549 if (strlen(tok
->args
[0]) == HEX_DIGEST_LEN
) {
1550 base16_decode(router
->cache_info
.extra_info_digest
,
1551 DIGEST_LEN
, tok
->args
[0], HEX_DIGEST_LEN
);
1553 log_warn(LD_DIR
, "Invalid extra info digest %s", escaped(tok
->args
[0]));
1557 if ((tok
= find_opt_by_keyword(tokens
, K_HIDDEN_SERVICE_DIR
))) {
1558 router
->wants_to_be_hs_dir
= 1;
1561 tok
= find_by_keyword(tokens
, K_ROUTER_SIGNATURE
);
1562 note_crypto_pk_op(VERIFY_RTR
);
1563 #ifdef COUNT_DISTINCT_DIGESTS
1564 if (!verified_digests
)
1565 verified_digests
= digestmap_new();
1566 digestmap_set(verified_digests
, signed_digest
, (void*)(uintptr_t)1);
1568 if (check_signature_token(digest
, DIGEST_LEN
, tok
, router
->identity_pkey
, 0,
1569 "router descriptor") < 0)
1572 routerinfo_set_country(router
);
1574 if (!router
->or_port
) {
1575 log_warn(LD_DIR
,"or_port unreadable or 0. Failing.");
1579 if (!router
->platform
) {
1580 router
->platform
= tor_strdup("<unknown>");
1586 dump_desc(s_dup
, "router descriptor");
1587 routerinfo_free(router
);
1591 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
1592 smartlist_free(tokens
);
1594 smartlist_free(exit_policy_tokens
);
1596 DUMP_AREA(area
, "routerinfo");
1597 memarea_drop_all(area
);
1602 /** Parse a single extrainfo entry from the string <b>s</b>, ending at
1603 * <b>end</b>. (If <b>end</b> is NULL, parse up to the end of <b>s</b>.) If
1604 * <b>cache_copy</b> is true, make a copy of the extra-info document in the
1605 * cache_info fields of the result. If <b>routermap</b> is provided, use it
1606 * as a map from router identity to routerinfo_t when looking up signing keys.
1609 extrainfo_parse_entry_from_string(const char *s
, const char *end
,
1610 int cache_copy
, struct digest_ri_map_t
*routermap
)
1612 extrainfo_t
*extrainfo
= NULL
;
1614 smartlist_t
*tokens
= NULL
;
1615 directory_token_t
*tok
;
1616 crypto_pk_env_t
*key
= NULL
;
1617 routerinfo_t
*router
= NULL
;
1618 memarea_t
*area
= NULL
;
1619 const char *s_dup
= s
;
1622 end
= s
+ strlen(s
);
1625 /* point 'end' to a point immediately after the final newline. */
1626 while (end
> s
+2 && *(end
-1) == '\n' && *(end
-2) == '\n')
1629 if (router_get_extrainfo_hash(s
, digest
) < 0) {
1630 log_warn(LD_DIR
, "Couldn't compute router hash.");
1633 tokens
= smartlist_create();
1634 area
= memarea_new();
1635 if (tokenize_string(area
,s
,end
,tokens
,extrainfo_token_table
,0)) {
1636 log_warn(LD_DIR
, "Error tokenizing extra-info document.");
1640 if (smartlist_len(tokens
) < 2) {
1641 log_warn(LD_DIR
, "Impossibly short extra-info document.");
1645 tok
= smartlist_get(tokens
,0);
1646 if (tok
->tp
!= K_EXTRA_INFO
) {
1647 log_warn(LD_DIR
,"Entry does not start with \"extra-info\"");
1651 extrainfo
= tor_malloc_zero(sizeof(extrainfo_t
));
1652 extrainfo
->cache_info
.is_extrainfo
= 1;
1654 extrainfo
->cache_info
.signed_descriptor_body
= tor_strndup(s
, end
-s
);
1655 extrainfo
->cache_info
.signed_descriptor_len
= end
-s
;
1656 memcpy(extrainfo
->cache_info
.signed_descriptor_digest
, digest
, DIGEST_LEN
);
1658 tor_assert(tok
->n_args
>= 2);
1659 if (!is_legal_nickname(tok
->args
[0])) {
1660 log_warn(LD_DIR
,"Bad nickname %s on \"extra-info\"",escaped(tok
->args
[0]));
1663 strlcpy(extrainfo
->nickname
, tok
->args
[0], sizeof(extrainfo
->nickname
));
1664 if (strlen(tok
->args
[1]) != HEX_DIGEST_LEN
||
1665 base16_decode(extrainfo
->cache_info
.identity_digest
, DIGEST_LEN
,
1666 tok
->args
[1], HEX_DIGEST_LEN
)) {
1667 log_warn(LD_DIR
,"Invalid fingerprint %s on \"extra-info\"",
1668 escaped(tok
->args
[1]));
1672 tok
= find_by_keyword(tokens
, K_PUBLISHED
);
1673 if (parse_iso_time(tok
->args
[0], &extrainfo
->cache_info
.published_on
)) {
1674 log_warn(LD_DIR
,"Invalid published time %s on \"extra-info\"",
1675 escaped(tok
->args
[0]));
1680 (router
= digestmap_get((digestmap_t
*)routermap
,
1681 extrainfo
->cache_info
.identity_digest
))) {
1682 key
= router
->identity_pkey
;
1685 tok
= find_by_keyword(tokens
, K_ROUTER_SIGNATURE
);
1686 if (strcmp(tok
->object_type
, "SIGNATURE") ||
1687 tok
->object_size
< 128 || tok
->object_size
> 512) {
1688 log_warn(LD_DIR
, "Bad object type or length on extra-info signature");
1693 note_crypto_pk_op(VERIFY_RTR
);
1694 if (check_signature_token(digest
, DIGEST_LEN
, tok
, key
, 0,
1699 extrainfo
->cache_info
.send_unencrypted
=
1700 router
->cache_info
.send_unencrypted
;
1702 extrainfo
->pending_sig
= tor_memdup(tok
->object_body
,
1704 extrainfo
->pending_sig_len
= tok
->object_size
;
1709 dump_desc(s_dup
, "extra-info descriptor");
1710 extrainfo_free(extrainfo
);
1714 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
1715 smartlist_free(tokens
);
1718 DUMP_AREA(area
, "extrainfo");
1719 memarea_drop_all(area
);
1724 /** Parse a key certificate from <b>s</b>; point <b>end-of-string</b> to
1725 * the first character after the certificate. */
1727 authority_cert_parse_from_string(const char *s
, const char **end_of_string
)
1729 /** Reject any certificate at least this big; it is probably an overflow, an
1730 * attack, a bug, or some other nonsense. */
1731 #define MAX_CERT_SIZE (128*1024)
1733 authority_cert_t
*cert
= NULL
, *old_cert
;
1734 smartlist_t
*tokens
= NULL
;
1735 char digest
[DIGEST_LEN
];
1736 directory_token_t
*tok
;
1737 char fp_declared
[DIGEST_LEN
];
1741 memarea_t
*area
= NULL
;
1742 const char *s_dup
= s
;
1744 s
= eat_whitespace(s
);
1745 eos
= strstr(s
, "\ndir-key-certification");
1747 log_warn(LD_DIR
, "No signature found on key certificate");
1750 eos
= strstr(eos
, "\n-----END SIGNATURE-----\n");
1752 log_warn(LD_DIR
, "No end-of-signature found on key certificate");
1755 eos
= strchr(eos
+2, '\n');
1760 if (len
> MAX_CERT_SIZE
) {
1761 log_warn(LD_DIR
, "Certificate is far too big (at %lu bytes long); "
1762 "rejecting", (unsigned long)len
);
1766 tokens
= smartlist_create();
1767 area
= memarea_new();
1768 if (tokenize_string(area
,s
, eos
, tokens
, dir_key_certificate_table
, 0) < 0) {
1769 log_warn(LD_DIR
, "Error tokenizing key certificate");
1772 if (router_get_hash_impl(s
, strlen(s
), digest
, "dir-key-certificate-version",
1773 "\ndir-key-certification", '\n', DIGEST_SHA1
) < 0)
1775 tok
= smartlist_get(tokens
, 0);
1776 if (tok
->tp
!= K_DIR_KEY_CERTIFICATE_VERSION
|| strcmp(tok
->args
[0], "3")) {
1778 "Key certificate does not begin with a recognized version (3).");
1782 cert
= tor_malloc_zero(sizeof(authority_cert_t
));
1783 memcpy(cert
->cache_info
.signed_descriptor_digest
, digest
, DIGEST_LEN
);
1785 tok
= find_by_keyword(tokens
, K_DIR_SIGNING_KEY
);
1786 tor_assert(tok
->key
);
1787 cert
->signing_key
= tok
->key
;
1789 if (crypto_pk_get_digest(cert
->signing_key
, cert
->signing_key_digest
))
1792 tok
= find_by_keyword(tokens
, K_DIR_IDENTITY_KEY
);
1793 tor_assert(tok
->key
);
1794 cert
->identity_key
= tok
->key
;
1797 tok
= find_by_keyword(tokens
, K_FINGERPRINT
);
1798 tor_assert(tok
->n_args
);
1799 if (base16_decode(fp_declared
, DIGEST_LEN
, tok
->args
[0],
1800 strlen(tok
->args
[0]))) {
1801 log_warn(LD_DIR
, "Couldn't decode key certificate fingerprint %s",
1802 escaped(tok
->args
[0]));
1806 if (crypto_pk_get_digest(cert
->identity_key
,
1807 cert
->cache_info
.identity_digest
))
1810 if (memcmp(cert
->cache_info
.identity_digest
, fp_declared
, DIGEST_LEN
)) {
1811 log_warn(LD_DIR
, "Digest of certificate key didn't match declared "
1816 tok
= find_opt_by_keyword(tokens
, K_DIR_ADDRESS
);
1819 char *address
= NULL
;
1820 tor_assert(tok
->n_args
);
1821 /* XXX023 use tor_addr_port_parse() below instead. -RD */
1822 if (parse_addr_port(LOG_WARN
, tok
->args
[0], &address
, NULL
,
1823 &cert
->dir_port
)<0 ||
1824 tor_inet_aton(address
, &in
) == 0) {
1825 log_warn(LD_DIR
, "Couldn't parse dir-address in certificate");
1829 cert
->addr
= ntohl(in
.s_addr
);
1833 tok
= find_by_keyword(tokens
, K_DIR_KEY_PUBLISHED
);
1834 if (parse_iso_time(tok
->args
[0], &cert
->cache_info
.published_on
) < 0) {
1837 tok
= find_by_keyword(tokens
, K_DIR_KEY_EXPIRES
);
1838 if (parse_iso_time(tok
->args
[0], &cert
->expires
) < 0) {
1842 tok
= smartlist_get(tokens
, smartlist_len(tokens
)-1);
1843 if (tok
->tp
!= K_DIR_KEY_CERTIFICATION
) {
1844 log_warn(LD_DIR
, "Certificate didn't end with dir-key-certification.");
1848 /* If we already have this cert, don't bother checking the signature. */
1849 old_cert
= authority_cert_get_by_digests(
1850 cert
->cache_info
.identity_digest
,
1851 cert
->signing_key_digest
);
1854 /* XXXX We could just compare signed_descriptor_digest, but that wouldn't
1856 if (old_cert
->cache_info
.signed_descriptor_len
== len
&&
1857 old_cert
->cache_info
.signed_descriptor_body
&&
1858 !memcmp(s
, old_cert
->cache_info
.signed_descriptor_body
, len
)) {
1859 log_debug(LD_DIR
, "We already checked the signature on this "
1860 "certificate; no need to do so again.");
1862 cert
->is_cross_certified
= old_cert
->is_cross_certified
;
1866 if (check_signature_token(digest
, DIGEST_LEN
, tok
, cert
->identity_key
, 0,
1867 "key certificate")) {
1871 if ((tok
= find_opt_by_keyword(tokens
, K_DIR_KEY_CROSSCERT
))) {
1872 /* XXXX Once all authorities generate cross-certified certificates,
1873 * make this field mandatory. */
1874 if (check_signature_token(cert
->cache_info
.identity_digest
,
1878 CST_NO_CHECK_OBJTYPE
,
1879 "key cross-certification")) {
1882 cert
->is_cross_certified
= 1;
1886 cert
->cache_info
.signed_descriptor_len
= len
;
1887 cert
->cache_info
.signed_descriptor_body
= tor_malloc(len
+1);
1888 memcpy(cert
->cache_info
.signed_descriptor_body
, s
, len
);
1889 cert
->cache_info
.signed_descriptor_body
[len
] = 0;
1890 cert
->cache_info
.saved_location
= SAVED_NOWHERE
;
1892 if (end_of_string
) {
1893 *end_of_string
= eat_whitespace(eos
);
1895 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
1896 smartlist_free(tokens
);
1898 DUMP_AREA(area
, "authority cert");
1899 memarea_drop_all(area
);
1903 dump_desc(s_dup
, "authority cert");
1904 authority_cert_free(cert
);
1905 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
1906 smartlist_free(tokens
);
1908 DUMP_AREA(area
, "authority cert");
1909 memarea_drop_all(area
);
1914 /** Helper: given a string <b>s</b>, return the start of the next router-status
1915 * object (starting with "r " at the start of a line). If none is found,
1916 * return the start of the directory footer, or the next directory signature.
1917 * If none is found, return the end of the string. */
1918 static INLINE
const char *
1919 find_start_of_next_routerstatus(const char *s
)
1921 const char *eos
, *footer
, *sig
;
1922 if ((eos
= strstr(s
, "\nr ")))
1925 eos
= s
+ strlen(s
);
1927 footer
= tor_memstr(s
, eos
-s
, "\ndirectory-footer");
1928 sig
= tor_memstr(s
, eos
-s
, "\ndirectory-signature");
1931 return MIN(footer
, sig
) + 1;
1940 /** Given a string at *<b>s</b>, containing a routerstatus object, and an
1941 * empty smartlist at <b>tokens</b>, parse and return the first router status
1942 * object in the string, and advance *<b>s</b> to just after the end of the
1943 * router status. Return NULL and advance *<b>s</b> on error.
1945 * If <b>vote</b> and <b>vote_rs</b> are provided, don't allocate a fresh
1946 * routerstatus but use <b>vote_rs</b> instead.
1948 * If <b>consensus_method</b> is nonzero, this routerstatus is part of a
1949 * consensus, and we should parse it according to the method used to
1950 * make that consensus.
1952 * Parse according to the syntax used by the consensus flavor <b>flav</b>.
1954 static routerstatus_t
*
1955 routerstatus_parse_entry_from_string(memarea_t
*area
,
1956 const char **s
, smartlist_t
*tokens
,
1957 networkstatus_t
*vote
,
1958 vote_routerstatus_t
*vote_rs
,
1959 int consensus_method
,
1960 consensus_flavor_t flav
)
1962 const char *eos
, *s_dup
= *s
;
1963 routerstatus_t
*rs
= NULL
;
1964 directory_token_t
*tok
;
1965 char timebuf
[ISO_TIME_LEN
+1];
1969 tor_assert(bool_eq(vote
, vote_rs
));
1971 if (!consensus_method
)
1974 eos
= find_start_of_next_routerstatus(*s
);
1976 if (tokenize_string(area
,*s
, eos
, tokens
, rtrstatus_token_table
,0)) {
1977 log_warn(LD_DIR
, "Error tokenizing router status");
1980 if (smartlist_len(tokens
) < 1) {
1981 log_warn(LD_DIR
, "Impossibly short router status");
1984 tok
= find_by_keyword(tokens
, K_R
);
1985 tor_assert(tok
->n_args
>= 7);
1986 if (flav
== FLAV_NS
) {
1987 if (tok
->n_args
< 8) {
1988 log_warn(LD_DIR
, "Too few arguments to r");
1995 rs
= &vote_rs
->status
;
1997 rs
= tor_malloc_zero(sizeof(routerstatus_t
));
2000 if (!is_legal_nickname(tok
->args
[0])) {
2002 "Invalid nickname %s in router status; skipping.",
2003 escaped(tok
->args
[0]));
2006 strlcpy(rs
->nickname
, tok
->args
[0], sizeof(rs
->nickname
));
2008 if (digest_from_base64(rs
->identity_digest
, tok
->args
[1])) {
2009 log_warn(LD_DIR
, "Error decoding identity digest %s",
2010 escaped(tok
->args
[1]));
2014 if (flav
== FLAV_NS
) {
2015 if (digest_from_base64(rs
->descriptor_digest
, tok
->args
[2])) {
2016 log_warn(LD_DIR
, "Error decoding descriptor digest %s",
2017 escaped(tok
->args
[2]));
2022 if (tor_snprintf(timebuf
, sizeof(timebuf
), "%s %s",
2023 tok
->args
[3+offset
], tok
->args
[4+offset
]) < 0 ||
2024 parse_iso_time(timebuf
, &rs
->published_on
)<0) {
2025 log_warn(LD_DIR
, "Error parsing time '%s %s' [%d %d]",
2026 tok
->args
[3+offset
], tok
->args
[4+offset
],
2031 if (tor_inet_aton(tok
->args
[5+offset
], &in
) == 0) {
2032 log_warn(LD_DIR
, "Error parsing router address in network-status %s",
2033 escaped(tok
->args
[5+offset
]));
2036 rs
->addr
= ntohl(in
.s_addr
);
2038 rs
->or_port
= (uint16_t) tor_parse_long(tok
->args
[6+offset
],
2039 10,0,65535,NULL
,NULL
);
2040 rs
->dir_port
= (uint16_t) tor_parse_long(tok
->args
[7+offset
],
2041 10,0,65535,NULL
,NULL
);
2043 tok
= find_opt_by_keyword(tokens
, K_S
);
2047 for (i
=0; i
< tok
->n_args
; ++i
) {
2048 int p
= smartlist_string_pos(vote
->known_flags
, tok
->args
[i
]);
2050 vote_rs
->flags
|= (1<<p
);
2052 log_warn(LD_DIR
, "Flags line had a flag %s not listed in known_flags.",
2053 escaped(tok
->args
[i
]));
2059 for (i
=0; i
< tok
->n_args
; ++i
) {
2060 if (!strcmp(tok
->args
[i
], "Exit"))
2062 else if (!strcmp(tok
->args
[i
], "Stable"))
2064 else if (!strcmp(tok
->args
[i
], "Fast"))
2066 else if (!strcmp(tok
->args
[i
], "Running"))
2068 else if (!strcmp(tok
->args
[i
], "Named"))
2070 else if (!strcmp(tok
->args
[i
], "Valid"))
2072 else if (!strcmp(tok
->args
[i
], "V2Dir"))
2074 else if (!strcmp(tok
->args
[i
], "Guard"))
2075 rs
->is_possible_guard
= 1;
2076 else if (!strcmp(tok
->args
[i
], "BadExit"))
2077 rs
->is_bad_exit
= 1;
2078 else if (!strcmp(tok
->args
[i
], "BadDirectory"))
2079 rs
->is_bad_directory
= 1;
2080 else if (!strcmp(tok
->args
[i
], "Authority"))
2081 rs
->is_authority
= 1;
2082 else if (!strcmp(tok
->args
[i
], "Unnamed") &&
2083 consensus_method
>= 2) {
2084 /* Unnamed is computed right by consensus method 2 and later. */
2086 } else if (!strcmp(tok
->args
[i
], "HSDir")) {
2091 if ((tok
= find_opt_by_keyword(tokens
, K_V
))) {
2092 tor_assert(tok
->n_args
== 1);
2093 rs
->version_known
= 1;
2094 if (strcmpstart(tok
->args
[0], "Tor ")) {
2095 rs
->version_supports_begindir
= 1;
2096 rs
->version_supports_extrainfo_upload
= 1;
2097 rs
->version_supports_conditional_consensus
= 1;
2099 rs
->version_supports_begindir
=
2100 tor_version_as_new_as(tok
->args
[0], "0.2.0.1-alpha");
2101 rs
->version_supports_extrainfo_upload
=
2102 tor_version_as_new_as(tok
->args
[0], "0.2.0.0-alpha-dev (r10070)");
2103 rs
->version_supports_v3_dir
=
2104 tor_version_as_new_as(tok
->args
[0], "0.2.0.8-alpha");
2105 rs
->version_supports_conditional_consensus
=
2106 tor_version_as_new_as(tok
->args
[0], "0.2.1.1-alpha");
2109 vote_rs
->version
= tor_strdup(tok
->args
[0]);
2113 /* handle weighting/bandwidth info */
2114 if ((tok
= find_opt_by_keyword(tokens
, K_W
))) {
2116 for (i
=0; i
< tok
->n_args
; ++i
) {
2117 if (!strcmpstart(tok
->args
[i
], "Bandwidth=")) {
2119 rs
->bandwidth
= (uint32_t)tor_parse_ulong(strchr(tok
->args
[i
], '=')+1,
2123 log_warn(LD_DIR
, "Invalid Bandwidth %s", escaped(tok
->args
[i
]));
2126 rs
->has_bandwidth
= 1;
2127 } else if (!strcmpstart(tok
->args
[i
], "Measured=")) {
2130 (uint32_t)tor_parse_ulong(strchr(tok
->args
[i
], '=')+1,
2131 10, 0, UINT32_MAX
, &ok
, NULL
);
2133 log_warn(LD_DIR
, "Invalid Measured Bandwidth %s",
2134 escaped(tok
->args
[i
]));
2137 rs
->has_measured_bw
= 1;
2142 /* parse exit policy summaries */
2143 if ((tok
= find_opt_by_keyword(tokens
, K_P
))) {
2144 tor_assert(tok
->n_args
== 1);
2145 if (strcmpstart(tok
->args
[0], "accept ") &&
2146 strcmpstart(tok
->args
[0], "reject ")) {
2147 log_warn(LD_DIR
, "Unknown exit policy summary type %s.",
2148 escaped(tok
->args
[0]));
2151 /* XXX weasel: parse this into ports and represent them somehow smart,
2152 * maybe not here but somewhere on if we need it for the client.
2153 * we should still parse it here to check it's valid tho.
2155 rs
->exitsummary
= tor_strdup(tok
->args
[0]);
2156 rs
->has_exitsummary
= 1;
2160 SMARTLIST_FOREACH_BEGIN(tokens
, directory_token_t
*, t
) {
2161 if (t
->tp
== K_M
&& t
->n_args
) {
2162 vote_microdesc_hash_t
*line
=
2163 tor_malloc(sizeof(vote_microdesc_hash_t
));
2164 line
->next
= vote_rs
->microdesc
;
2165 line
->microdesc_hash_line
= tor_strdup(t
->args
[0]);
2166 vote_rs
->microdesc
= line
;
2168 } SMARTLIST_FOREACH_END(t
);
2171 if (!strcasecmp(rs
->nickname
, UNNAMED_ROUTER_NICKNAME
))
2176 dump_desc(s_dup
, "routerstatus entry");
2178 routerstatus_free(rs
);
2181 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
2182 smartlist_clear(tokens
);
2184 DUMP_AREA(area
, "routerstatus entry");
2185 memarea_clear(area
);
2192 /** Helper to sort a smartlist of pointers to routerstatus_t */
2194 compare_routerstatus_entries(const void **_a
, const void **_b
)
2196 const routerstatus_t
*a
= *_a
, *b
= *_b
;
2197 return memcmp(a
->identity_digest
, b
->identity_digest
, DIGEST_LEN
);
2200 /** Helper: used in call to _smartlist_uniq to clear out duplicate entries. */
2202 _free_duplicate_routerstatus_entry(void *e
)
2205 "Network-status has two entries for the same router. "
2207 routerstatus_free(e
);
2210 /** Given a v2 network-status object in <b>s</b>, try to
2211 * parse it and return the result. Return NULL on failure. Check the
2212 * signature of the network status, but do not (yet) check the signing key for
2215 networkstatus_v2_t
*
2216 networkstatus_v2_parse_from_string(const char *s
)
2218 const char *eos
, *s_dup
= s
;
2219 smartlist_t
*tokens
= smartlist_create();
2220 smartlist_t
*footer_tokens
= smartlist_create();
2221 networkstatus_v2_t
*ns
= NULL
;
2222 char ns_digest
[DIGEST_LEN
];
2223 char tmp_digest
[DIGEST_LEN
];
2225 directory_token_t
*tok
;
2227 memarea_t
*area
= NULL
;
2229 if (router_get_networkstatus_v2_hash(s
, ns_digest
)) {
2230 log_warn(LD_DIR
, "Unable to compute digest of network-status");
2234 area
= memarea_new();
2235 eos
= find_start_of_next_routerstatus(s
);
2236 if (tokenize_string(area
, s
, eos
, tokens
, netstatus_token_table
,0)) {
2237 log_warn(LD_DIR
, "Error tokenizing network-status header.");
2240 ns
= tor_malloc_zero(sizeof(networkstatus_v2_t
));
2241 memcpy(ns
->networkstatus_digest
, ns_digest
, DIGEST_LEN
);
2243 tok
= find_by_keyword(tokens
, K_NETWORK_STATUS_VERSION
);
2244 tor_assert(tok
->n_args
>= 1);
2245 if (strcmp(tok
->args
[0], "2")) {
2246 log_warn(LD_BUG
, "Got a non-v2 networkstatus. Version was "
2247 "%s", escaped(tok
->args
[0]));
2251 tok
= find_by_keyword(tokens
, K_DIR_SOURCE
);
2252 tor_assert(tok
->n_args
>= 3);
2253 ns
->source_address
= tor_strdup(tok
->args
[0]);
2254 if (tor_inet_aton(tok
->args
[1], &in
) == 0) {
2255 log_warn(LD_DIR
, "Error parsing network-status source address %s",
2256 escaped(tok
->args
[1]));
2259 ns
->source_addr
= ntohl(in
.s_addr
);
2260 ns
->source_dirport
=
2261 (uint16_t) tor_parse_long(tok
->args
[2],10,0,65535,NULL
,NULL
);
2262 if (ns
->source_dirport
== 0) {
2263 log_warn(LD_DIR
, "Directory source without dirport; skipping.");
2267 tok
= find_by_keyword(tokens
, K_FINGERPRINT
);
2268 tor_assert(tok
->n_args
);
2269 if (base16_decode(ns
->identity_digest
, DIGEST_LEN
, tok
->args
[0],
2270 strlen(tok
->args
[0]))) {
2271 log_warn(LD_DIR
, "Couldn't decode networkstatus fingerprint %s",
2272 escaped(tok
->args
[0]));
2276 if ((tok
= find_opt_by_keyword(tokens
, K_CONTACT
))) {
2277 tor_assert(tok
->n_args
);
2278 ns
->contact
= tor_strdup(tok
->args
[0]);
2281 tok
= find_by_keyword(tokens
, K_DIR_SIGNING_KEY
);
2282 tor_assert(tok
->key
);
2283 ns
->signing_key
= tok
->key
;
2286 if (crypto_pk_get_digest(ns
->signing_key
, tmp_digest
)<0) {
2287 log_warn(LD_DIR
, "Couldn't compute signing key digest");
2290 if (memcmp(tmp_digest
, ns
->identity_digest
, DIGEST_LEN
)) {
2292 "network-status fingerprint did not match dir-signing-key");
2296 if ((tok
= find_opt_by_keyword(tokens
, K_DIR_OPTIONS
))) {
2297 for (i
=0; i
< tok
->n_args
; ++i
) {
2298 if (!strcmp(tok
->args
[i
], "Names"))
2299 ns
->binds_names
= 1;
2300 if (!strcmp(tok
->args
[i
], "Versions"))
2301 ns
->recommends_versions
= 1;
2302 if (!strcmp(tok
->args
[i
], "BadExits"))
2303 ns
->lists_bad_exits
= 1;
2304 if (!strcmp(tok
->args
[i
], "BadDirectories"))
2305 ns
->lists_bad_directories
= 1;
2309 if (ns
->recommends_versions
) {
2310 if (!(tok
= find_opt_by_keyword(tokens
, K_CLIENT_VERSIONS
))) {
2311 log_warn(LD_DIR
, "Missing client-versions on versioning directory");
2314 ns
->client_versions
= tor_strdup(tok
->args
[0]);
2316 if (!(tok
= find_opt_by_keyword(tokens
, K_SERVER_VERSIONS
)) ||
2318 log_warn(LD_DIR
, "Missing server-versions on versioning directory");
2321 ns
->server_versions
= tor_strdup(tok
->args
[0]);
2324 tok
= find_by_keyword(tokens
, K_PUBLISHED
);
2325 tor_assert(tok
->n_args
== 1);
2326 if (parse_iso_time(tok
->args
[0], &ns
->published_on
) < 0) {
2330 ns
->entries
= smartlist_create();
2332 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
2333 smartlist_clear(tokens
);
2334 memarea_clear(area
);
2335 while (!strcmpstart(s
, "r ")) {
2337 if ((rs
= routerstatus_parse_entry_from_string(area
, &s
, tokens
,
2339 smartlist_add(ns
->entries
, rs
);
2341 smartlist_sort(ns
->entries
, compare_routerstatus_entries
);
2342 smartlist_uniq(ns
->entries
, compare_routerstatus_entries
,
2343 _free_duplicate_routerstatus_entry
);
2345 if (tokenize_string(area
,s
, NULL
, footer_tokens
, dir_footer_token_table
,0)) {
2346 log_warn(LD_DIR
, "Error tokenizing network-status footer.");
2349 if (smartlist_len(footer_tokens
) < 1) {
2350 log_warn(LD_DIR
, "Too few items in network-status footer.");
2353 tok
= smartlist_get(footer_tokens
, smartlist_len(footer_tokens
)-1);
2354 if (tok
->tp
!= K_DIRECTORY_SIGNATURE
) {
2356 "Expected network-status footer to end with a signature.");
2360 note_crypto_pk_op(VERIFY_DIR
);
2361 if (check_signature_token(ns_digest
, DIGEST_LEN
, tok
, ns
->signing_key
, 0,
2362 "network-status") < 0)
2367 dump_desc(s_dup
, "v2 networkstatus");
2368 networkstatus_v2_free(ns
);
2371 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
2372 smartlist_free(tokens
);
2373 SMARTLIST_FOREACH(footer_tokens
, directory_token_t
*, t
, token_clear(t
));
2374 smartlist_free(footer_tokens
);
2376 DUMP_AREA(area
, "v2 networkstatus");
2377 memarea_drop_all(area
);
2382 /** Verify the bandwidth weights of a network status document */
2384 networkstatus_verify_bw_weights(networkstatus_t
*ns
)
2386 int64_t weight_scale
;
2387 int64_t G
=0, M
=0, E
=0, D
=0, T
=0;
2388 double Wgg
, Wgm
, Wgd
, Wmg
, Wmm
, Wme
, Wmd
, Weg
, Wem
, Wee
, Wed
;
2389 double Gtotal
=0, Mtotal
=0, Etotal
=0;
2390 const char *casename
= NULL
;
2393 weight_scale
= circuit_build_times_get_bw_scale(ns
);
2394 Wgg
= networkstatus_get_bw_weight(ns
, "Wgg", -1);
2395 Wgm
= networkstatus_get_bw_weight(ns
, "Wgm", -1);
2396 Wgd
= networkstatus_get_bw_weight(ns
, "Wgd", -1);
2397 Wmg
= networkstatus_get_bw_weight(ns
, "Wmg", -1);
2398 Wmm
= networkstatus_get_bw_weight(ns
, "Wmm", -1);
2399 Wme
= networkstatus_get_bw_weight(ns
, "Wme", -1);
2400 Wmd
= networkstatus_get_bw_weight(ns
, "Wmd", -1);
2401 Weg
= networkstatus_get_bw_weight(ns
, "Weg", -1);
2402 Wem
= networkstatus_get_bw_weight(ns
, "Wem", -1);
2403 Wee
= networkstatus_get_bw_weight(ns
, "Wee", -1);
2404 Wed
= networkstatus_get_bw_weight(ns
, "Wed", -1);
2406 if (Wgg
<0 || Wgm
<0 || Wgd
<0 || Wmg
<0 || Wmm
<0 || Wme
<0 || Wmd
<0 || Weg
<0
2407 || Wem
<0 || Wee
<0 || Wed
<0) {
2408 log_warn(LD_BUG
, "No bandwidth weights produced in consensus!");
2412 // First, sanity check basic summing properties that hold for all cases
2413 // We use > 1 as the check for these because they are computed as integers.
2414 // Sometimes there are rounding errors.
2415 if (fabs(Wmm
- weight_scale
) > 1) {
2416 log_warn(LD_BUG
, "Wmm=%lf != "I64_FORMAT
,
2417 Wmm
, I64_PRINTF_ARG(weight_scale
));
2421 if (fabs(Wem
- Wee
) > 1) {
2422 log_warn(LD_BUG
, "Wem=%lf != Wee=%lf", Wem
, Wee
);
2426 if (fabs(Wgm
- Wgg
) > 1) {
2427 log_warn(LD_BUG
, "Wgm=%lf != Wgg=%lf", Wgm
, Wgg
);
2431 if (fabs(Weg
- Wed
) > 1) {
2432 log_warn(LD_BUG
, "Wed=%lf != Weg=%lf", Wed
, Weg
);
2436 if (fabs(Wgg
+ Wmg
- weight_scale
) > 0.001*weight_scale
) {
2437 log_warn(LD_BUG
, "Wgg=%lf != "I64_FORMAT
" - Wmg=%lf", Wgg
,
2438 I64_PRINTF_ARG(weight_scale
), Wmg
);
2442 if (fabs(Wee
+ Wme
- weight_scale
) > 0.001*weight_scale
) {
2443 log_warn(LD_BUG
, "Wee=%lf != "I64_FORMAT
" - Wme=%lf", Wee
,
2444 I64_PRINTF_ARG(weight_scale
), Wme
);
2448 if (fabs(Wgd
+ Wmd
+ Wed
- weight_scale
) > 0.001*weight_scale
) {
2449 log_warn(LD_BUG
, "Wgd=%lf + Wmd=%lf + Wed=%lf != "I64_FORMAT
,
2450 Wgd
, Wmd
, Wed
, I64_PRINTF_ARG(weight_scale
));
2454 Wgg
/= weight_scale
;
2455 Wgm
/= weight_scale
;
2456 Wgd
/= weight_scale
;
2458 Wmg
/= weight_scale
;
2459 Wmm
/= weight_scale
;
2460 Wme
/= weight_scale
;
2461 Wmd
/= weight_scale
;
2463 Weg
/= weight_scale
;
2464 Wem
/= weight_scale
;
2465 Wee
/= weight_scale
;
2466 Wed
/= weight_scale
;
2468 // Then, gather G, M, E, D, T to determine case
2469 SMARTLIST_FOREACH_BEGIN(ns
->routerstatus_list
, routerstatus_t
*, rs
) {
2470 if (rs
->has_bandwidth
) {
2472 if (rs
->is_exit
&& rs
->is_possible_guard
) {
2474 Gtotal
+= Wgd
*rs
->bandwidth
;
2475 Mtotal
+= Wmd
*rs
->bandwidth
;
2476 Etotal
+= Wed
*rs
->bandwidth
;
2477 } else if (rs
->is_exit
) {
2479 Mtotal
+= Wme
*rs
->bandwidth
;
2480 Etotal
+= Wee
*rs
->bandwidth
;
2481 } else if (rs
->is_possible_guard
) {
2483 Gtotal
+= Wgg
*rs
->bandwidth
;
2484 Mtotal
+= Wmg
*rs
->bandwidth
;
2487 Mtotal
+= Wmm
*rs
->bandwidth
;
2490 log_warn(LD_BUG
, "Missing consensus bandwidth for router %s",
2493 } SMARTLIST_FOREACH_END(rs
);
2495 // Finally, check equality conditions depending upon case 1, 2 or 3
2496 // Full equality cases: 1, 3b
2497 // Partial equality cases: 2b (E=G), 3a (M=E)
2498 // Fully unknown: 2a
2499 if (3*E
>= T
&& 3*G
>= T
) {
2500 // Case 1: Neither are scarce
2501 casename
= "Case 1";
2502 if (fabs(Etotal
-Mtotal
) > 0.01*MAX(Etotal
,Mtotal
)) {
2504 "Bw Weight Failure for %s: Etotal %lf != Mtotal %lf. "
2505 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2507 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2508 casename
, Etotal
, Mtotal
,
2509 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2510 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2511 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2514 if (fabs(Etotal
-Gtotal
) > 0.01*MAX(Etotal
,Gtotal
)) {
2516 "Bw Weight Failure for %s: Etotal %lf != Gtotal %lf. "
2517 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2519 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2520 casename
, Etotal
, Gtotal
,
2521 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2522 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2523 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2526 if (fabs(Gtotal
-Mtotal
) > 0.01*MAX(Gtotal
,Mtotal
)) {
2528 "Bw Weight Failure for %s: Mtotal %lf != Gtotal %lf. "
2529 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2531 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2532 casename
, Mtotal
, Gtotal
,
2533 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2534 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2535 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2538 } else if (3*E
< T
&& 3*G
< T
) {
2539 int64_t R
= MIN(E
, G
);
2540 int64_t S
= MAX(E
, G
);
2542 * Case 2: Both Guards and Exits are scarce
2543 * Balance D between E and G, depending upon
2544 * D capacity and scarcity. Devote no extra
2545 * bandwidth to middle nodes.
2547 if (R
+D
< S
) { // Subcase a
2548 double Rtotal
, Stotal
;
2556 casename
= "Case 2a";
2558 if (Rtotal
> Stotal
) {
2560 "Bw Weight Failure for %s: Rtotal %lf > Stotal %lf. "
2561 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2563 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2564 casename
, Rtotal
, Stotal
,
2565 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2566 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2567 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2573 "Bw Weight Failure for %s: 3*Rtotal %lf > T "
2574 I64_FORMAT
". G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
2575 " D="I64_FORMAT
" T="I64_FORMAT
". "
2576 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2577 casename
, Rtotal
*3, I64_PRINTF_ARG(T
),
2578 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2579 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2580 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2586 "Bw Weight Failure for %s: 3*Stotal %lf > T "
2587 I64_FORMAT
". G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
2588 " D="I64_FORMAT
" T="I64_FORMAT
". "
2589 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2590 casename
, Stotal
*3, I64_PRINTF_ARG(T
),
2591 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2592 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2593 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2599 "Bw Weight Failure for %s: 3*Mtotal %lf < T "
2601 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2603 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2604 casename
, Mtotal
*3, I64_PRINTF_ARG(T
),
2605 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2606 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2607 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2610 } else { // Subcase b: R+D > S
2611 casename
= "Case 2b";
2613 /* Check the rare-M redirect case. */
2614 if (D
!= 0 && 3*M
< T
) {
2615 casename
= "Case 2b (balanced)";
2616 if (fabs(Etotal
-Mtotal
) > 0.01*MAX(Etotal
,Mtotal
)) {
2618 "Bw Weight Failure for %s: Etotal %lf != Mtotal %lf. "
2619 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2621 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2622 casename
, Etotal
, Mtotal
,
2623 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2624 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2625 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2628 if (fabs(Etotal
-Gtotal
) > 0.01*MAX(Etotal
,Gtotal
)) {
2630 "Bw Weight Failure for %s: Etotal %lf != Gtotal %lf. "
2631 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2633 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2634 casename
, Etotal
, Gtotal
,
2635 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2636 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2637 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2640 if (fabs(Gtotal
-Mtotal
) > 0.01*MAX(Gtotal
,Mtotal
)) {
2642 "Bw Weight Failure for %s: Mtotal %lf != Gtotal %lf. "
2643 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2645 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2646 casename
, Mtotal
, Gtotal
,
2647 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2648 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2649 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2653 if (fabs(Etotal
-Gtotal
) > 0.01*MAX(Etotal
,Gtotal
)) {
2655 "Bw Weight Failure for %s: Etotal %lf != Gtotal %lf. "
2656 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2658 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2659 casename
, Etotal
, Gtotal
,
2660 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2661 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2662 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2667 } else { // if (E < T/3 || G < T/3) {
2668 int64_t S
= MIN(E
, G
);
2669 int64_t NS
= MAX(E
, G
);
2670 if (3*(S
+D
) < T
) { // Subcase a:
2674 casename
= "Case 3a (G scarce)";
2677 } else { // if (G >= E) {
2678 casename
= "Case 3a (E scarce)";
2685 "Bw Weight Failure for %s: 3*Stotal %lf > T "
2686 I64_FORMAT
". G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
2687 " D="I64_FORMAT
" T="I64_FORMAT
". "
2688 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2689 casename
, Stotal
*3, I64_PRINTF_ARG(T
),
2690 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2691 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2692 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2696 if (fabs(NStotal
-Mtotal
) > 0.01*MAX(NStotal
,Mtotal
)) {
2698 "Bw Weight Failure for %s: NStotal %lf != Mtotal %lf. "
2699 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2701 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2702 casename
, NStotal
, Mtotal
,
2703 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2704 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2705 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2709 // if NS < M, NStotal > T/3 because only one of G or E is scarce
2710 if (3*NStotal
< T
) {
2712 "Bw Weight Failure for %s: 3*NStotal %lf < T "
2713 I64_FORMAT
". G="I64_FORMAT
" M="I64_FORMAT
2714 " E="I64_FORMAT
" D="I64_FORMAT
" T="I64_FORMAT
". "
2715 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2716 casename
, NStotal
*3, I64_PRINTF_ARG(T
),
2717 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2718 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2719 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2723 } else { // Subcase b: S+D >= T/3
2724 casename
= "Case 3b";
2725 if (fabs(Etotal
-Mtotal
) > 0.01*MAX(Etotal
,Mtotal
)) {
2727 "Bw Weight Failure for %s: Etotal %lf != Mtotal %lf. "
2728 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2730 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2731 casename
, Etotal
, Mtotal
,
2732 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2733 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2734 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2737 if (fabs(Etotal
-Gtotal
) > 0.01*MAX(Etotal
,Gtotal
)) {
2739 "Bw Weight Failure for %s: Etotal %lf != Gtotal %lf. "
2740 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2742 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2743 casename
, Etotal
, Gtotal
,
2744 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2745 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2746 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2749 if (fabs(Gtotal
-Mtotal
) > 0.01*MAX(Gtotal
,Mtotal
)) {
2751 "Bw Weight Failure for %s: Mtotal %lf != Gtotal %lf. "
2752 "G="I64_FORMAT
" M="I64_FORMAT
" E="I64_FORMAT
" D="I64_FORMAT
2754 "Wgg=%lf Wgd=%lf Wmg=%lf Wme=%lf Wmd=%lf Wee=%lf Wed=%lf",
2755 casename
, Mtotal
, Gtotal
,
2756 I64_PRINTF_ARG(G
), I64_PRINTF_ARG(M
), I64_PRINTF_ARG(E
),
2757 I64_PRINTF_ARG(D
), I64_PRINTF_ARG(T
),
2758 Wgg
, Wgd
, Wmg
, Wme
, Wmd
, Wee
, Wed
);
2765 log_notice(LD_DIR
, "Bandwidth-weight %s is verified and valid.",
2771 /** Parse a v3 networkstatus vote, opinion, or consensus (depending on
2772 * ns_type), from <b>s</b>, and return the result. Return NULL on failure. */
2774 networkstatus_parse_vote_from_string(const char *s
, const char **eos_out
,
2775 networkstatus_type_t ns_type
)
2777 smartlist_t
*tokens
= smartlist_create();
2778 smartlist_t
*rs_tokens
= NULL
, *footer_tokens
= NULL
;
2779 networkstatus_voter_info_t
*voter
= NULL
;
2780 networkstatus_t
*ns
= NULL
;
2781 digests_t ns_digests
;
2782 const char *cert
, *end_of_header
, *end_of_footer
, *s_dup
= s
;
2783 directory_token_t
*tok
;
2786 int i
, inorder
, n_signatures
= 0;
2787 memarea_t
*area
= NULL
, *rs_area
= NULL
;
2788 consensus_flavor_t flav
= FLAV_NS
;
2795 if (router_get_networkstatus_v3_hashes(s
, &ns_digests
)) {
2796 log_warn(LD_DIR
, "Unable to compute digest of network-status");
2800 area
= memarea_new();
2801 end_of_header
= find_start_of_next_routerstatus(s
);
2802 if (tokenize_string(area
, s
, end_of_header
, tokens
,
2803 (ns_type
== NS_TYPE_CONSENSUS
) ?
2804 networkstatus_consensus_token_table
:
2805 networkstatus_token_table
, 0)) {
2806 log_warn(LD_DIR
, "Error tokenizing network-status vote header");
2810 ns
= tor_malloc_zero(sizeof(networkstatus_t
));
2811 memcpy(&ns
->digests
, &ns_digests
, sizeof(ns_digests
));
2813 tok
= find_by_keyword(tokens
, K_NETWORK_STATUS_VERSION
);
2815 if (tok
->n_args
> 1) {
2816 int flavor
= networkstatus_parse_flavor_name(tok
->args
[1]);
2818 log_warn(LD_DIR
, "Can't parse document with unknown flavor %s",
2819 escaped(tok
->args
[2]));
2822 ns
->flavor
= flav
= flavor
;
2824 if (flav
!= FLAV_NS
&& ns_type
!= NS_TYPE_CONSENSUS
) {
2825 log_warn(LD_DIR
, "Flavor found on non-consensus networkstatus.");
2829 if (ns_type
!= NS_TYPE_CONSENSUS
) {
2830 const char *end_of_cert
= NULL
;
2831 if (!(cert
= strstr(s
, "\ndir-key-certificate-version")))
2834 ns
->cert
= authority_cert_parse_from_string(cert
, &end_of_cert
);
2835 if (!ns
->cert
|| !end_of_cert
|| end_of_cert
> end_of_header
)
2839 tok
= find_by_keyword(tokens
, K_VOTE_STATUS
);
2840 tor_assert(tok
->n_args
);
2841 if (!strcmp(tok
->args
[0], "vote")) {
2842 ns
->type
= NS_TYPE_VOTE
;
2843 } else if (!strcmp(tok
->args
[0], "consensus")) {
2844 ns
->type
= NS_TYPE_CONSENSUS
;
2845 } else if (!strcmp(tok
->args
[0], "opinion")) {
2846 ns
->type
= NS_TYPE_OPINION
;
2848 log_warn(LD_DIR
, "Unrecognized vote status %s in network-status",
2849 escaped(tok
->args
[0]));
2852 if (ns_type
!= ns
->type
) {
2853 log_warn(LD_DIR
, "Got the wrong kind of v3 networkstatus.");
2857 if (ns
->type
== NS_TYPE_VOTE
|| ns
->type
== NS_TYPE_OPINION
) {
2858 tok
= find_by_keyword(tokens
, K_PUBLISHED
);
2859 if (parse_iso_time(tok
->args
[0], &ns
->published
))
2862 ns
->supported_methods
= smartlist_create();
2863 tok
= find_opt_by_keyword(tokens
, K_CONSENSUS_METHODS
);
2865 for (i
=0; i
< tok
->n_args
; ++i
)
2866 smartlist_add(ns
->supported_methods
, tor_strdup(tok
->args
[i
]));
2868 smartlist_add(ns
->supported_methods
, tor_strdup("1"));
2871 tok
= find_opt_by_keyword(tokens
, K_CONSENSUS_METHOD
);
2873 ns
->consensus_method
= (int)tor_parse_long(tok
->args
[0], 10, 1, INT_MAX
,
2878 ns
->consensus_method
= 1;
2882 tok
= find_by_keyword(tokens
, K_VALID_AFTER
);
2883 if (parse_iso_time(tok
->args
[0], &ns
->valid_after
))
2886 tok
= find_by_keyword(tokens
, K_FRESH_UNTIL
);
2887 if (parse_iso_time(tok
->args
[0], &ns
->fresh_until
))
2890 tok
= find_by_keyword(tokens
, K_VALID_UNTIL
);
2891 if (parse_iso_time(tok
->args
[0], &ns
->valid_until
))
2894 tok
= find_by_keyword(tokens
, K_VOTING_DELAY
);
2895 tor_assert(tok
->n_args
>= 2);
2897 (int) tor_parse_long(tok
->args
[0], 10, 0, INT_MAX
, &ok
, NULL
);
2901 (int) tor_parse_long(tok
->args
[1], 10, 0, INT_MAX
, &ok
, NULL
);
2904 if (ns
->valid_after
+ MIN_VOTE_INTERVAL
> ns
->fresh_until
) {
2905 log_warn(LD_DIR
, "Vote/consensus freshness interval is too short");
2908 if (ns
->valid_after
+ MIN_VOTE_INTERVAL
*2 > ns
->valid_until
) {
2909 log_warn(LD_DIR
, "Vote/consensus liveness interval is too short");
2912 if (ns
->vote_seconds
< MIN_VOTE_SECONDS
) {
2913 log_warn(LD_DIR
, "Vote seconds is too short");
2916 if (ns
->dist_seconds
< MIN_DIST_SECONDS
) {
2917 log_warn(LD_DIR
, "Dist seconds is too short");
2921 if ((tok
= find_opt_by_keyword(tokens
, K_CLIENT_VERSIONS
))) {
2922 ns
->client_versions
= tor_strdup(tok
->args
[0]);
2924 if ((tok
= find_opt_by_keyword(tokens
, K_SERVER_VERSIONS
))) {
2925 ns
->server_versions
= tor_strdup(tok
->args
[0]);
2928 tok
= find_by_keyword(tokens
, K_KNOWN_FLAGS
);
2929 ns
->known_flags
= smartlist_create();
2931 for (i
= 0; i
< tok
->n_args
; ++i
) {
2932 smartlist_add(ns
->known_flags
, tor_strdup(tok
->args
[i
]));
2933 if (i
>0 && strcmp(tok
->args
[i
-1], tok
->args
[i
])>= 0) {
2934 log_warn(LD_DIR
, "%s >= %s", tok
->args
[i
-1], tok
->args
[i
]);
2939 log_warn(LD_DIR
, "known-flags not in order");
2943 tok
= find_opt_by_keyword(tokens
, K_PARAMS
);
2946 ns
->net_params
= smartlist_create();
2947 for (i
= 0; i
< tok
->n_args
; ++i
) {
2949 char *eq
= strchr(tok
->args
[i
], '=');
2951 log_warn(LD_DIR
, "Bad element '%s' in params", escaped(tok
->args
[i
]));
2954 tor_parse_long(eq
+1, 10, INT32_MIN
, INT32_MAX
, &ok
, NULL
);
2956 log_warn(LD_DIR
, "Bad element '%s' in params", escaped(tok
->args
[i
]));
2959 if (i
> 0 && strcmp(tok
->args
[i
-1], tok
->args
[i
]) >= 0) {
2960 log_warn(LD_DIR
, "%s >= %s", tok
->args
[i
-1], tok
->args
[i
]);
2963 smartlist_add(ns
->net_params
, tor_strdup(tok
->args
[i
]));
2966 log_warn(LD_DIR
, "params not in order");
2971 ns
->voters
= smartlist_create();
2973 SMARTLIST_FOREACH_BEGIN(tokens
, directory_token_t
*, _tok
) {
2975 if (tok
->tp
== K_DIR_SOURCE
) {
2976 tor_assert(tok
->n_args
>= 6);
2979 smartlist_add(ns
->voters
, voter
);
2980 voter
= tor_malloc_zero(sizeof(networkstatus_voter_info_t
));
2981 voter
->sigs
= smartlist_create();
2982 if (ns
->type
!= NS_TYPE_CONSENSUS
)
2983 memcpy(voter
->vote_digest
, ns_digests
.d
[DIGEST_SHA1
], DIGEST_LEN
);
2985 voter
->nickname
= tor_strdup(tok
->args
[0]);
2986 if (strlen(tok
->args
[1]) != HEX_DIGEST_LEN
||
2987 base16_decode(voter
->identity_digest
, sizeof(voter
->identity_digest
),
2988 tok
->args
[1], HEX_DIGEST_LEN
) < 0) {
2989 log_warn(LD_DIR
, "Error decoding identity digest %s in "
2990 "network-status vote.", escaped(tok
->args
[1]));
2993 if (ns
->type
!= NS_TYPE_CONSENSUS
&&
2994 memcmp(ns
->cert
->cache_info
.identity_digest
,
2995 voter
->identity_digest
, DIGEST_LEN
)) {
2996 log_warn(LD_DIR
,"Mismatch between identities in certificate and vote");
2999 voter
->address
= tor_strdup(tok
->args
[2]);
3000 if (!tor_inet_aton(tok
->args
[3], &in
)) {
3001 log_warn(LD_DIR
, "Error decoding IP address %s in network-status.",
3002 escaped(tok
->args
[3]));
3005 voter
->addr
= ntohl(in
.s_addr
);
3006 voter
->dir_port
= (uint16_t)
3007 tor_parse_long(tok
->args
[4], 10, 0, 65535, &ok
, NULL
);
3010 voter
->or_port
= (uint16_t)
3011 tor_parse_long(tok
->args
[5], 10, 0, 65535, &ok
, NULL
);
3014 } else if (tok
->tp
== K_CONTACT
) {
3015 if (!voter
|| voter
->contact
) {
3016 log_warn(LD_DIR
, "contact element is out of place.");
3019 voter
->contact
= tor_strdup(tok
->args
[0]);
3020 } else if (tok
->tp
== K_VOTE_DIGEST
) {
3021 tor_assert(ns
->type
== NS_TYPE_CONSENSUS
);
3022 tor_assert(tok
->n_args
>= 1);
3023 if (!voter
|| ! tor_digest_is_zero(voter
->vote_digest
)) {
3024 log_warn(LD_DIR
, "vote-digest element is out of place.");
3027 if (strlen(tok
->args
[0]) != HEX_DIGEST_LEN
||
3028 base16_decode(voter
->vote_digest
, sizeof(voter
->vote_digest
),
3029 tok
->args
[0], HEX_DIGEST_LEN
) < 0) {
3030 log_warn(LD_DIR
, "Error decoding vote digest %s in "
3031 "network-status consensus.", escaped(tok
->args
[0]));
3035 } SMARTLIST_FOREACH_END(_tok
);
3037 smartlist_add(ns
->voters
, voter
);
3040 if (smartlist_len(ns
->voters
) == 0) {
3041 log_warn(LD_DIR
, "Missing dir-source elements in a vote networkstatus.");
3043 } else if (ns
->type
!= NS_TYPE_CONSENSUS
&& smartlist_len(ns
->voters
) != 1) {
3044 log_warn(LD_DIR
, "Too many dir-source elements in a vote networkstatus.");
3048 if (ns
->type
!= NS_TYPE_CONSENSUS
&&
3049 (tok
= find_opt_by_keyword(tokens
, K_LEGACY_DIR_KEY
))) {
3051 if (strlen(tok
->args
[0]) == HEX_DIGEST_LEN
) {
3052 networkstatus_voter_info_t
*voter
= smartlist_get(ns
->voters
, 0);
3053 if (base16_decode(voter
->legacy_id_digest
, DIGEST_LEN
,
3054 tok
->args
[0], HEX_DIGEST_LEN
)<0)
3060 log_warn(LD_DIR
, "Invalid legacy key digest %s on vote.",
3061 escaped(tok
->args
[0]));
3065 /* Parse routerstatus lines. */
3066 rs_tokens
= smartlist_create();
3067 rs_area
= memarea_new();
3069 ns
->routerstatus_list
= smartlist_create();
3071 while (!strcmpstart(s
, "r ")) {
3072 if (ns
->type
!= NS_TYPE_CONSENSUS
) {
3073 vote_routerstatus_t
*rs
= tor_malloc_zero(sizeof(vote_routerstatus_t
));
3074 if (routerstatus_parse_entry_from_string(rs_area
, &s
, rs_tokens
, ns
,
3076 smartlist_add(ns
->routerstatus_list
, rs
);
3078 tor_free(rs
->version
);
3083 if ((rs
= routerstatus_parse_entry_from_string(rs_area
, &s
, rs_tokens
,
3085 ns
->consensus_method
,
3087 smartlist_add(ns
->routerstatus_list
, rs
);
3090 for (i
= 1; i
< smartlist_len(ns
->routerstatus_list
); ++i
) {
3091 routerstatus_t
*rs1
, *rs2
;
3092 if (ns
->type
!= NS_TYPE_CONSENSUS
) {
3093 vote_routerstatus_t
*a
= smartlist_get(ns
->routerstatus_list
, i
-1);
3094 vote_routerstatus_t
*b
= smartlist_get(ns
->routerstatus_list
, i
);
3095 rs1
= &a
->status
; rs2
= &b
->status
;
3097 rs1
= smartlist_get(ns
->routerstatus_list
, i
-1);
3098 rs2
= smartlist_get(ns
->routerstatus_list
, i
);
3100 if (memcmp(rs1
->identity_digest
, rs2
->identity_digest
, DIGEST_LEN
) >= 0) {
3101 log_warn(LD_DIR
, "Vote networkstatus entries not sorted by identity "
3107 /* Parse footer; check signature. */
3108 footer_tokens
= smartlist_create();
3109 if ((end_of_footer
= strstr(s
, "\nnetwork-status-version ")))
3112 end_of_footer
= s
+ strlen(s
);
3113 if (tokenize_string(area
,s
, end_of_footer
, footer_tokens
,
3114 networkstatus_vote_footer_token_table
, 0)) {
3115 log_warn(LD_DIR
, "Error tokenizing network-status vote footer.");
3121 SMARTLIST_FOREACH_BEGIN(footer_tokens
, directory_token_t
*, _tok
) {
3123 if (tok
->tp
== K_DIRECTORY_SIGNATURE
)
3125 else if (found_sig
) {
3126 log_warn(LD_DIR
, "Extraneous token after first directory-signature");
3129 } SMARTLIST_FOREACH_END(_tok
);
3132 if ((tok
= find_opt_by_keyword(footer_tokens
, K_DIRECTORY_FOOTER
))) {
3133 if (tok
!= smartlist_get(footer_tokens
, 0)) {
3134 log_warn(LD_DIR
, "Misplaced directory-footer token");
3139 tok
= find_opt_by_keyword(footer_tokens
, K_BW_WEIGHTS
);
3141 ns
->weight_params
= smartlist_create();
3142 for (i
= 0; i
< tok
->n_args
; ++i
) {
3144 char *eq
= strchr(tok
->args
[i
], '=');
3146 log_warn(LD_DIR
, "Bad element '%s' in weight params",
3147 escaped(tok
->args
[i
]));
3150 tor_parse_long(eq
+1, 10, INT32_MIN
, INT32_MAX
, &ok
, NULL
);
3152 log_warn(LD_DIR
, "Bad element '%s' in params", escaped(tok
->args
[i
]));
3155 smartlist_add(ns
->weight_params
, tor_strdup(tok
->args
[i
]));
3159 SMARTLIST_FOREACH_BEGIN(footer_tokens
, directory_token_t
*, _tok
) {
3160 char declared_identity
[DIGEST_LEN
];
3161 networkstatus_voter_info_t
*v
;
3162 document_signature_t
*sig
;
3163 const char *id_hexdigest
= NULL
;
3164 const char *sk_hexdigest
= NULL
;
3165 digest_algorithm_t alg
= DIGEST_SHA1
;
3167 if (tok
->tp
!= K_DIRECTORY_SIGNATURE
)
3169 tor_assert(tok
->n_args
>= 2);
3170 if (tok
->n_args
== 2) {
3171 id_hexdigest
= tok
->args
[0];
3172 sk_hexdigest
= tok
->args
[1];
3174 const char *algname
= tok
->args
[0];
3176 id_hexdigest
= tok
->args
[1];
3177 sk_hexdigest
= tok
->args
[2];
3178 a
= crypto_digest_algorithm_parse_name(algname
);
3180 log_warn(LD_DIR
, "Unknown digest algorithm %s; skipping",
3187 if (!tok
->object_type
||
3188 strcmp(tok
->object_type
, "SIGNATURE") ||
3189 tok
->object_size
< 128 || tok
->object_size
> 512) {
3190 log_warn(LD_DIR
, "Bad object type or length on directory-signature");
3194 if (strlen(id_hexdigest
) != HEX_DIGEST_LEN
||
3195 base16_decode(declared_identity
, sizeof(declared_identity
),
3196 id_hexdigest
, HEX_DIGEST_LEN
) < 0) {
3197 log_warn(LD_DIR
, "Error decoding declared identity %s in "
3198 "network-status vote.", escaped(id_hexdigest
));
3201 if (!(v
= networkstatus_get_voter_by_id(ns
, declared_identity
))) {
3202 log_warn(LD_DIR
, "ID on signature on network-status vote does not match "
3203 "any declared directory source.");
3206 sig
= tor_malloc_zero(sizeof(document_signature_t
));
3207 memcpy(sig
->identity_digest
, v
->identity_digest
, DIGEST_LEN
);
3209 if (strlen(sk_hexdigest
) != HEX_DIGEST_LEN
||
3210 base16_decode(sig
->signing_key_digest
, sizeof(sig
->signing_key_digest
),
3211 sk_hexdigest
, HEX_DIGEST_LEN
) < 0) {
3212 log_warn(LD_DIR
, "Error decoding declared signing key digest %s in "
3213 "network-status vote.", escaped(sk_hexdigest
));
3218 if (ns
->type
!= NS_TYPE_CONSENSUS
) {
3219 if (memcmp(declared_identity
, ns
->cert
->cache_info
.identity_digest
,
3221 log_warn(LD_DIR
, "Digest mismatch between declared and actual on "
3222 "network-status vote.");
3228 if (voter_get_sig_by_algorithm(v
, sig
->alg
)) {
3229 /* We already parsed a vote with this algorithm from this voter. Use the
3231 log_fn(LOG_PROTOCOL_WARN
, LD_DIR
, "We received a networkstatus "
3232 "that contains two votes from the same voter with the same "
3233 "algorithm. Ignoring the second vote.");
3238 if (ns
->type
!= NS_TYPE_CONSENSUS
) {
3239 if (check_signature_token(ns_digests
.d
[DIGEST_SHA1
], DIGEST_LEN
,
3240 tok
, ns
->cert
->signing_key
, 0,
3241 "network-status vote")) {
3245 sig
->good_signature
= 1;
3247 if (tok
->object_size
>= INT_MAX
|| tok
->object_size
>= SIZE_T_CEILING
) {
3251 sig
->signature
= tor_memdup(tok
->object_body
, tok
->object_size
);
3252 sig
->signature_len
= (int) tok
->object_size
;
3254 smartlist_add(v
->sigs
, sig
);
3257 } SMARTLIST_FOREACH_END(_tok
);
3259 if (! n_signatures
) {
3260 log_warn(LD_DIR
, "No signatures on networkstatus vote.");
3262 } else if (ns
->type
== NS_TYPE_VOTE
&& n_signatures
!= 1) {
3263 log_warn(LD_DIR
, "Received more than one signature on a "
3264 "network-status vote.");
3269 *eos_out
= end_of_footer
;
3273 dump_desc(s_dup
, "v3 networkstatus");
3274 networkstatus_vote_free(ns
);
3278 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
3279 smartlist_free(tokens
);
3283 SMARTLIST_FOREACH(voter
->sigs
, document_signature_t
*, sig
,
3284 document_signature_free(sig
));
3285 smartlist_free(voter
->sigs
);
3287 tor_free(voter
->nickname
);
3288 tor_free(voter
->address
);
3289 tor_free(voter
->contact
);
3293 SMARTLIST_FOREACH(rs_tokens
, directory_token_t
*, t
, token_clear(t
));
3294 smartlist_free(rs_tokens
);
3296 if (footer_tokens
) {
3297 SMARTLIST_FOREACH(footer_tokens
, directory_token_t
*, t
, token_clear(t
));
3298 smartlist_free(footer_tokens
);
3301 DUMP_AREA(area
, "v3 networkstatus");
3302 memarea_drop_all(area
);
3305 memarea_drop_all(rs_area
);
3310 /** Return the digests_t that holds the digests of the
3311 * <b>flavor_name</b>-flavored networkstatus according to the detached
3312 * signatures document <b>sigs</b>, allocating a new digests_t as neeeded. */
3314 detached_get_digests(ns_detached_signatures_t
*sigs
, const char *flavor_name
)
3316 digests_t
*d
= strmap_get(sigs
->digests
, flavor_name
);
3318 d
= tor_malloc_zero(sizeof(digests_t
));
3319 strmap_set(sigs
->digests
, flavor_name
, d
);
3324 /** Return the list of signatures of the <b>flavor_name</b>-flavored
3325 * networkstatus according to the detached signatures document <b>sigs</b>,
3326 * allocating a new digests_t as neeeded. */
3327 static smartlist_t
*
3328 detached_get_signatures(ns_detached_signatures_t
*sigs
,
3329 const char *flavor_name
)
3331 smartlist_t
*sl
= strmap_get(sigs
->signatures
, flavor_name
);
3333 sl
= smartlist_create();
3334 strmap_set(sigs
->signatures
, flavor_name
, sl
);
3339 /** Parse a detached v3 networkstatus signature document between <b>s</b> and
3340 * <b>eos</b> and return the result. Return -1 on failure. */
3341 ns_detached_signatures_t
*
3342 networkstatus_parse_detached_signatures(const char *s
, const char *eos
)
3344 /* XXXX there is too much duplicate shared between this function and
3345 * networkstatus_parse_vote_from_string(). */
3346 directory_token_t
*tok
;
3347 memarea_t
*area
= NULL
;
3350 smartlist_t
*tokens
= smartlist_create();
3351 ns_detached_signatures_t
*sigs
=
3352 tor_malloc_zero(sizeof(ns_detached_signatures_t
));
3353 sigs
->digests
= strmap_new();
3354 sigs
->signatures
= strmap_new();
3357 eos
= s
+ strlen(s
);
3359 area
= memarea_new();
3360 if (tokenize_string(area
,s
, eos
, tokens
,
3361 networkstatus_detached_signature_token_table
, 0)) {
3362 log_warn(LD_DIR
, "Error tokenizing detached networkstatus signatures");
3366 /* Grab all the digest-like tokens. */
3367 SMARTLIST_FOREACH_BEGIN(tokens
, directory_token_t
*, _tok
) {
3368 const char *algname
;
3369 digest_algorithm_t alg
;
3371 const char *hexdigest
;
3372 size_t expected_length
;
3376 if (tok
->tp
== K_CONSENSUS_DIGEST
) {
3380 hexdigest
= tok
->args
[0];
3381 } else if (tok
->tp
== K_ADDITIONAL_DIGEST
) {
3382 int a
= crypto_digest_algorithm_parse_name(tok
->args
[1]);
3384 log_warn(LD_DIR
, "Unrecognized algorithm name %s", tok
->args
[0]);
3387 alg
= (digest_algorithm_t
) a
;
3388 flavor
= tok
->args
[0];
3389 algname
= tok
->args
[1];
3390 hexdigest
= tok
->args
[2];
3396 (alg
== DIGEST_SHA1
) ? HEX_DIGEST_LEN
: HEX_DIGEST256_LEN
;
3398 if (strlen(hexdigest
) != expected_length
) {
3399 log_warn(LD_DIR
, "Wrong length on consensus-digest in detached "
3400 "networkstatus signatures");
3403 digests
= detached_get_digests(sigs
, flavor
);
3404 tor_assert(digests
);
3405 if (!tor_mem_is_zero(digests
->d
[alg
], DIGEST256_LEN
)) {
3406 log_warn(LD_DIR
, "Multiple digests for %s with %s on detached "
3407 "signatures document", flavor
, algname
);
3410 if (base16_decode(digests
->d
[alg
], DIGEST256_LEN
,
3411 hexdigest
, strlen(hexdigest
)) < 0) {
3412 log_warn(LD_DIR
, "Bad encoding on consensus-digest in detached "
3413 "networkstatus signatures");
3416 } SMARTLIST_FOREACH_END(_tok
);
3418 tok
= find_by_keyword(tokens
, K_VALID_AFTER
);
3419 if (parse_iso_time(tok
->args
[0], &sigs
->valid_after
)) {
3420 log_warn(LD_DIR
, "Bad valid-after in detached networkstatus signatures");
3424 tok
= find_by_keyword(tokens
, K_FRESH_UNTIL
);
3425 if (parse_iso_time(tok
->args
[0], &sigs
->fresh_until
)) {
3426 log_warn(LD_DIR
, "Bad fresh-until in detached networkstatus signatures");
3430 tok
= find_by_keyword(tokens
, K_VALID_UNTIL
);
3431 if (parse_iso_time(tok
->args
[0], &sigs
->valid_until
)) {
3432 log_warn(LD_DIR
, "Bad valid-until in detached networkstatus signatures");
3436 SMARTLIST_FOREACH_BEGIN(tokens
, directory_token_t
*, _tok
) {
3437 const char *id_hexdigest
;
3438 const char *sk_hexdigest
;
3439 const char *algname
;
3441 digest_algorithm_t alg
;
3443 char id_digest
[DIGEST_LEN
];
3444 char sk_digest
[DIGEST_LEN
];
3445 smartlist_t
*siglist
;
3446 document_signature_t
*sig
;
3450 if (tok
->tp
== K_DIRECTORY_SIGNATURE
) {
3451 tor_assert(tok
->n_args
>= 2);
3454 id_hexdigest
= tok
->args
[0];
3455 sk_hexdigest
= tok
->args
[1];
3456 } else if (tok
->tp
== K_ADDITIONAL_SIGNATURE
) {
3457 tor_assert(tok
->n_args
>= 4);
3458 flavor
= tok
->args
[0];
3459 algname
= tok
->args
[1];
3460 id_hexdigest
= tok
->args
[2];
3461 sk_hexdigest
= tok
->args
[3];
3467 int a
= crypto_digest_algorithm_parse_name(algname
);
3469 log_warn(LD_DIR
, "Unrecognized algorithm name %s", algname
);
3472 alg
= (digest_algorithm_t
) a
;
3475 if (!tok
->object_type
||
3476 strcmp(tok
->object_type
, "SIGNATURE") ||
3477 tok
->object_size
< 128 || tok
->object_size
> 512) {
3478 log_warn(LD_DIR
, "Bad object type or length on directory-signature");
3482 if (strlen(id_hexdigest
) != HEX_DIGEST_LEN
||
3483 base16_decode(id_digest
, sizeof(id_digest
),
3484 id_hexdigest
, HEX_DIGEST_LEN
) < 0) {
3485 log_warn(LD_DIR
, "Error decoding declared identity %s in "
3486 "network-status vote.", escaped(id_hexdigest
));
3489 if (strlen(sk_hexdigest
) != HEX_DIGEST_LEN
||
3490 base16_decode(sk_digest
, sizeof(sk_digest
),
3491 sk_hexdigest
, HEX_DIGEST_LEN
) < 0) {
3492 log_warn(LD_DIR
, "Error decoding declared signing key digest %s in "
3493 "network-status vote.", escaped(sk_hexdigest
));
3497 siglist
= detached_get_signatures(sigs
, flavor
);
3499 SMARTLIST_FOREACH(siglist
, document_signature_t
*, s
, {
3500 if (s
->alg
== alg
&&
3501 !memcmp(id_digest
, s
->identity_digest
, DIGEST_LEN
) &&
3502 !memcmp(sk_digest
, s
->signing_key_digest
, DIGEST_LEN
)) {
3507 log_warn(LD_DIR
, "Two signatures with identical keys and algorithm "
3512 sig
= tor_malloc_zero(sizeof(document_signature_t
));
3514 memcpy(sig
->identity_digest
, id_digest
, DIGEST_LEN
);
3515 memcpy(sig
->signing_key_digest
, sk_digest
, DIGEST_LEN
);
3516 if (tok
->object_size
>= INT_MAX
|| tok
->object_size
>= SIZE_T_CEILING
) {
3520 sig
->signature
= tor_memdup(tok
->object_body
, tok
->object_size
);
3521 sig
->signature_len
= (int) tok
->object_size
;
3523 smartlist_add(siglist
, sig
);
3524 } SMARTLIST_FOREACH_END(_tok
);
3528 ns_detached_signatures_free(sigs
);
3531 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
3532 smartlist_free(tokens
);
3534 DUMP_AREA(area
, "detached signatures");
3535 memarea_drop_all(area
);
3540 /** Parse the addr policy in the string <b>s</b> and return it. If
3541 * assume_action is nonnegative, then insert its action (ADDR_POLICY_ACCEPT or
3542 * ADDR_POLICY_REJECT) for items that specify no action.
3545 router_parse_addr_policy_item_from_string(const char *s
, int assume_action
)
3547 directory_token_t
*tok
= NULL
;
3548 const char *cp
, *eos
;
3549 /* Longest possible policy is "accept ffff:ffff:..255/ffff:...255:0-65535".
3550 * But note that there can be an arbitrary amount of space between the
3551 * accept and the address:mask/port element. */
3552 char line
[TOR_ADDR_BUF_LEN
*2 + 32];
3554 memarea_t
*area
= NULL
;
3556 s
= eat_whitespace(s
);
3557 if ((*s
== '*' || TOR_ISDIGIT(*s
)) && assume_action
>= 0) {
3558 if (tor_snprintf(line
, sizeof(line
), "%s %s",
3559 assume_action
== ADDR_POLICY_ACCEPT
?"accept":"reject", s
)<0) {
3560 log_warn(LD_DIR
, "Policy %s is too long.", escaped(s
));
3565 } else { /* assume an already well-formed address policy line */
3569 eos
= cp
+ strlen(cp
);
3570 area
= memarea_new();
3571 tok
= get_next_token(area
, &cp
, eos
, routerdesc_token_table
);
3572 if (tok
->tp
== _ERR
) {
3573 log_warn(LD_DIR
, "Error reading address policy: %s", tok
->error
);
3576 if (tok
->tp
!= K_ACCEPT
&& tok
->tp
!= K_ACCEPT6
&&
3577 tok
->tp
!= K_REJECT
&& tok
->tp
!= K_REJECT6
) {
3578 log_warn(LD_DIR
, "Expected 'accept' or 'reject'.");
3582 r
= router_parse_addr_policy(tok
);
3589 DUMP_AREA(area
, "policy item");
3590 memarea_drop_all(area
);
3595 /** Add an exit policy stored in the token <b>tok</b> to the router info in
3596 * <b>router</b>. Return 0 on success, -1 on failure. */
3598 router_add_exit_policy(routerinfo_t
*router
, directory_token_t
*tok
)
3600 addr_policy_t
*newe
;
3601 newe
= router_parse_addr_policy(tok
);
3604 if (! router
->exit_policy
)
3605 router
->exit_policy
= smartlist_create();
3607 if (((tok
->tp
== K_ACCEPT6
|| tok
->tp
== K_REJECT6
) &&
3608 tor_addr_family(&newe
->addr
) == AF_INET
)
3610 ((tok
->tp
== K_ACCEPT
|| tok
->tp
== K_REJECT
) &&
3611 tor_addr_family(&newe
->addr
) == AF_INET6
)) {
3612 log_warn(LD_DIR
, "Mismatch between field type and address type in exit "
3614 addr_policy_free(newe
);
3618 smartlist_add(router
->exit_policy
, newe
);
3623 /** Given a K_ACCEPT or K_REJECT token and a router, create and return
3624 * a new exit_policy_t corresponding to the token. */
3625 static addr_policy_t
*
3626 router_parse_addr_policy(directory_token_t
*tok
)
3631 tor_assert(tok
->tp
== K_REJECT
|| tok
->tp
== K_REJECT6
||
3632 tok
->tp
== K_ACCEPT
|| tok
->tp
== K_ACCEPT6
);
3634 if (tok
->n_args
!= 1)
3638 if (!strcmpstart(arg
,"private"))
3639 return router_parse_addr_policy_private(tok
);
3641 memset(&newe
, 0, sizeof(newe
));
3643 if (tok
->tp
== K_REJECT
|| tok
->tp
== K_REJECT6
)
3644 newe
.policy_type
= ADDR_POLICY_REJECT
;
3646 newe
.policy_type
= ADDR_POLICY_ACCEPT
;
3648 if (tor_addr_parse_mask_ports(arg
, &newe
.addr
, &newe
.maskbits
,
3649 &newe
.prt_min
, &newe
.prt_max
) < 0) {
3650 log_warn(LD_DIR
,"Couldn't parse line %s. Dropping", escaped(arg
));
3654 return addr_policy_get_canonical_entry(&newe
);
3657 /** Parse an exit policy line of the format "accept/reject private:...".
3658 * This didn't exist until Tor 0.1.1.15, so nobody should generate it in
3659 * router descriptors until earlier versions are obsolete.
3661 static addr_policy_t
*
3662 router_parse_addr_policy_private(directory_token_t
*tok
)
3665 uint16_t port_min
, port_max
;
3666 addr_policy_t result
;
3669 if (strcmpstart(arg
, "private"))
3672 arg
+= strlen("private");
3673 arg
= (char*) eat_whitespace(arg
);
3674 if (!arg
|| *arg
!= ':')
3677 if (parse_port_range(arg
+1, &port_min
, &port_max
)<0)
3680 memset(&result
, 0, sizeof(result
));
3681 if (tok
->tp
== K_REJECT
|| tok
->tp
== K_REJECT6
)
3682 result
.policy_type
= ADDR_POLICY_REJECT
;
3684 result
.policy_type
= ADDR_POLICY_ACCEPT
;
3685 result
.is_private
= 1;
3686 result
.prt_min
= port_min
;
3687 result
.prt_max
= port_max
;
3689 return addr_policy_get_canonical_entry(&result
);
3692 /** Log and exit if <b>t</b> is malformed */
3694 assert_addr_policy_ok(smartlist_t
*lst
)
3697 SMARTLIST_FOREACH(lst
, addr_policy_t
*, t
, {
3698 tor_assert(t
->policy_type
== ADDR_POLICY_REJECT
||
3699 t
->policy_type
== ADDR_POLICY_ACCEPT
);
3700 tor_assert(t
->prt_min
<= t
->prt_max
);
3705 * Low-level tokenizer for router descriptors and directories.
3708 /** Free all resources allocated for <b>tok</b> */
3710 token_clear(directory_token_t
*tok
)
3713 crypto_free_pk_env(tok
->key
);
3716 #define ALLOC_ZERO(sz) memarea_alloc_zero(area,sz)
3717 #define ALLOC(sz) memarea_alloc(area,sz)
3718 #define STRDUP(str) memarea_strdup(area,str)
3719 #define STRNDUP(str,n) memarea_strndup(area,(str),(n))
3721 #define RET_ERR(msg) \
3723 if (tok) token_clear(tok); \
3724 tok = ALLOC_ZERO(sizeof(directory_token_t)); \
3726 tok->error = STRDUP(msg); \
3727 goto done_tokenizing; \
3730 /** Helper: make sure that the token <b>tok</b> with keyword <b>kwd</b> obeys
3731 * the object syntax of <b>o_syn</b>. Allocate all storage in <b>area</b>.
3732 * Return <b>tok</b> on success, or a new _ERR token if the token didn't
3733 * conform to the syntax we wanted.
3735 static INLINE directory_token_t
*
3736 token_check_object(memarea_t
*area
, const char *kwd
,
3737 directory_token_t
*tok
, obj_syntax o_syn
)
3742 /* No object is allowed for this token. */
3743 if (tok
->object_body
) {
3744 tor_snprintf(ebuf
, sizeof(ebuf
), "Unexpected object for %s", kwd
);
3748 tor_snprintf(ebuf
, sizeof(ebuf
), "Unexpected public key for %s", kwd
);
3753 /* There must be a (non-key) object. */
3754 if (!tok
->object_body
) {
3755 tor_snprintf(ebuf
, sizeof(ebuf
), "Missing object for %s", kwd
);
3759 case NEED_KEY_1024
: /* There must be a 1024-bit public key. */
3760 case NEED_SKEY_1024
: /* There must be a 1024-bit private key. */
3761 if (tok
->key
&& crypto_pk_keysize(tok
->key
) != PK_BYTES
) {
3762 tor_snprintf(ebuf
, sizeof(ebuf
), "Wrong size on key for %s: %d bits",
3763 kwd
, (int)crypto_pk_keysize(tok
->key
));
3767 case NEED_KEY
: /* There must be some kind of key. */
3769 tor_snprintf(ebuf
, sizeof(ebuf
), "Missing public key for %s", kwd
);
3772 if (o_syn
!= NEED_SKEY_1024
) {
3773 if (crypto_pk_key_is_private(tok
->key
)) {
3774 tor_snprintf(ebuf
, sizeof(ebuf
),
3775 "Private key given for %s, which wants a public key", kwd
);
3778 } else { /* o_syn == NEED_SKEY_1024 */
3779 if (!crypto_pk_key_is_private(tok
->key
)) {
3780 tor_snprintf(ebuf
, sizeof(ebuf
),
3781 "Public key given for %s, which wants a private key", kwd
);
3787 /* Anything goes with this token. */
3795 /** Helper: parse space-separated arguments from the string <b>s</b> ending at
3796 * <b>eol</b>, and store them in the args field of <b>tok</b>. Store the
3797 * number of parsed elements into the n_args field of <b>tok</b>. Allocate
3798 * all storage in <b>area</b>. Return the number of arguments parsed, or
3799 * return -1 if there was an insanely high number of arguments. */
3801 get_token_arguments(memarea_t
*area
, directory_token_t
*tok
,
3802 const char *s
, const char *eol
)
3804 /** Largest number of arguments we'll accept to any token, ever. */
3805 #define MAX_ARGS 512
3806 char *mem
= memarea_strndup(area
, s
, eol
-s
);
3809 char *args
[MAX_ARGS
];
3814 cp
= (char*)find_whitespace(cp
);
3816 break; /* End of the line. */
3818 cp
= (char*)eat_whitespace(cp
);
3821 tok
->args
= memarea_memdup(area
, args
, j
*sizeof(char*));
3826 /** Helper function: read the next token from *s, advance *s to the end of the
3827 * token, and return the parsed token. Parse *<b>s</b> according to the list
3828 * of tokens in <b>table</b>.
3830 static directory_token_t
*
3831 get_next_token(memarea_t
*area
,
3832 const char **s
, const char *eos
, token_rule_t
*table
)
3834 /** Reject any object at least this big; it is probably an overflow, an
3835 * attack, a bug, or some other nonsense. */
3836 #define MAX_UNPARSED_OBJECT_SIZE (128*1024)
3837 /** Reject any line at least this big; it is probably an overflow, an
3838 * attack, a bug, or some other nonsense. */
3839 #define MAX_LINE_LENGTH (128*1024)
3841 const char *next
, *eol
, *obstart
;
3844 directory_token_t
*tok
;
3845 obj_syntax o_syn
= NO_OBJ
;
3847 const char *kwd
= "";
3850 tok
= ALLOC_ZERO(sizeof(directory_token_t
));
3853 /* Set *s to first token, eol to end-of-line, next to after first token */
3854 *s
= eat_whitespace_eos(*s
, eos
); /* eat multi-line whitespace */
3855 tor_assert(eos
>= *s
);
3856 eol
= memchr(*s
, '\n', eos
-*s
);
3859 if (eol
- *s
> MAX_LINE_LENGTH
) {
3860 RET_ERR("Line far too long");
3863 next
= find_whitespace_eos(*s
, eol
);
3865 if (!strcmp_len(*s
, "opt", next
-*s
)) {
3866 /* Skip past an "opt" at the start of the line. */
3867 *s
= eat_whitespace_eos_no_nl(next
, eol
);
3868 next
= find_whitespace_eos(*s
, eol
);
3869 } else if (*s
== eos
) { /* If no "opt", and end-of-line, line is invalid */
3870 RET_ERR("Unexpected EOF");
3873 /* Search the table for the appropriate entry. (I tried a binary search
3874 * instead, but it wasn't any faster.) */
3875 for (i
= 0; table
[i
].t
; ++i
) {
3876 if (!strcmp_len(*s
, table
[i
].t
, next
-*s
)) {
3877 /* We've found the keyword. */
3879 tok
->tp
= table
[i
].v
;
3880 o_syn
= table
[i
].os
;
3881 *s
= eat_whitespace_eos_no_nl(next
, eol
);
3882 /* We go ahead whether there are arguments or not, so that tok->args is
3883 * always set if we want arguments. */
3884 if (table
[i
].concat_args
) {
3885 /* The keyword takes the line as a single argument */
3886 tok
->args
= ALLOC(sizeof(char*));
3887 tok
->args
[0] = STRNDUP(*s
,eol
-*s
); /* Grab everything on line */
3890 /* This keyword takes multiple arguments. */
3891 if (get_token_arguments(area
, tok
, *s
, eol
)<0) {
3892 tor_snprintf(ebuf
, sizeof(ebuf
),"Far too many arguments to %s", kwd
);
3897 if (tok
->n_args
< table
[i
].min_args
) {
3898 tor_snprintf(ebuf
, sizeof(ebuf
), "Too few arguments to %s", kwd
);
3900 } else if (tok
->n_args
> table
[i
].max_args
) {
3901 tor_snprintf(ebuf
, sizeof(ebuf
), "Too many arguments to %s", kwd
);
3908 if (tok
->tp
== _ERR
) {
3909 /* No keyword matched; call it an "K_opt" or "A_unrecognized" */
3911 tok
->tp
= _A_UNKNOWN
;
3914 tok
->args
= ALLOC(sizeof(char*));
3915 tok
->args
[0] = STRNDUP(*s
, eol
-*s
);
3920 /* Check whether there's an object present */
3921 *s
= eat_whitespace_eos(eol
, eos
); /* Scan from end of first line */
3922 tor_assert(eos
>= *s
);
3923 eol
= memchr(*s
, '\n', eos
-*s
);
3924 if (!eol
|| eol
-*s
<11 || strcmpstart(*s
, "-----BEGIN ")) /* No object. */
3927 obstart
= *s
; /* Set obstart to start of object spec */
3928 if (*s
+16 >= eol
|| memchr(*s
+11,'\0',eol
-*s
-16) || /* no short lines, */
3929 strcmp_len(eol
-5, "-----", 5) || /* nuls or invalid endings */
3930 (eol
-*s
) > MAX_UNPARSED_OBJECT_SIZE
) { /* name too long */
3931 RET_ERR("Malformed object: bad begin line");
3933 tok
->object_type
= STRNDUP(*s
+11, eol
-*s
-16);
3934 obname_len
= eol
-*s
-16; /* store objname length here to avoid a strlen() */
3935 *s
= eol
+1; /* Set *s to possible start of object data (could be eos) */
3937 /* Go to the end of the object */
3938 next
= tor_memstr(*s
, eos
-*s
, "-----END ");
3940 RET_ERR("Malformed object: missing object end line");
3942 tor_assert(eos
>= next
);
3943 eol
= memchr(next
, '\n', eos
-next
);
3944 if (!eol
) /* end-of-line marker, or eos if there's no '\n' */
3946 /* Validate the ending tag, which should be 9 + NAME + 5 + eol */
3947 if ((size_t)(eol
-next
) != 9+obname_len
+5 ||
3948 strcmp_len(next
+9, tok
->object_type
, obname_len
) ||
3949 strcmp_len(eol
-5, "-----", 5)) {
3950 snprintf(ebuf
, sizeof(ebuf
), "Malformed object: mismatched end tag %s",
3952 ebuf
[sizeof(ebuf
)-1] = '\0';
3955 if (next
- *s
> MAX_UNPARSED_OBJECT_SIZE
)
3956 RET_ERR("Couldn't parse object: missing footer or object much too big.");
3958 if (!strcmp(tok
->object_type
, "RSA PUBLIC KEY")) { /* If it's a public key */
3959 tok
->key
= crypto_new_pk_env();
3960 if (crypto_pk_read_public_key_from_string(tok
->key
, obstart
, eol
-obstart
))
3961 RET_ERR("Couldn't parse public key.");
3962 } else if (!strcmp(tok
->object_type
, "RSA PRIVATE KEY")) { /* private key */
3963 tok
->key
= crypto_new_pk_env();
3964 if (crypto_pk_read_private_key_from_string(tok
->key
, obstart
, eol
-obstart
))
3965 RET_ERR("Couldn't parse private key.");
3966 } else { /* If it's something else, try to base64-decode it */
3968 tok
->object_body
= ALLOC(next
-*s
); /* really, this is too much RAM. */
3969 r
= base64_decode(tok
->object_body
, next
-*s
, *s
, next
-*s
);
3971 RET_ERR("Malformed object: bad base64-encoded data");
3972 tok
->object_size
= r
;
3977 tok
= token_check_object(area
, kwd
, tok
, o_syn
);
3989 /** Read all tokens from a string between <b>start</b> and <b>end</b>, and add
3990 * them to <b>out</b>. Parse according to the token rules in <b>table</b>.
3991 * Caller must free tokens in <b>out</b>. If <b>end</b> is NULL, use the
3995 tokenize_string(memarea_t
*area
,
3996 const char *start
, const char *end
, smartlist_t
*out
,
3997 token_rule_t
*table
, int flags
)
4000 directory_token_t
*tok
= NULL
;
4003 int first_nonannotation
;
4004 int prev_len
= smartlist_len(out
);
4009 end
= start
+strlen(start
);
4010 for (i
= 0; i
< _NIL
; ++i
)
4013 SMARTLIST_FOREACH(out
, const directory_token_t
*, t
, ++counts
[t
->tp
]);
4015 while (*s
< end
&& (!tok
|| tok
->tp
!= _EOF
)) {
4016 tok
= get_next_token(area
, s
, end
, table
);
4017 if (tok
->tp
== _ERR
) {
4018 log_warn(LD_DIR
, "parse error: %s", tok
->error
);
4023 smartlist_add(out
, tok
);
4024 *s
= eat_whitespace_eos(*s
, end
);
4027 if (flags
& TS_NOCHECK
)
4030 if ((flags
& TS_ANNOTATIONS_OK
)) {
4031 first_nonannotation
= -1;
4032 for (i
= 0; i
< smartlist_len(out
); ++i
) {
4033 tok
= smartlist_get(out
, i
);
4034 if (tok
->tp
< MIN_ANNOTATION
|| tok
->tp
> MAX_ANNOTATION
) {
4035 first_nonannotation
= i
;
4039 if (first_nonannotation
< 0) {
4040 log_warn(LD_DIR
, "parse error: item contains only annotations");
4043 for (i
=first_nonannotation
; i
< smartlist_len(out
); ++i
) {
4044 tok
= smartlist_get(out
, i
);
4045 if (tok
->tp
>= MIN_ANNOTATION
&& tok
->tp
<= MAX_ANNOTATION
) {
4046 log_warn(LD_DIR
, "parse error: Annotations mixed with keywords");
4050 if ((flags
& TS_NO_NEW_ANNOTATIONS
)) {
4051 if (first_nonannotation
!= prev_len
) {
4052 log_warn(LD_DIR
, "parse error: Unexpected annotations.");
4057 for (i
=0; i
< smartlist_len(out
); ++i
) {
4058 tok
= smartlist_get(out
, i
);
4059 if (tok
->tp
>= MIN_ANNOTATION
&& tok
->tp
<= MAX_ANNOTATION
) {
4060 log_warn(LD_DIR
, "parse error: no annotations allowed.");
4064 first_nonannotation
= 0;
4066 for (i
= 0; table
[i
].t
; ++i
) {
4067 if (counts
[table
[i
].v
] < table
[i
].min_cnt
) {
4068 log_warn(LD_DIR
, "Parse error: missing %s element.", table
[i
].t
);
4071 if (counts
[table
[i
].v
] > table
[i
].max_cnt
) {
4072 log_warn(LD_DIR
, "Parse error: too many %s elements.", table
[i
].t
);
4075 if (table
[i
].pos
& AT_START
) {
4076 if (smartlist_len(out
) < 1 ||
4077 (tok
= smartlist_get(out
, first_nonannotation
))->tp
!= table
[i
].v
) {
4078 log_warn(LD_DIR
, "Parse error: first item is not %s.", table
[i
].t
);
4082 if (table
[i
].pos
& AT_END
) {
4083 if (smartlist_len(out
) < 1 ||
4084 (tok
= smartlist_get(out
, smartlist_len(out
)-1))->tp
!= table
[i
].v
) {
4085 log_warn(LD_DIR
, "Parse error: last item is not %s.", table
[i
].t
);
4093 /** Find the first token in <b>s</b> whose keyword is <b>keyword</b>; return
4094 * NULL if no such keyword is found.
4096 static directory_token_t
*
4097 find_opt_by_keyword(smartlist_t
*s
, directory_keyword keyword
)
4099 SMARTLIST_FOREACH(s
, directory_token_t
*, t
, if (t
->tp
== keyword
) return t
);
4103 /** Find the first token in <b>s</b> whose keyword is <b>keyword</b>; fail
4104 * with an assert if no such keyword is found.
4106 static directory_token_t
*
4107 _find_by_keyword(smartlist_t
*s
, directory_keyword keyword
,
4108 const char *keyword_as_string
)
4110 directory_token_t
*tok
= find_opt_by_keyword(s
, keyword
);
4111 if (PREDICT_UNLIKELY(!tok
)) {
4112 log_err(LD_BUG
, "Missing %s [%d] in directory object that should have "
4113 "been validated. Internal error.", keyword_as_string
, (int)keyword
);
4119 /** Return a newly allocated smartlist of all accept or reject tokens in
4122 static smartlist_t
*
4123 find_all_exitpolicy(smartlist_t
*s
)
4125 smartlist_t
*out
= smartlist_create();
4126 SMARTLIST_FOREACH(s
, directory_token_t
*, t
,
4127 if (t
->tp
== K_ACCEPT
|| t
->tp
== K_ACCEPT6
||
4128 t
->tp
== K_REJECT
|| t
->tp
== K_REJECT6
)
4129 smartlist_add(out
,t
));
4134 router_get_hash_impl_helper(const char *s
, size_t s_len
,
4135 const char *start_str
,
4136 const char *end_str
, char end_c
,
4137 const char **start_out
, const char **end_out
)
4139 const char *start
, *end
;
4140 start
= tor_memstr(s
, s_len
, start_str
);
4142 log_warn(LD_DIR
,"couldn't find start of hashed material \"%s\"",start_str
);
4145 if (start
!= s
&& *(start
-1) != '\n') {
4147 "first occurrence of \"%s\" is not at the start of a line",
4151 end
= tor_memstr(start
+strlen(start_str
),
4152 s_len
- (start
-s
) - strlen(start_str
), end_str
);
4154 log_warn(LD_DIR
,"couldn't find end of hashed material \"%s\"",end_str
);
4157 end
= memchr(end
+strlen(end_str
), end_c
, s_len
- (end
-s
) - strlen(end_str
));
4159 log_warn(LD_DIR
,"couldn't find EOL");
4169 /** Compute the digest of the substring of <b>s</b> taken from the first
4170 * occurrence of <b>start_str</b> through the first instance of c after the
4171 * first subsequent occurrence of <b>end_str</b>; store the 20-byte result in
4172 * <b>digest</b>; return 0 on success.
4174 * If no such substring exists, return -1.
4177 router_get_hash_impl(const char *s
, size_t s_len
, char *digest
,
4178 const char *start_str
,
4179 const char *end_str
, char end_c
,
4180 digest_algorithm_t alg
)
4182 const char *start
=NULL
, *end
=NULL
;
4183 if (router_get_hash_impl_helper(s
,s_len
,start_str
,end_str
,end_c
,
4187 if (alg
== DIGEST_SHA1
) {
4188 if (crypto_digest(digest
, start
, end
-start
)) {
4189 log_warn(LD_BUG
,"couldn't compute digest");
4193 if (crypto_digest256(digest
, start
, end
-start
, alg
)) {
4194 log_warn(LD_BUG
,"couldn't compute digest");
4202 /** As router_get_hash_impl, but compute all hashes. */
4204 router_get_hashes_impl(const char *s
, size_t s_len
, digests_t
*digests
,
4205 const char *start_str
,
4206 const char *end_str
, char end_c
)
4208 const char *start
=NULL
, *end
=NULL
;
4209 if (router_get_hash_impl_helper(s
,s_len
,start_str
,end_str
,end_c
,
4213 if (crypto_digest_all(digests
, start
, end
-start
)) {
4214 log_warn(LD_BUG
,"couldn't compute digests");
4221 /** Assuming that s starts with a microdesc, return the start of the
4222 * *NEXT* one. Return NULL on "not found." */
4224 find_start_of_next_microdesc(const char *s
, const char *eos
)
4226 int started_with_annotations
;
4227 s
= eat_whitespace_eos(s
, eos
);
4231 #define CHECK_LENGTH() STMT_BEGIN \
4236 #define NEXT_LINE() STMT_BEGIN \
4237 s = memchr(s, '\n', eos-s); \
4238 if (!s || s+1 >= eos) \
4245 started_with_annotations
= (*s
== '@');
4247 if (started_with_annotations
) {
4248 /* Start by advancing to the first non-annotation line. */
4254 /* Now we should be pointed at an onion-key line. If we are, then skip
4256 if (!strcmpstart(s
, "onion-key"))
4259 /* Okay, now we're pointed at the first line of the microdescriptor which is
4260 not an annotation or onion-key. The next line that _is_ an annotation or
4261 onion-key is the start of the next microdescriptor. */
4262 while (s
+32 < eos
) {
4263 if (*s
== '@' || !strcmpstart(s
, "onion-key"))
4273 /** Parse as many microdescriptors as are found from the string starting at
4274 * <b>s</b> and ending at <b>eos</b>. If allow_annotations is set, read any
4275 * annotations we recognize and ignore ones we don't. If <b>copy_body</b> is
4276 * true, then strdup the bodies of the microdescriptors. Return all newly
4277 * parsed microdescriptors in a newly allocated smartlist_t. */
4279 microdescs_parse_from_string(const char *s
, const char *eos
,
4280 int allow_annotations
, int copy_body
)
4282 smartlist_t
*tokens
;
4283 smartlist_t
*result
;
4284 microdesc_t
*md
= NULL
;
4286 const char *start
= s
;
4287 const char *start_of_next_microdesc
;
4288 int flags
= allow_annotations
? TS_ANNOTATIONS_OK
: 0;
4290 directory_token_t
*tok
;
4293 eos
= s
+ strlen(s
);
4295 s
= eat_whitespace_eos(s
, eos
);
4296 area
= memarea_new();
4297 result
= smartlist_create();
4298 tokens
= smartlist_create();
4301 start_of_next_microdesc
= find_start_of_next_microdesc(s
, eos
);
4302 if (!start_of_next_microdesc
)
4303 start_of_next_microdesc
= eos
;
4305 if (tokenize_string(area
, s
, start_of_next_microdesc
, tokens
,
4306 microdesc_token_table
, flags
)) {
4307 log_warn(LD_DIR
, "Unparseable microdescriptor");
4311 md
= tor_malloc_zero(sizeof(microdesc_t
));
4313 const char *cp
= tor_memstr(s
, start_of_next_microdesc
-s
,
4317 md
->bodylen
= start_of_next_microdesc
- cp
;
4319 md
->body
= tor_strndup(cp
, md
->bodylen
);
4321 md
->body
= (char*)cp
;
4322 md
->off
= cp
- start
;
4325 if ((tok
= find_opt_by_keyword(tokens
, A_LAST_LISTED
))) {
4326 if (parse_iso_time(tok
->args
[0], &md
->last_listed
)) {
4327 log_warn(LD_DIR
, "Bad last-listed time in microdescriptor");
4332 tok
= find_by_keyword(tokens
, K_ONION_KEY
);
4333 md
->onion_pkey
= tok
->key
;
4336 if ((tok
= find_opt_by_keyword(tokens
, K_FAMILY
))) {
4338 md
->family
= smartlist_create();
4339 for (i
=0;i
<tok
->n_args
;++i
) {
4340 if (!is_legal_nickname_or_hexdigest(tok
->args
[i
])) {
4341 log_warn(LD_DIR
, "Illegal nickname %s in family line",
4342 escaped(tok
->args
[i
]));
4345 smartlist_add(md
->family
, tor_strdup(tok
->args
[i
]));
4349 if ((tok
= find_opt_by_keyword(tokens
, K_P
))) {
4350 md
->exitsummary
= tor_strdup(tok
->args
[0]);
4353 crypto_digest256(md
->digest
, md
->body
, md
->bodylen
, DIGEST_SHA256
);
4355 smartlist_add(result
, md
);
4362 memarea_clear(area
);
4363 smartlist_clear(tokens
);
4364 s
= start_of_next_microdesc
;
4367 memarea_drop_all(area
);
4368 smartlist_free(tokens
);
4373 /** Parse the Tor version of the platform string <b>platform</b>,
4374 * and compare it to the version in <b>cutoff</b>. Return 1 if
4375 * the router is at least as new as the cutoff, else return 0.
4378 tor_version_as_new_as(const char *platform
, const char *cutoff
)
4380 tor_version_t cutoff_version
, router_version
;
4381 char *s
, *s2
, *start
;
4384 tor_assert(platform
);
4386 if (tor_version_parse(cutoff
, &cutoff_version
)<0) {
4387 log_warn(LD_BUG
,"cutoff version '%s' unparseable.",cutoff
);
4390 if (strcmpstart(platform
,"Tor ")) /* nonstandard Tor; be safe and say yes */
4393 start
= (char *)eat_whitespace(platform
+3);
4394 if (!*start
) return 0;
4395 s
= (char *)find_whitespace(start
); /* also finds '\0', which is fine */
4396 s2
= (char*)eat_whitespace(s
);
4397 if (!strcmpstart(s2
, "(r") || !strcmpstart(s2
, "(git-"))
4398 s
= (char*)find_whitespace(s2
);
4400 if ((size_t)(s
-start
+1) >= sizeof(tmp
)) /* too big, no */
4402 strlcpy(tmp
, start
, s
-start
+1);
4404 if (tor_version_parse(tmp
, &router_version
)<0) {
4405 log_info(LD_DIR
,"Router version '%s' unparseable.",tmp
);
4406 return 1; /* be safe and say yes */
4409 /* Here's why we don't need to do any special handling for svn revisions:
4410 * - If neither has an svn revision, we're fine.
4411 * - If the router doesn't have an svn revision, we can't assume that it
4412 * is "at least" any svn revision, so we need to return 0.
4413 * - If the target version doesn't have an svn revision, any svn revision
4414 * (or none at all) is good enough, so return 1.
4415 * - If both target and router have an svn revision, we compare them.
4418 return tor_version_compare(&router_version
, &cutoff_version
) >= 0;
4421 /** Parse a tor version from <b>s</b>, and store the result in <b>out</b>.
4422 * Return 0 on success, -1 on failure. */
4424 tor_version_parse(const char *s
, tor_version_t
*out
)
4427 const char *cp
=NULL
;
4429 * "Tor " ? NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ - tag ] ]
4434 memset(out
, 0, sizeof(tor_version_t
));
4436 if (!strcasecmpstart(s
, "Tor "))
4440 out
->major
= (int)strtol(s
,&eos
,10);
4441 if (!eos
|| eos
==s
|| *eos
!= '.') return -1;
4445 out
->minor
= (int) strtol(cp
,&eos
,10);
4446 if (!eos
|| eos
==cp
|| *eos
!= '.') return -1;
4450 out
->micro
= (int) strtol(cp
,&eos
,10);
4451 if (!eos
|| eos
==cp
) return -1;
4453 out
->status
= VER_RELEASE
;
4454 out
->patchlevel
= 0;
4461 out
->status
= VER_RELEASE
;
4463 } else if (0==strncmp(cp
, "pre", 3)) {
4464 out
->status
= VER_PRE
;
4466 } else if (0==strncmp(cp
, "rc", 2)) {
4467 out
->status
= VER_RC
;
4473 /* Get patchlevel */
4474 out
->patchlevel
= (int) strtol(cp
,&eos
,10);
4475 if (!eos
|| eos
==cp
) return -1;
4478 /* Get status tag. */
4479 if (*cp
== '-' || *cp
== '.')
4481 eos
= (char*) find_whitespace(cp
);
4482 if (eos
-cp
>= (int)sizeof(out
->status_tag
))
4483 strlcpy(out
->status_tag
, cp
, sizeof(out
->status_tag
));
4485 memcpy(out
->status_tag
, cp
, eos
-cp
);
4486 out
->status_tag
[eos
-cp
] = 0;
4488 cp
= eat_whitespace(eos
);
4490 if (!strcmpstart(cp
, "(r")) {
4492 out
->svn_revision
= (int) strtol(cp
,&eos
,10);
4493 } else if (!strcmpstart(cp
, "(git-")) {
4494 char *close_paren
= strchr(cp
, ')');
4496 char digest
[DIGEST_LEN
];
4500 if (close_paren
-cp
> HEX_DIGEST_LEN
)
4502 hexlen
= (int)(close_paren
-cp
);
4503 memset(digest
, 0, sizeof(digest
));
4504 if ( hexlen
== 0 || (hexlen
% 2) == 1)
4506 if (base16_decode(digest
, hexlen
/2, cp
, hexlen
))
4508 memcpy(out
->git_tag
, digest
, hexlen
/2);
4509 out
->git_tag_len
= hexlen
/2;
4515 /** Compare two tor versions; Return <0 if a < b; 0 if a ==b, >0 if a >
4518 tor_version_compare(tor_version_t
*a
, tor_version_t
*b
)
4523 if ((i
= a
->major
- b
->major
))
4525 else if ((i
= a
->minor
- b
->minor
))
4527 else if ((i
= a
->micro
- b
->micro
))
4529 else if ((i
= a
->status
- b
->status
))
4531 else if ((i
= a
->patchlevel
- b
->patchlevel
))
4533 else if ((i
= strcmp(a
->status_tag
, b
->status_tag
)))
4535 else if ((i
= a
->svn_revision
- b
->svn_revision
))
4537 else if ((i
= a
->git_tag_len
- b
->git_tag_len
))
4539 else if (a
->git_tag_len
)
4540 return memcmp(a
->git_tag
, b
->git_tag
, a
->git_tag_len
);
4545 /** Return true iff versions <b>a</b> and <b>b</b> belong to the same series.
4548 tor_version_same_series(tor_version_t
*a
, tor_version_t
*b
)
4552 return ((a
->major
== b
->major
) &&
4553 (a
->minor
== b
->minor
) &&
4554 (a
->micro
== b
->micro
));
4557 /** Helper: Given pointers to two strings describing tor versions, return -1
4558 * if _a precedes _b, 1 if _b precedes _a, and 0 if they are equivalent.
4559 * Used to sort a list of versions. */
4561 _compare_tor_version_str_ptr(const void **_a
, const void **_b
)
4563 const char *a
= *_a
, *b
= *_b
;
4565 tor_version_t va
, vb
;
4566 ca
= tor_version_parse(a
, &va
);
4567 cb
= tor_version_parse(b
, &vb
);
4568 /* If they both parse, compare them. */
4570 return tor_version_compare(&va
,&vb
);
4571 /* If one parses, it comes first. */
4576 /* If neither parses, compare strings. Also, the directory server admin
4577 ** needs to be smacked upside the head. But Tor is tolerant and gentle. */
4581 /** Sort a list of string-representations of versions in ascending order. */
4583 sort_version_list(smartlist_t
*versions
, int remove_duplicates
)
4585 smartlist_sort(versions
, _compare_tor_version_str_ptr
);
4587 if (remove_duplicates
)
4588 smartlist_uniq(versions
, _compare_tor_version_str_ptr
, _tor_free
);
4591 /** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>,
4592 * write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the
4593 * binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the
4594 * encrypted introduction points to the newly allocated
4595 * *<b>intro_points_encrypted_out</b>, their encrypted size to
4596 * *<b>intro_points_encrypted_size_out</b>, the size of the encoded descriptor
4597 * to *<b>encoded_size_out</b>, and a pointer to the possibly next
4598 * descriptor to *<b>next_out</b>; return 0 for success (including validation)
4599 * and -1 for failure.
4602 rend_parse_v2_service_descriptor(rend_service_descriptor_t
**parsed_out
,
4604 char **intro_points_encrypted_out
,
4605 size_t *intro_points_encrypted_size_out
,
4606 size_t *encoded_size_out
,
4607 const char **next_out
, const char *desc
)
4609 rend_service_descriptor_t
*result
=
4610 tor_malloc_zero(sizeof(rend_service_descriptor_t
));
4611 char desc_hash
[DIGEST_LEN
];
4613 smartlist_t
*tokens
= smartlist_create();
4614 directory_token_t
*tok
;
4615 char secret_id_part
[DIGEST_LEN
];
4616 int i
, version
, num_ok
=1;
4617 smartlist_t
*versions
;
4618 char public_key_hash
[DIGEST_LEN
];
4619 char test_desc_id
[DIGEST_LEN
];
4620 memarea_t
*area
= NULL
;
4622 /* Check if desc starts correctly. */
4623 if (strncmp(desc
, "rendezvous-service-descriptor ",
4624 strlen("rendezvous-service-descriptor "))) {
4625 log_info(LD_REND
, "Descriptor does not start correctly.");
4628 /* Compute descriptor hash for later validation. */
4629 if (router_get_hash_impl(desc
, strlen(desc
), desc_hash
,
4630 "rendezvous-service-descriptor ",
4631 "\nsignature", '\n', DIGEST_SHA1
) < 0) {
4632 log_warn(LD_REND
, "Couldn't compute descriptor hash.");
4635 /* Determine end of string. */
4636 eos
= strstr(desc
, "\nrendezvous-service-descriptor ");
4638 eos
= desc
+ strlen(desc
);
4642 if (eos
-desc
> REND_DESC_MAX_SIZE
) {
4643 /* XXX023 If we are parsing this descriptor as a server, this
4644 * should be a protocol warning. */
4645 log_warn(LD_REND
, "Descriptor length is %d which exceeds "
4646 "maximum rendezvous descriptor size of %d bytes.",
4647 (int)(eos
-desc
), REND_DESC_MAX_SIZE
);
4650 /* Tokenize descriptor. */
4651 area
= memarea_new();
4652 if (tokenize_string(area
, desc
, eos
, tokens
, desc_token_table
, 0)) {
4653 log_warn(LD_REND
, "Error tokenizing descriptor.");
4656 /* Set next to next descriptor, if available. */
4658 /* Set length of encoded descriptor. */
4659 *encoded_size_out
= eos
- desc
;
4660 /* Check min allowed length of token list. */
4661 if (smartlist_len(tokens
) < 7) {
4662 log_warn(LD_REND
, "Impossibly short descriptor.");
4665 /* Parse base32-encoded descriptor ID. */
4666 tok
= find_by_keyword(tokens
, R_RENDEZVOUS_SERVICE_DESCRIPTOR
);
4667 tor_assert(tok
== smartlist_get(tokens
, 0));
4668 tor_assert(tok
->n_args
== 1);
4669 if (strlen(tok
->args
[0]) != REND_DESC_ID_V2_LEN_BASE32
||
4670 strspn(tok
->args
[0], BASE32_CHARS
) != REND_DESC_ID_V2_LEN_BASE32
) {
4671 log_warn(LD_REND
, "Invalid descriptor ID: '%s'", tok
->args
[0]);
4674 if (base32_decode(desc_id_out
, DIGEST_LEN
,
4675 tok
->args
[0], REND_DESC_ID_V2_LEN_BASE32
) < 0) {
4676 log_warn(LD_REND
, "Descriptor ID contains illegal characters: %s",
4680 /* Parse descriptor version. */
4681 tok
= find_by_keyword(tokens
, R_VERSION
);
4682 tor_assert(tok
->n_args
== 1);
4684 (int) tor_parse_long(tok
->args
[0], 10, 0, INT_MAX
, &num_ok
, NULL
);
4685 if (result
->version
!= 2 || !num_ok
) {
4686 /* If it's <2, it shouldn't be under this format. If the number
4687 * is greater than 2, we bumped it because we broke backward
4688 * compatibility. See how version numbers in our other formats
4690 log_warn(LD_REND
, "Unrecognized descriptor version: %s",
4691 escaped(tok
->args
[0]));
4694 /* Parse public key. */
4695 tok
= find_by_keyword(tokens
, R_PERMANENT_KEY
);
4696 result
->pk
= tok
->key
;
4697 tok
->key
= NULL
; /* Prevent free */
4698 /* Parse secret ID part. */
4699 tok
= find_by_keyword(tokens
, R_SECRET_ID_PART
);
4700 tor_assert(tok
->n_args
== 1);
4701 if (strlen(tok
->args
[0]) != REND_SECRET_ID_PART_LEN_BASE32
||
4702 strspn(tok
->args
[0], BASE32_CHARS
) != REND_SECRET_ID_PART_LEN_BASE32
) {
4703 log_warn(LD_REND
, "Invalid secret ID part: '%s'", tok
->args
[0]);
4706 if (base32_decode(secret_id_part
, DIGEST_LEN
, tok
->args
[0], 32) < 0) {
4707 log_warn(LD_REND
, "Secret ID part contains illegal characters: %s",
4711 /* Parse publication time -- up-to-date check is done when storing the
4713 tok
= find_by_keyword(tokens
, R_PUBLICATION_TIME
);
4714 tor_assert(tok
->n_args
== 1);
4715 if (parse_iso_time(tok
->args
[0], &result
->timestamp
) < 0) {
4716 log_warn(LD_REND
, "Invalid publication time: '%s'", tok
->args
[0]);
4719 /* Parse protocol versions. */
4720 tok
= find_by_keyword(tokens
, R_PROTOCOL_VERSIONS
);
4721 tor_assert(tok
->n_args
== 1);
4722 versions
= smartlist_create();
4723 smartlist_split_string(versions
, tok
->args
[0], ",",
4724 SPLIT_SKIP_SPACE
|SPLIT_IGNORE_BLANK
, 0);
4725 for (i
= 0; i
< smartlist_len(versions
); i
++) {
4726 version
= (int) tor_parse_long(smartlist_get(versions
, i
),
4727 10, 0, INT_MAX
, &num_ok
, NULL
);
4728 if (!num_ok
) /* It's a string; let's ignore it. */
4730 result
->protocols
|= 1 << version
;
4732 SMARTLIST_FOREACH(versions
, char *, cp
, tor_free(cp
));
4733 smartlist_free(versions
);
4734 /* Parse encrypted introduction points. Don't verify. */
4735 tok
= find_opt_by_keyword(tokens
, R_INTRODUCTION_POINTS
);
4737 if (strcmp(tok
->object_type
, "MESSAGE")) {
4738 log_warn(LD_DIR
, "Bad object type: introduction points should be of "
4742 *intro_points_encrypted_out
= tor_memdup(tok
->object_body
,
4744 *intro_points_encrypted_size_out
= tok
->object_size
;
4746 *intro_points_encrypted_out
= NULL
;
4747 *intro_points_encrypted_size_out
= 0;
4749 /* Parse and verify signature. */
4750 tok
= find_by_keyword(tokens
, R_SIGNATURE
);
4751 note_crypto_pk_op(VERIFY_RTR
);
4752 if (check_signature_token(desc_hash
, DIGEST_LEN
, tok
, result
->pk
, 0,
4753 "v2 rendezvous service descriptor") < 0)
4755 /* Verify that descriptor ID belongs to public key and secret ID part. */
4756 crypto_pk_get_digest(result
->pk
, public_key_hash
);
4757 rend_get_descriptor_id_bytes(test_desc_id
, public_key_hash
,
4759 if (memcmp(desc_id_out
, test_desc_id
, DIGEST_LEN
)) {
4760 log_warn(LD_REND
, "Parsed descriptor ID does not match "
4761 "computed descriptor ID.");
4766 rend_service_descriptor_free(result
);
4770 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
4771 smartlist_free(tokens
);
4774 memarea_drop_all(area
);
4775 *parsed_out
= result
;
4781 /** Decrypt the encrypted introduction points in <b>ipos_encrypted</b> of
4782 * length <b>ipos_encrypted_size</b> using <b>descriptor_cookie</b> and
4783 * write the result to a newly allocated string that is pointed to by
4784 * <b>ipos_decrypted</b> and its length to <b>ipos_decrypted_size</b>.
4785 * Return 0 if decryption was successful and -1 otherwise. */
4787 rend_decrypt_introduction_points(char **ipos_decrypted
,
4788 size_t *ipos_decrypted_size
,
4789 const char *descriptor_cookie
,
4790 const char *ipos_encrypted
,
4791 size_t ipos_encrypted_size
)
4793 tor_assert(ipos_encrypted
);
4794 tor_assert(descriptor_cookie
);
4795 if (ipos_encrypted_size
< 2) {
4796 log_warn(LD_REND
, "Size of encrypted introduction points is too "
4800 if (ipos_encrypted
[0] == (int)REND_BASIC_AUTH
) {
4801 char iv
[CIPHER_IV_LEN
], client_id
[REND_BASIC_AUTH_CLIENT_ID_LEN
],
4802 session_key
[CIPHER_KEY_LEN
], *dec
;
4803 int declen
, client_blocks
;
4804 size_t pos
= 0, len
, client_entries_len
;
4805 crypto_digest_env_t
*digest
;
4806 crypto_cipher_env_t
*cipher
;
4807 client_blocks
= (int) ipos_encrypted
[1];
4808 client_entries_len
= client_blocks
* REND_BASIC_AUTH_CLIENT_MULTIPLE
*
4809 REND_BASIC_AUTH_CLIENT_ENTRY_LEN
;
4810 if (ipos_encrypted_size
< 2 + client_entries_len
+ CIPHER_IV_LEN
+ 1) {
4811 log_warn(LD_REND
, "Size of encrypted introduction points is too "
4815 memcpy(iv
, ipos_encrypted
+ 2 + client_entries_len
, CIPHER_IV_LEN
);
4816 digest
= crypto_new_digest_env();
4817 crypto_digest_add_bytes(digest
, descriptor_cookie
, REND_DESC_COOKIE_LEN
);
4818 crypto_digest_add_bytes(digest
, iv
, CIPHER_IV_LEN
);
4819 crypto_digest_get_digest(digest
, client_id
,
4820 REND_BASIC_AUTH_CLIENT_ID_LEN
);
4821 crypto_free_digest_env(digest
);
4822 for (pos
= 2; pos
< 2 + client_entries_len
;
4823 pos
+= REND_BASIC_AUTH_CLIENT_ENTRY_LEN
) {
4824 if (!memcmp(ipos_encrypted
+ pos
, client_id
,
4825 REND_BASIC_AUTH_CLIENT_ID_LEN
)) {
4826 /* Attempt to decrypt introduction points. */
4827 cipher
= crypto_create_init_cipher(descriptor_cookie
, 0);
4828 if (crypto_cipher_decrypt(cipher
, session_key
, ipos_encrypted
4829 + pos
+ REND_BASIC_AUTH_CLIENT_ID_LEN
,
4830 CIPHER_KEY_LEN
) < 0) {
4831 log_warn(LD_REND
, "Could not decrypt session key for client.");
4832 crypto_free_cipher_env(cipher
);
4835 crypto_free_cipher_env(cipher
);
4836 cipher
= crypto_create_init_cipher(session_key
, 0);
4837 len
= ipos_encrypted_size
- 2 - client_entries_len
- CIPHER_IV_LEN
;
4838 dec
= tor_malloc(len
);
4839 declen
= crypto_cipher_decrypt_with_iv(cipher
, dec
, len
,
4840 ipos_encrypted
+ 2 + client_entries_len
,
4841 ipos_encrypted_size
- 2 - client_entries_len
);
4842 crypto_free_cipher_env(cipher
);
4844 log_warn(LD_REND
, "Could not decrypt introduction point string.");
4848 if (memcmpstart(dec
, declen
, "introduction-point ")) {
4849 log_warn(LD_REND
, "Decrypted introduction points don't "
4850 "look like we could parse them.");
4854 *ipos_decrypted
= dec
;
4855 *ipos_decrypted_size
= declen
;
4859 log_warn(LD_REND
, "Could not decrypt introduction points. Please "
4860 "check your authorization for this service!");
4862 } else if (ipos_encrypted
[0] == (int)REND_STEALTH_AUTH
) {
4863 crypto_cipher_env_t
*cipher
;
4866 dec
= tor_malloc_zero(ipos_encrypted_size
- CIPHER_IV_LEN
- 1);
4867 cipher
= crypto_create_init_cipher(descriptor_cookie
, 0);
4868 declen
= crypto_cipher_decrypt_with_iv(cipher
, dec
,
4869 ipos_encrypted_size
-
4872 ipos_encrypted_size
- 1);
4873 crypto_free_cipher_env(cipher
);
4875 log_warn(LD_REND
, "Decrypting introduction points failed!");
4879 *ipos_decrypted
= dec
;
4880 *ipos_decrypted_size
= declen
;
4883 log_warn(LD_REND
, "Unknown authorization type number: %d",
4889 /** Parse the encoded introduction points in <b>intro_points_encoded</b> of
4890 * length <b>intro_points_encoded_size</b> and write the result to the
4891 * descriptor in <b>parsed</b>; return the number of successfully parsed
4892 * introduction points or -1 in case of a failure. */
4894 rend_parse_introduction_points(rend_service_descriptor_t
*parsed
,
4895 const char *intro_points_encoded
,
4896 size_t intro_points_encoded_size
)
4898 const char *current_ipo
, *end_of_intro_points
;
4899 smartlist_t
*tokens
;
4900 directory_token_t
*tok
;
4901 rend_intro_point_t
*intro
;
4902 extend_info_t
*info
;
4903 int result
, num_ok
=1;
4904 memarea_t
*area
= NULL
;
4906 /** Function may only be invoked once. */
4907 tor_assert(!parsed
->intro_nodes
);
4908 tor_assert(intro_points_encoded
);
4909 tor_assert(intro_points_encoded_size
> 0);
4910 /* Consider one intro point after the other. */
4911 current_ipo
= intro_points_encoded
;
4912 end_of_intro_points
= intro_points_encoded
+ intro_points_encoded_size
;
4913 tokens
= smartlist_create();
4914 parsed
->intro_nodes
= smartlist_create();
4915 area
= memarea_new();
4917 while (!memcmpstart(current_ipo
, end_of_intro_points
-current_ipo
,
4918 "introduction-point ")) {
4919 /* Determine end of string. */
4920 const char *eos
= tor_memstr(current_ipo
, end_of_intro_points
-current_ipo
,
4921 "\nintroduction-point ");
4923 eos
= end_of_intro_points
;
4926 tor_assert(eos
<= intro_points_encoded
+intro_points_encoded_size
);
4927 /* Free tokens and clear token list. */
4928 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
4929 smartlist_clear(tokens
);
4930 memarea_clear(area
);
4931 /* Tokenize string. */
4932 if (tokenize_string(area
, current_ipo
, eos
, tokens
, ipo_token_table
, 0)) {
4933 log_warn(LD_REND
, "Error tokenizing introduction point");
4936 /* Advance to next introduction point, if available. */
4938 /* Check minimum allowed length of introduction point. */
4939 if (smartlist_len(tokens
) < 5) {
4940 log_warn(LD_REND
, "Impossibly short introduction point.");
4943 /* Allocate new intro point and extend info. */
4944 intro
= tor_malloc_zero(sizeof(rend_intro_point_t
));
4945 info
= intro
->extend_info
= tor_malloc_zero(sizeof(extend_info_t
));
4946 /* Parse identifier. */
4947 tok
= find_by_keyword(tokens
, R_IPO_IDENTIFIER
);
4948 if (base32_decode(info
->identity_digest
, DIGEST_LEN
,
4949 tok
->args
[0], REND_INTRO_POINT_ID_LEN_BASE32
) < 0) {
4950 log_warn(LD_REND
, "Identity digest contains illegal characters: %s",
4952 rend_intro_point_free(intro
);
4955 /* Write identifier to nickname. */
4956 info
->nickname
[0] = '$';
4957 base16_encode(info
->nickname
+ 1, sizeof(info
->nickname
) - 1,
4958 info
->identity_digest
, DIGEST_LEN
);
4959 /* Parse IP address. */
4960 tok
= find_by_keyword(tokens
, R_IPO_IP_ADDRESS
);
4961 if (tor_addr_from_str(&info
->addr
, tok
->args
[0])<0) {
4962 log_warn(LD_REND
, "Could not parse introduction point address.");
4963 rend_intro_point_free(intro
);
4966 if (tor_addr_family(&info
->addr
) != AF_INET
) {
4967 log_warn(LD_REND
, "Introduction point address was not ipv4.");
4968 rend_intro_point_free(intro
);
4972 /* Parse onion port. */
4973 tok
= find_by_keyword(tokens
, R_IPO_ONION_PORT
);
4974 info
->port
= (uint16_t) tor_parse_long(tok
->args
[0],10,1,65535,
4976 if (!info
->port
|| !num_ok
) {
4977 log_warn(LD_REND
, "Introduction point onion port %s is invalid",
4978 escaped(tok
->args
[0]));
4979 rend_intro_point_free(intro
);
4982 /* Parse onion key. */
4983 tok
= find_by_keyword(tokens
, R_IPO_ONION_KEY
);
4984 info
->onion_key
= tok
->key
;
4985 tok
->key
= NULL
; /* Prevent free */
4986 /* Parse service key. */
4987 tok
= find_by_keyword(tokens
, R_IPO_SERVICE_KEY
);
4988 intro
->intro_key
= tok
->key
;
4989 tok
->key
= NULL
; /* Prevent free */
4990 /* Add extend info to list of introduction points. */
4991 smartlist_add(parsed
->intro_nodes
, intro
);
4993 result
= smartlist_len(parsed
->intro_nodes
);
5000 /* Free tokens and clear token list. */
5001 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
5002 smartlist_free(tokens
);
5004 memarea_drop_all(area
);
5009 /** Parse the content of a client_key file in <b>ckstr</b> and add
5010 * rend_authorized_client_t's for each parsed client to
5011 * <b>parsed_clients</b>. Return the number of parsed clients as result
5012 * or -1 for failure. */
5014 rend_parse_client_keys(strmap_t
*parsed_clients
, const char *ckstr
)
5017 smartlist_t
*tokens
;
5018 directory_token_t
*tok
;
5019 const char *current_entry
= NULL
;
5020 memarea_t
*area
= NULL
;
5021 if (!ckstr
|| strlen(ckstr
) == 0)
5023 tokens
= smartlist_create();
5024 /* Begin parsing with first entry, skipping comments or whitespace at the
5026 area
= memarea_new();
5027 current_entry
= eat_whitespace(ckstr
);
5028 while (!strcmpstart(current_entry
, "client-name ")) {
5029 rend_authorized_client_t
*parsed_entry
;
5031 char descriptor_cookie_base64
[REND_DESC_COOKIE_LEN_BASE64
+2+1];
5032 char descriptor_cookie_tmp
[REND_DESC_COOKIE_LEN
+2];
5033 /* Determine end of string. */
5034 const char *eos
= strstr(current_entry
, "\nclient-name ");
5036 eos
= current_entry
+ strlen(current_entry
);
5039 /* Free tokens and clear token list. */
5040 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
5041 smartlist_clear(tokens
);
5042 memarea_clear(area
);
5043 /* Tokenize string. */
5044 if (tokenize_string(area
, current_entry
, eos
, tokens
,
5045 client_keys_token_table
, 0)) {
5046 log_warn(LD_REND
, "Error tokenizing client keys file.");
5049 /* Advance to next entry, if available. */
5050 current_entry
= eos
;
5051 /* Check minimum allowed length of token list. */
5052 if (smartlist_len(tokens
) < 2) {
5053 log_warn(LD_REND
, "Impossibly short client key entry.");
5056 /* Parse client name. */
5057 tok
= find_by_keyword(tokens
, C_CLIENT_NAME
);
5058 tor_assert(tok
== smartlist_get(tokens
, 0));
5059 tor_assert(tok
->n_args
== 1);
5061 len
= strlen(tok
->args
[0]);
5062 if (len
< 1 || len
> 19 ||
5063 strspn(tok
->args
[0], REND_LEGAL_CLIENTNAME_CHARACTERS
) != len
) {
5064 log_warn(LD_CONFIG
, "Illegal client name: %s. (Length must be "
5065 "between 1 and 19, and valid characters are "
5066 "[A-Za-z0-9+-_].)", tok
->args
[0]);
5069 /* Check if client name is duplicate. */
5070 if (strmap_get(parsed_clients
, tok
->args
[0])) {
5071 log_warn(LD_CONFIG
, "HiddenServiceAuthorizeClient contains a "
5072 "duplicate client name: '%s'. Ignoring.", tok
->args
[0]);
5075 parsed_entry
= tor_malloc_zero(sizeof(rend_authorized_client_t
));
5076 parsed_entry
->client_name
= tor_strdup(tok
->args
[0]);
5077 strmap_set(parsed_clients
, parsed_entry
->client_name
, parsed_entry
);
5078 /* Parse client key. */
5079 tok
= find_opt_by_keyword(tokens
, C_CLIENT_KEY
);
5081 parsed_entry
->client_key
= tok
->key
;
5082 tok
->key
= NULL
; /* Prevent free */
5085 /* Parse descriptor cookie. */
5086 tok
= find_by_keyword(tokens
, C_DESCRIPTOR_COOKIE
);
5087 tor_assert(tok
->n_args
== 1);
5088 if (strlen(tok
->args
[0]) != REND_DESC_COOKIE_LEN_BASE64
+ 2) {
5089 log_warn(LD_REND
, "Descriptor cookie has illegal length: %s",
5090 escaped(tok
->args
[0]));
5093 /* The size of descriptor_cookie_tmp needs to be REND_DESC_COOKIE_LEN+2,
5094 * because a base64 encoding of length 24 does not fit into 16 bytes in all
5096 if ((base64_decode(descriptor_cookie_tmp
, REND_DESC_COOKIE_LEN
+2,
5097 tok
->args
[0], REND_DESC_COOKIE_LEN_BASE64
+2+1)
5098 != REND_DESC_COOKIE_LEN
)) {
5099 log_warn(LD_REND
, "Descriptor cookie contains illegal characters: "
5100 "%s", descriptor_cookie_base64
);
5103 memcpy(parsed_entry
->descriptor_cookie
, descriptor_cookie_tmp
,
5104 REND_DESC_COOKIE_LEN
);
5106 result
= strmap_size(parsed_clients
);
5111 /* Free tokens and clear token list. */
5112 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
5113 smartlist_free(tokens
);
5115 memarea_drop_all(area
);